diff --git a/beacon_chain/beacon_chain_db.nim b/beacon_chain/beacon_chain_db.nim index 946bae97f..4c929f4ae 100644 --- a/beacon_chain/beacon_chain_db.nim +++ b/beacon_chain/beacon_chain_db.nim @@ -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 diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index 5ca9e7ada..3bed51190 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -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 diff --git a/beacon_chain/block_pool.nim b/beacon_chain/block_pool.nim index 7d14c335f..bd4a0da2c 100644 --- a/beacon_chain/block_pool.nim +++ b/beacon_chain/block_pool.nim @@ -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 diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index b1bb0f26e..25241e4dc 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -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, ) diff --git a/beacon_chain/spec/crypto.nim b/beacon_chain/spec/crypto.nim index 7dfbf59b1..b98a43329 100644 --- a/beacon_chain/spec/crypto.nim +++ b/beacon_chain/spec/crypto.nim @@ -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 = diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 3cca0a247..6d1721029 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -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) diff --git a/beacon_chain/spec/digest.nim b/beacon_chain/spec/digest.nim index 4ec1b0fbe..48260341b 100644 --- a/beacon_chain/spec/digest.nim +++ b/beacon_chain/spec/digest.nim @@ -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). diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 3cfaca548..a02d2deef 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -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``. diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index 7ba3f200e..040ff77f5 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -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] diff --git a/beacon_chain/ssz.nim b/beacon_chain/ssz.nim index d3ac75ce2..9b9e085ce 100644 --- a/beacon_chain/ssz.nim +++ b/beacon_chain/ssz.nim @@ -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) diff --git a/beacon_chain/state_transition.nim b/beacon_chain/state_transition.nim index a750d7a19..876acc396 100644 --- a/beacon_chain/state_transition.nim +++ b/beacon_chain/state_transition.nim @@ -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: diff --git a/beacon_chain/sync_protocol.nim b/beacon_chain/sync_protocol.nim index ec3ce3bd3..bc8143f11 100644 --- a/beacon_chain/sync_protocol.nim +++ b/beacon_chain/sync_protocol.nim @@ -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( diff --git a/beacon_chain/validator_pool.nim b/beacon_chain/validator_pool.nim index 4de4133a8..46d493202 100644 --- a/beacon_chain/validator_pool.nim +++ b/beacon_chain/validator_pool.nim @@ -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 diff --git a/research/fork_choice_rule/lmd_ghost.nim b/research/fork_choice_rule/lmd_ghost.nim index ec392f66d..3ba303bec 100644 --- a/research/fork_choice_rule/lmd_ghost.nim +++ b/research/fork_choice_rule/lmd_ghost.nim @@ -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 diff --git a/tests/test_beacon_chain_db.nim b/tests/test_beacon_chain_db.nim index 609de1105..bf975a950 100644 --- a/tests/test_beacon_chain_db.nim +++ b/tests/test_beacon_chain_db.nim @@ -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)) == [] diff --git a/tests/testutil.nim b/tests/testutil.nim index 8d21bb354..abfdec495 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -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