Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
541d640
chore: use tree view data pointers
wemeetagain Jan 8, 2026
0cdc10d
wip
wemeetagain Jan 8, 2026
587963b
fix: fix duplicate conflict syncCommitteeCache
GrapeBaBa Jan 9, 2026
e24495a
fix: fix missing pmt module in the state transition
GrapeBaBa Jan 9, 2026
adf0ccb
fix: add missing pool arg
GrapeBaBa Jan 9, 2026
3a36ba6
fix: fix generate_state test using treeview
GrapeBaBa Jan 9, 2026
60047f3
fix: fix seed isPostElectra migration
GrapeBaBa Jan 9, 2026
ba879cb
fix: fix beacon state get const ptr
GrapeBaBa Jan 9, 2026
ee58135
fix: fix generate_state test using setValue and getAllInto
GrapeBaBa Jan 9, 2026
9ddcb52
fix: fix fork epoch in the generate state
GrapeBaBa Jan 9, 2026
6807f23
fix: fix error union mismatch
GrapeBaBa Jan 9, 2026
2c10c6c
feat: add getAllReadonlyValues for array/list tree view
GrapeBaBa Jan 9, 2026
781d24f
fix: fix epoch cache get validators
GrapeBaBa Jan 9, 2026
2348644
fix: fix epoch cache issue
GrapeBaBa Jan 9, 2026
8ba1771
fix: fix several using tree view error
GrapeBaBa Jan 9, 2026
128b266
fix: processSlashings
wemeetagain Jan 9, 2026
76fa3c3
fix: processRewardsAndPenalties
wemeetagain Jan 9, 2026
5e8fcc6
fix: processRegistryUpdates
wemeetagain Jan 9, 2026
96bb17b
fix: processRandaoMixesReset
wemeetagain Jan 9, 2026
da46fde
fix: partially fix processProposerLookahead
wemeetagain Jan 9, 2026
cd5b954
fix: more processProposerLookahead
wemeetagain Jan 9, 2026
a0d7dd5
Merge remote-tracking branch 'origin/main' into tree-view-state
wemeetagain Jan 10, 2026
68a1b85
feat: add ListTreeView.iteratorReadonly
wemeetagain Jan 12, 2026
b019231
fix: processPendingDeposits
wemeetagain Jan 12, 2026
60fc413
fix: add electra/fulu in beacon execution payload
GrapeBaBa Jan 12, 2026
e2fb0aa
fix: fix beacon state test
GrapeBaBa Jan 12, 2026
524d58f
fix: fix state transition block
GrapeBaBa Jan 12, 2026
c4208b6
fix: fix state transition block issue
GrapeBaBa Jan 12, 2026
936ec93
fix: processPendingConsolidations
wemeetagain Jan 12, 2026
d1ad229
fix: processParticipationFlagUpdates
wemeetagain Jan 12, 2026
28b79ee
fix: processJustificationAndFinalization
wemeetagain Jan 12, 2026
0ac1ca0
fix: processInactivityUpdates
wemeetagain Jan 12, 2026
d353978
fix: processHistoricalSummariesUpdate
wemeetagain Jan 12, 2026
ad28b61
fix: processHistoricalRootsUpdate
wemeetagain Jan 12, 2026
02f2279
fix: processEth1DataReset
wemeetagain Jan 12, 2026
dfe5085
fix: processEffectiveBalanceUpdates
wemeetagain Jan 12, 2026
12602f5
fix: processEpoch
wemeetagain Jan 12, 2026
b59448f
feat: update TreeView.hashTreeRoot signature (return root const pointer)
wemeetagain Jan 12, 2026
27cefab
fix: stateTransition
wemeetagain Jan 12, 2026
619b003
fix: stray hashTreeRoot fixes
wemeetagain Jan 12, 2026
ddf127d
chore: remove interior mutability
wemeetagain Jan 12, 2026
7031c15
fix: start on sanity spec tests
wemeetagain Jan 12, 2026
22bf3c3
fix: fix state_transition test
GrapeBaBa Jan 13, 2026
fbd1dcf
fix: fix era treeview test
GrapeBaBa Jan 13, 2026
ef5c22f
fix: fix spec test unalign issue related to ownership
GrapeBaBa Jan 13, 2026
68d4a5f
fix: fix children nodes and datas cache not consistent
GrapeBaBa Jan 13, 2026
885f275
fix: fix skipped slots spec test
GrapeBaBa Jan 13, 2026
74c3e83
fix: remove debug log
GrapeBaBa Jan 13, 2026
b0ce31a
fix: various fixes
wemeetagain Jan 13, 2026
58f0cf8
fix: fix the phase0 epoch spec test
GrapeBaBa Jan 14, 2026
af8719b
fix: fix operation spec test
GrapeBaBa Jan 14, 2026
2b9582f
fix: fix finality spec test
GrapeBaBa Jan 14, 2026
5cce078
fix: fix random spec test
GrapeBaBa Jan 14, 2026
fe28bc6
fix: fix the phase0 fork spec test
GrapeBaBa Jan 14, 2026
f357119
fix: using setrootnode instead of transfer ownership
GrapeBaBa Jan 14, 2026
6f2294d
fix: fix altiar spec test
GrapeBaBa Jan 14, 2026
bd62993
fix: more spec test fixes
wemeetagain Jan 14, 2026
aad9fea
fix: simplify tree view semantics
wemeetagain Jan 14, 2026
c9527ae
fix: add TreeView.getReadonly behavior
wemeetagain Jan 14, 2026
03acfe3
fix: fixup becomesNewEth1Data
wemeetagain Jan 14, 2026
1b344f9
fix: bench_process_block
wemeetagain Jan 14, 2026
3a87de4
Merge branch 'main' into tree-view-state
GrapeBaBa Jan 15, 2026
e3303b4
fix: fix tests
GrapeBaBa Jan 15, 2026
caea327
refactor: make bench process epoch works
GrapeBaBa Jan 15, 2026
dbcd8c2
fix: fix lint
GrapeBaBa Jan 15, 2026
f034c58
fix: remove stray constCasts
wemeetagain Jan 15, 2026
ee69250
chore: use DebugAllocator in benchmarks
wemeetagain Jan 15, 2026
e1b9275
fix: illegal instruction
wemeetagain Jan 15, 2026
7464392
chore: minor tweaks
wemeetagain Jan 15, 2026
818e484
chore: commit state if verify_state_root = false
wemeetagain Jan 15, 2026
d273827
fix: slot check in processSlots
wemeetagain Jan 15, 2026
8f27a4c
chore: rename processSlots
wemeetagain Jan 15, 2026
9fb83a5
chore: fix bls wrapper test
wemeetagain Jan 15, 2026
5b1a961
chore: apply suggestions from code review
wemeetagain Jan 16, 2026
f7ee63b
fix: build errors
wemeetagain Jan 16, 2026
8990d8c
feat: rotateSyncCommittees
wemeetagain Jan 16, 2026
467e5ca
chore: more pr review
wemeetagain Jan 16, 2026
ad8b6ce
feat: add ssz.Type.default_root
wemeetagain Jan 9, 2026
bfd0c6a
feat: add ST.tree.default and ListST.tree.zeros
wemeetagain Jan 16, 2026
4e4dc56
chore: use EpochParticipation.tree.zeros to rotate epoch participation
wemeetagain Jan 16, 2026
7acc7d0
feat: BeaconState.balancesSlice
wemeetagain Jan 16, 2026
88d4f51
chore: remove allocator from processConsolidationRequest
wemeetagain Jan 16, 2026
30d8cca
chore: clean up processRandao
wemeetagain Jan 16, 2026
e66590c
chore: clean up BeaconState.populateFields
wemeetagain Jan 16, 2026
ac05476
chore: remove stale comment
wemeetagain Jan 16, 2026
12d3082
fix: errdefer remove dangling undefined in BaseTreeView.getChildDataR…
wemeetagain Jan 16, 2026
d10e670
chore: more comments on ListView.iteratorReadonly
wemeetagain Jan 16, 2026
0c70743
chore: use TreeView.getValue(out) pattern
wemeetagain Jan 16, 2026
be91097
chore: fix build errors
wemeetagain Jan 16, 2026
1fff4f1
fix: fix spec test failed
GrapeBaBa Jan 18, 2026
3ee0cc3
wip
wemeetagain Jan 20, 2026
f389502
feat: add slashed cache and use it in process_attestation
GrapeBaBa Jan 20, 2026
f300170
feat: add slashed cache and use it in process_attestation
GrapeBaBa Jan 20, 2026
d2a39ff
feat: track slashed flags per CachedBeaconState
GrapeBaBa Jan 20, 2026
bb778f1
Merge remote-tracking branch 'origin/gr/slashed_cache' into gr/slashe…
GrapeBaBa Jan 20, 2026
4b2fd98
wip
wemeetagain Jan 20, 2026
1bd6cab
chore: remove unused imports
GrapeBaBa Jan 21, 2026
8c2b1dd
refactor: move beacon_state to fork types to prepare refactor
GrapeBaBa Jan 21, 2026
b80bba7
refactor: change some processXX to use comptime fork
GrapeBaBa Jan 21, 2026
1e37e44
refactor: continue change func using comptime fork
GrapeBaBa Jan 21, 2026
011ea81
chore: fork_types tweaks
wemeetagain Jan 21, 2026
064c413
chore: more processXX updates, top-level stateTransition update
wemeetagain Jan 21, 2026
a13ffb1
Merge main (int tests migration)
GrapeBaBa Jan 22, 2026
ab58507
refactor: continue use comptimee fork
GrapeBaBa Jan 22, 2026
1876bfe
refactor: continue to use comptime fork
GrapeBaBa Jan 22, 2026
600beaa
refactor: continue translate functions using comptime fork
GrapeBaBa Jan 22, 2026
a689e5f
chore: continue refactor
wemeetagain Jan 22, 2026
fbbb1a3
fix: fix state transition test
GrapeBaBa Jan 23, 2026
71b16d8
fix: fix spec test
GrapeBaBa Jan 23, 2026
a951492
fix: fix build compile error
GrapeBaBa Jan 23, 2026
8616e50
fix: fix bench
GrapeBaBa Jan 23, 2026
9f754ff
chore: use `ForkBeaconBlockBody` in stf util
GrapeBaBa Jan 25, 2026
b856f10
Merge branch 'main' into comptime-fork
wemeetagain Jan 26, 2026
54623fd
chore: bring CachedBeaconState back to top-level stfn
wemeetagain Jan 26, 2026
cae6099
fix: fix the spec and bench tests
GrapeBaBa Jan 27, 2026
8c805a1
Merge branch 'comptime-fork' into gr/slashed_cache
GrapeBaBa Jan 28, 2026
2791109
refactor: optimize slash cache rebuild
GrapeBaBa Jan 29, 2026
911432f
merge: origin/main
GrapeBaBa Jan 30, 2026
a4c6257
fix: fix merge error
GrapeBaBa Jan 30, 2026
4e989ff
chore: refactor the cache build
GrapeBaBa Jan 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bench/state_transition/process_block.zig
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ fn ProcessOperationsBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type
cloned.config,
cloned.getEpochCache(),
cloned.state.castToFork(fork),
&cloned.slashings_cache,
.full,
self.body,
.{ .verify_signature = opts.verify_signature },
Expand Down Expand Up @@ -237,6 +238,7 @@ fn ProcessBlockBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
cloned.config,
cloned.getEpochCache(),
cloned.state.castToFork(fork),
&cloned.slashings_cache,
.full,
self.block,
external_data,
Expand Down Expand Up @@ -401,6 +403,7 @@ fn ProcessBlockSegmentedBench(comptime fork: ForkSeq) type {
cloned.config,
epoch_cache,
state,
&cloned.slashings_cache,
.full,
self.body,
.{ .verify_signature = true },
Expand Down Expand Up @@ -506,6 +509,7 @@ fn runBenchmark(comptime fork: ForkSeq, allocator: std.mem.Allocator, pool: *Nod
.{},
);
try cached_state.state.commit();
try state_transition.buildSlashingsCacheFromStateIfNeeded(allocator, cached_state.state, &cached_state.slashings_cache);
try stdout.print("State: slot={}, validators={}\n", .{ try cached_state.state.slot(), try beacon_state.validatorsCount() });

var bench = zbench.Benchmark.init(allocator, .{
Expand Down
7 changes: 3 additions & 4 deletions src/state_transition/block/process_attestation_altair.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ForkSeq = @import("config").ForkSeq;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const ForkTypes = @import("fork_types").ForkTypes;
const BeaconState = @import("fork_types").BeaconState;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const c = @import("constants");
const RootCache = @import("../cache/root_cache.zig").RootCache;
const validateAttestation = @import("./process_attestation_phase0.zig").validateAttestation;
Expand Down Expand Up @@ -35,6 +36,7 @@ pub fn processAttestationsAltair(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *const SlashingsCache,
attestations: []const ForkTypes(fork).Attestation.Type,
verify_signature: bool,
) !void {
Expand Down Expand Up @@ -84,7 +86,6 @@ pub fn processAttestationsAltair(
// For each participant, update their participation
// In epoch processing, this participation info is used to calculate balance updates
var total_balance_increments_with_weight: u64 = 0;
var validators = try state.validators();
for (attesting_indices.items) |validator_index| {
const flags = try epoch_participation.get(validator_index);

Expand Down Expand Up @@ -113,9 +114,7 @@ pub fn processAttestationsAltair(
// TODO: describe issue. Compute progressive target balances
// When processing each attestation, increase the cummulative target balance. Only applies post-altair
if ((flags_new_set & TIMELY_TARGET) == TIMELY_TARGET) {
var validator = try validators.get(validator_index);
const slashed = try validator.get("slashed");
if (!slashed) {
if (!slashings_cache.isSlashed(validator_index)) {
if (in_current_epoch) {
epoch_cache.current_target_unslashed_balance_increments += effective_balance_increments[validator_index];
} else {
Expand Down
6 changes: 6 additions & 0 deletions src/state_transition/block/process_attestations.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const BeaconConfig = @import("config").BeaconConfig;
const ForkTypes = @import("fork_types").ForkTypes;
const BeaconState = @import("fork_types").BeaconState;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const buildSlashingsCacheIfNeeded = @import("../cache/slashings_cache.zig").buildFromStateIfNeeded;
const processAttestationPhase0 = @import("./process_attestation_phase0.zig").processAttestationPhase0;
const processAttestationsAltair = @import("./process_attestation_altair.zig").processAttestationsAltair;
const Node = @import("persistent_merkle_tree").Node;
Expand All @@ -17,9 +19,11 @@ pub fn processAttestations(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
attestations: []const ForkTypes(fork).Attestation.Type,
verify_signatures: bool,
) !void {
try buildSlashingsCacheIfNeeded(allocator, state, slashings_cache);
if (comptime fork == .phase0) {
for (attestations) |attestation| {
try processAttestationPhase0(
Expand All @@ -38,6 +42,7 @@ pub fn processAttestations(
config,
epoch_cache,
state,
slashings_cache,
attestations,
verify_signatures,
);
Expand All @@ -64,6 +69,7 @@ test "process attestations - sanity" {
test_state.cached_state.config,
test_state.cached_state.getEpochCache(),
test_state.cached_state.state.castToFork(.electra),
&test_state.cached_state.slashings_cache,
electra.items,
true,
),
Expand Down
6 changes: 5 additions & 1 deletion src/state_transition/block/process_attester_slashing.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const ForkTypes = @import("fork_types").ForkTypes;
const BeaconState = @import("fork_types").BeaconState;
const types = @import("consensus_types");
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const buildSlashingsCacheIfNeeded = @import("../cache/slashings_cache.zig").buildFromStateIfNeeded;
const isSlashableAttestationData = @import("../utils/attestation.zig").isSlashableAttestationData;
const getAttesterSlashableIndices = @import("../utils/attestation.zig").getAttesterSlashableIndices;
const isValidIndexedAttestation = @import("./is_valid_indexed_attestation.zig").isValidIndexedAttestation;
Expand All @@ -21,10 +23,12 @@ pub fn processAttesterSlashing(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
current_epoch: u64,
attester_slashing: *const ForkTypes(fork).AttesterSlashing.Type,
verify_signature: bool,
) !void {
try buildSlashingsCacheIfNeeded(allocator, state, slashings_cache);
try assertValidAttesterSlashing(
fork,
allocator,
Expand All @@ -46,7 +50,7 @@ pub fn processAttesterSlashing(
try validators.getValue(undefined, validator_index, &validator);

if (isSlashableValidator(&validator, current_epoch)) {
try slashValidator(fork, config, epoch_cache, state, validator_index, null);
try slashValidator(fork, config, epoch_cache, state, slashings_cache, validator_index, null);
slashed_any = true;
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/state_transition/block/process_block.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const BeaconConfig = @import("config").BeaconConfig;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const buildSlashingsCacheIfNeeded = @import("../cache/slashings_cache.zig").buildFromStateIfNeeded;
const BeaconState = @import("fork_types").BeaconState;
const BlockType = @import("fork_types").BlockType;
const BeaconBlock = @import("fork_types").BeaconBlock;
Expand Down Expand Up @@ -37,13 +39,18 @@ pub fn processBlock(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
comptime block_type: BlockType,
block: *const BeaconBlock(block_type, fork),
external_data: BlockExternalData,
opts: ProcessBlockOpts,
// TODO: metrics
) !void {
// Build slashings cache against the *current* latest_block_header slot (pre-header update).
try buildSlashingsCacheIfNeeded(allocator, state, slashings_cache);
try processBlockHeader(fork, allocator, epoch_cache, state, block_type, block);
// Keep cache slot in sync with latest_block_header without forcing a rebuild.
slashings_cache.updateLatestBlockSlot(block.slot());
const body = block.body();
const current_epoch = epoch_cache.epoch;

Expand Down Expand Up @@ -100,7 +107,7 @@ pub fn processBlock(

try processRandao(fork, config, epoch_cache, state, block_type, body, block.proposerIndex(), opts.verify_signature);
try processEth1Data(fork, state, body.eth1Data());
try processOperations(fork, allocator, config, epoch_cache, state, block_type, body, opts);
try processOperations(fork, allocator, config, epoch_cache, state, slashings_cache, block_type, body, opts);
if (comptime fork.gte(.altair)) {
try processSyncAggregate(fork, allocator, config, epoch_cache, state, body.syncAggregate(), opts.verify_signature);
}
Expand Down
8 changes: 6 additions & 2 deletions src/state_transition/block/process_operations.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const BlockType = @import("fork_types").BlockType;
const BeaconBlockBody = @import("fork_types").BeaconBlockBody;
const ForkTypes = @import("fork_types").ForkTypes;
const ct = @import("consensus_types");
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;

const getEth1DepositCount = @import("../utils/deposit.zig").getEth1DepositCount;
const processAttestations = @import("./process_attestations.zig").processAttestations;
Expand All @@ -27,6 +28,7 @@ pub fn processOperations(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
comptime block_type: BlockType,
body: *const BeaconBlockBody(block_type, fork),
opts: ProcessBlockOpts,
Expand All @@ -40,7 +42,7 @@ pub fn processOperations(
const current_epoch = epoch_cache.epoch;

for (body.inner.proposer_slashings.items) |*proposer_slashing| {
try processProposerSlashing(fork, config, epoch_cache, state, proposer_slashing, opts.verify_signature);
try processProposerSlashing(fork, allocator, config, epoch_cache, state, slashings_cache, proposer_slashing, opts.verify_signature);
}

for (body.inner.attester_slashings.items) |*attester_slashing| {
Expand All @@ -50,13 +52,14 @@ pub fn processOperations(
config,
epoch_cache,
state,
slashings_cache,
current_epoch,
attester_slashing,
opts.verify_signature,
);
}

try processAttestations(fork, allocator, config, epoch_cache, state, body.inner.attestations.items, opts.verify_signature);
try processAttestations(fork, allocator, config, epoch_cache, state, slashings_cache, body.inner.attestations.items, opts.verify_signature);

for (body.inner.deposits.items) |*deposit| {
try processDeposit(fork, allocator, config, epoch_cache, state, deposit);
Expand Down Expand Up @@ -109,6 +112,7 @@ test "process operations" {
test_state.cached_state.config,
test_state.cached_state.getEpochCache(),
try test_state.cached_state.state.tryCastToFork(.electra),
&test_state.cached_state.slashings_cache,
.full,
beacon_block.beaconBlockBody().castToFork(.full, .electra),
.{},
Expand Down
7 changes: 6 additions & 1 deletion src/state_transition/block/process_proposer_slashing.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const ForkSeq = @import("config").ForkSeq;
const ForkTypes = @import("fork_types").ForkTypes;
const BeaconState = @import("fork_types").BeaconState;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const buildSlashingsCacheIfNeeded = @import("../cache/slashings_cache.zig").buildFromStateIfNeeded;
const types = @import("consensus_types");
const isSlashableValidator = @import("../utils/validator.zig").isSlashableValidator;
const getProposerSlashingSignatureSets = @import("../signature_sets/proposer_slashings.zig").getProposerSlashingSignatureSets;
Expand All @@ -12,15 +14,18 @@ const slashValidator = @import("./slash_validator.zig").slashValidator;

pub fn processProposerSlashing(
comptime fork: ForkSeq,
allocator: std.mem.Allocator,
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
proposer_slashing: *const ForkTypes(fork).ProposerSlashing.Type,
verify_signatures: bool,
) !void {
try buildSlashingsCacheIfNeeded(allocator, state, slashings_cache);
try assertValidProposerSlashing(fork, config, epoch_cache, state, proposer_slashing, verify_signatures);
const proposer_index = proposer_slashing.signed_header_1.message.proposer_index;
try slashValidator(fork, config, epoch_cache, state, proposer_index, null);
try slashValidator(fork, config, epoch_cache, state, slashings_cache, proposer_index, null);
}

pub fn assertValidProposerSlashing(
Expand Down
5 changes: 5 additions & 0 deletions src/state_transition/block/slash_validator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const c = @import("constants");
const ValidatorIndex = types.primitive.ValidatorIndex.Type;
const BeaconState = @import("fork_types").BeaconState;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const SlashingsCache = @import("../cache/slashings_cache.zig").SlashingsCache;
const decreaseBalance = @import("../utils/balance.zig").decreaseBalance;
const increaseBalance = @import("../utils/balance.zig").increaseBalance;
const initiateValidatorExit = @import("./initiate_validator_exit.zig").initiateValidatorExit;
Expand All @@ -21,6 +22,7 @@ pub fn slashValidator(
config: *const BeaconConfig,
epoch_cache: *EpochCache,
state: *BeaconState(fork),
slashings_cache: *SlashingsCache,
slashed_index: ValidatorIndex,
whistle_blower_index: ?ValidatorIndex,
) !void {
Expand All @@ -35,6 +37,9 @@ pub fn slashValidator(
try initiateValidatorExit(fork, config, epoch_cache, state, &validator);

try validator.set("slashed", true);
var latest_block_header = try state.latestBlockHeader();
const latest_block_slot = try latest_block_header.get("slot");
try slashings_cache.recordValidatorSlashing(latest_block_slot, slashed_index);
const cur_withdrawable_epoch = try validator.get("withdrawable_epoch");
try validator.set(
"withdrawable_epoch",
Expand Down
102 changes: 102 additions & 0 deletions src/state_transition/cache/slashings_cache.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const DynamicBitSet = std.DynamicBitSet;
const types = @import("consensus_types");
const Slot = types.primitive.Slot.Type;
const ValidatorIndex = types.primitive.ValidatorIndex.Type;
const Validator = types.phase0.Validator.Type;

/// Cache of slashed validator indices with an initialization slot.
pub const SlashingsCache = struct {
latest_block_slot: ?Slot,
slashed_validators: DynamicBitSet,

pub fn initEmpty(allocator: Allocator) !SlashingsCache {
return .{
.latest_block_slot = null,
.slashed_validators = try DynamicBitSet.initEmpty(allocator, 0),
};
}

pub fn initFromValidators(
allocator: Allocator,
latest_block_slot: Slot,
validators: []const Validator,
) !SlashingsCache {
var slashed_validators = try DynamicBitSet.initEmpty(allocator, validators.len);
errdefer slashed_validators.deinit();
for (validators, 0..) |validator, i| {
if (validator.slashed) {
slashed_validators.set(i);
}
}

return .{
.latest_block_slot = latest_block_slot,
.slashed_validators = slashed_validators,
};
}

pub fn clone(self: *const SlashingsCache, allocator: Allocator) !SlashingsCache {
var slashed_validators = try self.slashed_validators.clone(allocator);
errdefer slashed_validators.deinit();

return .{
.latest_block_slot = self.latest_block_slot,
.slashed_validators = slashed_validators,
};
}

pub fn deinit(self: *SlashingsCache) void {
self.slashed_validators.deinit();
self.* = undefined;
}

pub fn isInitialized(self: *const SlashingsCache, latest_block_slot: Slot) bool {
return self.latest_block_slot != null and self.latest_block_slot.? == latest_block_slot;
}

pub fn checkInitialized(self: *const SlashingsCache, latest_block_slot: Slot) !void {
if (self.isInitialized(latest_block_slot)) return;
return error.SlashingsCacheUninitialized;
}

pub fn recordValidatorSlashing(self: *SlashingsCache, block_slot: Slot, validator_index: ValidatorIndex) !void {
try self.checkInitialized(block_slot);
const idx: usize = @intCast(validator_index);
if (idx >= self.slashed_validators.capacity()) {
try self.slashed_validators.resize(idx + 1, false);
}
self.slashed_validators.set(idx);
}

pub fn isSlashed(self: *const SlashingsCache, validator_index: ValidatorIndex) bool {
const idx: usize = @intCast(validator_index);
if (idx >= self.slashed_validators.capacity()) return false;
return self.slashed_validators.isSet(idx);
}

pub fn updateLatestBlockSlot(self: *SlashingsCache, latest_block_slot: Slot) void {
self.latest_block_slot = latest_block_slot;
}
};

/// Rebuilds the cache if it's not initialized for the state's latest block slot.
pub fn buildFromStateIfNeeded(
allocator: Allocator,
state: anytype,
slashings_cache: *SlashingsCache,
) !void {
var latest_block_header = try state.latestBlockHeader();
const latest_block_slot = try latest_block_header.get("slot");
if (slashings_cache.isInitialized(latest_block_slot)) return;

var validators_view = try state.validators();
try validators_view.commit();
const validators = try validators_view.getAllReadonlyValues(allocator);
defer allocator.free(validators);
var new_cache = try SlashingsCache.initFromValidators(allocator, latest_block_slot, validators);
errdefer new_cache.deinit();
slashings_cache.deinit();
slashings_cache.* = new_cache;
}
Loading