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],
|
|
|
|
eth/p2p/[rlpx, peer_pool, private/p2p_types],
|
|
|
|
stint,
|
2022-05-13 16:30:10 +00:00
|
|
|
"."/[protocol, sync_types],
|
|
|
|
./snap/[chain_head_tracker, get_nodedata]
|
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
|
|
|
type
|
|
|
|
SnapSyncCtx* = ref object of SnapSync
|
|
|
|
peerPool: PeerPool
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private functions
|
|
|
|
# ------------------------------------------------------------------------------
|
2022-05-09 14:04:48 +00:00
|
|
|
|
|
|
|
proc syncPeerLoop(sp: SyncPeer) {.async.} =
|
|
|
|
# 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))
|
|
|
|
|
|
|
|
proc syncPeerStart(sp: SyncPeer) =
|
|
|
|
asyncSpawn sp.syncPeerLoop()
|
|
|
|
|
|
|
|
proc syncPeerStop(sp: SyncPeer) =
|
|
|
|
sp.stopped = true
|
|
|
|
# TODO: Cancel SyncPeers that are running. We need clean cancellation for
|
|
|
|
# this. Doing so reliably will be addressed at a later time.
|
|
|
|
|
2022-05-13 16:30:10 +00:00
|
|
|
proc onPeerConnected(ns: SnapSyncCtx, protocolPeer: Peer) =
|
2022-05-09 14:04:48 +00:00
|
|
|
let sp = SyncPeer(
|
|
|
|
ns: ns,
|
|
|
|
peer: protocolPeer,
|
|
|
|
stopped: false,
|
|
|
|
# Initial state: hunt forward, maximum uncertainty range.
|
|
|
|
syncMode: SyncHuntForward,
|
|
|
|
huntLow: 0.toBlockNumber,
|
|
|
|
huntHigh: high(BlockNumber),
|
|
|
|
huntStep: 0,
|
2022-05-13 16:30:10 +00:00
|
|
|
bestBlockNumber: 0.toBlockNumber)
|
2022-05-09 14:04:48 +00:00
|
|
|
trace "Sync: Peer connected", peer=sp
|
|
|
|
|
|
|
|
sp.setupGetNodeData()
|
|
|
|
|
|
|
|
if protocolPeer.state(eth).initialized:
|
|
|
|
# We know the hash but not the block number.
|
|
|
|
sp.bestBlockHash = protocolPeer.state(eth).bestBlockHash
|
|
|
|
#TODO: Temporarily disabled because it's useful to test the head hunter.
|
|
|
|
#sp.syncMode = SyncOnlyHash
|
|
|
|
else:
|
|
|
|
trace "Sync: state(eth) not initialized!"
|
|
|
|
|
|
|
|
ns.syncPeers.add(sp)
|
|
|
|
sp.syncPeerStart()
|
|
|
|
|
2022-05-13 16:30:10 +00:00
|
|
|
proc onPeerDisconnected(ns: SnapSyncCtx, protocolPeer: Peer) =
|
2022-05-09 14:04:48 +00:00
|
|
|
trace "Sync: Peer disconnected", peer=protocolPeer
|
|
|
|
# Find matching `sp` and remove from `ns.syncPeers`.
|
|
|
|
var sp: SyncPeer = nil
|
|
|
|
for i in 0 ..< ns.syncPeers.len:
|
|
|
|
if ns.syncPeers[i].peer == protocolPeer:
|
|
|
|
sp = ns.syncPeers[i]
|
|
|
|
ns.syncPeers.delete(i)
|
|
|
|
break
|
|
|
|
if sp.isNil:
|
|
|
|
debug "Sync: Unknown peer disconnected", peer=protocolPeer
|
|
|
|
return
|
|
|
|
|
|
|
|
sp.syncPeerStop()
|
|
|
|
|
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
|
|
|
|
# ------------------------------------------------------------------------------
|