Update spec types, use generics instead of static enums. TODO SSZ [skip CI]

This commit is contained in:
Mamy André-Ratsimbazafy 2020-12-22 10:57:33 +01:00
parent 7fde0a87d4
commit 0a0a304e8e
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
6 changed files with 141 additions and 138 deletions

View File

@ -250,7 +250,7 @@ proc initialize_beacon_state_from_eth1*(
Eth1Data(block_hash: eth1_block_hash, deposit_count: uint64(len(deposits))), Eth1Data(block_hash: eth1_block_hash, deposit_count: uint64(len(deposits))),
latest_block_header: latest_block_header:
BeaconBlockHeader( BeaconBlockHeader(
body_root: hash_tree_root(BeaconBlockBody( body_root: hash_tree_root(BeaconBlockBody[Unchecked](
# This differs from the spec intentionally. # This differs from the spec intentionally.
# We must specify the default value for `ValidatorSig` # We must specify the default value for `ValidatorSig`
# in order to get a correct `hash_tree_root`. # in order to get a correct `hash_tree_root`.
@ -321,19 +321,19 @@ proc initialize_hashed_beacon_state_from_eth1*(
preset, eth1_block_hash, eth1_timestamp, deposits, flags) preset, eth1_block_hash, eth1_timestamp, deposits, flags)
HashedBeaconState(data: genesisState[], root: hash_tree_root(genesisState[])) HashedBeaconState(data: genesisState[], root: hash_tree_root(genesisState[]))
func emptyBeaconBlockBody(): BeaconBlockBody = func emptyBeaconBlockBody(): BeaconBlockBody[Unchecked] =
# TODO: This shouldn't be necessary if OpaqueBlob is the default # TODO: This shouldn't be necessary if OpaqueBlob is the default
BeaconBlockBody(randao_reveal: ValidatorSig(kind: OpaqueBlob)) BeaconBlockBody[Unchecked](randao_reveal: ValidatorSig(kind: OpaqueBlob))
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#genesis-block # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#genesis-block
func get_initial_beacon_block*(state: BeaconState): SignedBeaconBlock = func get_initial_beacon_block*(state: BeaconState): SignedBeaconBlock[Unchecked] =
let message = BeaconBlock( let message = BeaconBlock[Unchecked](
slot: state.slot, slot: state.slot,
state_root: hash_tree_root(state), state_root: hash_tree_root(state),
body: emptyBeaconBlockBody()) body: emptyBeaconBlockBody())
# parent_root, randao_reveal, eth1_data, signature, and body automatically # parent_root, randao_reveal, eth1_data, signature, and body automatically
# initialized to default values. # initialized to default values.
SignedBeaconBlock(message: message, root: hash_tree_root(message)) SignedBeaconBlock[Unchecked](message: message, root: hash_tree_root(message))
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#get_block_root_at_slot # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: BeaconState, func get_block_root_at_slot*(state: BeaconState,
@ -430,7 +430,8 @@ proc process_registry_updates*(state: var BeaconState,
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#is_valid_indexed_attestation # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#is_valid_indexed_attestation
proc is_valid_indexed_attestation*( proc is_valid_indexed_attestation*(
state: BeaconState, indexed_attestation: SomeIndexedAttestation, state: BeaconState,
indexed_attestation: IndexedAttestation[Unchecked],
flags: UpdateFlags): Result[void, cstring] = flags: UpdateFlags): Result[void, cstring] =
## Check if ``indexed_attestation`` is not empty, has sorted and unique ## Check if ``indexed_attestation`` is not empty, has sorted and unique
## indices and has a valid aggregate signature. ## indices and has a valid aggregate signature.
@ -516,31 +517,15 @@ func get_attesting_indices*(state: BeaconState,
result.incl index result.incl index
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#get_indexed_attestation # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#get_indexed_attestation
func get_indexed_attestation(state: BeaconState, attestation: Attestation, func get_indexed_attestation[Trust](state: BeaconState, attestation: Attestation[Trust],
cache: var StateCache): IndexedAttestation = cache: var StateCache): IndexedAttestation[Trust] =
## Return the indexed attestation corresponding to ``attestation``. ## Return the indexed attestation corresponding to ``attestation``.
let let
attesting_indices = attesting_indices =
get_attesting_indices( get_attesting_indices(
state, attestation.data, attestation.aggregation_bits, cache) state, attestation.data, attestation.aggregation_bits, cache)
IndexedAttestation( IndexedAttestation[Trust](
attesting_indices:
List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE].init(
sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp)),
data: attestation.data,
signature: attestation.signature
)
func get_indexed_attestation(state: BeaconState, attestation: TrustedAttestation,
cache: var StateCache): TrustedIndexedAttestation =
## Return the indexed attestation corresponding to ``attestation``.
let
attesting_indices =
get_attesting_indices(
state, attestation.data, attestation.aggregation_bits, cache)
TrustedIndexedAttestation(
attesting_indices: attesting_indices:
List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE].init( List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE].init(
sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp)), sorted(mapIt(attesting_indices.toSeq, it.uint64), system.cmp)),
@ -592,7 +577,7 @@ func check_attestation_index(
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attestations # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attestations
proc check_attestation*( proc check_attestation*(
state: BeaconState, attestation: SomeAttestation, flags: UpdateFlags, state: BeaconState, attestation: Attestation, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] = cache: var StateCache): Result[void, cstring] =
## Check that an attestation follows the rules of being included in the state ## Check that an attestation follows the rules of being included in the state
## at the current slot. When acting as a proposer, the same rules need to ## at the current slot. When acting as a proposer, the same rules need to
@ -621,13 +606,13 @@ proc check_attestation*(
if not (data.source == state.previous_justified_checkpoint): if not (data.source == state.previous_justified_checkpoint):
return err("FFG data not matching previous justified epoch") return err("FFG data not matching previous justified epoch")
? is_valid_indexed_attestation( let idx_att = get_indexed_attestation(state, attestation, cache)
state, get_indexed_attestation(state, attestation, cache), flags) ? is_valid_indexed_attestation(state, idx_att, flags)
ok() ok()
proc process_attestation*( proc process_attestation*(
state: var BeaconState, attestation: SomeAttestation, flags: UpdateFlags, state: var BeaconState, attestation: Attestation, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] {.nbench.} = cache: var StateCache): Result[void, cstring] {.nbench.} =
# In the spec, attestation validation is mixed with state mutation, so here # In the spec, attestation validation is mixed with state mutation, so here
# we've split it into two functions so that the validation logic can be # we've split it into two functions so that the validation logic can be

View File

@ -78,6 +78,55 @@ const
template maxSize*(n: int) {.pragma.} template maxSize*(n: int) {.pragma.}
type type
# The trust level of a block, attestation or signature
#
# When we receive blocks from outside sources, they are untrusted and go
# through several layers of validation. Blocks that have gone through
# validations can be trusted to be well-formed, with a correct signature,
# having a parent and applying cleanly to the state that their parent
# left them with.
#
# When loading such blocks from the database, to rewind states for example,
# it is expensive to redo the validations (in particular, the signature
# checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
# checks can be skipped.
#
# docs/block_validation_flow.md
Unchecked* = object # Object hasn't gone through any verification
SigVerified* = object # Object cryptographic signature has been verified
TransitionVerified* = object # Object is valid according to the protocol state transition logic
Trusted* = object # Object is fully verified both cryptographically and logically
# We use dummy objects instead of static enum as static enum
# have cause issues with shortLog:
# - cannot use `auto`, need to use `tuple` as return value
# - overloading on Eth2Digest needed to be prefixed with the module digest.shortLog(_)
# They also required to reorder the type section.
# Generics are also better tested than static enums.
# TODO: we might want to compile with deduplication on
# as the C code will be the same but we will have 1 duplicate per trust level
# https://stackoverflow.com/questions/15168924/gcc-clang-merging-functions-with-identical-instructions-comdat-folding
# linker: --icf (identical COMDAT folding)
# GCC: -ffunction-sections
# Trust level aliases
# ---------------------------------------------------------------
TrustedSignedBeaconBlock* = SignedBeaconBlock[Trusted]
UntrustedSignedBeaconBlock* = SignedBeaconBlock[Unchecked] or
SignedBeaconBlock[SigVerified] or
SignedBeaconBlock[TransitionVerified]
TrustedBeaconBlock* = BeaconBlock[Trusted]
UntrustedBeaconBlock* = BeaconBlock[Unchecked] or
BeaconBlock[SigVerified] or
BeaconBlock[TransitionVerified]
TrustedIndexedAttestation* = IndexedAttestation[Trusted]
UntrustedIndexedAttestation* = IndexedAttestation[Unchecked] or
IndexedAttestation[SigVerified] or
IndexedAttestation[TransitionVerified]
# Domains # Domains
# --------------------------------------------------------------- # ---------------------------------------------------------------
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#domain-types # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#domain-types
@ -120,33 +169,29 @@ type
signed_header_2*: SignedBeaconBlockHeader signed_header_2*: SignedBeaconBlockHeader
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attesterslashing # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attesterslashing
AttesterSlashing* = object AttesterSlashing*[Trust] = object
attestation_1*: IndexedAttestation attestation_1*: IndexedAttestation[Trust]
attestation_2*: IndexedAttestation attestation_2*: IndexedAttestation[Trust]
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#indexedattestation # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#indexedattestation
IndexedAttestation* = object IndexedAttestation*[Trust] = object
attesting_indices*: List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE]
data*: AttestationData
signature*: ValidatorSig
TrustedIndexedAttestation* = object
attesting_indices*: List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE] attesting_indices*: List[uint64, Limit MAX_VALIDATORS_PER_COMMITTEE]
data*: AttestationData data*: AttestationData
when Trust is SigVerified|Trusted:
signature*: TrustedSig signature*: TrustedSig
else:
signature*: ValidatorSig
CommitteeValidatorsBits* = BitList[Limit MAX_VALIDATORS_PER_COMMITTEE] CommitteeValidatorsBits* = BitList[Limit MAX_VALIDATORS_PER_COMMITTEE]
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attestation # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attestation
Attestation* = object Attestation*[Trust] = object
aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData
signature*: ValidatorSig
TrustedAttestation* = object
aggregation_bits*: CommitteeValidatorsBits aggregation_bits*: CommitteeValidatorsBits
data*: AttestationData data*: AttestationData
when Trust is SigVerified|Trusted:
signature*: TrustedSig signature*: TrustedSig
else:
signature*: ValidatorSig
ForkDigest* = distinct array[4, byte] ForkDigest* = distinct array[4, byte]
@ -203,7 +248,7 @@ type
validator_index*: uint64 validator_index*: uint64
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblock # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object BeaconBlock*[Trust] = object
## For each slot, a proposer is chosen from the validator pool to propose ## For each slot, a proposer is chosen from the validator pool to propose
## a new block. Once the block as been proposed, it is transmitted to ## a new block. Once the block as been proposed, it is transmitted to
## validators that will have a chance to vote on it through attestations. ## validators that will have a chance to vote on it through attestations.
@ -219,30 +264,7 @@ type
state_root*: Eth2Digest ##\ state_root*: Eth2Digest ##\
## The state root, _after_ this block has been processed ## The state root, _after_ this block has been processed
body*: BeaconBlockBody body*: BeaconBlockBody[Trust]
TrustedBeaconBlock* = object
## When we receive blocks from outside sources, they are untrusted and go
## through several layers of validation. Blocks that have gone through
## validations can be trusted to be well-formed, with a correct signature,
## having a parent and applying cleanly to the state that their parent
## left them with.
##
## When loading such blocks from the database, to rewind states for example,
## it is expensive to redo the validations (in particular, the signature
## checks), thus `TrustedBlock` uses a `TrustedSig` type to mark that these
## checks can be skipped.
##
## TODO this could probably be solved with some type trickery, but there
## too many bugs in nim around generics handling, and we've used up
## the trickery budget in the serialization library already. Until
## then, the type must be manually kept compatible with its untrusted
## cousin.
slot*: Slot
proposer_index*: uint64
parent_root*: Eth2Digest ##\
state_root*: Eth2Digest ##\
body*: TrustedBeaconBlockBody
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblockheader # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblockheader
BeaconBlockHeader* = object BeaconBlockHeader* = object
@ -260,35 +282,20 @@ type
GraffitiBytes* = distinct array[MAX_GRAFFITI_SIZE, byte] GraffitiBytes* = distinct array[MAX_GRAFFITI_SIZE, byte]
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblockbody # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconblockbody
BeaconBlockBody* = object BeaconBlockBody*[Trust] = object
when Trust is SigVerified|Trusted:
randao_reveal*: TrustedSig
else:
randao_reveal*: ValidatorSig randao_reveal*: ValidatorSig
eth1_data*: Eth1Data eth1_data*: Eth1Data
graffiti*: GraffitiBytes graffiti*: GraffitiBytes
# Operations # Operations
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS] proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS] attester_slashings*: List[AttesterSlashing[Trust], Limit MAX_ATTESTER_SLASHINGS]
attestations*: List[Attestation, Limit MAX_ATTESTATIONS] attestations*: List[Attestation[Trust], Limit MAX_ATTESTATIONS]
deposits*: List[Deposit, Limit MAX_DEPOSITS] deposits*: List[Deposit, Limit MAX_DEPOSITS]
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS] # TODO: trust system?
TrustedBeaconBlockBody* = object
randao_reveal*: TrustedSig
eth1_data*: Eth1Data
graffiti*: GraffitiBytes
# Operations
proposer_slashings*: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]
attester_slashings*: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]
attestations*: List[TrustedAttestation, Limit MAX_ATTESTATIONS]
deposits*: List[Deposit, Limit MAX_DEPOSITS]
voluntary_exits*: List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]
SomeSignedBeaconBlock* = SignedBeaconBlock | TrustedSignedBeaconBlock
SomeBeaconBlock* = BeaconBlock | TrustedBeaconBlock
SomeBeaconBlockBody* = BeaconBlockBody | TrustedBeaconBlockBody
SomeAttestation* = Attestation | TrustedAttestation
SomeIndexedAttestation* = IndexedAttestation | TrustedIndexedAttestation
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconstate # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beaconstate
BeaconState* = object BeaconState* = object
@ -417,15 +424,12 @@ type
signature*: ValidatorSig signature*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#signedbeaconblock # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#signedbeaconblock
SignedBeaconBlock* = object SignedBeaconBlock*[Trust] = object
message*: BeaconBlock message*: BeaconBlock[Trust]
signature*: ValidatorSig when Trust is SigVerified|Trusted:
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
TrustedSignedBeaconBlock* = object
message*: TrustedBeaconBlock
signature*: TrustedSig signature*: TrustedSig
else:
signature*: ValidatorSig
root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block root* {.dontSerialize.}: Eth2Digest # cached root of signed beacon block
@ -437,7 +441,7 @@ type
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md#aggregateandproof # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md#aggregateandproof
AggregateAndProof* = object AggregateAndProof* = object
aggregator_index*: uint64 aggregator_index*: uint64
aggregate*: Attestation aggregate*: Attestation[Trusted]
selection_proof*: ValidatorSig selection_proof*: ValidatorSig
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md#signedaggregateandproof # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md#signedaggregateandproof
@ -667,7 +671,7 @@ func shortLog*(s: Slot): uint64 =
func shortLog*(e: Epoch): uint64 = func shortLog*(e: Epoch): uint64 =
e - GENESIS_EPOCH e - GENESIS_EPOCH
func shortLog*(v: SomeBeaconBlock): auto = func shortLog*(v: BeaconBlock): auto =
( (
slot: shortLog(v.slot), slot: shortLog(v.slot),
proposer_index: v.proposer_index, proposer_index: v.proposer_index,
@ -682,7 +686,7 @@ func shortLog*(v: SomeBeaconBlock): auto =
voluntary_exits_len: v.body.voluntary_exits.len(), voluntary_exits_len: v.body.voluntary_exits.len(),
) )
func shortLog*(v: SomeSignedBeaconBlock): auto = func shortLog*(v: SignedBeaconBlock): auto =
( (
blck: shortLog(v.message), blck: shortLog(v.message),
signature: shortLog(v.signature) signature: shortLog(v.signature)
@ -733,14 +737,14 @@ func shortLog*(v: PendingAttestation): auto =
proposer_index: v.proposer_index proposer_index: v.proposer_index
) )
func shortLog*(v: SomeAttestation): auto = func shortLog*(v: Attestation): auto =
( (
aggregation_bits: v.aggregation_bits, aggregation_bits: v.aggregation_bits,
data: shortLog(v.data), data: shortLog(v.data),
signature: shortLog(v.signature) signature: shortLog(v.signature)
) )
func shortLog*(v: SomeIndexedAttestation): auto = func shortLog*(v: IndexedAttestation): auto =
( (
attestating_indices: v.attesting_indices, attestating_indices: v.attesting_indices,
data: shortLog(v.data), data: shortLog(v.data),
@ -773,9 +777,15 @@ func shortLog*(v: SignedVoluntaryExit): auto =
chronicles.formatIt Slot: it.shortLog chronicles.formatIt Slot: it.shortLog
chronicles.formatIt Epoch: it.shortLog chronicles.formatIt Epoch: it.shortLog
chronicles.formatIt BeaconBlock: it.shortLog chronicles.formatIt BeaconBlock[Unchecked]: it.shortLog
chronicles.formatIt BeaconBlock[SigVerified]: it.shortLog
chronicles.formatIt BeaconBlock[TransitionVerified]: it.shortLog
chronicles.formatIt BeaconBlock[Trusted]: it.shortLog
chronicles.formatIt AttestationData: it.shortLog chronicles.formatIt AttestationData: it.shortLog
chronicles.formatIt Attestation: it.shortLog chronicles.formatIt Attestation[Unchecked]: it.shortLog
chronicles.formatIt Attestation[SigVerified]: it.shortLog
chronicles.formatIt Attestation[TransitionVerified]: it.shortLog
chronicles.formatIt Attestation[Trusted]: it.shortLog
chronicles.formatIt Checkpoint: it.shortLog chronicles.formatIt Checkpoint: it.shortLog
import json_serialization import json_serialization

View File

@ -90,7 +90,7 @@ func getAttestationTopic*(forkDigest: ForkDigest, subnetIndex: uint64):
raiseAssert e.msg raiseAssert e.msg
func getAttestationTopic*(forkDigest: ForkDigest, func getAttestationTopic*(forkDigest: ForkDigest,
attestation: Attestation, attestation: Attestation[Unchecked],
num_active_validators: uint64): string = num_active_validators: uint64): string =
getAttestationTopic( getAttestationTopic(
forkDigest, forkDigest,

View File

@ -84,7 +84,7 @@ func get_block_signature*(
proc verify_block_signature*( proc verify_block_signature*(
fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot, fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
blck: Eth2Digest | SomeBeaconBlock | BeaconBlockHeader, blck: Eth2Digest | BeaconBlock | BeaconBlockHeader,
pubkey: ValidatorPubKey, pubkey: ValidatorPubKey,
signature: SomeSig): bool = signature: SomeSig): bool =
withTrust(signature): withTrust(signature):

View File

@ -30,7 +30,7 @@ import
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc verify_block_signature*( proc verify_block_signature*(
state: BeaconState, signed_block: SomeSignedBeaconBlock): bool {.nbench.} = state: BeaconState, signed_block: SignedBeaconBlock): bool {.nbench.} =
let let
proposer_index = signed_block.message.proposer_index proposer_index = signed_block.message.proposer_index
if proposer_index >= state.validators.lenu64: if proposer_index >= state.validators.lenu64:
@ -49,7 +49,7 @@ proc verify_block_signature*(
true true
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc verifyStateRoot(state: BeaconState, blck: BeaconBlock): bool = proc verifyStateRoot(state: BeaconState, blck: UntrustedBeaconBlock): bool =
# This is inlined in state_transition(...) in spec. # This is inlined in state_transition(...) in spec.
let state_root = hash_tree_root(state) let state_root = hash_tree_root(state)
if state_root != blck.state_root: if state_root != blck.state_root:
@ -125,7 +125,7 @@ proc process_slots*(state: var HashedBeaconState, slot: Slot,
if slotProcessed notin updateFlags or state.data.slot != slot: if slotProcessed notin updateFlags or state.data.slot != slot:
notice( notice(
"Unusual request for a slot in the past", "Unusual request for a slot in the past",
state_root = shortLog(state.root), state_root = state.root,
current_slot = state.data.slot, current_slot = state.data.slot,
target_slot = slot target_slot = slot
) )
@ -142,7 +142,7 @@ proc noRollback*(state: var HashedBeaconState) =
proc state_transition*( proc state_transition*(
preset: RuntimePreset, preset: RuntimePreset,
state: var HashedBeaconState, signedBlock: SomeSignedBeaconBlock, state: var HashedBeaconState, signedBlock: SignedBeaconBlock,
stateCache: var StateCache, stateCache: var StateCache,
flags: UpdateFlags, rollback: RollbackHashedProc): bool {.nbench.} = flags: UpdateFlags, rollback: RollbackHashedProc): bool {.nbench.} =
## Time in the beacon chain moves by slots. Every time (haha.) that happens, ## Time in the beacon chain moves by slots. Every time (haha.) that happens,
@ -175,8 +175,8 @@ proc state_transition*(
verify_block_signature(state.data, signedBlock): verify_block_signature(state.data, signedBlock):
trace "state_transition: processing block, signature passed", trace "state_transition: processing block, signature passed",
signature = shortLog(signedBlock.signature), signature = signedBlock.signature,
blockRoot = shortLog(signedBlock.root) blockRoot = signedBlock.root
let res = process_block(preset, state.data, signedBlock.message, flags, stateCache) let res = process_block(preset, state.data, signedBlock.message, flags, stateCache)
if res.isOk: if res.isOk:
if skipStateRootValidation in flags or verifyStateRoot(state.data, signedBlock.message): if skipStateRootValidation in flags or verifyStateRoot(state.data, signedBlock.message):
@ -193,10 +193,10 @@ proc state_transition*(
return true return true
else: else:
debug "state_transition: process_block failed", debug "state_transition: process_block failed",
blck = shortLog(signedBlock.message), blck = signedBlock.message,
slot = state.data.slot, slot = state.data.slot,
eth1_deposit_index = state.data.eth1_deposit_index, eth1_deposit_index = state.data.eth1_deposit_index,
deposit_root = shortLog(state.data.eth1_data.deposit_root), deposit_root = state.data.eth1_data.deposit_root,
error = res.error error = res.error
# Block processing failed, roll back changes # Block processing failed, roll back changes
@ -213,13 +213,13 @@ proc makeBeaconBlock*(
randao_reveal: ValidatorSig, randao_reveal: ValidatorSig,
eth1_data: Eth1Data, eth1_data: Eth1Data,
graffiti: GraffitiBytes, graffiti: GraffitiBytes,
attestations: seq[Attestation], attestations: seq[Attestation[Unchecked]],
deposits: seq[Deposit], deposits: seq[Deposit],
proposerSlashings: seq[ProposerSlashing], proposerSlashings: seq[ProposerSlashing],
attesterSlashings: seq[AttesterSlashing], attesterSlashings: seq[AttesterSlashing[Unchecked]],
voluntaryExits: seq[SignedVoluntaryExit], voluntaryExits: seq[SignedVoluntaryExit],
rollback: RollbackHashedProc, rollback: RollbackHashedProc,
cache: var StateCache): Option[BeaconBlock] = cache: var StateCache): Option[BeaconBlock[Unchecked]] =
## Create a block for the given state. The last block applied to it must be ## Create a block for the given state. The last block applied to it must be
## the one identified by parent_root and process_slots must be called up to ## the one identified by parent_root and process_slots must be called up to
## the slot for which a block is to be created. ## the slot for which a block is to be created.
@ -227,31 +227,35 @@ proc makeBeaconBlock*(
# To create a block, we'll first apply a partial block to the state, skipping # To create a block, we'll first apply a partial block to the state, skipping
# some validations. # some validations.
var blck = BeaconBlock( # TODO: finish the code refactoring
# the result should be TransitionVerified
var blck = BeaconBlock[Unchecked](
slot: state.data.slot, slot: state.data.slot,
proposer_index: proposer_index.uint64, proposer_index: proposer_index.uint64,
parent_root: parent_root, parent_root: parent_root,
body: BeaconBlockBody( body: BeaconBlockBody[Unchecked](
randao_reveal: randao_reveal, randao_reveal: randao_reveal,
eth1_data: eth1data, eth1_data: eth1data,
graffiti: graffiti, graffiti: graffiti,
proposer_slashings: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]( proposer_slashings: List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS](
proposerSlashings), proposerSlashings),
attester_slashings: List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]( attester_slashings: List[AttesterSlashing[Unchecked], Limit MAX_ATTESTER_SLASHINGS](
attesterSlashings), attesterSlashings),
attestations: List[Attestation, Limit MAX_ATTESTATIONS](attestations), attestations: List[Attestation[Unchecked], Limit MAX_ATTESTATIONS](attestations),
deposits: List[Deposit, Limit MAX_DEPOSITS](deposits), deposits: List[Deposit, Limit MAX_DEPOSITS](deposits),
voluntary_exits: voluntary_exits:
List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS](voluntaryExits))) List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS](voluntaryExits)))
let res = process_block(preset, state.data, blck, {skipBlsValidation}, cache) let res = process_block(
preset, state.data, blck,
{skipBlsValidation}, cache)
if res.isErr: if res.isErr:
warn "Unable to apply new block to state", warn "Unable to apply new block to state",
blck = shortLog(blck), blck = blck,
slot = state.data.slot, slot = state.data.slot,
eth1_deposit_index = state.data.eth1_deposit_index, eth1_deposit_index = state.data.eth1_deposit_index,
deposit_root = shortLog(state.data.eth1_data.deposit_root), deposit_root = state.data.eth1_data.deposit_root,
error = res.error error = res.error
rollback(state) rollback(state)
return return

View File

@ -27,9 +27,11 @@ import
./signatures, ./presets, ./signatures, ./presets,
../../nbench/bench_lab ../../nbench/bench_lab
export sets # Generics visibility issue with toSeq(items(intersection(HashSet, HashSet)))
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#block-header # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#block-header
func process_block_header*( func process_block_header*(
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags, state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): Result[void, cstring] {.nbench.} = stateCache: var StateCache): Result[void, cstring] {.nbench.} =
# Verify that the slots match # Verify that the slots match
if not (blck.slot == state.slot): if not (blck.slot == state.slot):
@ -72,7 +74,7 @@ func `xor`[T: array](a, b: T): T =
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#randao # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#randao
proc process_randao( proc process_randao(
state: var BeaconState, body: SomeBeaconBlockBody, flags: UpdateFlags, state: var BeaconState, body: BeaconBlockBody, flags: UpdateFlags,
stateCache: var StateCache): bool {.nbench.} = stateCache: var StateCache): bool {.nbench.} =
let let
proposer_index = get_beacon_proposer_index(state, stateCache) proposer_index = get_beacon_proposer_index(state, stateCache)
@ -108,7 +110,7 @@ proc process_randao(
true true
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#eth1-data # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#eth1-data
func process_eth1_data(state: var BeaconState, body: SomeBeaconBlockBody) {.nbench.}= func process_eth1_data(state: var BeaconState, body: BeaconBlockBody) {.nbench.}=
state.eth1_data_votes.add body.eth1_data state.eth1_data_votes.add body.eth1_data
if state.eth1_data_votes.asSeq.count(body.eth1_data).uint64 * 2 > if state.eth1_data_votes.asSeq.count(body.eth1_data).uint64 * 2 >
@ -189,9 +191,9 @@ func is_slashable_attestation_data*(
data_2.target.epoch < data_1.target.epoch) data_2.target.epoch < data_1.target.epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attester-slashings # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#attester-slashings
proc check_attester_slashing*( proc check_attester_slashing*[Trust](
state: var BeaconState, state: var BeaconState,
attester_slashing: AttesterSlashing, attester_slashing: AttesterSlashing[Trust],
flags: UpdateFlags flags: UpdateFlags
): Result[seq[ValidatorIndex], cstring] {.nbench.} = ): Result[seq[ValidatorIndex], cstring] {.nbench.} =
let let
@ -210,6 +212,8 @@ proc check_attester_slashing*(
var slashed_indices: seq[ValidatorIndex] var slashed_indices: seq[ValidatorIndex]
# export sets otherwise
# generics visibility issue with toSeq(items(intersection(HashSet, HashSet)))
for index in sorted(toSeq(intersection( for index in sorted(toSeq(intersection(
toHashSet(attestation_1.attesting_indices.asSeq), toHashSet(attestation_1.attesting_indices.asSeq),
toHashSet(attestation_2.attesting_indices.asSeq)).items), system.cmp): toHashSet(attestation_2.attesting_indices.asSeq)).items), system.cmp):
@ -305,7 +309,7 @@ proc process_voluntary_exit*(
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#operations # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#operations
proc process_operations(preset: RuntimePreset, proc process_operations(preset: RuntimePreset,
state: var BeaconState, state: var BeaconState,
body: SomeBeaconBlockBody, body: BeaconBlockBody,
flags: UpdateFlags, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] {.nbench.} = cache: var StateCache): Result[void, cstring] {.nbench.} =
# Verify that outstanding deposits are processed up to the maximum number of # Verify that outstanding deposits are processed up to the maximum number of
@ -339,7 +343,7 @@ proc process_operations(preset: RuntimePreset,
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#block-processing # https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/beacon-chain.md#block-processing
proc process_block*( proc process_block*(
preset: RuntimePreset, preset: RuntimePreset,
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags, state: var BeaconState, blck: BeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): Result[void, cstring] {.nbench.}= stateCache: var StateCache): Result[void, cstring] {.nbench.}=
## When there's a new block, we need to verify that the block is sane and ## When there's a new block, we need to verify that the block is sane and
## update the state accordingly - the state is left in an unknown state when ## update the state accordingly - the state is left in an unknown state when