From 5d42859176852a8c30b0700ec65494b4adb36a17 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 19 Mar 2024 14:22:07 +0100 Subject: [PATCH] make `Gwei` `distinct` (#6090) #6087 introduced a subtle change to `nim-web3` resulting in `Gwei` to be serialized differently than before. Using a `distinct` type for `Gwei` improves type safety and avoids such problems in the future. --- beacon_chain/beacon_chain_db_immutable.nim | 12 +- beacon_chain/beacon_node.nim | 2 +- beacon_chain/el/el_manager.nim | 2 +- beacon_chain/fork_choice/fork_choice.nim | 4 +- .../fork_choice/fork_choice_types.nim | 2 +- beacon_chain/nimbus_beacon_node.nim | 19 +-- beacon_chain/rpc/rest_beacon_api.nim | 4 +- beacon_chain/spec/beaconstate.nim | 56 ++++---- beacon_chain/spec/datatypes/base.nim | 33 +++-- beacon_chain/spec/datatypes/capella.nim | 2 +- .../eth2_apis/eth2_rest_serialization.nim | 10 ++ beacon_chain/spec/eth2_apis/rest_types.nim | 4 +- beacon_chain/spec/helpers.nim | 10 +- beacon_chain/spec/mev/capella_mev.nim | 2 +- beacon_chain/spec/ssz_codec.nim | 4 + beacon_chain/spec/state_transition_block.nim | 2 +- beacon_chain/spec/state_transition_epoch.nim | 133 ++++++++++-------- beacon_chain/spec/validator.nim | 2 +- beacon_chain/spec/weak_subjectivity.nim | 4 +- beacon_chain/validators/validator_monitor.nim | 4 +- ncli/ncli_common.nim | 9 +- ncli/validator_db_aggregator.nim | 14 +- research/wss_sim.nim | 2 +- .../altair/test_fixture_operations.nim | 6 +- .../altair/test_fixture_rewards.nim | 2 +- .../bellatrix/test_fixture_operations.nim | 6 +- .../bellatrix/test_fixture_rewards.nim | 2 +- .../capella/test_fixture_operations.nim | 6 +- .../capella/test_fixture_rewards.nim | 3 +- .../deneb/test_fixture_operations.nim | 6 +- .../deneb/test_fixture_rewards.nim | 2 +- tests/consensus_spec/fixtures_utils.nim | 4 +- .../phase0/test_fixture_operations.nim | 6 +- .../phase0/test_fixture_rewards.nim | 2 +- tests/helpers/math_helpers.nim | 12 -- tests/mocking/mock_deposits.nim | 37 ++--- tests/mocking/mock_genesis.nim | 2 +- tests/testblockutil.nim | 2 +- tests/teststateutil.nim | 15 +- 39 files changed, 246 insertions(+), 203 deletions(-) delete mode 100644 tests/helpers/math_helpers.nim diff --git a/beacon_chain/beacon_chain_db_immutable.nim b/beacon_chain/beacon_chain_db_immutable.nim index 3a3df18399..e663283943 100644 --- a/beacon_chain/beacon_chain_db_immutable.nim +++ b/beacon_chain/beacon_chain_db_immutable.nim @@ -44,13 +44,13 @@ type # Registry validators*: HashList[ValidatorStatus, Limit VALIDATOR_REGISTRY_LIMIT] - balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] + balances*: HashList[Gwei, Limit VALIDATOR_REGISTRY_LIMIT] # Randomness randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest] # Slashings - slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] + slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, Gwei] ## Per-epoch sums of slashed effective balances # Attestations @@ -97,13 +97,13 @@ type # Registry validators*: HashList[ValidatorStatus, Limit VALIDATOR_REGISTRY_LIMIT] - balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] + balances*: HashList[Gwei, Limit VALIDATOR_REGISTRY_LIMIT] # Randomness randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest] # Slashings - slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] + slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, Gwei] ## Per-epoch sums of slashed effective balances # Participation @@ -155,13 +155,13 @@ type # Registry validators*: HashList[ValidatorStatus, Limit VALIDATOR_REGISTRY_LIMIT] - balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] + balances*: HashList[Gwei, Limit VALIDATOR_REGISTRY_LIMIT] # Randomness randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest] # Slashings - slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] + slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, Gwei] ## Per-epoch sums of slashed effective balances # Participation diff --git a/beacon_chain/beacon_node.nim b/beacon_chain/beacon_node.nim index a3a08ce32c..e48bcfe7c7 100644 --- a/beacon_chain/beacon_node.nim +++ b/beacon_chain/beacon_node.nim @@ -89,7 +89,7 @@ type processor*: ref Eth2Processor blockProcessor*: ref BlockProcessor consensusManager*: ref ConsensusManager - attachedValidatorBalanceTotal*: uint64 + attachedValidatorBalanceTotal*: Gwei gossipState*: GossipState blocksGossipState*: GossipState beaconClock*: BeaconClock diff --git a/beacon_chain/el/el_manager.nim b/beacon_chain/el/el_manager.nim index ed57face01..a3c0c1ce6e 100644 --- a/beacon_chain/el/el_manager.nim +++ b/beacon_chain/el/el_manager.nim @@ -1368,7 +1368,7 @@ func depositEventsToBlocks(depositsList: openArray[JsonString]): seq[Eth1Block] lastEth1Block.deposits.add DepositData( pubkey: ValidatorPubKey.init(pubkey.toArray), withdrawal_credentials: Eth2Digest(data: withdrawalCredentials.toArray), - amount: bytes_to_uint64(amount.toArray), + amount: bytes_to_uint64(amount.toArray).Gwei, signature: ValidatorSig.init(signature.toArray)) type diff --git a/beacon_chain/fork_choice/fork_choice.nim b/beacon_chain/fork_choice/fork_choice.nim index 1e229e8186..114c1cbde3 100644 --- a/beacon_chain/fork_choice/fork_choice.nim +++ b/beacon_chain/fork_choice/fork_choice.nim @@ -434,7 +434,7 @@ func compute_deltas( # If the validator was not included in `old_balances` (i.e. did not exist) # its balance is zero let old_balance = if val_index < old_balances.len: old_balances[val_index] - else: 0 + else: 0.Gwei # If the validator is not known in the `new_balances` then use balance of zero # @@ -444,7 +444,7 @@ func compute_deltas( # # Note that attesters are not different as they are activated only under finality let new_balance = if val_index < new_balances.len: new_balances[val_index] - else: 0 + else: 0.Gwei if vote.current_root != vote.next_root or old_balance != new_balance: # Ignore the current or next vote if it is not known in `indices`. diff --git a/beacon_chain/fork_choice/fork_choice_types.nim b/beacon_chain/fork_choice/fork_choice_types.nim index ab776cb406..c683f14ca5 100644 --- a/beacon_chain/fork_choice/fork_choice_types.nim +++ b/beacon_chain/fork_choice/fork_choice_types.nim @@ -103,7 +103,7 @@ type indices*: Table[Eth2Digest, Index] currentEpochTips*: Table[Index, FinalityCheckpoints] previousProposerBoostRoot*: Eth2Digest - previousProposerBoostScore*: uint64 + previousProposerBoostScore*: Gwei ProtoNode* = object bid*: BlockId diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index 5122c842dc..b534d3faaf 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -1204,16 +1204,17 @@ proc maybeUpdateActionTrackerNextEpoch( # functions get_flag_index_deltas() and get_inactivity_penalty_deltas(). # # There are no penalties associated with TIMELY_HEAD_FLAG_INDEX, but a - # reward exists. effective_balance == MAX_EFFECTIVE_BALANCE ensures if - # even so, then the effective balance cannot change as a result. + # reward exists. effective_balance == MAX_EFFECTIVE_BALANCE.Gwei ensures + # if even so, then the effective balance cannot change as a result. # # It's not truly necessary to avoid all rewards and penalties, but only # to bound them to ensure they won't unexpected alter effective balance # during the upcoming epoch transition. # - # During genesis epoch, the check for epoch participation is against current, - # not previous, epoch, and therefore there's a possibility of checking for if - # a validator has participated in an epoch before it will happen. + # During genesis epoch, the check for epoch participation is against + # current, not previous, epoch, and therefore there's a possibility of + # checking for if a validator has participated in an epoch before it will + # happen. # # Because process_rewards_and_penalties() in epoch processing happens # before the current/previous participation swap, previous is correct @@ -1234,7 +1235,7 @@ proc maybeUpdateActionTrackerNextEpoch( if participation_flags.has_flag(TIMELY_SOURCE_FLAG_INDEX) and participation_flags.has_flag(TIMELY_TARGET_FLAG_INDEX) and - effective_balance == MAX_EFFECTIVE_BALANCE and + effective_balance == MAX_EFFECTIVE_BALANCE.Gwei and forkyState.data.slot.epoch != GENESIS_EPOCH and forkyState.data.inactivity_scores.item( nextEpochFirstProposer) == 0 and @@ -1956,13 +1957,13 @@ proc start*(node: BeaconNode) {.raises: [CatchableError].} = node.elManager.start() node.run() -func formatGwei(amount: uint64): string = +func formatGwei(amount: Gwei): string = # TODO This is implemented in a quite a silly way. # Better routines for formatting decimal numbers # should exists somewhere else. let - eth = amount div 1000000000 - remainder = amount mod 1000000000 + eth = distinctBase(amount) div 1000000000 + remainder = distinctBase(amount) mod 1000000000 result = $eth if remainder != 0: diff --git a/beacon_chain/rpc/rest_beacon_api.nim b/beacon_chain/rpc/rest_beacon_api.nim index ac687e86a1..a170b296ff 100644 --- a/beacon_chain/rpc/rest_beacon_api.nim +++ b/beacon_chain/rpc/rest_beacon_api.nim @@ -100,10 +100,10 @@ proc getStatus(validator: Validator, ok(ValidatorFilterKind.ExitedSlashed) elif validator.withdrawable_epoch <= current_epoch: # withdrawal - if validator.effective_balance != 0: + if validator.effective_balance != 0.Gwei: ok(ValidatorFilterKind.WithdrawalPossible) else: - # validator.effective_balance == 0 + # validator.effective_balance == 0.Gwei ok(ValidatorFilterKind.WithdrawalDone) else: err("Invalid validator status") diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 6ec6fb6f20..5bb3273806 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -29,14 +29,14 @@ func increase_balance*(balance: var Gwei, delta: Gwei) = func increase_balance*( state: var ForkyBeaconState, index: ValidatorIndex, delta: Gwei) = ## Increase the validator balance at index ``index`` by ``delta``. - if delta != 0: # avoid dirtying the balance cache if not needed + if delta != 0.Gwei: # avoid dirtying the balance cache if not needed increase_balance(state.balances.mitem(index), delta) # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#decrease_balance func decrease_balance*(balance: var Gwei, delta: Gwei) = balance = if delta > balance: - 0'u64 + 0.Gwei else: balance - delta @@ -44,7 +44,7 @@ func decrease_balance*( state: var ForkyBeaconState, index: ValidatorIndex, delta: Gwei) = ## Decrease the validator balance at index ``index`` by ``delta``, with ## underflow protection. - if delta != 0: # avoid dirtying the balance cache if not needed + if delta != 0.Gwei: # avoid dirtying the balance cache if not needed decrease_balance(state.balances.mitem(index), delta) # https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/beacon-chain.md#deposits @@ -54,7 +54,8 @@ func get_validator_from_deposit*(deposit: DepositData): let amount = deposit.amount effective_balance = min( - amount - amount mod EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + amount - amount mod EFFECTIVE_BALANCE_INCREMENT.Gwei, + MAX_EFFECTIVE_BALANCE.Gwei) Validator( pubkeyData: HashedValidatorPubKey.init(deposit.pubkey), @@ -349,13 +350,13 @@ template get_total_balance( var res = 0.Gwei for validator_index in validator_indices: res += state.validators[validator_index].effective_balance - max(EFFECTIVE_BALANCE_INCREMENT, res) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res) # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue func is_eligible_for_activation_queue*(validator: Validator): bool = ## Check if ``validator`` is eligible to be placed into the activation queue. validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and - validator.effective_balance == MAX_EFFECTIVE_BALANCE + validator.effective_balance == MAX_EFFECTIVE_BALANCE.Gwei # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#is_eligible_for_activation func is_eligible_for_activation*( @@ -619,11 +620,13 @@ func get_total_active_balance*(state: ForkyBeaconState, cache: var StateCache): # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_base_reward_per_increment func get_base_reward_per_increment_sqrt( total_active_balance_sqrt: uint64): Gwei = - EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR div total_active_balance_sqrt + EFFECTIVE_BALANCE_INCREMENT.Gwei * BASE_REWARD_FACTOR div + total_active_balance_sqrt func get_base_reward_per_increment*( total_active_balance: Gwei): Gwei = - get_base_reward_per_increment_sqrt(integer_squareroot(total_active_balance)) + get_base_reward_per_increment_sqrt( + integer_squareroot(distinctBase(total_active_balance))) # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_base_reward func get_base_reward( @@ -633,7 +636,8 @@ func get_base_reward( ## Return the base reward for the validator defined by ``index`` with respect ## to the current ``state``. let increments = - state.validators[index].effective_balance div EFFECTIVE_BALANCE_INCREMENT + state.validators[index].effective_balance div + EFFECTIVE_BALANCE_INCREMENT.Gwei increments * base_reward_per_increment # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#attestations @@ -701,11 +705,12 @@ proc check_bls_to_execution_change*( ok() -func get_proposer_reward*(state: ForkyBeaconState, - attestation: SomeAttestation, - base_reward_per_increment: Gwei, - cache: var StateCache, - epoch_participation: var EpochParticipationFlags): uint64 = +func get_proposer_reward*( + state: ForkyBeaconState, + attestation: SomeAttestation, + base_reward_per_increment: Gwei, + cache: var StateCache, + epoch_participation: var EpochParticipationFlags): Gwei = let participation_flag_indices = get_attestation_participation_flag_indices( state, attestation.data, state.slot - attestation.data.slot) for index in get_attesting_indices_iter( @@ -724,7 +729,7 @@ func get_proposer_reward*(state: ForkyBeaconState, (WEIGHT_DENOMINATOR.uint64 - PROPOSER_WEIGHT.uint64) * WEIGHT_DENOMINATOR.uint64 div PROPOSER_WEIGHT.uint64 - return result div proposer_reward_denominator + result div proposer_reward_denominator proc process_attestation*( state: var ForkyBeaconState, attestation: SomeAttestation, flags: UpdateFlags, @@ -811,7 +816,8 @@ func get_next_sync_committee_keys( candidate_index = active_validator_indices[shuffled_index] random_byte = eth2digest(hash_buffer).data[i mod 32] effective_balance = state.validators[candidate_index].effective_balance - if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: + if effective_balance * MAX_RANDOM_BYTE >= + MAX_EFFECTIVE_BALANCE.Gwei * random_byte: res[index] = state.validators[candidate_index].pubkey inc index i += 1'u64 @@ -827,7 +833,7 @@ func is_fully_withdrawable_validator( validator: Validator, balance: Gwei, epoch: Epoch): bool = ## Check if ``validator`` is fully withdrawable. has_eth1_withdrawal_credential(validator) and - validator.withdrawable_epoch <= epoch and balance > 0 + validator.withdrawable_epoch <= epoch and balance > 0.Gwei # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#is_partially_withdrawable_validator func is_partially_withdrawable_validator( @@ -835,8 +841,8 @@ func is_partially_withdrawable_validator( ## Check if ``validator`` is partially withdrawable. let has_max_effective_balance = - validator.effective_balance == MAX_EFFECTIVE_BALANCE - has_excess_balance = balance > MAX_EFFECTIVE_BALANCE + validator.effective_balance == MAX_EFFECTIVE_BALANCE.Gwei + has_excess_balance = balance > MAX_EFFECTIVE_BALANCE.Gwei has_eth1_withdrawal_credential(validator) and has_max_effective_balance and has_excess_balance @@ -868,7 +874,7 @@ func get_expected_withdrawals*( var w = Withdrawal( index: withdrawal_index, validator_index: validator_index, - amount: balance - MAX_EFFECTIVE_BALANCE) + amount: balance - MAX_EFFECTIVE_BALANCE.Gwei) w.address.data[0..19] = validator.withdrawal_credentials.data[12..^1] withdrawals.add w withdrawal_index = WithdrawalIndex(withdrawal_index + 1) @@ -974,9 +980,10 @@ proc initialize_beacon_state_from_eth1( validator = addr state.validators.mitem(vidx) validator.effective_balance = min( - balance - balance mod EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + balance - balance mod EFFECTIVE_BALANCE_INCREMENT.Gwei, + MAX_EFFECTIVE_BALANCE.Gwei) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + if validator.effective_balance == MAX_EFFECTIVE_BALANCE.Gwei: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH @@ -1091,9 +1098,10 @@ proc initialize_beacon_state_from_eth1*( validator = addr state.validators.mitem(vidx) validator.effective_balance = min( - balance - balance mod EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + balance - balance mod EFFECTIVE_BALANCE_INCREMENT.Gwei, + MAX_EFFECTIVE_BALANCE.Gwei) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + if validator.effective_balance == MAX_EFFECTIVE_BALANCE.Gwei: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH diff --git a/beacon_chain/spec/datatypes/base.nim b/beacon_chain/spec/datatypes/base.nim index 12c8e68be7..a7fd51f0c5 100644 --- a/beacon_chain/spec/datatypes/base.nim +++ b/beacon_chain/spec/datatypes/base.nim @@ -63,7 +63,7 @@ import std/[macros, hashes, sets, strutils, tables, typetraits], results, - stew/[assign2, byteutils, endians2], + stew/[assign2, base10, byteutils, endians2], chronicles, json_serialization, ssz_serialization/types as sszTypes, @@ -122,22 +122,39 @@ template maxSize*(n: int) {.pragma.} type Wei* = UInt256 - Gwei* = uint64 + Gwei* = distinct uint64 Ether* = distinct uint64 template ethAmountUnit*(typ: type) {.dirty.} = - # Arithmetic func `+`*(x, y: typ): typ {.borrow.} func `-`*(x, y: typ): typ {.borrow.} func `*`*(x: typ, y: distinctBase(typ)): typ {.borrow.} func `*`*(x: distinctBase(typ), y: typ): typ {.borrow.} - - # Arithmetic, changing type func `div`*(x, y: typ): distinctBase(typ) {.borrow.} + func `div`*(x: typ, y: distinctBase(typ)): typ {.borrow.} + func `mod`*(x, y: typ): typ {.borrow.} + + func `+=`*(x: var typ, y: typ) {.borrow.} - # Comparison func `<`*(x, y: typ): bool {.borrow.} + func `<=`*(x, y: typ): bool {.borrow.} + func `==`*(x, y: typ): bool {.borrow.} + + func `$`*(x: typ): string {.borrow.} + + func u256*(n: typ): UInt256 {.borrow.} + + proc toString*(B: typedesc[Base10], value: typ): string {.borrow.} + + proc writeValue*(writer: var JsonWriter, value: typ) {.raises: [IOError].} = + writer.writeValue(distinctBase(value)) + + proc readValue*( + reader: var JsonReader, + value: var typ) {.raises: [IOError, SerializationError].} = + reader.readValue(distinctBase(value)) +ethAmountUnit Gwei ethAmountUnit Ether type @@ -758,8 +775,8 @@ template lenu64*(x: untyped): untyped = func `$`*(v: ForkDigest | Version | DomainType): string = toHex(distinctBase(v)) -func toGaugeValue*(x: uint64 | Epoch | Slot): int64 = - if x > uint64(int64.high): +func toGaugeValue*[T: uint64 | Gwei | Slot | Epoch](x: T): int64 = + if x > uint64(int64.high).T: int64.high else: int64(x) diff --git a/beacon_chain/spec/datatypes/capella.nim b/beacon_chain/spec/datatypes/capella.nim index 984aaf99a3..6a65f81870 100644 --- a/beacon_chain/spec/datatypes/capella.nim +++ b/beacon_chain/spec/datatypes/capella.nim @@ -557,7 +557,7 @@ type # Mod-increment randao_mix*: Eth2Digest - slashing*: uint64 + slashing*: Gwei # Represent in full; for the next epoch, current_epoch_participation in # epoch n is previous_epoch_participation in epoch n+1 but this doesn't diff --git a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim index 93c6c59f8f..ebd87f5cc1 100644 --- a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim +++ b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim @@ -1008,6 +1008,16 @@ proc readValue*(reader: var JsonReader[RestJson], value: var UInt256) {. raiseUnexpectedValue(reader, "UInt256 value should be a valid decimal string") +## Gwei +proc writeValue*( + writer: var JsonWriter[RestJson], value: Gwei) {.raises: [IOError].} = + writer.writeValue(distinctBase(value)) + +proc readValue*( + reader: var JsonReader[RestJson], + value: var Gwei) {.raises: [IOError, SerializationError].} = + reader.readValue(distinctBase(value)) + ## Slot proc writeValue*( writer: var JsonWriter[RestJson], value: Slot) {.raises: [IOError].} = diff --git a/beacon_chain/spec/eth2_apis/rest_types.nim b/beacon_chain/spec/eth2_apis/rest_types.nim index ea26c7abc9..7f7115842a 100644 --- a/beacon_chain/spec/eth2_apis/rest_types.nim +++ b/beacon_chain/spec/eth2_apis/rest_types.nim @@ -719,13 +719,13 @@ func init*(t: typedesc[RestBlockInfo], RestBlockInfo(slot: forkyBlck.message.slot, blck: forkyBlck.root) func init*(t: typedesc[RestValidator], index: ValidatorIndex, - balance: uint64, status: string, + balance: Gwei, status: string, validator: Validator): RestValidator = RestValidator(index: index, balance: Base10.toString(balance), status: status, validator: validator) func init*(t: typedesc[RestValidatorBalance], index: ValidatorIndex, - balance: uint64): RestValidatorBalance = + balance: Gwei): RestValidatorBalance = RestValidatorBalance(index: index, balance: Base10.toString(balance)) func init*(t: typedesc[Web3SignerRequest], fork: Fork, diff --git a/beacon_chain/spec/helpers.nim b/beacon_chain/spec/helpers.nim index 7836db9969..d7acb7058c 100644 --- a/beacon_chain/spec/helpers.nim +++ b/beacon_chain/spec/helpers.nim @@ -25,11 +25,15 @@ import export eth2_merkleization, forks, rlp, ssz_codec +# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/weak-subjectivity.md#constants +const ETH_TO_GWEI = 1_000_000_000.Gwei + func toEther*(gwei: Gwei): Ether = - # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/weak-subjectivity.md#constants - const ETH_TO_GWEI = 1_000_000_000 (gwei div ETH_TO_GWEI).Ether +func toGwei*(eth: Ether): Gwei = + distinctBase(eth) * ETH_TO_GWEI + type ExecutionHash256* = eth_types.Hash256 ExecutionTransaction* = eth_types.Transaction @@ -452,7 +456,7 @@ func toExecutionWithdrawal*( index: withdrawal.index, validatorIndex: withdrawal.validator_index, address: EthAddress withdrawal.address.data, - amount: withdrawal.amount) + amount: distinctBase(withdrawal.amount)) # https://eips.ethereum.org/EIPS/eip-4895 proc computeWithdrawalsTrieRoot*( diff --git a/beacon_chain/spec/mev/capella_mev.nim b/beacon_chain/spec/mev/capella_mev.nim index 7effc7ec9e..2a69742ed9 100644 --- a/beacon_chain/spec/mev/capella_mev.nim +++ b/beacon_chain/spec/mev/capella_mev.nim @@ -10,7 +10,7 @@ import ".."/datatypes/[altair, capella] from stew/byteutils import to0xHex -from ../eth2_merkleization import hash_tree_root +from ../eth2_merkleization import fromSszBytes, hash_tree_root, toSszType type # https://github.com/ethereum/builder-specs/blob/v0.4.0/specs/capella/builder.md#blindedbeaconblockbody diff --git a/beacon_chain/spec/ssz_codec.nim b/beacon_chain/spec/ssz_codec.nim index 228bc228c9..ce146df838 100644 --- a/beacon_chain/spec/ssz_codec.nim +++ b/beacon_chain/spec/ssz_codec.nim @@ -19,6 +19,7 @@ export codec, base, typetraits, EpochParticipationFlags # Coding and decoding of SSZ to spec-specific types +template toSszType*(v: Gwei): auto = uint64(v) template toSszType*(v: Slot|Epoch|SyncCommitteePeriod): auto = uint64(v) template toSszType*(v: BlsCurveType): auto = toRaw(v) template toSszType*(v: ForkDigest|GraffitiBytes): auto = distinctBase(v) @@ -32,6 +33,9 @@ func fromSszBytes*( raiseIncorrectSize T copyMem(result.addr, unsafeAddr data[0], sizeof(result)) +template fromSszBytes*(T: type Gwei, bytes: openArray[byte]): T = + T fromSszBytes(uint64, bytes) + template fromSszBytes*(T: type Slot, bytes: openArray[byte]): T = T fromSszBytes(uint64, bytes) diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index 8af6c24015..97af794b49 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -489,7 +489,7 @@ proc process_operations(cfg: RuntimeConfig, func get_participant_reward*(total_active_balance: Gwei): Gwei = let total_active_increments = - total_active_balance div EFFECTIVE_BALANCE_INCREMENT + total_active_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei total_base_rewards = get_base_reward_per_increment(total_active_balance) * total_active_increments diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index f95822f5a9..25d5a1e2de 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -42,19 +42,19 @@ logScope: topics = "consens" # Accessors that implement the max condition in `get_total_balance`: # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#get_total_balance template current_epoch*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.current_epoch_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_raw) template previous_epoch*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.previous_epoch_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_raw) template current_epoch_attesters*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.current_epoch_attesters_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_attesters_raw) template current_epoch_target_attesters*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.current_epoch_target_attesters_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.current_epoch_target_attesters_raw) template previous_epoch_attesters*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.previous_epoch_attesters_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_attesters_raw) template previous_epoch_target_attesters*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.previous_epoch_target_attesters_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_target_attesters_raw) template previous_epoch_head_attesters*(v: TotalBalances): Gwei = - max(EFFECTIVE_BALANCE_INCREMENT, v.previous_epoch_head_attesters_raw) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, v.previous_epoch_head_attesters_raw) func init*(info: var phase0.EpochInfo, state: phase0.BeaconState) = info.balances = TotalBalances() @@ -218,12 +218,12 @@ func get_unslashed_participating_balances*( for flag_index in TimelyFlag: res.previous_epoch[flag_index] = - max(EFFECTIVE_BALANCE_INCREMENT, res.previous_epoch[flag_index]) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.previous_epoch[flag_index]) res.current_epoch_TIMELY_TARGET = - max(EFFECTIVE_BALANCE_INCREMENT, res.current_epoch_TIMELY_TARGET) + max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.current_epoch_TIMELY_TARGET) - res.current_epoch = max(EFFECTIVE_BALANCE_INCREMENT, res.current_epoch) + res.current_epoch = max(EFFECTIVE_BALANCE_INCREMENT.Gwei, res.current_epoch) res @@ -504,24 +504,26 @@ func is_in_inactivity_leak(finality_delay: uint64): bool = func get_finality_delay*(state: ForkyBeaconState): uint64 = get_previous_epoch(state) - state.finalized_checkpoint.epoch -func get_attestation_component_reward*(attesting_balance: Gwei, - total_balance: Gwei, - base_reward: uint64, - finality_delay: uint64): Gwei = +func get_attestation_component_reward*( + attesting_balance: Gwei, + total_balance: Gwei, + base_reward: Gwei, + finality_delay: uint64): Gwei = if is_in_inactivity_leak(finality_delay): # Since full base reward will be canceled out by inactivity penalty deltas, # optimal participation receives full base reward compensation here. base_reward else: let reward_numerator = - base_reward * (attesting_balance div EFFECTIVE_BALANCE_INCREMENT) - reward_numerator div (total_balance div EFFECTIVE_BALANCE_INCREMENT) - -func get_attestation_component_delta(is_unslashed_attester: bool, - attesting_balance: Gwei, - total_balance: Gwei, - base_reward: uint64, - finality_delay: uint64): RewardDelta = + base_reward * (attesting_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei) + reward_numerator div (total_balance div EFFECTIVE_BALANCE_INCREMENT.Gwei) + +func get_attestation_component_delta( + is_unslashed_attester: bool, + attesting_balance: Gwei, + total_balance: Gwei, + base_reward: Gwei, + finality_delay: uint64): RewardDelta = # Helper with shared logic for use by get source, target, and head deltas # functions if is_unslashed_attester: @@ -534,10 +536,11 @@ func get_attestation_component_delta(is_unslashed_attester: bool, RewardDelta(penalties: base_reward) # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#components-of-attestation-deltas -func get_source_delta*(validator: RewardStatus, - base_reward: uint64, - balances: TotalBalances, - finality_delay: uint64): RewardDelta = +func get_source_delta*( + validator: RewardStatus, + base_reward: Gwei, + balances: TotalBalances, + finality_delay: uint64): RewardDelta = ## Return attester micro-rewards/penalties for source-vote for each validator. get_attestation_component_delta( validator.is_previous_epoch_attester.isSome() and @@ -547,10 +550,11 @@ func get_source_delta*(validator: RewardStatus, base_reward, finality_delay) -func get_target_delta*(validator: RewardStatus, - base_reward: uint64, - balances: TotalBalances, - finality_delay: uint64): RewardDelta = +func get_target_delta*( + validator: RewardStatus, + base_reward: Gwei, + balances: TotalBalances, + finality_delay: uint64): RewardDelta = ## Return attester micro-rewards/penalties for target-vote for each validator. get_attestation_component_delta( validator.flags.contains(RewardFlags.isPreviousEpochTargetAttester) and @@ -560,10 +564,11 @@ func get_target_delta*(validator: RewardStatus, base_reward, finality_delay) -func get_head_delta*(validator: RewardStatus, - base_reward: uint64, - balances: TotalBalances, - finality_delay: uint64): RewardDelta = +func get_head_delta*( + validator: RewardStatus, + base_reward: Gwei, + balances: TotalBalances, + finality_delay: uint64): RewardDelta = ## Return attester micro-rewards/penalties for head-vote for each validator. get_attestation_component_delta( validator.flags.contains(RewardFlags.isPreviousEpochHeadAttester) and @@ -573,9 +578,9 @@ func get_head_delta*(validator: RewardStatus, base_reward, finality_delay) -func get_inclusion_delay_delta*(validator: RewardStatus, - base_reward: uint64): - (RewardDelta, Opt[(uint64, RewardDelta)]) = +func get_inclusion_delay_delta*( + validator: RewardStatus, + base_reward: Gwei): (RewardDelta, Opt[(uint64, RewardDelta)]) = ## Return proposer and inclusion delay micro-rewards/penalties for each validator. if validator.is_previous_epoch_attester.isSome() and ((not validator.flags.contains(RewardFlags.isSlashed))): let @@ -589,9 +594,10 @@ func get_inclusion_delay_delta*(validator: RewardStatus, proposer_index = inclusion_info.proposer_index; return (delta, Opt.some((proposer_index, proposer_delta))) -func get_inactivity_penalty_delta*(validator: RewardStatus, - base_reward: Gwei, - finality_delay: uint64): RewardDelta = +func get_inactivity_penalty_delta*( + validator: RewardStatus, + base_reward: Gwei, + finality_delay: uint64): RewardDelta = ## Return inactivity reward/penalty deltas for each validator. var delta: RewardDelta @@ -615,11 +621,10 @@ func get_inactivity_penalty_delta*(validator: RewardStatus, func get_attestation_deltas( state: phase0.BeaconState, info: var phase0.EpochInfo) = ## Update rewards with attestation reward/penalty deltas for each validator. - let finality_delay = get_finality_delay(state) total_balance = info.balances.current_epoch - total_balance_sqrt = integer_squareroot(total_balance) + total_balance_sqrt = integer_squareroot(distinctBase(total_balance)) # Filter out ineligible validators. All sub-functions of the spec do this # except for `get_inclusion_delay_deltas`. It's safe to do so here because # any validator that is in the unslashed indices of the matching source @@ -664,15 +669,17 @@ func get_base_reward_increment*( ## Return the base reward for the validator defined by ``index`` with respect ## to the current ``state``. let increments = - state.validators[index].effective_balance div EFFECTIVE_BALANCE_INCREMENT + state.validators[index].effective_balance div + EFFECTIVE_BALANCE_INCREMENT.Gwei increments * base_reward_per_increment # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas func get_flag_index_reward*( state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState | electra.BeaconState, - base_reward: Gwei, active_increments: Gwei, - unslashed_participating_increments: Gwei, + base_reward: Gwei, + active_increments: uint64, + unslashed_participating_increments: uint64, weight, finality_delay: uint64): Gwei = if not is_in_inactivity_leak(finality_delay): let reward_numerator = @@ -683,13 +690,14 @@ func get_flag_index_reward*( # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas func get_unslashed_participating_increment*( - info: altair.EpochInfo | bellatrix.BeaconState, flag_index: TimelyFlag): Gwei = - info.balances.previous_epoch[flag_index] div EFFECTIVE_BALANCE_INCREMENT + info: altair.EpochInfo | bellatrix.BeaconState, + flag_index: TimelyFlag): uint64 = + info.balances.previous_epoch[flag_index] div EFFECTIVE_BALANCE_INCREMENT.Gwei # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas func get_active_increments*( - info: altair.EpochInfo | bellatrix.BeaconState): Gwei = - info.balances.current_epoch div EFFECTIVE_BALANCE_INCREMENT + info: altair.EpochInfo | bellatrix.BeaconState): uint64 = + info.balances.current_epoch div EFFECTIVE_BALANCE_INCREMENT.Gwei # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#get_flag_index_deltas # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas @@ -699,12 +707,14 @@ template get_flag_and_inactivity_delta( state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState | electra.BeaconState, base_reward_per_increment: Gwei, finality_delay: uint64, - previous_epoch: Epoch, active_increments: Gwei, + previous_epoch: Epoch, + active_increments: uint64, penalty_denominator: uint64, epoch_participation: ptr EpochParticipationFlags, - participating_increments: array[3, Gwei], info: var altair.EpochInfo, - vidx: ValidatorIndex): - (ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) = + participating_increments: array[3, uint64], + info: var altair.EpochInfo, + vidx: ValidatorIndex +): (ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) = let base_reward = get_base_reward_increment(state, vidx, base_reward_per_increment) pflags = @@ -728,13 +738,13 @@ template get_flag_and_inactivity_delta( participating_increments[ord(flag)], PARTICIPATION_FLAG_WEIGHTS[flag], finality_delay) else: - 0 + 0.Gwei template penalty(flag: untyped): untyped = if not has_flag(pflags, flag): base_reward * PARTICIPATION_FLAG_WEIGHTS[flag] div WEIGHT_DENOMINATOR else: - 0 + 0.Gwei let inactivity_penalty = if has_flag(pflags, TIMELY_TARGET_FLAG_INDEX): @@ -893,7 +903,7 @@ func process_registry_updates*( get_current_epoch(state) + 1 if is_active_validator(state.validators.item(vidx), get_current_epoch(state)) and - state.validators.item(vidx).effective_balance <= cfg.EJECTION_BALANCE: + state.validators.item(vidx).effective_balance <= cfg.EJECTION_BALANCE.Gwei: ? initiate_validator_exit(cfg, state, vidx, cache) let validator = unsafeAddr state.validators.item(vidx) @@ -950,7 +960,7 @@ func get_slashing_penalty*(validator: Validator, adjusted_total_slashing_balance, total_balance: Gwei): Gwei = # Factored out from penalty numerator to avoid uint64 overflow - const increment = EFFECTIVE_BALANCE_INCREMENT + const increment = EFFECTIVE_BALANCE_INCREMENT.Gwei let penalty_numerator = validator.effective_balance div increment * adjusted_total_slashing_balance penalty_numerator div total_balance * increment @@ -983,7 +993,8 @@ func process_eth1_data_reset*(state: var ForkyBeaconState) = template effective_balance_might_update*( balance: Gwei, effective_balance: Gwei): bool = const - HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT div HYSTERESIS_QUOTIENT + HYSTERESIS_INCREMENT = + EFFECTIVE_BALANCE_INCREMENT.Gwei div HYSTERESIS_QUOTIENT DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER balance + DOWNWARD_THRESHOLD < effective_balance or @@ -999,8 +1010,8 @@ func process_effective_balance_updates*(state: var ForkyBeaconState) = if effective_balance_might_update(balance, effective_balance): let new_effective_balance = min( - balance - balance mod EFFECTIVE_BALANCE_INCREMENT, - MAX_EFFECTIVE_BALANCE) + balance - balance mod EFFECTIVE_BALANCE_INCREMENT.Gwei, + MAX_EFFECTIVE_BALANCE.Gwei) # Protect against unnecessary cache invalidation if new_effective_balance != effective_balance: state.validators.mitem(vidx).effective_balance = new_effective_balance @@ -1081,7 +1092,7 @@ template compute_inactivity_update( state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState | electra.BeaconState, info: altair.EpochInfo, - pre_inactivity_score: Gwei): Gwei = + pre_inactivity_score: uint64): uint64 = let previous_epoch = get_previous_epoch(state) # get_eligible_validator_indices() # Increase the inactivity score of inactive validators diff --git a/beacon_chain/spec/validator.nim b/beacon_chain/spec/validator.nim index 6f60ceec2e..f802e23134 100644 --- a/beacon_chain/spec/validator.nim +++ b/beacon_chain/spec/validator.nim @@ -372,7 +372,7 @@ template compute_proposer_index(state: ForkyBeaconState, random_byte = (eth2digest(buffer).data)[i mod 32] effective_balance = state.validators[candidate_index].effective_balance if effective_balance * MAX_RANDOM_BYTE >= - MAX_EFFECTIVE_BALANCE * random_byte: + MAX_EFFECTIVE_BALANCE.Gwei * random_byte: res = Opt.some(candidate_index) break i += 1 diff --git a/beacon_chain/spec/weak_subjectivity.nim b/beacon_chain/spec/weak_subjectivity.nim index 81a7ccaeff..08092814de 100644 --- a/beacon_chain/spec/weak_subjectivity.nim +++ b/beacon_chain/spec/weak_subjectivity.nim @@ -29,8 +29,8 @@ func compute_weak_subjectivity_period( ws_period = cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY let N = get_active_validator_indices_len(state, get_current_epoch(state)) - t = (get_total_active_balance(state, cache) div N).toEther - const T = MAX_EFFECTIVE_BALANCE.toEther + t = (get_total_active_balance(state, cache) div N).toEther() + const T = MAX_EFFECTIVE_BALANCE.Gwei.toEther() let delta = cfg.get_validator_churn_limit(state, cache) const Delta = MAX_DEPOSITS * SLOTS_PER_EPOCH diff --git a/beacon_chain/validators/validator_monitor.nim b/beacon_chain/validators/validator_monitor.nim index 58672a197e..0ad7fba7d8 100644 --- a/beacon_chain/validators/validator_monitor.nim +++ b/beacon_chain/validators/validator_monitor.nim @@ -585,8 +585,8 @@ proc registerState*(self: var ValidatorMonitor, state: ForkyBeaconState) = if self.totals: var - balance: uint64 - effective_balance: uint64 + balance: Gwei + effective_balance: Gwei slashed: int64 active: int64 exited: int64 diff --git a/ncli/ncli_common.nim b/ncli/ncli_common.nim index 597cd734ee..c21624cefd 100644 --- a/ncli/ncli_common.nim +++ b/ncli/ncli_common.nim @@ -224,7 +224,7 @@ proc collectEpochRewardsAndPenalties*( let finality_delay = get_finality_delay(state) total_balance = info.balances.current_epoch - total_balance_sqrt = integer_squareroot(total_balance) + total_balance_sqrt = integer_squareroot(distinctBase(total_balance)) for index, validator in info.validators: if not is_eligible_validator(validator): @@ -233,9 +233,10 @@ proc collectEpochRewardsAndPenalties*( let base_reward = get_base_reward_sqrt( state, index.ValidatorIndex, total_balance_sqrt) - template get_attestation_component_reward_helper(attesting_balance: Gwei): Gwei = + template get_attestation_component_reward_helper( + attesting_balance: Gwei): Gwei = get_attestation_component_reward(attesting_balance, - info.balances.current_epoch, base_reward.uint64, finality_delay) + info.balances.current_epoch, base_reward, finality_delay) template rp: untyped = rewardsAndPenalties[index] @@ -374,7 +375,7 @@ func collectFromAttestations( when consensusFork > ConsensusFork.Phase0: let base_reward_per_increment = get_base_reward_per_increment( get_total_active_balance(forkyState.data, cache)) - doAssert base_reward_per_increment > 0 + doAssert base_reward_per_increment > 0.Gwei for attestation in forkyBlck.message.body.attestations: doAssert check_attestation( forkyState.data, attestation, {}, cache).isOk diff --git a/ncli/validator_db_aggregator.nim b/ncli/validator_db_aggregator.nim index c0bc50256c..ff67d36604 100644 --- a/ncli/validator_db_aggregator.nim +++ b/ncli/validator_db_aggregator.nim @@ -192,19 +192,19 @@ when isMainModule: func parseRow(csvRow: CsvRow): RewardsAndPenalties {.raises: [ValueError].} = result = RewardsAndPenalties( source_outcome: parseBiggestInt(csvRow[0]), - max_source_reward: parseBiggestUInt(csvRow[1]), + max_source_reward: parseBiggestUInt(csvRow[1]).Gwei, target_outcome: parseBiggestInt(csvRow[2]), - max_target_reward: parseBiggestUInt(csvRow[3]), + max_target_reward: parseBiggestUInt(csvRow[3]).Gwei, head_outcome: parseBiggestInt(csvRow[4]), - max_head_reward: parseBiggestUInt(csvRow[5]), + max_head_reward: parseBiggestUInt(csvRow[5]).Gwei, inclusion_delay_outcome: parseBiggestInt(csvRow[6]), - max_inclusion_delay_reward: parseBiggestUInt(csvRow[7]), + max_inclusion_delay_reward: parseBiggestUInt(csvRow[7]).Gwei, sync_committee_outcome: parseBiggestInt(csvRow[8]), - max_sync_committee_reward: parseBiggestUInt(csvRow[9]), + max_sync_committee_reward: parseBiggestUInt(csvRow[9]).Gwei, proposer_outcome: parseBiggestInt(csvRow[10]), - inactivity_penalty: parseBiggestUInt(csvRow[11]), + inactivity_penalty: parseBiggestUInt(csvRow[11]).Gwei, slashing_outcome: parseBiggestInt(csvRow[12]), - deposits: parseBiggestUInt(csvRow[13])) + deposits: parseBiggestUInt(csvRow[13]).Gwei) if csvRow[14].len > 0: result.inclusion_delay = some(parseBiggestUInt(csvRow[14])) diff --git a/research/wss_sim.nim b/research/wss_sim.nim index b5e4c12c60..41b555f711 100644 --- a/research/wss_sim.nim +++ b/research/wss_sim.nim @@ -120,7 +120,7 @@ cli do(validatorsDir: string, secretsDir: string, active = withState(state[]): get_active_validator_indices_len(forkyState.data, slot.epoch) balance = block: - var b: uint64 + var b: Gwei for k, _ in validators: if is_active_validator(getStateField(state[], validators).asSeq[k], slot.epoch): b += getStateField(state[], balances).asSeq[k] diff --git a/tests/consensus_spec/altair/test_fixture_operations.nim b/tests/consensus_spec/altair/test_fixture_operations.nim index 56f73156d2..8fc36e3dd5 100644 --- a/tests/consensus_spec/altair/test_fixture_operations.nim +++ b/tests/consensus_spec/altair/test_fixture_operations.nim @@ -95,7 +95,7 @@ suite baseDescription & "Attester Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attester_slashing( - defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpAttSlashingDir): @@ -134,7 +134,7 @@ suite baseDescription & "Proposer Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_proposer_slashing( - defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpProposerSlashingDir): @@ -149,7 +149,7 @@ suite baseDescription & "Sync Aggregate " & preset(): var cache: StateCache doAssert (? process_sync_aggregate( preState, syncAggregate, get_total_active_balance(preState, cache), - {}, cache)) > 0 + {}, cache)) > 0.Gwei ok() for path in walkTests(OpSyncAggregateDir): diff --git a/tests/consensus_spec/altair/test_fixture_rewards.nim b/tests/consensus_spec/altair/test_fixture_rewards.nim index 34f67526b0..2fa03281e2 100644 --- a/tests/consensus_spec/altair/test_fixture_rewards.nim +++ b/tests/consensus_spec/altair/test_fixture_rewards.nim @@ -74,7 +74,7 @@ proc runTest(rewardsDir, identifier: string) = flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] = penalty1 flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] = - 0 + 0.Gwei inactivityPenaltyDeltas2.penalties[validator_index] = penalty2 check: diff --git a/tests/consensus_spec/bellatrix/test_fixture_operations.nim b/tests/consensus_spec/bellatrix/test_fixture_operations.nim index 4bcaf3ed3e..53e6421732 100644 --- a/tests/consensus_spec/bellatrix/test_fixture_operations.nim +++ b/tests/consensus_spec/bellatrix/test_fixture_operations.nim @@ -100,7 +100,7 @@ suite baseDescription & "Attester Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attester_slashing( - defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpAttSlashingDir): @@ -158,7 +158,7 @@ suite baseDescription & "Proposer Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_proposer_slashing( - defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpProposerSlashingDir): @@ -173,7 +173,7 @@ suite baseDescription & "Sync Aggregate " & preset(): var cache: StateCache doAssert (? process_sync_aggregate( preState, syncAggregate, get_total_active_balance(preState, cache), - {}, cache)) > 0 + {}, cache)) > 0.Gwei ok() for path in walkTests(OpSyncAggregateDir): diff --git a/tests/consensus_spec/bellatrix/test_fixture_rewards.nim b/tests/consensus_spec/bellatrix/test_fixture_rewards.nim index bffce1009a..6e1bdcf6d9 100644 --- a/tests/consensus_spec/bellatrix/test_fixture_rewards.nim +++ b/tests/consensus_spec/bellatrix/test_fixture_rewards.nim @@ -74,7 +74,7 @@ proc runTest(rewardsDir, identifier: string) = flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] = penalty1 flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] = - 0 + 0.Gwei inactivityPenaltyDeltas2.penalties[validator_index] = penalty2 check: diff --git a/tests/consensus_spec/capella/test_fixture_operations.nim b/tests/consensus_spec/capella/test_fixture_operations.nim index 72e0346901..1ae74cc6a2 100644 --- a/tests/consensus_spec/capella/test_fixture_operations.nim +++ b/tests/consensus_spec/capella/test_fixture_operations.nim @@ -104,7 +104,7 @@ suite baseDescription & "Attester Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attester_slashing( - defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpAttSlashingDir): @@ -175,7 +175,7 @@ suite baseDescription & "Proposer Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_proposer_slashing( - defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpProposerSlashingDir): @@ -190,7 +190,7 @@ suite baseDescription & "Sync Aggregate " & preset(): var cache: StateCache doAssert (? process_sync_aggregate( preState, syncAggregate, get_total_active_balance(preState, cache), - {}, cache)) > 0 + {}, cache)) > 0.Gwei ok() for path in walkTests(OpSyncAggregateDir): diff --git a/tests/consensus_spec/capella/test_fixture_rewards.nim b/tests/consensus_spec/capella/test_fixture_rewards.nim index 6982b5d400..a1eaed7563 100644 --- a/tests/consensus_spec/capella/test_fixture_rewards.nim +++ b/tests/consensus_spec/capella/test_fixture_rewards.nim @@ -5,6 +5,7 @@ # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # at your option. This file may not be copied, modified, or distributed except according to those terms. +{.push raises: [].} {.used.} import @@ -73,7 +74,7 @@ proc runTest(rewardsDir, identifier: string) = flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] = penalty1 flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] = - 0 + 0.Gwei inactivityPenaltyDeltas2.penalties[validator_index] = penalty2 check: diff --git a/tests/consensus_spec/deneb/test_fixture_operations.nim b/tests/consensus_spec/deneb/test_fixture_operations.nim index d60eaeb62c..10db142b4e 100644 --- a/tests/consensus_spec/deneb/test_fixture_operations.nim +++ b/tests/consensus_spec/deneb/test_fixture_operations.nim @@ -104,7 +104,7 @@ suite baseDescription & "Attester Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attester_slashing( - defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpAttSlashingDir): @@ -177,7 +177,7 @@ suite baseDescription & "Proposer Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_proposer_slashing( - defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpProposerSlashingDir): @@ -192,7 +192,7 @@ suite baseDescription & "Sync Aggregate " & preset(): var cache: StateCache doAssert (? process_sync_aggregate( preState, syncAggregate, get_total_active_balance(preState, cache), - {}, cache)) > 0 + {}, cache)) > 0.Gwei ok() for path in walkTests(OpSyncAggregateDir): diff --git a/tests/consensus_spec/deneb/test_fixture_rewards.nim b/tests/consensus_spec/deneb/test_fixture_rewards.nim index 90cf68584f..cb98918faa 100644 --- a/tests/consensus_spec/deneb/test_fixture_rewards.nim +++ b/tests/consensus_spec/deneb/test_fixture_rewards.nim @@ -74,7 +74,7 @@ proc runTest(rewardsDir, identifier: string) = flagDeltas2[TimelyFlag.TIMELY_TARGET_FLAG_INDEX].penalties[validator_index] = penalty1 flagDeltas2[TimelyFlag.TIMELY_HEAD_FLAG_INDEX].penalties[validator_index] = - 0 + 0.Gwei inactivityPenaltyDeltas2.penalties[validator_index] = penalty2 check: diff --git a/tests/consensus_spec/fixtures_utils.nim b/tests/consensus_spec/fixtures_utils.nim index 8143e2bc84..7cf494b443 100644 --- a/tests/consensus_spec/fixtures_utils.nim +++ b/tests/consensus_spec/fixtures_utils.nim @@ -74,8 +74,8 @@ type # https://github.com/ethereum/consensus-specs/tree/v1.3.0/tests/formats/rewards#rewards-tests Deltas* = object - rewards*: List[uint64, Limit VALIDATOR_REGISTRY_LIMIT] - penalties*: List[uint64, Limit VALIDATOR_REGISTRY_LIMIT] + rewards*: List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT] + penalties*: List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT] # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/validator.md#eth1block Eth1Block* = object diff --git a/tests/consensus_spec/phase0/test_fixture_operations.nim b/tests/consensus_spec/phase0/test_fixture_operations.nim index 226de5c1f7..a6808fb604 100644 --- a/tests/consensus_spec/phase0/test_fixture_operations.nim +++ b/tests/consensus_spec/phase0/test_fixture_operations.nim @@ -72,7 +72,7 @@ suite baseDescription & "Attestation " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attestation( - preState, attestation, {}, 0.Gwei, cache)) == 0 + preState, attestation, {}, 0.Gwei, cache)) == 0.Gwei ok() for path in walkTests(OpAttestationsDir): @@ -86,7 +86,7 @@ suite baseDescription & "Attester Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_attester_slashing( - defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, attesterSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpAttSlashingDir): @@ -126,7 +126,7 @@ suite baseDescription & "Proposer Slashing " & preset(): Result[void, cstring] = var cache: StateCache doAssert (? process_proposer_slashing( - defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0 + defaultRuntimeConfig, preState, proposerSlashing, {}, cache)) > 0.Gwei ok() for path in walkTests(OpProposerSlashingDir): diff --git a/tests/consensus_spec/phase0/test_fixture_rewards.nim b/tests/consensus_spec/phase0/test_fixture_rewards.nim index de59f8e2eb..90163baf13 100644 --- a/tests/consensus_spec/phase0/test_fixture_rewards.nim +++ b/tests/consensus_spec/phase0/test_fixture_rewards.nim @@ -58,7 +58,7 @@ proc runTest(rewardsDir, identifier: string) = info.process_attestations(state[], cache) let total_balance = info.balances.current_epoch - total_balance_sqrt = integer_squareroot(total_balance) + total_balance_sqrt = integer_squareroot(distinctBase(total_balance)) var sourceDeltas2 = Deltas.init(state[].validators.len) diff --git a/tests/helpers/math_helpers.nim b/tests/helpers/math_helpers.nim deleted file mode 100644 index 7b647654c8..0000000000 --- a/tests/helpers/math_helpers.nim +++ /dev/null @@ -1,12 +0,0 @@ -# beacon_chain -# Copyright (c) 2018-2024 Status Research & Development GmbH -# Licensed and distributed under either of -# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). -# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). -# at your option. This file may not be copied, modified, or distributed except according to those terms. - -{.push raises: [].} - -func round_multiple_down*(x: uint64, n: uint64): uint64 = - ## Round the input to the previous multiple of "n" - x - x mod n diff --git a/tests/mocking/mock_deposits.nim b/tests/mocking/mock_deposits.nim index e509b8da4e..f07029da08 100644 --- a/tests/mocking/mock_deposits.nim +++ b/tests/mocking/mock_deposits.nim @@ -11,11 +11,9 @@ # --------------------------------------------------------------- import - # Standard library - std/math, - # Specs - ../../beacon_chain/spec/[eth2_merkleization, keystore, forks, signatures], + ../../beacon_chain/spec/[ + eth2_merkleization, keystore, forks, helpers, signatures], ../../beacon_chain/spec/datatypes/base, # Internals @@ -25,10 +23,7 @@ import # Test utilities ../testblockutil -func mockDepositData( - pubkey: ValidatorPubKey, - amount: uint64, - ): DepositData = +func mockDepositData(pubkey: ValidatorPubKey, amount: Gwei): DepositData = # Insecurely use pubkey as withdrawal key DepositData( pubkey: pubkey, @@ -37,12 +32,12 @@ func mockDepositData( ) func mockDepositData( - pubkey: ValidatorPubKey, - privkey: ValidatorPrivKey, - amount: uint64, - # withdrawal_credentials: Eth2Digest, - flags: UpdateFlags = {} - ): DepositData = + pubkey: ValidatorPubKey, + privkey: ValidatorPrivKey, + amount: Gwei, + # withdrawal_credentials: Eth2Digest, + flags: UpdateFlags = {} +): DepositData = var ret = mockDepositData(pubkey, amount) if skipBlsValidation notin flags: ret.signature = defaultRuntimeConfig.get_deposit_signature(ret, privkey).toValidatorSig() @@ -92,10 +87,10 @@ template mockGenesisDepositsImpl( depositsDataHash.add hash_tree_root(result[valIdx]) proc mockGenesisBalancedDeposits*( - validatorCount: uint64, - amountInEth: Positive, - flags: UpdateFlags = {} - ): seq[DepositData] = + validatorCount: uint64, + amountInEth: Ether, + flags: UpdateFlags = {} +): seq[DepositData] = ## The amount should be strictly positive ## - 1 is the minimum deposit amount (MIN_DEPOSIT_AMOUNT) ## - 16 is the ejection balance (EJECTION_BALANCE) @@ -104,19 +99,17 @@ proc mockGenesisBalancedDeposits*( ## ## Only validators with 32 ETH will be active at genesis - let amount = amountInEth.uint64 * 10'u64^9 + let amount = amountInEth.toGwei() mockGenesisDepositsImpl(result, validatorCount,amount,flags): discard proc mockUpdateStateForNewDeposit*( state: var ForkyBeaconState, validator_index: uint64, - amount: uint64, + amount: Gwei, # withdrawal_credentials: Eth2Digest flags: UpdateFlags ): Deposit = - - # TODO withdrawal credentials result.data = mockDepositData( diff --git a/tests/mocking/mock_genesis.nim b/tests/mocking/mock_genesis.nim index badfa26d60..a9aec10b23 100644 --- a/tests/mocking/mock_genesis.nim +++ b/tests/mocking/mock_genesis.nim @@ -24,7 +24,7 @@ proc initGenesisState*( cfg = defaultRuntimeConfig): ref ForkedHashedBeaconState = let deposits = mockGenesisBalancedDeposits( validatorCount = num_validators, - amountInEth = 32, # We create canonical validators with 32 Eth + amountInEth = 32.Ether, # We create canonical validators with 32 Eth flags = {} ) diff --git a/tests/testblockutil.nim b/tests/testblockutil.nim index d3c6a0f361..204539eed1 100644 --- a/tests/testblockutil.nim +++ b/tests/testblockutil.nim @@ -62,7 +62,7 @@ proc makeDeposit*( result = DepositData( pubkey: pubkey, withdrawal_credentials: withdrawal_credentials, - amount: MAX_EFFECTIVE_BALANCE) + amount: MAX_EFFECTIVE_BALANCE.Gwei) if skipBlsValidation notin flags: result.signature = get_deposit_signature(cfg, result, privkey).toValidatorSig() diff --git a/tests/teststateutil.nim b/tests/teststateutil.nim index af8b5b5cc3..1bd24e6a9e 100644 --- a/tests/teststateutil.nim +++ b/tests/teststateutil.nim @@ -13,11 +13,14 @@ import ../beacon_chain/spec/[ forks, state_transition, state_transition_block] -from "."/helpers/math_helpers import round_multiple_down from ".."/beacon_chain/bloomfilter import constructBloomFilter +func round_multiple_down(x: Gwei, n: Gwei): Gwei = + ## Round the input to the previous multiple of "n" + x - x mod n + proc valid_deposit(state: var ForkyHashedBeaconState) = - const deposit_amount = MAX_EFFECTIVE_BALANCE + const deposit_amount = MAX_EFFECTIVE_BALANCE.Gwei let validator_index = state.data.validators.len let deposit = mockUpdateStateForNewDeposit( state.data, @@ -30,7 +33,7 @@ proc valid_deposit(state: var ForkyHashedBeaconState) = let pre_balance = if validator_index < pre_val_count: state.data.balances.item(validator_index) else: - 0 + 0.Gwei doAssert process_deposit( defaultRuntimeConfig, state.data, constructBloomFilter(state.data.validators.asSeq)[], deposit, {}).isOk @@ -39,8 +42,10 @@ proc valid_deposit(state: var ForkyHashedBeaconState) = doAssert state.data.balances.item(validator_index) == pre_balance + deposit.data.amount doAssert state.data.validators.item(validator_index).effective_balance == round_multiple_down( - min(MAX_EFFECTIVE_BALANCE, state.data.balances.item(validator_index)), - EFFECTIVE_BALANCE_INCREMENT + min( + MAX_EFFECTIVE_BALANCE.Gwei, + state.data.balances.item(validator_index)), + EFFECTIVE_BALANCE_INCREMENT.Gwei ) state.root = hash_tree_root(state.data)