diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index 2d52a3cd6..921f84eac 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -30,8 +30,6 @@ const stateStoragePeriod = EPOCH_LENGTH * 10 # Save states once per this number of slots. TODO: Find a good number. -func humaneSlotNum(s: SlotNumber): SlotNumber = - s - GENESIS_SLOT func shortHash(x: auto): string = ($x)[0..7] @@ -51,7 +49,7 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): T = result.config = conf result.attachedValidators = ValidatorPool.init - init result.attestationPool, 0 + init result.attestationPool, GENESIS_SLOT init result.mainchainMonitor, "", Port(0) # TODO: specify geth address and port let trieDB = trieDB newChainDb(string conf.dataDir) @@ -236,7 +234,8 @@ proc proposeBlock(node: BeaconNode, info "Block proposed", slot = humaneSlotNum(slot), stateRoot = shortHash(newBlock.state_root), - validator = shortValidatorKey(node, validator.idx) + validator = shortValidatorKey(node, validator.idx), + idx = validator.idx proc scheduleBlockProposal(node: BeaconNode, slot: uint64, @@ -251,6 +250,7 @@ proc scheduleBlockProposal(node: BeaconNode, info "Scheduling block proposal", validator = shortValidatorKey(node, validator.idx), + idx = validator.idx, slot = humaneSlotNum(slot), fromNow = (at - fastEpochTime()) div 1000 @@ -288,9 +288,11 @@ proc scheduleEpochActions(node: BeaconNode, epoch: uint64) = # see the comments in `get_beacon_proposer_index` var nextState = node.beaconState - for i in 0.uint64 ..< EPOCH_LENGTH: + let start = if epoch == GENESIS_EPOCH: 1.uint64 else: 0.uint64 + + for i in start ..< EPOCH_LENGTH: # Schedule block proposals - let slot = epoch * EPOCH_LENGTH + i + 1 + let slot = epoch * EPOCH_LENGTH + i nextState.slot = slot let proposerIdx = get_beacon_proposer_index(nextState, slot) let validator = node.getAttachedValidator(proposerIdx) diff --git a/beacon_chain/fork_choice.nim b/beacon_chain/fork_choice.nim index 670f953ce..5efc736a6 100644 --- a/beacon_chain/fork_choice.nim +++ b/beacon_chain/fork_choice.nim @@ -15,7 +15,7 @@ type # shard number. When we haven't received an attestation for a particular # shard yet, the Option value will be `none` attestations: Deque[array[SHARD_COUNT, Option[Attestation]]] - startingSlot: int + startingSlot: uint64 # TODO: # The compilicated Deque above is not needed. @@ -37,7 +37,7 @@ type # substantial difficulties in network layer aggregation, then adding bits to # aid in supporting overlaps is one potential solution -proc init*(T: type AttestationPool, startingSlot: int): T = +proc init*(T: type AttestationPool, startingSlot: uint64): T = result.attestations = initDeque[array[SHARD_COUNT, Option[Attestation]]]() result.startingSlot = startingSlot @@ -74,14 +74,14 @@ proc add*(pool: var AttestationPool, beaconState: BeaconState) = # The caller of this function is responsible for ensuring that # the attestations will be given in a strictly slot increasing order: - doAssert attestation.data.slot.int >= pool.startingSlot + doAssert attestation.data.slot >= pool.startingSlot # TODO: # Validate that the attestation is authentic (it's properly signed) # and make sure that the validator is supposed to make an attestation # for the specific shard/slot - let slotIdxInPool = attestation.data.slot.int - pool.startingSlot + let slotIdxInPool = int(attestation.data.slot - pool.startingSlot) if slotIdxInPool >= pool.attestations.len: pool.attestations.setLen(slotIdxInPool + 1) @@ -104,20 +104,20 @@ proc getAttestationsForBlock*(pool: AttestationPool, firstSlot = 0.uint64 lastSlot = newBlockSlot - MIN_ATTESTATION_INCLUSION_DELAY - if pool.startingSlot.uint64 + MIN_ATTESTATION_INCLUSION_DELAY <= lastState.slot: + if pool.startingSlot + MIN_ATTESTATION_INCLUSION_DELAY <= lastState.slot: firstSlot = lastState.slot - MIN_ATTESTATION_INCLUSION_DELAY for slot in firstSlot .. lastSlot: - let slotDequeIdx = slot.int - pool.startingSlot + let slotDequeIdx = int(slot - pool.startingSlot) if slotDequeIdx >= pool.attestations.len: return let shardAndComittees = get_crosslink_committees_at_slot(lastState, slot) for s in shardAndComittees: if pool.attestations[slotDequeIdx][s.shard].isSome: result.add pool.attestations[slotDequeIdx][s.shard].get -proc discardHistoryToSlot*(pool: var AttestationPool, slot: int) = +proc discardHistoryToSlot*(pool: var AttestationPool, slot: uint64) = ## The index is treated inclusively - let slot = slot - MIN_ATTESTATION_INCLUSION_DELAY.int + let slot = slot - MIN_ATTESTATION_INCLUSION_DELAY if slot < pool.startingSlot: return let slotIdx = int(slot - pool.startingSlot) @@ -187,7 +187,7 @@ func getVoteCount(aggregation_bitfield: openarray[byte]): int = for validatorIdx in 0 ..< aggregation_bitfield.len * 8: result += int aggregation_bitfield.get_bitfield_bit(validatorIdx) -func getAttestationVoteCount(pool: AttestationPool, current_slot: int): CountTable[Eth2Digest] = +func getAttestationVoteCount(pool: AttestationPool, current_slot: uint64): CountTable[Eth2Digest] = ## Returns all blocks more recent that the current slot ## that were attested and their vote count # This replaces: @@ -202,7 +202,7 @@ func getAttestationVoteCount(pool: AttestationPool, current_slot: int): CountTab # while the following implementation will count such blockhash multiple times instead. result = initCountTable[Eth2Digest]() - for slot in current_slot - pool.startingSlot ..< pool.attestations.len: + for slot in current_slot - pool.startingSlot ..< pool.attestations.len.uint64: for attestation in pool.attestations[slot]: if attestation.isSome: # Increase the block attestation counts by the number of validators aggregated @@ -218,7 +218,7 @@ proc lmdGhost*( # LMD GHOST (Latest Message Driven - Greediest Heaviest Observed SubTree) # Raw vote count from all attestations - let rawVoteCount = pool.getAttestationVoteCount(state.slot.int) + let rawVoteCount = pool.getAttestationVoteCount(state.slot) # The real vote count for a block also takes into account votes for its children diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index f59d33164..1dc58b453 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -37,7 +37,7 @@ func validate_proof_of_possession(state: BeaconState, proof_of_possession, get_domain( state.fork, - state.slot, + slot_to_epoch(state.slot), DOMAIN_DEPOSIT, ) ) diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index cb8bb045b..68db522eb 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -469,6 +469,12 @@ when true: proc read*(rlp: var Rlp, T: type ValidatorSig): T {.inline.} = discard +func shortValidatorKey*(state: BeaconState, validatorIdx: int): string = + ($state.validator_registry[validatorIdx].pubkey)[0..7] + +func humaneSlotNum*(s: SlotNumber): SlotNumber = + s - GENESIS_SLOT + export writeValue, readValue diff --git a/beacon_chain/state_transition.nim b/beacon_chain/state_transition.nim index ff3b9bc85..5d5663a16 100644 --- a/beacon_chain/state_transition.nim +++ b/beacon_chain/state_transition.nim @@ -39,7 +39,7 @@ func flatten[T](v: openArray[seq[T]]): seq[T] = # TODO not in nim - doh. for x in v: result.add x -func verifyProposerSignature(state: BeaconState, blck: BeaconBlock): bool = +proc verifyProposerSignature(state: BeaconState, blck: BeaconBlock): bool = ## When creating a block, the proposer will sign a version of the block that ## doesn't contain the data (chicken and egg), then add the signature to that ## block. Here, we check that the signature is correct by repeating the same @@ -61,7 +61,7 @@ func verifyProposerSignature(state: BeaconState, blck: BeaconBlock): bool = bls_verify( state.validator_registry[proposer_index].pubkey, proposal_hash.data, blck.signature, - get_domain(state.fork, state.slot, DOMAIN_PROPOSAL)) + get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_PROPOSAL)) proc processRandao( state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags): bool = @@ -147,7 +147,7 @@ proc processProposerSlashings( hash_tree_root_final(proposer_slashing.proposal_data_1).data, proposer_slashing.proposal_signature_1, get_domain( - state.fork, proposer_slashing.proposal_data_1.slot, + state.fork, slot_to_epoch(proposer_slashing.proposal_data_1.slot), DOMAIN_PROPOSAL)): notice "PropSlash: invalid signature 1" return false @@ -156,7 +156,7 @@ proc processProposerSlashings( hash_tree_root_final(proposer_slashing.proposal_data_2).data, proposer_slashing.proposal_signature_2, get_domain( - state.fork, proposer_slashing.proposal_data_2.slot, + state.fork, slot_to_epoch(proposer_slashing.proposal_data_2.slot), DOMAIN_PROPOSAL)): notice "PropSlash: invalid signature 2" return false @@ -401,7 +401,7 @@ proc processBlock( # 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 verifyProposerSignature(state, blck): - notice "Proposer signature not valid" + notice "Proposer signature not valid", slot = humaneSlotNum(state.slot) return false if not processRandao(state, blck, flags): diff --git a/beacon_chain/validator_pool.nim b/beacon_chain/validator_pool.nim index bb8685177..cd351e14f 100644 --- a/beacon_chain/validator_pool.nim +++ b/beacon_chain/validator_pool.nim @@ -51,7 +51,7 @@ proc signBlockProposal*(v: AttachedValidator, fork: Fork, # TODO: Should we use proposalRoot as data, or digest in regards to signature? result = bls_sign(v.privKey, proposalRoot.data, - get_domain(fork, proposal.slot, DOMAIN_PROPOSAL)) + get_domain(fork, slot_to_epoch(proposal.slot), DOMAIN_PROPOSAL)) else: # TODO: # send RPC diff --git a/tests/testutil.nim b/tests/testutil.nim index beafac5ee..e294d93da 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -134,12 +134,12 @@ proc addBlock*( # TODO domain present do something! new_block.signature = bls_sign(proposerPrivkey, proposal_hash, - get_domain(state.fork, state.slot, DOMAIN_PROPOSAL)) + get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_PROPOSAL)) assert bls_verify( proposer.pubkey, proposal_hash, new_block.signature, - get_domain(state.fork, state.slot, DOMAIN_PROPOSAL)), + get_domain(state.fork, slot_to_epoch(state.slot), DOMAIN_PROPOSAL)), "we just signed this message - it should pass verification!" new_block