improve slot processing speeds (#1670)

about 40% better slot processing times (with LTO enabled) - these don't
do BLS but are used
heavily during replay (state transition = slot + block transition)

tests using a recent medalla state and advancing it 1000 slots:

```
./ncli slots --preState2:state-302271-3c1dbf19-c1f944bf.ssz --slot:1000
--postState2:xx.ssz
```
pre:

```

All time are ms
Average,       StdDev,          Min,          Max,      Samples,
Test
Validation is turned off meaning that no BLS operations are performed
39.236,        0.000,       39.236,       39.236,            1,
Load state from file
0.049,        0.002,        0.046,        0.063,          968,
Apply slot
256.504,       81.008,      213.471,      591.902,           32,
Apply epoch slot
28.597,        0.000,       28.597,       28.597,            1,
Save state to file
```

cast:
```
All time are ms
Average,       StdDev,          Min,          Max,      Samples,
Test
Validation is turned off meaning that no BLS operations are performed
37.079,        0.000,       37.079,       37.079,            1,
Load state from file
0.042,        0.002,        0.040,        0.090,          968,
Apply slot
215.552,       68.763,      180.155,      500.103,           32,
Apply epoch slot
25.106,        0.000,       25.106,       25.106,            1,
Save state to file
```

cast+rewards:
```
All time are ms
Average,       StdDev,          Min,          Max,      Samples,
Test
Validation is turned off meaning that no BLS operations are performed
40.049,        0.000,       40.049,       40.049,            1,
Load state from file
0.048,        0.001,        0.045,        0.060,          968,
Apply slot
164.981,       76.273,      142.099,      477.868,           32,
Apply epoch slot
28.498,        0.000,       28.498,       28.498,            1,
Save state to file
```

cast+rewards+shr
```
All time are ms
Average,       StdDev,          Min,          Max,      Samples,
Test
Validation is turned off meaning that no BLS operations are performed
12.898,        0.000,       12.898,       12.898,            1,
Load state from file
0.039,        0.002,        0.038,        0.054,          968,
Apply slot
139.971,       68.797,      120.088,      428.844,           32,
Apply epoch slot
24.761,        0.000,       24.761,       24.761,            1,
Save state to file

```
This commit is contained in:
Jacek Sieka 2020-09-16 22:59:33 +02:00 committed by GitHub
parent ce85f58d29
commit dcf8a6b05d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 86 deletions

View File

@ -43,7 +43,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ Reverse order block add & get [Preset: mainnet] OK + Reverse order block add & get [Preset: mainnet] OK
+ Simple block add&get [Preset: mainnet] OK + Simple block add&get [Preset: mainnet] OK
+ getRef returns nil for missing blocks OK + getRef returns nil for missing blocks OK
+ loadTailState gets genesis block on first load [Preset: mainnet] OK + loading tail block works [Preset: mainnet] OK
+ updateHead updates head and headState [Preset: mainnet] OK + updateHead updates head and headState [Preset: mainnet] OK
+ updateStateData sanity [Preset: mainnet] OK + updateStateData sanity [Preset: mainnet] OK
``` ```
@ -173,6 +173,7 @@ OK: 52/59 Fail: 0/59 Skip: 7/59
+ Access peers by key test OK + Access peers by key test OK
+ Acquire from empty pool OK + Acquire from empty pool OK
+ Acquire/Sorting and consistency test OK + Acquire/Sorting and consistency test OK
+ Delete peer on release text OK
+ Iterators test OK + Iterators test OK
+ Peer lifetime test OK + Peer lifetime test OK
+ Safe/Clear test OK + Safe/Clear test OK
@ -181,7 +182,7 @@ OK: 52/59 Fail: 0/59 Skip: 7/59
+ addPeerNoWait() test OK + addPeerNoWait() test OK
+ deletePeer() test OK + deletePeer() test OK
``` ```
OK: 10/10 Fail: 0/10 Skip: 0/10 OK: 11/11 Fail: 0/11 Skip: 0/11
## SSZ dynamic navigator ## SSZ dynamic navigator
```diff ```diff
+ navigating fields OK + navigating fields OK
@ -253,4 +254,4 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
OK: 1/1 Fail: 0/1 Skip: 0/1 OK: 1/1 Fail: 0/1 Skip: 0/1
---TOTAL--- ---TOTAL---
OK: 136/143 Fail: 0/143 Skip: 7/143 OK: 137/144 Fail: 0/144 Skip: 7/144

View File

@ -241,18 +241,19 @@ proc process_justification_and_finalization*(state: var BeaconState,
checkpoint = shortLog(state.finalized_checkpoint) checkpoint = shortLog(state.finalized_checkpoint)
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#helpers # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#helpers
func get_base_reward(state: BeaconState, index: ValidatorIndex, func get_base_reward_sqrt(state: BeaconState, index: ValidatorIndex,
total_balance: auto): Gwei = total_balance_sqrt: auto): Gwei =
# Spec function recalculates total_balance every time, which creates an # Spec function recalculates total_balance every time, which creates an
# O(n^2) situation. # O(n^2) situation.
let effective_balance = state.validators[index].effective_balance let effective_balance = state.validators[index].effective_balance
effective_balance * BASE_REWARD_FACTOR div effective_balance * BASE_REWARD_FACTOR div
integer_squareroot(total_balance) div BASE_REWARDS_PER_EPOCH total_balance_sqrt div BASE_REWARDS_PER_EPOCH
func get_proposer_reward(state: BeaconState, attesting_index: ValidatorIndex, func get_proposer_reward_sqrt(state: BeaconState, attesting_index: ValidatorIndex,
total_balance: Gwei): Gwei = total_balance_sqrt: Gwei): Gwei =
# Spec version recalculates get_total_active_balance(state) quadratically # Spec version recalculates get_total_active_balance(state) quadratically
get_base_reward(state, attesting_index, total_balance) div PROPOSER_REWARD_QUOTIENT get_base_reward_sqrt(state, attesting_index, total_balance_sqrt) div
PROPOSER_REWARD_QUOTIENT
func get_finality_delay(state: BeaconState): uint64 = func get_finality_delay(state: BeaconState): uint64 =
get_previous_epoch(state) - state.finalized_checkpoint.epoch get_previous_epoch(state) - state.finalized_checkpoint.epoch
@ -271,17 +272,16 @@ iterator get_eligible_validator_indices(state: BeaconState): ValidatorIndex =
func get_attestation_component_deltas(state: BeaconState, func get_attestation_component_deltas(state: BeaconState,
attestations: seq[PendingAttestation], attestations: seq[PendingAttestation],
total_balance: Gwei, total_balance: Gwei,
rewards, penalties: var seq[Gwei],
cache: var StateCache, cache: var StateCache,
): tuple[a: seq[Gwei], b: seq[Gwei]] = ) =
# Helper with shared logic for use by get source, target, and head deltas # Helper with shared logic for use by get source, target, and head deltas
# functions # functions
var
rewards = repeat(0'u64, len(state.validators))
penalties = repeat(0'u64, len(state.validators))
let let
unslashed_attesting_indices = unslashed_attesting_indices =
get_unslashed_attesting_indices(state, attestations, cache) get_unslashed_attesting_indices(state, attestations, cache)
attesting_balance = get_total_balance(state, unslashed_attesting_indices) attesting_balance = get_total_balance(state, unslashed_attesting_indices)
total_balance_sqrt = integer_squareroot(total_balance)
for index in get_eligible_validator_indices(state): for index in get_eligible_validator_indices(state):
if index in unslashed_attesting_indices: if index in unslashed_attesting_indices:
@ -291,50 +291,50 @@ func get_attestation_component_deltas(state: BeaconState,
if is_in_inactivity_leak(state): if is_in_inactivity_leak(state):
# Since full base reward will be canceled out by inactivity penalty deltas, # Since full base reward will be canceled out by inactivity penalty deltas,
# optimal participation receives full base reward compensation here. # optimal participation receives full base reward compensation here.
rewards[index] += get_base_reward(state, index, total_balance) rewards[index] += get_base_reward_sqrt(state, index, total_balance_sqrt)
else: else:
let reward_numerator = get_base_reward(state, index, total_balance) * (attesting_balance div increment) let reward_numerator = get_base_reward_sqrt(state, index, total_balance_sqrt) *
(attesting_balance div increment)
rewards[index] += reward_numerator div (total_balance div increment) rewards[index] += reward_numerator div (total_balance div increment)
else: else:
penalties[index] += get_base_reward(state, index, total_balance) penalties[index] += get_base_reward_sqrt(state, index, total_balance_sqrt)
(rewards, penalties)
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#components-of-attestation-deltas # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#components-of-attestation-deltas
# These is slightly refactored to calculate total_balance once. # These is slightly refactored to calculate total_balance once.
func get_source_deltas*( func get_source_deltas*(
state: BeaconState, total_balance: Gwei, cache: var StateCache): state: BeaconState, total_balance: Gwei, rewards, penalties: var seq[Gwei],
tuple[a: seq[Gwei], b: seq[Gwei]] = cache: var StateCache) =
## Return attester micro-rewards/penalties for source-vote for each validator. ## Return attester micro-rewards/penalties for source-vote for each validator.
get_attestation_component_deltas( get_attestation_component_deltas(
state, state,
get_matching_source_attestations(state, get_previous_epoch(state)), get_matching_source_attestations(state, get_previous_epoch(state)),
total_balance, cache) total_balance, rewards, penalties, cache)
func get_target_deltas*( func get_target_deltas*(
state: BeaconState, total_balance: Gwei, cache: var StateCache): state: BeaconState, total_balance: Gwei, rewards, penalties: var seq[Gwei],
tuple[a: seq[Gwei], b: seq[Gwei]] = cache: var StateCache) =
## Return attester micro-rewards/penalties for target-vote for each validator. ## Return attester micro-rewards/penalties for target-vote for each validator.
let matching_target_attestations = let matching_target_attestations =
get_matching_target_attestations(state, get_previous_epoch(state)) get_matching_target_attestations(state, get_previous_epoch(state))
get_attestation_component_deltas( get_attestation_component_deltas(
state, matching_target_attestations, total_balance, cache) state, matching_target_attestations, total_balance, rewards, penalties,
cache)
func get_head_deltas*( func get_head_deltas*(
state: BeaconState, total_balance: Gwei, cache: var StateCache): state: BeaconState, total_balance: Gwei, rewards, penalties: var seq[Gwei],
tuple[a: seq[Gwei], b: seq[Gwei]] = cache: var StateCache) =
## Return attester micro-rewards/penalties for head-vote for each validator. ## Return attester micro-rewards/penalties for head-vote for each validator.
let matching_head_attestations = let matching_head_attestations =
get_matching_head_attestations(state, get_previous_epoch(state)) get_matching_head_attestations(state, get_previous_epoch(state))
get_attestation_component_deltas( get_attestation_component_deltas(
state, matching_head_attestations, total_balance, cache) state, matching_head_attestations, total_balance, rewards, penalties, cache)
func get_inclusion_delay_deltas*( func get_inclusion_delay_deltas*(
state: BeaconState, total_balance: Gwei, cache: var StateCache): state: BeaconState, total_balance: Gwei, rewards: var seq[Gwei],
seq[Gwei] = cache: var StateCache) =
## Return proposer and inclusion delay micro-rewards/penalties for each validator. ## Return proposer and inclusion delay micro-rewards/penalties for each validator.
var var
rewards = repeat(0'u64, len(state.validators))
matching_source_attestations = matching_source_attestations =
get_matching_source_attestations(state, get_previous_epoch(state)) get_matching_source_attestations(state, get_previous_epoch(state))
@ -351,9 +351,11 @@ func get_inclusion_delay_deltas*(
cmp(x.inclusion_delay, y.inclusion_delay) cmp(x.inclusion_delay, y.inclusion_delay)
# Order/indices in source_attestation_attesting_indices matches sorted order # Order/indices in source_attestation_attesting_indices matches sorted order
let source_attestation_attesting_indices = mapIt( let
source_attestation_attesting_indices = mapIt(
matching_source_attestations, matching_source_attestations,
get_attesting_indices(state, it.data, it.aggregation_bits, cache)) get_attesting_indices(state, it.data, it.aggregation_bits, cache))
total_balance_sqrt = integer_squareroot(total_balance)
for index in get_unslashed_attesting_indices( for index in get_unslashed_attesting_indices(
state, matching_source_attestations, cache): state, matching_source_attestations, cache):
@ -361,35 +363,31 @@ func get_inclusion_delay_deltas*(
if index in if index in
source_attestation_attesting_indices[source_attestation_index]: source_attestation_attesting_indices[source_attestation_index]:
rewards[attestation.proposer_index] += rewards[attestation.proposer_index] +=
get_proposer_reward(state, index, total_balance) get_proposer_reward_sqrt(state, index, total_balance_sqrt)
let max_attester_reward = let max_attester_reward =
get_base_reward(state, index, total_balance) - get_base_reward_sqrt(state, index, total_balance_sqrt) -
get_proposer_reward(state, index, total_balance) get_proposer_reward_sqrt(state, index, total_balance_sqrt)
rewards[index] += rewards[index] +=
Gwei(max_attester_reward div attestation.inclusion_delay) Gwei(max_attester_reward div attestation.inclusion_delay)
break break
# No penalties associated with inclusion delay
# Spec constructs both and returns both; this doesn't
rewards
func get_inactivity_penalty_deltas*( func get_inactivity_penalty_deltas*(
state: BeaconState, total_balance: Gwei, cache: var StateCache): state: BeaconState, total_balance: Gwei, penalties: var seq[Gwei],
seq[Gwei] = cache: var StateCache) =
## Return inactivity reward/penalty deltas for each validator. ## Return inactivity reward/penalty deltas for each validator.
var penalties = repeat(0'u64, len(state.validators))
if is_in_inactivity_leak(state): if is_in_inactivity_leak(state):
let let
matching_target_attestations = matching_target_attestations =
get_matching_target_attestations(state, get_previous_epoch(state)) get_matching_target_attestations(state, get_previous_epoch(state))
matching_target_attesting_indices = matching_target_attesting_indices =
get_unslashed_attesting_indices(state, matching_target_attestations, cache) get_unslashed_attesting_indices(state, matching_target_attestations, cache)
total_balance_sqrt = integer_squareroot(total_balance)
for index in get_eligible_validator_indices(state): for index in get_eligible_validator_indices(state):
# If validator is performing optimally this cancels all rewards for a neutral balance # If validator is performing optimally this cancels all rewards for a neutral balance
let base_reward = get_base_reward(state, index, total_balance) let base_reward = get_base_reward_sqrt(state, index, total_balance_sqrt)
penalties[index] += penalties[index] +=
Gwei(BASE_REWARDS_PER_EPOCH * base_reward - Gwei(BASE_REWARDS_PER_EPOCH * base_reward -
get_proposer_reward(state, index, total_balance)) get_proposer_reward_sqrt(state, index, total_balance_sqrt))
# matching_target_attesting_indices is a HashSet # matching_target_attesting_indices is a HashSet
if index notin matching_target_attesting_indices: if index notin matching_target_attesting_indices:
let effective_balance = state.validators[index].effective_balance let effective_balance = state.validators[index].effective_balance
@ -397,36 +395,20 @@ func get_inactivity_penalty_deltas*(
Gwei(effective_balance * get_finality_delay(state) div Gwei(effective_balance * get_finality_delay(state) div
INACTIVITY_PENALTY_QUOTIENT) INACTIVITY_PENALTY_QUOTIENT)
# No rewards associated with inactivity penalties
# Spec constructs rewards anyway; this doesn't
penalties
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#get_attestation_deltas # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#get_attestation_deltas
func get_attestation_deltas(state: BeaconState, cache: var StateCache): func get_attestation_deltas(
tuple[a: seq[Gwei], b: seq[Gwei]] = state: BeaconState, rewards, penalties: var seq[Gwei],
cache: var StateCache) =
## Return attestation reward/penalty deltas for each validator. ## Return attestation reward/penalty deltas for each validator.
let let
total_balance = get_total_active_balance(state, cache) total_balance = get_total_active_balance(state, cache)
(source_rewards, source_penalties) =
get_source_deltas(state, total_balance, cache)
(target_rewards, target_penalties) =
get_target_deltas(state, total_balance, cache)
(head_rewards, head_penalties) =
get_head_deltas(state, total_balance, cache)
inclusion_delay_rewards =
get_inclusion_delay_deltas(state, total_balance, cache)
inactivity_penalties =
get_inactivity_penalty_deltas(state, total_balance, cache)
let rewards = mapIt(0 ..< len(state.validators),
source_rewards[it] + target_rewards[it] + head_rewards[it] +
inclusion_delay_rewards[it])
let penalties = mapIt(0 ..< len(state.validators), get_source_deltas(state, total_balance, rewards, penalties, cache)
source_penalties[it] + target_penalties[it] + head_penalties[it] + get_target_deltas(state, total_balance, rewards, penalties, cache)
inactivity_penalties[it]) get_head_deltas(state, total_balance, rewards, penalties, cache)
get_inclusion_delay_deltas(state, total_balance, rewards, cache)
(rewards, penalties) get_inactivity_penalty_deltas(state, total_balance, penalties, cache)
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#process_rewards_and_penalties # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#process_rewards_and_penalties
func process_rewards_and_penalties( func process_rewards_and_penalties(
@ -434,7 +416,10 @@ func process_rewards_and_penalties(
if get_current_epoch(state) == GENESIS_EPOCH: if get_current_epoch(state) == GENESIS_EPOCH:
return return
let (rewards, penalties) = get_attestation_deltas(state, cache) var
rewards = newSeq[uint64](len(state.validators))
penalties = newSeq[uint64](len(state.validators))
get_attestation_deltas(state, rewards, penalties, cache)
for i in 0 ..< len(state.validators): for i in 0 ..< len(state.validators):
increase_balance(state, i.ValidatorIndex, rewards[i]) increase_balance(state, i.ValidatorIndex, rewards[i])

View File

@ -147,9 +147,13 @@ template isCached*(v: Eth2Digest): bool =
## An entry is "in the cache" if the first 8 bytes are zero - conveniently, ## An entry is "in the cache" if the first 8 bytes are zero - conveniently,
## Nim initializes values this way, and while there may be false positives, ## Nim initializes values this way, and while there may be false positives,
## that's fine. ## that's fine.
v.data.toOpenArray(0, 7) != [byte 0, 0, 0, 0, 0, 0, 0, 0]
# Checking and resetting the cache status are hotspots - profile before
# touching!
cast[ptr uint64](unsafeAddr v.data[0])[] != 0 # endian safe
template clearCache*(v: var Eth2Digest) = template clearCache*(v: var Eth2Digest) =
v.data[0..<8] = [byte 0, 0, 0, 0, 0, 0, 0, 0] cast[ptr uint64](addr v.data[0])[] = 0 # endian safe
template maxChunks*(a: HashList|HashArray): int64 = template maxChunks*(a: HashList|HashArray): int64 =
## Layer where data is ## Layer where data is
@ -164,10 +168,10 @@ template chunkIdx(a: HashList|HashArray, dataIdx: int64): int64 =
proc clearCaches*(a: var HashArray, dataIdx: auto) = proc clearCaches*(a: var HashArray, dataIdx: auto) =
## Clear all cache entries after data at dataIdx has been modified ## Clear all cache entries after data at dataIdx has been modified
var idx = 1 shl (a.maxDepth - 1) + (chunkIdx(a, dataIdx) div 2) var idx = 1 shl (a.maxDepth - 1) + (chunkIdx(a, dataIdx) shr 1)
while idx != 0: while idx != 0:
clearCache(a.hashes[idx]) clearCache(a.hashes[idx])
idx = idx div 2 idx = idx shr 1
func nodesAtLayer*(layer, depth, leaves: int): int = func nodesAtLayer*(layer, depth, leaves: int): int =
## Given a number of leaves, how many nodes do you need at a given layer ## Given a number of leaves, how many nodes do you need at a given layer
@ -188,7 +192,7 @@ proc clearCaches*(a: var HashList, dataIdx: int64) =
return return
var var
idx = 1'i64 shl (a.maxDepth - 1) + (chunkIdx(a, dataIdx) div 2) idx = 1'i64 shl (a.maxDepth - 1) + (chunkIdx(a, dataIdx) shr 1)
layer = a.maxDepth - 1 layer = a.maxDepth - 1
while idx > 0: while idx > 0:
let let
@ -197,7 +201,7 @@ proc clearCaches*(a: var HashList, dataIdx: int64) =
if layerIdx < a.indices[layer + 1]: if layerIdx < a.indices[layer + 1]:
clearCache(a.hashes[layerIdx]) clearCache(a.hashes[layerIdx])
idx = idx div 2 idx = idx shr 1
layer = layer - 1 layer = layer - 1
clearCache(a.hashes[0]) clearCache(a.hashes[0])

View File

@ -1,7 +1,9 @@
import import
confutils, chronicles, os, strutils, json_serialization, std/[os, strutils, stats],
confutils, chronicles, json_serialization,
stew/byteutils, stew/byteutils,
../beacon_chain/spec/[crypto, datatypes, digest, state_transition], ../research/simutils,
../beacon_chain/spec/[crypto, datatypes, digest, helpers, state_transition],
../beacon_chain/extras, ../beacon_chain/extras,
../beacon_chain/network_metadata, ../beacon_chain/network_metadata,
../beacon_chain/ssz/[merkleization, ssz_serialization] ../beacon_chain/ssz/[merkleization, ssz_serialization]
@ -11,6 +13,7 @@ type
hashTreeRoot = "Compute hash tree root of SSZ object" hashTreeRoot = "Compute hash tree root of SSZ object"
pretty = "Pretty-print SSZ object" pretty = "Pretty-print SSZ object"
transition = "Run state transition function" transition = "Run state transition function"
slots = "Apply empty slots"
NcliConf* = object NcliConf* = object
@ -57,6 +60,19 @@ type
desc: "Verify state root (default true)" desc: "Verify state root (default true)"
defaultValue: true}: bool defaultValue: true}: bool
of slots:
preState2* {.
argument
desc: "State to which to apply specified block"}: string
slot* {.
argument
desc: "Block to apply to preState"}: uint64
postState2* {.
argument
desc: "Filename of state resulting from applying blck to preState"}: string
proc doTransition(conf: NcliConf) = proc doTransition(conf: NcliConf) =
let let
stateY = (ref HashedBeaconState)( stateY = (ref HashedBeaconState)(
@ -74,12 +90,39 @@ proc doTransition(conf: NcliConf) =
else: else:
SSZ.saveFile(conf.postState, stateY.data) SSZ.saveFile(conf.postState, stateY.data)
proc doSlots(conf: NcliConf) =
type
Timers = enum
tLoadState = "Load state from file"
tApplySlot = "Apply slot"
tApplyEpochSlot = "Apply epoch slot"
tSaveState = "Save state to file"
var timers: array[Timers, RunningStat]
let
stateY = withTimerRet(timers[tLoadState]): (ref HashedBeaconState)(
data: SSZ.loadFile(conf.preState2, BeaconState),
)
stateY.root = hash_tree_root(stateY.data)
var cache: StateCache
for i in 0'u64..<conf.slot:
let isEpoch = (stateY[].data.slot + 1).isEpoch
withTimer(timers[if isEpoch: tApplyEpochSlot else: tApplySlot]):
advance_slot(stateY[], {}, cache)
withTimer(timers[tSaveState]):
SSZ.saveFile(conf.postState, stateY.data)
printTimers(false, timers)
proc doSSZ(conf: NcliConf) = proc doSSZ(conf: NcliConf) =
let (kind, file) = let (kind, file) =
case conf.cmd: case conf.cmd:
of hashTreeRoot: (conf.htrKind, conf.htrFile) of hashTreeRoot: (conf.htrKind, conf.htrFile)
of pretty: (conf.prettyKind, conf.prettyFile) of pretty: (conf.prettyKind, conf.prettyFile)
of transition: else:
raiseAssert "doSSZ() only implements hashTreeRoot and pretty commands" raiseAssert "doSSZ() only implements hashTreeRoot and pretty commands"
template printit(t: untyped) {.dirty.} = template printit(t: untyped) {.dirty.} =
@ -101,7 +144,7 @@ proc doSSZ(conf: NcliConf) =
echo hash_tree_root(v[]).data.toHex() echo hash_tree_root(v[]).data.toHex()
of pretty: of pretty:
echo JSON.encode(v[], pretty = true) echo JSON.encode(v[], pretty = true)
of transition: else:
raiseAssert "doSSZ() only implements hashTreeRoot and pretty commands" raiseAssert "doSSZ() only implements hashTreeRoot and pretty commands"
let ext = splitFile(file).ext let ext = splitFile(file).ext
@ -127,3 +170,4 @@ when isMainModule:
of hashTreeRoot: doSSZ(conf) of hashTreeRoot: doSSZ(conf)
of pretty: doSSZ(conf) of pretty: doSSZ(conf)
of transition: doTransition(conf) of transition: doTransition(conf)
of slots: doSlots(conf)

View File

@ -54,14 +54,24 @@ proc runTest(identifier: string) =
inactivityPenaltyDeltas = inactivityPenaltyDeltas =
parseTest(testDir/"inactivity_penalty_deltas.ssz", SSZ, Deltas) parseTest(testDir/"inactivity_penalty_deltas.ssz", SSZ, Deltas)
template get_deltas(body: untyped): untyped =
var
rewards {.inject.} = newSeq[Gwei](state[].validators.len)
penalties {.inject.} = newSeq[Gwei](state[].validators.len)
body
(rewards, penalties)
check: check:
compareDeltas(sourceDeltas, get_source_deltas(state[], total_balance, cache)) compareDeltas(sourceDeltas, get_deltas(
compareDeltas(targetDeltas, get_target_deltas(state[], total_balance, cache)) get_source_deltas(state[], total_balance, rewards, penalties, cache)))
compareDeltas(headDeltas, get_head_deltas(state[], total_balance, cache)) compareDeltas(targetDeltas, get_deltas(
inclusionDelayDeltas.rewards.asSeq == get_target_deltas(state[], total_balance, rewards, penalties, cache)))
get_inclusion_delay_deltas(state[], total_balance, cache) compareDeltas(headDeltas, get_deltas(
inactivityPenaltyDeltas.penalties.asSeq == get_head_deltas(state[], total_balance, rewards, penalties, cache)))
get_inactivity_penalty_deltas(state[], total_balance, cache) compareDeltas(inclusionDelayDeltas, get_deltas(
get_inclusion_delay_deltas(state[], total_balance, rewards, cache)))
compareDeltas(inactivityPenaltyDeltas, get_deltas(
get_inactivity_penalty_deltas(state[], total_balance, penalties, cache)))
`testImpl _ rewards _ identifier`() `testImpl _ rewards _ identifier`()