|
|
|
@ -435,7 +435,7 @@ 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 *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { |
|
|
|
|
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode, input []byte, allowEOF bool) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { |
|
|
|
|
if evm.Config.Tracer != nil { |
|
|
|
|
evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig()) |
|
|
|
|
defer func(startGas uint64) { |
|
|
|
@ -450,6 +450,33 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, |
|
|
|
|
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { |
|
|
|
|
return nil, common.Address{}, gas, ErrInsufficientBalance |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
|
|
|
|
// The contract is a scoped environment for this execution context only. If
|
|
|
|
|
// the initcode is EOF, contract.Container will be set.
|
|
|
|
|
contract := NewContract(caller, AccountRef(address), value, gas) |
|
|
|
|
contract.SetCodeOptionalHash(&address, codeAndHash) |
|
|
|
|
contract.IsDeployment = true |
|
|
|
|
|
|
|
|
|
// Validate initcode per EOF rules. If caller is EOF and initcode is legacy, fail.
|
|
|
|
|
isInitcodeEOF := hasEOFMagic(codeAndHash.code) |
|
|
|
|
if isInitcodeEOF { |
|
|
|
|
if allowEOF { |
|
|
|
|
// If the initcode is EOF, verify it is well-formed.
|
|
|
|
|
var c Container |
|
|
|
|
if err := c.UnmarshalBinary(codeAndHash.code, isInitcodeEOF); err != nil { |
|
|
|
|
return nil, common.Address{}, gas, fmt.Errorf("%w: %v", ErrInvalidEOFInitcode, err) |
|
|
|
|
} |
|
|
|
|
if err := c.ValidateCode(evm.interpreter.tableEOF, isInitcodeEOF); err != nil { |
|
|
|
|
return nil, common.Address{}, gas, fmt.Errorf("%w: %v", ErrInvalidEOFInitcode, err) |
|
|
|
|
} |
|
|
|
|
contract.Container = &c |
|
|
|
|
} else { |
|
|
|
|
// Don't allow EOF contract to execute legacy initcode.
|
|
|
|
|
return nil, common.Address{}, gas, ErrLegacyCode |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Check for nonce overflow and then update caller nonce by 1.
|
|
|
|
|
nonce := evm.StateDB.GetNonce(caller.Address()) |
|
|
|
|
if nonce+1 < nonce { |
|
|
|
|
return nil, common.Address{}, gas, ErrNonceUintOverflow |
|
|
|
@ -517,13 +544,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, |
|
|
|
|
} |
|
|
|
|
evm.Context.Transfer(evm.StateDB, caller.Address(), address, value) |
|
|
|
|
|
|
|
|
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
|
|
|
|
// The contract is a scoped environment for this execution context only.
|
|
|
|
|
contract := NewContract(caller, AccountRef(address), value, gas) |
|
|
|
|
contract.SetCodeOptionalHash(&address, codeAndHash) |
|
|
|
|
contract.IsDeployment = true |
|
|
|
|
|
|
|
|
|
ret, err = evm.initNewContract(contract, address, value) |
|
|
|
|
ret, err = evm.initNewContract(contract, address, value, isInitcodeEOF) |
|
|
|
|
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { |
|
|
|
|
evm.StateDB.RevertToSnapshot(snapshot) |
|
|
|
|
if err != ErrExecutionReverted { |
|
|
|
@ -535,7 +556,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, |
|
|
|
|
|
|
|
|
|
// initNewContract runs a new contract's creation code, performs checks on the
|
|
|
|
|
// resulting code that is to be deployed, and consumes necessary gas.
|
|
|
|
|
func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) { |
|
|
|
|
func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int, isInitcodeEOF bool) ([]byte, error) { |
|
|
|
|
// Charge the contract creation init gas in verkle mode
|
|
|
|
|
if evm.chainRules.IsEIP4762 { |
|
|
|
|
if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { |
|
|
|
@ -543,7 +564,7 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret, err := evm.interpreter.Run(contract, nil, false, true) |
|
|
|
|
ret, err := evm.interpreter.Run(contract, nil, false, contract.IsDeployment) |
|
|
|
|
if err != nil { |
|
|
|
|
return ret, err |
|
|
|
|
} |
|
|
|
@ -553,9 +574,22 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu |
|
|
|
|
return ret, ErrMaxCodeSizeExceeded |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Reject legacy contract deployment from EOF.
|
|
|
|
|
if isInitcodeEOF && !hasEOFMagic(ret) { |
|
|
|
|
return ret, fmt.Errorf("%w: %v", ErrInvalidEOFInitcode, ErrLegacyCode) |
|
|
|
|
} |
|
|
|
|
// Reject EOF deployment from legacy.
|
|
|
|
|
if isInitcodeEOF && hasEOFMagic(ret) { |
|
|
|
|
return ret, ErrLegacyCode |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Reject code starting with 0xEF if EIP-3541 is enabled.
|
|
|
|
|
if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { |
|
|
|
|
return ret, ErrInvalidCode |
|
|
|
|
if len(ret) >= 1 && HasEOFByte(ret) { |
|
|
|
|
if evm.chainRules.IsPrague && isInitcodeEOF { |
|
|
|
|
// Don't reject EOF contracts after Shanghai
|
|
|
|
|
} else if evm.chainRules.IsLondon { |
|
|
|
|
err = ErrInvalidCode |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !evm.chainRules.IsEIP4762 { |
|
|
|
@ -576,7 +610,7 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu |
|
|
|
|
// Create creates a new contract using code as deployment code.
|
|
|
|
|
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int, allowEOF bool) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { |
|
|
|
|
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) |
|
|
|
|
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE) |
|
|
|
|
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE, nil, allowEOF) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create2 creates a new contract using code as deployment code.
|
|
|
|
@ -586,7 +620,14 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint2 |
|
|
|
|
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { |
|
|
|
|
codeAndHash := &codeAndHash{code: code} |
|
|
|
|
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) |
|
|
|
|
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) |
|
|
|
|
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2, nil, false) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// EOFCreate creates a new eof contract.
|
|
|
|
|
func (evm *EVM) EOFCreate(caller ContractRef, input []byte, subcontainer []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { |
|
|
|
|
codeAndHash := &codeAndHash{code: subcontainer} |
|
|
|
|
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) |
|
|
|
|
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2, input, true) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ChainConfig returns the environment's chain configuration
|
|
|
|
|