Fixed new keccak256 implementation that wasn't working properly

This commit is contained in:
Matthieu Vachon 2024-03-15 10:57:39 -04:00
parent d673f1927c
commit 5cf6340406

View file

@ -35,7 +35,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
) )
var firehoseTracerLogLevel = strings.ToLower(os.Getenv("GETH_FIREHOSE_TRACER_LOG_LEVEL")) var firehoseTracerLogLevel = strings.ToLower(os.Getenv("FIREHOSE_ETHEREUM_TRACER_LOG_LEVEL"))
var isFirehoseDebugEnabled = firehoseTracerLogLevel == "debug" || firehoseTracerLogLevel == "trace" var isFirehoseDebugEnabled = firehoseTracerLogLevel == "debug" || firehoseTracerLogLevel == "trace"
var isFirehoseTracerEnabled = firehoseTracerLogLevel == "trace" var isFirehoseTracerEnabled = firehoseTracerLogLevel == "trace"
@ -80,7 +80,8 @@ func newFirehoseTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
OnStorageChange: tracer.OnStorageChange, OnStorageChange: tracer.OnStorageChange,
OnGasChange: tracer.OnGasChange, OnGasChange: tracer.OnGasChange,
OnLog: tracer.OnLog, OnLog: tracer.OnLog,
OnNewAccount: tracer.OnNewAccount,
OnNewAccount: tracer.OnNewAccount,
}, nil }, nil
} }
@ -522,23 +523,41 @@ func (f *Firehose) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.
} }
if opCode == vm.KECCAK256 { if opCode == vm.KECCAK256 {
f.onOpcodeSha3(activeCall, scope.StackData(), Memory(scope.MemoryData())) f.onOpcodeKeccak256(activeCall, scope.StackData(), Memory(scope.MemoryData()))
} }
} }
} }
type Memory []byte // onOpcodeKeccak256 is called during the SHA3 (a.k.a KECCAK256) opcode it's known
// in Firehose tracer as Keccak preimages. The preimage is the input data that
func (m Memory) GetPtr(offset, size int64) []byte { // was used to produce the given keccak hash.
if size == 0 { func (f *Firehose) onOpcodeKeccak256(call *pbeth.Call, stack []uint256.Int, memory Memory) {
return nil if call.KeccakPreimages == nil {
call.KeccakPreimages = make(map[string]string)
} }
if len(m) > int(offset) { offset, size := stack[len(stack)-1], stack[len(stack)-2]
return m[offset : offset+size] preImage := memory.GetPtrUint256(&offset, &size)
// We should have exclusive access to the hasher, we can safely reset it.
f.hasher.Reset()
f.hasher.Write(preImage)
f.hasher.Read(f.hasherBuf[:])
// Known Firehose issue: It appears the old Firehose instrumentation have a bug
// where when the keccak256 preimage is empty, it is written as "." which is
// completely wrong.
//
// To keep the same behavior, we will write the preimage as a "." when the encoded
// data is an empty string.
//
// For new chain, this code should be remove so that we just keep `hex.EncodeToString(data)`.
encodedData := hex.EncodeToString(preImage)
if encodedData == "" {
encodedData = "."
} }
return nil call.KeccakPreimages[hex.EncodeToString(f.hasherBuf[:])] = encodedData
} }
var opCodeToGasChangeReasonMap = map[vm.OpCode]pbeth.GasChange_Reason{ var opCodeToGasChangeReasonMap = map[vm.OpCode]pbeth.GasChange_Reason{
@ -562,38 +581,6 @@ var opCodeToGasChangeReasonMap = map[vm.OpCode]pbeth.GasChange_Reason{
vm.RETURNDATACOPY: pbeth.GasChange_REASON_RETURN_DATA_COPY, vm.RETURNDATACOPY: pbeth.GasChange_REASON_RETURN_DATA_COPY,
} }
// onOpcodeSha3 is called during the SHA3 (a.k.a KECCAK256) opcode it's known
// in Firehose tracer as Keccak preimages. The preimage is the input data that
// was used to produce the given keccak hash.
func (f *Firehose) onOpcodeSha3(call *pbeth.Call, stack []uint256.Int, memory Memory) {
if call.KeccakPreimages == nil {
call.KeccakPreimages = make(map[string]string)
}
offset, size := stack[0], stack[1]
preImage := memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
// We should have exclusive access to the hasher, we can safely reset it.
f.hasher.Reset()
f.hasher.Write(preImage)
f.hasher.Read(f.hasherBuf[:])
// Known Firehose issue: It appears the old Firehose instrumentation have a bug
// where when the keccak256 preimage is empty, it is written as "." which is
// completely wrong.
//
// To keep the same behavior, we will write the preimage as a "." when the encoded
// data is an empty string.
//
// For new chain, this code should be remove so that we just keep `hex.EncodeToString(data)`.
encodedData := hex.EncodeToString(preImage)
if encodedData == "" {
encodedData = "."
}
call.KeccakPreimages[hex.EncodeToString(f.hasherBuf[:])] = encodedData
}
// OnOpcodeFault implements the EVMLogger interface to trace an execution fault. // OnOpcodeFault implements the EVMLogger interface to trace an execution fault.
func (f *Firehose) OnOpcodeFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { func (f *Firehose) OnOpcodeFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
if activeCall := f.callStack.Peek(); activeCall != nil { if activeCall := f.callStack.Peek(); activeCall != nil {
@ -675,13 +662,13 @@ func (f *Firehose) getExecutedCode(evm *tracing.VMContext, call *pbeth.Call) boo
if !evm.StateDB.Exist(common.BytesToAddress(call.Address)) && if !evm.StateDB.Exist(common.BytesToAddress(call.Address)) &&
!precompile && f.blockRules.IsEIP158 && !precompile && f.blockRules.IsEIP158 &&
(call.Value == nil || call.Value.Native().Sign() == 0) { (call.Value == nil || call.Value.Native().Sign() == 0) {
firehoseDebug("executed code IsSpuriousDragon callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) firehoseDebug("executed code IsSpuriousDragon callType=%s inputLength=%d", call.CallType.String(), len(call.Input))
return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0
} }
} }
if precompile { if precompile {
firehoseDebug("executed code isprecompile callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) firehoseDebug("executed code isprecompile callType=%s inputLength=%d", call.CallType.String(), len(call.Input))
return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0
} }
@ -691,7 +678,7 @@ func (f *Firehose) getExecutedCode(evm *tracing.VMContext, call *pbeth.Call) boo
return false return false
} }
firehoseDebug("executed code default callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) firehoseDebug("executed code default callType=%s inputLength=%d", call.CallType.String(), len(call.Input))
return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0
} }
@ -1973,3 +1960,21 @@ func validateField[T any](into *validationResult, field string, a, b T, equal bo
func ptr[T any](t T) *T { func ptr[T any](t T) *T {
return &t return &t
} }
type Memory []byte
func (m Memory) GetPtrUint256(offset, size *uint256.Int) []byte {
return m.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
}
func (m Memory) GetPtr(offset, size int64) []byte {
if size == 0 {
return nil
}
if len(m) > int(offset) {
return m[offset : offset+size]
}
return nil
}