core/vm: reuse Keccak-256 hashes across opcode executions (#17863)
This commit is contained in:
parent
c5cb214f68
commit
1d3d4a4d57
@ -24,7 +24,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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"
|
"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) {
|
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
offset, size := stack.pop(), stack.pop()
|
offset, size := stack.pop(), stack.pop()
|
||||||
data := memory.Get(offset.Int64(), size.Int64())
|
data := memory.Get(offset.Int64(), size.Int64())
|
||||||
hash := crypto.Keccak256(data)
|
|
||||||
evm := interpreter.evm
|
|
||||||
|
|
||||||
if evm.vmConfig.EnablePreimageRecording {
|
if interpreter.hasher == nil {
|
||||||
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
interpreter.hasher = sha3.NewKeccak256().(keccakState)
|
||||||
|
} else {
|
||||||
|
interpreter.hasher.Reset()
|
||||||
}
|
}
|
||||||
stack.push(interpreter.intPool.get().SetBytes(hash))
|
interpreter.hasher.Write(data)
|
||||||
|
interpreter.hasher.Read(interpreter.hasherBuf[:])
|
||||||
|
|
||||||
|
evm := interpreter.evm
|
||||||
|
if evm.vmConfig.EnablePreimageRecording {
|
||||||
|
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
|
||||||
|
}
|
||||||
|
stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:]))
|
||||||
|
|
||||||
interpreter.intPool.put(offset, size)
|
interpreter.intPool.put(offset, size)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -492,6 +492,27 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
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) {
|
func TestCreate2Addreses(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
origin string
|
origin string
|
||||||
|
@ -18,8 +18,10 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
@ -68,13 +70,25 @@ type Interpreter interface {
|
|||||||
CanRun([]byte) bool
|
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
|
// EVMInterpreter represents an EVM interpreter
|
||||||
type EVMInterpreter struct {
|
type EVMInterpreter struct {
|
||||||
evm *EVM
|
evm *EVM
|
||||||
cfg Config
|
cfg Config
|
||||||
gasTable params.GasTable
|
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
|
readOnly bool // Whether to throw on stateful modifications
|
||||||
returnData []byte // Last CALL's return data for subsequent reuse
|
returnData []byte // Last CALL's return data for subsequent reuse
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user