improve getStateField compile checks (#2889)

The current `getStateField` implementation fails at run-time when called
on a post-Altair state. This is improved by replacing the `if` structure
with a `case` expression, which is checked for exhaustive coverage at
compile time. Care is taken to preserve the `unsafeAddr` optimization.
This commit is contained in:
Etan Kissling 2021-09-22 22:06:50 +02:00 committed by GitHub
parent 4491259c52
commit c95d4f31ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 9 additions and 5 deletions

View File

@ -122,11 +122,15 @@ func assign*(tgt: var ForkedHashedBeaconState, src: ForkedHashedBeaconState) =
# with nimOldCaseObjects. This is infrequent.
tgt = src
macro getStateField*(s, y: untyped): untyped =
result = quote do:
(if `s`.beaconStateFork == forkPhase0:
unsafeAddr (`s`.hbsPhase0.data.`y`) else:
unsafeAddr (`s`.hbsAltair.data.`y`))[]
template getStateField*(x, y: untyped): untyped =
# The use of `unsafeAddr` avoids excessive copying in certain situations, e.g.,
# ```
# for index, validator in getStateField(stateData.data, validators).pairs():
# ```
# Without `unsafeAddr`, the `validators` list would be copied to a temporary variable.
(case x.beaconStateFork
of forkPhase0: unsafeAddr (x.hbsPhase0.data.y)
of forkAltair: unsafeAddr (x.hbsAltair.data.y))[]
template getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork: