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. # with nimOldCaseObjects. This is infrequent.
tgt = src tgt = src
macro getStateField*(s, y: untyped): untyped = template getStateField*(x, y: untyped): untyped =
result = quote do: # The use of `unsafeAddr` avoids excessive copying in certain situations, e.g.,
(if `s`.beaconStateFork == forkPhase0: # ```
unsafeAddr (`s`.hbsPhase0.data.`y`) else: # for index, validator in getStateField(stateData.data, validators).pairs():
unsafeAddr (`s`.hbsAltair.data.`y`))[] # ```
# 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 = template getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork: case x.beaconStateFork: