2022-05-09 14:04:48 +00:00
|
|
|
# Nimbus - New sync approach - A fusion of snap, trie, beam and other methods
|
|
|
|
#
|
|
|
|
# Copyright (c) 2021 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
|
|
# http://opensource.org/licenses/MIT)
|
|
|
|
# at your option. This file may not be copied, modified, or distributed
|
|
|
|
# except according to those terms.
|
|
|
|
|
|
|
|
import
|
|
|
|
chronicles,
|
|
|
|
chronos,
|
|
|
|
eth/[common/eth_types, p2p, rlp],
|
2022-05-17 11:09:49 +00:00
|
|
|
eth/p2p/[peer_pool, private/p2p_types, rlpx],
|
2022-05-09 14:04:48 +00:00
|
|
|
stint,
|
2022-05-17 11:09:49 +00:00
|
|
|
./protocol,
|
|
|
|
./snap/[base_desc, chain_head_tracker, get_nodedata, types],
|
|
|
|
./snap/pie/[sync_desc, peer_desc]
|
2022-05-13 16:30:10 +00:00
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
|
|
|
type
|
2022-05-17 11:09:49 +00:00
|
|
|
SnapSyncCtx* = ref object of SnapSyncEx
|
2022-05-13 16:30:10 +00:00
|
|
|
peerPool: PeerPool
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private helpers
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc fetchPeerDesc(ns: SnapSyncCtx, peer: Peer): SnapPeerEx =
|
|
|
|
## Find matching peer and remove descriptor from list
|
|
|
|
for i in 0 ..< ns.syncPeers.len:
|
|
|
|
if ns.syncPeers[i].peer == peer:
|
|
|
|
result = ns.syncPeers[i].ex
|
|
|
|
ns.syncPeers.delete(i)
|
|
|
|
return
|
|
|
|
|
|
|
|
proc new(T: type SnapPeerEx; ns: SnapSyncCtx; peer: Peer): T =
|
|
|
|
T(
|
|
|
|
ns: ns,
|
|
|
|
peer: peer,
|
|
|
|
stopped: false,
|
|
|
|
# Initial state: hunt forward, maximum uncertainty range.
|
|
|
|
syncMode: SyncHuntForward,
|
|
|
|
huntLow: 0.toBlockNumber,
|
|
|
|
huntHigh: high(BlockNumber),
|
|
|
|
huntStep: 0,
|
|
|
|
bestBlockNumber: 0.toBlockNumber)
|
|
|
|
|
2022-05-13 16:30:10 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private functions
|
|
|
|
# ------------------------------------------------------------------------------
|
2022-05-09 14:04:48 +00:00
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
proc syncPeerLoop(sp: SnapPeerEx) {.async.} =
|
2022-05-09 14:04:48 +00:00
|
|
|
# This basic loop just runs the head-hunter for each peer.
|
|
|
|
while not sp.stopped:
|
|
|
|
await sp.peerHuntCanonical()
|
|
|
|
if sp.stopped:
|
|
|
|
return
|
|
|
|
let delayMs = if sp.syncMode == SyncLocked: 1000 else: 50
|
|
|
|
await sleepAsync(chronos.milliseconds(delayMs))
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
|
|
|
|
proc syncPeerStart(sp: SnapPeerEx) =
|
2022-05-09 14:04:48 +00:00
|
|
|
asyncSpawn sp.syncPeerLoop()
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
proc syncPeerStop(sp: SnapPeerEx) =
|
2022-05-09 14:04:48 +00:00
|
|
|
sp.stopped = true
|
2022-05-17 11:09:49 +00:00
|
|
|
# TODO: Cancel running `SnapPeerEx` instances. We need clean cancellation
|
|
|
|
# for this. Doing so reliably will be addressed at a later time.
|
2022-05-09 14:04:48 +00:00
|
|
|
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
proc onPeerConnected(ns: SnapSyncCtx, peer: Peer) =
|
|
|
|
trace "Snap: Peer connected", peer
|
|
|
|
|
|
|
|
let sp = SnapPeerEx.new(ns, peer)
|
2022-05-09 14:04:48 +00:00
|
|
|
sp.setupGetNodeData()
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
if peer.state(eth).initialized:
|
2022-05-09 14:04:48 +00:00
|
|
|
# We know the hash but not the block number.
|
2022-05-17 11:09:49 +00:00
|
|
|
sp.bestBlockHash = peer.state(eth).bestBlockHash.BlockHash
|
|
|
|
# TODO: Temporarily disabled because it's useful to test the head hunter.
|
|
|
|
# sp.syncMode = SyncOnlyHash
|
2022-05-09 14:04:48 +00:00
|
|
|
else:
|
2022-05-17 11:09:49 +00:00
|
|
|
trace "Snap: state(eth) not initialized!"
|
2022-05-09 14:04:48 +00:00
|
|
|
|
|
|
|
ns.syncPeers.add(sp)
|
|
|
|
sp.syncPeerStart()
|
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
proc onPeerDisconnected(ns: SnapSyncCtx, peer: Peer) =
|
|
|
|
trace "Snap: Peer disconnected", peer
|
2022-05-09 14:04:48 +00:00
|
|
|
|
2022-05-17 11:09:49 +00:00
|
|
|
let sp = ns.fetchPeerDesc(peer)
|
|
|
|
if sp.isNil:
|
|
|
|
debug "Snap: Disconnected from unregistered peer", peer
|
|
|
|
else:
|
|
|
|
sp.syncPeerStop()
|
2022-05-09 14:04:48 +00:00
|
|
|
|
2022-05-13 16:30:10 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public functions
|
|
|
|
# ------------------------------------------------------------------------------
|
2022-05-09 14:04:48 +00:00
|
|
|
|
2022-05-13 16:30:10 +00:00
|
|
|
proc new*(T: type SnapSyncCtx; ethNode: EthereumNode): T =
|
|
|
|
## Constructor
|
|
|
|
new result
|
|
|
|
result.peerPool = ethNode.peerPool
|
|
|
|
|
|
|
|
proc start*(ctx: SnapSyncCtx) =
|
|
|
|
## Set up syncing. This call should come early.
|
2022-05-09 14:04:48 +00:00
|
|
|
var po = PeerObserver(
|
|
|
|
onPeerConnected:
|
2022-05-13 16:30:10 +00:00
|
|
|
proc(p: Peer) {.gcsafe.} =
|
|
|
|
ctx.onPeerConnected(p),
|
2022-05-09 14:04:48 +00:00
|
|
|
onPeerDisconnected:
|
2022-05-13 16:30:10 +00:00
|
|
|
proc(p: Peer) {.gcsafe.} =
|
|
|
|
ctx.onPeerDisconnected(p))
|
|
|
|
po.setProtocol eth
|
|
|
|
ctx.peerPool.addObserver(ctx, po)
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|