diff options
author | Martin Holst Swende <martin@swende.se> | 2018-10-04 23:15:37 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2018-10-04 23:15:37 +0800 |
commit | 89a32451aeb418db3fd5d9c427a0c29fddb1e85b (patch) | |
tree | 24df0d470d52030635712364a947bc7a8293d366 /core/vm/contract.go | |
parent | 8c63d0d2e44128c6a0f12fb9db8f0a32528b4a7d (diff) | |
download | go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar.gz go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar.bz2 go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar.lz go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar.xz go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.tar.zst go-tangerine-89a32451aeb418db3fd5d9c427a0c29fddb1e85b.zip |
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
Diffstat (limited to 'core/vm/contract.go')
-rw-r--r-- | core/vm/contract.go | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/core/vm/contract.go b/core/vm/contract.go index 26bca6895..20baa6e75 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -49,7 +49,8 @@ type Contract struct { caller ContractRef self ContractRef - jumpdests destinations // result of JUMPDEST analysis. + jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. + analysis bitvec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash @@ -58,21 +59,17 @@ type Contract struct { Gas uint64 value *big.Int - - Args []byte - - DelegateCall bool } // NewContract returns a new contract environment for the execution of EVM. func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { - c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} + c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} if parent, ok := caller.(*Contract); ok { // Reuse JUMPDEST analysis from parent context if available. c.jumpdests = parent.jumpdests } else { - c.jumpdests = make(destinations) + c.jumpdests = make(map[common.Hash]bitvec) } // Gas should be a pointer so it can safely be reduced through the run @@ -84,10 +81,42 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin return c } +func (c *Contract) validJumpdest(dest *big.Int) bool { + udest := dest.Uint64() + // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. + // Don't bother checking for JUMPDEST in that case. + if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) { + return false + } + // Only JUMPDESTs allowed for destinations + if OpCode(c.Code[udest]) != JUMPDEST { + return false + } + // Do we have a contract hash already? + if c.CodeHash != (common.Hash{}) { + // Does parent context have the analysis? + analysis, exist := c.jumpdests[c.CodeHash] + if !exist { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.jumpdests[c.CodeHash] = analysis + } + return analysis.codeSegment(udest) + } + // We don't have the code hash, most likely a piece of initcode not already + // in state trie. In that case, we do an analysis, and save it locally, so + // we don't have to recalculate it for every JUMP instruction in the execution + // However, we don't save it within the parent context + if c.analysis == nil { + c.analysis = codeBitmap(c.Code) + } + return c.analysis.codeSegment(udest) +} + // AsDelegate sets the contract to be a delegate call and returns the current // contract (for chaining calls) func (c *Contract) AsDelegate() *Contract { - c.DelegateCall = true // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := c.caller.(*Contract) @@ -138,12 +167,6 @@ func (c *Contract) Value() *big.Int { return c.value } -// SetCode sets the code to the contract -func (c *Contract) SetCode(hash common.Hash, code []byte) { - c.Code = code - c.CodeHash = hash -} - // SetCallCode sets the code of the contract and address of the backing data // object func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { @@ -151,3 +174,11 @@ func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []by c.CodeHash = hash c.CodeAddr = addr } + +// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. +// In case hash is not provided, the jumpdest analysis will not be saved to the parent context +func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { + c.Code = codeAndHash.code + c.CodeHash = codeAndHash.hash + c.CodeAddr = addr +} |