2018-11-23 23:58:49 +00:00
|
|
|
import
|
2019-10-25 10:59:56 +00:00
|
|
|
options, tables, sets, macros,
|
2020-03-22 20:54:47 +00:00
|
|
|
chronicles, chronos, stew/ranges/bitranges, libp2p/switch,
|
2020-01-24 08:32:52 +00:00
|
|
|
spec/[datatypes, crypto, digest, helpers],
|
2019-11-25 14:36:25 +00:00
|
|
|
beacon_node_types, eth2_network, block_pool, ssz
|
2019-03-12 15:03:14 +00:00
|
|
|
|
2019-11-11 01:28:13 +00:00
|
|
|
logScope:
|
|
|
|
topics = "sync"
|
|
|
|
|
2018-11-23 23:58:49 +00:00
|
|
|
type
|
2020-04-20 14:59:18 +00:00
|
|
|
StatusMsg* = object
|
|
|
|
forkDigest*: ForkDigest
|
|
|
|
finalizedRoot*: Eth2Digest
|
|
|
|
finalizedEpoch*: Epoch
|
|
|
|
headRoot*: Eth2Digest
|
|
|
|
headSlot*: Slot
|
|
|
|
|
2019-07-08 13:19:52 +00:00
|
|
|
ValidatorSetDeltaFlags {.pure.} = enum
|
|
|
|
Activation = 0
|
|
|
|
Exit = 1
|
|
|
|
|
2018-11-23 23:58:49 +00:00
|
|
|
ValidatorChangeLogEntry* = object
|
|
|
|
case kind*: ValidatorSetDeltaFlags
|
2018-12-03 17:46:22 +00:00
|
|
|
of Activation:
|
2018-11-29 01:08:34 +00:00
|
|
|
pubkey: ValidatorPubKey
|
2018-11-23 23:58:49 +00:00
|
|
|
else:
|
|
|
|
index: uint32
|
|
|
|
|
2020-02-29 15:15:44 +00:00
|
|
|
BeaconBlockCallback* = proc(signedBlock: SignedBeaconBlock) {.gcsafe.}
|
2020-04-15 02:41:22 +00:00
|
|
|
|
2019-09-08 22:03:41 +00:00
|
|
|
BeaconSyncNetworkState* = ref object
|
2019-11-25 14:36:25 +00:00
|
|
|
blockPool*: BlockPool
|
2020-04-15 02:41:22 +00:00
|
|
|
forkDigest*: ForkDigest
|
2019-11-25 14:36:25 +00:00
|
|
|
onBeaconBlock*: BeaconBlockCallback
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-09-08 22:03:41 +00:00
|
|
|
BeaconSyncPeerState* = ref object
|
2020-04-20 14:59:18 +00:00
|
|
|
initialStatusReceived*: bool
|
|
|
|
statusMsg*: StatusMsg
|
2019-09-08 22:03:41 +00:00
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
BlockRootSlot* = object
|
|
|
|
blockRoot: Eth2Digest
|
|
|
|
slot: Slot
|
|
|
|
|
2019-04-09 07:53:40 +00:00
|
|
|
const
|
2019-09-11 16:45:22 +00:00
|
|
|
MAX_REQUESTED_BLOCKS = 20'u64
|
2019-11-25 14:36:25 +00:00
|
|
|
|
|
|
|
proc importBlocks(state: BeaconSyncNetworkState,
|
2019-12-16 18:08:50 +00:00
|
|
|
blocks: openarray[SignedBeaconBlock]) {.gcsafe.} =
|
2019-06-10 11:13:53 +00:00
|
|
|
for blk in blocks:
|
2019-11-25 14:36:25 +00:00
|
|
|
state.onBeaconBlock(blk)
|
2019-06-10 11:13:53 +00:00
|
|
|
info "Forward sync imported blocks", len = blocks.len
|
|
|
|
|
2019-11-25 14:36:25 +00:00
|
|
|
proc getCurrentStatus(state: BeaconSyncNetworkState): StatusMsg {.gcsafe.} =
|
2019-09-09 23:55:01 +00:00
|
|
|
let
|
2019-11-25 14:36:25 +00:00
|
|
|
blockPool = state.blockPool
|
2019-09-09 23:55:01 +00:00
|
|
|
finalizedHead = blockPool.finalizedHead
|
|
|
|
headBlock = blockPool.head.blck
|
|
|
|
headRoot = headBlock.root
|
|
|
|
headSlot = headBlock.slot
|
initial 0.9.0 spec sync (#509)
* rename compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* remove some unnecessary imports; remove some crosslink-related code and tests; complete renaming of compute_epoch_of_slot(...) to compute_epoch_at_slot(...)
* rm more transfer-related code and tests; rm more unnecessary strutils imports
* rm remaining unused imports
* remove useless get_empty_per_epoch_cache(...)/compute_start_slot_of_epoch(...) calls
* rename compute_start_slot_of_epoch(...) to compute_start_slot_at_epoch(...)
* rename ACTIVATION_EXIT_DELAY to MAX_SEED_LOOKAHEAD
* update domain types to 0.9.0
* mark AttesterSlashing, IndexedAttestation, AttestationDataAndCustodyBit, DepositData, BeaconBlockHeader, Fork, integer_squareroot(...), and process_voluntary_exit(...) as 0.9.0
* mark increase_balance(...), decrease_balance(...), get_block_root(...), CheckPoint, Deposit, PendingAttestation, HistoricalBatch, is_active_validator(...), and is_slashable_attestation_data(...) as 0.9.0
* mark compute_activation_exit_epoch(...), bls_verify(...), Validator, get_active_validator_indices(...), get_current_epoch(...), get_total_active_balance(...), and get_previous_epoch(...) as 0.9.0
* mark get_block_root_at_slot(...), ProposerSlashing, get_domain(...), VoluntaryExit, mainnet preset Gwei values, minimal preset max operations, process_block_header(...), and is_slashable_validator(...) as 0.9.0
* mark makeWithdrawalCredentials(...), get_validator_churn_limit(...), get_total_balance(...), is_valid_indexed_attestation(...), bls_aggregate_pubkeys(...), initial genesis value/constants, Attestation, get_randao_mix(...), mainnet preset max operations per block constants, minimal preset Gwei values and time parameters, process_eth1_data(...), get_shuffled_seq(...), compute_committee(...), and process_slots(...) as 0.9.0; partially update get_indexed_attestation(...) to 0.9.0 by removing crosslink refs and associated tests
* mark initiate_validator_exit(...), process_registry_updates(...), BeaconBlock, Eth1Data, compute_domain(...), process_randao(...), process_attester_slashing(...), get_base_reward(...), and process_slot(...) as 0.9.0
2019-10-30 19:41:19 +00:00
|
|
|
finalizedEpoch = finalizedHead.slot.compute_epoch_at_slot()
|
2019-09-09 23:55:01 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
StatusMsg(
|
2020-04-15 02:41:22 +00:00
|
|
|
forkDigest: state.forkDigest,
|
2019-09-09 23:55:01 +00:00
|
|
|
finalizedRoot: finalizedHead.blck.root,
|
|
|
|
finalizedEpoch: finalizedEpoch,
|
|
|
|
headRoot: headRoot,
|
|
|
|
headSlot: headSlot)
|
2019-09-08 22:03:41 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
proc handleInitialStatus(peer: Peer,
|
2019-11-25 14:36:25 +00:00
|
|
|
state: BeaconSyncNetworkState,
|
2019-09-11 16:45:22 +00:00
|
|
|
ourStatus: StatusMsg,
|
2020-04-20 14:59:18 +00:00
|
|
|
theirStatus: StatusMsg): Future[bool] {.async, gcsafe.}
|
2019-09-08 13:08:44 +00:00
|
|
|
|
2018-11-29 01:08:34 +00:00
|
|
|
p2pProtocol BeaconSync(version = 1,
|
2019-08-05 00:00:49 +00:00
|
|
|
rlpxName = "bcs",
|
2019-09-08 22:03:41 +00:00
|
|
|
networkState = BeaconSyncNetworkState,
|
|
|
|
peerState = BeaconSyncPeerState):
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-06-05 02:00:07 +00:00
|
|
|
onPeerConnected do (peer: Peer):
|
2019-09-08 22:03:41 +00:00
|
|
|
if peer.wasDialed:
|
|
|
|
let
|
2019-11-25 14:36:25 +00:00
|
|
|
ourStatus = peer.networkState.getCurrentStatus()
|
2019-11-12 22:53:19 +00:00
|
|
|
# TODO: The timeout here is so high only because we fail to
|
|
|
|
# respond in time due to high CPU load in our single thread.
|
|
|
|
theirStatus = await peer.status(ourStatus, timeout = 60.seconds)
|
2019-09-09 23:55:01 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
if theirStatus.isSome:
|
2020-04-20 14:59:18 +00:00
|
|
|
let tstatus = theirStatus.get()
|
|
|
|
let res = await peer.handleInitialStatus(peer.networkState,
|
|
|
|
ourStatus, tstatus)
|
|
|
|
if res:
|
|
|
|
peer.state(BeaconSync).statusMsg = tstatus
|
2019-02-18 10:34:39 +00:00
|
|
|
else:
|
2019-11-06 14:56:54 +00:00
|
|
|
warn "Status response not received in time"
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-09-08 22:03:41 +00:00
|
|
|
requestResponse:
|
2019-09-11 16:45:22 +00:00
|
|
|
proc status(peer: Peer, theirStatus: StatusMsg) {.libp2pProtocol("status", 1).} =
|
2019-09-08 22:03:41 +00:00
|
|
|
let
|
2019-11-25 14:36:25 +00:00
|
|
|
ourStatus = peer.networkState.getCurrentStatus()
|
2019-09-09 23:55:01 +00:00
|
|
|
|
2019-11-15 14:09:25 +00:00
|
|
|
trace "Sending status msg", ourStatus
|
2019-09-11 16:45:22 +00:00
|
|
|
await response.send(ourStatus)
|
2019-09-08 22:03:41 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
if not peer.state.initialStatusReceived:
|
|
|
|
peer.state.initialStatusReceived = true
|
2020-04-20 14:59:18 +00:00
|
|
|
let res = await peer.handleInitialStatus(peer.networkState,
|
|
|
|
ourStatus, theirStatus)
|
|
|
|
if res:
|
|
|
|
peer.state(BeaconSync).statusMsg = theirStatus
|
2019-09-08 22:03:41 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
proc statusResp(peer: Peer, msg: StatusMsg)
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-09-10 05:50:37 +00:00
|
|
|
proc goodbye(peer: Peer, reason: DisconnectionReason) {.libp2pProtocol("goodbye", 1).}
|
2019-05-22 07:13:15 +00:00
|
|
|
|
2020-04-15 02:41:22 +00:00
|
|
|
requestResponse:
|
|
|
|
proc ping(peer: Peer, value: uint64) {.libp2pProtocol("ping", 1).} =
|
|
|
|
await response.write(peer.network.metadata.seq_number)
|
|
|
|
|
|
|
|
proc pingResp(peer: Peer, value: uint64)
|
|
|
|
|
|
|
|
requestResponse:
|
|
|
|
proc getMetadata(peer: Peer) {.libp2pProtocol("metadata", 1).} =
|
|
|
|
await response.write(peer.network.metadata)
|
|
|
|
|
|
|
|
proc metadataReps(peer: Peer, metadata: Eth2Metadata)
|
|
|
|
|
2019-08-05 00:00:49 +00:00
|
|
|
requestResponse:
|
2019-09-08 14:54:31 +00:00
|
|
|
proc beaconBlocksByRange(
|
2019-08-05 00:00:49 +00:00
|
|
|
peer: Peer,
|
2019-09-10 05:50:37 +00:00
|
|
|
startSlot: Slot,
|
2019-08-05 00:00:49 +00:00
|
|
|
count: uint64,
|
|
|
|
step: uint64) {.
|
2019-09-08 22:03:41 +00:00
|
|
|
libp2pProtocol("beacon_blocks_by_range", 1).} =
|
2020-04-20 14:59:18 +00:00
|
|
|
trace "got range request", peer, count, startSlot, step
|
2019-09-10 05:50:37 +00:00
|
|
|
|
|
|
|
if count > 0'u64:
|
2019-09-11 16:45:22 +00:00
|
|
|
let count = if step != 0: min(count, MAX_REQUESTED_BLOCKS.uint64) else: 1
|
2019-11-25 14:36:25 +00:00
|
|
|
let pool = peer.networkState.blockPool
|
2019-09-11 16:45:22 +00:00
|
|
|
var results: array[MAX_REQUESTED_BLOCKS, BlockRef]
|
2019-09-10 05:50:37 +00:00
|
|
|
let
|
|
|
|
lastPos = min(count.int, results.len) - 1
|
2020-04-20 14:59:18 +00:00
|
|
|
firstPos = pool.getBlockRange(pool.head.blck.root, startSlot, step,
|
2019-09-10 05:50:37 +00:00
|
|
|
results.toOpenArray(0, lastPos))
|
|
|
|
for i in firstPos.int .. lastPos.int:
|
2019-11-11 01:28:13 +00:00
|
|
|
trace "wrote response block", slot = results[i].slot
|
2019-09-10 05:50:37 +00:00
|
|
|
await response.write(pool.get(results[i]).data)
|
2019-08-05 00:00:49 +00:00
|
|
|
|
2019-09-08 14:54:31 +00:00
|
|
|
proc beaconBlocksByRoot(
|
2019-08-05 00:00:49 +00:00
|
|
|
peer: Peer,
|
|
|
|
blockRoots: openarray[Eth2Digest]) {.
|
2019-09-08 22:03:41 +00:00
|
|
|
libp2pProtocol("beacon_blocks_by_root", 1).} =
|
2019-09-09 02:39:44 +00:00
|
|
|
let
|
2019-11-25 14:36:25 +00:00
|
|
|
pool = peer.networkState.blockPool
|
2019-08-05 00:00:49 +00:00
|
|
|
|
|
|
|
for root in blockRoots:
|
2019-09-08 13:08:44 +00:00
|
|
|
let blockRef = pool.getRef(root)
|
2019-09-09 02:39:44 +00:00
|
|
|
if not isNil(blockRef):
|
|
|
|
await response.write(pool.get(blockRef).data)
|
2019-08-05 00:00:49 +00:00
|
|
|
|
|
|
|
proc beaconBlocks(
|
|
|
|
peer: Peer,
|
2019-12-16 18:08:50 +00:00
|
|
|
blocks: openarray[SignedBeaconBlock])
|
2019-05-22 07:13:15 +00:00
|
|
|
|
2019-09-11 16:45:22 +00:00
|
|
|
proc handleInitialStatus(peer: Peer,
|
2019-11-25 14:36:25 +00:00
|
|
|
state: BeaconSyncNetworkState,
|
2019-09-11 16:45:22 +00:00
|
|
|
ourStatus: StatusMsg,
|
2020-04-20 14:59:18 +00:00
|
|
|
theirStatus: StatusMsg): Future[bool] {.async, gcsafe.} =
|
2020-04-15 02:41:22 +00:00
|
|
|
if theirStatus.forkDigest != state.forkDigest:
|
2020-04-20 14:59:18 +00:00
|
|
|
notice "Irrelevant peer",
|
|
|
|
peer, theirFork = theirStatus.forkDigest, ourFork = state.forkDigest
|
2019-09-09 23:55:01 +00:00
|
|
|
await peer.disconnect(IrrelevantNetwork)
|
2020-04-20 14:59:18 +00:00
|
|
|
return false
|
|
|
|
debug "Peer connected", peer,
|
|
|
|
localHeadSlot = ourStatus.headSlot,
|
|
|
|
remoteHeadSlot = theirStatus.headSlot,
|
|
|
|
remoteHeadRoot = theirStatus.headRoot
|
|
|
|
return true
|
2019-12-02 15:38:18 +00:00
|
|
|
|
2020-04-15 02:41:22 +00:00
|
|
|
proc initBeaconSync*(network: Eth2Node,
|
|
|
|
blockPool: BlockPool,
|
|
|
|
forkDigest: ForkDigest,
|
|
|
|
onBeaconBlock: BeaconBlockCallback) =
|
|
|
|
var networkState = network.protocolState(BeaconSync)
|
|
|
|
networkState.blockPool = blockPool
|
|
|
|
networkState.forkDigest = forkDigest
|
|
|
|
networkState.onBeaconBlock = onBeaconBlock
|