aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/contract.go
diff options
context:
space:
mode:
authorMartin Holst Swende <martin@swende.se>2018-10-04 23:15:37 +0800
committerPéter Szilágyi <peterke@gmail.com>2018-10-04 23:15:37 +0800
commit89a32451aeb418db3fd5d9c427a0c29fddb1e85b (patch)
tree24df0d470d52030635712364a947bc7a8293d366 /core/vm/contract.go
parent8c63d0d2e44128c6a0f12fb9db8f0a32528b4a7d (diff)
downloadgo-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.go59
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
+}