diff --git a/core/error.go b/core/error.go index 51ebefc137bc..238d881d14e7 100644 --- a/core/error.go +++ b/core/error.go @@ -63,6 +63,11 @@ var ( // have enough funds for transfer(topmost call only). ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer") + // ErrInsufficientBalanceWitness is returned if the transaction sender has enough + // funds to cover the transfer, but not enough to pay for witness access/modification + // costs for the transaction + ErrInsufficientBalanceWitness = errors.New("insufficient funds to cover witness access costs for transaction") + // ErrInsufficientFunds is returned if the total cost of executing a transaction // is higher than the balance of the user's account. ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") diff --git a/core/state_transition.go b/core/state_transition.go index ae9643f71762..2c29b6da096e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -317,23 +317,24 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) } if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber) { - var targetBalance, targetNonce, targetCodeSize, targetCodeKeccak, originBalance, originNonce []byte + var targetBalance, targetNonce, targetCodeSize, targetCodeKeccak, originBalance, originNonceBytes []byte targetAddr := msg.To() originAddr := msg.From() statelessGasOrigin := st.evm.Accesses.TouchTxOriginAndComputeGas(originAddr.Bytes(), msg.Value().Sign() != 0) if !tryConsumeGas(&st.gas, statelessGasOrigin) { - return nil, fmt.Errorf("insufficient gas to cover witness access costs") + return nil, ErrInsufficientBalanceWitness } originBalance = st.evm.StateDB.GetBalanceLittleEndian(originAddr) - originNonce = st.evm.StateDB.GetNonceLittleEndian(originAddr) - st.evm.Accesses.SetTxOriginTouchedLeaves(originAddr.Bytes(), originBalance, originNonce) + originNonce := st.evm.StateDB.GetNonce(originAddr) + originNonceBytes = st.evm.StateDB.GetNonceLittleEndian(originAddr) + st.evm.Accesses.SetTxOriginTouchedLeaves(originAddr.Bytes(), originBalance, originNonceBytes) if msg.To() != nil { statelessGasDest := st.evm.Accesses.TouchTxExistingAndComputeGas(targetAddr.Bytes(), msg.Value().Sign() != 0) if !tryConsumeGas(&st.gas, statelessGasDest) { - return nil, fmt.Errorf("insufficient gas to cover witness access costs") + return nil, ErrInsufficientBalanceWitness } targetBalance = st.evm.StateDB.GetBalanceLittleEndian(*targetAddr) targetNonce = st.evm.StateDB.GetNonceLittleEndian(*targetAddr) @@ -343,7 +344,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { var codeSizeBytes [32]byte binary.LittleEndian.PutUint64(codeSizeBytes[:8], codeSize) st.evm.Accesses.SetTxExistingTouchedLeaves(targetAddr.Bytes(), targetBalance, targetNonce, targetCodeSize, targetCodeKeccak) + } else { + contractAddr := crypto.CreateAddress(originAddr, originNonce) + if !tryConsumeGas(&st.gas, st.evm.Accesses.TouchAndChargeContractCreateInit(contractAddr.Bytes(), msg.Value().Sign() != 0)) { + return nil, ErrInsufficientBalanceWitness + } } + if st.gas < gas { return nil, fmt.Errorf("Insufficient funds to cover witness access costs for transaction: have %d, want %d", st.gas, gas) } diff --git a/core/vm/evm.go b/core/vm/evm.go index 42b7daad87d4..3bbbdfb04dfb 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -474,18 +474,21 @@ func (c *codeAndHash) Hash() common.Hash { // create creates a new contract using code as deployment code. func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) { var zeroVerkleLeaf [32]byte + var balance []byte if evm.chainConfig.IsCancun(evm.Context.BlockNumber) { // note: assumption is that the nonce, code size, code hash // will be 0x0000...00 at the target account before it is created // otherwise would imply contract creation collision which is // impossible if self-destruct is removed - balance := evm.StateDB.GetBalanceLittleEndian(address) + if evm.StateDB.GetBalance(address).Sign() != 0 { + balance = evm.StateDB.GetBalanceLittleEndian(address) + } if value.Sign() != 0 { evm.Accesses.SetLeafValuesContractCreateInit(address.Bytes()[:], zeroVerkleLeaf[:], nil) } else { - evm.Accesses.SetLeafValuesContractCreateInit(address.Bytes()[:], zeroVerkleLeaf[:], balance[:]) + evm.Accesses.SetLeafValuesContractCreateInit(address.Bytes()[:], zeroVerkleLeaf[:], balance) } }