diff options
author | Péter Szilágyi <peterke@gmail.com> | 2018-10-08 19:14:29 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2018-10-08 19:14:29 +0800 |
commit | 1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b (patch) | |
tree | 00ce13af5e001692be11412e2e8e372bd9c0bbc5 | |
parent | c5cb214f689e5c34bf487daa8eb4234d6e3237a7 (diff) | |
download | dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.gz dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.bz2 dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.lz dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.xz dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.zst dexon-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.zip |
core/vm: reuse Keccak-256 hashes across opcode executions (#17863)
-rw-r--r-- | core/vm/instructions.go | 17 | ||||
-rw-r--r-- | core/vm/instructions_test.go | 21 | ||||
-rw-r--r-- | core/vm/interpreter.go | 16 |
3 files changed, 48 insertions, 6 deletions
diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9623fb8de..e94a2777b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/params" ) @@ -373,13 +373,20 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() data := memory.Get(offset.Int64(), size.Int64()) - hash := crypto.Keccak256(data) - evm := interpreter.evm + if interpreter.hasher == nil { + interpreter.hasher = sha3.NewKeccak256().(keccakState) + } else { + interpreter.hasher.Reset() + } + interpreter.hasher.Write(data) + interpreter.hasher.Read(interpreter.hasherBuf[:]) + + evm := interpreter.evm if evm.vmConfig.EnablePreimageRecording { - evm.StateDB.AddPreimage(common.BytesToHash(hash), data) + evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - stack.push(interpreter.intPool.get().SetBytes(hash)) + stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) interpreter.intPool.put(offset, size) return nil, nil diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 73c5befaa..8a48d765d 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -492,6 +492,27 @@ func BenchmarkOpMstore(bench *testing.B) { poolOfIntPools.put(evmInterpreter.intPool) } +func BenchmarkOpSHA3(bench *testing.B) { + var ( + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + ) + env.interpreter = evmInterpreter + evmInterpreter.intPool = poolOfIntPools.get() + mem.Resize(32) + pc := uint64(0) + start := big.NewInt(0) + + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + stack.pushN(big.NewInt(32), start) + opSha3(&pc, evmInterpreter, nil, mem, stack) + } + poolOfIntPools.put(evmInterpreter.intPool) +} + func TestCreate2Addreses(t *testing.T) { type testcase struct { origin string diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 8e934f60e..952d96dd4 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,8 +18,10 @@ package vm import ( "fmt" + "hash" "sync/atomic" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" ) @@ -68,12 +70,24 @@ type Interpreter interface { CanRun([]byte) bool } +// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports +// Read to get a variable amount of data from the hash state. Read is faster than Sum +// because it doesn't copy the internal state, but also modifies the internal state. +type keccakState interface { + hash.Hash + Read([]byte) (int, error) +} + // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { evm *EVM cfg Config gasTable params.GasTable - intPool *intPool + + intPool *intPool + + hasher keccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes readOnly bool // Whether to throw on stateful modifications returnData []byte // Last CALL's return data for subsequent reuse |