Bugfix: the client can miss the genesis event in the absence of new deposits

This commit is contained in:
Zahary Karadjov 2020-11-14 22:51:50 +02:00 committed by zah
parent 9f28a464fb
commit 8012102704
1 changed files with 73 additions and 42 deletions

View File

@ -463,6 +463,13 @@ proc signalGenesis(m: Eth1Monitor, genesisState: BeaconStateRef) =
template hasEnoughValidators(m: Eth1Monitor, blk: Eth1Block): bool = template hasEnoughValidators(m: Eth1Monitor, blk: Eth1Block): bool =
blk.activeValidatorsCount >= m.preset.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT blk.activeValidatorsCount >= m.preset.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
func chainHasEnoughValidators(m: Eth1Monitor): bool =
if m.eth1Chain.blocks.len > 0:
m.hasEnoughValidators(m.eth1Chain.blocks[^1])
else:
m.eth1Chain.knownStart.deposit_count >=
m.preset.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
func isAfterMinGenesisTime(m: Eth1Monitor, blk: Eth1Block): bool = func isAfterMinGenesisTime(m: Eth1Monitor, blk: Eth1Block): bool =
doAssert blk.timestamp != 0 doAssert blk.timestamp != 0
let t = genesis_time_from_eth1_timestamp(m.preset, uint64 blk.timestamp) let t = genesis_time_from_eth1_timestamp(m.preset, uint64 blk.timestamp)
@ -527,21 +534,23 @@ proc stop*(m: Eth1Monitor) =
proc syncBlockRange(m: Eth1Monitor, fromBlock, toBlock: Eth1BlockNumber) {.async.} = proc syncBlockRange(m: Eth1Monitor, fromBlock, toBlock: Eth1BlockNumber) {.async.} =
var currentBlock = fromBlock var currentBlock = fromBlock
while currentBlock <= toBlock: while currentBlock <= toBlock:
var depositLogs: JsonNode = nil var
depositLogs: JsonNode = nil
blocksPerRequest = 5000'u64 # This is roughly a day of Eth1 blocks
maxBlockNumberRequested: Eth1BlockNumber
var blocksPerRequest = 5000'u64 # This is roughly a day of Eth1 blocks
while true: while true:
let requestToBlock = min(toBlock, currentBlock + blocksPerRequest - 1) maxBlockNumberRequested = min(toBlock, currentBlock + blocksPerRequest - 1)
debug "Obtaining deposit log events", debug "Obtaining deposit log events",
fromBlock = currentBlock, fromBlock = currentBlock,
toBlock = requestToBlock toBlock = maxBlockNumberRequested
try: try:
depositLogs = await m.dataProvider.ns.getJsonLogs( depositLogs = await m.dataProvider.ns.getJsonLogs(
DepositEvent, DepositEvent,
fromBlock = some blockId(currentBlock), fromBlock = some blockId(currentBlock),
toBlock = some blockId(requestToBlock)) toBlock = some blockId(maxBlockNumberRequested))
currentBlock = requestToBlock + 1 currentBlock = maxBlockNumberRequested + 1
break break
except CatchableError as err: except CatchableError as err:
blocksPerRequest = blocksPerRequest div 2 blocksPerRequest = blocksPerRequest div 2
@ -568,7 +577,8 @@ proc syncBlockRange(m: Eth1Monitor, fromBlock, toBlock: Eth1BlockNumber) {.async
m.eth1Chain.addBlock blk m.eth1Chain.addBlock blk
if eth1Blocks.len > 0: if eth1Blocks.len > 0:
let lastBlock = eth1Blocks[^1] let lastIdx = eth1Blocks.len - 1
template lastBlock: auto = eth1Blocks[lastIdx]
when hasDepositRootChecks: when hasDepositRootChecks:
let status = await m.dataProvider.fetchDepositContractData(lastBlock) let status = await m.dataProvider.fetchDepositContractData(lastBlock)
@ -582,10 +592,31 @@ proc syncBlockRange(m: Eth1Monitor, fromBlock, toBlock: Eth1BlockNumber) {.async
blockNumber = lastBlock.number, blockNumber = lastBlock.number,
depositsProcessed = lastBlock.voteData.deposit_count depositsProcessed = lastBlock.voteData.deposit_count
if m.genesisStateFut != nil and m.hasEnoughValidators(lastBlock): if m.genesisStateFut != nil and m.chainHasEnoughValidators:
let lastIdx = m.eth1Chain.blocks.len - 1
template lastBlock: auto = m.eth1Chain.blocks[lastIdx]
if maxBlockNumberRequested == toBlock and
(m.eth1Chain.blocks.len == 0 or lastBlock.number != toBlock):
let web3Block = await m.dataProvider.getBlockByNumber(toBlock)
debug "Latest block doesn't hold deposits. Obtaining it",
ts = web3Block.timestamp.uint64,
number = web3Block.number.uint64
m.eth1Chain.addBlock Eth1Block(
number: Eth1BlockNumber web3Block.number,
timestamp: Eth1BlockTimestamp web3Block.timestamp,
voteData: Eth1Data(
block_hash: web3Block.hash.asEth2Digest,
deposit_count: lastBlock.voteData.deposit_count,
deposit_root: lastBlock.voteData.deposit_root),
activeValidatorsCount: lastBlock.activeValidatorsCount)
else:
await m.dataProvider.fetchTimestamp(lastBlock) await m.dataProvider.fetchTimestamp(lastBlock)
if m.isAfterMinGenesisTime(lastBlock):
var genesisBlockIdx = m.eth1Chain.blocks.len - 1 var genesisBlockIdx = m.eth1Chain.blocks.len - 1
if m.isAfterMinGenesisTime(m.eth1Chain.blocks[genesisBlockIdx]):
for i in 1 ..< eth1Blocks.len: for i in 1 ..< eth1Blocks.len:
let idx = (m.eth1Chain.blocks.len - 1) - i let idx = (m.eth1Chain.blocks.len - 1) - i
let blk = m.eth1Chain.blocks[idx] let blk = m.eth1Chain.blocks[idx]
@ -650,7 +681,7 @@ proc handleEth1Progress(m: Eth1Monitor) {.async.} =
await m.syncBlockRange(eth1SyncedTo + 1, targetBlock) await m.syncBlockRange(eth1SyncedTo + 1, targetBlock)
eth1SyncedTo = targetBlock eth1SyncedTo = targetBlock
while m.eth1Chain.blocks.len > 0: while m.eth1Chain.blocks.len > 1:
# We'll clean old blocks that can no longer be voting candidates. # We'll clean old blocks that can no longer be voting candidates.
# Technically, we should check that the block is outside of the current # Technically, we should check that the block is outside of the current
# voting period as determined by its timestamp, but we'll approximate # voting period as determined by its timestamp, but we'll approximate