Signed-off-by: jsvisa <delweng@gmail.com>
This commit is contained in:
Sina Mahmoodi 2023-09-18 18:34:40 +02:00 committed by jsvisa
parent be43dcebac
commit 99188a60b8

View file

@ -358,14 +358,16 @@ func (api *FilterAPI) histLogs(notifier notifier, rpcSub *rpc.Subscription, from
cancel() cancel()
}() }()
var ( var (
// delivered is the block number of the last historical log delivered.
delivered uint64 delivered uint64
// liveOnly is true when all historical logs are delivered // liveMode is true when either:
// and we switch-over to solely returning live logs. // - all historical logs are delivered.
liveOnly bool // - or, during history processing a reorg is detected.
// reorged is true when a reorg is detected. liveMode bool
// Question is if its enough to keep one flag (liveMode). // reorgedBlockHash is the block hash of the reorg point. It is set when
//reorged bool // a reorg is detected in the future. It is used to detect if the history
staleHash common.Hash // processor is sending stale logs.
reorgedBlockHash common.Hash
) )
for { for {
select { select {
@ -376,43 +378,51 @@ func (api *FilterAPI) histLogs(notifier notifier, rpcSub *rpc.Subscription, from
} }
// Else historical logs are all delivered, let's switch to live mode // Else historical logs are all delivered, let's switch to live mode
logger.Info("History logs delivery finished, and now enter into live mode", "delivered", delivered) logger.Info("History logs delivery finished, and now enter into live mode", "delivered", delivered)
liveOnly = true // TODO: It's theoretically possible that we miss logs due to
// asynchrony between the history processor and the chain subscription.
liveMode = true
histLogs = nil histLogs = nil
case logs := <-liveLogs: case logs := <-liveLogs:
if len(logs) == 0 { if len(logs) == 0 {
continue continue
} }
reorgBlock := logs[0].BlockNumber // TODO: further reorgs are possible during history processing.
if !liveOnly && reorgBlock <= delivered { if !liveMode && logs[0].BlockNumber <= delivered {
logger.Info("Reorg detected", "reorgBlock", reorgBlock, "delivered", delivered) // History is being processed and a reorg is encountered.
liveOnly = true // From this point we ignore historical logs coming in and
} // only send logs from the chain subscription.
if !liveOnly && logs[0].Removed && staleHash == (common.Hash{}) { logger.Info("Reorg detected", "reorgBlock", logs[0].BlockNumber, "delivered", delivered)
// Reorg in future. Remember fork point. liveMode = true
staleHash = logs[0].BlockHash // On reorg the chain will send first the removed logs.
continue // Send them up to the block we've delivered historical logs for.
}
if logs[0].Removed {
// Send removed logs notification up until the point
// we have delivered logs from old chain.
notifyLogsIf(notifier, rpcSub.ID, logs, func(log *types.Log) bool { notifyLogsIf(notifier, rpcSub.ID, logs, func(log *types.Log) bool {
return log.BlockNumber <= delivered return log.BlockNumber <= delivered
}) })
} else { continue
// New logs are emitted for the whole new chain since the reorg block.
// Send them all.
notifyLogsIf(notifier, rpcSub.ID, logs, nil)
} }
if !liveMode {
if logs[0].Removed && reorgedBlockHash == (common.Hash{}) {
// Reorg in future. Remember fork point.
reorgedBlockHash = logs[0].BlockHash
}
// Implicit cases:
// - there was a reorg in future and blockchain is sending logs from the new chain.
// - history is still being processed and blockchain sends logs from the tip.
continue
}
// New logs are emitted for the whole new chain since the reorg block.
// Send them all.
notifyLogsIf(notifier, rpcSub.ID, logs, nil)
case logs := <-histLogs: case logs := <-histLogs:
if len(logs) == 0 { if len(logs) == 0 {
continue continue
} }
if liveOnly { if liveMode {
continue continue
} }
if logs[0].BlockHash == staleHash { if logs[0].BlockHash == reorgedBlockHash {
// We have reached the fork point and the historical producer // We have reached the fork point and the historical producer
// is emitting old logs because of delay. Restart the process // is emitting old logs because of delay. Restart the process
// from last delivered block. // from last delivered block.