mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
Add beacon chain lc content bridging to the Fluffy bridge (#1517)
Also delete the old, obsolete bridge that only stores content into the db.
This commit is contained in:
parent
a31db89e0e
commit
84d9b9889f
@ -1,227 +0,0 @@
|
|||||||
# Nimbus
|
|
||||||
# Copyright (c) 2022-2023 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.
|
|
||||||
|
|
||||||
{.push raises: [].}
|
|
||||||
|
|
||||||
import
|
|
||||||
std/[os, strutils],
|
|
||||||
chronicles, chronicles/chronos_tools, chronos,
|
|
||||||
eth/keys,
|
|
||||||
beacon_chain/eth1/eth1_monitor,
|
|
||||||
beacon_chain/gossip_processing/[optimistic_processor, light_client_processor],
|
|
||||||
beacon_chain/spec/beaconstate,
|
|
||||||
beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
|
|
||||||
beacon_chain/[light_client, nimbus_binary_common, version],
|
|
||||||
"."/network/beacon_light_client/[
|
|
||||||
light_client_db,
|
|
||||||
light_client_network,
|
|
||||||
light_client_content,
|
|
||||||
beacon_light_client_bridge_conf
|
|
||||||
],
|
|
||||||
"."/network/wire/[portal_stream, portal_protocol_config, portal_protocol]
|
|
||||||
|
|
||||||
# TODO Find what can throw exception
|
|
||||||
proc run() {.raises: [Exception, Defect].} =
|
|
||||||
{.pop.}
|
|
||||||
var config = makeBannerAndConfig(
|
|
||||||
"Beacon light client bridge " & fullVersionStr, BridgeConf)
|
|
||||||
{.push raises: [].}
|
|
||||||
|
|
||||||
# Required as both Eth2Node and LightClient requires correct config type
|
|
||||||
var lcConfig = config.asLightClientConf()
|
|
||||||
|
|
||||||
setupLogging(config.logLevel, config.logStdout, none(OutFile))
|
|
||||||
|
|
||||||
notice "Launching Beacon light client bridge",
|
|
||||||
version = fullVersionStr, cmdParams = commandLineParams(), config
|
|
||||||
|
|
||||||
let
|
|
||||||
metadata = loadEth2Network(lcConfig.eth2Network)
|
|
||||||
|
|
||||||
for node in metadata.bootstrapNodes:
|
|
||||||
lcConfig.bootstrapNodes.add node
|
|
||||||
|
|
||||||
template cfg(): auto = metadata.cfg
|
|
||||||
|
|
||||||
let
|
|
||||||
genesisState =
|
|
||||||
try:
|
|
||||||
template genesisData(): auto = metadata.genesisData
|
|
||||||
newClone(readSszForkedHashedBeaconState(
|
|
||||||
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))
|
|
||||||
|
|
||||||
getBeaconTime = beaconClock.getBeaconTimeFn()
|
|
||||||
|
|
||||||
genesis_validators_root =
|
|
||||||
getStateField(genesisState[], genesis_validators_root)
|
|
||||||
|
|
||||||
forkDigests = newClone ForkDigests.init(cfg, genesis_validators_root)
|
|
||||||
|
|
||||||
genesisBlockRoot = get_initial_beacon_block(genesisState[]).root
|
|
||||||
|
|
||||||
rng = keys.newRng()
|
|
||||||
|
|
||||||
netKeys = getRandomNetKeys(rng[])
|
|
||||||
|
|
||||||
network = createEth2Node(
|
|
||||||
rng, lcConfig, netKeys, cfg,
|
|
||||||
forkDigests, getBeaconTime, genesis_validators_root
|
|
||||||
)
|
|
||||||
|
|
||||||
streamManager = StreamManager.new(network.discovery)
|
|
||||||
|
|
||||||
db = LightClientDb.new(lcConfig.dataDir / "db")
|
|
||||||
|
|
||||||
lcNetwork = LightClientNetwork.new(
|
|
||||||
network.discovery,
|
|
||||||
db,
|
|
||||||
streamManager,
|
|
||||||
forkDigests[]
|
|
||||||
)
|
|
||||||
|
|
||||||
lightClient = createLightClient(
|
|
||||||
network, rng, lcConfig, cfg, forkDigests, getBeaconTime,
|
|
||||||
genesis_validators_root, LightClientFinalizationMode.Optimistic)
|
|
||||||
|
|
||||||
info "Listening to incoming network requests"
|
|
||||||
network.initBeaconSync(cfg, forkDigests, genesisBlockRoot, getBeaconTime)
|
|
||||||
|
|
||||||
lightClient.installMessageValidators()
|
|
||||||
waitFor network.startListening()
|
|
||||||
waitFor network.start()
|
|
||||||
lcNetwork.start()
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# TODO Currently the only thing bridge does it to save all lc objects received
|
|
||||||
# from libp2p network to portal compatible database format. This way portal
|
|
||||||
# nodes can find this content in the network if bridge node is their neighbour.
|
|
||||||
# Ultimately bridge node should not only save objects into db, but also actively
|
|
||||||
# gossip them into the portal light client network.
|
|
||||||
proc onBootstrap(
|
|
||||||
lightClient: LightClient,
|
|
||||||
bootstrap: altair.LightClientBootstrap) =
|
|
||||||
info "New LC boostrap",
|
|
||||||
bootstrap, period = bootstrap.header.slot.sync_committee_period
|
|
||||||
|
|
||||||
let
|
|
||||||
bh = hash_tree_root(bootstrap.header)
|
|
||||||
contentKey = encode(bootstrapContentKey(bh))
|
|
||||||
contentId = toContentId(contentKey)
|
|
||||||
content = encodeBootstrapForked(
|
|
||||||
network.forkDigests.altair,
|
|
||||||
bootstrap
|
|
||||||
)
|
|
||||||
lcNetwork.portalProtocol.storeContent(
|
|
||||||
contentKey,
|
|
||||||
contentId,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
proc onLCUpdate(lightClient: LightClient, update: altair.LightClientUpdate) =
|
|
||||||
info "New LC update",
|
|
||||||
update, period = update.attested_header.slot.sync_committee_period
|
|
||||||
let
|
|
||||||
period = update.attested_header.slot.sync_committee_period
|
|
||||||
contentKey = encode(updateContentKey(period.uint64, uint64(1)))
|
|
||||||
contentId = toContentId(contentKey)
|
|
||||||
content = encodeLightClientUpdatesForked(
|
|
||||||
network.forkDigests.altair,
|
|
||||||
@[update]
|
|
||||||
)
|
|
||||||
lcNetwork.portalProtocol.storeContent(
|
|
||||||
contentKey,
|
|
||||||
contentId,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
proc onOptimisticUpdate(
|
|
||||||
lightClient: LightClient,
|
|
||||||
optUpdate: altair.LightClientOptimisticUpdate) =
|
|
||||||
info "New LC optimistic update",
|
|
||||||
optUpdate, period = optUpdate.attested_header.slot.sync_committee_period
|
|
||||||
let
|
|
||||||
slot = optUpdate.attested_header.slot
|
|
||||||
contentKey = encode(optimisticUpdateContentKey(slot.uint64))
|
|
||||||
contentId = toContentId(contentKey)
|
|
||||||
content = encodeOptimisticUpdateForked(
|
|
||||||
network.forkDigests.altair,
|
|
||||||
optUpdate
|
|
||||||
)
|
|
||||||
lcNetwork.portalProtocol.storeContent(
|
|
||||||
contentKey,
|
|
||||||
contentId,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
proc onFinalityUpdate(
|
|
||||||
lightClient: LightClient,
|
|
||||||
finUpdate: altair.LightClientFinalityUpdate) =
|
|
||||||
info "New LC finality update",
|
|
||||||
finUpdate, period = finUpdate.attested_header.slot.sync_committee_period
|
|
||||||
let
|
|
||||||
finSlot = finUpdate.finalized_header.slot
|
|
||||||
optSlot = finUpdate.attested_header.slot
|
|
||||||
contentKey = encode(finalityUpdateContentKey(finSlot.uint64, optSlot.uint64))
|
|
||||||
contentId = toContentId(contentKey)
|
|
||||||
content = encodeFinalityUpdateForked(
|
|
||||||
network.forkDigests.altair,
|
|
||||||
finUpdate
|
|
||||||
)
|
|
||||||
lcNetwork.portalProtocol.storeContent(
|
|
||||||
contentKey,
|
|
||||||
contentId,
|
|
||||||
content
|
|
||||||
)
|
|
||||||
|
|
||||||
lightClient.onFinalizedHeader = onFinalizedHeader
|
|
||||||
lightClient.onOptimisticHeader = onOptimisticHeader
|
|
||||||
lightClient.trustedBlockRoot = some config.trustedBlockRoot
|
|
||||||
lightClient.bootstrapObserver = onBootstrap
|
|
||||||
lightClient.updateObserver = onLCUpdate
|
|
||||||
lightClient.finalityUpdateObserver = onFinalityUpdate
|
|
||||||
lightClient.optimisticUpdateObserver = onOptimisticUpdate
|
|
||||||
|
|
||||||
proc onSecond(time: Moment) =
|
|
||||||
let wallSlot = getBeaconTime().slotOrZero()
|
|
||||||
lightClient.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())
|
|
||||||
|
|
||||||
lightClient.start()
|
|
||||||
|
|
||||||
asyncSpawn runOnSecondLoop()
|
|
||||||
|
|
||||||
while true:
|
|
||||||
poll()
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
run()
|
|
@ -1,162 +0,0 @@
|
|||||||
# beacon light client bridge
|
|
||||||
# Copyright (c) 2022-2023 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.
|
|
||||||
|
|
||||||
{.push raises: [].}
|
|
||||||
|
|
||||||
import
|
|
||||||
std/os,
|
|
||||||
json_serialization/std/net,
|
|
||||||
beacon_chain/light_client,
|
|
||||||
beacon_chain/conf
|
|
||||||
|
|
||||||
export net, conf
|
|
||||||
|
|
||||||
proc defaultBridgeDataDir*(): string =
|
|
||||||
let dataDir = when defined(windows):
|
|
||||||
"AppData" / "Roaming" / "BeaconLightClientBridge"
|
|
||||||
elif defined(macosx):
|
|
||||||
"Library" / "Application Support" / "BeaconLightClientBridge"
|
|
||||||
else:
|
|
||||||
".cache" / "beacon-ligh-client-bridge"
|
|
||||||
|
|
||||||
getHomeDir() / dataDir
|
|
||||||
|
|
||||||
const
|
|
||||||
defaultBridgeDataDirDesc* = defaultBridgeDataDir()
|
|
||||||
|
|
||||||
type BridgeConf* = object
|
|
||||||
# Config
|
|
||||||
configFile* {.
|
|
||||||
desc: "Loads the configuration from a TOML file"
|
|
||||||
name: "config-file" .}: Option[InputFile]
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
logLevel* {.
|
|
||||||
desc: "Sets the log level"
|
|
||||||
defaultValue: "INFO"
|
|
||||||
name: "log-level" .}: string
|
|
||||||
|
|
||||||
logStdout* {.
|
|
||||||
hidden
|
|
||||||
desc: "Specifies what kind of logs should be written to stdout (auto, colors, nocolors, json)"
|
|
||||||
defaultValueDesc: "auto"
|
|
||||||
defaultValue: StdoutLogKind.Auto
|
|
||||||
name: "log-format" .}: StdoutLogKind
|
|
||||||
|
|
||||||
# Storage
|
|
||||||
dataDir* {.
|
|
||||||
desc: "The directory where beacon light client bridge will store all data"
|
|
||||||
defaultValue: defaultBridgeDataDir()
|
|
||||||
defaultValueDesc: $defaultBridgeDataDirDesc
|
|
||||||
abbr: "d"
|
|
||||||
name: "data-dir" .}: OutDir
|
|
||||||
|
|
||||||
# Consensus light sync
|
|
||||||
# No default - Needs to be provided by the user
|
|
||||||
trustedBlockRoot* {.
|
|
||||||
desc: "Recent trusted finalized block root to initialize the consensus light client from"
|
|
||||||
name: "trusted-block-root" .}: Eth2Digest
|
|
||||||
|
|
||||||
# Libp2p
|
|
||||||
bootstrapNodes* {.
|
|
||||||
desc: "Specifies one or more bootstrap nodes to use when connecting to the network"
|
|
||||||
abbr: "b"
|
|
||||||
name: "bootstrap-node" .}: seq[string]
|
|
||||||
|
|
||||||
bootstrapNodesFile* {.
|
|
||||||
desc: "Specifies a line-delimited file of bootstrap Ethereum network addresses"
|
|
||||||
defaultValue: ""
|
|
||||||
name: "bootstrap-file" .}: InputFile
|
|
||||||
|
|
||||||
listenAddress* {.
|
|
||||||
desc: "Listening address for the Ethereum LibP2P and Discovery v5 traffic"
|
|
||||||
defaultValue: defaultListenAddress
|
|
||||||
defaultValueDesc: $defaultListenAddressDesc
|
|
||||||
name: "listen-address" .}: ValidIpAddress
|
|
||||||
|
|
||||||
tcpPort* {.
|
|
||||||
desc: "Listening TCP port for Ethereum LibP2P traffic"
|
|
||||||
defaultValue: defaultEth2TcpPort
|
|
||||||
defaultValueDesc: $defaultEth2TcpPortDesc
|
|
||||||
name: "tcp-port" .}: Port
|
|
||||||
|
|
||||||
udpPort* {.
|
|
||||||
desc: "Listening UDP port for node discovery"
|
|
||||||
defaultValue: defaultEth2TcpPort
|
|
||||||
defaultValueDesc: $defaultEth2TcpPortDesc
|
|
||||||
name: "udp-port" .}: Port
|
|
||||||
|
|
||||||
# TODO: Select a lower amount of peers.
|
|
||||||
maxPeers* {.
|
|
||||||
desc: "The target number of peers to connect to"
|
|
||||||
defaultValue: 160 # 5 (fanout) * 64 (subnets) / 2 (subs) for a healthy mesh
|
|
||||||
name: "max-peers" .}: int
|
|
||||||
|
|
||||||
hardMaxPeers* {.
|
|
||||||
desc: "The maximum number of peers to connect to. Defaults to maxPeers * 1.5"
|
|
||||||
name: "hard-max-peers" .}: Option[int]
|
|
||||||
|
|
||||||
nat* {.
|
|
||||||
desc: "Specify method to use for determining public address. " &
|
|
||||||
"Must be one of: any, none, upnp, pmp, extip:<IP>"
|
|
||||||
defaultValue: NatConfig(hasExtIp: false, nat: NatAny)
|
|
||||||
defaultValueDesc: "any"
|
|
||||||
name: "nat" .}: NatConfig
|
|
||||||
|
|
||||||
enrAutoUpdate* {.
|
|
||||||
desc: "Discovery can automatically update its ENR with the IP address " &
|
|
||||||
"and UDP port as seen by other nodes it communicates with. " &
|
|
||||||
"This option allows to enable/disable this functionality"
|
|
||||||
defaultValue: false
|
|
||||||
name: "enr-auto-update" .}: bool
|
|
||||||
|
|
||||||
agentString* {.
|
|
||||||
defaultValue: "nimbus",
|
|
||||||
desc: "Node agent string which is used as identifier in the LibP2P network"
|
|
||||||
name: "agent-string" .}: string
|
|
||||||
|
|
||||||
discv5Enabled* {.
|
|
||||||
desc: "Enable Discovery v5"
|
|
||||||
defaultValue: true
|
|
||||||
name: "discv5" .}: bool
|
|
||||||
|
|
||||||
directPeers* {.
|
|
||||||
desc: "The list of priviledged, secure and known peers to connect and" &
|
|
||||||
"maintain the connection to, this requires a not random netkey-file." &
|
|
||||||
"In the complete multiaddress format like:" &
|
|
||||||
"/ip4/<address>/tcp/<port>/p2p/<peerId-public-key>." &
|
|
||||||
"Peering agreements are established out of band and must be reciprocal"
|
|
||||||
name: "direct-peer" .}: seq[string]
|
|
||||||
|
|
||||||
|
|
||||||
func asLightClientConf*(pc: BridgeConf): LightClientConf =
|
|
||||||
return LightClientConf(
|
|
||||||
configFile: pc.configFile,
|
|
||||||
logLevel: pc.logLevel,
|
|
||||||
logStdout: pc.logStdout,
|
|
||||||
logFile: none(OutFile),
|
|
||||||
dataDir: pc.dataDir,
|
|
||||||
# Portal networks are defined only over mainnet therefore bridging makes
|
|
||||||
# sense only for mainnet
|
|
||||||
eth2Network: some("mainnet"),
|
|
||||||
bootstrapNodes: pc.bootstrapNodes,
|
|
||||||
bootstrapNodesFile: pc.bootstrapNodesFile,
|
|
||||||
listenAddress: pc.listenAddress,
|
|
||||||
tcpPort: pc.tcpPort,
|
|
||||||
udpPort: pc.udpPort,
|
|
||||||
maxPeers: pc.maxPeers,
|
|
||||||
hardMaxPeers: pc.hardMaxPeers,
|
|
||||||
nat: pc.nat,
|
|
||||||
enrAutoUpdate: pc.enrAutoUpdate,
|
|
||||||
agentString: pc.agentString,
|
|
||||||
discv5Enabled: pc.discv5Enabled,
|
|
||||||
directPeers: pc.directPeers,
|
|
||||||
trustedBlockRoot: pc.trustedBlockRoot,
|
|
||||||
web3Urls: @[],
|
|
||||||
jwtSecret: none(string),
|
|
||||||
stopAtEpoch: 0
|
|
||||||
)
|
|
@ -82,6 +82,7 @@ import
|
|||||||
libp2p/protocols/pubsub/errors,
|
libp2p/protocols/pubsub/errors,
|
||||||
../../rpc/portal_rpc_client,
|
../../rpc/portal_rpc_client,
|
||||||
../../network/history/history_content,
|
../../network/history/history_content,
|
||||||
|
../../network/beacon_light_client/beacon_light_client_content,
|
||||||
../../common/common_types,
|
../../common/common_types,
|
||||||
./beacon_chain_bridge_conf
|
./beacon_chain_bridge_conf
|
||||||
|
|
||||||
@ -157,6 +158,10 @@ proc asPortalBlockData*(
|
|||||||
|
|
||||||
(hash, headerWithProof, body)
|
(hash, headerWithProof, body)
|
||||||
|
|
||||||
|
func forkDigestAtEpoch(
|
||||||
|
forkDigests: ForkDigests, epoch: Epoch, cfg: RuntimeConfig): ForkDigest =
|
||||||
|
forkDigests.atEpoch(epoch, cfg)
|
||||||
|
|
||||||
proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
||||||
# Required as both Eth2Node and LightClient requires correct config type
|
# Required as both Eth2Node and LightClient requires correct config type
|
||||||
var lcConfig = config.asLightClientConf()
|
var lcConfig = config.asLightClientConf()
|
||||||
@ -225,12 +230,12 @@ proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
|||||||
blockhash = history_content.`$`hash
|
blockhash = history_content.`$`hash
|
||||||
|
|
||||||
block: # gossip header
|
block: # gossip header
|
||||||
let contentKey = ContentKey.init(blockHeader, hash)
|
let contentKey = history_content.ContentKey.init(blockHeader, hash)
|
||||||
let encodedContentKey = contentKey.encode.asSeq()
|
let encodedContentKey = contentKey.encode.asSeq()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let peers = await rpcHttpclient.portal_historyGossip(
|
let peers = await rpcHttpclient.portal_historyGossip(
|
||||||
encodedContentKey.toHex(),
|
toHex(encodedContentKey),
|
||||||
SSZ.encode(headerWithProof).toHex())
|
SSZ.encode(headerWithProof).toHex())
|
||||||
info "Block header gossiped", peers,
|
info "Block header gossiped", peers,
|
||||||
contentKey = encodedContentKey.toHex()
|
contentKey = encodedContentKey.toHex()
|
||||||
@ -245,7 +250,7 @@ proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
|||||||
await sleepAsync(1.seconds)
|
await sleepAsync(1.seconds)
|
||||||
|
|
||||||
block: # gossip block
|
block: # gossip block
|
||||||
let contentKey = ContentKey.init(blockBody, hash)
|
let contentKey = history_content.ContentKey.init(blockBody, hash)
|
||||||
let encodedContentKey = contentKey.encode.asSeq()
|
let encodedContentKey = contentKey.encode.asSeq()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -267,6 +272,148 @@ proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
|||||||
network, rng, lcConfig, cfg, forkDigests, getBeaconTime,
|
network, rng, lcConfig, cfg, forkDigests, getBeaconTime,
|
||||||
genesis_validators_root, LightClientFinalizationMode.Optimistic)
|
genesis_validators_root, LightClientFinalizationMode.Optimistic)
|
||||||
|
|
||||||
|
### Beacon Light Client content bridging specific callbacks
|
||||||
|
proc onBootstrap(
|
||||||
|
lightClient: LightClient,
|
||||||
|
bootstrap: ForkedLightClientBootstrap) =
|
||||||
|
withForkyObject(bootstrap):
|
||||||
|
when lcDataFork > LightClientDataFork.None:
|
||||||
|
info "New Beacon LC bootstrap",
|
||||||
|
forkyObject, slot = forkyObject.header.beacon.slot
|
||||||
|
|
||||||
|
let
|
||||||
|
root = hash_tree_root(forkyObject.header)
|
||||||
|
contentKey = encode(bootstrapContentKey(root))
|
||||||
|
contentId = beacon_light_client_content.toContentId(contentKey)
|
||||||
|
forkDigest = forkDigestAtEpoch(
|
||||||
|
forkDigests[], epoch(forkyObject.header.beacon.slot), cfg)
|
||||||
|
content = encodeBootstrapForked(
|
||||||
|
forkDigest,
|
||||||
|
bootstrap
|
||||||
|
)
|
||||||
|
|
||||||
|
proc GossipRpcAndClose() {.async.} =
|
||||||
|
try:
|
||||||
|
let
|
||||||
|
contentKeyHex = contentKey.asSeq().toHex()
|
||||||
|
peers = await rpcHttpclient.portal_beaconLightClientGossip(
|
||||||
|
contentKeyHex,
|
||||||
|
content.toHex())
|
||||||
|
info "Beacon LC bootstrap gossiped", peers,
|
||||||
|
contentKey = contentKeyHex
|
||||||
|
except CatchableError as e:
|
||||||
|
error "JSON-RPC error", error = $e.msg
|
||||||
|
|
||||||
|
await rpcHttpclient.close()
|
||||||
|
|
||||||
|
asyncSpawn(GossipRpcAndClose())
|
||||||
|
|
||||||
|
proc onUpdate(lightClient: LightClient, update: ForkedLightClientUpdate) =
|
||||||
|
withForkyObject(update):
|
||||||
|
when lcDataFork > LightClientDataFork.None:
|
||||||
|
info "New Beacon LC update",
|
||||||
|
update, slot = forkyObject.attested_header.beacon.slot
|
||||||
|
|
||||||
|
let
|
||||||
|
period = forkyObject.attested_header.beacon.slot.sync_committee_period
|
||||||
|
contentKey = encode(updateContentKey(period.uint64, uint64(1)))
|
||||||
|
contentId = beacon_light_client_content.toContentId(contentKey)
|
||||||
|
forkDigest = forkDigestAtEpoch(
|
||||||
|
forkDigests[], epoch(forkyObject.attested_header.beacon.slot), cfg)
|
||||||
|
content = encodeLightClientUpdatesForked(
|
||||||
|
forkDigest,
|
||||||
|
@[update]
|
||||||
|
)
|
||||||
|
|
||||||
|
proc GossipRpcAndClose() {.async.} =
|
||||||
|
try:
|
||||||
|
let
|
||||||
|
contentKeyHex = contentKey.asSeq().toHex()
|
||||||
|
peers = await rpcHttpclient.portal_beaconLightClientGossip(
|
||||||
|
contentKeyHex,
|
||||||
|
content.toHex())
|
||||||
|
info "Beacon LC bootstrap gossiped", peers,
|
||||||
|
contentKey = contentKeyHex
|
||||||
|
except CatchableError as e:
|
||||||
|
error "JSON-RPC error", error = $e.msg
|
||||||
|
|
||||||
|
await rpcHttpclient.close()
|
||||||
|
|
||||||
|
asyncSpawn(GossipRpcAndClose())
|
||||||
|
|
||||||
|
proc onOptimisticUpdate(
|
||||||
|
lightClient: LightClient,
|
||||||
|
update: ForkedLightClientOptimisticUpdate) =
|
||||||
|
withForkyObject(update):
|
||||||
|
when lcDataFork > LightClientDataFork.None:
|
||||||
|
info "New Beacon LC optimistic update",
|
||||||
|
update, slot = forkyObject.attested_header.beacon.slot
|
||||||
|
|
||||||
|
let
|
||||||
|
slot = forkyObject.attested_header.beacon.slot
|
||||||
|
contentKey = encode(optimisticUpdateContentKey(slot.uint64))
|
||||||
|
contentId = beacon_light_client_content.toContentId(contentKey)
|
||||||
|
forkDigest = forkDigestAtEpoch(
|
||||||
|
forkDigests[], epoch(forkyObject.attested_header.beacon.slot), cfg)
|
||||||
|
content = encodeOptimisticUpdateForked(
|
||||||
|
forkDigest,
|
||||||
|
update
|
||||||
|
)
|
||||||
|
|
||||||
|
proc GossipRpcAndClose() {.async.} =
|
||||||
|
try:
|
||||||
|
let
|
||||||
|
contentKeyHex = contentKey.asSeq().toHex()
|
||||||
|
peers = await rpcHttpclient.portal_beaconLightClientGossip(
|
||||||
|
contentKeyHex,
|
||||||
|
content.toHex())
|
||||||
|
info "Beacon LC bootstrap gossiped", peers,
|
||||||
|
contentKey = contentKeyHex
|
||||||
|
except CatchableError as e:
|
||||||
|
error "JSON-RPC error", error = $e.msg
|
||||||
|
|
||||||
|
await rpcHttpclient.close()
|
||||||
|
|
||||||
|
asyncSpawn(GossipRpcAndClose())
|
||||||
|
|
||||||
|
proc onFinalityUpdate(
|
||||||
|
lightClient: LightClient,
|
||||||
|
update: ForkedLightClientFinalityUpdate) =
|
||||||
|
withForkyObject(update):
|
||||||
|
when lcDataFork > LightClientDataFork.None:
|
||||||
|
info "New Beacon LC finality update",
|
||||||
|
update, slot = forkyObject.attested_header.beacon.slot
|
||||||
|
let
|
||||||
|
finalizedSlot = forkyObject.finalized_header.beacon.slot
|
||||||
|
optimisticSlot = forkyObject.attested_header.beacon.slot
|
||||||
|
contentKey = encode(finalityUpdateContentKey(
|
||||||
|
finalizedSlot.uint64, optimisticSlot.uint64))
|
||||||
|
contentId = beacon_light_client_content.toContentId(contentKey)
|
||||||
|
forkDigest = forkDigestAtEpoch(
|
||||||
|
forkDigests[], epoch(forkyObject.attested_header.beacon.slot), cfg)
|
||||||
|
content = encodeFinalityUpdateForked(
|
||||||
|
forkDigest,
|
||||||
|
update
|
||||||
|
)
|
||||||
|
|
||||||
|
proc GossipRpcAndClose() {.async.} =
|
||||||
|
try:
|
||||||
|
let
|
||||||
|
contentKeyHex = contentKey.asSeq().toHex()
|
||||||
|
peers = await rpcHttpclient.portal_beaconLightClientGossip(
|
||||||
|
contentKeyHex,
|
||||||
|
content.toHex())
|
||||||
|
info "Beacon LC bootstrap gossiped", peers,
|
||||||
|
contentKey = contentKeyHex
|
||||||
|
except CatchableError as e:
|
||||||
|
error "JSON-RPC error", error = $e.msg
|
||||||
|
|
||||||
|
await rpcHttpclient.close()
|
||||||
|
|
||||||
|
asyncSpawn(GossipRpcAndClose())
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
waitFor rpcHttpclient.connect(config.rpcAddress, Port(config.rpcPort), false)
|
waitFor rpcHttpclient.connect(config.rpcAddress, Port(config.rpcPort), false)
|
||||||
|
|
||||||
info "Listening to incoming network requests"
|
info "Listening to incoming network requests"
|
||||||
@ -310,6 +457,12 @@ proc run(config: BeaconBridgeConf) {.raises: [CatchableError].} =
|
|||||||
lightClient.onOptimisticHeader = onOptimisticHeader
|
lightClient.onOptimisticHeader = onOptimisticHeader
|
||||||
lightClient.trustedBlockRoot = some config.trustedBlockRoot
|
lightClient.trustedBlockRoot = some config.trustedBlockRoot
|
||||||
|
|
||||||
|
if config.beaconLightClient:
|
||||||
|
lightClient.bootstrapObserver = onBootstrap
|
||||||
|
lightClient.updateObserver = onUpdate
|
||||||
|
lightClient.finalityUpdateObserver = onFinalityUpdate
|
||||||
|
lightClient.optimisticUpdateObserver = onOptimisticUpdate
|
||||||
|
|
||||||
func shouldSyncOptimistically(wallSlot: Slot): bool =
|
func shouldSyncOptimistically(wallSlot: Slot): bool =
|
||||||
let optimisticHeader = lightClient.optimisticHeader
|
let optimisticHeader = lightClient.optimisticHeader
|
||||||
withForkyHeader(optimisticHeader):
|
withForkyHeader(optimisticHeader):
|
||||||
|
@ -18,11 +18,11 @@ export net, conf
|
|||||||
|
|
||||||
proc defaultVerifiedProxyDataDir*(): string =
|
proc defaultVerifiedProxyDataDir*(): string =
|
||||||
let dataDir = when defined(windows):
|
let dataDir = when defined(windows):
|
||||||
"AppData" / "Roaming" / "NimbusVerifiedProxy"
|
"AppData" / "Roaming" / "FluffyBeaconChainBridge"
|
||||||
elif defined(macosx):
|
elif defined(macosx):
|
||||||
"Library" / "Application Support" / "NimbusVerifiedProxy"
|
"Library" / "Application Support" / "FluffyBeaconChainBridge"
|
||||||
else:
|
else:
|
||||||
".cache" / "nimbus-verified-proxy"
|
".cache" / "fluffy-beacon-chain-bridge"
|
||||||
|
|
||||||
getHomeDir() / dataDir
|
getHomeDir() / dataDir
|
||||||
|
|
||||||
@ -64,6 +64,12 @@ type BeaconBridgeConf* = object
|
|||||||
abbr: "d"
|
abbr: "d"
|
||||||
name: "data-dir" .}: OutDir
|
name: "data-dir" .}: OutDir
|
||||||
|
|
||||||
|
# Bridge options
|
||||||
|
beaconLightClient* {.
|
||||||
|
desc: "Enable beacon light client content bridging"
|
||||||
|
defaultValue: false
|
||||||
|
name: "beacon-light-client" .}: bool
|
||||||
|
|
||||||
# Network
|
# Network
|
||||||
eth2Network* {.
|
eth2Network* {.
|
||||||
desc: "The Eth2 network to join"
|
desc: "The Eth2 network to join"
|
||||||
|
@ -74,9 +74,6 @@ task test_evm, "Run EVM tests":
|
|||||||
task fluffy, "Build fluffy":
|
task fluffy, "Build fluffy":
|
||||||
buildBinary "fluffy", "fluffy/", "-d:chronicles_log_level=TRACE -d:chronosStrictException -d:PREFER_BLST_SHA256=false"
|
buildBinary "fluffy", "fluffy/", "-d:chronicles_log_level=TRACE -d:chronosStrictException -d:PREFER_BLST_SHA256=false"
|
||||||
|
|
||||||
task lc_bridge, "Build light client bridge":
|
|
||||||
buildBinary "beacon_light_client_bridge", "fluffy/", "-d:chronicles_log_level=TRACE -d:chronosStrictException -d:PREFER_BLST_SHA256=false -d:libp2p_pki_schemes=secp256k1"
|
|
||||||
|
|
||||||
task fluffy_test, "Run fluffy tests":
|
task fluffy_test, "Run fluffy tests":
|
||||||
# Need the nimbus_db_backend in state network tests as we need a Hexary to
|
# Need the nimbus_db_backend in state network tests as we need a Hexary to
|
||||||
# start from, even though it only uses the MemoryDb.
|
# start from, even though it only uses the MemoryDb.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user