2022-05-09 15:04:48 +01:00
|
|
|
# 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.
|
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
|
|
|
import
|
2022-05-13 17:30:10 +01:00
|
|
|
std/[sets, random],
|
2022-05-09 15:04:48 +01:00
|
|
|
chronos,
|
|
|
|
nimcrypto/keccak,
|
|
|
|
stint,
|
|
|
|
eth/[common/eth_types, p2p, rlp],
|
2022-05-13 17:30:10 +01:00
|
|
|
../../sync_types,
|
2022-05-09 15:04:48 +01:00
|
|
|
"."/[common, fetch_trie, fetch_snap]
|
|
|
|
|
|
|
|
# Note: To test disabling snap (or trie), modify `peerSupportsGetNodeData` or
|
|
|
|
# `peerSupportsSnap` where those are defined.
|
|
|
|
|
|
|
|
proc stateFetch*(sp: SyncPeer) {.async.} =
|
|
|
|
var stateRoot = sp.syncStateRoot.get
|
|
|
|
trace "Sync: Syncing from stateRoot", peer=sp, stateRoot=($stateRoot)
|
|
|
|
|
|
|
|
while true:
|
|
|
|
if not sp.peerSupportsGetNodeData() and not sp.peerSupportsSnap():
|
|
|
|
trace "Sync: Cannot sync more from this peer", peer=sp
|
|
|
|
return
|
|
|
|
|
|
|
|
if not sp.hasSlice():
|
|
|
|
trace "Sync: 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.syncStateRoot.isNone:
|
|
|
|
trace "Sync: No current state root for this peer", peer=sp
|
|
|
|
while sp.syncStateRoot.isNone and
|
|
|
|
(sp.peerSupportsGetNodeData() or sp.peerSupportsSnap()) and
|
|
|
|
sp.hasSlice():
|
|
|
|
await sleepAsync(5.seconds) # TODO: Use an event trigger instead.
|
|
|
|
continue
|
|
|
|
|
|
|
|
if stateRoot != sp.syncStateRoot.get:
|
|
|
|
trace "Sync: Syncing from new stateRoot", peer=sp, stateRoot=($stateRoot)
|
|
|
|
stateRoot = sp.syncStateRoot.get
|
|
|
|
sp.stopThisState = false
|
|
|
|
|
|
|
|
if sp.stopThisState:
|
|
|
|
trace "Sync: Pausing sync until we get a new state root", peer=sp
|
|
|
|
while sp.syncStateRoot.isSome and stateRoot == sp.syncStateRoot.get and
|
|
|
|
(sp.peerSupportsGetNodeData() or sp.peerSupportsSnap()) 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.peerSupportsSnap() and sp.peerSupportsGetNodeData():
|
|
|
|
if rand(99) < 50:
|
|
|
|
allowSnap = false
|
|
|
|
|
|
|
|
if sp.peerSupportsSnap() and allowSnap:
|
|
|
|
discard sp.getSlice(leafRange)
|
|
|
|
trace "Sync: snap.GetAccountRange segment", peer=sp,
|
|
|
|
leafRange=pathRange(leafRange.leafLow, leafRange.leafHigh),
|
|
|
|
stateRoot=($stateRoot)
|
|
|
|
await sp.snapFetch(stateRoot, leafRange)
|
|
|
|
elif sp.peerSupportsGetNodeData():
|
|
|
|
discard sp.getSlice(leafRange)
|
|
|
|
trace "Sync: eth.GetNodeData segment", peer=sp,
|
|
|
|
leafRange=pathRange(leafRange.leafLow, leafRange.leafHigh),
|
|
|
|
stateRoot=($stateRoot)
|
|
|
|
await sp.trieFetch(stateRoot, leafRange)
|