More fixes towards a 1-1 Firehose tracer against old model

This commit is contained in:
Matthieu Vachon 2023-07-27 15:37:36 -04:00
parent 9af0334dff
commit b797e5d261

View file

@ -48,8 +48,9 @@ type Firehose struct {
blockLogIndex uint32 blockLogIndex uint32
// Transaction state // Transaction state
inTransaction *atomic.Bool inTransaction *atomic.Bool
transaction *pbeth.TransactionTrace transaction *pbeth.TransactionTrace
transactionLogIndex uint32
// Call state // Call state
callStack *CallStack callStack *CallStack
@ -69,7 +70,8 @@ func NewFirehoseLogger() *Firehose {
blockOrdinal: &Ordinal{}, blockOrdinal: &Ordinal{},
blockLogIndex: 0, blockLogIndex: 0,
inTransaction: atomic.NewBool(false), inTransaction: atomic.NewBool(false),
transactionLogIndex: 0,
callStack: &CallStack{}, callStack: &CallStack{},
deferredCallState: &DeferredCallState{}, deferredCallState: &DeferredCallState{},
@ -89,6 +91,7 @@ func (f *Firehose) resetBlock() {
// resetTransaction resets the transaction state and the call state in one shot // resetTransaction resets the transaction state and the call state in one shot
func (f *Firehose) resetTransaction() { func (f *Firehose) resetTransaction() {
f.inTransaction.Store(false) f.inTransaction.Store(false)
f.transactionLogIndex = 0
f.callStack.Reset() f.callStack.Reset()
f.latestCallStartSuicided = false f.latestCallStartSuicided = false
@ -194,6 +197,10 @@ func (f *Firehose) completeTransaction(receipt *types.Receipt) *pbeth.Transactio
return i.Index < j.Index return i.Index < j.Index
}) })
if !f.deferredCallState.IsEmpty() {
f.deferredCallState.MaybePopulateCallAndReset("root", f.transaction.Calls[0])
}
// Receipt can be nil if an error occurred during the transaction execution, right now we don't have it // Receipt can be nil if an error occurred during the transaction execution, right now we don't have it
if receipt != nil { if receipt != nil {
f.transaction.Index = uint32(receipt.TransactionIndex) f.transaction.Index = uint32(receipt.TransactionIndex)
@ -286,11 +293,18 @@ func (f *Firehose) callStart(source string, callType pbeth.CallType, from common
call.BeginOrdinal = 0 call.BeginOrdinal = 0
} }
if callType == pbeth.CallType_CREATE {
// Replicates a previous bug in Firehose instrumentation where create calls input is always
// set to `nil` (this was done on purpose but it missed the fact that we are missing the
// actual input data of the constuctor call, if present and invoked).
call.Input = nil
}
f.callStack.Push(call) f.callStack.Push(call)
} }
func (f *Firehose) callEnd(source string, output []byte, gasUsed uint64, err error) { func (f *Firehose) callEnd(source string, output []byte, gasUsed uint64, err error) {
firehoseDebug("call end source=%s err=%s", source, errorView(err)) firehoseDebug("call end source=%s output=%s gasUsed=%d err=%s", source, outputView(output), gasUsed, errorView(err))
if f.latestCallStartSuicided { if f.latestCallStartSuicided {
if source != "child" { if source != "child" {
@ -326,7 +340,16 @@ func (f *Firehose) callEnd(source string, output []byte, gasUsed uint64, err err
} }
// CaptureKeccakPreimage is called during the KECCAK256 opcode. // CaptureKeccakPreimage is called during the KECCAK256 opcode.
func (f *Firehose) CaptureKeccakPreimage(hash common.Hash, data []byte) {} func (f *Firehose) CaptureKeccakPreimage(hash common.Hash, data []byte) {
f.ensureInBlockAndInTrxAndInCall()
activeCall := f.callStack.Peek()
if activeCall.KeccakPreimages == nil {
activeCall.KeccakPreimages = make(map[string]string)
}
activeCall.KeccakPreimages[hex.EncodeToString(hash.Bytes())] = hex.EncodeToString(data)
}
func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) {
// FIXME: Re-implement by actualling callin `OnBlockStart/OnTrxStart/CaptureStart` etc. // FIXME: Re-implement by actualling callin `OnBlockStart/OnTrxStart/CaptureStart` etc.
@ -548,11 +571,12 @@ func (f *Firehose) OnLog(l *types.Log) {
Address: l.Address.Bytes(), Address: l.Address.Bytes(),
Topics: topics, Topics: topics,
Data: l.Data, Data: l.Data,
Index: uint32(l.TxIndex), Index: f.transactionLogIndex,
BlockIndex: f.blockLogIndex, BlockIndex: uint32(l.Index),
Ordinal: f.blockOrdinal.Next(), Ordinal: f.blockOrdinal.Next(),
}) })
f.transactionLogIndex++
f.blockLogIndex++ f.blockLogIndex++
} }
@ -569,10 +593,15 @@ func (f *Firehose) OnNewAccount(a common.Address) {
func (f *Firehose) OnGasConsumed(gas, amount uint64) { func (f *Firehose) OnGasConsumed(gas, amount uint64) {
f.ensureInBlockAndInTrx() f.ensureInBlockAndInTrx()
if amount == 0 {
return
}
activeCall := f.callStack.Peek() activeCall := f.callStack.Peek()
change := &pbeth.GasChange{ change := &pbeth.GasChange{
OldValue: gas, OldValue: gas,
NewValue: gas + amount, NewValue: gas + amount,
Ordinal: f.blockOrdinal.Next(),
} }
// There is an initial gas consumption happening will the call is not yet started, we track it manually // There is an initial gas consumption happening will the call is not yet started, we track it manually
@ -810,7 +839,7 @@ func newTxReceiptFromChain(receipt *types.Receipt) (out *pbeth.TransactionReceip
if len(receipt.Logs) > 0 { if len(receipt.Logs) > 0 {
out.Logs = make([]*pbeth.Log, len(receipt.Logs)) out.Logs = make([]*pbeth.Log, len(receipt.Logs))
for i, log := range receipt.Logs { for i, log := range receipt.Logs {
out.Logs = append(out.Logs, &pbeth.Log{ out.Logs[i] = &pbeth.Log{
Address: log.Address.Bytes(), Address: log.Address.Bytes(),
Topics: func() [][]byte { Topics: func() [][]byte {
if len(log.Topics) == 0 { if len(log.Topics) == 0 {
@ -829,7 +858,7 @@ func newTxReceiptFromChain(receipt *types.Receipt) (out *pbeth.TransactionReceip
// FIXME: Fix ordinal for logs in receipt! // FIXME: Fix ordinal for logs in receipt!
// Ordinal: uint64, // Ordinal: uint64,
}) }
} }
} }
@ -978,11 +1007,13 @@ func (o *Ordinal) Next() (out uint64) {
type CallStack struct { type CallStack struct {
index uint32 index uint32
stack []*pbeth.Call stack []*pbeth.Call
depth int
} }
func (s *CallStack) Reset() { func (s *CallStack) Reset() {
s.index = 0 s.index = 0
s.stack = s.stack[:0] s.stack = s.stack[:0]
s.depth = 0
} }
func (s *CallStack) HasActiveCall() bool { func (s *CallStack) HasActiveCall() bool {
@ -996,6 +1027,9 @@ func (s *CallStack) Push(call *pbeth.Call) {
s.index++ s.index++
call.Index = s.index call.Index = s.index
call.Depth = uint32(s.depth)
s.depth++
// If a current call is active, it's the parent of this call // If a current call is active, it's the parent of this call
if parent := s.Peek(); parent != nil { if parent := s.Peek(); parent != nil {
call.ParentIndex = parent.Index call.ParentIndex = parent.Index
@ -1011,6 +1045,8 @@ func (s *CallStack) Pop() (out *pbeth.Call) {
out = s.stack[len(s.stack)-1] out = s.stack[len(s.stack)-1]
s.stack = s.stack[:len(s.stack)-1] s.stack = s.stack[:len(s.stack)-1]
s.depth--
return return
} }
@ -1042,9 +1078,10 @@ func (d *DeferredCallState) MaybePopulateCallAndReset(source string, call *pbeth
return fmt.Errorf("unexpected source for deferred call state, expected root but got %s, deferred call's state are always produced on the 'root' call", source) return fmt.Errorf("unexpected source for deferred call state, expected root but got %s, deferred call's state are always produced on the 'root' call", source)
} }
call.BalanceChanges = d.balanceChanges // We must happen because it's populated at beginning of the call as well as at the very end
call.GasChanges = d.gasChanges call.BalanceChanges = append(call.BalanceChanges, d.balanceChanges...)
call.NonceChanges = d.nonceChanges call.GasChanges = append(call.GasChanges, d.gasChanges...)
call.NonceChanges = append(call.NonceChanges, d.nonceChanges...)
d.Reset() d.Reset()
@ -1100,6 +1137,16 @@ func (b inputView) String() string {
return fmt.Sprintf("%d bytes", len(rest)) return fmt.Sprintf("%d bytes", len(rest))
} }
type outputView []byte
func (b outputView) String() string {
if len(b) == 0 {
return "<empty>"
}
return fmt.Sprintf("%d bytes", len(b))
}
type receiptView types.Receipt type receiptView types.Receipt
func (r *receiptView) String() string { func (r *receiptView) String() string {