Stable network simulation
This commit is contained in:
parent
1c30214e9a
commit
a586087472
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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].
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue