import EL deposits even when EL is stuck (#3956)

* import EL deposits even when EL is stuck

The `eth1_monitor` only starts importing deposits once the EL reports a
new head block. However, the EL may be stuck at a block, e.g., the TTD.
By polling the latest EL block once after subscribing to new EL block
events it is ensured that deposits are still imported in this situation.

* also poll once on re-connects

* update `eth1_latest_head` metric in poll mode

* add comment about similar polling vs events parts

* replace check with assert

* `isNewLastBlock` helper
This commit is contained in:
Etan Kissling 2022-08-12 21:44:55 +02:00 committed by GitHub
parent b1974d90eb
commit 052f9edfd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 15 additions and 13 deletions

View File

@ -1314,6 +1314,9 @@ proc syncBlockRange(m: Eth1Monitor,
func init(T: type FullBlockId, blk: Eth1BlockHeader|BlockObject): T =
FullBlockId(number: Eth1BlockNumber blk.number, hash: blk.hash)
func isNewLastBlock(m: Eth1Monitor, blk: Eth1BlockHeader|BlockObject): bool =
blk.number.uint64 > m.latestEth1BlockNumber
proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
if m.state == Started:
return
@ -1401,7 +1404,7 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
proc newBlockHeadersHandler(blk: Eth1BlockHeader)
{.raises: [Defect], gcsafe.} =
try:
if blk.number.uint64 > m.latestEth1BlockNumber:
if m.isNewLastBlock(blk):
eth1_latest_head.set blk.number.toGaugeValue
m.latestEth1Block = some FullBlockId.init(blk)
m.eth1Progress.fire()
@ -1440,6 +1443,7 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
debug "Starting Eth1 syncing", `from` = shortLog(m.depositsChain.blocks[^1])
var didPollOnce = false
while true:
if bnStatus == BeaconNodeStatus.Stopping:
when hasGenesisDetection:
@ -1457,18 +1461,21 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
m.startIdx = 0
return
let nextBlock = if mustUsePolling:
let nextBlock = if mustUsePolling or not didPollOnce:
let blk = awaitWithRetries(
m.dataProvider.web3.provider.eth_getBlockByNumber(blockId("latest"), false))
let fullBlockId = FullBlockId.init(blk)
if m.latestEth1Block.isSome and
m.latestEth1Block.get == fullBlockId:
# Same as when handling events, minus `m.eth1Progress` round trip
if m.isNewLastBlock(blk):
eth1_latest_head.set blk.number.toGaugeValue
m.latestEth1Block = some FullBlockId.init(blk)
elif mustUsePolling:
await sleepAsync(m.cfg.SECONDS_PER_ETH1_BLOCK.int.seconds)
continue
else:
doAssert not didPollOnce
m.latestEth1Block = some fullBlockId
didPollOnce = true
blk
else:
awaitWithTimeout(m.eth1Progress.wait(), 5.minutes):
@ -1476,12 +1483,7 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
m.eth1Progress.clear()
if m.latestEth1Block.isNone:
# It should not be possible for `latestEth1Block` to be none here.
# Firing the `eth1Progress` event is always done after assinging
# a value for it.
continue
doAssert m.latestEth1Block.isSome
awaitWithRetries m.dataProvider.getBlockByHash(m.latestEth1Block.get.hash)
if m.currentEpoch >= m.cfg.BELLATRIX_FORK_EPOCH and m.terminalBlockHash.isNone: