More 0.5.1 spec updates (#195)
* rm gone-in-0.5.0 Proposal, verifyBlockSignature, and slot check which moved to spec function processBlockHeader * mark get_attestation_participants and get_epoch_committee_count as 0.5.1; finish updating processAttestations to 0.5.1; add kludgy workaround for bug relating to get_winning_roots_etc using crosslink_data_root as index when we have that as ZERO_HASH for all leading to it confusing attesters on different shards; rm BeaconState.latest_attestations, which splits into previous_epoch_attestations and current_epoch_attestations * Fix CI due to removed latest_attestations field
This commit is contained in:
parent
0a027e410a
commit
9f55b4646c
|
@ -428,13 +428,8 @@ proc proposeBlock(node: BeaconNode,
|
||||||
|
|
||||||
newBlock.state_root = node.state.root
|
newBlock.state_root = node.state.root
|
||||||
|
|
||||||
let proposal = Proposal(
|
|
||||||
slot: slot.uint64,
|
|
||||||
block_root: Eth2Digest(data: signed_root(newBlock)),
|
|
||||||
signature: ValidatorSig(),
|
|
||||||
)
|
|
||||||
newBlock.signature =
|
newBlock.signature =
|
||||||
await validator.signBlockProposal(node.state.data.fork, proposal)
|
await validator.signBlockProposal(node.state.data.fork, newBlock)
|
||||||
|
|
||||||
# TODO what are we waiting for here? broadcast should never block, and never
|
# TODO what are we waiting for here? broadcast should never block, and never
|
||||||
# fail...
|
# fail...
|
||||||
|
@ -442,7 +437,7 @@ proc proposeBlock(node: BeaconNode,
|
||||||
|
|
||||||
info "Block proposed",
|
info "Block proposed",
|
||||||
blck = shortLog(newBlock),
|
blck = shortLog(newBlock),
|
||||||
blockRoot = shortLog(proposal.block_root),
|
blockRoot = shortLog(Eth2Digest(data: signed_root(newBlock))),
|
||||||
validator = shortValidatorKey(node, validator.idx),
|
validator = shortValidatorKey(node, validator.idx),
|
||||||
idx = validator.idx
|
idx = validator.idx
|
||||||
|
|
||||||
|
|
|
@ -334,7 +334,7 @@ func get_block_root*(state: BeaconState,
|
||||||
doAssert slot < state.slot
|
doAssert slot < state.slot
|
||||||
state.latest_block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
|
state.latest_block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_attestation_participants
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_attestation_participants
|
||||||
func get_attestation_participants*(state: BeaconState,
|
func get_attestation_participants*(state: BeaconState,
|
||||||
attestation_data: AttestationData,
|
attestation_data: AttestationData,
|
||||||
bitfield: BitField): seq[ValidatorIndex] =
|
bitfield: BitField): seq[ValidatorIndex] =
|
||||||
|
@ -350,10 +350,10 @@ func get_attestation_participants*(state: BeaconState,
|
||||||
# TODO Linear search through shard list? borderline ok, it's a small list
|
# TODO Linear search through shard list? borderline ok, it's a small list
|
||||||
# TODO iterator candidate
|
# TODO iterator candidate
|
||||||
|
|
||||||
## Return the participant indices at for the ``attestation_data`` and
|
# Find the committee in the list with the desired shard
|
||||||
## ``bitfield``.
|
|
||||||
let crosslink_committees = get_crosslink_committees_at_slot(
|
let crosslink_committees = get_crosslink_committees_at_slot(
|
||||||
state, attestation_data.slot)
|
state, attestation_data.slot)
|
||||||
|
|
||||||
doAssert anyIt(
|
doAssert anyIt(
|
||||||
crosslink_committees,
|
crosslink_committees,
|
||||||
it[1] == attestation_data.shard)
|
it[1] == attestation_data.shard)
|
||||||
|
@ -442,8 +442,7 @@ func update_validator_registry*(state: var BeaconState) =
|
||||||
|
|
||||||
state.validator_registry_update_epoch = current_epoch
|
state.validator_registry_update_epoch = current_epoch
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#attestations
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#attestations
|
||||||
# with last half or so still not fully converted from 0.4.0 (tag, remove when done)
|
|
||||||
proc checkAttestation*(
|
proc checkAttestation*(
|
||||||
state: var BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
state: var BeaconState, attestation: Attestation, flags: UpdateFlags): bool =
|
||||||
## Check that an attestation follows the rules of being included in the state
|
## Check that an attestation follows the rules of being included in the state
|
||||||
|
@ -499,34 +498,50 @@ proc checkAttestation*(
|
||||||
state_slot = humaneSlotNum(state.slot))
|
state_slot = humaneSlotNum(state.slot))
|
||||||
return
|
return
|
||||||
|
|
||||||
if not (state.latest_crosslinks[attestation.data.shard] in [
|
# Check that the crosslink data is valid
|
||||||
attestation.data.previous_crosslink,
|
let acceptable_crosslink_data = @[
|
||||||
Crosslink(
|
# Case 1: Latest crosslink matches the one in the state
|
||||||
crosslink_data_root: attestation.data.crosslink_data_root,
|
attestation.data.previous_crosslink,
|
||||||
epoch: slot_to_epoch(attestation.data.slot))]):
|
|
||||||
|
# Case 2: State has already been updated, state's latest crosslink matches
|
||||||
|
# the crosslink the attestation is trying to create
|
||||||
|
Crosslink(
|
||||||
|
crosslink_data_root: attestation.data.crosslink_data_root,
|
||||||
|
epoch: slot_to_epoch(attestation.data.slot)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
if not (state.latest_crosslinks[attestation.data.shard] in
|
||||||
|
acceptable_crosslink_data):
|
||||||
warn("Unexpected crosslink shard",
|
warn("Unexpected crosslink shard",
|
||||||
state_latest_crosslinks_attestation_data_shard =
|
state_latest_crosslinks_attestation_data_shard =
|
||||||
state.latest_crosslinks[attestation.data.shard],
|
state.latest_crosslinks[attestation.data.shard],
|
||||||
attestation_data_previous_crosslink = attestation.data.previous_crosslink,
|
attestation_data_previous_crosslink = attestation.data.previous_crosslink,
|
||||||
epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)),
|
epoch = humaneEpochNum(slot_to_epoch(attestation.data.slot)),
|
||||||
crosslink_data_root = attestation.data.crosslink_data_root)
|
actual_epoch = slot_to_epoch(attestation.data.slot),
|
||||||
|
crosslink_data_root = attestation.data.crosslink_data_root,
|
||||||
|
acceptable_crosslink_data = acceptable_crosslink_data)
|
||||||
return
|
return
|
||||||
|
|
||||||
doAssert allIt(attestation.custody_bitfield.bits, it == 0) #TO BE REMOVED IN PHASE 1
|
# Attestation must be nonempty!
|
||||||
doAssert anyIt(attestation.aggregation_bitfield.bits, it != 0)
|
doAssert anyIt(attestation.aggregation_bitfield.bits, it != 0)
|
||||||
|
|
||||||
|
# Custody must be empty (to be removed in phase 1)
|
||||||
|
doAssert allIt(attestation.custody_bitfield.bits, it == 0)
|
||||||
|
|
||||||
|
# Get the committee for the specific shard that this attestation is for
|
||||||
let crosslink_committee = mapIt(
|
let crosslink_committee = mapIt(
|
||||||
filterIt(get_crosslink_committees_at_slot(state, attestation.data.slot),
|
filterIt(get_crosslink_committees_at_slot(state, attestation.data.slot),
|
||||||
it.shard == attestation.data.shard),
|
it.shard == attestation.data.shard),
|
||||||
it.committee)[0]
|
it.committee)[0]
|
||||||
|
|
||||||
|
# Custody bitfield must be a subset of the attestation bitfield
|
||||||
doAssert allIt(0 ..< len(crosslink_committee),
|
doAssert allIt(0 ..< len(crosslink_committee),
|
||||||
if not get_bitfield_bit(attestation.aggregation_bitfield, it):
|
if not get_bitfield_bit(attestation.aggregation_bitfield, it):
|
||||||
# Should always be true in phase 0, because of above assertion
|
|
||||||
not get_bitfield_bit(attestation.custody_bitfield, it)
|
not get_bitfield_bit(attestation.custody_bitfield, it)
|
||||||
else:
|
else:
|
||||||
true)
|
true)
|
||||||
|
|
||||||
|
# Verify aggregate signature
|
||||||
let
|
let
|
||||||
participants = get_attestation_participants(
|
participants = get_attestation_participants(
|
||||||
state, attestation.data, attestation.aggregation_bitfield)
|
state, attestation.data, attestation.aggregation_bitfield)
|
||||||
|
@ -557,7 +572,7 @@ proc checkAttestation*(
|
||||||
DOMAIN_ATTESTATION),
|
DOMAIN_ATTESTATION),
|
||||||
)
|
)
|
||||||
|
|
||||||
# To be removed in Phase1:
|
# Crosslink data root is zero (to be removed in phase 1)
|
||||||
if attestation.data.crosslink_data_root != ZERO_HASH:
|
if attestation.data.crosslink_data_root != ZERO_HASH:
|
||||||
warn("Invalid crosslink data root")
|
warn("Invalid crosslink data root")
|
||||||
return
|
return
|
||||||
|
@ -573,7 +588,6 @@ func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorI
|
||||||
validator.withdrawable_epoch = get_current_epoch(state) +
|
validator.withdrawable_epoch = get_current_epoch(state) +
|
||||||
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/validator/0_beacon-chain-validator.md#attestations-1
|
|
||||||
proc makeAttestationData*(
|
proc makeAttestationData*(
|
||||||
state: BeaconState, shard: uint64,
|
state: BeaconState, shard: uint64,
|
||||||
beacon_block_root: Eth2Digest): AttestationData =
|
beacon_block_root: Eth2Digest): AttestationData =
|
||||||
|
|
|
@ -46,7 +46,7 @@ type
|
||||||
Epoch* = distinct uint64
|
Epoch* = distinct uint64
|
||||||
|
|
||||||
const
|
const
|
||||||
SPEC_VERSION* = "0.5.0" ## \
|
SPEC_VERSION* = "0.5.1" ## \
|
||||||
## Spec version we're aiming to be compatible with, right now
|
## Spec version we're aiming to be compatible with, right now
|
||||||
## TODO: improve this scheme once we can negotiate versions in protocol
|
## TODO: improve this scheme once we can negotiate versions in protocol
|
||||||
|
|
||||||
|
@ -360,18 +360,7 @@ type
|
||||||
voluntary_exits*: seq[VoluntaryExit]
|
voluntary_exits*: seq[VoluntaryExit]
|
||||||
transfers*: seq[Transfer]
|
transfers*: seq[Transfer]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposal
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#beaconstate
|
||||||
Proposal* = object
|
|
||||||
slot*: uint64 ##\
|
|
||||||
## Slot number
|
|
||||||
|
|
||||||
block_root*: Eth2Digest ##\
|
|
||||||
## Block root
|
|
||||||
|
|
||||||
signature*: ValidatorSig ##\
|
|
||||||
## Signature
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconstate
|
|
||||||
BeaconState* = object
|
BeaconState* = object
|
||||||
slot*: Slot
|
slot*: Slot
|
||||||
genesis_time*: uint64
|
genesis_time*: uint64
|
||||||
|
@ -423,9 +412,6 @@ type
|
||||||
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||||
historical_roots*: seq[Eth2Digest]
|
historical_roots*: seq[Eth2Digest]
|
||||||
|
|
||||||
# TOOD remove, gone in 0.5
|
|
||||||
latest_attestations*: seq[PendingAttestation]
|
|
||||||
|
|
||||||
# Ethereum 1.0 chain data
|
# Ethereum 1.0 chain data
|
||||||
latest_eth1_data*: Eth1Data
|
latest_eth1_data*: Eth1Data
|
||||||
eth1_data_votes*: seq[Eth1DataVote]
|
eth1_data_votes*: seq[Eth1DataVote]
|
||||||
|
|
|
@ -132,7 +132,7 @@ func get_active_validator_indices*(validators: openArray[Validator], epoch: Epoc
|
||||||
if is_active_validator(val, epoch):
|
if is_active_validator(val, epoch):
|
||||||
result.add idx.ValidatorIndex
|
result.add idx.ValidatorIndex
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_epoch_committee_count
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#get_epoch_committee_count
|
||||||
func get_epoch_committee_count*(active_validator_count: int): uint64 =
|
func get_epoch_committee_count*(active_validator_count: int): uint64 =
|
||||||
clamp(
|
clamp(
|
||||||
active_validator_count div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE,
|
active_validator_count div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE,
|
||||||
|
|
|
@ -39,25 +39,6 @@ func flatten[T](v: openArray[seq[T]]): seq[T] =
|
||||||
# TODO not in nim - doh.
|
# TODO not in nim - doh.
|
||||||
for x in v: result.add x
|
for x in v: result.add x
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#block-signature
|
|
||||||
func verifyBlockSignature(state: BeaconState, blck: BeaconBlock): bool =
|
|
||||||
## When creating a block, the proposer will sign a version of the block that
|
|
||||||
## doesn't contain the data (chicken and egg), then add the signature to that
|
|
||||||
## block. Here, we check that the signature is correct by repeating the same
|
|
||||||
## process.
|
|
||||||
let
|
|
||||||
proposer =
|
|
||||||
state.validator_registry[get_beacon_proposer_index(state, state.slot)]
|
|
||||||
proposal = Proposal(
|
|
||||||
slot: blck.slot.uint64,
|
|
||||||
block_root: Eth2Digest(data: signed_root(blck)),
|
|
||||||
signature: blck.signature)
|
|
||||||
bls_verify(
|
|
||||||
proposer.pubkey,
|
|
||||||
signed_root(proposal),
|
|
||||||
proposal.signature,
|
|
||||||
get_domain(state.fork, get_current_epoch(state), DOMAIN_BEACON_BLOCK))
|
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#block-header
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#block-header
|
||||||
proc processBlockHeader(
|
proc processBlockHeader(
|
||||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||||
|
@ -70,13 +51,16 @@ proc processBlockHeader(
|
||||||
|
|
||||||
## https://github.com/ethereum/eth2.0-specs/pull/816/files remove when
|
## https://github.com/ethereum/eth2.0-specs/pull/816/files remove when
|
||||||
## switched to 0.5.1
|
## switched to 0.5.1
|
||||||
if not (blck.previous_block_root.data ==
|
when false:
|
||||||
signed_root(state.latest_block_header)):
|
## TODO Re-enable when it works; currently, some code in processBlock
|
||||||
notice "Block header: previous block root mismatch",
|
## also checks this invariant in a different way. tag as 0.4.0.
|
||||||
previous_block_root = blck.previous_block_root,
|
if not (blck.previous_block_root.data ==
|
||||||
latest_block_header = state.latest_block_header,
|
signed_root(state.latest_block_header)):
|
||||||
latest_block_header_root = hash_tree_root_final(state.latest_block_header)
|
notice "Block header: previous block root mismatch",
|
||||||
return false
|
previous_block_root = blck.previous_block_root,
|
||||||
|
latest_block_header = state.latest_block_header,
|
||||||
|
latest_block_header_root = hash_tree_root_final(state.latest_block_header)
|
||||||
|
return false
|
||||||
|
|
||||||
state.latest_block_header = get_temporary_block_header(blck)
|
state.latest_block_header = get_temporary_block_header(blck)
|
||||||
|
|
||||||
|
@ -277,7 +261,7 @@ proc processAttesterSlashings(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#attestations
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#attestations
|
||||||
proc processAttestations(
|
proc processAttestations(
|
||||||
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
|
||||||
## Each block includes a number of attestations that the proposer chose. Each
|
## Each block includes a number of attestations that the proposer chose. Each
|
||||||
|
@ -294,18 +278,23 @@ proc processAttestations(
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# All checks passed - update state
|
# All checks passed - update state
|
||||||
state.latest_attestations.add blck.body.attestations.mapIt(
|
# Apply the attestations
|
||||||
PendingAttestation(
|
for attestation in blck.body.attestations:
|
||||||
data: it.data,
|
let pending_attestation = PendingAttestation(
|
||||||
aggregation_bitfield: it.aggregation_bitfield,
|
data: attestation.data,
|
||||||
custody_bitfield: it.custody_bitfield,
|
aggregation_bitfield: attestation.aggregation_bitfield,
|
||||||
inclusion_slot: state.slot,
|
custody_bitfield: attestation.custody_bitfield,
|
||||||
|
inclusion_slot: state.slot
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
if slot_to_epoch(attestation.data.slot) == get_current_epoch(state):
|
||||||
|
state.current_epoch_attestations.add(pending_attestation)
|
||||||
|
else:
|
||||||
|
state.previous_epoch_attestations.add(pending_attestation)
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.3.0/specs/core/0_beacon-chain.md#deposits-1
|
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#deposits-1
|
||||||
func processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
func processDeposits(state: var BeaconState, blck: BeaconBlock): bool =
|
||||||
true
|
true
|
||||||
|
|
||||||
|
@ -484,18 +473,11 @@ proc processBlock(
|
||||||
# TODO when there's a failure, we should reset the state!
|
# TODO when there's a failure, we should reset the state!
|
||||||
# TODO probably better to do all verification first, then apply state changes
|
# TODO probably better to do all verification first, then apply state changes
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slot-1
|
|
||||||
if not (blck.slot == state.slot):
|
|
||||||
notice "Unexpected block slot number",
|
|
||||||
blockSlot = humaneSlotNum(blck.slot),
|
|
||||||
stateSlot = humaneSlotNum(state.slot)
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Spec does not have this check explicitly, but requires that this condition
|
# Spec does not have this check explicitly, but requires that this condition
|
||||||
# holds - so we give verify it as well - this would happen naturally if
|
# holds - so we give verify it as well - this would happen naturally if
|
||||||
# `blck.previous_block_root` was used in `processSlot` - but that doesn't cut it for
|
# `blck.previous_block_root` was used in `processSlot` - but that doesn't cut it for
|
||||||
# blockless slot processing.
|
# blockless slot processing.
|
||||||
# TODO compare with check in processBlockHeader, might be redundant
|
# TODO compare with processBlockHeader check, might be redundant and to be removed
|
||||||
let stateParentRoot =
|
let stateParentRoot =
|
||||||
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT]
|
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT]
|
||||||
if not (blck.previous_block_root == stateParentRoot):
|
if not (blck.previous_block_root == stateParentRoot):
|
||||||
|
@ -504,18 +486,9 @@ proc processBlock(
|
||||||
stateParentRoot
|
stateParentRoot
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# TODO Technically, we could make processBlock take a generic type instead
|
if not processBlockHeader(state, blck, flags):
|
||||||
# of BeaconBlock - we would then have an intermediate `ProposedBlock`
|
notice "Block header not valid", slot = humaneSlotNum(state.slot)
|
||||||
# type that omits some fields - this way, the compiler would guarantee
|
return false
|
||||||
# that we don't try to access fields that don't have a value yet
|
|
||||||
#if not processBlockHeader(state, blck, flags):
|
|
||||||
# notice "Block header not valid", slot = humaneSlotNum(state.slot)
|
|
||||||
# return false
|
|
||||||
# TODO this starts requiring refactoring blockpool, etc
|
|
||||||
if skipValidation notin flags:
|
|
||||||
if not verifyBlockSignature(state, blck):
|
|
||||||
notice "Block signature not valid", slot = humaneSlotNum(state.slot)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if not processRandao(state, blck, flags):
|
if not processRandao(state, blck, flags):
|
||||||
return false
|
return false
|
||||||
|
@ -542,7 +515,7 @@ proc processBlock(
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#helper-functions-1
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#helper-functions-1
|
||||||
func get_current_total_balance(state: BeaconState): Gwei =
|
func get_current_total_balance(state: BeaconState): Gwei =
|
||||||
return get_total_balance(
|
return get_total_balance(
|
||||||
state,
|
state,
|
||||||
|
@ -615,7 +588,9 @@ func get_winning_root_and_participants(state: BeaconState, shard: Shard):
|
||||||
return (ZERO_HASH, @[])
|
return (ZERO_HASH, @[])
|
||||||
|
|
||||||
func get_attestations_for(root: Eth2Digest): seq[PendingAttestation] =
|
func get_attestations_for(root: Eth2Digest): seq[PendingAttestation] =
|
||||||
filterIt(valid_attestations, it.data.crosslink_data_root == root)
|
filterIt(
|
||||||
|
valid_attestations,
|
||||||
|
it.data.crosslink_data_root == root)
|
||||||
|
|
||||||
## Winning crosslink root is the root with the most votes for it, ties broken
|
## Winning crosslink root is the root with the most votes for it, ties broken
|
||||||
## in favor of lexicographically higher hash
|
## in favor of lexicographically higher hash
|
||||||
|
@ -641,7 +616,7 @@ func inclusion_slots(state: BeaconState): auto =
|
||||||
result = initTable[ValidatorIndex, Slot]()
|
result = initTable[ValidatorIndex, Slot]()
|
||||||
|
|
||||||
let previous_epoch_attestations =
|
let previous_epoch_attestations =
|
||||||
state.latest_attestations.filterIt(
|
state.previous_epoch_attestations.filterIt(
|
||||||
get_previous_epoch(state) == slot_to_epoch(it.data.slot))
|
get_previous_epoch(state) == slot_to_epoch(it.data.slot))
|
||||||
|
|
||||||
## TODO switch previous_epoch_attestations to state.foo,
|
## TODO switch previous_epoch_attestations to state.foo,
|
||||||
|
@ -659,7 +634,7 @@ func inclusion_distances(state: BeaconState): auto =
|
||||||
result = initTable[ValidatorIndex, Slot]()
|
result = initTable[ValidatorIndex, Slot]()
|
||||||
|
|
||||||
let previous_epoch_attestations =
|
let previous_epoch_attestations =
|
||||||
state.latest_attestations.filterIt(
|
state.previous_epoch_attestations.filterIt(
|
||||||
get_previous_epoch(state) == slot_to_epoch(it.data.slot))
|
get_previous_epoch(state) == slot_to_epoch(it.data.slot))
|
||||||
|
|
||||||
## TODO switch previous_epoch_attestations to state.foo,
|
## TODO switch previous_epoch_attestations to state.foo,
|
||||||
|
@ -741,13 +716,20 @@ func update_justification_and_finalization(state: var BeaconState) =
|
||||||
state.finalized_root =
|
state.finalized_root =
|
||||||
get_block_root(state, get_epoch_start_slot(new_finalized_epoch))
|
get_block_root(state, get_epoch_start_slot(new_finalized_epoch))
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#crosslinks
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.1/specs/core/0_beacon-chain.md#crosslinks
|
||||||
func process_crosslinks(state: var BeaconState) =
|
func process_crosslinks(state: var BeaconState) =
|
||||||
let
|
let
|
||||||
current_epoch = get_current_epoch(state)
|
current_epoch = get_current_epoch(state)
|
||||||
previous_epoch = current_epoch - 1
|
previous_epoch = current_epoch - 1
|
||||||
next_epoch = current_epoch + 1
|
next_epoch = current_epoch + 1
|
||||||
for slot in get_epoch_start_slot(previous_epoch).uint64 ..<
|
## TODO is it actually correct to be setting state.latest_crosslinks[shard]
|
||||||
|
## to something pre-GENESIS_EPOCH, ever? I guess the intent is if there are
|
||||||
|
## a quorum of participants for get_epoch_start_slot(previous_epoch), when
|
||||||
|
## state.slot == GENESIS_SLOT, then there will be participants for a quorum
|
||||||
|
## in the current-epoch (i.e. genesis epoch) version of that shard?
|
||||||
|
#for slot in get_epoch_start_slot(previous_epoch).uint64 ..<
|
||||||
|
for slot in max(
|
||||||
|
GENESIS_SLOT.uint64, get_epoch_start_slot(previous_epoch).uint64) ..<
|
||||||
get_epoch_start_slot(next_epoch).uint64:
|
get_epoch_start_slot(next_epoch).uint64:
|
||||||
for cas in get_crosslink_committees_at_slot(state, slot):
|
for cas in get_crosslink_committees_at_slot(state, slot):
|
||||||
let
|
let
|
||||||
|
@ -756,7 +738,11 @@ func process_crosslinks(state: var BeaconState) =
|
||||||
get_winning_root_and_participants(state, shard)
|
get_winning_root_and_participants(state, shard)
|
||||||
participating_balance = get_total_balance(state, participants)
|
participating_balance = get_total_balance(state, participants)
|
||||||
total_balance = get_total_balance(state, crosslink_committee)
|
total_balance = get_total_balance(state, crosslink_committee)
|
||||||
|
|
||||||
if 3'u64 * participating_balance >= 2'u64 * total_balance:
|
if 3'u64 * participating_balance >= 2'u64 * total_balance:
|
||||||
|
# Check not from spec; seems kludgy
|
||||||
|
doAssert slot >= GENESIS_SLOT
|
||||||
|
|
||||||
state.latest_crosslinks[shard] = Crosslink(
|
state.latest_crosslinks[shard] = Crosslink(
|
||||||
epoch: slot_to_epoch(slot),
|
epoch: slot_to_epoch(slot),
|
||||||
crosslink_data_root: winning_root
|
crosslink_data_root: winning_root
|
||||||
|
@ -1117,14 +1103,20 @@ proc advanceState*(
|
||||||
## We now define the state transition function. At a high level the state
|
## We now define the state transition function. At a high level the state
|
||||||
## transition is made up of four parts:
|
## transition is made up of four parts:
|
||||||
|
|
||||||
# 1. State caching, which happens at the start of every slot.
|
## 1. State caching, which happens at the start of every slot.
|
||||||
|
## The state caching, caches the state root of the previous slot
|
||||||
cacheState(state)
|
cacheState(state)
|
||||||
|
|
||||||
## (2) The per-epoch transitions, which happens at the start of the first
|
## 2. The per-epoch transitions, which happens at the start of the first
|
||||||
## slot of every epoch.
|
## slot of every epoch.
|
||||||
|
## The per-epoch transitions focus on the validator registry, including
|
||||||
|
## adjusting balances and activating and exiting validators, as well as
|
||||||
|
## processing crosslinks and managing block justification/finalization.
|
||||||
processEpoch(state)
|
processEpoch(state)
|
||||||
|
|
||||||
# (3) The per-slot transitions, which happens at every slot.
|
## 3. The per-slot transitions, which happens at every slot.
|
||||||
|
## The per-slot transitions focus on the slot counter and block roots
|
||||||
|
## records updates.
|
||||||
processSlot(state, previous_block_root)
|
processSlot(state, previous_block_root)
|
||||||
|
|
||||||
proc updateState*(
|
proc updateState*(
|
||||||
|
|
|
@ -25,13 +25,11 @@ proc getValidator*(pool: ValidatorPool,
|
||||||
pool.validators.getOrDefault(validatorKey)
|
pool.validators.getOrDefault(validatorKey)
|
||||||
|
|
||||||
proc signBlockProposal*(v: AttachedValidator, fork: Fork,
|
proc signBlockProposal*(v: AttachedValidator, fork: Fork,
|
||||||
proposal: Proposal): Future[ValidatorSig] {.async.} =
|
blck: BeaconBlock): Future[ValidatorSig] {.async.} =
|
||||||
if v.kind == inProcess:
|
if v.kind == inProcess:
|
||||||
await sleepAsync(1)
|
await sleepAsync(1)
|
||||||
let proposalRoot = hash_tree_root_final(proposal)
|
result = bls_sign(v.privKey, signed_root(blck),
|
||||||
|
get_domain(fork, slot_to_epoch(blck.slot), DOMAIN_BEACON_BLOCK))
|
||||||
result = bls_sign(v.privKey, signed_root(proposal),
|
|
||||||
get_domain(fork, slot_to_epoch(proposal.slot), DOMAIN_BEACON_BLOCK))
|
|
||||||
else:
|
else:
|
||||||
# TODO:
|
# TODO:
|
||||||
# send RPC
|
# send RPC
|
||||||
|
|
|
@ -10,16 +10,20 @@ proc stateSize(deposits: int, maxContent = false) =
|
||||||
deposits, {skipValidation}), 0, Eth1Data(), {skipValidation})
|
deposits, {skipValidation}), 0, Eth1Data(), {skipValidation})
|
||||||
|
|
||||||
if maxContent:
|
if maxContent:
|
||||||
# TODO verify this is correct, but generally we collect up to two epochs
|
# TODO: state.latest_attestations was removed
|
||||||
# of attestations, and each block has a cap on the number of
|
# in https://github.com/status-im/nim-beacon-chain/pull/195
|
||||||
# attestations it may hold, so we'll just add so many of them
|
raise newException(ValueError, "Not supported at the moment")
|
||||||
state.latest_attestations.setLen(MAX_ATTESTATIONS * SLOTS_PER_EPOCH * 2)
|
|
||||||
let
|
# # TODO verify this is correct, but generally we collect up to two epochs
|
||||||
crosslink_committees = get_crosslink_committees_at_slot(state, 0.Slot)
|
# # of attestations, and each block has a cap on the number of
|
||||||
validatorsPerCommittee =
|
# # attestations it may hold, so we'll just add so many of them
|
||||||
len(crosslink_committees[0].committee) # close enough..
|
# state.latest_attestations.setLen(MAX_ATTESTATIONS * SLOTS_PER_EPOCH * 2)
|
||||||
for a in state.latest_attestations.mitems():
|
# let
|
||||||
a.aggregation_bitfield = BitField.init(validatorsPerCommittee)
|
# crosslink_committees = get_crosslink_committees_at_slot(state, 0.Slot)
|
||||||
|
# validatorsPerCommittee =
|
||||||
|
# len(crosslink_committees[0].committee) # close enough..
|
||||||
|
# for a in state.latest_attestations.mitems():
|
||||||
|
# a.aggregation_bitfield = BitField.init(validatorsPerCommittee)
|
||||||
echo "Validators: ", deposits, ", total: ", SSZ.encode(state).len
|
echo "Validators: ", deposits, ", total: ", SSZ.encode(state).len
|
||||||
|
|
||||||
dispatch(stateSize)
|
dispatch(stateSize)
|
||||||
|
|
|
@ -101,7 +101,7 @@ suite "Block processing":
|
||||||
discard updateState(state, previous_block_root, new_block, {})
|
discard updateState(state, previous_block_root, new_block, {})
|
||||||
|
|
||||||
check:
|
check:
|
||||||
state.latest_attestations.len == 1
|
state.current_epoch_attestations.len == 1
|
||||||
|
|
||||||
while state.slot < 191:
|
while state.slot < 191:
|
||||||
advanceState(state, previous_block_root)
|
advanceState(state, previous_block_root)
|
||||||
|
|
|
@ -118,31 +118,21 @@ proc addBlock*(
|
||||||
# can set the state root in order to be able to create a valid signature
|
# can set the state root in order to be able to create a valid signature
|
||||||
new_block.state_root = Eth2Digest(data: hash_tree_root(state))
|
new_block.state_root = Eth2Digest(data: hash_tree_root(state))
|
||||||
|
|
||||||
let
|
let proposerPrivkey = hackPrivKey(proposer)
|
||||||
proposerPrivkey = hackPrivKey(proposer)
|
|
||||||
|
|
||||||
# Once we've collected all the state data, we sign the block data along with
|
|
||||||
# some book-keeping values
|
|
||||||
signed_data = Proposal(
|
|
||||||
slot: new_block.slot.uint64,
|
|
||||||
block_root: Eth2Digest(data: signed_root(new_block)),
|
|
||||||
signature: ValidatorSig(),
|
|
||||||
)
|
|
||||||
proposal_hash = signed_root(signed_data)
|
|
||||||
|
|
||||||
doAssert proposerPrivkey.pubKey() == proposer.pubkey,
|
doAssert proposerPrivkey.pubKey() == proposer.pubkey,
|
||||||
"signature key should be derived from private key! - wrong privkey?"
|
"signature key should be derived from private key! - wrong privkey?"
|
||||||
|
|
||||||
if skipValidation notin flags:
|
if skipValidation notin flags:
|
||||||
|
let block_root = signed_root(new_block)
|
||||||
# We have a signature - put it in the block and we should be done!
|
# We have a signature - put it in the block and we should be done!
|
||||||
new_block.signature =
|
new_block.signature =
|
||||||
bls_sign(proposerPrivkey, proposal_hash,
|
bls_sign(proposerPrivkey, block_root,
|
||||||
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_BEACON_BLOCK))
|
get_domain(state.fork, slot_to_epoch(new_block.slot), DOMAIN_BEACON_BLOCK))
|
||||||
|
|
||||||
doAssert bls_verify(
|
doAssert bls_verify(
|
||||||
proposer.pubkey,
|
proposer.pubkey,
|
||||||
proposal_hash, new_block.signature,
|
block_root, new_block.signature,
|
||||||
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_BEACON_BLOCK)),
|
get_domain(state.fork, slot_to_epoch(new_block.slot), DOMAIN_BEACON_BLOCK)),
|
||||||
"we just signed this message - it should pass verification!"
|
"we just signed this message - it should pass verification!"
|
||||||
|
|
||||||
new_block
|
new_block
|
||||||
|
|
Loading…
Reference in New Issue