github.com/0xsequence/ethkit@v1.25.0/ethreceipts/finalizer.go (about) 1 package ethreceipts 2 3 import ( 4 "math/big" 5 "sort" 6 "sync" 7 8 "github.com/0xsequence/ethkit" 9 ) 10 11 type finalizer struct { 12 queue []finalTxn 13 txns map[ethkit.Hash]struct{} 14 numBlocksToFinality *big.Int 15 mu sync.Mutex 16 } 17 18 type finalTxn struct { 19 receipt Receipt 20 blockNum *big.Int 21 } 22 23 func (f *finalizer) len() int { 24 f.mu.Lock() 25 defer f.mu.Unlock() 26 return len(f.queue) 27 } 28 29 // func (f *finalizer) lastBlockNum() *big.Int { 30 // f.mu.Lock() 31 // defer f.mu.Unlock() 32 // if len(f.queue) == 0 { 33 // return big.NewInt(0) 34 // } 35 // return f.queue[0].blockNum 36 // } 37 38 func (f *finalizer) enqueue(filterID uint64, receipt Receipt, blockNum *big.Int) { 39 f.mu.Lock() 40 defer f.mu.Unlock() 41 42 if receipt.Final { 43 // do not enqueue if the receipt is already final 44 return 45 } 46 47 txnHash := receipt.TransactionHash() 48 49 // txn id based on the hash + filterID to ensure we get finalize callback for any unique filterID 50 txnID := txnHash 51 if filterID > 0 { 52 for i := 0; i < 8; i++ { 53 txnID[i] = txnID[i] + byte(filterID>>i) 54 } 55 } 56 57 if _, ok := f.txns[txnID]; ok { 58 // update the blockNum if we already have this txn, as it could have been included 59 // again after a reorg in a new block 60 for i, entry := range f.queue { 61 if entry.receipt.TransactionHash() == txnHash { 62 f.queue[i] = finalTxn{receipt, blockNum} 63 } 64 } 65 return 66 } 67 68 // append new 69 f.queue = append(f.queue, finalTxn{receipt, blockNum}) 70 f.txns[txnID] = struct{}{} 71 72 // sort block order from oldest to newest in case of a reorg 73 if len(f.queue) >= 2 && f.queue[0].blockNum.Cmp(f.queue[1].blockNum) < 0 { 74 sort.SliceStable(f.queue, func(i, j int) bool { 75 return f.queue[i].blockNum.Cmp(f.queue[j].blockNum) < 0 76 }) 77 } 78 } 79 80 func (f *finalizer) dequeue(currentBlockNum *big.Int) []finalTxn { 81 f.mu.Lock() 82 defer f.mu.Unlock() 83 84 finalTxns := []finalTxn{} 85 86 for _, txn := range f.queue { 87 if currentBlockNum.Cmp(big.NewInt(0).Add(txn.blockNum, f.numBlocksToFinality)) > 0 { 88 finalTxns = append(finalTxns, txn) 89 } 90 } 91 92 if len(finalTxns) > 0 { 93 f.queue = f.queue[len(finalTxns):] 94 } 95 96 return finalTxns 97 }