reduce redundant zero initialization for LC data objects (#5479)

Directly initialize `ForkedLightClientObj` instead of separately first
 setting the `kind` (initializing everything to zero) and then assigning
the forky data after that.
This commit is contained in:
Etan Kissling 2023-10-04 18:11:45 +02:00 committed by GitHub
parent 37967ba03b
commit 297c768816
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 91 additions and 106 deletions

View File

@ -504,10 +504,8 @@ proc getBestUpdate*(
withAll(LightClientDataFork): withAll(LightClientDataFork):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
if update[0] == ord(lcDataFork).int64: if update[0] == ord(lcDataFork).int64:
var obj = ForkedLightClientUpdate(kind: lcDataFork) return ForkedLightClientUpdate.init(SSZ.decode(
obj.forky(lcDataFork) = SSZ.decode( update[1], lcDataFork.LightClientUpdate))
update[1], lcDataFork.LightClientUpdate)
return obj
warn "Unsupported LC data store kind", store = "bestUpdates", warn "Unsupported LC data store kind", store = "bestUpdates",
period, kind = update[0] period, kind = update[0]
return default(ForkedLightClientUpdate) return default(ForkedLightClientUpdate)

View File

@ -175,8 +175,8 @@ proc updateLightClientFromDag*(node: BeaconNode) =
withBlck(bdata): withBlck(bdata):
const lcDataFork = lcDataForkAtConsensusFork(consensusFork) const lcDataFork = lcDataForkAtConsensusFork(consensusFork)
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
header = ForkedLightClientHeader(kind: lcDataFork) header = ForkedLightClientHeader.init(
header.forky(lcDataFork) = forkyBlck.toLightClientHeader(lcDataFork) forkyBlck.toLightClientHeader(lcDataFork))
else: raiseAssert "Unreachable" else: raiseAssert "Unreachable"
let current_sync_committee = block: let current_sync_committee = block:
let tmpState = assignClone(node.dag.headState) let tmpState = assignClone(node.dag.headState)

View File

@ -367,15 +367,16 @@ proc initLightClientUpdateForPeriod(
withStateAndBlck(updatedState, bdata): withStateAndBlck(updatedState, bdata):
when consensusFork >= ConsensusFork.Altair: when consensusFork >= ConsensusFork.Altair:
const lcDataFork = lcDataForkAtConsensusFork(consensusFork) const lcDataFork = lcDataForkAtConsensusFork(consensusFork)
update = ForkedLightClientUpdate(kind: lcDataFork) update = ForkedLightClientUpdate.init(lcDataFork.LightClientUpdate(
template forkyUpdate: untyped = update.forky(lcDataFork) attested_header: forkyBlck.toLightClientHeader(lcDataFork),
forkyUpdate.attested_header = forkyBlck.toLightClientHeader(lcDataFork) next_sync_committee: forkyState.data.next_sync_committee,
forkyUpdate.next_sync_committee = forkyState.data.next_sync_committee next_sync_committee_branch:
forkyUpdate.next_sync_committee_branch = forkyState.data.build_proof(altair.NEXT_SYNC_COMMITTEE_INDEX).get,
forkyState.data.build_proof(altair.NEXT_SYNC_COMMITTEE_INDEX).get finality_branch:
if finalizedBid.slot != FAR_FUTURE_SLOT: if finalizedBid.slot != FAR_FUTURE_SLOT:
forkyUpdate.finality_branch =
forkyState.data.build_proof(altair.FINALIZED_ROOT_INDEX).get forkyState.data.build_proof(altair.FINALIZED_ROOT_INDEX).get
else:
default(FinalityBranch)))
else: raiseAssert "Unreachable" else: raiseAssert "Unreachable"
do: do:
dag.handleUnexpectedLightClientError(attestedBid.slot) dag.handleUnexpectedLightClientError(attestedBid.slot)
@ -974,18 +975,16 @@ proc getLightClientBootstrap(
# Construct `LightClientBootstrap` from cached data # Construct `LightClientBootstrap` from cached data
const lcDataFork = typeof(header).kind const lcDataFork = typeof(header).kind
var bootstrap = ForkedLightClientBootstrap(kind: lcDataFork) ForkedLightClientBootstrap.init(lcDataFork.LightClientBootstrap(
template forkyBootstrap: untyped = bootstrap.forky(lcDataFork) header: header,
forkyBootstrap.header = header current_sync_committee: (block:
forkyBootstrap.current_sync_committee =
dag.lcDataStore.db.getSyncCommittee(period).valueOr: dag.lcDataStore.db.getSyncCommittee(period).valueOr:
debug "LC bootstrap unavailable: Sync committee not cached", period debug "LC bootstrap unavailable: Sync committee not cached", period
return default(ForkedLightClientBootstrap) return default(ForkedLightClientBootstrap)),
forkyBootstrap.current_sync_committee_branch = current_sync_committee_branch: (block:
dag.lcDataStore.db.getCurrentSyncCommitteeBranch(slot).valueOr: dag.lcDataStore.db.getCurrentSyncCommitteeBranch(slot).valueOr:
debug "LC bootstrap unavailable: Sync committee branch not cached", slot debug "LC bootstrap unavailable: Committee branch not cached", slot
return default(ForkedLightClientBootstrap) return default(ForkedLightClientBootstrap))))
bootstrap
proc getLightClientBootstrap*( proc getLightClientBootstrap*(
dag: ChainDAGRef, dag: ChainDAGRef,

View File

@ -230,8 +230,7 @@ proc processObject(
if initRes.isErr: if initRes.isErr:
err(initRes.error) err(initRes.error)
else: else:
self.store[] = ForkedLightClientStore(kind: lcDataFork) self.store[] = ForkedLightClientStore.init(initRes.get)
self.store[].forky(lcDataFork) = initRes.get
ok() ok()
elif forkyObject is SomeForkyLightClientUpdate: elif forkyObject is SomeForkyLightClientUpdate:
if self.store[].kind == LightClientDataFork.None: if self.store[].kind == LightClientDataFork.None:
@ -306,16 +305,12 @@ template withReportedProgress(
var var
oldFinalized = withForkyStore(self.store[]): oldFinalized = withForkyStore(self.store[]):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork) ForkedLightClientHeader.init(forkyStore.finalized_header)
header.forky(lcDataFork) = forkyStore.finalized_header
header
else: else:
default(ForkedLightClientHeader) default(ForkedLightClientHeader)
oldOptimistic = withForkyStore(self.store[]): oldOptimistic = withForkyStore(self.store[]):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork) ForkedLightClientHeader.init(forkyStore.optimistic_header)
header.forky(lcDataFork) = forkyStore.optimistic_header
header
else: else:
default(ForkedLightClientHeader) default(ForkedLightClientHeader)
@ -424,12 +419,11 @@ proc resetToFinalizedHeader*(
discard withReportedProgress: discard withReportedProgress:
withForkyHeader(header): withForkyHeader(header):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
self.store[] = ForkedLightClientStore(kind: lcDataFork) self.store[] = ForkedLightClientStore.init(lcDataFork.LightClientStore(
template forkyStore: untyped = self.store[].forky(lcDataFork)
forkyStore = lcDataFork.LightClientStore(
finalized_header: forkyHeader, finalized_header: forkyHeader,
current_sync_committee: current_sync_committee, current_sync_committee: current_sync_committee,
optimistic_header: forkyHeader) optimistic_header: forkyHeader))
template forkyStore: untyped = self.store[].forky(lcDataFork)
debug "LC reset to finalized header", debug "LC reset to finalized header",
finalizedSlot = forkyStore.finalized_header.beacon.slot, finalizedSlot = forkyStore.finalized_header.beacon.slot,
optimisticSlot = forkyStore.optimistic_header.beacon.slot optimisticSlot = forkyStore.optimistic_header.beacon.slot

View File

@ -56,9 +56,7 @@ func finalizedHeader*(
lightClient: LightClient): ForkedLightClientHeader = lightClient: LightClient): ForkedLightClientHeader =
withForkyStore(lightClient.store[]): withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork) ForkedLightClientHeader.init(forkyStore.finalized_header)
header.forky(lcDataFork) = forkyStore.finalized_header
header
else: else:
default(ForkedLightClientHeader) default(ForkedLightClientHeader)
@ -66,9 +64,7 @@ func optimisticHeader*(
lightClient: LightClient): ForkedLightClientHeader = lightClient: LightClient): ForkedLightClientHeader =
withForkyStore(lightClient.store[]): withForkyStore(lightClient.store[]):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var header = ForkedLightClientHeader(kind: lcDataFork) ForkedLightClientHeader.init(forkyStore.optimistic_header)
header.forky(lcDataFork) = forkyStore.optimistic_header
header
else: else:
default(ForkedLightClientHeader) default(ForkedLightClientHeader)
@ -294,9 +290,7 @@ proc installMessageValidators*(
(ValidationResult.Reject, cstring "Invalid context fork")) (ValidationResult.Reject, cstring "Invalid context fork"))
return ValidationResult.Reject return ValidationResult.Reject
const lcDataFork = T.kind let obj = T.Forked.init(msg)
var obj = T.Forked(kind: lcDataFork)
obj.forky(lcDataFork) = msg
var var
ignoreErrors {.noinit.}: array[2, ValidationError] ignoreErrors {.noinit.}: array[2, ValidationError]

View File

@ -152,10 +152,8 @@ proc getLatestFinalizedHeader*(
withAll(LightClientDataFork): withAll(LightClientDataFork):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
if header[0] == ord(lcDataFork).int64: if header[0] == ord(lcDataFork).int64:
var obj = ForkedLightClientHeader(kind: lcDataFork) return ForkedLightClientHeader.init(SSZ.decode(
obj.forky(lcDataFork) = SSZ.decode( header[1], lcDataFork.LightClientHeader))
header[1], lcDataFork.LightClientHeader)
return obj
warn "Unsupported LC store kind", store = "headers", warn "Unsupported LC store kind", store = "headers",
key, kind = header[0] key, kind = header[0]
return default(ForkedLightClientHeader) return default(ForkedLightClientHeader)

View File

@ -2108,13 +2108,12 @@ proc readValue*[T: SomeForkedLightClientObject](
withLcDataFork(lcDataForkAtConsensusFork(version.get)): withLcDataFork(lcDataForkAtConsensusFork(version.get)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
value = T(kind: lcDataFork)
try: try:
value.forky(lcDataFork) = RestJson.decode( value = T.init(RestJson.decode(
string(data.get()), string(data.get()),
T.Forky(lcDataFork), T.Forky(lcDataFork),
requireAllFields = true, requireAllFields = true,
allowUnknownFields = true) allowUnknownFields = true))
except SerializationError: except SerializationError:
reader.raiseUnexpectedValue("Incorrect format (" & $lcDataFork & ")") reader.raiseUnexpectedValue("Incorrect format (" & $lcDataFork & ")")
else: else:

View File

@ -46,8 +46,7 @@ func decodeSszLightClientObject[T: SomeForkedLightClientObject](
try: try:
withLcDataFork(lcDataForkAtConsensusFork(consensusFork)): withLcDataFork(lcDataForkAtConsensusFork(consensusFork)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var obj = T(kind: lcDataFork) var obj = T.init(SSZ.decode(data, T.Forky(lcDataFork)))
obj.forky(lcDataFork) = SSZ.decode(data, T.Forky(lcDataFork))
obj.checkForkConsistency(cfg, consensusFork) obj.checkForkConsistency(cfg, consensusFork)
obj obj
else: else:
@ -136,10 +135,9 @@ proc decodeSszLightClientObjects[S: seq[SomeForkedLightClientObject]](
withLcDataFork(lcDataForkAtConsensusFork(consensusFork)): withLcDataFork(lcDataForkAtConsensusFork(consensusFork)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
type T = typeof(res[0]) type T = typeof(res[0])
var obj = T(kind: lcDataFork) var obj = T.init(SSZ.decode(
obj.forky(lcDataFork) = SSZ.decode(
data.toOpenArray(begin + contextLen, after - 1), data.toOpenArray(begin + contextLen, after - 1),
T.Forky(lcDataFork)) T.Forky(lcDataFork)))
obj.checkForkConsistency(cfg, consensusFork) obj.checkForkConsistency(cfg, consensusFork)
res.add obj res.add obj
else: else:

View File

@ -461,6 +461,42 @@ template withForkyStore*(
const lcDataFork {.inject, used.} = LightClientDataFork.None const lcDataFork {.inject, used.} = LightClientDataFork.None
body body
func init*(
x: typedesc[
ForkedLightClientHeader |
SomeForkedLightClientObject |
ForkedLightClientStore],
forkyData:
ForkyLightClientHeader |
SomeForkyLightClientObject |
ForkyLightClientStore): auto =
type ResultType = typeof(forkyData).Forked
static: doAssert ResultType is x
const kind = typeof(forkyData).kind
when kind == LightClientDataFork.Deneb:
ResultType(kind: kind, denebData: forkyData)
elif kind == LightClientDataFork.Capella:
ResultType(kind: kind, capellaData: forkyData)
elif kind == LightClientDataFork.Altair:
ResultType(kind: kind, altairData: forkyData)
else:
static: raiseAssert "Unreachable"
template forky*(
x:
ForkedLightClientHeader |
SomeForkedLightClientObject |
ForkedLightClientStore,
kind: static LightClientDataFork): untyped =
when kind == LightClientDataFork.Deneb:
x.denebData
elif kind == LightClientDataFork.Capella:
x.capellaData
elif kind == LightClientDataFork.Altair:
x.altairData
else:
static: raiseAssert "Unreachable"
func toFull*( func toFull*(
update: SomeForkyLightClientUpdate): auto = update: SomeForkyLightClientUpdate): auto =
type ResultType = typeof(update).kind.LightClientUpdate type ResultType = typeof(update).kind.LightClientUpdate
@ -486,10 +522,7 @@ func toFull*(
else: else:
withForkyObject(update): withForkyObject(update):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var res = ForkedLightClientUpdate(kind: lcDataFork) ForkedLightClientUpdate.init(forkyObject.toFull())
template forkyRes: untyped = res.forky(lcDataFork)
forkyRes = forkyObject.toFull()
res
else: else:
default(ForkedLightClientUpdate) default(ForkedLightClientUpdate)
@ -518,10 +551,7 @@ func toFinality*(
else: else:
withForkyObject(update): withForkyObject(update):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var res = ForkedLightClientFinalityUpdate(kind: lcDataFork) ForkedLightClientFinalityUpdate.init(forkyObject.toFinality())
template forkyRes: untyped = res.forky(lcDataFork)
forkyRes = forkyObject.toFinality()
res
else: else:
default(ForkedLightClientFinalityUpdate) default(ForkedLightClientFinalityUpdate)
@ -543,10 +573,7 @@ func toOptimistic*(
else: else:
withForkyObject(update): withForkyObject(update):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
var res = ForkedLightClientOptimisticUpdate(kind: lcDataFork) ForkedLightClientOptimisticUpdate.init(forkyObject.toOptimistic())
template forkyRes: untyped = res.forky(lcDataFork)
forkyRes = forkyObject.toOptimistic()
res
else: else:
default(ForkedLightClientOptimisticUpdate) default(ForkedLightClientOptimisticUpdate)
@ -581,21 +608,6 @@ func matches*[A, B: SomeForkedLightClientUpdate](a: A, b: B): bool =
else: else:
true true
template forky*(
x:
ForkedLightClientHeader |
SomeForkedLightClientObject |
ForkedLightClientStore,
kind: static LightClientDataFork): untyped =
when kind == LightClientDataFork.Deneb:
x.denebData
elif kind == LightClientDataFork.Capella:
x.capellaData
elif kind == LightClientDataFork.Altair:
x.altairData
else:
static: raiseAssert "Unreachable"
func migrateToDataFork*( func migrateToDataFork*(
x: var ForkedLightClientHeader, x: var ForkedLightClientHeader,
newKind: static LightClientDataFork) = newKind: static LightClientDataFork) =

View File

@ -153,9 +153,7 @@ proc readChunkPayload*(
if contextFork != if contextFork !=
peer.network.cfg.consensusForkAtEpoch(res.get.contextEpoch): peer.network.cfg.consensusForkAtEpoch(res.get.contextEpoch):
return neterr InvalidContextBytes return neterr InvalidContextBytes
var obj = ok MsgType(kind: lcDataFork) return ok MsgType.init(res.get)
obj.get.forky(lcDataFork) = res.get
return obj
else: else:
return err(res.error) return err(res.error)
else: else:

View File

@ -220,8 +220,7 @@ proc doTrustedNodeSync*(
quit 1 quit 1
bootstrap.migrateToDataFork(lcDataFork) bootstrap.migrateToDataFork(lcDataFork)
var storeRes = var storeRes = initialize_light_client_store(
initialize_light_client_store(
trustedBlockRoot, bootstrap.forky(lcDataFork), cfg) trustedBlockRoot, bootstrap.forky(lcDataFork), cfg)
if storeRes.isErr: if storeRes.isErr:
error "`initialize_light_client_store` failed", err = storeRes.error error "`initialize_light_client_store` failed", err = storeRes.error

View File

@ -94,10 +94,9 @@ proc loadSteps(path: string, fork_digests: ForkDigests): seq[TestStep] =
var update {.noinit.}: ForkedLightClientUpdate var update {.noinit.}: ForkedLightClientUpdate
withLcDataFork(lcDataForkAtConsensusFork(update_consensus_fork)): withLcDataFork(lcDataForkAtConsensusFork(update_consensus_fork)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
update = ForkedLightClientUpdate(kind: lcDataFork) update = ForkedLightClientUpdate.init(parseTest(
update.forky(lcDataFork) = parseTest(
path/update_filename & ".ssz_snappy", SSZ, path/update_filename & ".ssz_snappy", SSZ,
lcDataFork.LightClientUpdate) lcDataFork.LightClientUpdate))
else: raiseAssert "Unreachable update fork " & $update_fork_digest else: raiseAssert "Unreachable update fork " & $update_fork_digest
result.add TestStep( result.add TestStep(
@ -177,10 +176,9 @@ proc runTest(suiteName, path: string) =
var bootstrap {.noinit.}: ForkedLightClientBootstrap var bootstrap {.noinit.}: ForkedLightClientBootstrap
withLcDataFork(lcDataForkAtConsensusFork(bootstrap_consensus_fork)): withLcDataFork(lcDataForkAtConsensusFork(bootstrap_consensus_fork)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
bootstrap = ForkedLightClientBootstrap(kind: lcDataFork) bootstrap = ForkedLightClientBootstrap.init(parseTest(
bootstrap.forky(lcDataFork) = parseTest(
path/"bootstrap.ssz_snappy", SSZ, path/"bootstrap.ssz_snappy", SSZ,
lcDataFork.LightClientBootstrap) lcDataFork.LightClientBootstrap))
else: else:
raiseAssert "Unknown bootstrap fork " & $meta.bootstrap_fork_digest raiseAssert "Unknown bootstrap fork " & $meta.bootstrap_fork_digest
bootstrap bootstrap
@ -194,10 +192,9 @@ proc runTest(suiteName, path: string) =
var store {.noinit.}: ForkedLightClientStore var store {.noinit.}: ForkedLightClientStore
withLcDataFork(lcDataForkAtConsensusFork(store_consensus_fork)): withLcDataFork(lcDataForkAtConsensusFork(store_consensus_fork)):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
store = ForkedLightClientStore(kind: lcDataFork)
bootstrap[].migrateToDataFork(lcDataFork) bootstrap[].migrateToDataFork(lcDataFork)
store.forky(lcDataFork) = initialize_light_client_store( store = ForkedLightClientStore.init(initialize_light_client_store(
meta.trusted_block_root, bootstrap[].forky(lcDataFork), cfg).get meta.trusted_block_root, bootstrap[].forky(lcDataFork), cfg).get)
else: raiseAssert "Unreachable store fork " & $meta.store_fork_digest else: raiseAssert "Unreachable store fork " & $meta.store_fork_digest
store store

View File

@ -148,8 +148,7 @@ suite "Light client" & preset():
var storeRes = newClone(initialize_light_client_store( var storeRes = newClone(initialize_light_client_store(
trusted_block_root, forkyBootstrap, cfg)) trusted_block_root, forkyBootstrap, cfg))
check storeRes[].isOk check storeRes[].isOk
store = (ref ForkedLightClientStore)(kind: lcDataFork)[] store = newClone(ForkedLightClientStore.init(storeRes[].get))[]
store.forky(lcDataFork) = storeRes[].get
# Sync to latest sync committee period # Sync to latest sync committee period
var numIterations = 0 var numIterations = 0

View File

@ -284,8 +284,8 @@ suite "Light client processor" & preset():
var oldFinalized {.noinit.}: ForkedLightClientHeader var oldFinalized {.noinit.}: ForkedLightClientHeader
withForkyStore(store[]): withForkyStore(store[]):
when lcDataFork > LightClientDataFork.None: when lcDataFork > LightClientDataFork.None:
oldFinalized = ForkedLightClientHeader(kind: lcDataFork) oldFinalized = ForkedLightClientHeader.init(
oldFinalized.forky(lcDataFork) = forkyStore.finalized_header forkyStore.finalized_header)
else: raiseAssert "Unreachable" else: raiseAssert "Unreachable"
let finalityUpdate = dag.getLightClientFinalityUpdate() let finalityUpdate = dag.getLightClientFinalityUpdate()
check finalityUpdate.kind > LightClientDataFork.None check finalityUpdate.kind > LightClientDataFork.None