aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2018-10-08 19:14:29 +0800
committerFelix Lange <fjl@users.noreply.github.com>2018-10-08 19:14:29 +0800
commit1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b (patch)
tree00ce13af5e001692be11412e2e8e372bd9c0bbc5 /core
parentc5cb214f689e5c34bf487daa8eb4234d6e3237a7 (diff)
downloadgo-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.gz
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.bz2
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.lz
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.xz
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.tar.zst
go-tangerine-1d3d4a4d578825b040a3cac9eb163e7f3c16ce4b.zip
core/vm: reuse Keccak-256 hashes across opcode executions (#17863)
Diffstat (limited to 'core')
-rw-r--r--core/vm/instructions.go17
-rw-r--r--core/vm/instructions_test.go21
-rw-r--r--core/vm/interpreter.go16
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