-
Notifications
You must be signed in to change notification settings - Fork 20.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core/vm: implement EIP-3860: Limit and meter initcode #23847
Changes from all commits
f0cf887
7eda541
493db58
b5a3aec
0fe2b2c
8896d41
9a109f3
db41c88
8edb9d3
5d73263
ed09df5
a55f5cb
effeefc
a326b8c
9b558fb
56df86a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,16 +120,17 @@ func (result *ExecutionResult) Revert() []byte { | |
} | ||
|
||
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. | ||
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) { | ||
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) { | ||
// Set the starting gas for the raw transaction | ||
var gas uint64 | ||
if isContractCreation && isHomestead { | ||
gas = params.TxGasContractCreation | ||
} else { | ||
gas = params.TxGas | ||
} | ||
dataLen := uint64(len(data)) | ||
// Bump the required gas by the amount of transactional data | ||
if len(data) > 0 { | ||
if dataLen > 0 { | ||
// Zero and non-zero bytes are priced differently | ||
var nz uint64 | ||
for _, byt := range data { | ||
|
@@ -147,11 +148,19 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b | |
} | ||
gas += nz * nonZeroGas | ||
|
||
z := uint64(len(data)) - nz | ||
z := dataLen - nz | ||
if (math.MaxUint64-gas)/params.TxDataZeroGas < z { | ||
return 0, ErrGasUintOverflow | ||
} | ||
gas += z * params.TxDataZeroGas | ||
|
||
if isContractCreation && isEIP3860 { | ||
lenWords := toWordSize(dataLen) | ||
if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { | ||
return 0, ErrGasUintOverflow | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because you check the EIP-3860 length limit before calculating the cost the overflow cannot happen. Do you want to convert this to a panic? |
||
} | ||
gas += lenWords * params.InitCodeWordGas | ||
} | ||
} | ||
if accessList != nil { | ||
gas += uint64(len(accessList)) * params.TxAccessListAddressGas | ||
|
@@ -160,6 +169,15 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b | |
return gas, nil | ||
} | ||
|
||
// toWordSize returns the ceiled word size required for init code payment calculation. | ||
func toWordSize(size uint64) uint64 { | ||
MariusVanDerWijden marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternative implementations: https://godbolt.org/z/3r17eWvjY. |
||
if size > math.MaxUint64-31 { | ||
return math.MaxUint64/32 + 1 | ||
} | ||
|
||
return (size + 31) / 32 | ||
} | ||
|
||
// NewStateTransition initialises and returns a new state transition object. | ||
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { | ||
return &StateTransition{ | ||
|
@@ -305,7 +323,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { | |
) | ||
|
||
// Check clauses 4-5, subtract intrinsic gas if everything is correct | ||
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) | ||
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -319,6 +337,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { | |
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) | ||
} | ||
|
||
// Check whether the init code size has been exceeded. | ||
if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize { | ||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize) | ||
} | ||
|
||
// Execute the preparatory steps for state transition which includes: | ||
// - prepare accessList(post-berlin) | ||
// - reset transient storage(eip 1153) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -245,6 +245,7 @@ type TxPool struct { | |
istanbul bool // Fork indicator whether we are in the istanbul stage. | ||
eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions. | ||
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. | ||
shanghai bool // Fork indicator whether we are in the Shanghai stage. | ||
|
||
currentState *state.StateDB // Current state in the blockchain head | ||
pendingNonces *noncer // Pending state tracking virtual nonces | ||
|
@@ -637,7 +638,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { | |
return core.ErrInsufficientFunds | ||
} | ||
// Ensure the transaction has more gas than the basic tx fee. | ||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) | ||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having 3860 activated in Shanghai allows txpool to enable new intrinsic gas rules at the right moment |
||
if err != nil { | ||
return err | ||
} | ||
|
@@ -1306,6 +1307,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { | |
pool.istanbul = pool.chainconfig.IsIstanbul(next) | ||
pool.eip2718 = pool.chainconfig.IsBerlin(next) | ||
pool.eip1559 = pool.chainconfig.IsLondon(next) | ||
pool.shanghai = pool.chainconfig.IsShanghai(big.NewInt(time.Now().Unix())) | ||
} | ||
|
||
// promoteExecutables moves transactions that have become processable from the | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isEIP2028 bool
seems not used anymoreThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is, afaict: