mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-11 14:54:12 +00:00
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.
This commit is contained in:
parent
1dd2c939ac
commit
5d42859176
@ -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
|
||||
|
@ -89,7 +89,7 @@ type
|
||||
processor*: ref Eth2Processor
|
||||
blockProcessor*: ref BlockProcessor
|
||||
consensusManager*: ref ConsensusManager
|
||||
attachedValidatorBalanceTotal*: uint64
|
||||
attachedValidatorBalanceTotal*: Gwei
|
||||
gossipState*: GossipState
|
||||
blocksGossipState*: GossipState
|
||||
beaconClock*: BeaconClock
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -103,7 +103,7 @@ type
|
||||
indices*: Table[Eth2Digest, Index]
|
||||
currentEpochTips*: Table[Index, FinalityCheckpoints]
|
||||
previousProposerBoostRoot*: Eth2Digest
|
||||
previousProposerBoostScore*: uint64
|
||||
previousProposerBoostScore*: Gwei
|
||||
|
||||
ProtoNode* = object
|
||||
bid*: BlockId
|
||||
|
@ -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:
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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].} =
|
||||
|
@ -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,
|
||||
|
@ -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*(
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
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: uint64,
|
||||
finality_delay: uint64): RewardDelta =
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]))
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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(
|
||||
|
@ -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 = {}
|
||||
)
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user