diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index 81067d933..c5b840484 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -15,7 +15,7 @@ type attachedValidators: ValidatorPool attestationPool: AttestationPool mainchainMonitor: MainchainMonitor - lastScheduledCycle: int + lastScheduledEpoch: uint64 headBlock: BeaconBlock headBlockRoot: Eth2Digest @@ -77,7 +77,7 @@ proc connectToNetwork(node: BeaconNode) {.async.} = proc sync*(node: BeaconNode): Future[bool] {.async.} = let persistedState = node.db.lastFinalizedState() if persistedState.isNil or - persistedState[].slotDistanceFromNow() > WEAK_SUBJECTVITY_PERIOD: + persistedState[].slotDistanceFromNow() > WEAK_SUBJECTVITY_PERIOD.int64: if node.config.stateSnapshot.isSome: node.beaconState = node.config.stateSnapshot.get else: @@ -86,7 +86,7 @@ proc sync*(node: BeaconNode): Future[bool] {.async.} = node.beaconState = persistedState[] var targetSlot = toSlot timeSinceGenesis(node.beaconState) - while node.beaconState.finalized_slot.int < targetSlot: + while node.beaconState.finalized_slot < targetSlot: var (peer, changeLog) = await node.network.getValidatorChangeLog( node.beaconState.validator_registry_delta_chain_tip) @@ -218,11 +218,11 @@ proc proposeBlock(node: BeaconNode, validator = validator.idx proc scheduleBlockProposal(node: BeaconNode, - slot: int, + slot: uint64, validator: AttachedValidator) = # TODO: # This function exists only to hide a bug with Nim's closures. - # If you inline it in `scheduleCycleActions`, you'll see the + # If you inline it in `scheduleEpochActions`, you'll see the # internal `doAssert` starting to fail. doAssert validator != nil @@ -232,13 +232,13 @@ proc scheduleBlockProposal(node: BeaconNode, proc scheduleAttestation(node: BeaconNode, validator: AttachedValidator, - slot: int, + slot: uint64, shard: uint64, committeeLen: int, indexInCommittee: int) = # TODO: # This function exists only to hide a bug with Nim's closures. - # If you inline it in `scheduleCycleActions`, you'll see the + # If you inline it in `scheduleEpochActions`, you'll see the # internal `doAssert` starting to fail. doAssert validator != nil @@ -247,7 +247,7 @@ proc scheduleAttestation(node: BeaconNode, asyncCheck makeAttestation(node, validator, slot.uint64, shard, committeeLen, indexInCommittee) -proc scheduleCycleActions(node: BeaconNode, cycleStart: int) = +proc scheduleEpochActions(node: BeaconNode, epoch: uint64) = ## This schedules the required block proposals and ## attestations from our attached validators. doAssert node != nil @@ -256,14 +256,12 @@ proc scheduleCycleActions(node: BeaconNode, cycleStart: int) = # see the comments in `get_beacon_proposer_index` var nextState = node.beaconState - for i in 1 ..< EPOCH_LENGTH: + for i in 1.uint64 ..< EPOCH_LENGTH: # Schedule block proposals - nextState.slot = node.beaconState.slot + i.uint64 - - let - slot = cycleStart + i - proposerIdx = get_beacon_proposer_index(nextState, nextState.slot.uint64) - validator = node.getAttachedValidator(proposerIdx) + let slot = epoch * EPOCH_LENGTH + i + nextState.slot = slot + let proposerIdx = get_beacon_proposer_index(nextState, slot) + let validator = node.getAttachedValidator(proposerIdx) if validator != nil: # TODO: @@ -273,7 +271,7 @@ proc scheduleCycleActions(node: BeaconNode, cycleStart: int) = # Schedule attestations let - committeesIdx = get_shard_committees_index(nextState, nextState.slot.uint64) + committeesIdx = get_shard_committees_index(nextState, slot) for shard in node.beaconState.shard_committees_at_slots[committees_idx]: for i, validatorIdx in shard.committee: @@ -281,12 +279,12 @@ proc scheduleCycleActions(node: BeaconNode, cycleStart: int) = if validator != nil: scheduleAttestation(node, validator, slot, shard.shard, shard.committee.len, i) - node.lastScheduledCycle = cycleStart - let nextCycle = cycleStart + EPOCH_LENGTH + node.lastScheduledEpoch = epoch + let nextEpoch = epoch + 1 - addTimer(node.beaconState.slotMiddle(nextCycle)) do (p: pointer): - if node.lastScheduledCycle != nextCycle: - node.scheduleCycleActions(nextCycle) + addTimer(node.beaconState.slotMiddle(nextEpoch * EPOCH_LENGTH)) do (p: pointer): + if node.lastScheduledEpoch != nextEpoch: + node.scheduleEpochActions(nextEpoch) proc processBlocks*(node: BeaconNode) = node.network.subscribe(topicBeaconBlocks) do (newBlock: BeaconBlock): @@ -314,10 +312,9 @@ proc processBlocks*(node: BeaconNode) = # 3. Peform block processing / state recalculation / etc # - let slot = newBlock.slot.int - if slot mod EPOCH_LENGTH == 0: - node.scheduleCycleActions(slot) - node.attestationPool.discardHistoryToSlot(slot) + let epoch = newBlock.slot.epoch + if epoch != node.lastScheduledEpoch: + node.scheduleEpochActions(epoch) node.network.subscribe(topicAttestations) do (a: Attestation): info "Attestation received", slot = a.data.slot, @@ -327,8 +324,8 @@ proc processBlocks*(node: BeaconNode) = node.attestationPool.add(a, node.beaconState) dynamicLogScope(node = node.config.tcpPort - 50000): - let cycleStart = node.beaconState.slot.int - node.scheduleCycleActions(cycleStart) + let epoch = node.beaconState.slot.epoch + node.scheduleEpochActions(epoch) runForever() diff --git a/beacon_chain/fork_choice.nim b/beacon_chain/fork_choice.nim index 80e834730..1456d3d37 100644 --- a/beacon_chain/fork_choice.nim +++ b/beacon_chain/fork_choice.nim @@ -17,6 +17,14 @@ type attestations: Deque[array[SHARD_COUNT, Option[Attestation]]] startingSlot: int + # TODO: + # The compilicated Deque above is not needed. + # + # In fact, we can use a simple array with length SHARD_COUNT because + # in each epoch, each shard is going to receive attestations exactly once. + # Once the epoch is over, we can discard all attestations and start all + # over again (no need for `discardHistoryToSlot` too). + proc init*(T: type AttestationPool, startingSlot: int): T = result.attestations = initDeque[array[SHARD_COUNT, Option[Attestation]]]() result.startingSlot = startingSlot diff --git a/beacon_chain/spec/datatypes.nim b/beacon_chain/spec/datatypes.nim index 9510bd8a3..4f384ff46 100644 --- a/beacon_chain/spec/datatypes.nim +++ b/beacon_chain/spec/datatypes.nim @@ -94,7 +94,7 @@ const ZERO_HASH* = Eth2Digest() # Time constants - SLOT_DURATION* = 6 ## \ + SLOT_DURATION* = 6'u64 ## \ ## TODO consistent time unit across projects, similar to C++ chrono? MIN_ATTESTATION_INCLUSION_DELAY* = 2'u64^2 ##\ @@ -415,6 +415,9 @@ type DOMAIN_PROPOSAL = 2 DOMAIN_EXIT = 3 +template epoch*(slot: int|uint64): auto = + slot div EPOCH_LENGTH + when true: # TODO: Remove these once RLP serialization is no longer used import nimcrypto, rlp, json_serialization diff --git a/beacon_chain/time.nim b/beacon_chain/time.nim index f909d6cd5..6b294b969 100644 --- a/beacon_chain/time.nim +++ b/beacon_chain/time.nim @@ -15,20 +15,20 @@ proc timeSinceGenesis*(s: BeaconState): Timestamp = Timestamp(int64(fastEpochTime() - s.genesis_time * 1000) - detectedClockDrift) -template toSlot*(t: Timestamp): int = - int(t div uint64(SLOT_DURATION * 1000)) +template toSlot*(t: Timestamp): uint64 = + t div (SLOT_DURATION * 1000) -template slotStart*(s: BeaconState, slot: int): Timestamp = - (s.genesis_time + uint64(slot * SLOT_DURATION)) * 1000 +template slotStart*(s: BeaconState, slot: uint64): Timestamp = + (s.genesis_time + (slot * SLOT_DURATION)) * 1000 -template slotMiddle*(s: BeaconState, slot: int): Timestamp = +template slotMiddle*(s: BeaconState, slot: uint64): Timestamp = s.slotStart(slot) + SLOT_DURATION * 500 -template slotEnd*(s: BeaconState, slot: int): Timestamp = +template slotEnd*(s: BeaconState, slot: uint64): Timestamp = s.slotStart(slot + 1) proc randomTimeInSlot*(s: BeaconState, - slot: Natural, + slot: uint64, interval: HSlice[float, float]): Timestamp = ## Returns a random moment within the slot. ## The interval must be a sub-interval of [0..1]. diff --git a/beacon_chain/trusted_state_snapshots.nim b/beacon_chain/trusted_state_snapshots.nim index 310b03bec..c6ed9fcf2 100644 --- a/beacon_chain/trusted_state_snapshots.nim +++ b/beacon_chain/trusted_state_snapshots.nim @@ -3,7 +3,7 @@ import spec/[datatypes, crypto, digest, beaconstate], beacon_chain_db, conf const - WEAK_SUBJECTVITY_PERIOD* = 4 * 30 * 24 * 60 * 60 div SLOT_DURATION + WEAK_SUBJECTVITY_PERIOD* = uint64(4 * 30 * 24 * 60 * 60) div SLOT_DURATION # TODO: This needs revisiting. # Why was the validator WITHDRAWAL_PERIOD altered in the spec? diff --git a/beacon_chain/validator_pool.nim b/beacon_chain/validator_pool.nim index 7aa45dfaf..461ffe66b 100644 --- a/beacon_chain/validator_pool.nim +++ b/beacon_chain/validator_pool.nim @@ -50,7 +50,7 @@ proc signBlockProposal*(v: AttachedValidator, let proposalRoot = hash_tree_root_final(proposal) # TODO: Should we use proposalRoot as data, or digest in regards to signature? - return signMessage(v.privKey, proposalRoot.data) + result = signMessage(v.privKey, proposalRoot.data) else: # TODO: # send RPC @@ -64,7 +64,8 @@ proc signAttestation*(v: AttachedValidator, let attestationRoot = hash_tree_root_final(attestation) # TODO: Avoid the allocations belows - return signMessage(v.privKey, @(attestationRoot.data) & @[0'u8]) + var dataToSign = @(attestationRoot.data) & @[0'u8] + result = signMessage(v.privKey, dataToSign) else: # TODO: # send RPC diff --git a/tests/simulation/start.sh b/tests/simulation/start.sh index 5a973fee8..3bb632999 100755 --- a/tests/simulation/start.sh +++ b/tests/simulation/start.sh @@ -13,15 +13,20 @@ SNAPSHOT_FILE="$SIMULATION_DIR/state_snapshot.json" cd $(git rev-parse --show-toplevel) ROOT_DIR=$PWD -nim c beacon_chain/validator_keygen -nim c beacon_chain/beacon_node +BEACON_NODE_BIN=$BUILD_OUTPUTS_DIR/beacon_node +VALIDATOR_KEYGEN_BIN=$BUILD_OUTPUTS_DIR/validator_keygen + +if [[ ! -z "$SKIP_BUILDS" ]]; then + nim c -o:"$VALIDATOR_KEYGEN_BIN" beacon_chain/validator_keygen + nim c -o:"$BEACON_NODE_BIN" beacon_chain/beacon_node +fi if [ ! -f $STARTUP_FILE ]; then - beacon_chain/validator_keygen $NUMBER_OF_VALIDATORS "$SIMULATION_DIR" + $VALIDATOR_KEYGEN_BIN $NUMBER_OF_VALIDATORS "$SIMULATION_DIR" fi if [ ! -f $SNAPSHOT_FILE ]; then - beacon_chain/beacon_node createChain \ + $BEACON_NODE_BIN createChain \ --chainStartupData:$STARTUP_FILE \ --out:$SNAPSHOT_FILE fi @@ -47,7 +52,7 @@ for i in $(seq 0 9); do DATA_DIR=$SIMULATION_DIR/data-$i - beacon_chain/beacon_node \ + $BEACON_NODE_BIN \ --dataDir:"$DATA_DIR" \ --validator:"$SIMULATION_DIR/validator-${i}1.json" \ --validator:"$SIMULATION_DIR/validator-${i}2.json" \ @@ -64,3 +69,12 @@ for i in $(seq 0 9); do $BOOTSTRAP_NODES_FLAG & done +trap ctrl_c INT + +function ctrl_c() { + killall beacon_node + exit 0 +} + +sleep 100000 +