parent
d4680df8d2
commit
8be1699014
|
@ -739,7 +739,6 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Testing ForkData OK
|
||||
+ Testing HistoricalBatch OK
|
||||
+ Testing IndexedAttestation OK
|
||||
+ Testing LightClientSnapshot OK
|
||||
+ Testing LightClientUpdate OK
|
||||
+ Testing PendingAttestation OK
|
||||
+ Testing ProposerSlashing OK
|
||||
|
@ -757,12 +756,12 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Testing Validator OK
|
||||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 36/36 Fail: 0/36 Skip: 0/36
|
||||
OK: 35/35 Fail: 0/35 Skip: 0/35
|
||||
## Ethereum Foundation - Altair - Unittests - Sync protocol [Preset: mainnet]
|
||||
```diff
|
||||
+ process_light_client_update_finality_updated OK
|
||||
+ process_light_client_update_not_updated OK
|
||||
+ process_light_client_update_timeout OK
|
||||
+ test_process_light_client_update_not_timeout OK
|
||||
```
|
||||
OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||
## Ethereum Foundation - ForkChoice [Preset: mainnet]
|
||||
|
@ -902,7 +901,6 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Testing ForkData OK
|
||||
+ Testing HistoricalBatch OK
|
||||
+ Testing IndexedAttestation OK
|
||||
+ Testing LightClientSnapshot OK
|
||||
+ Testing LightClientUpdate OK
|
||||
+ Testing PendingAttestation OK
|
||||
+ Testing PowBlock OK
|
||||
|
@ -921,7 +919,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Testing Validator OK
|
||||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 39/39 Fail: 0/39 Skip: 0/39
|
||||
OK: 38/38 Fail: 0/38 Skip: 0/38
|
||||
## Ethereum Foundation - Phase 0 - Epoch Processing - Effective balance updates [Preset: mainnet]
|
||||
```diff
|
||||
+ Effective balance updates - effective_balance_hysteresis [Preset: mainnet] OK
|
||||
|
@ -1167,4 +1165,4 @@ OK: 44/44 Fail: 0/44 Skip: 0/44
|
|||
OK: 27/27 Fail: 0/27 Skip: 0/27
|
||||
|
||||
---TOTAL---
|
||||
OK: 991/993 Fail: 0/993 Skip: 2/993
|
||||
OK: 989/991 Fail: 0/991 Skip: 2/991
|
||||
|
|
|
@ -775,7 +775,6 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
|
|||
+ Testing ForkData OK
|
||||
+ Testing HistoricalBatch OK
|
||||
+ Testing IndexedAttestation OK
|
||||
+ Testing LightClientSnapshot OK
|
||||
+ Testing LightClientUpdate OK
|
||||
+ Testing PendingAttestation OK
|
||||
+ Testing ProposerSlashing OK
|
||||
|
@ -793,12 +792,12 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
|
|||
+ Testing Validator OK
|
||||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 36/36 Fail: 0/36 Skip: 0/36
|
||||
OK: 35/35 Fail: 0/35 Skip: 0/35
|
||||
## Ethereum Foundation - Altair - Unittests - Sync protocol [Preset: minimal]
|
||||
```diff
|
||||
+ process_light_client_update_finality_updated OK
|
||||
+ process_light_client_update_not_updated OK
|
||||
+ process_light_client_update_timeout OK
|
||||
+ test_process_light_client_update_not_timeout OK
|
||||
```
|
||||
OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||
## Ethereum Foundation - ForkChoice [Preset: minimal]
|
||||
|
@ -963,7 +962,6 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
|
|||
+ Testing ForkData OK
|
||||
+ Testing HistoricalBatch OK
|
||||
+ Testing IndexedAttestation OK
|
||||
+ Testing LightClientSnapshot OK
|
||||
+ Testing LightClientUpdate OK
|
||||
+ Testing PendingAttestation OK
|
||||
+ Testing PowBlock OK
|
||||
|
@ -982,7 +980,7 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
|
|||
+ Testing Validator OK
|
||||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 39/39 Fail: 0/39 Skip: 0/39
|
||||
OK: 38/38 Fail: 0/38 Skip: 0/38
|
||||
## Ethereum Foundation - Phase 0 - Epoch Processing - Effective balance updates [Preset: minimal]
|
||||
```diff
|
||||
+ Effective balance updates - effective_balance_hysteresis [Preset: minimal] OK
|
||||
|
@ -1239,4 +1237,4 @@ OK: 48/48 Fail: 0/48 Skip: 0/48
|
|||
OK: 30/30 Fail: 0/30 Skip: 0/30
|
||||
|
||||
---TOTAL---
|
||||
OK: 1037/1057 Fail: 0/1057 Skip: 20/1057
|
||||
OK: 1035/1055 Fail: 0/1055 Skip: 20/1055
|
||||
|
|
|
@ -65,6 +65,10 @@ const
|
|||
INACTIVITY_SCORE_BIAS* = 4
|
||||
INACTIVITY_SCORE_RECOVERY_RATE* = 16
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#misc
|
||||
# MIN_SYNC_COMMITTEE_PARTICIPANTS defined in presets
|
||||
UPDATE_TIMEOUT* = SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
|
||||
SYNC_SUBCOMMITTEE_SIZE* = SYNC_COMMITTEE_SIZE div SYNC_COMMITTEE_SUBNET_COUNT
|
||||
|
||||
# "Note: The sum of the weights equal WEIGHT_DENOMINATOR."
|
||||
|
@ -146,41 +150,45 @@ type
|
|||
|
||||
### Modified/overloaded
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/sync-protocol.md#lightclientsnapshot
|
||||
LightClientSnapshot* = object
|
||||
header*: BeaconBlockHeader ##\
|
||||
## Beacon block header
|
||||
|
||||
current_sync_committee*: SyncCommittee ##\
|
||||
## Sync committees corresponding to the header
|
||||
|
||||
next_sync_committee*: SyncCommittee
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/sync-protocol.md#lightclientupdate
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#lightclientupdate
|
||||
LightClientUpdate* = object
|
||||
header*: BeaconBlockHeader ##\
|
||||
## Update beacon block header
|
||||
attested_header*: BeaconBlockHeader ##\
|
||||
## The beacon block header that is attested to by the sync committee
|
||||
|
||||
# Next sync committee corresponding to the header
|
||||
# Next sync committee corresponding to the active header
|
||||
next_sync_committee*: SyncCommittee
|
||||
next_sync_committee_branch*: array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest]
|
||||
next_sync_committee_branch*:
|
||||
array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest]
|
||||
|
||||
# Finality proof for the update header
|
||||
finality_header*: BeaconBlockHeader
|
||||
# The finalized beacon block header attested to by Merkle branch
|
||||
finalized_header*: BeaconBlockHeader
|
||||
finality_branch*: array[log2trunc(FINALIZED_ROOT_INDEX), Eth2Digest]
|
||||
|
||||
# Sync committee aggregate signature
|
||||
sync_committee_bits*: BitArray[SYNC_COMMITTEE_SIZE]
|
||||
sync_committee_signature*: ValidatorSig
|
||||
sync_committee_aggregate*: SyncAggregate
|
||||
|
||||
fork_version*: Version ##\
|
||||
## Fork version for the aggregate signature
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/sync-protocol.md#lightclientstore
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#lightclientstore
|
||||
LightClientStore* = object
|
||||
snapshot*: LightClientSnapshot
|
||||
valid_updates*: HashSet[LightClientUpdate]
|
||||
## TODO: This will benefit from being an ordered set
|
||||
finalized_header*: BeaconBlockHeader ##\
|
||||
## Beacon block header that is finalized
|
||||
|
||||
# Sync committees corresponding to the header
|
||||
current_sync_committee*: SyncCommittee
|
||||
next_sync_committee*: SyncCommittee
|
||||
|
||||
best_valid_update*: Option[LightClientUpdate] ##\
|
||||
## Best available header to switch finalized head to if we see nothing else
|
||||
|
||||
optimistic_header*: BeaconBlockHeader ##\
|
||||
## Most recent available reasonably-safe header
|
||||
|
||||
# Max number of active participants in a sync committee (used to calculate
|
||||
# safety threshold)
|
||||
previous_max_active_participants*: uint64
|
||||
current_max_active_participants*: uint64
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/beacon-chain.md#beaconstate
|
||||
BeaconState* = object
|
||||
|
|
|
@ -57,7 +57,7 @@ export
|
|||
# Eventually, we could also differentiate between user/tainted data and
|
||||
# internal state that's gone through sanity checks already.
|
||||
|
||||
const SPEC_VERSION* = "1.1.6"
|
||||
const SPEC_VERSION* = "1.1.7"
|
||||
## Spec version we're aiming to be compatible with, right now
|
||||
|
||||
const
|
||||
|
|
|
@ -4,112 +4,147 @@ import
|
|||
datatypes/altair,
|
||||
helpers
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/altair/sync-protocol.md#validate_light_client_update
|
||||
proc validate_light_client_update*(snapshot: LightClientSnapshot,
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#get_active_header
|
||||
func get_active_header(update: LightClientUpdate): BeaconBlockHeader =
|
||||
# The "active header" is the header that the update is trying to convince
|
||||
# us to accept. If a finalized header is present, it's the finalized
|
||||
# header, otherwise it's the attested header
|
||||
if update.finalized_header != BeaconBlockHeader():
|
||||
update.finalized_header
|
||||
else:
|
||||
update.attested_header
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#validate_light_client_update
|
||||
proc validate_light_client_update*(store: LightClientStore,
|
||||
update: LightClientUpdate,
|
||||
current_slot: Slot,
|
||||
genesis_validators_root: Eth2Digest): bool =
|
||||
# Verify update slot is larger than snapshot slot
|
||||
if update.header.slot <= snapshot.header.slot:
|
||||
# Verify update slot is larger than slot of current best finalized header
|
||||
let active_header = get_active_header(update)
|
||||
if not (current_slot >= active_header.slot and
|
||||
active_header.slot > store.finalized_header.slot):
|
||||
return false
|
||||
|
||||
# Verify update does not skip a sync committee period
|
||||
let
|
||||
snapshot_period = sync_committee_period(snapshot.header.slot)
|
||||
update_period = sync_committee_period(update.header.slot)
|
||||
if update_period notin [snapshot_period, snapshot_period + 1]:
|
||||
finalized_period =
|
||||
compute_epoch_at_slot(store.finalized_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
update_period =
|
||||
compute_epoch_at_slot(active_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
|
||||
if update_period notin [finalized_period, finalized_period + 1]:
|
||||
return false
|
||||
|
||||
# Verify update header root is the finalized root of the finality header, if specified
|
||||
# TODO: Use a view type instead of `unsafeAddr`
|
||||
let signed_header = if update.finality_header.isZeroMemory:
|
||||
# Verify that the `finalized_header`, if present, actually is the finalized
|
||||
# header saved in the state of the `attested header`
|
||||
if update.finalized_header.isZeroMemory:
|
||||
if not update.finality_branch.isZeroMemory:
|
||||
return false
|
||||
unsafeAddr update.header
|
||||
else:
|
||||
if not is_valid_merkle_branch(hash_tree_root(update.header),
|
||||
if not is_valid_merkle_branch(hash_tree_root(update.finalized_header),
|
||||
update.finality_branch,
|
||||
log2trunc(FINALIZED_ROOT_INDEX),
|
||||
get_subtree_index(FINALIZED_ROOT_INDEX),
|
||||
update.finality_header.state_root):
|
||||
update.attested_header.state_root):
|
||||
return false
|
||||
unsafeAddr update.finality_header
|
||||
|
||||
# Verify update next sync committee if the update period incremented
|
||||
# TODO: Use a view type instead of `unsafeAddr`
|
||||
let sync_committee = if update_period == snapshot_period:
|
||||
let sync_committee = if update_period == finalized_period:
|
||||
if not update.next_sync_committee_branch.isZeroMemory:
|
||||
return false
|
||||
unsafeAddr snapshot.current_sync_committee
|
||||
unsafeAddr store.current_sync_committee
|
||||
else:
|
||||
if not is_valid_merkle_branch(hash_tree_root(update.next_sync_committee),
|
||||
update.next_sync_committee_branch,
|
||||
log2trunc(NEXT_SYNC_COMMITTEE_INDEX),
|
||||
get_subtree_index(NEXT_SYNC_COMMITTEE_INDEX),
|
||||
update.header.state_root):
|
||||
active_header.state_root):
|
||||
return false
|
||||
unsafeAddr snapshot.next_sync_committee
|
||||
unsafeAddr store.next_sync_committee
|
||||
|
||||
template sync_aggregate(): auto = update.sync_committee_aggregate
|
||||
let sync_committee_participants_count = countOnes(sync_aggregate.sync_committee_bits)
|
||||
|
||||
let sync_committee_participants_count = countOnes(update.sync_committee_bits)
|
||||
# Verify sync committee has sufficient participants
|
||||
if sync_committee_participants_count < MIN_SYNC_COMMITTEE_PARTICIPANTS:
|
||||
return false
|
||||
|
||||
# Verify sync committee aggregate signature
|
||||
# participant_pubkeys = [pubkey for (bit, pubkey) in zip(update.sync_committee_bits, sync_committee.pubkeys) if bit]
|
||||
# participant_pubkeys = [pubkey for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys) if bit]
|
||||
var participant_pubkeys = newSeqOfCap[ValidatorPubKey](sync_committee_participants_count)
|
||||
for idx, bit in update.sync_committee_bits:
|
||||
for idx, bit in sync_aggregate.sync_committee_bits:
|
||||
if bit:
|
||||
participant_pubkeys.add(sync_committee.pubkeys[idx])
|
||||
|
||||
let domain = compute_domain(DOMAIN_SYNC_COMMITTEE, update.fork_version, genesis_validators_root)
|
||||
let signing_root = compute_signing_root(signed_header[], domain)
|
||||
let domain = compute_domain(
|
||||
DOMAIN_SYNC_COMMITTEE, update.fork_version, genesis_validators_root)
|
||||
let signing_root = compute_signing_root(update.attested_header, domain)
|
||||
|
||||
blsFastAggregateVerify(participant_pubkeys, signing_root.data, update.sync_committee_signature)
|
||||
blsFastAggregateVerify(
|
||||
participant_pubkeys, signing_root.data, sync_aggregate.sync_committee_signature)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/sync-protocol.md#apply_light_client_update
|
||||
proc apply_light_client_update(snapshot: var LightClientSnapshot, update: LightClientUpdate) =
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#apply_light_client_update
|
||||
func apply_light_client_update(
|
||||
store: var LightClientStore, update: LightClientUpdate) =
|
||||
let
|
||||
snapshot_period = sync_committee_period(snapshot.header.slot)
|
||||
update_period = sync_committee_period(update.header.slot)
|
||||
if update_period == snapshot_period + 1:
|
||||
snapshot.current_sync_committee = snapshot.next_sync_committee
|
||||
snapshot.next_sync_committee = update.next_sync_committee
|
||||
snapshot.header = update.header
|
||||
active_header = get_active_header(update)
|
||||
finalized_period =
|
||||
compute_epoch_at_slot(store.finalized_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
update_period =
|
||||
compute_epoch_at_slot(active_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
if update_period == finalized_period + 1:
|
||||
store.current_sync_committee = store.next_sync_committee
|
||||
store.next_sync_committee = update.next_sync_committee
|
||||
store.finalized_header = active_header
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/altair/sync-protocol.md#process_light_client_update
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#get_safety_threshold
|
||||
func get_safety_threshold(store: LightClientStore): uint64 =
|
||||
max(
|
||||
store.previous_max_active_participants,
|
||||
store.current_max_active_participants
|
||||
) div 2
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/specs/altair/sync-protocol.md#process_light_client_update
|
||||
proc process_light_client_update*(store: var LightClientStore,
|
||||
update: LightClientUpdate,
|
||||
current_slot: Slot,
|
||||
genesis_validators_root: Eth2Digest): bool =
|
||||
if not validate_light_client_update(store.snapshot, update, genesis_validators_root):
|
||||
if not validate_light_client_update(
|
||||
store, update, current_slot, genesis_validators_root):
|
||||
return false
|
||||
store.valid_updates.incl(update)
|
||||
|
||||
var update_timeout = SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
let sync_committee_participants_count = countOnes(update.sync_committee_bits)
|
||||
if sync_committee_participants_count * 3 >= update.sync_committee_bits.len * 2 and
|
||||
not update.finality_header.isZeroMemory:
|
||||
# Apply update if (1) 2/3 quorum is reached and (2) we have a finality proof.
|
||||
# Note that (2) means that the current light client design needs finality.
|
||||
# It may be changed to re-organizable light client design. See the on-going issue consensus-specs#2182.
|
||||
apply_light_client_update(store.snapshot, update)
|
||||
store.valid_updates.clear()
|
||||
elif current_slot > store.snapshot.header.slot + update_timeout:
|
||||
var best_update_participants = 0
|
||||
# TODO:
|
||||
# Use a view type to avoid the copying when a new best update
|
||||
# is discovered.
|
||||
# Alterantively, we could have a `set.max` operation returning
|
||||
# the best item as a `lent` value. We would need an `OrderedSet`
|
||||
# type with support for a custom comparison operation.
|
||||
var best_update: LightClientUpdate
|
||||
for update in store.valid_updates:
|
||||
let update_participants = countOnes(update.sync_committee_bits)
|
||||
if update_participants > best_update_participants:
|
||||
best_update = update
|
||||
best_update_participants = update_participants
|
||||
let
|
||||
sync_committee_bits = update.sync_committee_aggregate.sync_committee_bits
|
||||
sum_sync_committee_bits = countOnes(sync_committee_bits)
|
||||
|
||||
# Update the best update in case we have to force-update to it if the
|
||||
# timeout elapses
|
||||
if store.best_valid_update.isNone or
|
||||
sum_sync_committee_bits > countOnes(
|
||||
store.best_valid_update.get.sync_committee_aggregate.sync_committee_bits):
|
||||
store.best_valid_update = some(update)
|
||||
|
||||
# Track the maximum number of active participants in the committee signatures
|
||||
store.current_max_active_participants = max(
|
||||
store.current_max_active_participants,
|
||||
sum_sync_committee_bits.uint64,
|
||||
)
|
||||
|
||||
# Update the optimistic header
|
||||
if sum_sync_committee_bits.uint64 > get_safety_threshold(store) and
|
||||
update.attested_header.slot > store.optimistic_header.slot:
|
||||
store.optimistic_header = update.attested_header
|
||||
|
||||
# Update finalized header
|
||||
if sum_sync_committee_bits * 3 >= len(sync_committee_bits) * 2 and
|
||||
update.finalized_header != default(BeaconBlockHeader):
|
||||
# Normal update through 2/3 threshold
|
||||
apply_light_client_update(store, update)
|
||||
store.best_valid_update = none(LightClientUpdate)
|
||||
|
||||
# Forced best update when the update timeout has elapsed
|
||||
apply_light_client_update(store.snapshot, best_update)
|
||||
store.valid_updates.clear()
|
||||
true
|
||||
|
|
|
@ -114,7 +114,6 @@ suite "Ethereum Foundation - Altair - SSZ consensus objects " & preset():
|
|||
of "ForkData": checkSSZ(ForkData, path, hash)
|
||||
of "HistoricalBatch": checkSSZ(HistoricalBatch, path, hash)
|
||||
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
|
||||
of "LightClientSnapshot": checkSSZ(LightClientSnapshot, path, hash)
|
||||
of "LightClientUpdate": checkSSZ(LightClientUpdate, path, hash)
|
||||
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
|
||||
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)
|
||||
|
|
|
@ -72,6 +72,18 @@ let full_sync_committee_bits = block:
|
|||
res.bytes.fill(byte.high)
|
||||
res
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L24-L33
|
||||
func initialize_light_client_store(state: auto): LightClientStore =
|
||||
LightClientStore(
|
||||
finalized_header: BeaconBlockHeader(),
|
||||
current_sync_committee: state.current_sync_committee,
|
||||
next_sync_committee: state.next_sync_committee,
|
||||
best_valid_update: none(LightClientUpdate),
|
||||
optimistic_header: BeaconBlockHeader(),
|
||||
previous_max_active_participants: 0,
|
||||
current_max_active_participants: 0,
|
||||
)
|
||||
|
||||
suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
||||
let
|
||||
cfg = block:
|
||||
|
@ -80,15 +92,11 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
res
|
||||
genesisState = newClone(initGenesisState(cfg = cfg))
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L22-L78
|
||||
test "process_light_client_update_not_updated":
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L36-L90
|
||||
test "test_process_light_client_update_not_timeout":
|
||||
var forked = assignClone(genesisState[])
|
||||
template state: untyped {.inject.} = forked[].altairData.data
|
||||
|
||||
let pre_snapshot = LightClientSnapshot(
|
||||
current_sync_committee: state.current_sync_committee,
|
||||
next_sync_committee: state.next_sync_committee)
|
||||
var store = LightClientStore(snapshot: pre_snapshot)
|
||||
var store = initialize_light_client_store(state)
|
||||
|
||||
# Block at slot 1 doesn't increase sync committee period,
|
||||
# so it won't update snapshot
|
||||
|
@ -108,52 +116,55 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
sync_committee_bits = full_sync_committee_bits
|
||||
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
||||
forked[], committee)
|
||||
sync_committee_aggregate = SyncAggregate(
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature)
|
||||
|
||||
var next_sync_committee_branch:
|
||||
array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest]
|
||||
|
||||
# Ensure that finality checkpoint is genesis
|
||||
check: state.finalized_checkpoint.epoch == 0
|
||||
# Finality is unchanged
|
||||
let finality_header = BeaconBlockHeader()
|
||||
let
|
||||
finality_header = BeaconBlockHeader()
|
||||
pre_store_finalized_header = store.finalized_header
|
||||
var finality_branch: array[log2trunc(FINALIZED_ROOT_INDEX), Eth2Digest]
|
||||
|
||||
let update = LightClientUpdate(
|
||||
header: block_header,
|
||||
attested_header: block_header,
|
||||
next_sync_committee: state.next_sync_committee,
|
||||
next_sync_committee_branch: next_sync_committee_branch,
|
||||
finality_header: finality_header,
|
||||
finalized_header: finality_header,
|
||||
finality_branch: finality_branch,
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature,
|
||||
sync_committee_aggregate: sync_committee_aggregate,
|
||||
fork_version: state.fork.current_version)
|
||||
|
||||
check:
|
||||
process_light_client_update(
|
||||
store, update, state.slot, state.genesis_validators_root)
|
||||
|
||||
len(store.valid_updates) == 1
|
||||
store.valid_updates.pop() == update
|
||||
store.snapshot == pre_snapshot
|
||||
store.current_max_active_participants > 0
|
||||
store.optimistic_header == update.attested_header
|
||||
store.finalized_header == pre_store_finalized_header
|
||||
store.best_valid_update.get == update
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L81-L144
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L93-L154
|
||||
test "process_light_client_update_timeout":
|
||||
var forked = assignClone(genesisState[])
|
||||
template state: untyped {.inject.} = forked[].altairData.data
|
||||
|
||||
let pre_snapshot = LightClientSnapshot(
|
||||
current_sync_committee: state.current_sync_committee,
|
||||
next_sync_committee: state.next_sync_committee)
|
||||
var store = LightClientStore(snapshot: pre_snapshot)
|
||||
var store = initialize_light_client_store(state)
|
||||
|
||||
# Forward to next sync committee period
|
||||
var
|
||||
cache = StateCache()
|
||||
info = ForkedEpochInfo()
|
||||
doAssert process_slots(
|
||||
cfg, forked[], Slot(SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD),
|
||||
cache, info, flags = {})
|
||||
cfg, forked[], Slot(UPDATE_TIMEOUT), cache, info, flags = {})
|
||||
let
|
||||
snapshot_period = sync_committee_period(pre_snapshot.header.slot)
|
||||
snapshot_period =
|
||||
compute_epoch_at_slot(store.optimistic_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
update_period = sync_committee_period(state.slot)
|
||||
check: snapshot_period + 1 == update_period
|
||||
|
||||
|
@ -173,23 +184,27 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
sync_committee_bits = full_sync_committee_bits
|
||||
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
||||
forked[], committee, block_root = block_header.hash_tree_root())
|
||||
sync_committee_aggregate = SyncAggregate(
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature)
|
||||
|
||||
# Sync committee is updated
|
||||
var next_sync_committee_branch {.noinit.}:
|
||||
array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest]
|
||||
build_proof(state, NEXT_SYNC_COMMITTEE_INDEX, next_sync_committee_branch)
|
||||
# Finality is unchanged
|
||||
let finality_header = BeaconBlockHeader()
|
||||
let
|
||||
finality_header = BeaconBlockHeader()
|
||||
pre_store_finalized_header = store.finalized_header
|
||||
var finality_branch: array[log2trunc(FINALIZED_ROOT_INDEX), Eth2Digest]
|
||||
|
||||
let update = LightClientUpdate(
|
||||
header: block_header,
|
||||
attested_header: block_header,
|
||||
next_sync_committee: state.next_sync_committee,
|
||||
next_sync_committee_branch: next_sync_committee_branch,
|
||||
finality_header: finality_header,
|
||||
finalized_header: finality_header,
|
||||
finality_branch: finality_branch,
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature,
|
||||
sync_committee_aggregate: sync_committee_aggregate,
|
||||
fork_version: state.fork.current_version)
|
||||
|
||||
check:
|
||||
|
@ -197,18 +212,16 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
store, update, state.slot, state.genesis_validators_root)
|
||||
|
||||
# snapshot has been updated
|
||||
len(store.valid_updates) == 0
|
||||
store.snapshot.header == update.header
|
||||
store.current_max_active_participants > 0
|
||||
store.optimistic_header == update.attested_header
|
||||
store.best_valid_update.get == update
|
||||
store.finalized_header == pre_store_finalized_header
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L150-L218
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.7/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L157-L224
|
||||
test "process_light_client_update_finality_updated":
|
||||
var forked = assignClone(genesisState[])
|
||||
template state: untyped {.inject.} = forked[].altairData.data
|
||||
|
||||
let pre_snapshot = LightClientSnapshot(
|
||||
current_sync_committee: state.current_sync_committee,
|
||||
next_sync_committee: state.next_sync_committee)
|
||||
var store = LightClientStore(snapshot: pre_snapshot)
|
||||
var store = initialize_light_client_store(state)
|
||||
|
||||
# Change finality
|
||||
var
|
||||
|
@ -225,8 +238,11 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
check: state.finalized_checkpoint.epoch == 3
|
||||
# Ensure that it's same period
|
||||
let
|
||||
snapshot_period = sync_committee_period(pre_snapshot.header.slot)
|
||||
update_period = sync_committee_period(state.slot)
|
||||
snapshot_period =
|
||||
compute_epoch_at_slot(store.optimistic_header.slot) div
|
||||
EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
update_period =
|
||||
compute_epoch_at_slot(state.slot) div EPOCHS_PER_SYNC_COMMITTEE_PERIOD
|
||||
check: snapshot_period == update_period
|
||||
|
||||
# Updated sync_committee and finality
|
||||
|
@ -266,15 +282,17 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
sync_committee_bits = full_sync_committee_bits
|
||||
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
||||
forked[], committee, block_root = block_header.hash_tree_root())
|
||||
sync_committee_aggregate = SyncAggregate(
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature)
|
||||
|
||||
update = LightClientUpdate(
|
||||
header: finalized_block_header,
|
||||
attested_header: block_header,
|
||||
next_sync_committee: state.next_sync_committee,
|
||||
next_sync_committee_branch: next_sync_committee_branch,
|
||||
finality_header: block_header,
|
||||
finalized_header: finalized_block_header,
|
||||
finality_branch: finality_branch,
|
||||
sync_committee_bits: sync_committee_bits,
|
||||
sync_committee_signature: sync_committee_signature,
|
||||
sync_committee_aggregate: sync_committee_aggregate,
|
||||
fork_version: state.fork.current_version)
|
||||
|
||||
check:
|
||||
|
@ -282,5 +300,7 @@ suite "Ethereum Foundation - Altair - Unittests - Sync protocol" & preset():
|
|||
store, update, state.slot, state.genesis_validators_root)
|
||||
|
||||
# snapshot has been updated
|
||||
len(store.valid_updates) == 0
|
||||
store.snapshot.header == update.header
|
||||
store.current_max_active_participants > 0
|
||||
store.optimistic_header == update.attested_header
|
||||
store.finalized_header == update.finalized_header
|
||||
store.best_valid_update.isNone
|
||||
|
|
|
@ -50,7 +50,7 @@ type
|
|||
const
|
||||
FixturesDir* =
|
||||
currentSourcePath.rsplit(DirSep, 1)[0] / ".." / ".." / "vendor" / "nim-eth2-scenarios"
|
||||
SszTestsDir* = FixturesDir / "tests-v1.1.6"
|
||||
SszTestsDir* = FixturesDir / "tests-v1.1.7"
|
||||
MaxObjectSize* = 3_000_000
|
||||
|
||||
proc parseTest*(path: string, Format: typedesc[Json], T: typedesc): T =
|
||||
|
|
|
@ -117,7 +117,6 @@ suite "Ethereum Foundation - Merge - SSZ consensus objects " & preset():
|
|||
of "ForkData": checkSSZ(ForkData, path, hash)
|
||||
of "HistoricalBatch": checkSSZ(HistoricalBatch, path, hash)
|
||||
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
|
||||
of "LightClientSnapshot": checkSSZ(LightClientSnapshot, path, hash)
|
||||
of "LightClientUpdate": checkSSZ(LightClientUpdate, path, hash)
|
||||
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
|
||||
of "PowBlock": checkSSZ(PowBlock, path, hash)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ee640a4506e73068a3eaa17db254973764e09b4f
|
||||
Subproject commit 976a490e40a57eb76df457605132ab55642dad0e
|
Loading…
Reference in New Issue