diff --git a/Makefile b/Makefile index 059aa71cc..4e220fe35 100644 --- a/Makefile +++ b/Makefile @@ -601,7 +601,6 @@ gnosis-build gnosis-chain-build: | build deps $(NIM_PARAMS) \ -d:gnosisChainBinary \ -d:const_preset=gnosis \ - -d:has_genesis_detection \ && \ echo -e $(BUILD_END_MSG) "build/nimbus_beacon_node_gnosis" diff --git a/beacon_chain/eth1/eth1_monitor.nim b/beacon_chain/eth1/eth1_monitor.nim index c1d6d881a..318aa81a8 100644 --- a/beacon_chain/eth1/eth1_monitor.nim +++ b/beacon_chain/eth1/eth1_monitor.nim @@ -59,7 +59,6 @@ contract(DepositContract): const web3Timeouts = 60.seconds hasDepositRootChecks = defined(has_deposit_root_checks) - hasGenesisDetection* = defined(has_genesis_detection) targetBlocksPerLogsRequest = 5000'u64 # This is roughly a day of Eth1 blocks @@ -85,9 +84,6 @@ type ## Global deposits count and hash tree root of the entire sequence ## These are computed when the block is added to the chain (see `addBlock`) - when hasGenesisDetection: - activeValidatorsCount*: uint64 - Eth1Chain* = object db: BeaconChainDB cfg: RuntimeConfig @@ -143,12 +139,6 @@ type ttdReachedField: bool - when hasGenesisDetection: - genesisValidators: seq[ImmutableValidatorData] - genesisValidatorKeyToIndex: Table[ValidatorPubKey, ValidatorIndex] - genesisState: GenesisStateRef - genesisStateFut: Future[void] - Web3DataProvider* = object url: string web3: Web3 @@ -204,72 +194,6 @@ func ttdReached*(m: Eth1Monitor): bool = template cfg(m: Eth1Monitor): auto = m.depositsChain.cfg -when hasGenesisDetection: - import ../spec/[beaconstate, signatures] - - template hasEnoughValidators(m: Eth1Monitor, blk: Eth1Block): bool = - blk.activeValidatorsCount >= m.cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - - func chainHasEnoughValidators(m: Eth1Monitor): bool = - m.depositsChain.blocks.len > 0 and m.hasEnoughValidators(m.depositsChain.blocks[^1]) - - func isAfterMinGenesisTime(m: Eth1Monitor, blk: Eth1Block): bool = - doAssert blk.timestamp != 0 - let t = genesis_time_from_eth1_timestamp(m.cfg, uint64 blk.timestamp) - t >= m.cfg.MIN_GENESIS_TIME - - func isGenesisCandidate(m: Eth1Monitor, blk: Eth1Block): bool = - m.hasEnoughValidators(blk) and m.isAfterMinGenesisTime(blk) - - proc findGenesisBlockInRange(m: Eth1Monitor, startBlock, endBlock: Eth1Block): - Future[Eth1Block] {.gcsafe.} - - proc signalGenesis(m: Eth1Monitor, genesisState: GenesisStateRef) = - m.genesisState = genesisState - - if not m.genesisStateFut.isNil: - m.genesisStateFut.complete() - m.genesisStateFut = nil - - func allGenesisDepositsUpTo(m: Eth1Monitor, totalDeposits: uint64): seq[DepositData] = - for i in 0 ..< int64(totalDeposits): - result.add m.depositsChain.db.genesisDeposits.get(i) - - proc createGenesisState(m: Eth1Monitor, eth1Block: Eth1Block): GenesisStateRef = - notice "Generating genesis state", - blockNum = eth1Block.number, - blockHash = eth1Block.hash, - blockTimestamp = eth1Block.timestamp, - totalDeposits = eth1Block.depositCount, - activeValidators = eth1Block.activeValidatorsCount - - var deposits = m.allGenesisDepositsUpTo(eth1Block.depositCount) - - result = newClone(initialize_beacon_state_from_eth1( - m.cfg, - eth1Block.hash, - eth1Block.timestamp.uint64, - deposits, {})) - - if eth1Block.activeValidatorsCount != 0: - doAssert result.validators.lenu64 == eth1Block.activeValidatorsCount - - proc produceDerivedData(m: Eth1Monitor, deposit: DepositData) = - let htr = hash_tree_root(deposit) - - if verify_deposit_signature(m.cfg, deposit): - let pubkey = deposit.pubkey - if pubkey notin m.genesisValidatorKeyToIndex: - let idx = ValidatorIndex m.genesisValidators.len - m.genesisValidators.add ImmutableValidatorData( - pubkey: pubkey, - withdrawal_credentials: deposit.withdrawal_credentials) - m.genesisValidatorKeyToIndex[pubkey] = idx - - proc processGenesisDeposit*(m: Eth1Monitor, newDeposit: DepositData) = - m.depositsChain.db.genesisDeposits.add newDeposit - m.produceDerivedData(newDeposit) - template depositChainBlocks*(m: Eth1Monitor): Deque[Eth1Block] = m.depositsChain.blocks @@ -508,9 +432,6 @@ func makeSuccessorWithoutDeposits(existingBlock: Eth1Block, number: Eth1BlockNumber successor.number, timestamp: Eth1BlockTimestamp successor.timestamp) - when hasGenesisDetection: - result.activeValidatorsCount = existingBlock.activeValidatorsCount - func latestCandidateBlock(chain: Eth1Chain, periodStart: uint64): Eth1Block = for i in countdown(chain.blocks.len - 1, 0): let blk = chain.blocks[i] @@ -1423,74 +1344,6 @@ proc syncBlockRange(m: Eth1Monitor, blockNumber = lastBlock.number, depositsProcessed = lastBlock.depositCount - when hasGenesisDetection: - if blocksWithDeposits.len > 0: - for blk in blocksWithDeposits: - for deposit in blk.deposits: - m.processGenesisDeposit(deposit) - blk.activeValidatorsCount = m.genesisValidators.lenu64 - - let - lastBlock = blocksWithDeposits[^1] - depositTreeSnapshot = DepositTreeSnapshot( - eth1Block: lastBlock.hash, - depositContractState: m.headMerkleizer.toDepositContractState, - blockHeight: lastBlock.number) - - m.depositsChain.db.putDepositTreeSnapshot depositTreeSnapshot - - if m.genesisStateFut != nil and m.chainHasEnoughValidators: - let lastIdx = m.depositsChain.blocks.len - 1 - template lastBlock: auto = m.depositsChain.blocks[lastIdx] - - if maxBlockNumberRequested == toBlock and - (m.depositsChain.blocks.len == 0 or lastBlock.number != toBlock): - let web3Block = awaitWithRetries( - m.dataProvider.getBlockByNumber(toBlock)) - - debug "Latest block doesn't hold deposits. Obtaining it", - ts = web3Block.timestamp.uint64, - number = web3Block.number.uint64 - - m.depositsChain.addBlock lastBlock.makeSuccessorWithoutDeposits(web3Block) - else: - await lastBlock.fetchTimestampWithRetries(m.dataProvider) - - var genesisBlockIdx = m.depositsChain.blocks.len - 1 - if m.isAfterMinGenesisTime(m.depositsChain.blocks[genesisBlockIdx]): - for i in 1 ..< blocksWithDeposits.len: - let idx = (m.depositsChain.blocks.len - 1) - i - let blk = m.depositsChain.blocks[idx] - await blk.fetchTimestampWithRetries(m.dataProvider) - if m.isGenesisCandidate(blk): - genesisBlockIdx = idx - else: - break - # We have a candidate state on our hands, but our current Eth1Chain - # may consist only of blocks that have deposits attached to them - # while the real genesis may have happened in a block without any - # deposits (triggered by MIN_GENESIS_TIME). - # - # This can happen when the beacon node is launched after the genesis - # event. We take a short cut when constructing the initial Eth1Chain - # by downloading only deposit log entries. Thus, we'll see all the - # blocks with deposits, but not the regular blocks in between. - # - # We'll handle this special case below by examing whether we are in - # this potential scenario and we'll use a fast guessing algorith to - # discover the ETh1 block with minimal valid genesis time. - var genesisBlock = m.depositsChain.blocks[genesisBlockIdx] - if genesisBlockIdx > 0: - let genesisParent = m.depositsChain.blocks[genesisBlockIdx - 1] - if genesisParent.timestamp == 0: - await genesisParent.fetchTimestampWithRetries(m.dataProvider) - if m.hasEnoughValidators(genesisParent) and - genesisBlock.number - genesisParent.number > 1: - genesisBlock = awaitWithRetries( - m.findGenesisBlockInRange(genesisParent, genesisBlock)) - - m.signalGenesis m.createGenesisState(genesisBlock) - func init(T: type FullBlockId, blk: Eth1BlockHeader|BlockObject): T = FullBlockId(number: Eth1BlockNumber blk.number, hash: blk.hash) @@ -1681,10 +1534,6 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} = var didPollOnce = false while true: if bnStatus == BeaconNodeStatus.Stopping: - when hasGenesisDetection: - if not m.genesisStateFut.isNil: - m.genesisStateFut.complete() - m.genesisStateFut = nil await m.stop() return @@ -1827,70 +1676,3 @@ proc testWeb3Provider*(web3Url: Uri, depositRoot = request "Deposit root": ns.get_deposit_root.call(blockNumber = latestBlock.number.uint64) - -when hasGenesisDetection: - proc loadPersistedDeposits*(monitor: Eth1Monitor) = - for i in 0 ..< monitor.depositsChain.db.genesisDeposits.len: - monitor.produceDerivedData monitor.depositsChain.db.genesisDeposits.get(i) - - proc findGenesisBlockInRange(m: Eth1Monitor, startBlock, endBlock: Eth1Block): - Future[Eth1Block] {.async.} = - doAssert m.dataProvider != nil, "close not called concurrently" - doAssert startBlock.timestamp != 0 and not m.isAfterMinGenesisTime(startBlock) - doAssert endBlock.timestamp != 0 and m.isAfterMinGenesisTime(endBlock) - doAssert m.hasEnoughValidators(startBlock) - doAssert m.hasEnoughValidators(endBlock) - - var - startBlock = startBlock - endBlock = endBlock - activeValidatorsCountDuringRange = startBlock.activeValidatorsCount - - while startBlock.number + 1 < endBlock.number: - let - MIN_GENESIS_TIME = m.cfg.MIN_GENESIS_TIME - startBlockTime = genesis_time_from_eth1_timestamp(m.cfg, startBlock.timestamp) - secondsPerBlock = float(endBlock.timestamp - startBlock.timestamp) / - float(endBlock.number - startBlock.number) - blocksToJump = max(float(MIN_GENESIS_TIME - startBlockTime) / secondsPerBlock, 1.0) - candidateNumber = min(endBlock.number - 1, startBlock.number + blocksToJump.uint64) - candidateBlock = awaitWithRetries( - m.dataProvider.getBlockByNumber(candidateNumber)) - - var candidateAsEth1Block = Eth1Block(hash: candidateBlock.hash.asEth2Digest, - number: candidateBlock.number.uint64, - timestamp: candidateBlock.timestamp.uint64) - - let candidateGenesisTime = genesis_time_from_eth1_timestamp( - m.cfg, candidateBlock.timestamp.uint64) - - notice "Probing possible genesis block", - `block` = candidateBlock.number.uint64, - candidateGenesisTime - - if candidateGenesisTime < MIN_GENESIS_TIME: - startBlock = candidateAsEth1Block - else: - endBlock = candidateAsEth1Block - - if endBlock.activeValidatorsCount == 0: - endBlock.activeValidatorsCount = activeValidatorsCountDuringRange - - return endBlock - - proc waitGenesis*(m: Eth1Monitor): Future[GenesisStateRef] {.async.} = - if m.genesisState.isNil: - m.start() - - if m.genesisStateFut.isNil: - m.genesisStateFut = newFuture[void]("waitGenesis") - - info "Awaiting genesis event" - await m.genesisStateFut - m.genesisStateFut = nil - - if m.genesisState != nil: - return m.genesisState - else: - doAssert bnStatus == BeaconNodeStatus.Stopping - return nil diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index f9a879ed4..540abf7ea 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -492,51 +492,9 @@ proc init*(T: type BeaconNode, if not ChainDAGRef.isInitialized(db).isOk(): if genesisState == nil and checkpointState == nil: - when hasGenesisDetection: - # This is a fresh start without a known genesis state - # (most likely, it hasn't arrived yet). We'll try to - # obtain a genesis through the Eth1 deposits monitor: - if config.web3Urls.len == 0: - fatal "Web3 URL not specified" - quit 1 - - # TODO Could move this to a separate "GenesisMonitor" process or task - # that would do only this - see Paul's proposal for this. - let eth1Monitor = Eth1Monitor.init( - cfg, - metadata.depositContractBlock, - metadata.depositContractBlockHash, - db, - nil, - config.web3Urls, - eth1Network, - config.web3ForcePolling, - optJwtSecret, - ttdReached = false) - - eth1Monitor.loadPersistedDeposits() - - let phase0Genesis = waitFor eth1Monitor.waitGenesis() - genesisState = (ref ForkedHashedBeaconState)( - kind: BeaconStateFork.Phase0, - phase0Data: - (ref phase0.HashedBeaconState)( - data: phase0Genesis[], - root: hash_tree_root(phase0Genesis[]))[]) - - if bnStatus == BeaconNodeStatus.Stopping: - return nil - - notice "Eth2 genesis state detected", - genesisTime = phase0Genesis.genesisTime, - eth1Block = phase0Genesis.eth1_data.block_hash, - totalDeposits = phase0Genesis.eth1_data.deposit_count - else: - fatal "No database and no genesis snapshot found: supply a genesis.ssz " & - "with the network configuration, or compile the beacon node with " & - "the -d:has_genesis_detection option " & - "in order to support monitoring for genesis events" - quit 1 + fatal "No database and no genesis snapshot found. Please supply a genesis.ssz " & + "with the network configuration" + quit 1 if not genesisState.isNil and not checkpointState.isNil: if getStateField(genesisState[], genesis_validators_root) !=