nimbus-eth1/fluffy/network/beacon/beacon_light_client.nim

195 lines
6.2 KiB
Nim

# Nimbus - Portal Network
# Copyright (c) 2022-2024 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
chronicles,
eth/p2p/discoveryv5/random2,
beacon_chain/gossip_processing/light_client_processor,
beacon_chain/spec/datatypes/altair,
beacon_chain/beacon_clock,
"."/[beacon_init_loader, beacon_network, beacon_light_client_manager]
export LightClientFinalizationMode, beacon_network, beacon_light_client_manager
logScope:
topics = "beacon_lc"
type
LightClientHeaderCallback* = proc(
lightClient: LightClient, header: ForkedLightClientHeader
) {.gcsafe, raises: [].}
LightClient* = ref object
network*: BeaconNetwork
cfg: RuntimeConfig
forkDigests: ref ForkDigests
getBeaconTime*: GetBeaconTimeFn
store*: ref ForkedLightClientStore
processor*: ref LightClientProcessor
manager: LightClientManager
onFinalizedHeader*, onOptimisticHeader*: LightClientHeaderCallback
trustedBlockRoot*: Opt[Eth2Digest]
func getFinalizedHeader*(lightClient: LightClient): ForkedLightClientHeader =
withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork)
header.forky(lcDataFork) = forkyStore.finalized_header
header
else:
default(ForkedLightClientHeader)
func getOptimisticHeader*(lightClient: LightClient): ForkedLightClientHeader =
withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork)
header.forky(lcDataFork) = forkyStore.optimistic_header
header
else:
default(ForkedLightClientHeader)
proc new*(
T: type LightClient,
network: BeaconNetwork,
rng: ref HmacDrbgContext,
dumpEnabled: bool,
dumpDirInvalid, dumpDirIncoming: string,
cfg: RuntimeConfig,
forkDigests: ref ForkDigests,
getBeaconTime: GetBeaconTimeFn,
genesis_validators_root: Eth2Digest,
finalizationMode: LightClientFinalizationMode,
): T =
let lightClient = LightClient(
network: network,
cfg: cfg,
forkDigests: forkDigests,
getBeaconTime: getBeaconTime,
store: (ref ForkedLightClientStore)(),
)
func getTrustedBlockRoot(): Option[Eth2Digest] =
# TODO: use Opt in LC processor
if lightClient.trustedBlockRoot.isSome():
some(lightClient.trustedBlockRoot.value)
else:
none(Eth2Digest)
proc onStoreInitialized() =
discard
proc onFinalizedHeader() =
if lightClient.onFinalizedHeader != nil:
lightClient.onFinalizedHeader(lightClient, lightClient.getFinalizedHeader)
proc onOptimisticHeader() =
if lightClient.onOptimisticHeader != nil:
lightClient.onOptimisticHeader(lightClient, lightClient.getOptimisticHeader)
lightClient.processor = LightClientProcessor.new(
dumpEnabled, dumpDirInvalid, dumpDirIncoming, cfg, genesis_validators_root,
finalizationMode, lightClient.store, getBeaconTime, getTrustedBlockRoot,
onStoreInitialized, onFinalizedHeader, onOptimisticHeader,
)
proc lightClientVerifier(
obj: SomeForkedLightClientObject
): Future[Result[void, VerifierError]] {.
async: (raises: [CancelledError], raw: true)
.} =
let resfut = Future[Result[void, VerifierError]].Raising([CancelledError]).init(
"lightClientVerifier"
)
lightClient.processor[].addObject(MsgSource.gossip, obj, resfut)
resfut
proc bootstrapVerifier(obj: ForkedLightClientBootstrap): auto =
lightClientVerifier(obj)
proc updateVerifier(obj: ForkedLightClientUpdate): auto =
lightClientVerifier(obj)
proc finalityVerifier(obj: ForkedLightClientFinalityUpdate): auto =
lightClientVerifier(obj)
proc optimisticVerifier(obj: ForkedLightClientOptimisticUpdate): auto =
lightClientVerifier(obj)
func isLightClientStoreInitialized(): bool =
lightClient.store[].kind > LightClientDataFork.None
func isNextSyncCommitteeKnown(): bool =
withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None:
forkyStore.is_next_sync_committee_known
else:
false
func getFinalizedSlot(): Slot =
withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None:
forkyStore.finalized_header.beacon.slot
else:
GENESIS_SLOT
func getOptimisticSlot(): Slot =
withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None:
forkyStore.optimistic_header.beacon.slot
else:
GENESIS_SLOT
lightClient.manager = LightClientManager.init(
lightClient.network, rng, getTrustedBlockRoot, bootstrapVerifier, updateVerifier,
finalityVerifier, optimisticVerifier, isLightClientStoreInitialized,
isNextSyncCommitteeKnown, getFinalizedSlot, getOptimisticSlot, getBeaconTime,
)
lightClient
proc new*(
T: type LightClient,
network: BeaconNetwork,
rng: ref HmacDrbgContext,
networkData: NetworkInitData,
finalizationMode: LightClientFinalizationMode,
): T =
let
getBeaconTime = networkData.clock.getBeaconTimeFn()
forkDigests = newClone networkData.forks
LightClient.new(
network,
rng,
dumpEnabled = false,
dumpDirInvalid = ".",
dumpDirIncoming = ".",
networkData.metadata.cfg,
forkDigests,
getBeaconTime,
networkData.genesis_validators_root,
finalizationMode,
)
proc start*(lightClient: LightClient) =
info "Starting beacon light client", trusted_block_root = lightClient.trustedBlockRoot
lightClient.manager.start()
proc stop*(lightClient: LightClient) {.async: (raises: []).} =
info "Stopping beacon light client"
await lightClient.manager.stop()
proc resetToFinalizedHeader*(
lightClient: LightClient,
header: ForkedLightClientHeader,
current_sync_committee: altair.SyncCommittee,
) =
lightClient.processor[].resetToFinalizedHeader(header, current_sync_committee)