From efc32877dec232c572e4799b6d557058cf97e127 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 1 Oct 2018 13:12:43 +0200 Subject: [PATCH] core/vm: do less hashing in CREATE2 --- core/vm/evm.go | 27 +++++++++++++++++++++------ crypto/crypto.go | 6 +++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index fc040c6216..e604d79822 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -352,8 +352,21 @@ 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 == nil { + h := crypto.Keccak256Hash(c.code) + c.hash = &h + } + 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 +395,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.SetCallCode(&address, codeAndHash.Hash(), codeAndHash.code) 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() @@ -432,8 +445,9 @@ 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) { + codeAndHash := codeAndHash{code: code} contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, code, gas, value, contractAddr) + return evm.create(caller, codeAndHash, gas, value, contractAddr) } // Create2 creates a new contract using code as deployment code. @@ -441,8 +455,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 diff --git a/crypto/crypto.go b/crypto/crypto.go index 3211957e0a..9b3e76d406 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -77,9 +77,9 @@ func CreateAddress(b common.Address, nonce uint64) common.Address { } // CreateAddress2 creates an ethereum address given the address bytes, initial -// contract code and a salt. -func CreateAddress2(b common.Address, salt [32]byte, code []byte) common.Address { - return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], Keccak256(code))[12:]) +// contract code hash and a salt. +func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address { + return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:]) } // ToECDSA creates a private key with the given D value.