From 101b723f52e837aaecc8feffeab7e566bafb980e Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 9 Nov 2023 21:41:17 +0100 Subject: [PATCH] make `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` configurable (#5582) * make `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` configurable Gnosis uses custom `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` to account for the faster slot timing, so that blobs still remain available for roughly the same amount of real time. Also extend REST config endpoint with full config form `v1.4.0-beta.4`, and extend compatibility checks when loading configs to reduce warnings. --- beacon_chain/nimbus_beacon_node.nim | 10 +- beacon_chain/rpc/rest_config_api.nim | 48 ++++- beacon_chain/spec/datatypes/base.nim | 6 +- beacon_chain/spec/datatypes/constants.nim | 9 +- beacon_chain/spec/presets.nim | 239 ++++++++++++++++++---- beacon_chain/sync/sync_manager.nim | 7 +- beacon_chain/sync/sync_protocol.nim | 4 +- ncli/resttest-rules.json | 2 +- 8 files changed, 269 insertions(+), 56 deletions(-) diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index cdb709527..eb1cfedd5 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -423,11 +423,15 @@ proc initFullNode( validatorChangePool, node.attachedValidators, syncCommitteeMsgPool, lightClientPool, quarantine, blobQuarantine, rng, getBeaconTime, taskpool) syncManager = newSyncManager[Peer, PeerId]( - node.network.peerPool, dag.cfg.DENEB_FORK_EPOCH, SyncQueueKind.Forward, getLocalHeadSlot, + node.network.peerPool, + dag.cfg.DENEB_FORK_EPOCH, dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, + SyncQueueKind.Forward, getLocalHeadSlot, getLocalWallSlot, getFirstSlotAtFinalizedEpoch, getBackfillSlot, getFrontfillSlot, dag.tail.slot, blockVerifier) backfiller = newSyncManager[Peer, PeerId]( - node.network.peerPool, dag.cfg.DENEB_FORK_EPOCH, SyncQueueKind.Backward, getLocalHeadSlot, + node.network.peerPool, + dag.cfg.DENEB_FORK_EPOCH, dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, + SyncQueueKind.Backward, getLocalHeadSlot, getLocalWallSlot, getFirstSlotAtFinalizedEpoch, getBackfillSlot, getFrontfillSlot, dag.backfill.slot, blockVerifier, maxHeadAge = 0) @@ -1326,7 +1330,7 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} = proc pruneBlobs(node: BeaconNode, slot: Slot) = let blobPruneEpoch = (slot.epoch - - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS - 1) + node.dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS - 1) if slot.is_epoch() and blobPruneEpoch >= node.dag.cfg.DENEB_FORK_EPOCH: var blocks: array[SLOTS_PER_EPOCH.int, BlockId] var count = 0 diff --git a/beacon_chain/rpc/rest_config_api.nim b/beacon_chain/rpc/rest_config_api.nim index 17937a306..970c4a497 100644 --- a/beacon_chain/rpc/rest_config_api.nim +++ b/beacon_chain/rpc/rest_config_api.nim @@ -138,7 +138,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) = KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: Base10.toString(uint64(KZG_COMMITMENT_INCLUSION_PROOF_DEPTH)), - # https://github.com/ethereum/consensus-specs/blob/v1.3.0/configs/mainnet.yaml + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/configs/mainnet.yaml PRESET_BASE: cfg.PRESET_BASE, CONFIG_NAME: @@ -197,12 +197,56 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) = Base10.toString(cfg.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT), PROPOSER_SCORE_BOOST: Base10.toString(PROPOSER_SCORE_BOOST), + REORG_HEAD_WEIGHT_THRESHOLD: + Base10.toString(REORG_HEAD_WEIGHT_THRESHOLD), + REORG_PARENT_WEIGHT_THRESHOLD: + Base10.toString(REORG_PARENT_WEIGHT_THRESHOLD), + REORG_MAX_EPOCHS_SINCE_FINALIZATION: + Base10.toString(uint64(REORG_MAX_EPOCHS_SINCE_FINALIZATION)), DEPOSIT_CHAIN_ID: Base10.toString(cfg.DEPOSIT_CHAIN_ID), DEPOSIT_NETWORK_ID: Base10.toString(cfg.DEPOSIT_NETWORK_ID), DEPOSIT_CONTRACT_ADDRESS: $cfg.DEPOSIT_CONTRACT_ADDRESS, + GOSSIP_MAX_SIZE: + Base10.toString(GOSSIP_MAX_SIZE), + MAX_REQUEST_BLOCKS: + Base10.toString(MAX_REQUEST_BLOCKS), + EPOCHS_PER_SUBNET_SUBSCRIPTION: + Base10.toString(EPOCHS_PER_SUBNET_SUBSCRIPTION), + MIN_EPOCHS_FOR_BLOCK_REQUESTS: + Base10.toString(cfg.MIN_EPOCHS_FOR_BLOCK_REQUESTS), + MAX_CHUNK_SIZE: + Base10.toString(MAX_CHUNK_SIZE), + TTFB_TIMEOUT: + Base10.toString(TTFB_TIMEOUT), + RESP_TIMEOUT: + Base10.toString(RESP_TIMEOUT), + ATTESTATION_PROPAGATION_SLOT_RANGE: + Base10.toString(ATTESTATION_PROPAGATION_SLOT_RANGE), + MAXIMUM_GOSSIP_CLOCK_DISPARITY: + Base10.toString(MAXIMUM_GOSSIP_CLOCK_DISPARITY.milliseconds.uint64), + MESSAGE_DOMAIN_INVALID_SNAPPY: + to0xHex(MESSAGE_DOMAIN_INVALID_SNAPPY), + MESSAGE_DOMAIN_VALID_SNAPPY: + to0xHex(MESSAGE_DOMAIN_VALID_SNAPPY), + SUBNETS_PER_NODE: + Base10.toString(SUBNETS_PER_NODE), + ATTESTATION_SUBNET_COUNT: + Base10.toString(ATTESTATION_SUBNET_COUNT), + ATTESTATION_SUBNET_EXTRA_BITS: + Base10.toString(ATTESTATION_SUBNET_EXTRA_BITS), + ATTESTATION_SUBNET_PREFIX_BITS: + Base10.toString(ATTESTATION_SUBNET_PREFIX_BITS), + MAX_REQUEST_BLOCKS_DENEB: + Base10.toString(MAX_REQUEST_BLOCKS_DENEB), + MAX_REQUEST_BLOB_SIDECARS: + Base10.toString(MAX_REQUEST_BLOB_SIDECARS), + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: + Base10.toString(cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS), + BLOB_SIDECAR_SUBNET_COUNT: + Base10.toString(BLOB_SIDECAR_SUBNET_COUNT), # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/beacon-chain.md#constants # GENESIS_SLOT @@ -265,8 +309,6 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) = # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#constants TARGET_AGGREGATORS_PER_COMMITTEE: Base10.toString(TARGET_AGGREGATORS_PER_COMMITTEE), - ATTESTATION_SUBNET_COUNT: - Base10.toString(ATTESTATION_SUBNET_COUNT), # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/altair/validator.md#constants TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE: diff --git a/beacon_chain/spec/datatypes/base.nim b/beacon_chain/spec/datatypes/base.nim index 7b9bec795..c7fe91a77 100644 --- a/beacon_chain/spec/datatypes/base.nim +++ b/beacon_chain/spec/datatypes/base.nim @@ -65,13 +65,12 @@ import stew/[assign2, byteutils, results], chronicles, json_serialization, - chronos/timer, ssz_serialization/types as sszTypes, ../../version, ".."/[beacon_time, crypto, digest, presets] export - tables, results, json_serialization, timer, sszTypes, beacon_time, crypto, + tables, results, json_serialization, sszTypes, beacon_time, crypto, digest, presets const SPEC_VERSION* = "1.4.0-beta.4" @@ -82,9 +81,6 @@ const ZERO_HASH* = Eth2Digest() MAX_GRAFFITI_SIZE* = 32 - # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/p2p-interface.md#configuration - MAXIMUM_GOSSIP_CLOCK_DISPARITY* = 500.millis - SLOTS_PER_ETH1_VOTING_PERIOD* = EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index 44306d2c7..630f86a10 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -5,6 +5,8 @@ # * 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. +import chronos/timer + type Slot* = distinct uint64 Epoch* = distinct uint64 @@ -54,8 +56,11 @@ const # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/specs/capella/beacon-chain.md#domain-types DOMAIN_BLS_TO_EXECUTION_CHANGE* = DomainType([byte 0x0a, 0x00, 0x00, 0x00]) - # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/fork-choice.md#configuration + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/specs/phase0/fork-choice.md#configuration PROPOSER_SCORE_BOOST*: uint64 = 40 + REORG_HEAD_WEIGHT_THRESHOLD*: uint64 = 20 + REORG_PARENT_WEIGHT_THRESHOLD*: uint64 = 160 + REORG_MAX_EPOCHS_SINCE_FINALIZATION* = Epoch(2) # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/deneb/p2p-interface.md#configuration BLOB_SIDECAR_SUBNET_COUNT*: uint64 = 6 @@ -64,11 +69,11 @@ const MAX_REQUEST_BLOCKS* = 1024'u64 RESP_TIMEOUT* = 10'u64 ATTESTATION_PROPAGATION_SLOT_RANGE*: uint64 = 32 + MAXIMUM_GOSSIP_CLOCK_DISPARITY* = 500.millis # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/p2p-interface.md#configuration GOSSIP_MAX_SIZE* = 10'u64 * 1024 * 1024 # bytes MAX_CHUNK_SIZE* = 10'u64 * 1024 * 1024 # bytes # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/deneb/p2p-interface.md#configuration - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS*: uint64 = 4096 MAX_REQUEST_BLOCKS_DENEB*: uint64 = 128 # TODO Make use of in request code diff --git a/beacon_chain/spec/presets.nim b/beacon_chain/spec/presets.nim index a2b42b19c..74c4c98b3 100644 --- a/beacon_chain/spec/presets.nim +++ b/beacon_chain/spec/presets.nim @@ -9,6 +9,7 @@ import std/[strutils, parseutils, tables, typetraits], + chronos/timer, stew/[byteutils], stint, web3/[ethtypes], ./datatypes/constants @@ -26,21 +27,23 @@ const # Not used anywhere; only for network preset checking EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: uint64 = 256 - MESSAGE_DOMAIN_INVALID_SNAPPY = 0'u64 - TTFB_TIMEOUT = 5'u64 + TTFB_TIMEOUT* = 5'u64 + MESSAGE_DOMAIN_INVALID_SNAPPY*: array[4, byte] = [0x00, 0x00, 0x00, 0x00] + MESSAGE_DOMAIN_VALID_SNAPPY*: array[4, byte] = [0x01, 0x00, 0x00, 0x00] type Version* = distinct array[4, byte] Eth1Address* = ethtypes.Address RuntimeConfig* = object - ## https://github.com/ethereum/consensus-specs/tree/v1.3.0/configs + ## https://github.com/ethereum/consensus-specs/tree/v1.4.0-beta.4/configs PRESET_BASE*: string CONFIG_NAME*: string # Transition TERMINAL_TOTAL_DIFFICULTY*: UInt256 TERMINAL_BLOCK_HASH*: BlockHash + TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH*: Epoch # Not actively used, but part of the spec # Genesis MIN_GENESIS_ACTIVE_VALIDATOR_COUNT*: uint64 @@ -75,14 +78,37 @@ type # Fork choice # TODO PROPOSER_SCORE_BOOST*: uint64 + # TODO REORG_HEAD_WEIGHT_THRESHOLD*: uint64 + # TODO REORG_PARENT_WEIGHT_THRESHOLD*: uint64 + # TODO REORG_MAX_EPOCHS_SINCE_FINALIZATION*: uint64 # Deposit contract DEPOSIT_CHAIN_ID*: uint64 DEPOSIT_NETWORK_ID*: uint64 DEPOSIT_CONTRACT_ADDRESS*: Eth1Address - # Not actively used, but part of the spec - TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH*: Epoch + # Networking + # TODO GOSSIP_MAX_SIZE*: uint64 + # TODO MAX_REQUEST_BLOCKS*: uint64 + # TODO EPOCHS_PER_SUBNET_SUBSCRIPTION*: uint64 + # TODO MIN_EPOCHS_FOR_BLOCK_REQUESTS*: uint64 + # TODO MAX_CHUNK_SIZE*: uint64 + # TODO TTFB_TIMEOUT*: uint64 + # TODO RESP_TIMEOUT*: uint64 + # TODO ATTESTATION_PROPAGATION_SLOT_RANGE*: uint64 + # TODO MAXIMUM_GOSSIP_CLOCK_DISPARITY*: uint64 + # TODO MESSAGE_DOMAIN_INVALID_SNAPPY*: array[4, byte] + # TODO MESSAGE_DOMAIN_VALID_SNAPPY*: array[4, byte] + # TODO SUBNETS_PER_NODE*: uint64 + # TODO ATTESTATION_SUBNET_COUNT*: uint64 + # TODO ATTESTATION_SUBNET_EXTRA_BITS*: uint64 + # TODO ATTESTATION_SUBNET_PREFIX_BITS*: uint64 + + # Deneb + # TODO MAX_REQUEST_BLOCKS_DENEB*: uint64 + # TODO MAX_REQUEST_BLOB_SIDECARS*: uint64 + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS*: uint64 + # TODO BLOB_SIDECAR_SUBNET_COUNT*: uint64 PresetFile* = object values*: Table[string, string] @@ -203,7 +229,46 @@ when const_preset == "mainnet": # Ethereum PoW Mainnet DEPOSIT_CHAIN_ID: 1, DEPOSIT_NETWORK_ID: 1, - DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address) + DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address), + + # Networking + # --------------------------------------------------------------- + # `10 * 2**20` (= 10485760, 10 MiB) + # TODO GOSSIP_MAX_SIZE: 10485760, + # `2**10` (= 1024) + # TODO MAX_REQUEST_BLOCKS: 1024, + # `2**8` (= 256) + # TODO EPOCHS_PER_SUBNET_SUBSCRIPTION: 256, + # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) + # TODO MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024, + # `10 * 2**20` (=10485760, 10 MiB) + # TODO MAX_CHUNK_SIZE: 10485760, + # 5s + # TODO TTFB_TIMEOUT: 5, + # 10s + # TODO RESP_TIMEOUT: 10, + # TODO ATTESTATION_PROPAGATION_SLOT_RANGE: 32, + # 500ms + # TODO MAXIMUM_GOSSIP_CLOCK_DISPARITY: 500, + # TODO MESSAGE_DOMAIN_INVALID_SNAPPY: [byte 0x00, 0x00, 0x00, 0x00], + # TODO MESSAGE_DOMAIN_VALID_SNAPPY: [byte 0x01, 0x00, 0x00, 0x00], + # 2 subnets per node + # TODO SUBNETS_PER_NODE: 2, + # 2**8 (= 64) + # TODO ATTESTATION_SUBNET_COUNT: 64, + # TODO ATTESTATION_SUBNET_EXTRA_BITS: 0, + # ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS + # TODO ATTESTATION_SUBNET_PREFIX_BITS: 6, + + # Deneb + # `2**7` (=128) + # TODO MAX_REQUEST_BLOCKS_DENEB: 128, + # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK + # TODO MAX_REQUEST_BLOB_SIDECARS: 768, + # `2**12` (= 4096 epochs, ~18 days) + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + # `6` + # TODO BLOB_SIDECAR_SUBNET_COUNT: 6, ) elif const_preset == "gnosis": @@ -309,7 +374,46 @@ elif const_preset == "gnosis": # Gnosis PoW Mainnet DEPOSIT_CHAIN_ID: 100, DEPOSIT_NETWORK_ID: 100, - DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address) + DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address), + + # Networking + # --------------------------------------------------------------- + # `10 * 2**20` (= 10485760, 10 MiB) + # TODO GOSSIP_MAX_SIZE: 10485760, + # `2**10` (= 1024) + # TODO MAX_REQUEST_BLOCKS: 1024, + # `2**8` (= 256) + # TODO EPOCHS_PER_SUBNET_SUBSCRIPTION: 256, + # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) + # TODO MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024, + # `10 * 2**20` (=10485760, 10 MiB) + # TODO MAX_CHUNK_SIZE: 10485760, + # 5s + # TODO TTFB_TIMEOUT: 5, + # 10s + # TODO RESP_TIMEOUT: 10, + # TODO ATTESTATION_PROPAGATION_SLOT_RANGE: 32, + # 500ms + # TODO MAXIMUM_GOSSIP_CLOCK_DISPARITY: 500, + # TODO MESSAGE_DOMAIN_INVALID_SNAPPY: [byte 0x00, 0x00, 0x00, 0x00], + # TODO MESSAGE_DOMAIN_VALID_SNAPPY: [byte 0x01, 0x00, 0x00, 0x00], + # 2 subnets per node + # TODO SUBNETS_PER_NODE: 2, + # 2**8 (= 64) + # TODO ATTESTATION_SUBNET_COUNT: 64, + # TODO ATTESTATION_SUBNET_EXTRA_BITS: 0, + # ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS + # TODO ATTESTATION_SUBNET_PREFIX_BITS: 6, + + # Deneb + # `2**7` (=128) + # TODO MAX_REQUEST_BLOCKS_DENEB: 128, + # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK + # TODO MAX_REQUEST_BLOB_SIDECARS: 768, + # `2**12` (= 4096 epochs, ~18 days) + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 16384, + # `6` + # TODO BLOB_SIDECAR_SUBNET_COUNT: 6, ) elif const_preset == "minimal": @@ -412,7 +516,46 @@ elif const_preset == "minimal": DEPOSIT_CHAIN_ID: 5, DEPOSIT_NETWORK_ID: 5, # Configured on a per testnet basis - DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address) + DEPOSIT_CONTRACT_ADDRESS: default(Eth1Address), + + # Networking + # --------------------------------------------------------------- + # `10 * 2**20` (= 10485760, 10 MiB) + # TODO GOSSIP_MAX_SIZE: 10485760, + # `2**10` (= 1024) + # TODO MAX_REQUEST_BLOCKS: 1024, + # `2**8` (= 256) + # TODO EPOCHS_PER_SUBNET_SUBSCRIPTION: 256, + # [customized] `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 272) + # TODO MIN_EPOCHS_FOR_BLOCK_REQUESTS: 272, + # `10 * 2**20` (=10485760, 10 MiB) + # TODO MAX_CHUNK_SIZE: 10485760, + # 5s + # TODO TTFB_TIMEOUT: 5, + # 10s + # TODO RESP_TIMEOUT: 10, + # TODO ATTESTATION_PROPAGATION_SLOT_RANGE: 32, + # 500ms + # TODO MAXIMUM_GOSSIP_CLOCK_DISPARITY: 500, + # TODO MESSAGE_DOMAIN_INVALID_SNAPPY: [byte 0x00, 0x00, 0x00, 0x00], + # TODO MESSAGE_DOMAIN_VALID_SNAPPY: [byte 0x01, 0x00, 0x00, 0x00], + # 2 subnets per node + # TODO SUBNETS_PER_NODE: 2, + # 2**8 (= 64) + # TODO ATTESTATION_SUBNET_COUNT: 64, + # TODO ATTESTATION_SUBNET_EXTRA_BITS: 0, + # ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS + # TODO ATTESTATION_SUBNET_PREFIX_BITS: 6, + + # Deneb + # `2**7` (=128) + # TODO MAX_REQUEST_BLOCKS_DENEB: 128, + # MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK + # TODO MAX_REQUEST_BLOB_SIDECARS: 768, + # `2**12` (= 4096 epochs, ~18 days) + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, + # `6` + # TODO BLOB_SIDECAR_SUBNET_COUNT: 6, ) else: @@ -443,6 +586,10 @@ else: const SLOTS_PER_SYNC_COMMITTEE_PERIOD* = SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD +# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#configuration +func MIN_EPOCHS_FOR_BLOCK_REQUESTS*(cfg: RuntimeConfig): uint64 = + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + cfg.CHURN_LIMIT_QUOTIENT div 2 + func parse(T: type uint64, input: string): T {.raises: [ValueError].} = var res: BiggestUInt if input.len > 2 and input[0] == '0' and input[1] == 'x': @@ -457,6 +604,10 @@ func parse(T: type uint64, input: string): T {.raises: [ValueError].} = template parse(T: type byte, input: string): T = byte parse(uint64, input) +func parse(T: type array[4, byte], input: string): T + {.raises: [ValueError].} = + hexToByteArray(input, 4) + func parse(T: type Version, input: string): T {.raises: [ValueError].} = Version hexToByteArray(input, 4) @@ -517,27 +668,30 @@ proc readRuntimeConfig*( # Certain config keys are baked into the binary at compile-time # and cannot be overridden via config. + template checkCompatibility(constValue: untyped, name: string): untyped = + if values.hasKey(name): + try: + let value = parse(typeof(constValue), values[name]) + when constValue is distinct: + if distinctBase(value) != distinctBase(constValue): + raise (ref PresetFileError)(msg: + "Cannot override config" & + " (compiled: " & name & "=" & $distinctBase(constValue) & + " - config: " & name & "=" & values[name] & ")") + else: + if value != constValue: + raise (ref PresetFileError)(msg: + "Cannot override config" & + " (compiled: " & name & "=" & $constValue & + " - config: " & name & "=" & values[name] & ")") + values.del name + except ValueError: + raise (ref PresetFileError)(msg: "Unable to parse " & name) + template checkCompatibility(constValue: untyped): untyped = block: const name = astToStr(constValue) - if values.hasKey(name): - try: - let value = parse(typeof(constValue), values[name]) - when constValue is distinct: - if distinctBase(value) != distinctBase(constValue): - raise (ref PresetFileError)(msg: - "Cannot override config" & - " (compiled: " & name & "=" & $distinctBase(constValue) & - " - config: " & name & "=" & values[name] & ")") - else: - if value != constValue: - raise (ref PresetFileError)(msg: - "Cannot override config" & - " (compiled: " & name & "=" & $constValue & - " - config: " & name & "=" & values[name] & ")") - values.del name - except ValueError: - raise (ref PresetFileError)(msg: "Unable to parse " & name) + checkCompatibility(constValue, name) checkCompatibility SECONDS_PER_SLOT @@ -578,7 +732,6 @@ proc readRuntimeConfig*( checkCompatibility TARGET_AGGREGATORS_PER_COMMITTEE checkCompatibility EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION - checkCompatibility ATTESTATION_SUBNET_COUNT checkCompatibility DOMAIN_BEACON_PROPOSER checkCompatibility DOMAIN_BEACON_ATTESTER @@ -595,19 +748,29 @@ proc readRuntimeConfig*( checkCompatibility MAX_REQUEST_BLOCKS checkCompatibility EPOCHS_PER_SUBNET_SUBSCRIPTION checkCompatibility MAX_CHUNK_SIZE + checkCompatibility TTFB_TIMEOUT + checkCompatibility RESP_TIMEOUT + checkCompatibility ATTESTATION_PROPAGATION_SLOT_RANGE + checkCompatibility MAXIMUM_GOSSIP_CLOCK_DISPARITY.milliseconds.uint64, + "MAXIMUM_GOSSIP_CLOCK_DISPARITY" + checkCompatibility MESSAGE_DOMAIN_INVALID_SNAPPY + checkCompatibility MESSAGE_DOMAIN_VALID_SNAPPY checkCompatibility SUBNETS_PER_NODE + checkCompatibility ATTESTATION_SUBNET_COUNT checkCompatibility ATTESTATION_SUBNET_EXTRA_BITS checkCompatibility ATTESTATION_SUBNET_PREFIX_BITS - checkCompatibility BLOB_SIDECAR_SUBNET_COUNT - checkCompatibility MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS - checkCompatibility RESP_TIMEOUT - checkCompatibility TTFB_TIMEOUT - checkCompatibility MESSAGE_DOMAIN_INVALID_SNAPPY - checkCompatibility MAX_REQUEST_BLOCKS_DENEB - checkCompatibility ATTESTATION_PROPAGATION_SLOT_RANGE + checkCompatibility MAX_REQUEST_BLOCKS_DENEB + checkCompatibility MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK, + "MAX_REQUEST_BLOB_SIDECARS" + checkCompatibility BLOB_SIDECAR_SUBNET_COUNT + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/specs/phase0/fork-choice.md#configuration # Isn't being used as a preset in the usual way: at any time, there's one correct value checkCompatibility PROPOSER_SCORE_BOOST + checkCompatibility REORG_HEAD_WEIGHT_THRESHOLD + checkCompatibility REORG_PARENT_WEIGHT_THRESHOLD + checkCompatibility REORG_MAX_EPOCHS_SINCE_FINALIZATION for name, field in cfg.fieldPairs(): if name in values: @@ -621,6 +784,10 @@ proc readRuntimeConfig*( raise (ref PresetIncompatibleError)( msg: "Config not compatible with binary, compile with -d:const_preset=" & cfg.PRESET_BASE) + # Requires initialized `cfg` + checkCompatibility cfg.MIN_EPOCHS_FOR_BLOCK_REQUESTS, + "MIN_EPOCHS_FOR_BLOCK_REQUESTS" + var unknowns: seq[string] for name in values.keys: unknowns.add name @@ -638,10 +805,6 @@ template name*(cfg: RuntimeConfig): string = else: const_preset -# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#configuration -func MIN_EPOCHS_FOR_BLOCK_REQUESTS*(cfg: RuntimeConfig): uint64 = - cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + cfg.CHURN_LIMIT_QUOTIENT div 2 - func defaultLightClientDataMaxPeriods*(cfg: RuntimeConfig): uint64 = const epochsPerPeriod = EPOCHS_PER_SYNC_COMMITTEE_PERIOD let maxEpochs = cfg.MIN_EPOCHS_FOR_BLOCK_REQUESTS diff --git a/beacon_chain/sync/sync_manager.nim b/beacon_chain/sync/sync_manager.nim index c0c35567e..4200bc9bc 100644 --- a/beacon_chain/sync/sync_manager.nim +++ b/beacon_chain/sync/sync_manager.nim @@ -49,6 +49,7 @@ type SyncManager*[A, B] = ref object pool: PeerPool[A, B] DENEB_FORK_EPOCH: Epoch + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: uint64 responseTimeout: chronos.Duration maxHeadAge: uint64 getLocalHeadSlot: GetSlotCallback @@ -116,6 +117,7 @@ proc initQueue[A, B](man: SyncManager[A, B]) = proc newSyncManager*[A, B](pool: PeerPool[A, B], denebEpoch: Epoch, + minEpochsForBlobSidecarsRequests: uint64, direction: SyncQueueKind, getLocalHeadSlotCb: GetSlotCallback, getLocalWallSlotCb: GetSlotCallback, @@ -138,6 +140,7 @@ proc newSyncManager*[A, B](pool: PeerPool[A, B], var res = SyncManager[A, B]( pool: pool, DENEB_FORK_EPOCH: denebEpoch, + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: minEpochsForBlobSidecarsRequests, getLocalHeadSlot: getLocalHeadSlotCb, getLocalWallSlot: getLocalWallSlotCb, getSafeSlot: getSafeSlot, @@ -187,8 +190,8 @@ proc getBlocks*[A, B](man: SyncManager[A, B], peer: A, proc shouldGetBlobs[A, B](man: SyncManager[A, B], e: Epoch): bool = let wallEpoch = man.getLocalWallSlot().epoch e >= man.DENEB_FORK_EPOCH and - (wallEpoch < MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS or - e >= wallEpoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) + (wallEpoch < man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS or + e >= wallEpoch - man.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) proc getBlobSidecars*[A, B](man: SyncManager[A, B], peer: A, req: SyncRequest): Future[BlobSidecarsRes] {.async.} = diff --git a/beacon_chain/sync/sync_protocol.nim b/beacon_chain/sync/sync_protocol.nim index 150cea622..02ae89caf 100644 --- a/beacon_chain/sync/sync_protocol.nim +++ b/beacon_chain/sync/sync_protocol.nim @@ -498,10 +498,10 @@ p2pProtocol BeaconSync(version = 1, let dag = peer.networkState.dag epochBoundary = - if MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS >= dag.head.slot.epoch: + if dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS >= dag.head.slot.epoch: GENESIS_EPOCH else: - dag.head.slot.epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS + dag.head.slot.epoch - dag.cfg.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS if startSlot.epoch < epochBoundary: raise newException(ResourceUnavailableError, BlobsOutOfRange) diff --git a/ncli/resttest-rules.json b/ncli/resttest-rules.json index 032bd9841..ec19ceb58 100644 --- a/ncli/resttest-rules.json +++ b/ncli/resttest-rules.json @@ -2826,7 +2826,7 @@ "response": { "status": {"operator": "equals", "value": "200"}, "headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}], - "body": [{"operator": "jstructcmps", "start": ["data"], "value": {"MAX_COMMITTEES_PER_SLOT":"","TARGET_COMMITTEE_SIZE":"","MAX_VALIDATORS_PER_COMMITTEE":"","SHUFFLE_ROUND_COUNT":"","HYSTERESIS_QUOTIENT":"","HYSTERESIS_DOWNWARD_MULTIPLIER":"","HYSTERESIS_UPWARD_MULTIPLIER":"","MIN_DEPOSIT_AMOUNT":"","MAX_EFFECTIVE_BALANCE":"","EFFECTIVE_BALANCE_INCREMENT":"","MIN_ATTESTATION_INCLUSION_DELAY":"","SLOTS_PER_EPOCH":"","MIN_SEED_LOOKAHEAD":"","MAX_SEED_LOOKAHEAD":"","EPOCHS_PER_ETH1_VOTING_PERIOD":"","SLOTS_PER_HISTORICAL_ROOT":"","MIN_EPOCHS_TO_INACTIVITY_PENALTY":"","EPOCHS_PER_HISTORICAL_VECTOR":"","EPOCHS_PER_SLASHINGS_VECTOR":"","HISTORICAL_ROOTS_LIMIT":"","VALIDATOR_REGISTRY_LIMIT":"","BASE_REWARD_FACTOR":"","WHISTLEBLOWER_REWARD_QUOTIENT":"","PROPOSER_REWARD_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT":"","MIN_SLASHING_PENALTY_QUOTIENT":"","PROPORTIONAL_SLASHING_MULTIPLIER":"","MAX_PROPOSER_SLASHINGS":"","MAX_ATTESTER_SLASHINGS":"","MAX_ATTESTATIONS":"","MAX_DEPOSITS":"","MAX_VOLUNTARY_EXITS":"","INACTIVITY_PENALTY_QUOTIENT_ALTAIR":"","MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR":"","PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR":"","SYNC_COMMITTEE_SIZE":"","EPOCHS_PER_SYNC_COMMITTEE_PERIOD":"","MIN_SYNC_COMMITTEE_PARTICIPANTS":"","UPDATE_TIMEOUT":"","INACTIVITY_PENALTY_QUOTIENT_BELLATRIX":"","MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX":"","PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX":"","MAX_BYTES_PER_TRANSACTION":"","MAX_TRANSACTIONS_PER_PAYLOAD":"","BYTES_PER_LOGS_BLOOM":"","MAX_EXTRA_DATA_BYTES":"","MAX_BLS_TO_EXECUTION_CHANGES":"","MAX_WITHDRAWALS_PER_PAYLOAD":"","MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP":"","PRESET_BASE":"","CONFIG_NAME":"","TERMINAL_TOTAL_DIFFICULTY":"","TERMINAL_BLOCK_HASH":"","TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":"","MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":"","MIN_GENESIS_TIME":"","GENESIS_FORK_VERSION":"","GENESIS_DELAY":"","ALTAIR_FORK_VERSION":"","ALTAIR_FORK_EPOCH":"","BELLATRIX_FORK_VERSION":"","BELLATRIX_FORK_EPOCH":"","CAPELLA_FORK_VERSION":"","CAPELLA_FORK_EPOCH":"","DENEB_FORK_VERSION":"","DENEB_FORK_EPOCH":"","SECONDS_PER_SLOT":"","SECONDS_PER_ETH1_BLOCK":"","MIN_VALIDATOR_WITHDRAWABILITY_DELAY":"","FIELD_ELEMENTS_PER_BLOB":"","MAX_BLOB_COMMITMENTS_PER_BLOCK":"","MAX_BLOBS_PER_BLOCK":"","KZG_COMMITMENT_INCLUSION_PROOF_DEPTH":"","SHARD_COMMITTEE_PERIOD":"","ETH1_FOLLOW_DISTANCE":"","INACTIVITY_SCORE_BIAS":"","INACTIVITY_SCORE_RECOVERY_RATE":"","EJECTION_BALANCE":"","MIN_PER_EPOCH_CHURN_LIMIT":"","CHURN_LIMIT_QUOTIENT":"","MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":"","PROPOSER_SCORE_BOOST":"","DEPOSIT_CHAIN_ID":"","DEPOSIT_NETWORK_ID":"","DEPOSIT_CONTRACT_ADDRESS":"","BLS_WITHDRAWAL_PREFIX":"","ETH1_ADDRESS_WITHDRAWAL_PREFIX":"","DOMAIN_BEACON_PROPOSER":"","DOMAIN_BEACON_ATTESTER":"","DOMAIN_RANDAO":"","DOMAIN_DEPOSIT":"","DOMAIN_VOLUNTARY_EXIT":"","DOMAIN_SELECTION_PROOF":"","DOMAIN_AGGREGATE_AND_PROOF":"","TIMELY_SOURCE_FLAG_INDEX":"","TIMELY_TARGET_FLAG_INDEX":"","TIMELY_HEAD_FLAG_INDEX":"","TIMELY_SOURCE_WEIGHT":"","TIMELY_TARGET_WEIGHT":"","TIMELY_HEAD_WEIGHT":"","SYNC_REWARD_WEIGHT":"","PROPOSER_WEIGHT":"","WEIGHT_DENOMINATOR":"","DOMAIN_SYNC_COMMITTEE":"","DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF":"","DOMAIN_CONTRIBUTION_AND_PROOF":"","DOMAIN_BLS_TO_EXECUTION_CHANGE":"","TARGET_AGGREGATORS_PER_COMMITTEE":"","ATTESTATION_SUBNET_COUNT":"","TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE":"","SYNC_COMMITTEE_SUBNET_COUNT":""}}] + "body": [{"operator": "jstructcmps", "start": ["data"], "value": {"MAX_COMMITTEES_PER_SLOT":"","TARGET_COMMITTEE_SIZE":"","MAX_VALIDATORS_PER_COMMITTEE":"","SHUFFLE_ROUND_COUNT":"","HYSTERESIS_QUOTIENT":"","HYSTERESIS_DOWNWARD_MULTIPLIER":"","HYSTERESIS_UPWARD_MULTIPLIER":"","MIN_DEPOSIT_AMOUNT":"","MAX_EFFECTIVE_BALANCE":"","EFFECTIVE_BALANCE_INCREMENT":"","MIN_ATTESTATION_INCLUSION_DELAY":"","SLOTS_PER_EPOCH":"","MIN_SEED_LOOKAHEAD":"","MAX_SEED_LOOKAHEAD":"","EPOCHS_PER_ETH1_VOTING_PERIOD":"","SLOTS_PER_HISTORICAL_ROOT":"","MIN_EPOCHS_TO_INACTIVITY_PENALTY":"","EPOCHS_PER_HISTORICAL_VECTOR":"","EPOCHS_PER_SLASHINGS_VECTOR":"","HISTORICAL_ROOTS_LIMIT":"","VALIDATOR_REGISTRY_LIMIT":"","BASE_REWARD_FACTOR":"","WHISTLEBLOWER_REWARD_QUOTIENT":"","PROPOSER_REWARD_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT":"","MIN_SLASHING_PENALTY_QUOTIENT":"","PROPORTIONAL_SLASHING_MULTIPLIER":"","MAX_PROPOSER_SLASHINGS":"","MAX_ATTESTER_SLASHINGS":"","MAX_ATTESTATIONS":"","MAX_DEPOSITS":"","MAX_VOLUNTARY_EXITS":"","INACTIVITY_PENALTY_QUOTIENT_ALTAIR":"","MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR":"","PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR":"","SYNC_COMMITTEE_SIZE":"","EPOCHS_PER_SYNC_COMMITTEE_PERIOD":"","MIN_SYNC_COMMITTEE_PARTICIPANTS":"","UPDATE_TIMEOUT":"","INACTIVITY_PENALTY_QUOTIENT_BELLATRIX":"","MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX":"","PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX":"","MAX_BYTES_PER_TRANSACTION":"","MAX_TRANSACTIONS_PER_PAYLOAD":"","BYTES_PER_LOGS_BLOOM":"","MAX_EXTRA_DATA_BYTES":"","MAX_BLS_TO_EXECUTION_CHANGES":"","MAX_WITHDRAWALS_PER_PAYLOAD":"","MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP":"","PRESET_BASE":"","CONFIG_NAME":"","TERMINAL_TOTAL_DIFFICULTY":"","TERMINAL_BLOCK_HASH":"","TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":"","MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":"","MIN_GENESIS_TIME":"","GENESIS_FORK_VERSION":"","GENESIS_DELAY":"","ALTAIR_FORK_VERSION":"","ALTAIR_FORK_EPOCH":"","BELLATRIX_FORK_VERSION":"","BELLATRIX_FORK_EPOCH":"","CAPELLA_FORK_VERSION":"","CAPELLA_FORK_EPOCH":"","DENEB_FORK_VERSION":"","DENEB_FORK_EPOCH":"","SECONDS_PER_SLOT":"","SECONDS_PER_ETH1_BLOCK":"","MIN_VALIDATOR_WITHDRAWABILITY_DELAY":"","FIELD_ELEMENTS_PER_BLOB":"","MAX_BLOB_COMMITMENTS_PER_BLOCK":"","MAX_BLOBS_PER_BLOCK":"","KZG_COMMITMENT_INCLUSION_PROOF_DEPTH":"","SHARD_COMMITTEE_PERIOD":"","ETH1_FOLLOW_DISTANCE":"","INACTIVITY_SCORE_BIAS":"","INACTIVITY_SCORE_RECOVERY_RATE":"","EJECTION_BALANCE":"","MIN_PER_EPOCH_CHURN_LIMIT":"","CHURN_LIMIT_QUOTIENT":"","MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":"","PROPOSER_SCORE_BOOST":"","REORG_HEAD_WEIGHT_THRESHOLD":"","REORG_PARENT_WEIGHT_THRESHOLD":"","REORG_MAX_EPOCHS_SINCE_FINALIZATION":"","DEPOSIT_CHAIN_ID":"","DEPOSIT_NETWORK_ID":"","DEPOSIT_CONTRACT_ADDRESS":"","GOSSIP_MAX_SIZE":"","MAX_REQUEST_BLOCKS":"","EPOCHS_PER_SUBNET_SUBSCRIPTION":"","MIN_EPOCHS_FOR_BLOCK_REQUESTS":"","MAX_CHUNK_SIZE":"","TTFB_TIMEOUT":"","RESP_TIMEOUT":"","ATTESTATION_PROPAGATION_SLOT_RANGE":"","MAXIMUM_GOSSIP_CLOCK_DISPARITY":"","MESSAGE_DOMAIN_INVALID_SNAPPY":"","MESSAGE_DOMAIN_VALID_SNAPPY":"","SUBNETS_PER_NODE":"","ATTESTATION_SUBNET_COUNT":"","ATTESTATION_SUBNET_EXTRA_BITS":"","ATTESTATION_SUBNET_PREFIX_BITS":"","MAX_REQUEST_BLOCKS_DENEB":"","MAX_REQUEST_BLOB_SIDECARS":"","MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS":"","BLOB_SIDECAR_SUBNET_COUNT":"","BLS_WITHDRAWAL_PREFIX":"","ETH1_ADDRESS_WITHDRAWAL_PREFIX":"","DOMAIN_BEACON_PROPOSER":"","DOMAIN_BEACON_ATTESTER":"","DOMAIN_RANDAO":"","DOMAIN_DEPOSIT":"","DOMAIN_VOLUNTARY_EXIT":"","DOMAIN_SELECTION_PROOF":"","DOMAIN_AGGREGATE_AND_PROOF":"","TIMELY_SOURCE_FLAG_INDEX":"","TIMELY_TARGET_FLAG_INDEX":"","TIMELY_HEAD_FLAG_INDEX":"","TIMELY_SOURCE_WEIGHT":"","TIMELY_TARGET_WEIGHT":"","TIMELY_HEAD_WEIGHT":"","SYNC_REWARD_WEIGHT":"","PROPOSER_WEIGHT":"","WEIGHT_DENOMINATOR":"","DOMAIN_SYNC_COMMITTEE":"","DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF":"","DOMAIN_CONTRIBUTION_AND_PROOF":"","DOMAIN_BLS_TO_EXECUTION_CHANGE":"","TARGET_AGGREGATORS_PER_COMMITTEE":"","TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE":"","SYNC_COMMITTEE_SUBNET_COUNT":""}}] } }, {