2018-11-23 23:58:49 +00:00
|
|
|
import
|
2019-05-22 07:13:15 +00:00
|
|
|
options, tables, sequtils, algorithm, sets, macros,
|
2019-09-07 17:48:05 +00:00
|
|
|
chronicles, chronos, metrics, stew/ranges/bitranges,
|
2019-05-01 09:19:29 +00:00
|
|
|
spec/[datatypes, crypto, digest, helpers], eth/rlp,
|
2019-03-12 15:03:14 +00:00
|
|
|
beacon_node_types, eth2_network, beacon_chain_db, block_pool, time, ssz
|
|
|
|
|
2019-08-15 16:00:12 +00:00
|
|
|
when networkBackend == rlpxBackend:
|
|
|
|
import eth/rlp/options as rlpOptions
|
|
|
|
template libp2pProtocol*(name: string, version: int) {.pragma.}
|
|
|
|
|
2019-09-07 17:48:05 +00:00
|
|
|
declareGauge libp2p_peers, "Number of libp2p peers"
|
|
|
|
|
2018-11-23 23:58:49 +00:00
|
|
|
type
|
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
|
|
|
|
|
2019-01-17 18:27:11 +00:00
|
|
|
ValidatorSet = seq[Validator]
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2019-02-18 10:34:39 +00:00
|
|
|
BeaconSyncState* = ref object
|
|
|
|
node*: BeaconNode
|
|
|
|
db*: BeaconChainDB
|
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
BlockRootSlot* = object
|
|
|
|
blockRoot: Eth2Digest
|
|
|
|
slot: Slot
|
|
|
|
|
2019-04-09 07:53:40 +00:00
|
|
|
const
|
2019-07-03 07:35:05 +00:00
|
|
|
MaxRootsToRequest = 512'u64
|
2019-04-09 07:53:40 +00:00
|
|
|
MaxHeadersToRequest = MaxRootsToRequest
|
2019-04-26 06:21:46 +00:00
|
|
|
MaxAncestorBlocksResponse = 256
|
2019-04-09 07:53:40 +00:00
|
|
|
|
2019-06-10 11:13:53 +00:00
|
|
|
func toHeader(b: BeaconBlock): BeaconBlockHeader =
|
|
|
|
BeaconBlockHeader(
|
|
|
|
slot: b.slot,
|
2019-06-14 16:21:04 +00:00
|
|
|
parent_root: b.parent_root,
|
2019-03-01 20:09:20 +00:00
|
|
|
state_root: b.state_root,
|
2019-06-14 16:21:04 +00:00
|
|
|
body_root: hash_tree_root(b.body),
|
2019-06-10 11:13:53 +00:00
|
|
|
signature: b.signature
|
2019-03-01 20:09:20 +00:00
|
|
|
)
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-06-10 11:13:53 +00:00
|
|
|
proc fromHeaderAndBody(b: var BeaconBlock, h: BeaconBlockHeader, body: BeaconBlockBody) =
|
2019-06-14 16:21:04 +00:00
|
|
|
doAssert(hash_tree_root(body) == h.body_root)
|
2019-06-10 11:13:53 +00:00
|
|
|
b.slot = h.slot
|
2019-06-14 16:21:04 +00:00
|
|
|
b.parent_root = h.parent_root
|
2019-02-18 10:34:39 +00:00
|
|
|
b.state_root = h.state_root
|
2019-03-05 13:55:09 +00:00
|
|
|
b.body = body
|
2019-06-10 11:13:53 +00:00
|
|
|
b.signature = h.signature
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-03-13 21:23:01 +00:00
|
|
|
proc importBlocks(node: BeaconNode,
|
2019-06-10 11:13:53 +00:00
|
|
|
blocks: openarray[BeaconBlock]) =
|
|
|
|
for blk in blocks:
|
2019-06-17 11:08:05 +00:00
|
|
|
node.onBeaconBlock(node, blk)
|
2019-06-10 11:13:53 +00:00
|
|
|
info "Forward sync imported blocks", len = blocks.len
|
|
|
|
|
|
|
|
proc mergeBlockHeadersAndBodies(headers: openarray[BeaconBlockHeader], bodies: openarray[BeaconBlockBody]): Option[seq[BeaconBlock]] =
|
|
|
|
if bodies.len != headers.len:
|
|
|
|
info "Cannot merge bodies and headers. Length mismatch.", bodies = bodies.len, headers = headers.len
|
|
|
|
return
|
|
|
|
|
|
|
|
var res: seq[BeaconBlock]
|
|
|
|
for i in 0 ..< headers.len:
|
2019-06-14 16:21:04 +00:00
|
|
|
if hash_tree_root(bodies[i]) != headers[i].body_root:
|
2019-06-10 11:13:53 +00:00
|
|
|
info "Block body is wrong for header"
|
|
|
|
return
|
|
|
|
|
|
|
|
res.setLen(res.len + 1)
|
|
|
|
res[^1].fromHeaderAndBody(headers[i], bodies[i])
|
|
|
|
some(res)
|
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
proc getBeaconBlocks*(peer: Peer,
|
|
|
|
blockRoot: Eth2Digest,
|
|
|
|
slot: Slot,
|
|
|
|
maxBlocks, skipSlots: uint64,
|
|
|
|
backward: bool): Future[Option[seq[BeaconBlock]]] {.gcsafe, async.}
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-09-08 13:08:44 +00:00
|
|
|
proc getBeaconBlocksSpec*(peer: Peer, blockRoot: Eth2Digest,
|
|
|
|
slot: Slot, maxBlocks, skipSlots: uint64,
|
|
|
|
backward: bool): Future[Option[seq[BeaconBlock]]] {.gcsafe, async.}
|
|
|
|
|
2018-11-29 01:08:34 +00:00
|
|
|
p2pProtocol BeaconSync(version = 1,
|
2019-08-05 00:00:49 +00:00
|
|
|
rlpxName = "bcs",
|
2019-02-18 10:34:39 +00:00
|
|
|
networkState = BeaconSyncState):
|
|
|
|
|
2019-06-05 02:00:07 +00:00
|
|
|
onPeerConnected do (peer: Peer):
|
2019-03-18 03:54:08 +00:00
|
|
|
let
|
2019-02-18 10:34:39 +00:00
|
|
|
protocolVersion = 1 # TODO: Spec doesn't specify this yet
|
2019-03-18 03:54:08 +00:00
|
|
|
node = peer.networkState.node
|
2019-03-25 20:52:23 +00:00
|
|
|
blockPool = node.blockPool
|
2019-05-01 09:19:29 +00:00
|
|
|
finalizedHead = blockPool.finalizedHead
|
|
|
|
headBlock = blockPool.head.blck
|
|
|
|
bestRoot = headBlock.root
|
2019-04-09 07:53:40 +00:00
|
|
|
bestSlot = headBlock.slot
|
2019-07-01 07:53:42 +00:00
|
|
|
latestFinalizedEpoch = finalizedHead.slot.compute_epoch_of_slot()
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-08-15 18:41:58 +00:00
|
|
|
let handshakeFut = peer.hello(node.forkVersion,
|
|
|
|
finalizedHead.blck.root, latestFinalizedEpoch,
|
|
|
|
bestRoot, bestSlot, timeout = 10.seconds)
|
|
|
|
let m = await handshakeFut
|
2019-03-18 03:54:08 +00:00
|
|
|
|
2019-08-05 00:00:49 +00:00
|
|
|
if m.forkVersion != node.forkVersion:
|
2019-06-03 17:07:50 +00:00
|
|
|
await peer.disconnect(IrrelevantNetwork)
|
2019-03-18 03:54:08 +00:00
|
|
|
return
|
|
|
|
|
2019-03-26 10:01:13 +00:00
|
|
|
# TODO: onPeerConnected runs unconditionally for every connected peer, but we
|
|
|
|
# don't need to sync with everybody. The beacon node should detect a situation
|
|
|
|
# where it needs to sync and it should execute the sync algorithm with a certain
|
|
|
|
# number of randomly selected peers. The algorithm itself must be extracted in a proc.
|
|
|
|
try:
|
2019-09-07 17:48:05 +00:00
|
|
|
libp2p_peers.set peer.network.peers.len.int64
|
2019-04-09 07:53:40 +00:00
|
|
|
debug "Peer connected. Initiating sync", peer, bestSlot, remoteBestSlot = m.bestSlot
|
2019-03-27 13:04:09 +00:00
|
|
|
|
2019-03-26 10:01:13 +00:00
|
|
|
let bestDiff = cmp((latestFinalizedEpoch, bestSlot), (m.latestFinalizedEpoch, m.bestSlot))
|
2019-04-09 07:53:40 +00:00
|
|
|
if bestDiff >= 0:
|
2019-03-26 10:01:13 +00:00
|
|
|
# Nothing to do?
|
2019-06-17 11:08:05 +00:00
|
|
|
debug "Nothing to sync", peer
|
2019-02-18 10:34:39 +00:00
|
|
|
else:
|
2019-03-26 10:01:13 +00:00
|
|
|
# TODO: Check for WEAK_SUBJECTIVITY_PERIOD difference and terminate the
|
|
|
|
# connection if it's too big.
|
|
|
|
|
2019-04-09 07:53:40 +00:00
|
|
|
var s = bestSlot + 1
|
|
|
|
while s <= m.bestSlot:
|
2019-06-10 11:13:53 +00:00
|
|
|
debug "Waiting for block headers", fromPeer = peer, remoteBestSlot = m.bestSlot, peer
|
2019-07-03 07:35:05 +00:00
|
|
|
let headersLeft = uint64(m.bestSlot - s)
|
2019-09-08 13:08:44 +00:00
|
|
|
let blocks = await peer.getBeaconBlocksSpec(bestRoot, s, min(headersLeft, MaxHeadersToRequest), 0, false)
|
2019-06-10 11:13:53 +00:00
|
|
|
if blocks.isSome:
|
|
|
|
if blocks.get.len == 0:
|
|
|
|
info "Got 0 blocks while syncing", peer
|
2019-04-10 12:47:37 +00:00
|
|
|
break
|
2019-06-10 11:13:53 +00:00
|
|
|
node.importBlocks(blocks.get)
|
|
|
|
let lastSlot = blocks.get[^1].slot
|
|
|
|
if lastSlot <= s:
|
|
|
|
info "Slot did not advance during sync", peer
|
|
|
|
break
|
2019-06-17 11:08:05 +00:00
|
|
|
|
2019-06-10 11:13:53 +00:00
|
|
|
s = lastSlot + 1
|
2019-04-09 07:53:40 +00:00
|
|
|
else:
|
|
|
|
break
|
2019-03-27 13:04:09 +00:00
|
|
|
|
2019-03-26 10:01:13 +00:00
|
|
|
except CatchableError:
|
|
|
|
warn "Failed to sync with peer", peer, err = getCurrentExceptionMsg()
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-09-07 17:48:05 +00:00
|
|
|
onPeerDisconnected do (peer: Peer):
|
|
|
|
libp2p_peers.set peer.network.peers.len.int64
|
|
|
|
|
2019-05-22 07:13:15 +00:00
|
|
|
handshake:
|
|
|
|
proc hello(
|
2019-03-05 22:54:08 +00:00
|
|
|
peer: Peer,
|
2019-08-05 00:00:49 +00:00
|
|
|
fork_version: array[4, byte],
|
2019-03-05 22:54:08 +00:00
|
|
|
latestFinalizedRoot: Eth2Digest,
|
2019-03-13 21:23:01 +00:00
|
|
|
latestFinalizedEpoch: Epoch,
|
2019-03-05 22:54:08 +00:00
|
|
|
bestRoot: Eth2Digest,
|
2019-08-05 00:00:49 +00:00
|
|
|
bestSlot: Slot) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/hello/1/ssz", 1).}
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-08-05 00:00:49 +00:00
|
|
|
proc goodbye(
|
|
|
|
peer: Peer,
|
|
|
|
reason: DisconnectionReason) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/goodbye/1/ssz", 1).}
|
2019-05-22 07:13:15 +00:00
|
|
|
|
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,
|
|
|
|
headBlockRoot: Eth2Digest,
|
2019-09-08 13:08:44 +00:00
|
|
|
start_slot: uint64,
|
2019-08-05 00:00:49 +00:00
|
|
|
count: uint64,
|
|
|
|
step: uint64) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/beacon_blocks_by_range/1/ssz", 1).} =
|
2019-09-08 13:08:44 +00:00
|
|
|
var blocks: seq[BeaconBlock]
|
|
|
|
# `step == 0` has no sense, so we will return empty array of blocks.
|
|
|
|
# `count == 0` means that empty array of blocks requested.
|
|
|
|
#
|
|
|
|
# Current version of network specification do not cover case when
|
|
|
|
# `start_slot` is empty, in such case we will return next available slot
|
|
|
|
# which is follows `start_slot + step` sequence. For example for, if
|
|
|
|
# `start_slot` is 2 and `step` is 2 and slots 2, 4, 6 are not available,
|
|
|
|
# then [8, 10, ...] will be returned.
|
|
|
|
if step > 0'u64 and count > 0'u64:
|
|
|
|
let pool = peer.networkState.node.blockPool
|
|
|
|
var blck = pool.getRef(headBlockRoot)
|
|
|
|
var slot = start_slot
|
|
|
|
while not(isNil(blck)):
|
|
|
|
if blck.slot == slot:
|
|
|
|
blocks.add(pool.get(blck).data)
|
|
|
|
slot = slot + step
|
|
|
|
elif blck.slot > slot:
|
|
|
|
if (blck.slot - slot) mod step == 0:
|
|
|
|
blocks.add(pool.get(blck).data)
|
|
|
|
slot = slot + ((blck.slot - slot) div step + 1) * step
|
|
|
|
if uint64(len(blocks)) == count:
|
|
|
|
break
|
|
|
|
blck = blck.parent
|
2019-08-05 00:00:49 +00:00
|
|
|
|
|
|
|
await response.send(blocks)
|
|
|
|
|
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 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/beacon_blocks_by_root/1/ssz", 1).} =
|
2019-09-08 13:08:44 +00:00
|
|
|
let pool = peer.networkState.node.blockPool
|
|
|
|
var blocks = newSeq[BeaconBlock](len(blockRoots))
|
2019-08-05 00:00:49 +00:00
|
|
|
|
2019-09-08 13:08:44 +00:00
|
|
|
var index = 0
|
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)
|
|
|
|
if not(isNil(blockRef)):
|
|
|
|
blocks[index] = pool.get(blockRef).data
|
|
|
|
inc(index)
|
2019-08-05 00:00:49 +00:00
|
|
|
|
|
|
|
await response.send(blocks)
|
|
|
|
|
|
|
|
proc beaconBlocks(
|
|
|
|
peer: Peer,
|
2019-09-08 13:08:44 +00:00
|
|
|
blocks: openarray[BeaconBlock])
|
2019-05-22 07:13:15 +00:00
|
|
|
|
2019-04-09 07:53:40 +00:00
|
|
|
requestResponse:
|
2019-05-22 07:13:15 +00:00
|
|
|
proc getBeaconBlockRoots(
|
|
|
|
peer: Peer,
|
|
|
|
fromSlot: Slot,
|
2019-08-05 00:00:49 +00:00
|
|
|
maxRoots: uint64) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/beacon_block_roots/1/ssz", 1).} =
|
2019-04-10 12:47:37 +00:00
|
|
|
let maxRoots = min(MaxRootsToRequest, maxRoots)
|
2019-04-09 07:53:40 +00:00
|
|
|
var s = fromSlot
|
2019-07-03 07:35:05 +00:00
|
|
|
var roots = newSeqOfCap[BlockRootSlot](maxRoots)
|
2019-04-09 07:53:40 +00:00
|
|
|
let blockPool = peer.networkState.node.blockPool
|
2019-05-01 09:19:29 +00:00
|
|
|
let maxSlot = blockPool.head.blck.slot
|
2019-04-09 07:53:40 +00:00
|
|
|
while s <= maxSlot:
|
|
|
|
for r in blockPool.blockRootsForSlot(s):
|
2019-07-03 07:35:05 +00:00
|
|
|
roots.add BlockRootSlot(blockRoot: r, slot: s)
|
|
|
|
if roots.len == maxRoots.int: break
|
2019-04-09 07:53:40 +00:00
|
|
|
s += 1
|
|
|
|
await response.send(roots)
|
|
|
|
|
2019-08-05 00:00:49 +00:00
|
|
|
proc beaconBlockRoots(
|
|
|
|
peer: Peer,
|
|
|
|
roots: openarray[BlockRootSlot])
|
2019-02-18 10:34:39 +00:00
|
|
|
|
|
|
|
requestResponse:
|
2019-03-05 22:54:08 +00:00
|
|
|
proc getBeaconBlockHeaders(
|
|
|
|
peer: Peer,
|
|
|
|
blockRoot: Eth2Digest,
|
2019-03-13 21:23:01 +00:00
|
|
|
slot: Slot,
|
2019-07-03 07:35:05 +00:00
|
|
|
maxHeaders: uint64,
|
|
|
|
skipSlots: uint64,
|
2019-08-05 00:00:49 +00:00
|
|
|
backward: bool) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/beacon_block_headers/1/ssz", 1).} =
|
2019-04-10 12:47:37 +00:00
|
|
|
let maxHeaders = min(MaxHeadersToRequest, maxHeaders)
|
2019-06-10 11:13:53 +00:00
|
|
|
var headers: seq[BeaconBlockHeader]
|
2019-02-18 10:34:39 +00:00
|
|
|
let db = peer.networkState.db
|
2019-06-10 11:13:53 +00:00
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
if backward:
|
2019-06-10 11:13:53 +00:00
|
|
|
# TODO: implement skipSlots
|
|
|
|
|
|
|
|
var blockRoot = blockRoot
|
|
|
|
if slot != GENESIS_SLOT:
|
|
|
|
# TODO: Get block from the best chain by slot
|
|
|
|
# blockRoot = ...
|
|
|
|
discard
|
|
|
|
|
|
|
|
let blockPool = peer.networkState.node.blockPool
|
|
|
|
var br = blockPool.getRef(blockRoot)
|
|
|
|
var blockRefs = newSeqOfCap[BlockRef](maxHeaders)
|
|
|
|
|
|
|
|
while not br.isNil:
|
|
|
|
blockRefs.add(br)
|
2019-07-03 07:35:05 +00:00
|
|
|
if blockRefs.len == maxHeaders.int:
|
2019-06-10 11:13:53 +00:00
|
|
|
break
|
|
|
|
br = br.parent
|
|
|
|
|
|
|
|
headers = newSeqOfCap[BeaconBlockHeader](blockRefs.len)
|
|
|
|
for i in blockRefs.high .. 0:
|
|
|
|
headers.add(blockPool.get(blockRefs[i]).data.toHeader)
|
|
|
|
else:
|
|
|
|
# TODO: This branch has to be revisited and possibly somehow merged with the
|
|
|
|
# branch above once we can traverse the best chain forward
|
|
|
|
# TODO: implement skipSlots
|
|
|
|
headers = newSeqOfCap[BeaconBlockHeader](maxHeaders)
|
|
|
|
var s = slot
|
|
|
|
let blockPool = peer.networkState.node.blockPool
|
|
|
|
let maxSlot = blockPool.head.blck.slot
|
|
|
|
while s <= maxSlot:
|
|
|
|
for r in blockPool.blockRootsForSlot(s):
|
|
|
|
headers.add(db.getBlock(r).get().toHeader)
|
2019-07-03 07:35:05 +00:00
|
|
|
if headers.len == maxHeaders.int: break
|
2019-06-10 11:13:53 +00:00
|
|
|
s += 1
|
|
|
|
|
2019-03-05 22:54:08 +00:00
|
|
|
await response.send(headers)
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-08-05 00:00:49 +00:00
|
|
|
proc beaconBlockHeaders(
|
|
|
|
peer: Peer,
|
|
|
|
blockHeaders: openarray[BeaconBlockHeader])
|
|
|
|
|
|
|
|
# TODO move this at the bottom, because it's not in the spec yet, but it will
|
|
|
|
# consume a `method_id`
|
|
|
|
requestResponse:
|
|
|
|
proc getAncestorBlocks(
|
|
|
|
peer: Peer,
|
|
|
|
needed: openarray[FetchRecord]) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/ancestor_blocks/1/ssz", 1).} =
|
2019-08-05 00:00:49 +00:00
|
|
|
var resp = newSeqOfCap[BeaconBlock](needed.len)
|
|
|
|
let db = peer.networkState.db
|
|
|
|
var neededRoots = initSet[Eth2Digest]()
|
|
|
|
for rec in needed: neededRoots.incl(rec.root)
|
|
|
|
|
|
|
|
for rec in needed:
|
|
|
|
if (var blck = db.getBlock(rec.root); blck.isSome()):
|
|
|
|
# TODO validate historySlots
|
|
|
|
let firstSlot = blck.get().slot - rec.historySlots
|
|
|
|
|
|
|
|
for i in 0..<rec.historySlots.int:
|
|
|
|
resp.add(blck.get())
|
|
|
|
if resp.len >= MaxAncestorBlocksResponse:
|
|
|
|
break
|
|
|
|
|
|
|
|
if blck.get().parent_root in neededRoots:
|
|
|
|
# Don't send duplicate blocks, if neededRoots has roots that are
|
|
|
|
# in the same chain
|
|
|
|
break
|
|
|
|
|
|
|
|
if (blck = db.getBlock(blck.get().parent_root);
|
|
|
|
blck.isNone() or blck.get().slot < firstSlot):
|
|
|
|
break
|
|
|
|
|
|
|
|
if resp.len >= MaxAncestorBlocksResponse:
|
|
|
|
break
|
|
|
|
|
|
|
|
await response.send(resp)
|
|
|
|
|
|
|
|
proc ancestorBlocks(
|
|
|
|
peer: Peer,
|
|
|
|
blocks: openarray[BeaconBlock])
|
2019-03-28 14:03:19 +00:00
|
|
|
|
2019-02-18 10:34:39 +00:00
|
|
|
requestResponse:
|
2019-03-05 22:54:08 +00:00
|
|
|
proc getBeaconBlockBodies(
|
|
|
|
peer: Peer,
|
2019-08-05 00:00:49 +00:00
|
|
|
blockRoots: openarray[Eth2Digest]) {.
|
2019-09-08 14:54:31 +00:00
|
|
|
libp2pProtocol("/eth2/beacon_chain/req/beacon_block_bodies/1/ssz", 1).} =
|
2019-02-18 10:34:39 +00:00
|
|
|
# TODO: Validate blockRoots.len
|
|
|
|
var bodies = newSeqOfCap[BeaconBlockBody](blockRoots.len)
|
|
|
|
let db = peer.networkState.db
|
|
|
|
for r in blockRoots:
|
|
|
|
if (let blk = db.getBlock(r); blk.isSome):
|
|
|
|
bodies.add(blk.get().body)
|
2019-06-10 11:13:53 +00:00
|
|
|
else:
|
|
|
|
bodies.setLen(bodies.len + 1) # According to wire spec. Pad with zero body.
|
2019-03-05 22:54:08 +00:00
|
|
|
await response.send(bodies)
|
2019-02-18 10:34:39 +00:00
|
|
|
|
2019-03-05 22:54:08 +00:00
|
|
|
proc beaconBlockBodies(
|
|
|
|
peer: Peer,
|
|
|
|
blockBodies: openarray[BeaconBlockBody])
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2019-07-03 07:35:05 +00:00
|
|
|
proc getBeaconBlocks*(peer: Peer,
|
|
|
|
blockRoot: Eth2Digest,
|
|
|
|
slot: Slot,
|
|
|
|
maxBlocks, skipSlots: uint64,
|
|
|
|
backward: bool): Future[Option[seq[BeaconBlock]]] {.async.} =
|
2019-09-08 13:08:44 +00:00
|
|
|
## Retrieve block headers and block bodies from the remote peer,
|
|
|
|
## merge them into blocks.
|
2019-06-10 11:13:53 +00:00
|
|
|
assert(maxBlocks <= MaxHeadersToRequest)
|
|
|
|
let headersResp = await peer.getBeaconBlockHeaders(blockRoot, slot, maxBlocks, skipSlots, backward)
|
|
|
|
if headersResp.isNone: return
|
|
|
|
|
|
|
|
let headers = headersResp.get.blockHeaders
|
|
|
|
if headers.len == 0:
|
|
|
|
info "Peer has no headers", peer
|
|
|
|
var res: seq[BeaconBlock]
|
|
|
|
return some(res)
|
|
|
|
|
|
|
|
let bodiesRequest = headers.mapIt(signing_root(it))
|
|
|
|
|
|
|
|
debug "Block headers received. Requesting block bodies", peer
|
|
|
|
let bodiesResp = await peer.getBeaconBlockBodies(bodiesRequest)
|
|
|
|
if bodiesResp.isNone:
|
|
|
|
info "Did not receive bodies", peer
|
|
|
|
return
|
|
|
|
|
|
|
|
result = mergeBlockHeadersAndBodies(headers, bodiesResp.get.blockBodies)
|
|
|
|
# If result.isNone: disconnect with BreachOfProtocol?
|
2019-09-08 13:08:44 +00:00
|
|
|
|
|
|
|
proc getBeaconBlocksSpec*(peer: Peer, blockRoot: Eth2Digest, slot: Slot,
|
|
|
|
maxBlocks, skipSlots: uint64,
|
|
|
|
backward: bool): Future[Option[seq[BeaconBlock]]] {.async.} =
|
|
|
|
## Retrieve blocks from the remote peer, according to new network
|
|
|
|
## specification.
|
|
|
|
doAssert(maxBlocks <= MaxHeadersToRequest)
|
|
|
|
var startSlot = uint64(slot) + skipSlots
|
2019-09-08 14:54:31 +00:00
|
|
|
var blocksResp = await peer.beaconBlocksByRange(blockRoot, startSlot,
|
2019-09-08 13:08:44 +00:00
|
|
|
maxBlocks, 1'u64)
|
|
|
|
let blocks = blocksResp.get.blocks
|
|
|
|
info "Peer returned blocks", peer, count = len(blocks)
|
|
|
|
result = some(blocks)
|