aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-10-01 21:58:49 +0800
committerGitHub <noreply@github.com>2016-10-01 21:58:49 +0800
commit0731b44809f72ed5880dc3654ee70ae85420bd77 (patch)
tree68eb52c91a136e820f3656e394847c4e695afa63
parentd8715fba1a366944a069397775fc52a30358eff3 (diff)
parentcb84e3f02953f2df166ae69369d222dcbbd7d78d (diff)
downloadgo-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar.gz
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar.bz2
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar.lz
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar.xz
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.tar.zst
go-tangerine-0731b44809f72ed5880dc3654ee70ae85420bd77.zip
Merge pull request #3067 from karalabe/vm-avoid-hashing
cmd, core, internal, light, tests: avoid hashing the code in the VM
-rw-r--r--cmd/evm/main.go5
-rw-r--r--core/execution.go16
-rw-r--r--core/state/state_object.go4
-rw-r--r--core/state/state_test.go7
-rw-r--r--core/state/statedb.go11
-rw-r--r--core/state/statedb_test.go9
-rw-r--r--core/state/sync_test.go2
-rw-r--r--core/vm/contract.go11
-rw-r--r--core/vm/environment.go3
-rw-r--r--core/vm/jit_test.go2
-rw-r--r--core/vm/logger_test.go2
-rw-r--r--core/vm/runtime/runtime.go2
-rw-r--r--core/vm/vm.go9
-rw-r--r--internal/ethapi/tracer_test.go2
-rw-r--r--light/state_test.go3
-rw-r--r--tests/block_test_util.go3
-rw-r--r--tests/util.go5
17 files changed, 59 insertions, 37 deletions
diff --git a/cmd/evm/main.go b/cmd/evm/main.go
index 3f44e0f3c..09ade1577 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger/glog"
"gopkg.in/urfave/cli.v1"
@@ -146,7 +147,9 @@ func run(ctx *cli.Context) error {
)
} else {
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
- receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)))
+
+ code := common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
+ receiver.SetCode(crypto.Keccak256Hash(code), code)
ret, err = vmenv.Call(
sender,
receiver.Address(),
diff --git a/core/execution.go b/core/execution.go
index 82143443c..1bc02f7fb 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -27,14 +27,14 @@ import (
// Call executes within the given contract
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
- ret, _, err = exec(env, caller, &addr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value)
+ ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
return ret, err
}
// CallCode executes the given address' code as the given contract address
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
callerAddr := caller.Address()
- ret, _, err = exec(env, caller, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value)
+ ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
return ret, err
}
@@ -43,13 +43,13 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address
callerAddr := caller.Address()
originAddr := env.Origin()
callerValue := caller.Value()
- ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
+ ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
return ret, err
}
// Create creates a new contract with the given code
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
- ret, address, err = exec(env, caller, nil, nil, nil, code, gas, gasPrice, value)
+ ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value)
// Here we get an error if we run into maximum stack depth,
// See: https://github.com/ethereum/yellowpaper/pull/131
// and YP definitions for CREATE instruction
@@ -59,7 +59,7 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric
return ret, address, err
}
-func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
+func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
evm := env.Vm()
// Depth check execution. Fail if we're trying to execute above the
// limit.
@@ -105,7 +105,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
- contract.SetCallCode(codeAddr, code)
+ contract.SetCallCode(codeAddr, codeHash, code)
defer contract.Finalise()
ret, err = evm.Run(contract, input)
@@ -135,7 +135,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
return ret, addr, err
}
-func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
+func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
evm := env.Vm()
// Depth check execution. Fail if we're trying to execute above the
// limit.
@@ -155,7 +155,7 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
// Iinitialise a new contract and make initialise the delegate values
contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate()
- contract.SetCallCode(codeAddr, code)
+ contract.SetCallCode(codeAddr, codeHash, code)
defer contract.Finalise()
ret, err = evm.Run(contract, input)
diff --git a/core/state/state_object.go b/core/state/state_object.go
index a54620d55..121a2ec5c 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -273,9 +273,9 @@ func (self *StateObject) Code(db trie.Database) []byte {
return code
}
-func (self *StateObject) SetCode(code []byte) {
+func (self *StateObject) SetCode(codeHash common.Hash, code []byte) {
self.code = code
- self.data.CodeHash = crypto.Keccak256(code)
+ self.data.CodeHash = codeHash[:]
self.dirtyCode = true
if self.onDirty != nil {
self.onDirty(self.Address())
diff --git a/core/state/state_test.go b/core/state/state_test.go
index fcdc38588..5fe98939b 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -24,6 +24,7 @@ import (
checker "gopkg.in/check.v1"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
)
@@ -40,7 +41,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
obj2 := s.state.GetOrNewStateObject(toAddr([]byte{0x01, 0x02}))
- obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3})
+ obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(toAddr([]byte{0x02}))
obj3.SetBalance(big.NewInt(44))
@@ -148,7 +149,7 @@ func TestSnapshot2(t *testing.T) {
so0 := state.GetStateObject(stateobjaddr0)
so0.SetBalance(big.NewInt(42))
so0.SetNonce(43)
- so0.SetCode([]byte{'c', 'a', 'f', 'e'})
+ so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
so0.remove = false
so0.deleted = false
state.SetStateObject(so0)
@@ -160,7 +161,7 @@ func TestSnapshot2(t *testing.T) {
so1 := state.GetStateObject(stateobjaddr1)
so1.SetBalance(big.NewInt(52))
so1.SetNonce(53)
- so1.SetCode([]byte{'c', 'a', 'f', 'e', '2'})
+ so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
so1.remove = true
so1.deleted = true
state.SetStateObject(so1)
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 5c51e3b59..4204c456e 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
@@ -246,6 +247,14 @@ func (self *StateDB) GetCodeSize(addr common.Address) int {
return size
}
+func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
+ stateObject := self.GetStateObject(addr)
+ if stateObject == nil {
+ return common.Hash{}
+ }
+ return common.BytesToHash(stateObject.CodeHash())
+}
+
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
stateObject := self.GetStateObject(a)
if stateObject != nil {
@@ -283,7 +292,7 @@ func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
func (self *StateDB) SetCode(addr common.Address, code []byte) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
- stateObject.SetCode(code)
+ stateObject.SetCode(crypto.Keccak256Hash(code), code)
}
}
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 928333459..7930b620d 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -21,6 +21,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
)
@@ -40,7 +41,7 @@ func TestUpdateLeaks(t *testing.T) {
obj.SetState(common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
}
if i%3 == 0 {
- obj.SetCode([]byte{i, i, i, i, i})
+ obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
}
state.UpdateStateObject(obj)
}
@@ -70,7 +71,7 @@ func TestIntermediateLeaks(t *testing.T) {
obj.SetState(common.BytesToHash([]byte{i, i, i, 0}), common.BytesToHash([]byte{i, i, i, i, 0}))
}
if i%3 == 0 {
- obj.SetCode([]byte{i, i, i, i, i, 0})
+ obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i, 0}), []byte{i, i, i, i, i, 0})
}
transState.UpdateStateObject(obj)
@@ -82,7 +83,7 @@ func TestIntermediateLeaks(t *testing.T) {
obj.SetState(common.BytesToHash([]byte{i, i, i, 1}), common.BytesToHash([]byte{i, i, i, i, 1}))
}
if i%3 == 0 {
- obj.SetCode([]byte{i, i, i, i, i, 1})
+ obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i, 1}), []byte{i, i, i, i, i, 1})
}
transState.UpdateStateObject(obj)
@@ -94,7 +95,7 @@ func TestIntermediateLeaks(t *testing.T) {
obj.SetState(common.BytesToHash([]byte{i, i, i, 1}), common.BytesToHash([]byte{i, i, i, i, 1}))
}
if i%3 == 0 {
- obj.SetCode([]byte{i, i, i, i, i, 1})
+ obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i, 1}), []byte{i, i, i, i, i, 1})
}
finalState.UpdateStateObject(obj)
}
diff --git a/core/state/sync_test.go b/core/state/sync_test.go
index c768781a4..670e1fb1b 100644
--- a/core/state/sync_test.go
+++ b/core/state/sync_test.go
@@ -54,7 +54,7 @@ func makeTestState() (ethdb.Database, common.Hash, []*testAccount) {
acc.nonce = uint64(42 * i)
if i%3 == 0 {
- obj.SetCode([]byte{i, i, i, i, i})
+ obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
acc.code = []byte{i, i, i, i, i}
}
state.UpdateStateObject(obj)
diff --git a/core/vm/contract.go b/core/vm/contract.go
index 844d3f328..70455a4c2 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -27,7 +27,7 @@ type ContractRef interface {
ReturnGas(*big.Int, *big.Int)
Address() common.Address
Value() *big.Int
- SetCode([]byte)
+ SetCode(common.Hash, []byte)
ForEachStorage(callback func(key, value common.Hash) bool)
}
@@ -44,8 +44,9 @@ type Contract struct {
jumpdests destinations // result of JUMPDEST analysis.
Code []byte
- Input []byte
+ CodeHash common.Hash
CodeAddr *common.Address
+ Input []byte
value, Gas, UsedGas, Price *big.Int
@@ -143,14 +144,16 @@ func (c *Contract) Value() *big.Int {
}
// SetCode sets the code to the contract
-func (self *Contract) SetCode(code []byte) {
+func (self *Contract) SetCode(hash common.Hash, code []byte) {
self.Code = code
+ self.CodeHash = hash
}
// SetCallCode sets the code of the contract and address of the backing data
// object
-func (self *Contract) SetCallCode(addr *common.Address, code []byte) {
+func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
self.Code = code
+ self.CodeHash = hash
self.CodeAddr = addr
}
diff --git a/core/vm/environment.go b/core/vm/environment.go
index 4bd03de7e..daf6fb90d 100644
--- a/core/vm/environment.go
+++ b/core/vm/environment.go
@@ -94,6 +94,7 @@ type Database interface {
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64)
+ GetCodeHash(common.Address) common.Hash
GetCodeSize(common.Address) int
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
@@ -118,7 +119,7 @@ type Account interface {
Balance() *big.Int
Address() common.Address
ReturnGas(*big.Int, *big.Int)
- SetCode([]byte)
+ SetCode(common.Hash, []byte)
ForEachStorage(cb func(key, value common.Hash) bool)
Value() *big.Int
}
diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go
index 809abfea9..e6922aeb7 100644
--- a/core/vm/jit_test.go
+++ b/core/vm/jit_test.go
@@ -135,7 +135,7 @@ func (account) SetNonce(uint64) {}
func (account) Balance() *big.Int { return nil }
func (account) Address() common.Address { return common.Address{} }
func (account) ReturnGas(*big.Int, *big.Int) {}
-func (account) SetCode([]byte) {}
+func (account) SetCode(common.Hash, []byte) {}
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
func runVmBench(test vmBench, b *testing.B) {
diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go
index e85bca227..d4d164eb6 100644
--- a/core/vm/logger_test.go
+++ b/core/vm/logger_test.go
@@ -30,7 +30,7 @@ type dummyContractRef struct {
func (dummyContractRef) ReturnGas(*big.Int, *big.Int) {}
func (dummyContractRef) Address() common.Address { return common.Address{} }
func (dummyContractRef) Value() *big.Int { return new(big.Int) }
-func (dummyContractRef) SetCode([]byte) {}
+func (dummyContractRef) SetCode(common.Hash, []byte) {}
func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) {
d.calledForEach = true
}
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index 309d508c3..6d980cb32 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -104,7 +104,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
)
// set the receiver's (the executing contract) code for execution.
- receiver.SetCode(code)
+ receiver.SetCode(crypto.Keccak256Hash(code), code)
// Call the code with the given configuration.
ret, err := vmenv.Call(
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 9d7b55058..5d78b4a2a 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -71,10 +71,11 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
return nil, nil
}
- var (
- codehash = crypto.Keccak256Hash(contract.Code) // codehash is used when doing jump dest caching
- program *Program
- )
+ codehash := contract.CodeHash // codehash is used when doing jump dest caching
+ if codehash == (common.Hash{}) {
+ codehash = crypto.Keccak256Hash(contract.Code)
+ }
+ var program *Program
if evm.cfg.EnableJit {
// If the JIT is enabled check the status of the JIT program,
// if it doesn't exist compile a new program in a separate
diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go
index 301ff4840..7c831d299 100644
--- a/internal/ethapi/tracer_test.go
+++ b/internal/ethapi/tracer_test.go
@@ -93,7 +93,7 @@ func (account) SetNonce(uint64) {}
func (account) Balance() *big.Int { return nil }
func (account) Address() common.Address { return common.Address{} }
func (account) ReturnGas(*big.Int, *big.Int) {}
-func (account) SetCode([]byte) {}
+func (account) SetCode(common.Hash, []byte) {}
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
func runTrace(tracer *JavascriptTracer) (interface{}, error) {
diff --git a/light/state_test.go b/light/state_test.go
index d7014a2dc..d4fe95022 100644
--- a/light/state_test.go
+++ b/light/state_test.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie"
"golang.org/x/net/context"
@@ -60,7 +61,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
so.SetNonce(100)
}
so.AddBalance(big.NewInt(int64(i)))
- so.SetCode([]byte{i, i, i})
+ so.SetCode(crypto.Keccak256Hash([]byte{i, i, i}), []byte{i, i, i})
so.UpdateRoot(sdb)
st.UpdateStateObject(so)
}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 7da15cebe..7096b866d 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger/glog"
@@ -219,7 +220,7 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
return nil, err
}
obj := statedb.CreateAccount(common.HexToAddress(addrString))
- obj.SetCode(code)
+ obj.SetCode(crypto.Keccak256Hash(code), code)
obj.SetBalance(balance)
obj.SetNonce(nonce)
for k, v := range acct.Storage {
diff --git a/tests/util.go b/tests/util.go
index 08fac2dd1..ffbcb9d56 100644
--- a/tests/util.go
+++ b/tests/util.go
@@ -108,12 +108,13 @@ func StateObjectFromAccount(db ethdb.Database, addr string, account Account, onD
account.Code = account.Code[2:]
}
code := common.Hex2Bytes(account.Code)
+ codeHash := crypto.Keccak256Hash(code)
obj := state.NewObject(common.HexToAddress(addr), state.Account{
Balance: common.Big(account.Balance),
- CodeHash: crypto.Keccak256(code),
+ CodeHash: codeHash[:],
Nonce: common.Big(account.Nonce).Uint64(),
}, onDirty)
- obj.SetCode(code)
+ obj.SetCode(codeHash, code)
return obj
}