Add light client mode to fluffy (#1396)
This commit is contained in:
parent
270ce41d5c
commit
2bce04afc7
|
@ -12,6 +12,8 @@ import
|
|||
uri, confutils, confutils/std/net, chronicles,
|
||||
eth/keys, eth/net/nat, eth/p2p/discoveryv5/[enr, node],
|
||||
json_rpc/rpcproxy,
|
||||
nimcrypto/hash,
|
||||
stew/byteutils,
|
||||
./network/wire/portal_protocol_config
|
||||
|
||||
proc defaultDataDir*(): string =
|
||||
|
@ -40,6 +42,8 @@ const
|
|||
defaultStorageSizeDesc* = $defaultStorageSize
|
||||
|
||||
type
|
||||
TrustedDigest* = MDigest[32 * 8]
|
||||
|
||||
PortalCmd* = enum
|
||||
noCommand
|
||||
|
||||
|
@ -208,12 +212,25 @@ type
|
|||
defaultValueDesc: $defaultStorageSizeDesc
|
||||
name: "storage-size" .}: uint32
|
||||
|
||||
trustedBlockRoot* {.
|
||||
desc: "Recent trusted finalized block root to initialize the consensus light client from. " &
|
||||
"If not provided by the user, portal light client will be disabled."
|
||||
defaultValue: none(TrustedDigest)
|
||||
name: "trusted-block-root" .}: Option[TrustedDigest]
|
||||
|
||||
case cmd* {.
|
||||
command
|
||||
defaultValue: noCommand .}: PortalCmd
|
||||
of noCommand:
|
||||
discard
|
||||
|
||||
func parseCmdArg*(T: type TrustedDigest, input: string): T
|
||||
{.raises: [ValueError, Defect].} =
|
||||
TrustedDigest.fromHex(input)
|
||||
|
||||
func completeCmdArg*(T: type TrustedDigest, input: string): seq[string] =
|
||||
return @[]
|
||||
|
||||
proc parseCmdArg*(T: type enr.Record, p: TaintedString): T
|
||||
{.raises: [Defect, ConfigurationError].} =
|
||||
if not fromURI(result, p):
|
||||
|
|
|
@ -14,11 +14,22 @@ import
|
|||
json_rpc/rpcproxy, stew/[byteutils, io2],
|
||||
eth/keys, eth/net/nat,
|
||||
eth/p2p/discoveryv5/protocol as discv5_protocol,
|
||||
beacon_chain/beacon_clock,
|
||||
beacon_chain/spec/forks,
|
||||
beacon_chain/spec/datatypes/altair,
|
||||
beacon_chain/gossip_processing/light_client_processor,
|
||||
./conf, ./network_metadata, ./common/common_utils,
|
||||
./rpc/[rpc_eth_api, bridge_client, rpc_discovery_api, rpc_portal_api,
|
||||
rpc_portal_debug_api],
|
||||
./network/state/[state_network, state_content],
|
||||
./network/history/[history_network, history_content],
|
||||
./network/beacon_light_client/[
|
||||
light_client_init_loader,
|
||||
light_client_content,
|
||||
beacon_light_client,
|
||||
light_client_db,
|
||||
light_client_network
|
||||
],
|
||||
./network/wire/[portal_stream, portal_protocol_config],
|
||||
./data/[history_data_seeding, history_data_parser],
|
||||
./content_db
|
||||
|
@ -163,6 +174,78 @@ proc run(config: PortalConf) {.raises: [CatchableError, Defect].} =
|
|||
let bridgeClient = initializeBridgeClient(config.bridgeUri)
|
||||
|
||||
d.start()
|
||||
|
||||
# TODO: Currently disabled by default as it is not stable/polished enough,
|
||||
# ultimatetely this should probably be always on.
|
||||
if config.trustedBlockRoot.isSome():
|
||||
# fluffy light client works only over mainnet data
|
||||
let
|
||||
networkData = loadNetworkData("mainnet")
|
||||
|
||||
db = LightClientDb.new(config.dataDir / "lightClientDb")
|
||||
|
||||
lightClientNetwork = LightClientNetwork.new(
|
||||
d,
|
||||
db,
|
||||
streamManager,
|
||||
networkData.forks,
|
||||
bootstrapRecords = bootstrapRecords)
|
||||
|
||||
getBeaconTime = networkData.clock.getBeaconTimeFn()
|
||||
|
||||
refDigests = newClone networkData.forks
|
||||
|
||||
lc = LightClient.new(
|
||||
lightClientNetwork,
|
||||
rng,
|
||||
networkData.metadata.cfg,
|
||||
refDigests,
|
||||
getBeaconTime,
|
||||
networkData.genesis_validators_root,
|
||||
LightClientFinalizationMode.Optimistic
|
||||
)
|
||||
|
||||
# TODO: For now just log headers. Ultimately we should also use callbacks for each
|
||||
# lc object to save them to db and offer them to the network.
|
||||
proc onFinalizedHeader(
|
||||
lightClient: LightClient, finalizedHeader: BeaconBlockHeader) =
|
||||
info "New LC finalized header",
|
||||
finalized_header = shortLog(finalizedHeader)
|
||||
|
||||
proc onOptimisticHeader(
|
||||
lightClient: LightClient, optimisticHeader: BeaconBlockHeader) =
|
||||
info "New LC optimistic header",
|
||||
optimistic_header = shortLog(optimisticHeader)
|
||||
|
||||
lc.onFinalizedHeader = onFinalizedHeader
|
||||
lc.onOptimisticHeader = onOptimisticHeader
|
||||
lc.trustedBlockRoot = config.trustedBlockRoot
|
||||
|
||||
proc onSecond(time: Moment) =
|
||||
let wallSlot = getBeaconTime().slotOrZero()
|
||||
# TODO this is a place to enable/disable gossip based on the current status
|
||||
# of light client
|
||||
# lc.updateGossipStatus(wallSlot + 1)
|
||||
|
||||
proc runOnSecondLoop() {.async.} =
|
||||
let sleepTime = chronos.seconds(1)
|
||||
while true:
|
||||
let start = chronos.now(chronos.Moment)
|
||||
await chronos.sleepAsync(sleepTime)
|
||||
let afterSleep = chronos.now(chronos.Moment)
|
||||
let sleepTime = afterSleep - start
|
||||
onSecond(start)
|
||||
let finished = chronos.now(chronos.Moment)
|
||||
let processingTime = finished - afterSleep
|
||||
trace "onSecond task completed", sleepTime, processingTime
|
||||
|
||||
onSecond(Moment.now())
|
||||
|
||||
lightClientNetwork.start()
|
||||
lc.start()
|
||||
|
||||
asyncSpawn runOnSecondLoop()
|
||||
|
||||
historyNetwork.start()
|
||||
stateNetwork.start()
|
||||
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
chronicles,
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# Nimbus - Portal Network
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
beacon_chain/networking/network_metadata,
|
||||
beacon_chain/spec/forks,
|
||||
beacon_chain/spec/datatypes/altair,
|
||||
beacon_chain/beacon_clock,
|
||||
beacon_chain/nimbus_binary_common,
|
||||
beacon_chain/conf
|
||||
|
||||
type
|
||||
NetworkInitData* = object
|
||||
clock*: BeaconClock
|
||||
metaData*: Eth2NetworkMetadata
|
||||
forks*: ForkDigests
|
||||
genesis_validators_root*: Eth2Digest
|
||||
|
||||
proc loadNetworkData*(networkName: string): NetworkInitData {.raises: [CatchableError, Defect].}=
|
||||
let
|
||||
metadata =
|
||||
try:
|
||||
loadEth2Network(some("mainnet"))
|
||||
except CatchableError as exc:
|
||||
raiseAssert(exc.msg)
|
||||
|
||||
genesisState =
|
||||
try:
|
||||
template genesisData(): auto = metadata.genesisData
|
||||
newClone(readSszForkedHashedBeaconState(
|
||||
metadata.cfg, genesisData.toOpenArrayByte(genesisData.low, genesisData.high)))
|
||||
except CatchableError as err:
|
||||
raiseAssert "Invalid baked-in state: " & err.msg
|
||||
|
||||
beaconClock = BeaconClock.init(getStateField(genesisState[], genesis_time))
|
||||
|
||||
genesis_validators_root =
|
||||
getStateField(genesisState[], genesis_validators_root)
|
||||
|
||||
forks = newClone ForkDigests.init(metadata.cfg, genesis_validators_root)
|
||||
|
||||
return NetworkInitData(
|
||||
clock: beaconClock,
|
||||
metaData: metaData,
|
||||
forks: forks[],
|
||||
genesis_validators_root: genesis_validators_root
|
||||
)
|
|
@ -14,7 +14,11 @@ import
|
|||
eth/[common/eth_types, rlp],
|
||||
../../nimbus/rpc/[rpc_types, hexstrings, filters],
|
||||
../../nimbus/transaction,
|
||||
../../nimbus/common/chain_config,
|
||||
# TODO: this is a bit weird but having this import makes beacon_light_client
|
||||
# to fail compilation due throwing undeclared `CatchableError` in
|
||||
# `vendor/nimbus-eth2/beacon_chain/spec/keystore.nim`. This is most probably
|
||||
# caused by `readValue` clashing ?
|
||||
# ../../nimbus/common/chain_config
|
||||
../network/history/[history_network, history_content]
|
||||
|
||||
# Subset of Eth JSON-RPC API: https://eth.wiki/json-rpc/API
|
||||
|
@ -190,8 +194,9 @@ proc installEthApiHandlers*(
|
|||
# Supported API through the Portal Network
|
||||
|
||||
rpcServerWithProxy.rpc("eth_chainId") do() -> HexQuantityStr:
|
||||
# The Portal Network can only support MainNet at the moment
|
||||
return encodeQuantity(distinctBase(MainNet.ChainId))
|
||||
# The Portal Network can only support MainNet at the moment, so always return
|
||||
# 1
|
||||
return encodeQuantity(uint64(1))
|
||||
|
||||
rpcServerWithProxy.rpc("eth_getBlockByHash") do(
|
||||
data: EthHashStr, fullTransactions: bool) -> Option[BlockObject]:
|
||||
|
|
Loading…
Reference in New Issue