core/vm: faster create/create2 (#17806)
* core/vm/runtim: benchmark create/create2 * core/vm: do less hashing in CREATE2 * core/vm: avoid storing jumpdest analysis for initcode * core/vm: avoid unneccesary lookups, remove unused fields * core/vm: go formatting tests * core/vm: save jumpdest analysis locally * core/vm: use common.Hash instead of nil, fix review comments * core/vm: removed type destinations * core/vm: correct check for empty hash * eth: more elegant api_tracer * core/vm: address review concerns
This commit is contained in:
committed by
Péter Szilágyi
parent
8c63d0d2e4
commit
89a32451ae
@ -212,12 +212,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
evm.StateDB.CreateAccount(addr)
|
||||
}
|
||||
evm.Transfer(evm.StateDB, caller.Address(), to.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, to, value, gas)
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
|
||||
// Even if the account has no code, we need to continue because it might be a precompile
|
||||
start := time.Now()
|
||||
|
||||
// Capture the tracer start/end events in debug mode
|
||||
@ -352,8 +352,20 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
return ret, contract.Gas, err
|
||||
}
|
||||
|
||||
type codeAndHash struct {
|
||||
code []byte
|
||||
hash common.Hash
|
||||
}
|
||||
|
||||
func (c *codeAndHash) Hash() common.Hash {
|
||||
if c.hash == (common.Hash{}) {
|
||||
c.hash = crypto.Keccak256Hash(c.code)
|
||||
}
|
||||
return c.hash
|
||||
}
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
|
||||
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
@ -382,14 +394,14 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// EVM. The contract is a scoped environment for this execution context
|
||||
// only.
|
||||
contract := NewContract(caller, AccountRef(address), value, gas)
|
||||
contract.SetCallCode(&address, crypto.Keccak256Hash(code), code)
|
||||
contract.SetCodeOptionalHash(&address, codeAndHash)
|
||||
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, address, gas, nil
|
||||
}
|
||||
|
||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value)
|
||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||
}
|
||||
start := time.Now()
|
||||
|
||||
@ -433,7 +445,7 @@ func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
|
||||
return evm.create(caller, code, gas, value, contractAddr)
|
||||
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr)
|
||||
}
|
||||
|
||||
// Create2 creates a new contract using code as deployment code.
|
||||
@ -441,8 +453,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:]
|
||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), code)
|
||||
return evm.create(caller, code, gas, endowment, contractAddr)
|
||||
codeAndHash := &codeAndHash{code: code}
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
|
||||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
|
||||
}
|
||||
|
||||
// ChainConfig returns the environment's chain configuration
|
||||
|
Reference in New Issue
Block a user