2021-03-26 06:52:01 +00:00
|
|
|
# beacon_chain
|
|
|
|
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
2018-11-26 13:33:06 +00:00
|
|
|
import
|
2021-12-03 15:04:58 +00:00
|
|
|
std/[deques, options, strformat, strutils, sequtils, tables,
|
2021-09-29 19:26:27 +00:00
|
|
|
typetraits, uri, json],
|
2020-12-09 22:44:59 +00:00
|
|
|
# Nimble packages:
|
2022-01-03 12:22:56 +00:00
|
|
|
chronos, json, metrics, chronicles/timings, stint/endians2,
|
2021-10-14 11:29:02 +00:00
|
|
|
web3, web3/ethtypes as web3Types, web3/ethhexstrings, web3/engine_api,
|
2021-09-29 19:26:27 +00:00
|
|
|
eth/common/eth_types,
|
2021-12-03 15:04:58 +00:00
|
|
|
eth/async_utils, stew/[objects, byteutils, shims/hashes],
|
2020-12-09 22:44:59 +00:00
|
|
|
# Local modules:
|
2021-08-18 18:57:58 +00:00
|
|
|
../spec/[eth2_merkleization, forks, helpers],
|
2021-12-23 14:58:54 +00:00
|
|
|
../spec/datatypes/[base, phase0, merge],
|
2021-03-05 13:12:00 +00:00
|
|
|
../networking/network_metadata,
|
2021-05-21 09:23:28 +00:00
|
|
|
../consensus_object_pools/block_pools_types,
|
2021-03-05 13:12:00 +00:00
|
|
|
".."/[beacon_chain_db, beacon_node_status],
|
2021-03-03 06:23:05 +00:00
|
|
|
./merkle_minimal
|
2018-11-26 13:33:06 +00:00
|
|
|
|
2020-06-19 17:42:28 +00:00
|
|
|
export
|
2021-08-27 09:00:06 +00:00
|
|
|
web3Types, deques
|
2020-06-19 17:42:28 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
logScope:
|
|
|
|
topics = "eth1"
|
|
|
|
|
2021-10-14 12:33:55 +00:00
|
|
|
type
|
|
|
|
PubKeyBytes = DynamicBytes[48, 48]
|
|
|
|
WithdrawalCredentialsBytes = DynamicBytes[32, 32]
|
|
|
|
SignatureBytes = DynamicBytes[96, 96]
|
|
|
|
Int64LeBytes = DynamicBytes[8, 8]
|
|
|
|
|
2020-03-24 11:13:07 +00:00
|
|
|
contract(DepositContract):
|
2021-10-14 12:33:55 +00:00
|
|
|
proc deposit(pubkey: PubKeyBytes,
|
|
|
|
withdrawalCredentials: WithdrawalCredentialsBytes,
|
|
|
|
signature: SignatureBytes,
|
2020-03-24 11:13:07 +00:00
|
|
|
deposit_data_root: FixedBytes[32])
|
|
|
|
|
|
|
|
proc get_deposit_root(): FixedBytes[32]
|
2021-10-14 12:33:55 +00:00
|
|
|
proc get_deposit_count(): Int64LeBytes
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2021-10-14 12:33:55 +00:00
|
|
|
proc DepositEvent(pubkey: PubKeyBytes,
|
|
|
|
withdrawalCredentials: WithdrawalCredentialsBytes,
|
|
|
|
amount: Int64LeBytes,
|
|
|
|
signature: SignatureBytes,
|
|
|
|
index: Int64LeBytes) {.event.}
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
const
|
2020-11-24 21:28:20 +00:00
|
|
|
web3Timeouts = 60.seconds
|
2020-12-15 23:09:19 +00:00
|
|
|
hasDepositRootChecks = defined(has_deposit_root_checks)
|
|
|
|
hasGenesisDetection* = defined(has_genesis_detection)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2018-11-26 13:33:06 +00:00
|
|
|
type
|
2020-03-24 11:13:07 +00:00
|
|
|
Eth1BlockNumber* = uint64
|
|
|
|
Eth1BlockTimestamp* = uint64
|
2020-07-02 15:14:11 +00:00
|
|
|
Eth1BlockHeader = web3Types.BlockHeader
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
GenesisStateRef = ref phase0.BeaconState
|
2020-10-12 01:07:20 +00:00
|
|
|
|
2020-03-24 11:13:07 +00:00
|
|
|
Eth1Block* = ref object
|
|
|
|
number*: Eth1BlockNumber
|
|
|
|
timestamp*: Eth1BlockTimestamp
|
2020-11-24 21:21:47 +00:00
|
|
|
deposits*: seq[DepositData]
|
2020-03-24 11:13:07 +00:00
|
|
|
voteData*: Eth1Data
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
when hasGenesisDetection:
|
|
|
|
activeValidatorsCount*: uint64
|
2020-06-25 23:33:06 +00:00
|
|
|
|
2021-05-17 16:37:26 +00:00
|
|
|
DepositsMerkleizer* = SszMerkleizer[depositContractLimit]
|
|
|
|
|
2020-03-24 11:13:07 +00:00
|
|
|
Eth1Chain* = object
|
2020-12-03 04:30:35 +00:00
|
|
|
db: BeaconChainDB
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
cfg: RuntimeConfig
|
2020-12-03 04:30:35 +00:00
|
|
|
finalizedBlockHash: Eth2Digest
|
|
|
|
finalizedDepositsMerkleizer: DepositsMerkleizer
|
2022-01-03 12:22:56 +00:00
|
|
|
|
|
|
|
## The latest block that reached a 50% majority vote from
|
|
|
|
## the Eth2 validators according to the follow distance and
|
|
|
|
## the ETH1_VOTING_PERIOD
|
|
|
|
|
|
|
|
blocks: Deque[Eth1Block]
|
|
|
|
## A non-forkable chain of blocks ending at the block with
|
|
|
|
## ETH1_FOLLOW_DISTANCE offset from the head.
|
|
|
|
|
|
|
|
blocksByHash: Table[BlockHash, Eth1Block]
|
|
|
|
|
2021-01-29 21:21:44 +00:00
|
|
|
hasConsensusViolation: bool
|
|
|
|
## The local chain contradicts the observed consensus on the network
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
Eth1MonitorState = enum
|
|
|
|
Initialized
|
|
|
|
Started
|
|
|
|
Failed
|
|
|
|
Stopping
|
|
|
|
Stopped
|
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
Eth1Monitor* = ref object
|
2020-12-15 21:59:29 +00:00
|
|
|
state: Eth1MonitorState
|
2021-04-06 21:42:59 +00:00
|
|
|
startIdx: int
|
|
|
|
web3Urls: seq[string]
|
2020-12-15 21:59:29 +00:00
|
|
|
eth1Network: Option[Eth1Network]
|
|
|
|
depositContractAddress*: Eth1Address
|
2021-11-25 16:51:51 +00:00
|
|
|
forcePolling: bool
|
2020-10-14 14:04:08 +00:00
|
|
|
|
|
|
|
dataProvider: Web3DataProviderRef
|
2021-11-25 16:51:51 +00:00
|
|
|
latestEth1Block: Option[FullBlockId]
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
depositsChain: Eth1Chain
|
2020-11-03 01:21:07 +00:00
|
|
|
eth1Progress: AsyncEvent
|
|
|
|
|
2019-11-22 13:16:07 +00:00
|
|
|
runFut: Future[void]
|
2020-12-15 21:59:29 +00:00
|
|
|
stopFut: Future[void]
|
2019-11-22 13:16:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
when hasGenesisDetection:
|
2020-12-15 21:59:29 +00:00
|
|
|
genesisValidators: seq[ImmutableValidatorData]
|
|
|
|
genesisValidatorKeyToIndex: Table[ValidatorPubKey, ValidatorIndex]
|
2021-12-23 14:58:54 +00:00
|
|
|
genesisState: GenesisStateRef
|
2020-11-24 21:21:47 +00:00
|
|
|
genesisStateFut: Future[void]
|
|
|
|
|
2020-10-14 14:04:08 +00:00
|
|
|
Web3DataProvider* = object
|
2020-03-24 11:13:07 +00:00
|
|
|
url: string
|
|
|
|
web3: Web3
|
|
|
|
ns: Sender[DepositContract]
|
2020-06-27 12:01:19 +00:00
|
|
|
blockHeadersSubscription: Subscription
|
2020-03-24 11:13:07 +00:00
|
|
|
|
|
|
|
Web3DataProviderRef* = ref Web3DataProvider
|
|
|
|
|
2021-11-25 16:51:51 +00:00
|
|
|
FullBlockId* = object
|
|
|
|
number: Eth1BlockNumber
|
|
|
|
hash: BlockHash
|
|
|
|
|
2021-05-28 12:42:39 +00:00
|
|
|
DataProviderFailure* = object of CatchableError
|
|
|
|
CorruptDataProvider* = object of DataProviderFailure
|
|
|
|
DataProviderTimeout* = object of DataProviderFailure
|
2020-03-24 11:13:07 +00:00
|
|
|
|
|
|
|
DisconnectHandler* = proc () {.gcsafe, raises: [Defect].}
|
|
|
|
|
|
|
|
DepositEventHandler* = proc (
|
2021-10-14 12:33:55 +00:00
|
|
|
pubkey: PubKeyBytes,
|
|
|
|
withdrawalCredentials: WithdrawalCredentialsBytes,
|
|
|
|
amount: Int64LeBytes,
|
|
|
|
signature: SignatureBytes,
|
|
|
|
merkleTreeIndex: Int64LeBytes,
|
|
|
|
j: JsonNode) {.gcsafe, raises: [Defect].}
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
BlockProposalEth1Data* = object
|
|
|
|
vote*: Eth1Data
|
|
|
|
deposits*: seq[Deposit]
|
2020-11-24 21:21:47 +00:00
|
|
|
hasMissingDeposits*: bool
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2020-12-09 22:44:59 +00:00
|
|
|
declareCounter failed_web3_requests,
|
|
|
|
"Failed web3 requests"
|
|
|
|
|
|
|
|
declareGauge eth1_latest_head,
|
|
|
|
"The highest Eth1 block number observed on the network"
|
|
|
|
|
|
|
|
declareGauge eth1_synced_head,
|
|
|
|
"Block number of the highest synchronized block according to follow distance"
|
|
|
|
|
|
|
|
declareGauge eth1_finalized_head,
|
|
|
|
"Block number of the highest Eth1 block finalized by Eth2 consensus"
|
|
|
|
|
|
|
|
declareGauge eth1_finalized_deposits,
|
|
|
|
"Number of deposits that were finalized by the Eth2 consensus"
|
|
|
|
|
|
|
|
declareGauge eth1_chain_len,
|
|
|
|
"The length of the in-memory chain of Eth1 blocks"
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
func depositCountU64(s: DepositContractState): uint64 =
|
|
|
|
for i in 0 .. 23:
|
|
|
|
doAssert s.deposit_count[i] == 0
|
|
|
|
|
2022-01-03 17:17:10 +00:00
|
|
|
uint64.fromBytesBE s.deposit_count.toOpenArray(24, 31)
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
template cfg(m: Eth1Monitor): auto =
|
|
|
|
m.depositsChain.cfg
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
when hasGenesisDetection:
|
2021-12-23 14:58:54 +00:00
|
|
|
import ../spec/[beaconstate, signatures]
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
template hasEnoughValidators(m: Eth1Monitor, blk: Eth1Block): bool =
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
blk.activeValidatorsCount >= m.cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
func chainHasEnoughValidators(m: Eth1Monitor): bool =
|
2021-12-23 14:58:54 +00:00
|
|
|
m.depositsChain.blocks.len > 0 and m.hasEnoughValidators(m.depositsChain.blocks[^1])
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
func isAfterMinGenesisTime(m: Eth1Monitor, blk: Eth1Block): bool =
|
|
|
|
doAssert blk.timestamp != 0
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
let t = genesis_time_from_eth1_timestamp(m.cfg, uint64 blk.timestamp)
|
|
|
|
t >= m.cfg.MIN_GENESIS_TIME
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
func isGenesisCandidate(m: Eth1Monitor, blk: Eth1Block): bool =
|
|
|
|
m.hasEnoughValidators(blk) and m.isAfterMinGenesisTime(blk)
|
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc findGenesisBlockInRange(m: Eth1Monitor, startBlock, endBlock: Eth1Block):
|
|
|
|
Future[Eth1Block] {.gcsafe.}
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc signalGenesis(m: Eth1Monitor, genesisState: GenesisStateRef) =
|
2020-12-15 21:59:29 +00:00
|
|
|
m.genesisState = genesisState
|
2020-10-14 14:04:08 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
if not m.genesisStateFut.isNil:
|
|
|
|
m.genesisStateFut.complete()
|
|
|
|
m.genesisStateFut = nil
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func allGenesisDepositsUpTo(m: Eth1Monitor, totalDeposits: uint64): seq[DepositData] =
|
2021-12-23 14:58:54 +00:00
|
|
|
for i in 0 ..< int64(totalDeposits):
|
|
|
|
result.add m.depositsChain.db.genesisDeposits.get(i)
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc createGenesisState(m: Eth1Monitor, eth1Block: Eth1Block): GenesisStateRef =
|
2020-12-15 21:59:29 +00:00
|
|
|
notice "Generating genesis state",
|
|
|
|
blockNum = eth1Block.number,
|
|
|
|
blockHash = eth1Block.voteData.block_hash,
|
|
|
|
blockTimestamp = eth1Block.timestamp,
|
|
|
|
totalDeposits = eth1Block.voteData.deposit_count,
|
|
|
|
activeValidators = eth1Block.activeValidatorsCount
|
|
|
|
|
|
|
|
var deposits = m.allGenesisDepositsUpTo(eth1Block.voteData.deposit_count)
|
|
|
|
|
2021-11-18 12:02:43 +00:00
|
|
|
result = newClone(initialize_beacon_state_from_eth1(
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
m.cfg,
|
2020-12-15 21:59:29 +00:00
|
|
|
eth1Block.voteData.block_hash,
|
|
|
|
eth1Block.timestamp.uint64,
|
2021-11-18 12:02:43 +00:00
|
|
|
deposits, {}))
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
if eth1Block.activeValidatorsCount != 0:
|
|
|
|
doAssert result.validators.lenu64 == eth1Block.activeValidatorsCount
|
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc produceDerivedData(m: Eth1Monitor, deposit: DepositData) =
|
2020-12-15 21:59:29 +00:00
|
|
|
let htr = hash_tree_root(deposit)
|
|
|
|
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
if verify_deposit_signature(m.cfg, deposit):
|
2020-12-15 21:59:29 +00:00
|
|
|
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)
|
2021-05-17 16:37:26 +00:00
|
|
|
m.genesisValidatorKeyToIndex[pubkey] = idx
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc processGenesisDeposit*(m: Eth1Monitor, newDeposit: DepositData) =
|
|
|
|
m.depositsChain.db.genesisDeposits.add newDeposit
|
2020-12-15 21:59:29 +00:00
|
|
|
m.produceDerivedData(newDeposit)
|
2020-10-14 14:04:08 +00:00
|
|
|
|
2022-01-03 12:22:56 +00:00
|
|
|
template depositChainBlocks*(m: Eth1Monitor): Deque[Eth1Block] =
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.blocks
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
template finalizedDepositsMerkleizer(m: Eth1Monitor): auto =
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.finalizedDepositsMerkleizer
|
2020-12-03 04:30:35 +00:00
|
|
|
|
2020-11-12 13:49:13 +00:00
|
|
|
proc fixupWeb3Urls*(web3Url: var string) =
|
2021-12-03 12:14:21 +00:00
|
|
|
## Converts HTTP and HTTPS Infura URLs to their WebSocket equivalents
|
|
|
|
## because we are missing a functional HTTPS client.
|
|
|
|
let normalizedUrl = toLowerAscii(web3Url)
|
|
|
|
var pos = 0
|
|
|
|
|
|
|
|
template skip(x: string): bool {.dirty.} =
|
|
|
|
if normalizedUrl.len - pos >= x.len and
|
|
|
|
normalizedUrl.toOpenArray(pos, pos + x.len - 1) == x:
|
|
|
|
pos += x.len
|
|
|
|
true
|
|
|
|
else:
|
|
|
|
false
|
|
|
|
|
|
|
|
if not (skip("https://") or skip("http://")):
|
|
|
|
if not (skip("ws://") or skip("wss://")):
|
|
|
|
web3Url = "ws://" & web3Url
|
|
|
|
warn "The Web3 URL does not specify a protocol. Assuming a WebSocket server", web3Url
|
|
|
|
return
|
|
|
|
|
|
|
|
block infuraRewrite:
|
|
|
|
var pos = pos
|
|
|
|
let network = if skip("mainnet"): mainnet
|
|
|
|
elif skip("goerli"): goerli
|
|
|
|
else: break
|
|
|
|
|
|
|
|
if not skip(".infura.io/v3/"):
|
|
|
|
break
|
|
|
|
|
|
|
|
template infuraKey: string = normalizedUrl.substr(pos)
|
|
|
|
|
|
|
|
web3Url = "wss://" & $network & ".infura.io/ws/v3/" & infuraKey
|
|
|
|
return
|
|
|
|
|
|
|
|
block gethRewrite:
|
|
|
|
web3Url = "ws://" & normalizedUrl.substr(pos)
|
|
|
|
warn "Only WebSocket web3 providers are supported. Rewriting URL", web3Url
|
2020-11-05 23:11:06 +00:00
|
|
|
|
2020-12-09 22:44:59 +00:00
|
|
|
template toGaugeValue(x: Quantity): int64 =
|
|
|
|
toGaugeValue(distinctBase x)
|
|
|
|
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
# TODO: Add cfg validation
|
2020-07-07 23:02:14 +00:00
|
|
|
# MIN_GENESIS_ACTIVE_VALIDATOR_COUNT should be larger than SLOTS_PER_EPOCH
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
# doAssert SECONDS_PER_ETH1_BLOCK * cfg.ETH1_FOLLOW_DISTANCE < GENESIS_DELAY,
|
2020-07-07 23:02:14 +00:00
|
|
|
# "Invalid configuration: GENESIS_DELAY is set too low"
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2022-01-04 03:57:15 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/validator.md#get_eth1_data
|
2021-06-11 17:51:46 +00:00
|
|
|
func compute_time_at_slot(genesis_time: uint64, slot: Slot): uint64 =
|
|
|
|
genesis_time + slot * SECONDS_PER_SLOT
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2022-01-04 03:57:15 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/validator.md#get_eth1_data
|
2021-12-05 17:32:41 +00:00
|
|
|
func voting_period_start_time(state: ForkedHashedBeaconState): uint64 =
|
2020-06-15 09:38:05 +00:00
|
|
|
let eth1_voting_period_start_slot =
|
2021-05-21 09:23:28 +00:00
|
|
|
getStateField(state, slot) - getStateField(state, slot) mod
|
|
|
|
SLOTS_PER_ETH1_VOTING_PERIOD.uint64
|
2021-06-11 17:51:46 +00:00
|
|
|
compute_time_at_slot(
|
|
|
|
getStateField(state, genesis_time), eth1_voting_period_start_slot)
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2022-01-04 03:57:15 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/validator.md#get_eth1_data
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
func is_candidate_block(cfg: RuntimeConfig,
|
2020-11-20 14:05:37 +00:00
|
|
|
blk: Eth1Block,
|
|
|
|
period_start: uint64): bool =
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
(blk.timestamp + cfg.SECONDS_PER_ETH1_BLOCK * cfg.ETH1_FOLLOW_DISTANCE <= period_start) and
|
|
|
|
(blk.timestamp + cfg.SECONDS_PER_ETH1_BLOCK * cfg.ETH1_FOLLOW_DISTANCE * 2 >= period_start)
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-06-19 17:42:28 +00:00
|
|
|
func asEth2Digest*(x: BlockHash): Eth2Digest =
|
2020-03-24 11:13:07 +00:00
|
|
|
Eth2Digest(data: array[32, byte](x))
|
|
|
|
|
|
|
|
template asBlockHash(x: Eth2Digest): BlockHash =
|
|
|
|
BlockHash(x.data)
|
|
|
|
|
2022-01-03 12:22:56 +00:00
|
|
|
func asConsensusExecutionPayload*(rpcExecutionPayload: ExecutionPayloadV1):
|
|
|
|
merge.ExecutionPayload =
|
|
|
|
template getTransaction(t: TypedTransaction): merge.Transaction =
|
|
|
|
merge.Transaction.init(t.distinctBase)
|
|
|
|
|
|
|
|
merge.ExecutionPayload(
|
|
|
|
parent_hash: rpcExecutionPayload.parentHash.asEth2Digest,
|
|
|
|
feeRecipient:
|
|
|
|
ExecutionAddress(data: rpcExecutionPayload.feeRecipient.distinctBase),
|
|
|
|
state_root: rpcExecutionPayload.stateRoot.asEth2Digest,
|
|
|
|
receipts_root: rpcExecutionPayload.receiptsRoot.asEth2Digest,
|
|
|
|
logs_bloom: BloomLogs(data: rpcExecutionPayload.logsBloom.distinctBase),
|
|
|
|
random: rpcExecutionPayload.random.asEth2Digest,
|
|
|
|
block_number: rpcExecutionPayload.blockNumber.uint64,
|
|
|
|
gas_limit: rpcExecutionPayload.gasLimit.uint64,
|
|
|
|
gas_used: rpcExecutionPayload.gasUsed.uint64,
|
|
|
|
timestamp: rpcExecutionPayload.timestamp.uint64,
|
|
|
|
extra_data:
|
|
|
|
List[byte, MAX_EXTRA_DATA_BYTES].init(
|
|
|
|
rpcExecutionPayload.extraData.distinctBase),
|
|
|
|
base_fee_per_gas:
|
|
|
|
Eth2Digest(data: rpcExecutionPayload.baseFeePerGas.toBytesLE),
|
|
|
|
block_hash: rpcExecutionPayload.blockHash.asEth2Digest,
|
|
|
|
transactions: List[merge.Transaction, MAX_TRANSACTIONS_PER_PAYLOAD].init(
|
|
|
|
mapIt(rpcExecutionPayload.transactions, it.getTransaction)))
|
|
|
|
|
|
|
|
func asEngineExecutionPayload*(executionPayload: merge.ExecutionPayload):
|
|
|
|
ExecutionPayloadV1 =
|
|
|
|
template getTypedTransaction(t: merge.Transaction): TypedTransaction =
|
|
|
|
TypedTransaction(t.distinctBase)
|
|
|
|
|
|
|
|
engine_api.ExecutionPayloadV1(
|
|
|
|
parentHash: executionPayload.parent_hash.asBlockHash,
|
|
|
|
feeRecipient: Address(executionPayload.feeRecipient.data),
|
|
|
|
stateRoot: executionPayload.state_root.asBlockHash,
|
|
|
|
receiptsRoot: executionPayload.receipts_root.asBlockHash,
|
|
|
|
logsBloom:
|
|
|
|
FixedBytes[BYTES_PER_LOGS_BLOOM](executionPayload.logs_bloom.data),
|
|
|
|
random: executionPayload.random.asBlockHash,
|
|
|
|
blockNumber: Quantity(executionPayload.block_number),
|
|
|
|
gasLimit: Quantity(executionPayload.gas_limit),
|
|
|
|
gasUsed: Quantity(executionPayload.gas_used),
|
|
|
|
timestamp: Quantity(executionPayload.timestamp),
|
|
|
|
extraData:
|
|
|
|
DynamicBytes[0, MAX_EXTRA_DATA_BYTES](executionPayload.extra_data),
|
|
|
|
baseFeePerGas:
|
|
|
|
UInt256.fromBytesLE(executionPayload.base_fee_per_gas.data),
|
|
|
|
blockHash: executionPayload.block_hash.asBlockHash,
|
|
|
|
transactions: mapIt(executionPayload.transactions, it.getTypedTransaction))
|
|
|
|
|
2020-09-06 08:39:25 +00:00
|
|
|
func shortLog*(b: Eth1Block): string =
|
2021-03-26 06:52:01 +00:00
|
|
|
try:
|
|
|
|
&"{b.number}:{shortLog b.voteData.block_hash}(deposits = {b.voteData.deposit_count})"
|
|
|
|
except ValueError as exc: raiseAssert exc.msg
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
template findBlock(chain: Eth1Chain, eth1Data: Eth1Data): Eth1Block =
|
2020-12-03 04:30:35 +00:00
|
|
|
getOrDefault(chain.blocksByHash, asBlockHash(eth1Data.block_hash), nil)
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
func makeSuccessorWithoutDeposits(existingBlock: Eth1Block,
|
|
|
|
successor: BlockObject): ETh1Block =
|
2020-11-24 21:21:47 +00:00
|
|
|
result = Eth1Block(
|
2020-11-19 17:19:03 +00:00
|
|
|
number: Eth1BlockNumber successor.number,
|
|
|
|
timestamp: Eth1BlockTimestamp successor.timestamp,
|
|
|
|
voteData: Eth1Data(
|
|
|
|
block_hash: successor.hash.asEth2Digest,
|
|
|
|
deposit_count: existingBlock.voteData.deposit_count,
|
2020-11-24 21:21:47 +00:00
|
|
|
deposit_root: existingBlock.voteData.deposit_root))
|
|
|
|
|
|
|
|
when hasGenesisDetection:
|
|
|
|
result.activeValidatorsCount = existingBlock.activeValidatorsCount
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
func latestCandidateBlock(chain: Eth1Chain, periodStart: uint64): Eth1Block =
|
|
|
|
for i in countdown(chain.blocks.len - 1, 0):
|
|
|
|
let blk = chain.blocks[i]
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
if is_candidate_block(chain.cfg, blk, periodStart):
|
2020-03-24 11:13:07 +00:00
|
|
|
return blk
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
proc popFirst(chain: var Eth1Chain) =
|
|
|
|
let removed = chain.blocks.popFirst
|
|
|
|
chain.blocksByHash.del removed.voteData.block_hash.asBlockHash
|
|
|
|
eth1_chain_len.set chain.blocks.len.int64
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
proc addBlock*(chain: var Eth1Chain, newBlock: Eth1Block) =
|
|
|
|
chain.blocks.addLast newBlock
|
|
|
|
chain.blocksByHash[newBlock.voteData.block_hash.asBlockHash] = newBlock
|
|
|
|
eth1_chain_len.set chain.blocks.len.int64
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2021-12-08 17:29:22 +00:00
|
|
|
func hash*(x: Eth1Data): Hash =
|
2021-12-03 15:04:58 +00:00
|
|
|
hash(x.block_hash)
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2021-05-28 12:42:39 +00:00
|
|
|
template awaitWithRetries*[T](lazyFutExpr: Future[T],
|
|
|
|
retries = 3,
|
|
|
|
timeout = web3Timeouts): untyped =
|
2020-12-01 21:20:28 +00:00
|
|
|
const
|
|
|
|
reqType = astToStr(lazyFutExpr)
|
|
|
|
|
|
|
|
var
|
|
|
|
retryDelayMs = 16000
|
|
|
|
f: Future[T]
|
|
|
|
attempts = 0
|
|
|
|
|
|
|
|
while true:
|
|
|
|
f = lazyFutExpr
|
|
|
|
yield f or sleepAsync(timeout)
|
|
|
|
if not f.finished:
|
|
|
|
await cancelAndWait(f)
|
|
|
|
elif f.failed:
|
|
|
|
if f.error[] of Defect:
|
|
|
|
raise f.error
|
|
|
|
else:
|
|
|
|
debug "Web3 request failed", req = reqType, err = f.error.msg
|
2020-12-09 22:44:59 +00:00
|
|
|
inc failed_web3_requests
|
2020-12-01 21:20:28 +00:00
|
|
|
else:
|
|
|
|
break
|
|
|
|
|
|
|
|
inc attempts
|
|
|
|
if attempts >= retries:
|
2020-12-09 23:45:49 +00:00
|
|
|
var errorMsg = reqType & " failed " & $retries & " times"
|
|
|
|
if f.failed: errorMsg &= ". Last error: " & f.error.msg
|
|
|
|
raise newException(DataProviderFailure, errorMsg)
|
2020-12-01 21:20:28 +00:00
|
|
|
|
|
|
|
await sleepAsync(chronos.milliseconds(retryDelayMs))
|
|
|
|
retryDelayMs *= 2
|
|
|
|
|
|
|
|
read(f)
|
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc close(p: Web3DataProviderRef): Future[void] {.async.} =
|
2020-06-27 12:01:19 +00:00
|
|
|
if p.blockHeadersSubscription != nil:
|
2020-12-15 21:59:29 +00:00
|
|
|
try:
|
|
|
|
awaitWithRetries(p.blockHeadersSubscription.unsubscribe())
|
|
|
|
except CatchableError:
|
|
|
|
debug "Failed to clean up block headers subscription properly"
|
2020-06-27 12:01:19 +00:00
|
|
|
|
|
|
|
await p.web3.close()
|
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc getBlockByHash(p: Web3DataProviderRef, hash: BlockHash):
|
|
|
|
Future[BlockObject] =
|
2020-06-27 12:01:19 +00:00
|
|
|
return p.web3.provider.eth_getBlockByHash(hash, false)
|
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc getBlockByNumber(p: Web3DataProviderRef,
|
|
|
|
number: Eth1BlockNumber): Future[BlockObject] =
|
2021-04-01 12:43:03 +00:00
|
|
|
let hexNumber = try: &"0x{number:X}" # No leading 0's!
|
|
|
|
except ValueError as exc: raiseAssert exc.msg # Never fails
|
|
|
|
p.web3.provider.eth_getBlockByNumber(hexNumber, false)
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2021-09-29 19:26:27 +00:00
|
|
|
proc getPayload*(p: Web3DataProviderRef,
|
2021-11-15 14:55:03 +00:00
|
|
|
payloadId: merge.PayloadID): Future[engine_api.ExecutionPayloadV1] =
|
|
|
|
p.web3.provider.engine_getPayloadV1(FixedBytes[8] payloadId)
|
2021-09-29 19:26:27 +00:00
|
|
|
|
|
|
|
proc executePayload*(p: Web3DataProviderRef,
|
2021-11-09 02:43:51 +00:00
|
|
|
payload: engine_api.ExecutionPayloadV1): Future[ExecutePayloadResponse] =
|
|
|
|
p.web3.provider.engine_executePayloadV1(payload)
|
2021-09-29 19:26:27 +00:00
|
|
|
|
2021-12-17 12:23:32 +00:00
|
|
|
proc forkchoiceUpdated*(p: Web3DataProviderRef,
|
|
|
|
headBlock, finalizedBlock: Eth2Digest):
|
|
|
|
Future[engine_api.ForkchoiceUpdatedResponse] =
|
|
|
|
p.web3.provider.engine_forkchoiceUpdatedV1(
|
|
|
|
ForkchoiceStateV1(
|
|
|
|
headBlockHash: headBlock.asBlockHash,
|
|
|
|
|
|
|
|
# https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
|
|
|
|
# "CL client software MUST use headBlockHash value as a stub for the
|
|
|
|
# safeBlockHash parameter"
|
|
|
|
safeBlockHash: headBlock.asBlockHash,
|
|
|
|
|
|
|
|
finalizedBlockHash: finalizedBlock.asBlockHash),
|
|
|
|
none(engine_api.PayloadAttributesV1))
|
|
|
|
|
2021-09-29 19:26:27 +00:00
|
|
|
proc forkchoiceUpdated*(p: Web3DataProviderRef,
|
2021-11-10 11:41:02 +00:00
|
|
|
headBlock, finalizedBlock: Eth2Digest,
|
|
|
|
timestamp: uint64,
|
|
|
|
randomData: array[32, byte],
|
2021-12-07 14:30:16 +00:00
|
|
|
suggestedFeeRecipient: Eth1Address):
|
2021-11-09 02:43:51 +00:00
|
|
|
Future[engine_api.ForkchoiceUpdatedResponse] =
|
|
|
|
p.web3.provider.engine_forkchoiceUpdatedV1(
|
|
|
|
ForkchoiceStateV1(
|
|
|
|
headBlockHash: headBlock.asBlockHash,
|
2021-11-10 11:41:02 +00:00
|
|
|
|
|
|
|
# https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
|
|
|
|
# "CL client software MUST use headBlockHash value as a stub for the
|
|
|
|
# safeBlockHash parameter"
|
|
|
|
safeBlockHash: headBlock.asBlockHash,
|
|
|
|
|
2021-11-09 02:43:51 +00:00
|
|
|
finalizedBlockHash: finalizedBlock.asBlockHash),
|
2021-11-10 11:41:02 +00:00
|
|
|
some(engine_api.PayloadAttributesV1(
|
|
|
|
timestamp: Quantity timestamp,
|
|
|
|
random: FixedBytes[32] randomData,
|
2021-12-07 14:30:16 +00:00
|
|
|
suggestedFeeRecipient: suggestedFeeRecipient)))
|
2021-05-20 10:44:13 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
template readJsonField(j: JsonNode, fieldName: string, ValueType: type): untyped =
|
2020-06-27 12:01:19 +00:00
|
|
|
var res: ValueType
|
|
|
|
fromJson(j[fieldName], fieldName, res)
|
|
|
|
res
|
|
|
|
|
2021-10-14 12:33:55 +00:00
|
|
|
template init[N: static int](T: type DynamicBytes[N, N]): T =
|
|
|
|
T newSeq[byte](N)
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func depositEventsToBlocks(depositsList: JsonNode): seq[Eth1Block] {.
|
2021-03-26 06:52:01 +00:00
|
|
|
raises: [Defect, CatchableError].} =
|
2020-06-27 12:01:19 +00:00
|
|
|
if depositsList.kind != JArray:
|
|
|
|
raise newException(CatchableError,
|
|
|
|
"Web3 provider didn't return a list of deposit events")
|
|
|
|
|
|
|
|
var lastEth1Block: Eth1Block
|
|
|
|
|
|
|
|
for logEvent in depositsList:
|
|
|
|
let
|
|
|
|
blockNumber = Eth1BlockNumber readJsonField(logEvent, "blockNumber", Quantity)
|
|
|
|
blockHash = readJsonField(logEvent, "blockHash", BlockHash)
|
|
|
|
logData = strip0xPrefix(logEvent["data"].getStr)
|
|
|
|
|
|
|
|
if lastEth1Block == nil or lastEth1Block.number != blockNumber:
|
|
|
|
lastEth1Block = Eth1Block(
|
|
|
|
number: blockNumber,
|
|
|
|
voteData: Eth1Data(block_hash: blockHash.asEth2Digest))
|
|
|
|
|
|
|
|
result.add lastEth1Block
|
|
|
|
|
|
|
|
var
|
2021-10-14 12:33:55 +00:00
|
|
|
pubkey = init PubKeyBytes
|
|
|
|
withdrawalCredentials = init WithdrawalCredentialsBytes
|
|
|
|
amount = init Int64LeBytes
|
|
|
|
signature = init SignatureBytes
|
|
|
|
index = init Int64LeBytes
|
2020-06-27 12:01:19 +00:00
|
|
|
|
|
|
|
var offset = 0
|
|
|
|
offset += decode(logData, offset, pubkey)
|
|
|
|
offset += decode(logData, offset, withdrawalCredentials)
|
|
|
|
offset += decode(logData, offset, amount)
|
|
|
|
offset += decode(logData, offset, signature)
|
|
|
|
offset += decode(logData, offset, index)
|
|
|
|
|
2021-10-14 12:33:55 +00:00
|
|
|
if pubkey.len != 48 or
|
|
|
|
withdrawalCredentials.len != 32 or
|
|
|
|
amount.len != 8 or
|
|
|
|
signature.len != 96 or
|
|
|
|
index.len != 8:
|
|
|
|
raise newException(CorruptDataProvider, "Web3 provider supplied invalid deposit logs")
|
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
lastEth1Block.deposits.add DepositData(
|
2021-10-14 12:33:55 +00:00
|
|
|
pubkey: ValidatorPubKey.init(pubkey.toArray),
|
|
|
|
withdrawal_credentials: Eth2Digest(data: withdrawalCredentials.toArray),
|
|
|
|
amount: bytes_to_uint64(amount.toArray),
|
|
|
|
signature: ValidatorSig.init(signature.toArray))
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
proc fetchTimestamp(p: Web3DataProviderRef, blk: Eth1Block) {.async.} =
|
2020-12-01 21:20:28 +00:00
|
|
|
let web3block = awaitWithRetries(
|
|
|
|
p.getBlockByHash(blk.voteData.block_hash.asBlockHash))
|
2020-11-03 01:21:07 +00:00
|
|
|
blk.timestamp = Eth1BlockTimestamp web3block.timestamp
|
|
|
|
|
2020-12-01 11:14:32 +00:00
|
|
|
type
|
|
|
|
DepositContractDataStatus = enum
|
|
|
|
Fetched
|
|
|
|
VerifiedCorrect
|
|
|
|
DepositRootIncorrect
|
|
|
|
DepositRootUnavailable
|
|
|
|
DepositCountIncorrect
|
|
|
|
DepositCountUnavailable
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2020-12-01 11:14:32 +00:00
|
|
|
when hasDepositRootChecks:
|
2020-11-24 21:21:47 +00:00
|
|
|
const
|
2020-11-24 21:28:20 +00:00
|
|
|
contractCallTimeout = seconds(60)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
template awaitOrRaiseOnTimeout[T](fut: Future[T],
|
|
|
|
timeout: Duration): T =
|
|
|
|
awaitWithTimeout(fut, timeout):
|
|
|
|
raise newException(DataProviderTimeout, "Timeout")
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func fetchDepositContractData(p: Web3DataProviderRef, blk: Eth1Block):
|
2020-11-03 01:21:07 +00:00
|
|
|
Future[DepositContractDataStatus] {.async.} =
|
|
|
|
let
|
|
|
|
depositRoot = p.ns.get_deposit_root.call(blockNumber = blk.number)
|
|
|
|
rawCount = p.ns.get_deposit_count.call(blockNumber = blk.number)
|
2020-10-21 13:25:53 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
try:
|
2020-11-24 21:21:47 +00:00
|
|
|
let fetchedRoot = asEth2Digest(
|
|
|
|
awaitOrRaiseOnTimeout(depositRoot, contractCallTimeout))
|
2020-11-03 01:21:07 +00:00
|
|
|
if blk.voteData.deposit_root == default(Eth2Digest):
|
|
|
|
blk.voteData.deposit_root = fetchedRoot
|
|
|
|
result = Fetched
|
|
|
|
elif blk.voteData.deposit_root == fetchedRoot:
|
|
|
|
result = VerifiedCorrect
|
|
|
|
else:
|
|
|
|
result = DepositRootIncorrect
|
|
|
|
except CatchableError as err:
|
|
|
|
debug "Failed to fetch deposits root",
|
|
|
|
blockNumber = blk.number,
|
|
|
|
err = err.msg
|
|
|
|
result = DepositRootUnavailable
|
2020-10-21 13:25:53 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
try:
|
2020-11-24 21:21:47 +00:00
|
|
|
let fetchedCount = bytes_to_uint64(array[8, byte](
|
|
|
|
awaitOrRaiseOnTimeout(rawCount, contractCallTimeout)))
|
2020-11-03 01:21:07 +00:00
|
|
|
if blk.voteData.deposit_count == 0:
|
|
|
|
blk.voteData.deposit_count = fetchedCount
|
|
|
|
elif blk.voteData.deposit_count != fetchedCount:
|
|
|
|
result = DepositCountIncorrect
|
|
|
|
except CatchableError as err:
|
|
|
|
debug "Failed to fetch deposits count",
|
|
|
|
blockNumber = blk.number,
|
|
|
|
err = err.msg
|
|
|
|
result = DepositCountUnavailable
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc onBlockHeaders(p: Web3DataProviderRef,
|
|
|
|
blockHeaderHandler: BlockHeaderHandler,
|
|
|
|
errorHandler: SubscriptionErrorHandler) {.async.} =
|
2020-10-12 01:07:20 +00:00
|
|
|
info "Waiting for new Eth1 block headers"
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2020-12-01 21:20:28 +00:00
|
|
|
p.blockHeadersSubscription = awaitWithRetries(
|
|
|
|
p.web3.subscribeForBlockHeaders(blockHeaderHandler, errorHandler))
|
2020-06-27 12:01:19 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
func getDepositsRoot*(m: DepositsMerkleizer): Eth2Digest =
|
2020-11-04 09:06:58 +00:00
|
|
|
mixInLength(m.getFinalHash, int m.totalChunks)
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
func toDepositContractState*(merkleizer: DepositsMerkleizer): DepositContractState =
|
2020-11-24 21:21:47 +00:00
|
|
|
# TODO There is an off by one discrepancy in the size of the arrays here that
|
|
|
|
# need to be investigated. It shouldn't matter as long as the tree is
|
|
|
|
# not populated to its maximum size.
|
|
|
|
result.branch[0..31] = merkleizer.getCombinedChunks[0..31]
|
|
|
|
result.deposit_count[24..31] = merkleizer.getChunkCount().toBytesBE
|
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
func createMerkleizer(s: DepositContractState): DepositsMerkleizer =
|
2020-12-03 04:30:35 +00:00
|
|
|
DepositsMerkleizer.init(s.branch, s.depositCountU64)
|
|
|
|
|
|
|
|
func createMerkleizer*(s: DepositContractSnapshot): DepositsMerkleizer =
|
|
|
|
createMerkleizer(s.depositContractState)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
func eth1DataFromMerkleizer(eth1Block: Eth2Digest,
|
|
|
|
merkleizer: DepositsMerkleizer): Eth1Data =
|
|
|
|
Eth1Data(
|
|
|
|
block_hash: eth1Block,
|
|
|
|
deposit_count: merkleizer.getChunkCount,
|
|
|
|
deposit_root: merkleizer.getDepositsRoot)
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
proc pruneOldBlocks(chain: var Eth1Chain, depositIndex: uint64) =
|
|
|
|
let initialChunks = chain.finalizedDepositsMerkleizer.getChunkCount
|
2020-11-24 21:21:47 +00:00
|
|
|
var lastBlock: Eth1Block
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
while chain.blocks.len > 0:
|
|
|
|
let blk = chain.blocks.peekFirst
|
2020-11-24 23:51:17 +00:00
|
|
|
if blk.voteData.deposit_count >= depositIndex:
|
2020-11-24 21:21:47 +00:00
|
|
|
break
|
|
|
|
else:
|
|
|
|
for deposit in blk.deposits:
|
2020-12-03 04:30:35 +00:00
|
|
|
chain.finalizedDepositsMerkleizer.addChunk hash_tree_root(deposit).data
|
|
|
|
chain.popFirst()
|
2020-11-24 21:21:47 +00:00
|
|
|
lastBlock = blk
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
if chain.finalizedDepositsMerkleizer.getChunkCount > initialChunks:
|
2021-01-29 21:21:44 +00:00
|
|
|
chain.finalizedBlockHash = lastBlock.voteData.block_hash
|
2020-12-03 04:30:35 +00:00
|
|
|
chain.db.putEth2FinalizedTo DepositContractSnapshot(
|
2020-11-24 21:21:47 +00:00
|
|
|
eth1Block: lastBlock.voteData.block_hash,
|
2020-12-03 04:30:35 +00:00
|
|
|
depositContractState: chain.finalizedDepositsMerkleizer.toDepositContractState)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-09 22:44:59 +00:00
|
|
|
eth1_finalized_head.set lastBlock.number.toGaugeValue
|
|
|
|
eth1_finalized_deposits.set lastBlock.voteData.deposit_count.toGaugeValue
|
|
|
|
|
2020-11-30 23:59:35 +00:00
|
|
|
debug "Eth1 blocks pruned",
|
|
|
|
newTailBlock = lastBlock.voteData.block_hash,
|
|
|
|
depositsCount = lastBlock.voteData.deposit_count
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func advanceMerkleizer(chain: Eth1Chain,
|
2020-11-24 21:21:47 +00:00
|
|
|
merkleizer: var DepositsMerkleizer,
|
|
|
|
depositIndex: uint64): bool =
|
2020-12-03 04:30:35 +00:00
|
|
|
if chain.blocks.len == 0:
|
2020-11-24 21:21:47 +00:00
|
|
|
return depositIndex == merkleizer.getChunkCount
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
if chain.blocks.peekLast.voteData.deposit_count < depositIndex:
|
2020-11-24 21:21:47 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
let
|
2020-12-03 04:30:35 +00:00
|
|
|
firstBlock = chain.blocks[0]
|
2020-11-24 21:21:47 +00:00
|
|
|
depositsInLastPrunedBlock = firstBlock.voteData.deposit_count -
|
|
|
|
firstBlock.deposits.lenu64
|
|
|
|
|
|
|
|
# advanceMerkleizer should always be called shortly after prunning the chain
|
|
|
|
doAssert depositsInLastPrunedBlock == merkleizer.getChunkCount
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
for blk in chain.blocks:
|
2020-11-24 21:21:47 +00:00
|
|
|
for deposit in blk.deposits:
|
|
|
|
if merkleizer.getChunkCount < depositIndex:
|
|
|
|
merkleizer.addChunk hash_tree_root(deposit).data
|
|
|
|
else:
|
|
|
|
return true
|
|
|
|
|
|
|
|
return merkleizer.getChunkCount == depositIndex
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func getDepositsRange(chain: Eth1Chain, first, last: uint64): seq[DepositData] =
|
2020-11-24 21:21:47 +00:00
|
|
|
# TODO It's possible to make this faster by performing binary search that
|
|
|
|
# will locate the blocks holding the `first` and `last` indices.
|
|
|
|
# TODO There is an assumption here that the requested range will be present
|
|
|
|
# in the Eth1Chain. This should hold true at the single call site right
|
|
|
|
# now, but we need to guard the pre-conditions better.
|
2020-12-03 04:30:35 +00:00
|
|
|
for blk in chain.blocks:
|
2020-11-24 21:21:47 +00:00
|
|
|
if blk.voteData.deposit_count <= first:
|
|
|
|
continue
|
|
|
|
|
|
|
|
let firstDepositIdxInBlk = blk.voteData.deposit_count - blk.deposits.lenu64
|
|
|
|
if firstDepositIdxInBlk >= last:
|
|
|
|
return
|
|
|
|
|
|
|
|
for i in 0 ..< blk.deposits.lenu64:
|
|
|
|
let globalIdx = firstDepositIdxInBlk + i
|
|
|
|
if globalIdx >= first and globalIdx < last:
|
2020-12-02 18:15:36 +00:00
|
|
|
result.add blk.deposits[i]
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func lowerBound(chain: Eth1Chain, depositCount: uint64): Eth1Block =
|
2020-11-30 23:59:35 +00:00
|
|
|
# TODO: This can be replaced with a proper binary search in the
|
|
|
|
# future, but the `algorithm` module currently requires an
|
|
|
|
# `openArray`, which the `deques` module can't provide yet.
|
|
|
|
for eth1Block in chain.blocks:
|
|
|
|
if eth1Block.voteData.deposit_count > depositCount:
|
|
|
|
return
|
|
|
|
result = eth1Block
|
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc trackFinalizedState(chain: var Eth1Chain,
|
|
|
|
finalizedEth1Data: Eth1Data,
|
|
|
|
finalizedStateDepositIndex: uint64): bool =
|
2020-11-30 23:59:35 +00:00
|
|
|
# Returns true if the Eth1Monitor is synced to the finalization point
|
2020-12-03 04:30:35 +00:00
|
|
|
if chain.blocks.len == 0:
|
2020-11-30 23:59:35 +00:00
|
|
|
debug "Eth1 chain not initialized"
|
|
|
|
return false
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
let latest = chain.blocks.peekLast
|
2020-11-30 23:59:35 +00:00
|
|
|
if latest.voteData.deposit_count < finalizedEth1Data.deposit_count:
|
2021-01-11 09:23:09 +00:00
|
|
|
warn "Eth1 chain not synced",
|
2020-11-30 23:59:35 +00:00
|
|
|
ourDepositsCount = latest.voteData.deposit_count,
|
|
|
|
targetDepositsCount = finalizedEth1Data.deposit_count
|
|
|
|
return false
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
let matchingBlock = chain.lowerBound(finalizedEth1Data.deposit_count)
|
2020-11-30 23:59:35 +00:00
|
|
|
result = if matchingBlock != nil:
|
|
|
|
if matchingBlock.voteData.deposit_root == finalizedEth1Data.deposit_root:
|
2020-11-24 21:21:47 +00:00
|
|
|
true
|
|
|
|
else:
|
|
|
|
error "Corrupted deposits history detected",
|
2020-12-03 04:30:35 +00:00
|
|
|
ourDepositsCount = matchingBlock.voteData.deposit_count,
|
|
|
|
taretDepositsCount = finalizedEth1Data.deposit_count,
|
|
|
|
ourDepositsRoot = matchingBlock.voteData.deposit_root,
|
|
|
|
targetDepositsRoot = finalizedEth1Data.deposit_root
|
2021-01-29 21:21:44 +00:00
|
|
|
chain.hasConsensusViolation = true
|
2020-11-04 09:06:58 +00:00
|
|
|
false
|
|
|
|
else:
|
2020-11-30 23:59:35 +00:00
|
|
|
error "The Eth1 chain is in inconsistent state",
|
2020-11-24 21:21:47 +00:00
|
|
|
checkpointHash = finalizedEth1Data.block_hash,
|
|
|
|
checkpointDeposits = finalizedEth1Data.deposit_count,
|
2020-12-03 04:30:35 +00:00
|
|
|
localChainStart = shortLog(chain.blocks.peekFirst),
|
|
|
|
localChainEnd = shortLog(chain.blocks.peekLast)
|
2021-01-29 21:21:44 +00:00
|
|
|
chain.hasConsensusViolation = true
|
2020-11-04 09:06:58 +00:00
|
|
|
false
|
2020-10-26 08:55:10 +00:00
|
|
|
|
2020-11-30 23:59:35 +00:00
|
|
|
if result:
|
2020-12-03 04:30:35 +00:00
|
|
|
chain.pruneOldBlocks(finalizedStateDepositIndex)
|
|
|
|
|
|
|
|
template trackFinalizedState*(m: Eth1Monitor,
|
|
|
|
finalizedEth1Data: Eth1Data,
|
|
|
|
finalizedStateDepositIndex: uint64): bool =
|
2021-11-15 12:01:47 +00:00
|
|
|
trackFinalizedState(m.depositsChain, finalizedEth1Data, finalizedStateDepositIndex)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2022-01-04 03:57:15 +00:00
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/validator.md#get_eth1_data
|
2020-12-03 04:30:35 +00:00
|
|
|
proc getBlockProposalData*(chain: var Eth1Chain,
|
2021-06-11 17:51:46 +00:00
|
|
|
state: ForkedHashedBeaconState,
|
2020-11-30 23:59:35 +00:00
|
|
|
finalizedEth1Data: Eth1Data,
|
|
|
|
finalizedStateDepositIndex: uint64): BlockProposalEth1Data =
|
|
|
|
let
|
|
|
|
periodStart = voting_period_start_time(state)
|
2020-12-03 04:30:35 +00:00
|
|
|
hasLatestDeposits = chain.trackFinalizedState(finalizedEth1Data,
|
|
|
|
finalizedStateDepositIndex)
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
var otherVotesCountTable = initCountTable[Eth1Data]()
|
2021-05-21 09:23:28 +00:00
|
|
|
for vote in getStateField(state, eth1_data_votes):
|
2020-12-03 04:30:35 +00:00
|
|
|
let eth1Block = chain.findBlock(vote)
|
2021-04-30 23:00:03 +00:00
|
|
|
if eth1Block != nil and
|
|
|
|
eth1Block.voteData.deposit_root == vote.deposit_root and
|
2021-05-21 09:23:28 +00:00
|
|
|
vote.deposit_count >= getStateField(state, eth1_data).deposit_count and
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
is_candidate_block(chain.cfg, eth1Block, periodStart):
|
2020-11-19 17:19:03 +00:00
|
|
|
otherVotesCountTable.inc vote
|
2020-11-20 14:05:37 +00:00
|
|
|
else:
|
2021-04-30 23:00:03 +00:00
|
|
|
debug "Ignoring eth1 vote",
|
|
|
|
root = vote.block_hash,
|
|
|
|
deposits = vote.deposit_count,
|
|
|
|
depositsRoot = vote.deposit_root,
|
2021-05-21 09:23:28 +00:00
|
|
|
localDeposits = getStateField(state, eth1_data).deposit_count
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2021-05-21 09:23:28 +00:00
|
|
|
var pendingDepositsCount =
|
|
|
|
getStateField(state, eth1_data).deposit_count -
|
|
|
|
getStateField(state, eth1_deposit_index)
|
2020-03-24 11:13:07 +00:00
|
|
|
if otherVotesCountTable.len > 0:
|
2020-11-19 17:19:03 +00:00
|
|
|
let (winningVote, votes) = otherVotesCountTable.largest
|
2020-11-20 14:05:37 +00:00
|
|
|
debug "Voting on eth1 head with majority", votes
|
2020-11-19 17:19:03 +00:00
|
|
|
result.vote = winningVote
|
2020-10-12 01:07:20 +00:00
|
|
|
if uint64((votes + 1) * 2) > SLOTS_PER_ETH1_VOTING_PERIOD:
|
2021-05-21 09:23:28 +00:00
|
|
|
pendingDepositsCount = winningVote.deposit_count -
|
|
|
|
getStateField(state, eth1_deposit_index)
|
2020-03-24 11:13:07 +00:00
|
|
|
else:
|
2020-12-03 04:30:35 +00:00
|
|
|
let latestBlock = chain.latestCandidateBlock(periodStart)
|
2020-10-12 01:07:20 +00:00
|
|
|
if latestBlock == nil:
|
2020-11-20 14:05:37 +00:00
|
|
|
debug "No acceptable eth1 votes and no recent candidates. Voting no change"
|
2021-05-21 09:23:28 +00:00
|
|
|
result.vote = getStateField(state, eth1_data)
|
2020-10-12 01:07:20 +00:00
|
|
|
else:
|
2020-11-20 14:05:37 +00:00
|
|
|
debug "No acceptable eth1 votes. Voting for latest candidate"
|
2020-11-19 17:19:03 +00:00
|
|
|
result.vote = latestBlock.voteData
|
2020-10-15 17:30:33 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
if pendingDepositsCount > 0:
|
|
|
|
if hasLatestDeposits:
|
2020-12-02 18:15:36 +00:00
|
|
|
let
|
|
|
|
totalDepositsInNewBlock = min(MAX_DEPOSITS, pendingDepositsCount)
|
2020-12-03 04:30:35 +00:00
|
|
|
deposits = chain.getDepositsRange(
|
2021-05-21 09:23:28 +00:00
|
|
|
getStateField(state, eth1_deposit_index),
|
|
|
|
getStateField(state, eth1_deposit_index) + pendingDepositsCount)
|
2020-12-02 18:15:36 +00:00
|
|
|
depositRoots = mapIt(deposits, hash_tree_root(it))
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
var scratchMerkleizer = copy chain.finalizedDepositsMerkleizer
|
2021-05-21 09:23:28 +00:00
|
|
|
if chain.advanceMerkleizer(
|
|
|
|
scratchMerkleizer, getStateField(state, eth1_deposit_index)):
|
2020-11-24 21:21:47 +00:00
|
|
|
let proofs = scratchMerkleizer.addChunksAndGenMerkleProofs(depositRoots)
|
2020-12-02 18:15:36 +00:00
|
|
|
for i in 0 ..< totalDepositsInNewBlock:
|
|
|
|
var proof: array[33, Eth2Digest]
|
|
|
|
proof[0..31] = proofs.getProof(i.int)
|
|
|
|
proof[32] = default(Eth2Digest)
|
|
|
|
proof[32].data[0..7] = toBytesLE uint64(result.vote.deposit_count)
|
|
|
|
result.deposits.add Deposit(data: deposits[i], proof: proof)
|
2020-11-24 21:21:47 +00:00
|
|
|
else:
|
|
|
|
error "The Eth1 chain is in inconsistent state" # This should not really happen
|
|
|
|
result.hasMissingDeposits = true
|
|
|
|
else:
|
|
|
|
result.hasMissingDeposits = true
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
template getBlockProposalData*(m: Eth1Monitor,
|
2021-06-11 17:51:46 +00:00
|
|
|
state: ForkedHashedBeaconState,
|
2020-12-03 04:30:35 +00:00
|
|
|
finalizedEth1Data: Eth1Data,
|
|
|
|
finalizedStateDepositIndex: uint64): BlockProposalEth1Data =
|
2021-11-15 12:01:47 +00:00
|
|
|
getBlockProposalData(m.depositsChain, state, finalizedEth1Data, finalizedStateDepositIndex)
|
2020-12-03 04:30:35 +00:00
|
|
|
|
2021-10-13 14:08:50 +00:00
|
|
|
proc new*(T: type Web3DataProvider,
|
|
|
|
depositContractAddress: Eth1Address,
|
|
|
|
web3Url: string): Future[Result[Web3DataProviderRef, string]] {.async.} =
|
2020-11-17 19:50:07 +00:00
|
|
|
let web3Fut = newWeb3(web3Url)
|
2021-04-06 21:42:59 +00:00
|
|
|
yield web3Fut or sleepAsync(chronos.seconds(10))
|
2020-11-17 19:50:07 +00:00
|
|
|
if (not web3Fut.finished) or web3Fut.failed:
|
|
|
|
await cancelAndWait(web3Fut)
|
|
|
|
return err "Failed to setup web3 connection"
|
|
|
|
|
|
|
|
let
|
|
|
|
web3 = web3Fut.read
|
|
|
|
ns = web3.contractSender(DepositContract, depositContractAddress)
|
|
|
|
|
|
|
|
return ok Web3DataProviderRef(url: web3Url, web3: web3, ns: ns)
|
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
proc putInitialDepositContractSnapshot*(db: BeaconChainDB,
|
|
|
|
s: DepositContractSnapshot) =
|
|
|
|
let existingStart = db.getEth2FinalizedTo()
|
|
|
|
if not existingStart.isOk:
|
|
|
|
db.putEth2FinalizedTo(s)
|
|
|
|
|
|
|
|
template getOrDefault[T, E](r: Result[T, E]): T =
|
|
|
|
type TT = T
|
|
|
|
get(r, default(TT))
|
|
|
|
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
proc init*(T: type Eth1Chain, cfg: RuntimeConfig, db: BeaconChainDB): T =
|
2020-12-03 04:30:35 +00:00
|
|
|
let finalizedDeposits = db.getEth2FinalizedTo().getOrDefault()
|
|
|
|
let m = finalizedDeposits.createMerkleizer
|
|
|
|
|
|
|
|
T(db: db,
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
cfg: cfg,
|
2020-12-03 04:30:35 +00:00
|
|
|
finalizedBlockHash: finalizedDeposits.eth1Block,
|
|
|
|
finalizedDepositsMerkleizer: finalizedDeposits.createMerkleizer)
|
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
proc init*(T: type Eth1Monitor,
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
cfg: RuntimeConfig,
|
2020-12-03 04:30:35 +00:00
|
|
|
db: BeaconChainDB,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Urls: seq[string],
|
2020-11-24 21:21:47 +00:00
|
|
|
depositContractSnapshot: DepositContractSnapshot,
|
2021-11-25 16:51:51 +00:00
|
|
|
eth1Network: Option[Eth1Network],
|
|
|
|
forcePolling: bool): T =
|
2021-04-06 21:42:59 +00:00
|
|
|
doAssert web3Urls.len > 0
|
|
|
|
|
|
|
|
var web3Urls = web3Urls
|
|
|
|
for url in mitems(web3Urls):
|
|
|
|
fixupWeb3Urls url
|
2020-11-05 23:11:06 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
putInitialDepositContractSnapshot(db, depositContractSnapshot)
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
T(state: Initialized,
|
2021-11-15 12:01:47 +00:00
|
|
|
depositsChain: Eth1Chain.init(cfg, db),
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
depositContractAddress: cfg.DEPOSIT_CONTRACT_ADDRESS,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Urls: web3Urls,
|
2020-12-15 21:59:29 +00:00
|
|
|
eth1Network: eth1Network,
|
2021-11-25 16:51:51 +00:00
|
|
|
eth1Progress: newAsyncEvent(),
|
|
|
|
forcePolling: forcePolling)
|
2019-09-09 15:59:02 +00:00
|
|
|
|
2020-09-28 15:19:57 +00:00
|
|
|
proc safeCancel(fut: var Future[void]) =
|
|
|
|
if not fut.isNil and not fut.finished:
|
|
|
|
fut.cancel()
|
2020-11-03 01:21:07 +00:00
|
|
|
fut = nil
|
2020-09-28 15:19:57 +00:00
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func clear(chain: var Eth1Chain) =
|
2020-11-24 21:21:47 +00:00
|
|
|
chain.blocks.clear()
|
|
|
|
chain.blocksByHash.clear()
|
2021-01-29 21:21:44 +00:00
|
|
|
chain.hasConsensusViolation = false
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
proc resetState(m: Eth1Monitor) {.async.} =
|
2020-09-28 15:19:57 +00:00
|
|
|
safeCancel m.runFut
|
2019-09-09 15:59:02 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.clear()
|
2021-11-25 16:51:51 +00:00
|
|
|
m.latestEth1Block = none(FullBlockId)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2021-02-04 15:24:34 +00:00
|
|
|
if m.dataProvider != nil:
|
|
|
|
await m.dataProvider.close()
|
|
|
|
m.dataProvider = nil
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2021-12-05 17:32:41 +00:00
|
|
|
proc stop(m: Eth1Monitor) {.async.} =
|
2020-12-15 21:59:29 +00:00
|
|
|
if m.state == Started:
|
|
|
|
m.state = Stopping
|
|
|
|
m.stopFut = resetState(m)
|
|
|
|
await m.stopFut
|
|
|
|
m.state = Stopped
|
|
|
|
elif m.state == Stopping:
|
|
|
|
await m.stopFut
|
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
const
|
2020-11-24 21:21:47 +00:00
|
|
|
votedBlocksSafetyMargin = 50
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2021-11-25 16:51:51 +00:00
|
|
|
func latestEth1BlockNumber(m: Eth1Monitor): Eth1BlockNumber =
|
|
|
|
if m.latestEth1Block.isSome:
|
|
|
|
Eth1BlockNumber m.latestEth1Block.get.number
|
|
|
|
else:
|
|
|
|
Eth1BlockNumber 0
|
|
|
|
|
2021-11-25 10:53:31 +00:00
|
|
|
func earliestBlockOfInterest(m: Eth1Monitor): Eth1BlockNumber =
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
m.latestEth1BlockNumber - (2 * m.cfg.ETH1_FOLLOW_DISTANCE) - votedBlocksSafetyMargin
|
2020-11-19 17:19:03 +00:00
|
|
|
|
|
|
|
proc syncBlockRange(m: Eth1Monitor,
|
2020-11-24 21:21:47 +00:00
|
|
|
merkleizer: ref DepositsMerkleizer,
|
2020-11-19 17:19:03 +00:00
|
|
|
fromBlock, toBlock,
|
2020-12-15 21:59:29 +00:00
|
|
|
fullSyncFromBlock: Eth1BlockNumber) {.gcsafe, async.} =
|
2021-11-15 12:01:47 +00:00
|
|
|
doAssert m.depositsChain.blocks.len > 0 and m.dataProvider != nil
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
var currentBlock = fromBlock
|
|
|
|
while currentBlock <= toBlock:
|
2020-11-14 20:51:50 +00:00
|
|
|
var
|
|
|
|
depositLogs: JsonNode = nil
|
|
|
|
blocksPerRequest = 5000'u64 # This is roughly a day of Eth1 blocks
|
|
|
|
maxBlockNumberRequested: Eth1BlockNumber
|
2020-12-01 23:35:07 +00:00
|
|
|
backoff = 100
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
while true:
|
2020-11-14 20:51:50 +00:00
|
|
|
maxBlockNumberRequested = min(toBlock, currentBlock + blocksPerRequest - 1)
|
2020-06-25 23:33:06 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
template retryOrRaise(err: ref CatchableError) =
|
2020-11-03 01:21:07 +00:00
|
|
|
blocksPerRequest = blocksPerRequest div 2
|
|
|
|
if blocksPerRequest == 0:
|
|
|
|
raise err
|
2020-11-24 21:21:47 +00:00
|
|
|
continue
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
debug "Obtaining deposit log events",
|
|
|
|
fromBlock = currentBlock,
|
2020-12-01 23:35:07 +00:00
|
|
|
toBlock = maxBlockNumberRequested,
|
|
|
|
backoff
|
2020-02-07 07:13:38 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
debug.logTime "Deposit logs obtained":
|
2020-12-01 11:14:32 +00:00
|
|
|
# Reduce all request rate until we have a more general solution
|
|
|
|
# for dealing with Infura's rate limits
|
2020-12-01 23:35:07 +00:00
|
|
|
await sleepAsync(milliseconds(backoff))
|
2020-12-01 11:14:32 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
let jsonLogsFut = m.dataProvider.ns.getJsonLogs(
|
|
|
|
DepositEvent,
|
|
|
|
fromBlock = some blockId(currentBlock),
|
|
|
|
toBlock = some blockId(maxBlockNumberRequested))
|
|
|
|
|
|
|
|
depositLogs = try:
|
|
|
|
# Downloading large amounts of deposits can be quite slow
|
2020-12-15 21:59:29 +00:00
|
|
|
awaitWithTimeout(jsonLogsFut, web3Timeouts):
|
2020-11-24 21:21:47 +00:00
|
|
|
retryOrRaise newException(DataProviderTimeout,
|
|
|
|
"Request time out while obtaining json logs")
|
|
|
|
except CatchableError as err:
|
2020-12-01 23:35:07 +00:00
|
|
|
debug "Request for deposit logs failed", err = err.msg
|
2020-12-09 22:44:59 +00:00
|
|
|
inc failed_web3_requests
|
2020-12-01 23:35:07 +00:00
|
|
|
backoff = (backoff * 3) div 2
|
2020-11-24 21:21:47 +00:00
|
|
|
retryOrRaise err
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
currentBlock = maxBlockNumberRequested + 1
|
|
|
|
break
|
|
|
|
|
2020-12-01 11:14:32 +00:00
|
|
|
let blocksWithDeposits = depositEventsToBlocks(depositLogs)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
for i in 0 ..< blocksWithDeposits.len:
|
|
|
|
let blk = blocksWithDeposits[i]
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2020-12-01 11:14:32 +00:00
|
|
|
for deposit in blk.deposits:
|
|
|
|
merkleizer[].addChunk hash_tree_root(deposit).data
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2020-12-01 11:14:32 +00:00
|
|
|
blk.voteData.deposit_count = merkleizer[].getChunkCount
|
|
|
|
blk.voteData.deposit_root = merkleizer[].getDepositsRoot
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
if blk.number > fullSyncFromBlock:
|
2021-11-15 12:01:47 +00:00
|
|
|
let lastBlock = m.depositsChain.blocks.peekLast
|
2020-11-19 17:19:03 +00:00
|
|
|
for n in max(lastBlock.number + 1, fullSyncFromBlock) ..< blk.number:
|
2020-12-01 23:35:07 +00:00
|
|
|
debug "Obtaining block without deposits", blockNum = n
|
2020-12-01 21:20:28 +00:00
|
|
|
let blockWithoutDeposits = awaitWithRetries(
|
|
|
|
m.dataProvider.getBlockByNumber(n))
|
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.addBlock(
|
2020-11-19 17:19:03 +00:00
|
|
|
lastBlock.makeSuccessorWithoutDeposits(blockWithoutDeposits))
|
2020-12-09 22:44:59 +00:00
|
|
|
eth1_synced_head.set blockWithoutDeposits.number.toGaugeValue
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.addBlock blk
|
2020-12-09 22:44:59 +00:00
|
|
|
eth1_synced_head.set blk.number.toGaugeValue
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
if blocksWithDeposits.len > 0:
|
|
|
|
let lastIdx = blocksWithDeposits.len - 1
|
|
|
|
template lastBlock: auto = blocksWithDeposits[lastIdx]
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
let status = when hasDepositRootChecks:
|
2020-12-01 21:20:28 +00:00
|
|
|
awaitWithRetries m.dataProvider.fetchDepositContractData(lastBlock)
|
2020-11-24 21:21:47 +00:00
|
|
|
else:
|
|
|
|
DepositRootUnavailable
|
2020-11-03 01:21:07 +00:00
|
|
|
|
|
|
|
when hasDepositRootChecks:
|
2020-11-24 21:21:47 +00:00
|
|
|
debug "Deposit contract state verified",
|
|
|
|
status = $status,
|
2020-11-03 01:21:07 +00:00
|
|
|
ourCount = lastBlock.voteData.deposit_count,
|
|
|
|
ourRoot = lastBlock.voteData.deposit_root
|
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
case status
|
|
|
|
of DepositRootIncorrect, DepositCountIncorrect:
|
|
|
|
raise newException(CorruptDataProvider,
|
|
|
|
"The deposit log events disagree with the deposit contract state")
|
|
|
|
else:
|
|
|
|
discard
|
2020-11-03 01:21:07 +00:00
|
|
|
|
2022-01-03 21:18:49 +00:00
|
|
|
info "Eth1 sync progress",
|
2020-11-24 21:21:47 +00:00
|
|
|
blockNumber = lastBlock.number,
|
|
|
|
depositsProcessed = lastBlock.voteData.deposit_count
|
2020-11-17 19:50:07 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
when hasGenesisDetection:
|
2020-12-15 21:59:29 +00:00
|
|
|
if blocksWithDeposits.len > 0:
|
2020-11-24 21:21:47 +00:00
|
|
|
for blk in blocksWithDeposits:
|
|
|
|
for deposit in blk.deposits:
|
2020-12-15 21:59:29 +00:00
|
|
|
m.processGenesisDeposit(deposit)
|
|
|
|
blk.activeValidatorsCount = m.genesisValidators.lenu64
|
|
|
|
|
|
|
|
let depositContractState = DepositContractSnapshot(
|
|
|
|
eth1Block: blocksWithDeposits[^1].voteData.block_hash,
|
|
|
|
depositContractState: merkleizer[].toDepositContractState)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
m.depositsChain.db.putEth2FinalizedTo depositContractState
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
if m.genesisStateFut != nil and m.chainHasEnoughValidators:
|
2021-11-15 12:01:47 +00:00
|
|
|
let lastIdx = m.depositsChain.blocks.len - 1
|
|
|
|
template lastBlock: auto = m.depositsChain.blocks[lastIdx]
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
if maxBlockNumberRequested == toBlock and
|
2021-11-15 12:01:47 +00:00
|
|
|
(m.depositsChain.blocks.len == 0 or lastBlock.number != toBlock):
|
2020-12-01 21:20:28 +00:00
|
|
|
let web3Block = awaitWithRetries(
|
|
|
|
m.dataProvider.getBlockByNumber(toBlock))
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
debug "Latest block doesn't hold deposits. Obtaining it",
|
|
|
|
ts = web3Block.timestamp.uint64,
|
|
|
|
number = web3Block.number.uint64
|
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.addBlock lastBlock.makeSuccessorWithoutDeposits(web3Block)
|
2020-11-24 21:21:47 +00:00
|
|
|
else:
|
2020-12-01 21:20:28 +00:00
|
|
|
awaitWithRetries m.dataProvider.fetchTimestamp(lastBlock)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
var genesisBlockIdx = m.depositsChain.blocks.len - 1
|
|
|
|
if m.isAfterMinGenesisTime(m.depositsChain.blocks[genesisBlockIdx]):
|
2020-12-15 21:59:29 +00:00
|
|
|
for i in 1 ..< blocksWithDeposits.len:
|
2021-11-15 12:01:47 +00:00
|
|
|
let idx = (m.depositsChain.blocks.len - 1) - i
|
|
|
|
let blk = m.depositsChain.blocks[idx]
|
2020-12-01 21:20:28 +00:00
|
|
|
awaitWithRetries m.dataProvider.fetchTimestamp(blk)
|
2020-11-24 21:21:47 +00:00
|
|
|
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.
|
2021-11-15 12:01:47 +00:00
|
|
|
var genesisBlock = m.depositsChain.blocks[genesisBlockIdx]
|
2020-11-24 21:21:47 +00:00
|
|
|
if genesisBlockIdx > 0:
|
2021-11-15 12:01:47 +00:00
|
|
|
let genesisParent = m.depositsChain.blocks[genesisBlockIdx - 1]
|
2020-11-24 21:21:47 +00:00
|
|
|
if genesisParent.timestamp == 0:
|
2020-12-01 21:20:28 +00:00
|
|
|
awaitWithRetries m.dataProvider.fetchTimestamp(genesisParent)
|
2020-11-24 21:21:47 +00:00
|
|
|
if m.hasEnoughValidators(genesisParent) and
|
|
|
|
genesisBlock.number - genesisParent.number > 1:
|
2020-12-01 21:20:28 +00:00
|
|
|
genesisBlock = awaitWithRetries(
|
|
|
|
m.findGenesisBlockInRange(genesisParent, genesisBlock))
|
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
m.signalGenesis m.createGenesisState(genesisBlock)
|
|
|
|
|
2021-11-25 16:51:51 +00:00
|
|
|
func init(T: type FullBlockId, blk: Eth1BlockHeader|BlockObject): T =
|
|
|
|
FullBlockId(number: Eth1BlockNumber blk.number, hash: blk.hash)
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =
|
|
|
|
if m.state == Failed:
|
|
|
|
await m.resetState()
|
|
|
|
elif m.state == Stopping:
|
|
|
|
await m.stopFut
|
|
|
|
|
|
|
|
if delayBeforeStart != ZeroDuration:
|
|
|
|
await sleepAsync(delayBeforeStart)
|
|
|
|
|
2021-04-06 21:42:59 +00:00
|
|
|
let web3Url = m.web3Urls[m.startIdx mod m.web3Urls.len]
|
|
|
|
inc m.startIdx
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
info "Starting Eth1 deposit contract monitoring",
|
2021-04-06 21:42:59 +00:00
|
|
|
contract = $m.depositContractAddress, url = web3Url
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
let dataProviderRes = await Web3DataProvider.new(
|
|
|
|
m.depositContractAddress,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Url)
|
2020-12-15 21:59:29 +00:00
|
|
|
|
|
|
|
m.dataProvider = dataProviderRes.tryGet()
|
|
|
|
let web3 = m.dataProvider.web3
|
|
|
|
|
|
|
|
if m.state == Initialized and m.eth1Network.isSome:
|
|
|
|
let
|
|
|
|
providerNetwork = awaitWithRetries web3.provider.net_version()
|
|
|
|
expectedNetwork = case m.eth1Network.get
|
|
|
|
of mainnet: "1"
|
|
|
|
of rinkeby: "4"
|
|
|
|
of goerli: "5"
|
|
|
|
if expectedNetwork != providerNetwork:
|
|
|
|
fatal "The specified web3 provider serves data for a different network",
|
|
|
|
expectedNetwork, providerNetwork
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
m.state = Started
|
2021-11-25 16:51:51 +00:00
|
|
|
var mustUsePolling = m.forcePolling or
|
|
|
|
web3Url.startsWith("http://") or
|
|
|
|
web3Url.startsWith("https://")
|
|
|
|
|
|
|
|
if not mustUsePolling:
|
|
|
|
proc newBlockHeadersHandler(blk: Eth1BlockHeader)
|
|
|
|
{.raises: [Defect], gcsafe.} =
|
|
|
|
try:
|
|
|
|
if blk.number.uint64 > m.latestEth1BlockNumber:
|
|
|
|
eth1_latest_head.set blk.number.toGaugeValue
|
|
|
|
m.latestEth1Block = some FullBlockId.init(blk)
|
|
|
|
m.eth1Progress.fire()
|
|
|
|
except Exception:
|
|
|
|
# TODO Investigate why this exception is being raised
|
|
|
|
raiseAssert "AsyncEvent.fire should not raise exceptions"
|
|
|
|
|
|
|
|
proc subscriptionErrorHandler(err: CatchableError)
|
|
|
|
{.raises: [Defect], gcsafe.} =
|
|
|
|
warn "Failed to subscribe for block headers. Switching to polling",
|
|
|
|
web3Url, err = err.msg
|
|
|
|
mustUsePolling = true
|
|
|
|
|
|
|
|
await m.dataProvider.onBlockHeaders(newBlockHeadersHandler,
|
|
|
|
subscriptionErrorHandler)
|
2020-12-15 21:59:29 +00:00
|
|
|
|
2020-12-01 21:20:28 +00:00
|
|
|
let startBlock = awaitWithRetries(
|
2021-11-15 12:01:47 +00:00
|
|
|
m.dataProvider.getBlockByHash(m.depositsChain.finalizedBlockHash.asBlockHash))
|
2020-11-19 17:19:03 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
doAssert m.depositsChain.blocks.len == 0
|
|
|
|
m.depositsChain.addBlock Eth1Block(
|
2020-11-19 17:19:03 +00:00
|
|
|
number: Eth1BlockNumber startBlock.number,
|
|
|
|
timestamp: Eth1BlockTimestamp startBlock.timestamp,
|
2020-11-24 21:21:47 +00:00
|
|
|
voteData: eth1DataFromMerkleizer(
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.finalizedBlockHash,
|
|
|
|
m.depositsChain.finalizedDepositsMerkleizer))
|
2020-11-19 17:19:03 +00:00
|
|
|
|
|
|
|
var eth1SyncedTo = Eth1BlockNumber startBlock.number
|
2020-12-09 22:44:59 +00:00
|
|
|
eth1_synced_head.set eth1SyncedTo.toGaugeValue
|
|
|
|
eth1_finalized_head.set eth1SyncedTo.toGaugeValue
|
|
|
|
eth1_finalized_deposits.set(
|
2021-11-15 12:01:47 +00:00
|
|
|
m.depositsChain.finalizedDepositsMerkleizer.getChunkCount.toGaugeValue)
|
2020-12-09 22:44:59 +00:00
|
|
|
|
2020-12-03 04:30:35 +00:00
|
|
|
var scratchMerkleizer = newClone(copy m.finalizedDepositsMerkleizer)
|
2020-09-28 15:19:57 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
debug "Starting Eth1 syncing", `from` = shortLog(m.depositsChain.blocks[0])
|
2020-11-30 23:59:35 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
while true:
|
|
|
|
if bnStatus == BeaconNodeStatus.Stopping:
|
2020-11-24 21:21:47 +00:00
|
|
|
when hasGenesisDetection:
|
|
|
|
if not m.genesisStateFut.isNil:
|
|
|
|
m.genesisStateFut.complete()
|
|
|
|
m.genesisStateFut = nil
|
2020-12-15 21:59:29 +00:00
|
|
|
await m.stop()
|
2020-11-03 01:21:07 +00:00
|
|
|
return
|
2020-10-14 14:04:08 +00:00
|
|
|
|
2021-11-15 12:01:47 +00:00
|
|
|
if m.depositsChain.hasConsensusViolation:
|
2021-01-29 21:21:44 +00:00
|
|
|
raise newException(CorruptDataProvider, "Eth1 chain contradicts Eth2 consensus")
|
|
|
|
|
2021-11-25 16:51:51 +00:00
|
|
|
if mustUsePolling:
|
|
|
|
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:
|
|
|
|
await sleepAsync(m.cfg.SECONDS_PER_ETH1_BLOCK.int.seconds)
|
|
|
|
continue
|
|
|
|
|
|
|
|
m.latestEth1Block = some fullBlockId
|
|
|
|
else:
|
|
|
|
awaitWithTimeout(m.eth1Progress.wait(), 5.minutes):
|
|
|
|
raise newException(CorruptDataProvider, "No eth1 chain progress for too long")
|
2021-02-04 15:01:47 +00:00
|
|
|
|
2021-11-25 16:51:51 +00:00
|
|
|
m.eth1Progress.clear()
|
2020-03-24 11:13:07 +00:00
|
|
|
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
if m.latestEth1BlockNumber <= m.cfg.ETH1_FOLLOW_DISTANCE:
|
2020-11-03 01:21:07 +00:00
|
|
|
continue
|
2020-06-27 12:01:19 +00:00
|
|
|
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
let targetBlock = m.latestEth1BlockNumber - m.cfg.ETH1_FOLLOW_DISTANCE
|
2020-11-03 01:21:07 +00:00
|
|
|
if targetBlock <= eth1SyncedTo:
|
|
|
|
continue
|
2020-03-24 11:13:07 +00:00
|
|
|
|
2020-11-19 17:19:03 +00:00
|
|
|
let earliestBlockOfInterest = m.earliestBlockOfInterest()
|
2020-11-24 21:21:47 +00:00
|
|
|
await m.syncBlockRange(scratchMerkleizer,
|
|
|
|
eth1SyncedTo + 1,
|
|
|
|
targetBlock,
|
|
|
|
earliestBlockOfInterest)
|
2020-11-03 01:21:07 +00:00
|
|
|
eth1SyncedTo = targetBlock
|
2020-12-09 22:44:59 +00:00
|
|
|
eth1_synced_head.set eth1SyncedTo.toGaugeValue
|
2019-11-22 13:16:07 +00:00
|
|
|
|
2020-11-03 01:21:07 +00:00
|
|
|
proc start(m: Eth1Monitor, delayBeforeStart: Duration) =
|
2019-11-22 13:16:07 +00:00
|
|
|
if m.runFut.isNil:
|
2020-12-15 21:59:29 +00:00
|
|
|
let runFut = m.startEth1Syncing(delayBeforeStart)
|
2019-11-22 13:16:07 +00:00
|
|
|
m.runFut = runFut
|
2020-03-24 11:13:07 +00:00
|
|
|
runFut.addCallback do (p: pointer):
|
|
|
|
if runFut.failed:
|
|
|
|
if runFut.error[] of CatchableError:
|
|
|
|
if runFut == m.runFut:
|
2021-11-01 14:50:24 +00:00
|
|
|
warn "Eth1 chain monitoring failure, restarting", err = runFut.error.msg
|
2020-12-15 21:59:29 +00:00
|
|
|
m.state = Failed
|
2020-03-24 11:13:07 +00:00
|
|
|
else:
|
|
|
|
fatal "Fatal exception reached", err = runFut.error.msg
|
|
|
|
quit 1
|
2019-11-22 13:16:07 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
safeCancel m.runFut
|
2020-11-19 17:19:03 +00:00
|
|
|
m.start(5.seconds)
|
|
|
|
|
2020-11-20 10:00:22 +00:00
|
|
|
proc start*(m: Eth1Monitor) =
|
2019-11-22 13:16:07 +00:00
|
|
|
m.start(0.seconds)
|
|
|
|
|
2020-07-28 13:36:11 +00:00
|
|
|
proc getEth1BlockHash*(url: string, blockId: RtBlockIdentifier): Future[BlockHash] {.async.} =
|
2019-10-25 14:53:31 +00:00
|
|
|
let web3 = await newWeb3(url)
|
2020-04-22 23:35:55 +00:00
|
|
|
try:
|
2020-12-01 21:20:28 +00:00
|
|
|
let blk = awaitWithRetries(
|
|
|
|
web3.provider.eth_getBlockByNumber(blockId, false))
|
2020-07-28 13:36:11 +00:00
|
|
|
return blk.hash
|
2020-04-22 23:35:55 +00:00
|
|
|
finally:
|
|
|
|
await web3.close()
|
|
|
|
|
2020-12-04 16:28:42 +00:00
|
|
|
proc testWeb3Provider*(web3Url: Uri,
|
2021-02-22 16:17:48 +00:00
|
|
|
depositContractAddress: Eth1Address) {.async.} =
|
2020-12-04 16:28:42 +00:00
|
|
|
template mustSucceed(action: static string, expr: untyped): untyped =
|
|
|
|
try: expr
|
|
|
|
except CatchableError as err:
|
|
|
|
fatal("Failed to " & action, err = err.msg)
|
|
|
|
quit 1
|
|
|
|
|
|
|
|
let
|
|
|
|
web3 = mustSucceed "connect to web3 provider":
|
|
|
|
await newWeb3($web3Url)
|
|
|
|
network = mustSucceed "get network version":
|
|
|
|
awaitWithRetries web3.provider.net_version()
|
|
|
|
latestBlock = mustSucceed "get latest block":
|
|
|
|
awaitWithRetries web3.provider.eth_getBlockByNumber(blockId("latest"), false)
|
|
|
|
|
|
|
|
echo "Network: ", network
|
|
|
|
echo "Latest block: ", latestBlock.number.uint64
|
|
|
|
|
2021-02-22 16:17:48 +00:00
|
|
|
let ns = web3.contractSender(DepositContract, depositContractAddress)
|
|
|
|
try:
|
|
|
|
let depositRoot = awaitWithRetries(
|
|
|
|
ns.get_deposit_root.call(blockNumber = latestBlock.number.uint64))
|
|
|
|
echo "Deposit root: ", depositRoot
|
|
|
|
except CatchableError as err:
|
|
|
|
echo "Web3 provider is not archive mode: ", err.msg
|
2020-12-04 16:28:42 +00:00
|
|
|
|
2020-11-24 21:21:47 +00:00
|
|
|
when hasGenesisDetection:
|
|
|
|
proc init*(T: type Eth1Monitor,
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
cfg: RuntimeConfig,
|
2021-12-23 14:58:54 +00:00
|
|
|
db: BeaconChainDB,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Urls: seq[string],
|
2020-11-24 21:21:47 +00:00
|
|
|
depositContractDeployedAt: BlockHashOrNumber,
|
2021-11-25 16:51:51 +00:00
|
|
|
eth1Network: Option[Eth1Network],
|
|
|
|
forcePolling: bool): Future[Result[T, string]] {.async.} =
|
2021-04-06 21:42:59 +00:00
|
|
|
doAssert web3Urls.len > 0
|
2020-11-24 21:21:47 +00:00
|
|
|
try:
|
2021-04-06 21:42:59 +00:00
|
|
|
var urlIdx = 0
|
2021-12-23 14:58:54 +00:00
|
|
|
let dataProviderRes = await Web3DataProvider.new(cfg.DEPOSIT_CONTRACT_ADDRESS, web3Urls[urlIdx])
|
2020-11-24 21:21:47 +00:00
|
|
|
if dataProviderRes.isErr:
|
|
|
|
return err(dataProviderRes.error)
|
2020-12-15 21:59:29 +00:00
|
|
|
var dataProvider = dataProviderRes.get
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
let knownStartBlockHash =
|
|
|
|
if depositContractDeployedAt.isHash:
|
|
|
|
depositContractDeployedAt.hash
|
|
|
|
else:
|
|
|
|
var blk: BlockObject
|
|
|
|
while true:
|
|
|
|
try:
|
2020-12-01 21:20:28 +00:00
|
|
|
blk = awaitWithRetries(
|
|
|
|
dataProvider.getBlockByNumber(depositContractDeployedAt.number))
|
2020-11-24 21:21:47 +00:00
|
|
|
break
|
|
|
|
except CatchableError as err:
|
|
|
|
error "Failed to obtain details for the starting block " &
|
|
|
|
"of the deposit contract sync. The Web3 provider " &
|
|
|
|
"may still be not fully synced", error = err.msg
|
|
|
|
await sleepAsync(chronos.seconds(10))
|
|
|
|
# TODO: After a single failure, the web3 object may enter a state
|
|
|
|
# where it's no longer possible to make additional requests.
|
|
|
|
# Until this is fixed upstream, we'll just try to recreate
|
|
|
|
# the web3 provider before retrying. In case this fails,
|
|
|
|
# the Eth1Monitor will be restarted.
|
2021-04-06 21:42:59 +00:00
|
|
|
inc urlIdx
|
2020-11-24 21:21:47 +00:00
|
|
|
dataProvider = tryGet(
|
2021-12-23 14:58:54 +00:00
|
|
|
await Web3DataProvider.new(cfg.DEPOSIT_CONTRACT_ADDRESS,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Urls[urlIdx mod web3Urls.len]))
|
2020-11-24 21:21:47 +00:00
|
|
|
blk.hash.asEth2Digest
|
|
|
|
|
|
|
|
let depositContractSnapshot = DepositContractSnapshot(
|
|
|
|
eth1Block: knownStartBlockHash)
|
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
var monitor = Eth1Monitor.init(
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
cfg,
|
2021-12-23 14:58:54 +00:00
|
|
|
db,
|
2021-04-06 21:42:59 +00:00
|
|
|
web3Urls,
|
2020-11-24 21:21:47 +00:00
|
|
|
depositContractSnapshot,
|
2021-11-25 16:51:51 +00:00
|
|
|
eth1Network,
|
|
|
|
forcePolling)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
for i in 0 ..< db.genesisDeposits.len:
|
|
|
|
monitor.produceDerivedData db.genesisDeposits.get(i)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
return ok monitor
|
2020-11-24 21:21:47 +00:00
|
|
|
|
2020-12-15 21:59:29 +00:00
|
|
|
except CatchableError as err:
|
|
|
|
return err("Failed to initialize the Eth1 monitor")
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
proc findGenesisBlockInRange(m: Eth1Monitor, startBlock, endBlock: Eth1Block):
|
|
|
|
Future[Eth1Block] {.async.} =
|
|
|
|
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
|
|
|
|
depositData = startBlock.voteData
|
|
|
|
activeValidatorsCountDuringRange = startBlock.activeValidatorsCount
|
|
|
|
|
|
|
|
while startBlock.number + 1 < endBlock.number:
|
|
|
|
let
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
MIN_GENESIS_TIME = m.cfg.MIN_GENESIS_TIME
|
|
|
|
startBlockTime = genesis_time_from_eth1_timestamp(m.cfg, startBlock.timestamp)
|
2020-11-24 21:21:47 +00:00
|
|
|
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)
|
2020-12-01 21:20:28 +00:00
|
|
|
candidateBlock = awaitWithRetries(
|
|
|
|
m.dataProvider.getBlockByNumber(candidateNumber))
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
var candidateAsEth1Block = Eth1Block(number: candidateBlock.number.uint64,
|
|
|
|
timestamp: candidateBlock.timestamp.uint64,
|
|
|
|
voteData: depositData)
|
|
|
|
candidateAsEth1Block.voteData.block_hash = candidateBlock.hash.asEth2Digest
|
|
|
|
|
|
|
|
let candidateGenesisTime = genesis_time_from_eth1_timestamp(
|
Implement split preset/config support (#2710)
* Implement split preset/config support
This is the initial bulk refactor to introduce runtime config values in
a number of places, somewhat replacing the existing mechanism of loading
network metadata.
It still needs more work, this is the initial refactor that introduces
runtime configuration in some of the places that need it.
The PR changes the way presets and constants work, to match the spec. In
particular, a "preset" now refers to the compile-time configuration
while a "cfg" or "RuntimeConfig" is the dynamic part.
A single binary can support either mainnet or minimal, but not both.
Support for other presets has been removed completely (can be readded,
in case there's need).
There's a number of outstanding tasks:
* `SECONDS_PER_SLOT` still needs fixing
* loading custom runtime configs needs redoing
* checking constants against YAML file
* yeerongpilly support
`build/nimbus_beacon_node --network=yeerongpilly --discv5:no --log-level=DEBUG`
* load fork epoch from config
* fix fork digest sent in status
* nicer error string for request failures
* fix tools
* one more
* fixup
* fixup
* fixup
* use "standard" network definition folder in local testnet
Files are loaded from their standard locations, including genesis etc,
to conform to the format used in the `eth2-networks` repo.
* fix launch scripts, allow unknown config values
* fix base config of rest test
* cleanups
* bundle mainnet config using common loader
* fix spec links and names
* only include supported preset in binary
* drop yeerongpilly, add altair-devnet-0, support boot_enr.yaml
2021-07-12 13:01:38 +00:00
|
|
|
m.cfg, candidateBlock.timestamp.uint64)
|
2020-11-24 21:21:47 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2021-12-23 14:58:54 +00:00
|
|
|
proc waitGenesis*(m: Eth1Monitor): Future[GenesisStateRef] {.async.} =
|
2020-11-24 21:21:47 +00:00
|
|
|
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
|
2021-12-23 14:58:54 +00:00
|
|
|
return nil
|