nimbus-eth1/nimbus/sync/snap/worker/fetch.nim

117 lines
3.8 KiB
Nim

# Nimbus - Fetch account and storage states from peers efficiently
#
# 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
std/[sets, random],
chronos,
nimcrypto/keccak,
stint,
eth/[common/eth_types, p2p],
../../types,
../path_desc,
./fetch/[common, fetch_snap, fetch_trie],
./worker_desc
{.push raises: [Defect].}
logScope:
topics = "snap fetch"
# Note: To test disabling snap (or trie), modify `fetchTrieOk` or
# `fetchSnapOk` where those are defined.
# ------------------------------------------------------------------------------
# Public start/stop and admin functions
# ------------------------------------------------------------------------------
proc fetchSetup*(ns: Worker) =
## Global set up
ns.commonSetup()
proc fetchRelease*(ns: Worker) =
## Global clean up
ns.commonRelease()
proc fetchStart*(sp: WorkerBuddy) =
## Initialise `WorkerBuddy` to support `ReplyData.new()` calls.
sp.fetchTrieStart()
trace "Supported fetch modes", peer=sp,
ctrlState=sp.ctrl.state, trieMode=sp.fetchTrieOk, snapMode=sp.fetchSnapOk
proc fetchStop*(sp: WorkerBuddy) =
## Clean up for this peer
sp.fetchTrieStop()
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc fetch*(sp: WorkerBuddy) {.async.} =
var stateRoot = sp.ctrl.stateRoot.get
trace "Syncing from stateRoot", peer=sp, stateRoot
while true:
if not sp.fetchTrieOk and not sp.fetchSnapOk:
trace "No more sync available from this peer", peer=sp
return
if not sp.hasSlice():
trace "Nothing more to sync from this peer", peer=sp
while not sp.hasSlice():
await sleepAsync(5.seconds) # TODO: Use an event trigger instead.
if sp.ctrl.stateRoot.isNone:
trace "No current state root for this peer", peer=sp
while sp.ctrl.stateRoot.isNone and
(sp.fetchTrieOk or sp.fetchSnapOk) and
sp.hasSlice():
await sleepAsync(5.seconds) # TODO: Use an event trigger instead.
continue
if stateRoot != sp.ctrl.stateRoot.get:
trace "Syncing from new stateRoot", peer=sp, stateRoot
stateRoot = sp.ctrl.stateRoot.get
sp.ctrl.stopped = false
if sp.ctrl.stopRequest:
trace "Pausing sync until we get a new state root", peer=sp
while sp.ctrl.stateRoot.isSome and stateRoot == sp.ctrl.stateRoot.get and
(sp.fetchTrieOk or sp.fetchSnapOk) and
sp.hasSlice():
await sleepAsync(5.seconds) # TODO: Use an event trigger instead.
continue
var leafRange: LeafRange
# Mix up different slice modes, because when connecting to static nodes one
# mode or the other tends to dominate, which makes the mix harder to test.
var allowSnap = true
if sp.fetchSnapOk and sp.fetchTrieOk:
if rand(99) < 50:
allowSnap = false
if sp.fetchSnapOk and allowSnap:
discard sp.getSlice(leafRange)
trace "GetAccountRange segment", peer=sp,
leafRange=pathRange(leafRange.leafLow, leafRange.leafHigh), stateRoot
await sp.fetchSnap(stateRoot, leafRange)
elif sp.fetchTrieOk:
discard sp.getSlice(leafRange)
trace "GetNodeData segment", peer=sp,
leafRange=pathRange(leafRange.leafLow, leafRange.leafHigh), stateRoot
await sp.fetchTrie(stateRoot, leafRange)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------