@@ -3,6 +3,7 @@ package syncer
33import (
44 "context"
55 "errors"
6+ "math/big"
67
78 "github.com/ethereum/go-ethereum/core/types"
89 "github.com/ethereum/go-ethereum/log"
@@ -52,17 +53,45 @@ func parseLogs() error {
5253}
5354
5455func (s * UnsafeHeadSyncer ) watchLatestUnsafeHead (ctx context.Context ) error {
56+ var currentBlock * big.Int
5557 for {
5658 select {
5759 case newHeader , ok := <- s .newLatestHeadCh :
5860 if ! ok {
5961 return nil
6062 }
63+ blockNum := number .BigToBlockNumber (newHeader .Number )
64+ if currentBlock != nil {
65+ switch newHeader .Number .Cmp (currentBlock ) {
66+ case - 1 , 0 :
67+ prevNum := new (big.Int ).Sub (newHeader .Number , big .NewInt (1 ))
68+ prevBlockNum := number .BigToBlockNumber (prevNum )
69+ // Re-emit the previous block, to pre-emptively signal an
70+ // incoming reorg. Like this a client is able to e.g.
71+ // rewind changes first before processing the new
72+ // events of the reorg
73+ ev := & event.LatestBlock {
74+ Number : prevBlockNum ,
75+ BlockHash : newHeader .ParentHash ,
76+ }
77+ err := s .Handler (ctx , ev )
78+ if err != nil {
79+ // XXX: return or log?
80+ // return err
81+ s .Log .Error (
82+ "handler for `NewLatestBlock` errored" ,
83+ "error" ,
84+ err .Error (),
85+ )
86+ }
87+ case 1 :
88+ // expected
89+ }
90+ }
91+
6192 // TODO: check bloom filter for topic of all
6293 // synced handlers and only call them if
6394 // the bloomfilter retrieves something.
64-
65- blockNum := number .BigToBlockNumber (newHeader .Number )
6695 for _ , h := range s .SyncedHandler {
6796 // NOTE: this has to be blocking!
6897 // So whenever this returns, it is expected
@@ -88,6 +117,7 @@ func (s *UnsafeHeadSyncer) watchLatestUnsafeHead(ctx context.Context) error {
88117 err .Error (),
89118 )
90119 }
120+ currentBlock = newHeader .Number
91121 case <- ctx .Done ():
92122 return ctx .Err ()
93123 }
0 commit comments