adopt Result[void, string] in place of some bool return signatures (#1275)

* adopt Result[void, string] in place of some bool return signatures

* string -> cstring to reduce memory allocations; ensure all err() strings are constants, with contextual information from higher-level callers

* logScope usage fixes

* homogenize err() reporting convention

* invalid signature in deposit isn't an error
This commit is contained in:
tersec 2020-07-03 17:03:14 +00:00 committed by GitHub
parent f06cc34406
commit a92276d510
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 123 additions and 140 deletions

View File

@ -50,8 +50,9 @@ func decrease_balance*(
state.balances[index] - delta state.balances[index] - delta
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#deposits # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#deposits
proc process_deposit*( func process_deposit*(
state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}): bool {.nbench.}= state: var BeaconState, deposit: Deposit, flags: UpdateFlags = {}):
Result[void, cstring] {.nbench.} =
# Process an Eth1 deposit, registering a validator or increasing its balance. # Process an Eth1 deposit, registering a validator or increasing its balance.
# Verify the Merkle branch # Verify the Merkle branch
@ -62,10 +63,7 @@ proc process_deposit*(
state.eth1_deposit_index, state.eth1_deposit_index,
state.eth1_data.deposit_root, state.eth1_data.deposit_root,
): ):
notice "Deposit Merkle validation failed", return err("process_deposit: deposit Merkle validation failed")
proof = deposit.proof, deposit_root = state.eth1_data.deposit_root,
deposit_index = state.eth1_deposit_index
return false
# Deposits must be processed in order # Deposits must be processed in order
state.eth1_deposit_index += 1 state.eth1_deposit_index += 1
@ -87,7 +85,7 @@ proc process_deposit*(
# large number of invalid deposits on Altona # large number of invalid deposits on Altona
trace "Skipping deposit with invalid signature", trace "Skipping deposit with invalid signature",
deposit = shortLog(deposit.data) deposit = shortLog(deposit.data)
return true return ok()
# Add validator and balance entries # Add validator and balance entries
state.validators.add(Validator( state.validators.add(Validator(
@ -105,7 +103,7 @@ proc process_deposit*(
# Increase balance by deposit amount # Increase balance by deposit amount
increase_balance(state, index.ValidatorIndex, amount) increase_balance(state, index.ValidatorIndex, amount)
true ok()
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#compute_activation_exit_epoch # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#compute_activation_exit_epoch
func compute_activation_exit_epoch(epoch: Epoch): Epoch = func compute_activation_exit_epoch(epoch: Epoch): Epoch =
@ -636,7 +634,7 @@ proc check_attestation*(
proc process_attestation*( proc process_attestation*(
state: var BeaconState, attestation: SomeAttestation, flags: UpdateFlags, state: var BeaconState, attestation: SomeAttestation, flags: UpdateFlags,
stateCache: var StateCache): bool {.nbench.}= stateCache: 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
# reused when looking for suitable blocks to include in attestations. # reused when looking for suitable blocks to include in attestations.
@ -645,8 +643,7 @@ proc process_attestation*(
let proposer_index = get_beacon_proposer_index(state, stateCache) let proposer_index = get_beacon_proposer_index(state, stateCache)
if proposer_index.isNone: if proposer_index.isNone:
debug "No beacon proposer index and probably no active validators" return err("process_attestation: no beacon proposer index and probably no active validators")
return false
if check_attestation(state, attestation, flags, stateCache): if check_attestation(state, attestation, flags, stateCache):
let let
@ -673,13 +670,9 @@ proc process_attestation*(
state, attestation.data, attestation.aggregation_bits, stateCache).len state, attestation.data, attestation.aggregation_bits, stateCache).len
state.previous_epoch_attestations.add(pending_attestation) state.previous_epoch_attestations.add(pending_attestation)
true ok()
else: else:
trace "process_attestation: check_attestation failed", err("process_attestation: check_attestation failed")
attestation = shortLog(attestation),
indices = get_attesting_indices(
state, attestation.data, attestation.aggregation_bits, stateCache).len
false
func makeAttestationData*( func makeAttestationData*(
state: BeaconState, slot: Slot, committee_index: uint64, state: BeaconState, slot: Slot, committee_index: uint64,

View File

@ -21,8 +21,6 @@
# spec does so also. # spec does so also.
# * For indices, we get a mix of uint64, ValidatorIndex and int - this is currently # * For indices, we get a mix of uint64, ValidatorIndex and int - this is currently
# swept under the rug with casts # swept under the rug with casts
# * Sane error handling is missing in most cases (yay, we'll get the chance to
# debate exceptions again!)
# When updating the code, add TODO sections to mark where there are clear # When updating the code, add TODO sections to mark where there are clear
# improvements to be made - other than that, keep things similar to spec for # improvements to be made - other than that, keep things similar to spec for
# now. # now.
@ -43,39 +41,28 @@ declareGauge beacon_pending_deposits, "Number of pending deposits (state.eth1_da
declareGauge beacon_processed_deposits_total, "Number of total deposits included on chain" # On block declareGauge beacon_processed_deposits_total, "Number of total deposits included on chain" # On block
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#block-header # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#block-header
proc process_block_header*( func process_block_header*(
state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags, state: var BeaconState, blck: SomeBeaconBlock, flags: UpdateFlags,
stateCache: var StateCache): bool {.nbench.} = stateCache: var StateCache): Result[void, cstring] {.nbench.} =
logScope:
blck = shortLog(blck)
# Verify that the slots match # Verify that the slots match
if not (blck.slot == state.slot): if not (blck.slot == state.slot):
notice "Block header: slot mismatch", return err("process_block_header: slot mismatch")
state_slot = shortLog(state.slot)
return false
# Verify that the block is newer than latest block header # Verify that the block is newer than latest block header
if not (blck.slot > state.latest_block_header.slot): if not (blck.slot > state.latest_block_header.slot):
debug "Block header: block not newer than latest block header" return err("process_block_header: block not newer than latest block header")
return false
# Verify that proposer index is the correct index # Verify that proposer index is the correct index
let proposer_index = get_beacon_proposer_index(state, stateCache) let proposer_index = get_beacon_proposer_index(state, stateCache)
if proposer_index.isNone: if proposer_index.isNone:
debug "Block header: proposer missing" return err("process_block_header: proposer missing")
return false
if not (blck.proposer_index.ValidatorIndex == proposer_index.get): if not (blck.proposer_index.ValidatorIndex == proposer_index.get):
notice "Block header: proposer index incorrect", return err("process_block_header: proposer index incorrect")
proposer_index = proposer_index.get
return false
# Verify that the parent matches # Verify that the parent matches
if not (blck.parent_root == hash_tree_root(state.latest_block_header)): if not (blck.parent_root == hash_tree_root(state.latest_block_header)):
notice "Block header: previous block root mismatch", return err("process_block_header: previous block root mismatch")
latest_block_header = state.latest_block_header,
latest_block_header_root = shortLog(hash_tree_root(state.latest_block_header))
return false
# Cache current block as the new latest block # Cache current block as the new latest block
state.latest_block_header = BeaconBlockHeader( state.latest_block_header = BeaconBlockHeader(
@ -89,12 +76,11 @@ proc process_block_header*(
# Verify proposer is not slashed # Verify proposer is not slashed
let proposer = state.validators[proposer_index.get] let proposer = state.validators[proposer_index.get]
if proposer.slashed: if proposer.slashed:
notice "Block header: proposer slashed" return err("process_block_header: proposer slashed")
return false
true ok()
proc `xor`[T: array](a, b: T): T = func `xor`[T: array](a, b: T): T =
for i in 0..<result.len: for i in 0..<result.len:
result[i] = a[i] xor b[i] result[i] = a[i] xor b[i]
@ -152,7 +138,8 @@ func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#proposer-slashings # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#proposer-slashings
proc process_proposer_slashing*( proc process_proposer_slashing*(
state: var BeaconState, proposer_slashing: ProposerSlashing, state: var BeaconState, proposer_slashing: ProposerSlashing,
flags: UpdateFlags, stateCache: var StateCache): bool {.nbench.}= flags: UpdateFlags, stateCache: var StateCache):
Result[void, cstring] {.nbench.} =
let let
header_1 = proposer_slashing.signed_header_1.message header_1 = proposer_slashing.signed_header_1.message
@ -160,29 +147,24 @@ proc process_proposer_slashing*(
# Not from spec # Not from spec
if header_1.proposer_index.int >= state.validators.len: if header_1.proposer_index.int >= state.validators.len:
notice "Proposer slashing: invalid proposer index" return err("process_proposer_slashing: invalid proposer index")
return false
# Verify header slots match # Verify header slots match
if not (header_1.slot == header_2.slot): if not (header_1.slot == header_2.slot):
notice "Proposer slashing: slot mismatch" return err("process_proposer_slashing: slot mismatch")
return false
# Verify header proposer indices match # Verify header proposer indices match
if not (header_1.proposer_index == header_2.proposer_index): if not (header_1.proposer_index == header_2.proposer_index):
notice "Proposer slashing: proposer indices mismatch" return err("process_proposer_slashing: proposer indices mismatch")
return false
# Verify the headers are different # Verify the headers are different
if not (header_1 != header_2): if not (header_1 != header_2):
notice "Proposer slashing: headers not different" return err("process_proposer_slashing: headers not different")
return false
# Verify the proposer is slashable # Verify the proposer is slashable
let proposer = state.validators[header_1.proposer_index] let proposer = state.validators[header_1.proposer_index]
if not is_slashable_validator(proposer, get_current_epoch(state)): if not is_slashable_validator(proposer, get_current_epoch(state)):
notice "Proposer slashing: slashed proposer" return err("process_proposer_slashing: slashed proposer")
return false
# Verify signatures # Verify signatures
if skipBlsValidation notin flags: if skipBlsValidation notin flags:
@ -191,13 +173,11 @@ proc process_proposer_slashing*(
if not verify_block_signature( if not verify_block_signature(
state.fork, state.genesis_validators_root, signed_header.message.slot, state.fork, state.genesis_validators_root, signed_header.message.slot,
signed_header.message, proposer.pubkey, signed_header.signature): signed_header.message, proposer.pubkey, signed_header.signature):
notice "Proposer slashing: invalid signature", return err("process_proposer_slashing: invalid signature")
signature_index = i
return false
slashValidator(state, header_1.proposer_index.ValidatorIndex, stateCache) slashValidator(state, header_1.proposer_index.ValidatorIndex, stateCache)
true ok()
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#is_slashable_attestation_data # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#is_slashable_attestation_data
func is_slashable_attestation_data( func is_slashable_attestation_data(
@ -217,84 +197,72 @@ proc process_attester_slashing*(
attester_slashing: AttesterSlashing, attester_slashing: AttesterSlashing,
flags: UpdateFlags, flags: UpdateFlags,
stateCache: var StateCache stateCache: var StateCache
): bool {.nbench.}= ): Result[void, cstring] {.nbench.}=
let let
attestation_1 = attester_slashing.attestation_1 attestation_1 = attester_slashing.attestation_1
attestation_2 = attester_slashing.attestation_2 attestation_2 = attester_slashing.attestation_2
if not is_slashable_attestation_data( if not is_slashable_attestation_data(
attestation_1.data, attestation_2.data): attestation_1.data, attestation_2.data):
notice "Attester slashing: surround or double vote check failed" return err("Attester slashing: surround or double vote check failed")
return false
if not is_valid_indexed_attestation(state, attestation_1, flags): if not is_valid_indexed_attestation(state, attestation_1, flags):
notice "Attester slashing: invalid attestation 1" return err("Attester slashing: invalid attestation 1")
return false
if not is_valid_indexed_attestation(state, attestation_2, flags): if not is_valid_indexed_attestation(state, attestation_2, flags):
notice "Attester slashing: invalid attestation 2" return err("Attester slashing: invalid attestation 2")
return false
var slashed_any = false var slashed_any = false
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):
if is_slashable_validator( if is_slashable_validator(
state.validators[index.int], get_current_epoch(state)): state.validators[index.int], get_current_epoch(state)):
slash_validator(state, index.ValidatorIndex, stateCache) slash_validator(state, index.ValidatorIndex, stateCache)
slashed_any = true slashed_any = true
if not slashed_any: if not slashed_any:
notice "Attester slashing: Trying to slash participant(s) twice" return err("Attester slashing: Trying to slash participant(s) twice")
return false ok()
return true
# https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/core/0_beacon-chain.md#voluntary-exits # https://github.com/ethereum/eth2.0-specs/blob/v0.9.4/specs/core/0_beacon-chain.md#voluntary-exits
proc process_voluntary_exit*( proc process_voluntary_exit*(
state: var BeaconState, state: var BeaconState,
signed_voluntary_exit: SignedVoluntaryExit, signed_voluntary_exit: SignedVoluntaryExit,
flags: UpdateFlags): bool {.nbench.}= flags: UpdateFlags): Result[void, cstring] {.nbench.} =
let voluntary_exit = signed_voluntary_exit.message let voluntary_exit = signed_voluntary_exit.message
# Not in spec. Check that validator_index is in range # Not in spec. Check that validator_index is in range
if voluntary_exit.validator_index >= state.validators.len.uint64: if voluntary_exit.validator_index >= state.validators.len.uint64:
notice "Exit: invalid validator index", return err("Exit: invalid validator index")
index = voluntary_exit.validator_index,
num_validators = state.validators.len
return false
let validator = state.validators[voluntary_exit.validator_index.int] let validator = state.validators[voluntary_exit.validator_index.int]
# Verify the validator is active # Verify the validator is active
if not is_active_validator(validator, get_current_epoch(state)): if not is_active_validator(validator, get_current_epoch(state)):
notice "Exit: validator not active" return err("Exit: validator not active")
return false
# Verify the validator has not yet exited # Verify the validator has not yet exited
if validator.exit_epoch != FAR_FUTURE_EPOCH: if validator.exit_epoch != FAR_FUTURE_EPOCH:
notice "Exit: validator has exited" return err("Exit: validator has exited")
return false
## Exits must specify an epoch when they become valid; they are not valid # Exits must specify an epoch when they become valid; they are not valid
## before then # before then
if not (get_current_epoch(state) >= voluntary_exit.epoch): if not (get_current_epoch(state) >= voluntary_exit.epoch):
notice "Exit: exit epoch not passed" return err("Exit: exit epoch not passed")
return false
# Verify the validator has been active long enough # Verify the validator has been active long enough
if not (get_current_epoch(state) >= validator.activation_epoch + if not (get_current_epoch(state) >= validator.activation_epoch +
SHARD_COMMITTEE_PERIOD): SHARD_COMMITTEE_PERIOD):
notice "Exit: not in validator set long enough" return err("Exit: not in validator set long enough")
return false
# Verify signature # Verify signature
if skipBlsValidation notin flags: if skipBlsValidation notin flags:
if not verify_voluntary_exit_signature( if not verify_voluntary_exit_signature(
state.fork, state.genesis_validators_root, voluntary_exit, state.fork, state.genesis_validators_root, voluntary_exit,
validator.pubkey, signed_voluntary_exit.signature): validator.pubkey, signed_voluntary_exit.signature):
notice "Exit: invalid signature" return err("Exit: invalid signature")
return false
# Initiate exit # Initiate exit
debug "Exit: processing voluntary exit (validator_leaving)", debug "Exit: processing voluntary exit (validator_leaving)",
@ -310,11 +278,12 @@ proc process_voluntary_exit*(
initiate_validator_exit( initiate_validator_exit(
state, voluntary_exit.validator_index.ValidatorIndex, cache) state, voluntary_exit.validator_index.ValidatorIndex, cache)
true ok()
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#operations # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#operations
proc process_operations(state: var BeaconState, body: SomeBeaconBlockBody, proc process_operations(state: var BeaconState, body: SomeBeaconBlockBody,
flags: UpdateFlags, stateCache: var StateCache): bool {.nbench.} = flags: UpdateFlags, stateCache: 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
# deposits # deposits
let let
@ -322,22 +291,19 @@ proc process_operations(state: var BeaconState, body: SomeBeaconBlockBody,
req_deposits = min(MAX_DEPOSITS, req_deposits = min(MAX_DEPOSITS,
state.eth1_data.deposit_count.int64 - state.eth1_deposit_index.int64) state.eth1_data.deposit_count.int64 - state.eth1_deposit_index.int64)
if not (num_deposits == req_deposits): if not (num_deposits == req_deposits):
notice "processOperations: incorrect number of deposits", return err("incorrect number of deposits")
num_deposits = num_deposits,
req_deposits = req_deposits,
deposit_count = state.eth1_data.deposit_count,
deposit_index = state.eth1_deposit_index
return false
template for_ops_cached(operations: auto, fn: auto) = template for_ops_cached(operations: auto, fn: auto) =
for operation in operations: for operation in operations:
if not fn(state, operation, flags, stateCache): let res = fn(state, operation, flags, stateCache)
return false if res.isErr:
return res
template for_ops(operations: auto, fn: auto) = template for_ops(operations: auto, fn: auto) =
for operation in operations: for operation in operations:
if not fn(state, operation, flags): let res = fn(state, operation, flags)
return false if res.isErr:
return res
for_ops_cached(body.proposer_slashings, process_proposer_slashing) for_ops_cached(body.proposer_slashings, process_proposer_slashing)
for_ops_cached(body.attester_slashings, process_attester_slashing) for_ops_cached(body.attester_slashings, process_attester_slashing)
@ -345,7 +311,7 @@ proc process_operations(state: var BeaconState, body: SomeBeaconBlockBody,
for_ops(body.deposits, process_deposit) for_ops(body.deposits, process_deposit)
for_ops(body.voluntary_exits, process_voluntary_exit) for_ops(body.voluntary_exits, process_voluntary_exit)
true ok()
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#block-processing # https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/beacon-chain.md#block-processing
proc process_block*( proc process_block*(
@ -371,8 +337,13 @@ proc process_block*(
beacon_previous_live_validators.set(toHashSet( beacon_previous_live_validators.set(toHashSet(
mapIt(state.previous_epoch_attestations, it.proposerIndex)).len.int64) mapIt(state.previous_epoch_attestations, it.proposerIndex)).len.int64)
if not process_block_header(state, blck, flags, stateCache): logScope:
notice "Block header not valid", slot = shortLog(state.slot) blck = shortLog(blck)
let res_block = process_block_header(state, blck, flags, stateCache)
if res_block.isErr:
debug "Block header not valid",
block_header_error = $(res_block.error),
slot = state.slot
return false return false
if not process_randao(state, blck.body, flags, stateCache): if not process_randao(state, blck.body, flags, stateCache):
@ -380,8 +351,14 @@ proc process_block*(
return false return false
process_eth1_data(state, blck.body) process_eth1_data(state, blck.body)
if not process_operations(state, blck.body, flags, stateCache):
# One could combine this and the default-true, but that's a bit implicit let res_ops = process_operations(state, blck.body, flags, stateCache)
if res_ops.isErr:
debug "process_operations encountered error",
operation_error = $(res_ops.error),
slot = state.slot,
eth1_deposit_index = state.eth1_deposit_index,
deposit_root = shortLog(state.eth1_data.deposit_root)
return false return false
true true

View File

@ -228,13 +228,13 @@ template processBlockScenarioImpl(
var consObj = parseSSZ(consObjPath, ConsensusObjectRefType) var consObj = parseSSZ(consObjPath, ConsensusObjectRefType)
when needFlags and needCache: when needFlags and needCache:
let success = transitionFn(state.data, consObj[], flags, cache) let success = transitionFn(state.data, consObj[], flags, cache).isOk
elif needFlags: elif needFlags:
let success = transitionFn(state.data, consObj[], flags) let success = transitionFn(state.data, consObj[], flags).isOk
elif needCache: elif needCache:
let success = transitionFn(state, consObj[], flags, cache) let success = transitionFn(state, consObj[], flags, cache).isOk
else: else:
let success = transitionFn(state, consObj[]) let success = transitionFn(state, consObj[]).isOk
echo astToStr(transitionFn) & " status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️" echo astToStr(transitionFn) & " status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️"

View File

@ -97,12 +97,12 @@ template decodeAndProcess(typ, process: untyped): bool =
proc nfuzz_attestation(input: openArray[byte], xoutput: ptr byte, proc nfuzz_attestation(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(AttestationInput): decodeAndProcess(AttestationInput):
process_attestation(data.state, data.attestation, flags, cache) process_attestation(data.state, data.attestation, flags, cache).isOk
proc nfuzz_attester_slashing(input: openArray[byte], xoutput: ptr byte, proc nfuzz_attester_slashing(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(AttesterSlashingInput): decodeAndProcess(AttesterSlashingInput):
process_attester_slashing(data.state, data.attesterSlashing, flags, cache) process_attester_slashing(data.state, data.attesterSlashing, flags, cache).isOk
proc nfuzz_block(input: openArray[byte], xoutput: ptr byte, proc nfuzz_block(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
@ -123,22 +123,22 @@ proc nfuzz_block(input: openArray[byte], xoutput: ptr byte,
proc nfuzz_block_header(input: openArray[byte], xoutput: ptr byte, proc nfuzz_block_header(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(BlockHeaderInput): decodeAndProcess(BlockHeaderInput):
process_block_header(data.state, data.beaconBlock.message, flags, cache) process_block_header(data.state, data.beaconBlock.message, flags, cache).isOk
proc nfuzz_deposit(input: openArray[byte], xoutput: ptr byte, proc nfuzz_deposit(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(DepositInput): decodeAndProcess(DepositInput):
process_deposit(data.state, data.deposit, flags) process_deposit(data.state, data.deposit, flags).isOk
proc nfuzz_proposer_slashing(input: openArray[byte], xoutput: ptr byte, proc nfuzz_proposer_slashing(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(ProposerSlashingInput): decodeAndProcess(ProposerSlashingInput):
process_proposer_slashing(data.state, data.proposerSlashing, flags, cache) process_proposer_slashing(data.state, data.proposerSlashing, flags, cache).isOk
proc nfuzz_voluntary_exit(input: openArray[byte], xoutput: ptr byte, proc nfuzz_voluntary_exit(input: openArray[byte], xoutput: ptr byte,
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} = xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
decodeAndProcess(VoluntaryExitInput): decodeAndProcess(VoluntaryExitInput):
process_voluntary_exit(data.state, data.exit, flags) process_voluntary_exit(data.state, data.exit, flags).isOk
# Note: Could also accept raw input pointer and access list_size + seed here. # Note: Could also accept raw input pointer and access list_size + seed here.
# However, list_size needs to be known also outside this proc to allocate xoutput. # However, list_size needs to be known also outside this proc to allocate xoutput.

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, beaconstate, validator], ../../beacon_chain/spec/[datatypes, beaconstate, validator],
../../beacon_chain/ssz, ../../beacon_chain/ssz,
@ -44,12 +46,12 @@ proc runTest(identifier: string) =
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState))
let done = process_attestation(preState[], attestation, {}, cache) let done = process_attestation(preState[], attestation, {}, cache).isOk
doAssert done, "Valid attestation not processed" doAssert done, "Valid attestation not processed"
check: preState[].hash_tree_root() == postState[].hash_tree_root() check: preState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
let done = process_attestation(preState[], attestation, {}, cache) let done = process_attestation(preState[], attestation, {}, cache).isOk
doAssert done == false, "We didn't expect this invalid attestation to be processed." doAssert done == false, "We didn't expect this invalid attestation to be processed."
`testImpl _ operations_attestations _ identifier`() `testImpl _ operations_attestations _ identifier`()

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, state_transition_block, validator], ../../beacon_chain/spec/[datatypes, state_transition_block, validator],
../../beacon_chain/ssz, ../../beacon_chain/ssz,
@ -45,13 +47,13 @@ proc runTest(identifier: string) =
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState))
let done = process_attester_slashing(preState[], attesterSlashing, let done = process_attester_slashing(preState[], attesterSlashing,
{}, cache) {}, cache).isOk
doAssert done, "Valid attestater slashing not processed" doAssert done, "Valid attestater slashing not processed"
check: preState[].hash_tree_root() == postState[].hash_tree_root() check: preState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
let done = process_attester_slashing(preState[], attesterSlashing, let done = process_attester_slashing(preState[], attesterSlashing,
{}, cache) {}, cache).isOk
doAssert done == false, "We didn't expect this invalid attester slashing to be processed." doAssert done == false, "We didn't expect this invalid attester slashing to be processed."
`testImpl _ operations_attester_slashing _ identifier`() `testImpl _ operations_attester_slashing _ identifier`()

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, state_transition_block, validator], ../../beacon_chain/spec/[datatypes, state_transition_block, validator],
../../beacon_chain/ssz, ../../beacon_chain/ssz,
@ -44,12 +46,12 @@ proc runTest(identifier: string) =
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState))
let done = process_block_header(preState[], blck, {}, cache) let done = process_block_header(preState[], blck, {}, cache).isOk
doAssert done, "Valid block header not processed" doAssert done, "Valid block header not processed"
check: preState[].hash_tree_root() == postState[].hash_tree_root() check: preState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
let done = process_block_header(preState[], blck, {}, cache) let done = process_block_header(preState[], blck, {}, cache).isOk
doAssert done == false, "We didn't expect this invalid block header to be processed." doAssert done == false, "We didn't expect this invalid block header to be processed."
`testImpl _ blockheader _ identifier`() `testImpl _ blockheader _ identifier`()

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, beaconstate], ../../beacon_chain/spec/[datatypes, beaconstate],
../../beacon_chain/[ssz, extras], ../../beacon_chain/[ssz, extras],
@ -48,7 +50,7 @@ proc runTest(identifier: string) =
discard process_deposit(preState[], deposit, flags) discard process_deposit(preState[], deposit, flags)
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
check not process_deposit(preState[], deposit, flags) check process_deposit(preState[], deposit, flags).isErr
`testImpl _ operations_deposits _ identifier`() `testImpl _ operations_deposits _ identifier`()

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, state_transition_block, validator], ../../beacon_chain/spec/[datatypes, state_transition_block, validator],
../../beacon_chain/ssz, ../../beacon_chain/ssz,
@ -44,12 +46,12 @@ proc runTest(identifier: string) =
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState))
let done = process_proposer_slashing(preState[], proposerSlashing, {}, cache) let done = process_proposer_slashing(preState[], proposerSlashing, {}, cache).isOk
doAssert done, "Valid proposer slashing not processed" doAssert done, "Valid proposer slashing not processed"
check: preState[].hash_tree_root() == postState[].hash_tree_root() check: preState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
let done = process_proposer_slashing(preState[], proposerSlashing, {}, cache) let done = process_proposer_slashing(preState[], proposerSlashing, {}, cache).isOk
doAssert done == false, "We didn't expect this invalid proposer slashing to be processed." doAssert done == false, "We didn't expect this invalid proposer slashing to be processed."
`testImpl_proposer_slashing _ identifier`() `testImpl_proposer_slashing _ identifier`()

View File

@ -10,6 +10,8 @@
import import
# Standard library # Standard library
os, unittest, os, unittest,
# Utilities
stew/results,
# Beacon chain internals # Beacon chain internals
../../beacon_chain/spec/[datatypes, state_transition_block], ../../beacon_chain/spec/[datatypes, state_transition_block],
../../beacon_chain/ssz, ../../beacon_chain/ssz,
@ -42,12 +44,12 @@ proc runTest(identifier: string) =
if existsFile(testDir/"post.ssz"): if existsFile(testDir/"post.ssz"):
let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz", SSZ, BeaconState))
let done = process_voluntary_exit(preState[], voluntaryExit, {}) let done = process_voluntary_exit(preState[], voluntaryExit, {}).isOk
doAssert done, "Valid voluntary exit not processed" doAssert done, "Valid voluntary exit not processed"
check: preState[].hash_tree_root() == postState[].hash_tree_root() check: preState[].hash_tree_root() == postState[].hash_tree_root()
reportDiff(preState, postState) reportDiff(preState, postState)
else: else:
let done = process_voluntary_exit(preState[], voluntaryExit, {}) let done = process_voluntary_exit(preState[], voluntaryExit, {}).isOk
doAssert done == false, "We didn't expect this invalid voluntary exit to be processed." doAssert done == false, "We didn't expect this invalid voluntary exit to be processed."
`testImpl _ voluntary_exit _ identifier`() `testImpl _ voluntary_exit _ identifier`()

View File

@ -14,6 +14,7 @@
import import
# Standard library # Standard library
unittest, unittest,
stew/results,
# Specs # Specs
../../beacon_chain/spec/[beaconstate, datatypes, helpers, validator], ../../beacon_chain/spec/[beaconstate, datatypes, helpers, validator],
# Mock helpers # Mock helpers
@ -50,7 +51,7 @@ suiteReport "[Unit - Spec - Block processing] Attestations " & preset():
var cache = get_empty_per_epoch_cache() var cache = get_empty_per_epoch_cache()
check process_attestation( check process_attestation(
state.data, attestation, flags = {}, cache state.data, attestation, flags = {}, cache
) ).isOk
# Check that the attestation was processed # Check that the attestation was processed
if attestation.data.target.epoch == get_current_epoch(state.data): if attestation.data.target.epoch == get_current_epoch(state.data):

View File

@ -55,7 +55,7 @@ suiteReport "[Unit - Spec - Block processing] Deposits " & preset():
# State transition # State transition
# ---------------------------------------- # ----------------------------------------
check: process_deposit(state.data, deposit, {skipBlsValidation}) check: process_deposit(state.data, deposit, {skipBlsValidation}).isOk
# Check invariants # Check invariants
# ---------------------------------------- # ----------------------------------------
@ -97,7 +97,7 @@ suiteReport "[Unit - Spec - Block processing] Deposits " & preset():
# State transition # State transition
# ---------------------------------------- # ----------------------------------------
check: process_deposit(state.data, deposit, {skipBlsValidation}) check: process_deposit(state.data, deposit, {skipBlsValidation}).isOk
# Check invariants # Check invariants
# ---------------------------------------- # ----------------------------------------