begin 0.5.0 spec update (#179)

* begin 0.5.0 spec update: parent_root -> previous_block_root, BeaconState.justified_epoch -> BeaconState.current_justified_epoch, DOMAIN_PROPOSAL -> DOMAIN_BEACON_BLOCK, temporarily rename BeaconBlockHeader to BeaconBlockHeaderRLP to allow for gradual re-merging without disrupting RLP; mark a few unchanged functions and data types, implement get_temporary_block_header/get_empty_block/should_update_validator_registry/processBlockHeader/cacheState; update a few others

* a dozen or so more trivial mostly comment changes, finding more unchanged parts of 0.5.0

* several more trivial changes; goal is to reduce noise around the upcoming substantial changes (epoch processing, etc)
This commit is contained in:
Dustin Brody 2019-03-16 19:52:37 +00:00 committed by Jacek Sieka
parent 8797a903ea
commit f36c2d86dc
16 changed files with 303 additions and 200 deletions

View File

@ -108,4 +108,4 @@ iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
while (let blck = db.getBlock(root); blck.isSome()):
yield (root, blck.get())
root = blck.get().parent_root
root = blck.get().previous_block_root

View File

@ -290,13 +290,13 @@ proc proposeBlock(node: BeaconNode,
# To create a block, we'll first apply a partial block to the state, skipping
# some validations.
var blockBody = BeaconBlockBody(
randao_reveal: validator.genRandaoReveal(node.state.data, slot),
eth1_data: node.mainchainMonitor.getBeaconBlockRef(),
attestations: node.attestationPool.getAttestationsForBlock(slot))
var newBlock = BeaconBlock(
slot: slot,
parent_root: node.state.blck.root,
randao_reveal: validator.genRandaoReveal(node.state.data, slot),
eth1_data: node.mainchainMonitor.getBeaconBlockRef(),
previous_block_root: node.state.blck.root,
body: blockBody,
signature: ValidatorSig(), # we need the rest of the block first!
)
@ -325,7 +325,7 @@ proc proposeBlock(node: BeaconNode,
info "Block proposed",
slot = humaneSlotNum(slot),
stateRoot = shortLog(newBlock.state_root),
parentRoot = shortLog(newBlock.parent_root),
parentRoot = shortLog(newBlock.previous_block_root),
validator = shortValidatorKey(node, validator.idx),
idx = validator.idx
@ -537,7 +537,7 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
blockRoot = shortLog(blockRoot),
slot = humaneSlotNum(blck.slot),
stateRoot = shortLog(blck.state_root),
parentRoot = shortLog(blck.parent_root),
parentRoot = shortLog(blck.previous_block_root),
signature = shortLog(blck.signature),
proposer_slashings = blck.body.proposer_slashings.len,
attester_slashings = blck.body.attester_slashings.len,
@ -549,7 +549,7 @@ proc onBeaconBlock(node: BeaconNode, blck: BeaconBlock) =
if not node.blockPool.add(node.state, blockRoot, blck):
# TODO the fact that add returns a bool that causes the parent block to be
# pre-emptively fetched is quite ugly - fix.
node.fetchBlocks(@[blck.parent_root])
node.fetchBlocks(@[blck.previous_block_root])
# The block we received contains attestations, and we might not yet know about
# all of them. Let's add them to the attestation pool - in case they block

View File

@ -100,7 +100,7 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
finalizedHead =
headRef.findAncestorBySlot(headState.finalized_epoch.get_epoch_start_slot())
justifiedHead =
headRef.findAncestorBySlot(headState.justified_epoch.get_epoch_start_slot())
headRef.findAncestorBySlot(headState.current_justified_epoch.get_epoch_start_slot())
doAssert justifiedHead.slot >= finalizedHead.slot,
"justified head comes before finalized head - database corrupt?"
@ -162,7 +162,7 @@ proc add*(
return true
let parent = pool.blocks.getOrDefault(blck.parent_root)
let parent = pool.blocks.getOrDefault(blck.previous_block_root)
if parent != nil:
# The block might have been in either of these - we don't want any more
@ -197,7 +197,7 @@ proc add*(
let
justifiedBlock =
blockRef.findAncestorBySlot(
state.data.justified_epoch.get_epoch_start_slot())
state.data.current_justified_epoch.get_epoch_start_slot())
if not justifiedBlock.justified:
info "Justified block",
@ -227,7 +227,7 @@ proc add*(
# think are useful - but, it would also risk filling the database with
# junk that's not part of the block graph
if blck.parent_root in pool.unresolved:
if blck.previous_block_root in pool.unresolved:
return true
# This is an unresolved block - put it on the unresolved list for now...
@ -244,7 +244,7 @@ proc add*(
blck = shortLog(blck),
blockRoot = shortLog(blockRoot)
pool.unresolved[blck.parent_root] = UnresolvedBlock()
pool.unresolved[blck.previous_block_root] = UnresolvedBlock()
pool.pending[blockRoot] = blck
false
@ -303,8 +303,8 @@ proc checkUnresolved*(pool: var BlockPool): seq[Eth2Digest] =
proc skipAndUpdateState(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
afterUpdate: proc (state: BeaconState)): bool =
skipSlots(state, blck.parent_root, blck.slot - 1, afterUpdate)
let ok = updateState(state, blck.parent_root, blck, flags)
skipSlots(state, blck.previous_block_root, blck.slot - 1, afterUpdate)
let ok = updateState(state, blck.previous_block_root, blck, flags)
afterUpdate(state)
@ -337,7 +337,7 @@ proc updateState*(
# Common case: the last thing that was applied to the state was the parent
# of blck
if state.blck.root == ancestors[0].data.parent_root and
if state.blck.root == ancestors[0].data.previous_block_root and
state.data.slot < blck.slot:
let ok = skipAndUpdateState(
state.data, ancestors[0].data, {skipValidation}) do (state: BeaconState):
@ -395,12 +395,12 @@ proc updateState*(
let last = ancestors[i]
skipSlots(
state.data, last.data.parent_root,
state.data, last.data.previous_block_root,
last.data.slot - 1) do(state: BeaconState):
pool.maybePutState(state)
let ok = updateState(
state.data, last.data.parent_root, last.data, {skipValidation})
state.data, last.data.previous_block_root, last.data, {skipValidation})
doAssert ok,
"We only keep validated blocks in the database, should never fail"
@ -443,7 +443,7 @@ proc updateHead*(pool: BlockPool, state: var StateData, blck: BlockRef) =
stateRoot = shortLog(state.root),
headBlockRoot = shortLog(state.blck.root),
stateSlot = humaneSlotNum(state.data.slot),
justifiedEpoch = humaneEpochNum(state.data.justified_epoch),
justifiedEpoch = humaneEpochNum(state.data.current_justified_epoch),
finalizedEpoch = humaneEpochNum(state.data.finalized_epoch)
let

View File

@ -10,8 +10,8 @@ import
../extras, ../ssz,
./crypto, ./datatypes, ./digest, ./helpers, ./validator
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_effective_balance
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): uint64 =
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_effective_balance
func get_effective_balance*(state: BeaconState, index: ValidatorIndex): Gwei =
## Return the effective balance (also known as "balance at stake") for a
## validator with the given ``index``.
min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
@ -61,13 +61,13 @@ func process_deposit(state: var BeaconState, deposit: Deposit) =
state.validator_balances[index] += amount
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_delayed_activation_exit_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_delayed_activation_exit_epoch
func get_delayed_activation_exit_epoch*(epoch: Epoch): Epoch =
## Return the epoch at which an activation or exit triggered in ``epoch``
## takes effect.
epoch + 1 + ACTIVATION_EXIT_DELAY
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#activate_validator
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#activate_validator
func activate_validator(state: var BeaconState,
index: ValidatorIndex,
is_genesis: bool) =
@ -81,7 +81,7 @@ func activate_validator(state: var BeaconState,
else:
get_delayed_activation_exit_epoch(get_current_epoch(state))
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initiate_validator_exit
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#initiate_validator_exit
func initiate_validator_exit*(state: var BeaconState,
index: ValidatorIndex) =
## Initiate exit for the validator with the given ``index``.
@ -107,7 +107,7 @@ func reduce_balance*(balance: var uint64, amount: uint64) =
# Not in spec, but useful to avoid underflow.
balance -= min(amount, balance)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slash_validator
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#slash_validator
func slash_validator*(state: var BeaconState, index: ValidatorIndex) =
## Slash the validator with index ``index``.
## Note that this function mutates ``state``.
@ -155,7 +155,22 @@ func update_shuffling_cache*(state: var BeaconState) =
state.shuffling_cache.shuffling_1 = shuffling_seq
state.shuffling_cache.index = 1 - state.shuffling_cache.index
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_temporary_block_header
func get_temporary_block_header*(blck: BeaconBlock): BeaconBlockHeader =
## Return the block header corresponding to a block with ``state_root`` set
## to ``ZERO_HASH``.
BeaconBlockHeader(
slot: blck.slot.uint64,
previous_block_root: blck.previous_block_root,
state_root: ZERO_HASH,
block_body_root: hash_tree_root_final(blck.body),
signature: blck.signature)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#on-genesis
func get_empty_block*(): BeaconBlock =
# Nim default values fill this in fine, mostly.
result.slot = GENESIS_SLOT
func get_genesis_beacon_state*(
genesis_validator_deposits: openArray[Deposit],
genesis_time: uint64,
@ -204,7 +219,7 @@ func get_genesis_beacon_state*(
# Finality
previous_justified_epoch: GENESIS_EPOCH,
justified_epoch: GENESIS_EPOCH,
current_justified_epoch: GENESIS_EPOCH,
justification_bitfield: 0,
finalized_epoch: GENESIS_EPOCH,
@ -214,6 +229,7 @@ func get_genesis_beacon_state*(
# Recent state
# latest_block_roots, latest_active_index_roots, latest_slashed_balances,
# latest_attestations, and batched_block_roots automatically initialized.
latest_block_header: get_temporary_block_header(get_empty_block()),
)
for i in 0 ..< SHARD_COUNT:
@ -251,14 +267,14 @@ func get_initial_beacon_block*(state: BeaconState): BeaconBlock =
# initialized to default values.
)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_block_root
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_block_root
func get_block_root*(state: BeaconState,
slot: Slot): Eth2Digest =
# Return the block root at a recent ``slot``.
doAssert state.slot <= slot + LATEST_BLOCK_ROOTS_LENGTH
doAssert state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
doAssert slot < state.slot
state.latest_block_roots[slot mod LATEST_BLOCK_ROOTS_LENGTH]
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
func get_attestation_participants*(state: BeaconState,
@ -304,17 +320,26 @@ func process_ejections*(state: var BeaconState) =
## Iterate through the validator registry and eject active validators with
## balance below ``EJECTION_BALANCE``
for index in get_active_validator_indices(
# Spec bug in 0.4.0: is just current_epoch(state)
state.validator_registry, get_current_epoch(state)):
if state.validator_balances[index] < EJECTION_BALANCE:
exit_validator(state, index)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_total_balance
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_total_balance
func get_total_balance*(state: BeaconState, validators: auto): Gwei =
# Return the combined effective balance of an array of validators.
foldl(validators, a + get_effective_balance(state, b), 0'u64)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#validator-registry-and-shuffling-seed-data
func should_update_validator_registry*(state: BeaconState): bool =
# Must have finalized a new block
if state.finalized_epoch <= state.validator_registry_update_epoch:
return false
# Must have processed new crosslinks on all shards of the current epoch
allIt(0 ..< get_current_epoch_committee_count(state).int,
not (state.latest_crosslinks[
((state.current_shuffling_start_shard + it.uint64) mod
SHARD_COUNT).int].epoch <= state.validator_registry_update_epoch))
func update_validator_registry*(state: var BeaconState) =
## Update validator registry.
## Note that this function mutates ``state``.
@ -389,7 +414,7 @@ proc checkAttestation*(
let expected_justified_epoch =
if slot_to_epoch(attestation.data.slot + 1) >= get_current_epoch(state):
state.justified_epoch
state.current_justified_epoch
else:
state.previous_justified_epoch
@ -488,7 +513,7 @@ proc checkAttestation*(
true
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#prepare_validator_for_withdrawal
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#prepare_validator_for_withdrawal
func prepare_validator_for_withdrawal*(state: var BeaconState, index: ValidatorIndex) =
## Set the validator with the given ``index`` as withdrawable
## ``MIN_VALIDATOR_WITHDRAWABILITY_DELAY`` after the current epoch.
@ -511,7 +536,7 @@ proc makeAttestationData*(
epoch_boundary_root =
if epoch_start_slot == state.slot: beacon_block_root
else: get_block_root(state, epoch_start_slot)
justified_slot = get_epoch_start_slot(state.justified_epoch)
justified_slot = get_epoch_start_slot(state.current_justified_epoch)
justified_block_root = get_block_root(state, justified_slot)
AttestationData(
@ -521,6 +546,6 @@ proc makeAttestationData*(
epoch_boundary_root: epoch_boundary_root,
crosslink_data_root: Eth2Digest(), # Stub in phase0
latest_crosslink: state.latest_crosslinks[shard],
justified_epoch: state.justified_epoch,
justified_epoch: state.current_justified_epoch,
justified_block_root: justified_block_root,
)

View File

@ -68,7 +68,7 @@ template hash*(k: ValidatorPubKey|ValidatorPrivKey): Hash =
func pubKey*(pk: ValidatorPrivKey): ValidatorPubKey = pk.getKey()
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/bls_signature.md#bls_aggregate_pubkeys
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/bls_signature.md#bls_aggregate_pubkeys
func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
var empty = true
for key in keys:
@ -78,14 +78,14 @@ func bls_aggregate_pubkeys*(keys: openArray[ValidatorPubKey]): ValidatorPubKey =
else:
result.combine(key)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/bls_signature.md#bls_verify
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/bls_signature.md#bls_verify
func bls_verify*(
pubkey: ValidatorPubKey, msg: openArray[byte], sig: ValidatorSig,
domain: uint64): bool =
# name from spec!
sig.verify(msg, domain, pubkey)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/bls_signature.md#bls_verify_multiple
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/bls_signature.md#bls_verify_multiple
func bls_verify_multiple*(
pubkeys: seq[ValidatorPubKey], message_hashes: seq[array[0..31, byte]],
sig: ValidatorSig, domain: uint64): bool =

View File

@ -82,11 +82,11 @@ const
SHUFFLE_ROUND_COUNT* = 90
# Deposit contract
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#deposit-contract
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#deposit-contract
DEPOSIT_CONTRACT_TREE_DEPTH* = 2^5
# Gwei values
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#gwei-values
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#gwei-values
MIN_DEPOSIT_AMOUNT* = 2'u64^0 * 10'u64^9 ##\
## Minimum amounth of ETH that can be deposited in one call - deposits can
## be used either to top up an existing validator or commit to a new one
@ -106,8 +106,7 @@ const
## processing is done
## Compile with -d:SLOTS_PER_EPOCH=4 for shorter epochs
# Initial values
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#initial-values
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#initial-values
GENESIS_FORK_VERSION* = 0'u64
GENESIS_SLOT* = (2'u64^32).Slot
GENESIS_EPOCH* = (GENESIS_SLOT.uint64 div SLOTS_PER_EPOCH).Epoch ##\
@ -146,18 +145,18 @@ const
EPOCHS_PER_ETH1_VOTING_PERIOD* = 2'u64^4 ##\
## epochs (~1.7 hours)
SLOTS_PER_HISTORICAL_ROOT* = 8192 ##\
## slots (13 hours)
MIN_VALIDATOR_WITHDRAWABILITY_DELAY* = 2'u64^8 ##\
## epochs (~27 hours)
# State list lengths
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#state-list-lengths
LATEST_BLOCK_ROOTS_LENGTH* = 2'u64^13
LATEST_RANDAO_MIXES_LENGTH* = 2'u64^13
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#state-list-lengths
LATEST_RANDAO_MIXES_LENGTH* = 8192
LATEST_ACTIVE_INDEX_ROOTS_LENGTH* = 8192 # 2'u64^13, epochs
LATEST_SLASHED_EXIT_LENGTH* = 8192 # epochs
# Reward and penalty quotients
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#reward-and-penalty-quotients
BASE_REWARD_QUOTIENT* = 2'u64^5 ##\
## The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It
## corresponds to ~2.54% annual interest assuming 10 million participating
@ -167,8 +166,7 @@ const
INACTIVITY_PENALTY_QUOTIENT* = 2'u64^24
MIN_PENALTY_QUOTIENT* = 32 # 2^5
# Max transactions per block
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#max-transactions-per-block
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#max-transactions-per-block
MAX_PROPOSER_SLASHINGS* = 2^4
MAX_ATTESTER_SLASHINGS* = 2^0
MAX_ATTESTATIONS* = 2^7
@ -181,16 +179,16 @@ type
Gwei* = uint64
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposerslashing
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#proposerslashing
ProposerSlashing* = object
proposer_index*: uint64 ##\
## Proposer index
proposal_1*: Proposal ##\
# First proposal
header_1*: BeaconBlockHeader ##\
# First block header
proposal_2*: Proposal ##\
# Second proposal
header_2*: BeaconBlockHeader ##\
# Second block header
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attesterslashing
AttesterSlashing* = object
@ -199,7 +197,7 @@ type
slashable_attestation_2*: SlashableAttestation ## \
## Second slashable attestation
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slashableattestation
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#slashableattestation
SlashableAttestation* = object
validator_indices*: seq[uint64] ##\
## Validator indices
@ -253,7 +251,7 @@ type
justified_block_root*: Eth2Digest ##\
## Hash of the last justified beacon block
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#attestationdataandcustodybit
AttestationDataAndCustodyBit* = object
data*: AttestationData
custody_bit*: bool
@ -269,20 +267,20 @@ type
deposit_data*: DepositData ##\
## Data
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#depositdata
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#depositdata
DepositData* = object
amount*: uint64 ## Amount in Gwei
timestamp*: uint64 # Timestamp from deposit contract
deposit_input*: DepositInput
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#depositinput
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#depositinput
DepositInput* = object
pubkey*: ValidatorPubKey
withdrawal_credentials*: Eth2Digest
proof_of_possession*: ValidatorSig ##\
## A BLS signature of this `DepositInput`
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#voluntaryexit
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#voluntaryexit
VoluntaryExit* = object
# Minimum epoch for processing exit
epoch*: Epoch
@ -314,7 +312,7 @@ type
signature*: ValidatorSig ##\
## Sender signature
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#beaconblock
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblock
BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to
@ -323,26 +321,33 @@ type
## is formed.
slot*: Slot
parent_root*: Eth2Digest ##\
previous_block_root*: Eth2Digest ##\
##\ Root hash of the previous block
state_root*: Eth2Digest ##\
## The state root, _after_ this block has been processed
randao_reveal*: ValidatorSig ##\
## Proposer RANDAO reveal
eth1_data*: Eth1Data
body*: BeaconBlockBody
signature*: ValidatorSig ##\
## Proposer signature
#https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblockheader
BeaconBlockHeader* = object
slot*: uint64
previous_block_root*: Eth2Digest
state_root*: Eth2Digest
block_body_root*: Eth2Digest
signature*: ValidatorSig
BeaconBlockHeaderRLP* = object
## Same as BeaconBlock, except `body` is the `hash_tree_root` of the
## associated BeaconBlockBody.
# TODO: Dry it up with BeaconBlock
# TODO: As a first step, don't change RLP output; only previous user,
# but as with others, randao_reveal and eth1_data move to body.
# This is from before spec had a version.
slot*: uint64
parent_root*: Eth2Digest
state_root*: Eth2Digest
@ -351,8 +356,10 @@ type
signature*: ValidatorSig
body*: Eth2Digest
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#beaconblockbody
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconblockbody
BeaconBlockBody* = object
randao_reveal*: ValidatorSig
eth1_data*: Eth1Data
proposer_slashings*: seq[ProposerSlashing]
attester_slashings*: seq[AttesterSlashing]
attestations*: seq[Attestation]
@ -374,7 +381,7 @@ type
signature*: ValidatorSig ##\
## Signature
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#beaconstate
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#beaconstate
BeaconState* = object
slot*: Slot
genesis_time*: uint64
@ -393,7 +400,7 @@ type
## For light clients to easily track delta
# Randomness and committees
latest_randao_mixes*: array[LATEST_BLOCK_ROOTS_LENGTH.int, Eth2Digest]
latest_randao_mixes*: array[LATEST_RANDAO_MIXES_LENGTH, Eth2Digest]
previous_shuffling_start_shard*: uint64
current_shuffling_start_shard*: uint64
previous_shuffling_epoch*: Epoch
@ -402,20 +409,31 @@ type
current_shuffling_seed*: Eth2Digest
# Finality
previous_epoch_attestations*: seq[PendingAttestation]
current_epoch_attestations*: seq[PendingAttestation]
previous_justified_epoch*: Epoch
justified_epoch*: Epoch
current_justified_epoch*: Epoch
previous_justified_root*: Eth2Digest
current_justified_root*: Eth2Digest
justification_bitfield*: uint64
finalized_epoch*: Epoch
finalized_root*: Eth2Digest
# Recent state
latest_crosslinks*: array[SHARD_COUNT, Crosslink]
latest_block_roots*: array[LATEST_BLOCK_ROOTS_LENGTH.int, Eth2Digest] ##\
latest_block_roots*: array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
## Needed to process attestations, older to newer
latest_active_index_roots*: array[LATEST_ACTIVE_INDEX_ROOTS_LENGTH.int, Eth2Digest]
latest_state_roots*: array[SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
latest_active_index_roots*: array[LATEST_ACTIVE_INDEX_ROOTS_LENGTH, Eth2Digest]
latest_slashed_balances*: array[LATEST_SLASHED_EXIT_LENGTH, uint64] ##\
## Balances penalized in the current withdrawal period
latest_block_header*: BeaconBlockHeader ##\
## `latest_block_header.state_root == ZERO_HASH` temporarily
historical_roots*: seq[Eth2Digest]
# TOOD remove these, gone in 0.5
latest_attestations*: seq[PendingAttestation]
batched_block_roots*: seq[Eth2Digest]
@ -427,7 +445,7 @@ type
# Not in spec. TODO: don't serialize or deserialize this.
shuffling_cache*: ShufflingCache
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#validator
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#validator
Validator* = object
pubkey*: ValidatorPubKey ##\
## BLS public key
@ -450,7 +468,7 @@ type
slashed*: bool ##\
## Was the validator slashed
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#crosslink
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#crosslink
Crosslink* = object
epoch*: Epoch ##\
## Epoch number
@ -458,20 +476,20 @@ type
crosslink_data_root*: Eth2Digest ##\
## Shard data since the previous crosslink
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#pendingattestation
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#pendingattestation
PendingAttestation* = object
aggregation_bitfield*: seq[byte] # Attester participation bitfield
data*: AttestationData # Attestation data
custody_bitfield*: seq[byte] # Custody bitfield
inclusion_slot*: Slot # Inclusion slot
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#fork
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#fork
Fork* = object
previous_version*: uint64 # Previous fork version
current_version*: uint64 # Current fork version
epoch*: Epoch # Fork epoch number
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#eth1data
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#eth1data
Eth1Data* = object
deposit_root*: Eth2Digest ##\
## Data being voted for
@ -479,7 +497,7 @@ type
block_hash*: Eth2Digest ##\
## Block hash
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#eth1datavote
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#eth1datavote
Eth1DataVote* = object
eth1_data*: Eth1Data ##\
## Data being voted for
@ -493,13 +511,13 @@ type
Activation = 0
Exit = 1
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#signature-domains
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#signature-domains
SignatureDomain* {.pure.} = enum
DOMAIN_DEPOSIT = 0
DOMAIN_ATTESTATION = 1
DOMAIN_PROPOSAL = 2
DOMAIN_EXIT = 3
DOMAIN_RANDAO = 4
DOMAIN_BEACON_BLOCK = 0
DOMAIN_RANDAO = 1
DOMAIN_ATTESTATION = 2
DOMAIN_DEPOSIT = 3
DOMAIN_VOLUNTARY_EXIT = 4
DOMAIN_TRANSFER = 5
# TODO: not in spec
@ -578,8 +596,8 @@ func humaneEpochNum*(e: Epoch): uint64 =
e - GENESIS_EPOCH
func shortLog*(v: BeaconBlock): tuple[
slot: uint64, parent_root: string, state_root: string,
randao_reveal: string, #[ eth1_data ]#
slot: uint64, previous_block_root: string, state_root: string,
#[ eth1_data ]#
proposer_slashings_len: int, attester_slashings_len: int,
attestations_len: int,
deposits_len: int,
@ -587,8 +605,8 @@ func shortLog*(v: BeaconBlock): tuple[
transfers_len: int,
signature: string
] = (
humaneSlotNum(v.slot), shortLog(v.parent_root), shortLog(v.state_root),
shortLog(v.randao_reveal), v.body.proposer_slashings.len(),
humaneSlotNum(v.slot), shortLog(v.previous_block_root),
shortLog(v.state_root), v.body.proposer_slashings.len(),
v.body.attester_slashings.len(), v.body.attestations.len(),
v.body.deposits.len(), v.body.voluntary_exits.len(), v.body.transfers.len(),
shortLog(v.signature)

View File

@ -7,7 +7,7 @@
# Serenity hash function / digest
#
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#hash
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#hash
#
# In Phase 0 the beacon chain is deployed with the same hash function as
# Ethereum 1.0, i.e. Keccak-256 (also incorrectly known as SHA3).

View File

@ -14,14 +14,14 @@ import ./datatypes, ./digest, sequtils, math
func bitSet*(bitfield: var openArray[byte], index: int) =
bitfield[index div 8] = bitfield[index div 8] or 1'u8 shl (7 - (index mod 8))
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_bitfield_bit
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_bitfield_bit
func get_bitfield_bit*(bitfield: openarray[byte], i: int): byte =
# Extract the bit in ``bitfield`` at position ``i``.
doAssert 0 <= i div 8, "i: " & $i & " i div 8: " & $(i div 8)
doAssert i div 8 < bitfield.len, "i: " & $i & " i div 8: " & $(i div 8)
(bitfield[i div 8] shr (7 - (i mod 8))) mod 2
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#verify_bitfield
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#verify_bitfield
func verify_bitfield*(bitfield: openarray[byte], committee_size: int): bool =
# Verify ``bitfield`` against the ``committee_size``.
if len(bitfield) != (committee_size + 7) div 8:
@ -34,7 +34,7 @@ func verify_bitfield*(bitfield: openarray[byte], committee_size: int): bool =
true
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#split
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#split
func split*[T](lst: openArray[T], N: Positive): seq[seq[T]] =
## split lst in N pieces, with each piece having `len(lst) div N` or
## `len(lst) div N + 1` pieces
@ -56,9 +56,11 @@ func get_new_recent_block_roots*(old_block_roots: seq[Eth2Digest],
func ceil_div8*(v: int): int = (v + 7) div 8 # TODO use a proper bitarray!
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#integer_squareroot
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#integer_squareroot
func integer_squareroot*(n: SomeInteger): SomeInteger =
## The largest integer ``x`` such that ``x**2`` is less than ``n``.
doAssert n >= 0'u64
var
x = n
y = (x + 1) div 2
@ -81,8 +83,8 @@ func get_domain*(
# Get the domain number that represents the fork meta and signature domain.
(get_fork_version(fork, epoch) shl 32) + domain_type.uint32
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_power_of_two
func is_power_of_2*(v: uint64): bool = (v and (v-1)) == 0
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#is_power_of_two
func is_power_of_2*(v: uint64): bool = (v > 0'u64) and (v and (v-1)) == 0
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#merkle_root
func merkle_root*(values: openArray[Eth2Digest]): Eth2Digest =
@ -119,16 +121,16 @@ func merkle_root*(values: openArray[Eth2Digest]): Eth2Digest =
o[1]
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slot_to_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#slot_to_epoch
func slot_to_epoch*(slot: Slot|uint64): Epoch =
(slot div SLOTS_PER_EPOCH).Epoch
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_epoch_start_slot
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_epoch_start_slot
func get_epoch_start_slot*(epoch: Epoch): Slot =
# Return the starting slot of the given ``epoch``.
(epoch * SLOTS_PER_EPOCH).Slot
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_double_vote
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#is_double_vote
func is_double_vote*(attestation_data_1: AttestationData,
attestation_data_2: AttestationData): bool =
## Check if ``attestation_data_1`` and ``attestation_data_2`` have the same
@ -139,7 +141,7 @@ func is_double_vote*(attestation_data_1: AttestationData,
target_epoch_2 = slot_to_epoch(attestation_data_2.slot)
target_epoch_1 == target_epoch_2
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_surround_vote
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#is_surround_vote
func is_surround_vote*(attestation_data_1: AttestationData,
attestation_data_2: AttestationData): bool =
## Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
@ -152,7 +154,7 @@ func is_surround_vote*(attestation_data_1: AttestationData,
source_epoch_1 < source_epoch_2 and target_epoch_2 < target_epoch_1
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#is_active_validator
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#is_active_validator
func is_active_validator*(validator: Validator, epoch: Epoch): bool =
### Check if ``validator`` is active
validator.activation_epoch <= epoch and epoch < validator.exit_epoch
@ -170,7 +172,7 @@ func get_epoch_committee_count*(active_validator_count: int): uint64 =
active_validator_count div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE,
1, SHARD_COUNT div SLOTS_PER_EPOCH).uint64 * SLOTS_PER_EPOCH
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_current_epoch_committee_count
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_current_epoch_committee_count
func get_current_epoch_committee_count*(state: BeaconState): uint64 =
# Return the number of committees in the current epoch of the given ``state``.
let current_active_validators = get_active_validator_indices(
@ -179,13 +181,13 @@ func get_current_epoch_committee_count*(state: BeaconState): uint64 =
)
get_epoch_committee_count(len(current_active_validators))
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_current_epoch
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_current_epoch
func get_current_epoch*(state: BeaconState): Epoch =
# Return the current epoch of the given ``state``.
doAssert state.slot >= GENESIS_SLOT, $state.slot
slot_to_epoch(state.slot)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_randao_mix
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_randao_mix
func get_randao_mix*(state: BeaconState,
epoch: Epoch): Eth2Digest =
## Returns the randao mix at a recent ``epoch``.
@ -196,7 +198,7 @@ func get_randao_mix*(state: BeaconState,
state.latest_randao_mixes[epoch mod LATEST_RANDAO_MIXES_LENGTH]
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_active_index_root
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_active_index_root
func get_active_index_root(state: BeaconState, epoch: Epoch): Eth2Digest =
# Returns the index root at a recent ``epoch``.
@ -216,7 +218,7 @@ func bytes_to_int*(data: seq[byte]): uint64 =
for i in countdown(7, 0):
result = result * 256 + data[i]
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#int_to_bytes1-int_to_bytes2-
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#int_to_bytes1-int_to_bytes2-
# Have 1, 4, and 32-byte versions. 2+ more and maybe worth metaprogramming.
func int_to_bytes32*(x: uint64): array[32, byte] =
## Little-endian data representation
@ -242,7 +244,7 @@ func int_to_bytes4*(x: uint64): array[4, byte] =
result[2] = ((x shr 16) and 0xff).byte
result[3] = ((x shr 24) and 0xff).byte
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#generate_seed
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#generate_seed
func generate_seed*(state: BeaconState, epoch: Epoch): Eth2Digest =
# Generate a seed for the given ``epoch``.

View File

@ -103,7 +103,7 @@ func get_shuffling*(seed: Eth2Digest,
result = split(shuffled_seq, committees_per_epoch)
doAssert result.len() == committees_per_epoch # what split should do..
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_previous_epoch_committee_count
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_previous_epoch_committee_count
func get_previous_epoch_committee_count(state: BeaconState): uint64 =
## Return the number of committees in the previous epoch of the given
## ``state``.
@ -113,7 +113,7 @@ func get_previous_epoch_committee_count(state: BeaconState): uint64 =
)
get_epoch_committee_count(len(previous_active_validators))
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_next_epoch_committee_count
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_next_epoch_committee_count
func get_next_epoch_committee_count(state: BeaconState): uint64 =
## Return the number of committees in the next epoch of the given ``state``.
let next_active_validators = get_active_validator_indices(
@ -140,8 +140,6 @@ func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot|uint64,
# TODO: the + 1 here works around a bug, remove when upgrading to
# some more recent version:
# https://github.com/ethereum/eth2.0-specs/pull/732
# It's not 100% clear to me regarding 0.4.0; waiting until 0.5.0 to remove
# TODO recheck
epoch = slot_to_epoch(slot + 1)
current_epoch = get_current_epoch(state)
previous_epoch = get_previous_epoch(state)
@ -217,7 +215,7 @@ func get_crosslink_committees_at_slot*(state: BeaconState, slot: Slot|uint64,
(slot_start_shard + i.uint64) mod SHARD_COUNT
)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#get_beacon_proposer_index
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(state: BeaconState, slot: Slot): ValidatorIndex =
## From Casper RPJ mini-spec:
## When slot i begins, validator Vidx is expected
@ -232,6 +230,15 @@ func get_beacon_proposer_index*(state: BeaconState, slot: Slot): ValidatorIndex
# because presently, `state.slot += 1` happens before this function
# is called - see also testutil.getNextBeaconProposerIndex
# TODO is the above still true? the shuffling has changed since it was written
let
epoch = slot_to_epoch(slot)
current_epoch = get_current_epoch(state)
previous_epoch = get_previous_epoch(state)
next_epoch = current_epoch + 1
doAssert previous_epoch <= epoch
doAssert epoch <= next_epoch
let (first_committee, _) = get_crosslink_committees_at_slot(state, slot)[0]
let idx = int(slot mod uint64(first_committee.len))
first_committee[idx]

View File

@ -315,14 +315,15 @@ func hash_tree_root*[T: object|tuple](x: T): array[32, byte] =
h.update hash_tree_root(field.toSSZType)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/simple-serialize.md#signed-roots
func signed_root*[T: object](x: T, field_name: string): array[32, byte] =
func signed_root*[T: object](x: T, ignored: string = "sig"): array[32, byte] =
# TODO write tests for this (check vs hash_tree_root)
var found_field_name = false
## TODO this isn't how 0.5 defines signed_root, but works well enough
withHash:
for name, field in x.fieldPairs:
if name == field_name:
if name == "signature":
found_field_name = true
break
h.update hash_tree_root(field.toSSZType)

View File

@ -57,9 +57,44 @@ func verifyBlockSignature(state: BeaconState, blck: BeaconBlock): bool =
proposer.pubkey,
signed_root(proposal, "signature"),
proposal.signature,
get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))
get_domain(state.fork, get_current_epoch(state), DOMAIN_BEACON_BLOCK))
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#randao
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#block-header
proc processBlockHeader(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
# Verify that the slots match
if not (blck.slot == state.slot):
notice "Block header: slot mismatch",
block_slot = humaneSlotNum(blck.slot),
state_slot = humaneSlotNum(state.slot)
return false
if not (blck.previous_block_root ==
hash_tree_root_final(state.latest_block_header)):
notice "Block header: previous block root mismatch",
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)
let proposer =
state.validator_registry[get_beacon_proposer_index(state, state.slot)]
if skipValidation notin flags and not bls_verify(
proposer.pubkey,
signed_root(blck),
blck.signature,
get_domain(state.fork, get_current_epoch(state), DOMAIN_BEACON_BLOCK)):
notice "Block header: invalid block header",
proposer_pubkey = proposer.pubkey,
signed_root_block = signed_root(blck),
block_signature = blck.signature
return false
true
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#randao
proc processRandao(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
let
@ -70,20 +105,21 @@ proc processRandao(
if not bls_verify(
proposer.pubkey,
hash_tree_root(get_current_epoch(state).uint64),
blck.randao_reveal,
blck.body.randao_reveal,
get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO)):
notice "Randao mismatch", proposer_pubkey = proposer.pubkey,
message = get_current_epoch(state),
signature = blck.randao_reveal,
signature = blck.body.randao_reveal,
slot = state.slot,
blck_slot = blck.slot
return false
# Update state and proposer now that we're alright
# Mix it in
let
mix = get_current_epoch(state) mod LATEST_RANDAO_MIXES_LENGTH
rr = hash_tree_root_final(blck.randao_reveal).data
# TODO hash_tree_root has some overloading for this
rr = eth2hash(blck.body.randao_reveal.getBytes()).data
for i, b in state.latest_randao_mixes[mix].data:
state.latest_randao_mixes[mix].data[i] = b xor rr[i]
@ -94,16 +130,16 @@ proc processRandao(
func processDepositRoot(state: var BeaconState, blck: BeaconBlock) =
# TODO verify that there's at most one match
for x in state.eth1_data_votes.mitems():
if blck.eth1_data == x.eth1_data:
if blck.body.eth1_data == x.eth1_data:
x.vote_count += 1
return
state.eth1_data_votes.add Eth1DataVote(
eth1_data: blck.eth1_data,
eth1_data: blck.body.eth1_data,
vote_count: 1
)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#proposer-slashings-1
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#proposer-slashings
proc processProposerSlashings(
state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool =
if len(blck.body.proposer_slashings) > MAX_PROPOSER_SLASHINGS:
@ -114,19 +150,13 @@ proc processProposerSlashings(
for proposer_slashing in blck.body.proposer_slashings:
let proposer = state.validator_registry[proposer_slashing.proposer_index.int]
if not (proposer_slashing.proposal_1.slot ==
proposer_slashing.proposal_2.slot):
notice "PropSlash: slot mismatch"
if not (slot_to_epoch(proposer_slashing.header_1.slot) ==
slot_to_epoch(proposer_slashing.header_2.slot)):
notice "PropSlash: epoch mismatch"
return false
if not (proposer_slashing.proposal_1.shard ==
proposer_slashing.proposal_2.shard):
notice "PropSlash: shard mismatch"
return false
if not (proposer_slashing.proposal_1.block_root !=
proposer_slashing.proposal_2.block_root):
notice "PropSlash: block root mismatch"
if not (proposer_slashing.header_1 != proposer_slashing.header_2):
notice "PropSlash: headers not different"
return false
if not (proposer.slashed == false):
@ -134,24 +164,16 @@ proc processProposerSlashings(
return false
if skipValidation notin flags:
if not bls_verify(
proposer.pubkey,
signed_root(proposer_slashing.proposal_1, "signature"),
proposer_slashing.proposal_1.signature,
get_domain(
state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot),
DOMAIN_PROPOSAL)):
notice "PropSlash: invalid signature 1"
return false
if not bls_verify(
proposer.pubkey,
signed_root(proposer_slashing.proposal_2, "signature"),
proposer_slashing.proposal_2.signature,
get_domain(
state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot),
DOMAIN_PROPOSAL)):
notice "PropSlash: invalid signature 2"
return false
for i, header in @[proposer_slashing.header_1, proposer_slashing.header_2]:
if not bls_verify(
proposer.pubkey,
signed_root(header),
header.signature,
get_domain(
state.fork, slot_to_epoch(header.slot), DOMAIN_BEACON_BLOCK)):
notice "PropSlash: invalid signature",
signature_index = i
return false
slashValidator(state, proposer_slashing.proposer_index.ValidatorIndex)
@ -303,8 +325,8 @@ proc processExits(
if skipValidation notin flags:
if not bls_verify(
validator.pubkey, signed_root(exit, "signature"), exit.signature,
get_domain(state.fork, exit.epoch, DOMAIN_EXIT)):
validator.pubkey, signed_root(exit), exit.signature,
get_domain(state.fork, exit.epoch, DOMAIN_VOLUNTARY_EXIT)):
notice "Exit: invalid signature"
return false
@ -357,7 +379,7 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
return false
if skipValidation notin flags:
let transfer_message = signed_root(transfer, "signature")
let transfer_message = signed_root(transfer)
if not bls_verify(
pubkey=transfer.pubkey, transfer_message, transfer.signature,
get_domain(
@ -375,20 +397,41 @@ proc processTransfers(state: var BeaconState, blck: BeaconBlock,
true
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#per-slot-processing
func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) =
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#per-slot-processing
func advanceSlot(state: var BeaconState) =
## Time on the beacon chain moves in slots. Every time we make it to a new
## slot, a proposer creates a block to represent the state of the beacon
## chain at that time. In case the proposer is missing, it may happen that
## the no block is produced during the slot.
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#slot
state.slot += 1
# https://github.com/ethereum/eth2.0-specs/blob/v0.5.0/specs/core/0_beacon-chain.md#state-caching
func cacheState(state: var BeaconState) =
let previous_slot_state_root = hash_tree_root_final(state)
# store the previous slot's post state transition root
state.latest_state_roots[state.slot mod SLOTS_PER_HISTORICAL_ROOT] =
previous_slot_state_root
# cache state root in stored latest_block_header if empty
if state.latest_block_header.state_root == ZERO_HASH:
state.latest_block_header.state_root = previous_slot_state_root
# store latest known block for previous slot
state.latest_block_roots[state.slot mod SLOTS_PER_HISTORICAL_ROOT] =
hash_tree_root_final(state.latest_block_header)
func processSlot(state: var BeaconState, previous_block_root: Eth2Digest) =
advanceSlot(state)
# TODO "at every slot > GENESIS_SLOT", after rest of epoch restructuring
if false and state.slot > GENESIS_SLOT:
cacheState(state)
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#block-roots
state.latest_block_roots[(state.slot - 1) mod LATEST_BLOCK_ROOTS_LENGTH] =
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT] =
previous_block_root
if state.slot mod LATEST_BLOCK_ROOTS_LENGTH == 0:
if state.slot mod SLOTS_PER_HISTORICAL_ROOT == 0:
state.batched_block_roots.add(merkle_root(state.latest_block_roots))
proc processBlock(
@ -408,21 +451,26 @@ proc processBlock(
# 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
# `blck.parent_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.
# TODO compare with check in processBlockHeader, might be redundant
let stateParentRoot =
state.latest_block_roots[(state.slot - 1) mod LATEST_BLOCK_ROOTS_LENGTH]
if not (blck.parent_root == stateParentRoot):
state.latest_block_roots[(state.slot - 1) mod SLOTS_PER_HISTORICAL_ROOT]
if not (blck.previous_block_root == stateParentRoot):
notice "Unexpected parent root",
blockParentRoot = blck.parent_root,
blockParentRoot = blck.previous_block_root,
stateParentRoot
return false
# TODO Technically, we could make processBlock take a generic type instead
# of BeaconBlock - we would then have an intermediate `ProposedBlock`
# type that omits some fields - this way, the compiler would guarantee
# 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:
# TODO Technically, we could make processBlock take a generic type instead
# of BeaconBlock - we would then have an intermediate `ProposedBlock`
# type that omits some fields - this way, the compiler would guarantee
# that we don't try to access fields that don't have a value yet
if not verifyBlockSignature(state, blck):
notice "Block signature not valid", slot = humaneSlotNum(state.slot)
return false
@ -683,7 +731,7 @@ func processEpoch(state: var BeaconState) =
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#justification
block:
# First, update the justification bitfield
var new_justified_epoch = state.justified_epoch
var new_justified_epoch = state.current_justified_epoch
state.justification_bitfield = state.justification_bitfield shl 1
if 3'u64 * previous_epoch_boundary_attesting_balance >= 2'u64 * previous_total_balance:
state.justification_bitfield = state.justification_bitfield or 2
@ -697,14 +745,14 @@ func processEpoch(state: var BeaconState) =
state.finalized_epoch = state.previous_justified_epoch
if (state.justification_bitfield shr 1) mod 4 == 0b11 and state.previous_justified_epoch == previous_epoch - 1:
state.finalized_epoch = state.previous_justified_epoch
if (state.justification_bitfield shr 0) mod 8 == 0b111 and state.justified_epoch == previous_epoch - 1:
state.finalized_epoch = state.justified_epoch
if (state.justification_bitfield shr 0) mod 4 == 0b11 and state.justified_epoch == previous_epoch:
state.finalized_epoch = state.justified_epoch
if (state.justification_bitfield shr 0) mod 8 == 0b111 and state.current_justified_epoch == previous_epoch - 1:
state.finalized_epoch = state.current_justified_epoch
if (state.justification_bitfield shr 0) mod 4 == 0b11 and state.current_justified_epoch == previous_epoch:
state.finalized_epoch = state.current_justified_epoch
# Finally, update the following
state.previous_justified_epoch = state.justified_epoch
state.justified_epoch = new_justified_epoch
state.previous_justified_epoch = state.current_justified_epoch
state.current_justified_epoch = new_justified_epoch
# https://github.com/ethereum/eth2.0-specs/blob/0.4.0/specs/core/0_beacon-chain.md#crosslinks
block:

View File

@ -22,30 +22,30 @@ type
node*: BeaconNode
db*: BeaconChainDB
func toHeader(b: BeaconBlock): BeaconBlockHeader =
BeaconBlockHeader(
func toHeader(b: BeaconBlock): BeaconBlockHeaderRLP =
BeaconBlockHeaderRLP(
slot: b.slot.uint64,
parent_root: b.parent_root,
parent_root: b.previous_block_root,
state_root: b.state_root,
randao_reveal: b.randao_reveal,
eth1_data : b.eth1_data,
randao_reveal: b.body.randao_reveal,
eth1_data : b.body.eth1_data,
signature: b.signature,
body: hash_tree_root_final(b.body)
)
proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeader, body: BeaconBlockBody) =
proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeaderRLP, body: BeaconBlockBody) =
doAssert(hash_tree_root_final(body) == h.body)
b.slot = h.slot.Slot
b.parent_root = h.parent_root
b.previous_block_root = h.parent_root
b.state_root = h.state_root
b.randao_reveal = h.randao_reveal
b.eth1_data = h.eth1_data
b.body.randao_reveal = h.randao_reveal
b.body.eth1_data = h.eth1_data
b.signature = h.signature
b.body = body
proc importBlocks(node: BeaconNode,
roots: openarray[(Eth2Digest, Slot)],
headers: openarray[BeaconBlockHeader],
headers: openarray[BeaconBlockHeaderRLP],
bodies: openarray[BeaconBlockBody]) =
var bodyMap = initTable[Eth2Digest, int]()
@ -135,7 +135,7 @@ p2pProtocol BeaconSync(version = 1,
skipSlots: int) {.libp2pProtocol("rpc/beacon_block_headers", "1.0.0").} =
# TODO: validate maxHeaders and implement slipSlots
var s = slot.int
var headers = newSeqOfCap[BeaconBlockHeader](maxHeaders)
var headers = newSeqOfCap[BeaconBlockHeaderRLP](maxHeaders)
let db = peer.networkState.db
let blockPool = peer.networkState.node.blockPool
while headers.len < maxHeaders:
@ -147,7 +147,7 @@ p2pProtocol BeaconSync(version = 1,
proc beaconBlockHeaders(
peer: Peer,
blockHeaders: openarray[BeaconBlockHeader])
blockHeaders: openarray[BeaconBlockHeaderRLP])
requestResponse:
proc getBeaconBlockBodies(

View File

@ -31,7 +31,7 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork,
let proposalRoot = hash_tree_root_final(proposal)
result = bls_sign(v.privKey, signed_root(proposal, "signature"),
get_domain(fork, slot_to_epoch(proposal.slot), DOMAIN_PROPOSAL))
get_domain(fork, slot_to_epoch(proposal.slot), DOMAIN_BEACON_BLOCK))
else:
# TODO:
# send RPC

View File

@ -56,7 +56,7 @@ func hash(x: BlockHash): Hash =
result = cast[array[num_hashes, Hash]](x)[0]
func get_parent(store: Store, blck: BeaconBlock): BeaconBlock =
store.verified_blocks[blck.parent_root]
store.verified_blocks[blck.previous_block_root]
func get_ancestor(store: Store, blck: BeaconBlock, slot: uint64): BeaconBlock =
## Find the ancestor with a specific slot number

View File

@ -57,12 +57,11 @@ suite "Beacon chain DB":
check: x == y
let
# TODO Not GENESIS_SLOT?
a0 = BeaconBlock(slot: 0.Slot)
a0 = BeaconBlock(slot: GENESIS_SLOT + 0)
a0r = hash_tree_root_final(a0)
a1 = BeaconBlock(slot: 1.Slot, parent_root: a0r)
a1 = BeaconBlock(slot: GENESIS_SLOT + 1, previous_block_root: a0r)
a1r = hash_tree_root_final(a1)
a2 = BeaconBlock(slot: 2.Slot, parent_root: a1r)
a2 = BeaconBlock(slot: GENESIS_SLOT + 2, previous_block_root: a1r)
a2r = hash_tree_root_final(a2)
doAssert toSeq(db.getAncestors(a0r)) == []

View File

@ -92,18 +92,21 @@ proc addBlock*(
proposer = state.validator_registry[proposer_index]
privKey = hackPrivKey(proposer)
# TODO ugly hack; API needs rethinking
var new_body = body
new_body.randao_reveal = privKey.genRandaoReveal(state, state.slot + 1)
new_body.eth1_data = Eth1Data()
var
# In order to reuse the state transition function, we first create a dummy
# block that has some fields set, and use that to generate the state as it
# would look with the new block applied.
new_block = BeaconBlock(
slot: state.slot + 1,
parent_root: previous_block_root,
previous_block_root: previous_block_root,
state_root: Eth2Digest(), # we need the new state first
randao_reveal: privKey.genRandaoReveal(state, state.slot + 1),
eth1_data: Eth1Data(), # TODO
signature: ValidatorSig(), # we need the rest of the block first!
body: body
body: new_body
)
let block_ok = updateState(
@ -134,12 +137,12 @@ proc addBlock*(
# We have a signature - put it in the block and we should be done!
new_block.signature =
bls_sign(proposerPrivkey, proposal_hash,
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_PROPOSAL))
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_BEACON_BLOCK))
doAssert bls_verify(
proposer.pubkey,
proposal_hash, new_block.signature,
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_PROPOSAL)),
get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_BEACON_BLOCK)),
"we just signed this message - it should pass verification!"
new_block