4
4
"bytes"
5
5
"encoding/base64"
6
6
"encoding/hex"
7
+ "encoding/json"
7
8
"errors"
8
9
"fmt"
9
10
"io"
@@ -110,7 +111,6 @@ func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.He
110
111
firehoseDebug ("block start number=%d hash=%s" , b .NumberU64 (), b .Hash ())
111
112
112
113
f .ensureNotInBlock ()
113
-
114
114
f .block = & pbeth.Block {
115
115
Hash : b .Hash ().Bytes (),
116
116
Number : b .Number ().Uint64 (),
@@ -127,6 +127,14 @@ func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.He
127
127
f .blockFinality .populateFromChain (finalized )
128
128
}
129
129
130
+ func (f * Firehose ) OnBlockUpdate (b * types.Block , td * big.Int ) {
131
+ f .ensureInBlock ()
132
+ f .block .Hash = b .Hash ().Bytes ()
133
+ f .block .Number = b .Number ().Uint64 ()
134
+ f .block .Header = newBlockHeaderFromChainBlock (b , firehoseBigIntFromNative (new (big.Int ).Add (td , b .Difficulty ())))
135
+ f .block .Size = b .Size ()
136
+ }
137
+
130
138
func (f * Firehose ) OnBlockEnd (err error ) {
131
139
firehoseDebug ("block ending err=%s" , errorView (err ))
132
140
@@ -164,6 +172,14 @@ func (f *Firehose) CaptureTxStart(evm *vm.EVM, tx *types.Transaction) {
164
172
}
165
173
166
174
f .captureTxStart (tx , tx .Hash (), from , to , evm .IsPrecompileAddr )
175
+
176
+ switch tx .Type () {
177
+ case types .ArbitrumDepositTxType , types .ArbitrumSubmitRetryableTxType , types .ArbitrumInternalTxType :
178
+ firehoseDebug ("Adding simulated root call to arbitrum tx hash=%s type=%d gas=%d input=%s" , tx .Hash (), tx .Type (), tx .Gas (), inputView (tx .Data ()))
179
+ f .callStart ("root" , pbeth .CallType_CALL , from , * tx .To (), tx .Data (), tx .Gas (), tx .Value ())
180
+ }
181
+ return
182
+
167
183
}
168
184
169
185
// captureTxStart is used internally a two places, in the normal "tracer" and in the "OnGenesisBlock",
@@ -198,6 +214,12 @@ func (f *Firehose) CaptureTxEnd(receipt *types.Receipt, err error) {
198
214
firehoseDebug ("trx ending" )
199
215
f .ensureInBlockAndInTrx ()
200
216
217
+ switch receipt .Type {
218
+ case types .ArbitrumDepositTxType , types .ArbitrumSubmitRetryableTxType , types .ArbitrumInternalTxType :
219
+ firehoseDebug ("Closing simulated root call to arbitrum tx type=%d" , receipt .Type )
220
+ f .callEnd ("root" , nil , receipt .GasUsed , err )
221
+ }
222
+
201
223
f .block .TransactionTraces = append (f .block .TransactionTraces , f .completeTransaction (receipt ))
202
224
203
225
// The reset must be done as the very last thing as the CallStack needs to be
@@ -275,6 +297,7 @@ func (f *Firehose) removeLogBlockIndexOnStateRevertedCalls() {
275
297
if call .StateReverted {
276
298
for _ , log := range call .Logs {
277
299
log .BlockIndex = 0
300
+ log .Index = 0
278
301
}
279
302
}
280
303
}
@@ -299,26 +322,45 @@ func (f *Firehose) assignOrdinalToReceiptLogs() {
299
322
})
300
323
301
324
if len (callLogs ) != len (receiptsLogs ) {
325
+ j , err := json .Marshal (trx )
326
+ if err != nil {
327
+ firehoseDebug ("error marshalling trx during panic handling: %s" , err )
328
+ }
329
+
330
+ firehoseDebug ("got this transaction: %s" , string (j ))
302
331
panic (fmt .Errorf (
303
332
"mismatch between Firehose call logs and Ethereum transaction receipt logs, transaction receipt has %d logs but there is %d Firehose call logs" ,
304
333
len (receiptsLogs ),
305
334
len (callLogs ),
306
335
))
307
336
}
308
337
338
+ var txIndex uint32 = 0
339
+ for _ , log := range callLogs {
340
+ log .Index = txIndex
341
+ txIndex ++
342
+ }
343
+
309
344
for i := 0 ; i < len (callLogs ); i ++ {
310
345
callLog := callLogs [i ]
311
346
receiptsLog := receiptsLogs [i ]
312
347
313
348
result := & validationResult {}
314
349
// Ordinal must **not** be checked as we are assigning it here below after the validations
315
350
validateBytesField (result , "Address" , callLog .Address , receiptsLog .Address )
316
- validateUint32Field (result , "Index" , callLog .Index , receiptsLog .Index )
351
+ // validateUint32Field(result, "Index", callLog.Index, receiptsLog.Index)
317
352
validateUint32Field (result , "BlockIndex" , callLog .BlockIndex , receiptsLog .BlockIndex )
318
353
validateBytesField (result , "Data" , callLog .Data , receiptsLog .Data )
319
354
validateArrayOfBytesField (result , "Topics" , callLog .Topics , receiptsLog .Topics )
320
355
321
356
if len (result .failures ) > 0 {
357
+ for i , ll := range callLogs {
358
+ result .failures = append (result .failures , fmt .Sprintf ("log %d, idx %d" , i , ll .Index ))
359
+ }
360
+ for i , ll := range receiptsLogs {
361
+ result .failures = append (result .failures , fmt .Sprintf ("theirs: log %d, idx %d" , i , ll .Index ))
362
+ }
363
+
322
364
result .panicOnAnyFailures ("mismatch between Firehose call log and Ethereum transaction receipt log at index %d" , i )
323
365
}
324
366
@@ -653,7 +695,15 @@ func (f *Firehose) newBalanceChange(tag string, address common.Address, oldValue
653
695
}
654
696
}
655
697
698
+ // maybe useful later
699
+ // var arbosAddress = common.HexToAddress("A4B05FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
700
+
656
701
func (f * Firehose ) OnNonceChange (a common.Address , prev , new uint64 ) {
702
+ if new == prev {
703
+ firehoseDebug ("skipping NonceChange new==prev (%d)" , prev )
704
+ return
705
+ }
706
+
657
707
f .ensureInBlockAndInTrx ()
658
708
659
709
activeCall := f .callStack .Peek ()
@@ -698,51 +748,79 @@ func (f *Firehose) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev
698
748
}
699
749
700
750
func (f * Firehose ) OnStorageChange (a common.Address , k , prev , new common.Hash ) {
701
- f .ensureInBlockAndInTrxAndInCall ()
751
+ firehoseTrace ("on storage change addr=%s" , a )
752
+
753
+ f .ensureInBlockAndInTrx ()
702
754
703
755
activeCall := f .callStack .Peek ()
704
- activeCall . StorageChanges = append ( activeCall . StorageChanges , & pbeth.StorageChange {
756
+ change := & pbeth.StorageChange {
705
757
Address : a .Bytes (),
706
758
Key : k .Bytes (),
707
759
OldValue : prev .Bytes (),
708
760
NewValue : new .Bytes (),
709
761
Ordinal : f .blockOrdinal .Next (),
710
- })
762
+ }
763
+
764
+ // There is an initial gas consumption happening will the call is not yet started, we track it manually
765
+ if activeCall == nil {
766
+ f .deferredCallState .storageChanges = append (f .deferredCallState .storageChanges , change )
767
+ return
768
+ }
769
+
770
+ activeCall .StorageChanges = append (activeCall .StorageChanges , change )
771
+
711
772
}
712
773
713
774
func (f * Firehose ) OnLog (l * types.Log ) {
714
- f .ensureInBlockAndInTrxAndInCall ()
775
+
776
+ firehoseTrace ("on log addr=%s topics=%d, txindex=%d" , l .Address , len (l .Topics ), f .transactionLogIndex )
777
+
778
+ f .ensureInBlockAndInTrx ()
715
779
716
780
topics := make ([][]byte , len (l .Topics ))
717
781
for i , topic := range l .Topics {
718
782
topics [i ] = topic .Bytes ()
719
783
}
720
784
721
- activeCall := f .callStack .Peek ()
722
- activeCall .Logs = append (activeCall .Logs , & pbeth.Log {
785
+ log := & pbeth.Log {
723
786
Address : l .Address .Bytes (),
724
787
Topics : topics ,
725
788
Data : l .Data ,
726
789
Index : f .transactionLogIndex ,
727
790
BlockIndex : uint32 (l .Index ),
728
791
Ordinal : f .blockOrdinal .Next (),
729
- })
792
+ }
730
793
731
794
f .transactionLogIndex ++
795
+
796
+ activeCall := f .callStack .Peek ()
797
+ if activeCall == nil {
798
+ f .deferredCallState .logs = append (f .deferredCallState .logs , log )
799
+ return
800
+ }
801
+
802
+ activeCall .Logs = append (activeCall .Logs , log )
732
803
}
733
804
734
805
func (f * Firehose ) OnNewAccount (a common.Address ) {
735
- f .ensureInBlockAndInTrxAndInCall ()
806
+ f .ensureInBlockAndInTrx ()
736
807
737
808
if f .isPrecompiledAddr (a ) {
738
809
return
739
810
}
740
811
741
- activeCall := f .callStack .Peek ()
742
- activeCall .AccountCreations = append (activeCall .AccountCreations , & pbeth.AccountCreation {
812
+ acc := & pbeth.AccountCreation {
743
813
Account : a .Bytes (),
744
814
Ordinal : f .blockOrdinal .Next (),
745
- })
815
+ }
816
+
817
+ activeCall := f .callStack .Peek ()
818
+ if activeCall == nil {
819
+ f .deferredCallState .accountCreations = append (f .deferredCallState .accountCreations , acc )
820
+ return
821
+ }
822
+
823
+ activeCall .AccountCreations = append (activeCall .AccountCreations )
746
824
}
747
825
748
826
func (f * Firehose ) OnGasConsumed (gas , amount uint64 , reason vm.GasChangeReason ) {
@@ -869,6 +947,7 @@ func (f *Firehose) ensureInCall() {
869
947
}
870
948
871
949
func (f * Firehose ) panicNotInState (msg string ) string {
950
+ firehoseDebugPrintStack ()
872
951
panic (fmt .Errorf ("%s (inBlock=%t, inTransaction=%t, inCall=%t)" , msg , f .block != nil , f .transaction != nil , f .callStack .HasActiveCall ()))
873
952
}
874
953
@@ -1307,9 +1386,12 @@ func (s *CallStack) Peek() *pbeth.Call {
1307
1386
// that is recorded before the Call has been started. This happens on the "starting"
1308
1387
// portion of the call/created.
1309
1388
type DeferredCallState struct {
1310
- balanceChanges []* pbeth.BalanceChange
1311
- gasChanges []* pbeth.GasChange
1312
- nonceChanges []* pbeth.NonceChange
1389
+ balanceChanges []* pbeth.BalanceChange
1390
+ gasChanges []* pbeth.GasChange
1391
+ storageChanges []* pbeth.StorageChange
1392
+ logs []* pbeth.Log
1393
+ accountCreations []* pbeth.AccountCreation
1394
+ nonceChanges []* pbeth.NonceChange
1313
1395
}
1314
1396
1315
1397
func NewDeferredCallState () * DeferredCallState {
@@ -1328,6 +1410,9 @@ func (d *DeferredCallState) MaybePopulateCallAndReset(source string, call *pbeth
1328
1410
// We must happen because it's populated at beginning of the call as well as at the very end
1329
1411
call .BalanceChanges = append (call .BalanceChanges , d .balanceChanges ... )
1330
1412
call .GasChanges = append (call .GasChanges , d .gasChanges ... )
1413
+ call .StorageChanges = append (call .StorageChanges , d .storageChanges ... )
1414
+ call .Logs = append (call .Logs , d .logs ... )
1415
+ call .AccountCreations = append (call .AccountCreations , d .accountCreations ... )
1331
1416
call .NonceChanges = append (call .NonceChanges , d .nonceChanges ... )
1332
1417
1333
1418
d .Reset ()
@@ -1336,12 +1421,15 @@ func (d *DeferredCallState) MaybePopulateCallAndReset(source string, call *pbeth
1336
1421
}
1337
1422
1338
1423
func (d * DeferredCallState ) IsEmpty () bool {
1339
- return len (d .balanceChanges ) == 0 && len (d .gasChanges ) == 0 && len (d .nonceChanges ) == 0
1424
+ return len (d .balanceChanges ) == 0 && len (d .gasChanges ) == 0 && len (d .nonceChanges ) == 0 && len ( d . storageChanges ) == 0 && len ( d . logs ) == 0
1340
1425
}
1341
1426
1342
1427
func (d * DeferredCallState ) Reset () {
1343
1428
d .balanceChanges = nil
1344
1429
d .gasChanges = nil
1430
+ d .storageChanges = nil
1431
+ d .logs = nil
1432
+ d .accountCreations = nil
1345
1433
d .nonceChanges = nil
1346
1434
}
1347
1435
0 commit comments