consensus spec v1.4.0 attestation stability subnets (#5092)

This commit is contained in:
tersec 2023-06-23 11:30:46 +02:00 committed by GitHub
parent fa212515f5
commit b62664915e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 11 deletions

View File

@ -258,10 +258,11 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ General pubsub topics OK + General pubsub topics OK
+ Liveness failsafe conditions OK + Liveness failsafe conditions OK
+ Mainnet attestation topics OK + Mainnet attestation topics OK
+ Stability subnets OK
+ isNearSyncCommitteePeriod OK + isNearSyncCommitteePeriod OK
+ is_aggregator OK + is_aggregator OK
``` ```
OK: 5/5 Fail: 0/5 Skip: 0/5 OK: 6/6 Fail: 0/6 Skip: 0/6
## ImportKeystores requests [Beacon Node] [Preset: mainnet] ## ImportKeystores requests [Beacon Node] [Preset: mainnet]
```diff ```diff
+ ImportKeystores/ListKeystores/DeleteKeystores [Beacon Node] [Preset: mainnet] OK + ImportKeystores/ListKeystores/DeleteKeystores [Beacon Node] [Preset: mainnet] OK
@ -691,4 +692,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 9/9 Fail: 0/9 Skip: 0/9 OK: 9/9 Fail: 0/9 Skip: 0/9
---TOTAL--- ---TOTAL---
OK: 392/397 Fail: 0/397 Skip: 5/397 OK: 393/398 Fail: 0/398 Skip: 5/398

View File

@ -341,7 +341,7 @@ func shortProtocolId(protocolId: string): string =
proc openStream(node: Eth2Node, proc openStream(node: Eth2Node,
peer: Peer, peer: Peer,
protocolId: string): Future[Connection] {.async.} = protocolId: string): Future[Connection] {.async.} =
# When dialling here, we do not provide addresses - all new connection # When dialing here, we do not provide addresses - all new connection
# attempts are handled via `connect` which also takes into account # attempts are handled via `connect` which also takes into account
# reconnection timeouts # reconnection timeouts
let let
@ -354,6 +354,10 @@ proc init(T: type Peer, network: Eth2Node, peerId: PeerId): Peer {.gcsafe.}
func peerId*(node: Eth2Node): PeerId = func peerId*(node: Eth2Node): PeerId =
node.switch.peerInfo.peerId node.switch.peerInfo.peerId
func nodeId*(node: Eth2Node): NodeId =
# `secp256k1` keys are always stored inside PeerId.
toNodeId(keys.PublicKey(node.switch.peerInfo.publicKey.skkey))
func enrRecord*(node: Eth2Node): Record = func enrRecord*(node: Eth2Node): Record =
node.discovery.localNode.record node.discovery.localNode.record

View File

@ -253,8 +253,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#constants # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#constants
TARGET_AGGREGATORS_PER_COMMITTEE: TARGET_AGGREGATORS_PER_COMMITTEE:
Base10.toString(TARGET_AGGREGATORS_PER_COMMITTEE), Base10.toString(TARGET_AGGREGATORS_PER_COMMITTEE),
RANDOM_SUBNETS_PER_VALIDATOR: RANDOM_SUBNETS_PER_VALIDATOR: "1",
Base10.toString(RANDOM_SUBNETS_PER_VALIDATOR),
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION:
Base10.toString(EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION), Base10.toString(EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION),
ATTESTATION_SUBNET_COUNT: ATTESTATION_SUBNET_COUNT:

View File

@ -15,6 +15,21 @@ type
DomainType* = distinct array[4, byte] DomainType* = distinct array[4, byte]
const
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#constants
NODE_ID_BITS* = 256
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#configuration
EPOCHS_PER_SUBNET_SUBSCRIPTION* = 256
SUBNETS_PER_NODE* = 2'u64
ATTESTATION_SUBNET_COUNT*: uint64 = 64
ATTESTATION_SUBNET_EXTRA_BITS* = 0
ATTESTATION_SUBNET_PREFIX_BITS* = 6 ## \
## int(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS)
static: doAssert 1 shl (ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_EXTRA_BITS) ==
ATTESTATION_SUBNET_COUNT
const const
# 2^64 - 1 in spec # 2^64 - 1 in spec
FAR_FUTURE_SLOT* = Slot(not 0'u64) FAR_FUTURE_SLOT* = Slot(not 0'u64)
@ -39,14 +54,11 @@ const
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/capella/beacon-chain.md#domain-types # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/capella/beacon-chain.md#domain-types
DOMAIN_BLS_TO_EXECUTION_CHANGE* = DomainType([byte 0x0a, 0x00, 0x00, 0x00]) DOMAIN_BLS_TO_EXECUTION_CHANGE* = DomainType([byte 0x0a, 0x00, 0x00, 0x00])
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#domain-types # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/deneb/beacon-chain.md#domain-types
DOMAIN_BLOB_SIDECAR* = DomainType([byte 0x0b, 0x00, 0x00, 0x00]) DOMAIN_BLOB_SIDECAR* = DomainType([byte 0x0b, 0x00, 0x00, 0x00])
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#transition-settings # https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/bellatrix/beacon-chain.md#transition-settings
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH* = FAR_FUTURE_EPOCH TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH* = FAR_FUTURE_EPOCH
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/fork-choice.md#configuration # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/fork-choice.md#configuration
PROPOSER_SCORE_BOOST*: uint64 = 40 PROPOSER_SCORE_BOOST*: uint64 = 40
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#configuration
ATTESTATION_SUBNET_COUNT*: uint64 = 64

View File

@ -470,3 +470,30 @@ func livenessFailsafeInEffect*(
streakLen = 0 streakLen = 0
false false
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#attestation-subnet-subcription
func compute_subscribed_subnet(node_id: UInt256, epoch: Epoch, index: uint64):
SubnetId =
# Ensure neither `truncate` loses information
static:
doAssert EPOCHS_PER_SUBNET_SUBSCRIPTION <= high(uint64)
doAssert sizeof(UInt256) * 8 == NODE_ID_BITS
doAssert ATTESTATION_SUBNET_PREFIX_BITS < sizeof(SubnetId) * 8
let
node_id_prefix = truncate(
node_id shr (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS), uint64)
node_offset = truncate(node_id mod EPOCHS_PER_SUBNET_SUBSCRIPTION, uint64)
permutation_seed = eth2digest(uint_to_bytes(
uint64((epoch + node_offset) div EPOCHS_PER_SUBNET_SUBSCRIPTION)))
permutated_prefix = compute_shuffled_index(
node_id_prefix,
1 shl ATTESTATION_SUBNET_PREFIX_BITS,
permutation_seed,
)
SubnetId((permutated_prefix + index) mod ATTESTATION_SUBNET_COUNT)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/p2p-interface.md#attestation-subnet-subcription
iterator compute_subscribed_subnets*(node_id: UInt256, epoch: Epoch): SubnetId =
for index in 0'u64 ..< SUBNETS_PER_NODE:
yield compute_subscribed_subnet(node_id, epoch, index)

View File

@ -1,5 +1,5 @@
# beacon_chain # beacon_chain
# Copyright (c) 2020-2022 Status Research & Development GmbH # Copyright (c) 2020-2023 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * 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). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -13,6 +13,8 @@ import
../beacon_chain/spec/[network, validator], ../beacon_chain/spec/[network, validator],
../beacon_chain/spec/datatypes/[base, altair] ../beacon_chain/spec/datatypes/[base, altair]
from std/sequtils import toSeq
suite "Honest validator": suite "Honest validator":
var forkDigest: ForkDigest var forkDigest: ForkDigest
@ -283,3 +285,20 @@ suite "Honest validator":
SLOTS_PER_HISTORICAL_ROOT .. SLOTS_PER_HISTORICAL_ROOT ..
SLOTS_PER_HISTORICAL_ROOT + FAULT_INSPECTION_WINDOW: SLOTS_PER_HISTORICAL_ROOT + FAULT_INSPECTION_WINDOW:
check: livenessFailsafeInEffect(x, i.Slot) check: livenessFailsafeInEffect(x, i.Slot)
test "Stability subnets":
check:
toSeq(compute_subscribed_subnets(default(UInt256), 0.Epoch)) ==
@[49.SubnetId, 50.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 1.Epoch)) ==
@[49.SubnetId, 50.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 2.Epoch)) ==
@[49.SubnetId, 50.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 2.Epoch)) ==
@[49.SubnetId, 50.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 200.Epoch)) ==
@[49.SubnetId, 50.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 300.Epoch)) ==
@[16.SubnetId, 17.SubnetId]
toSeq(compute_subscribed_subnets(default(UInt256), 400.Epoch)) ==
@[16.SubnetId, 17.SubnetId]