Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/state_transition/epoch/process_pending_deposits.zig
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ fn applyPendingDeposit(
// this is to fix the double deposit issue found in mekong
// see https://github.com/ChainSafe/lodestar/pull/7255
if (cache.balances) |*balances| {
try balances.append(cache.allocator, amount);
balances.appendAssumeCapacity(amount);
}
} else |_| {
// invalid deposit signature, ignore the deposit
Expand Down
24 changes: 18 additions & 6 deletions src/state_transition/epoch/process_rewards_and_penalties.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const BeaconState = @import("fork_types").BeaconState;
const EpochCache = @import("../cache/epoch_cache.zig").EpochCache;
const EpochTransitionCache = @import("../cache/epoch_transition_cache.zig").EpochTransitionCache;
const GENESIS_EPOCH = @import("preset").GENESIS_EPOCH;
const preset = @import("preset").preset;
const getAttestationDeltas = @import("./get_attestation_deltas.zig").getAttestationDeltas;
const getRewardsAndPenaltiesAltair = @import("./get_rewards_and_penalties.zig").getRewardsAndPenaltiesAltair;

Expand All @@ -25,8 +26,20 @@ pub fn processRewardsAndPenalties(
const penalties = cache.penalties;
try getRewardsAndPenalties(fork, config, epoch_cache, state, cache, rewards, penalties);

const balances = try state.balancesSlice(cache.allocator);
errdefer cache.allocator.free(balances);
var balances_view = try state.balances();
try balances_view.commit();
const validator_count = try balances_view.length();

// applyPendingDeposit appends with appendAssumeCapacity for each validator it adds, at most
// MAX_PENDING_DEPOSITS_PER_EPOCH per epoch, so this headroom is required.
var new_balances: std.ArrayList(u64) = try .initCapacity(
cache.allocator,
validator_count + preset.MAX_PENDING_DEPOSITS_PER_EPOCH,
);
errdefer new_balances.deinit(cache.allocator);

const balances = new_balances.addManyAsSliceAssumeCapacity(validator_count);
_ = try balances_view.getAllInto(balances);

for (rewards, penalties, balances) |reward, penalty, *balance| {
balance.* = (try std.math.add(u64, balance.*, reward)) -| penalty;
Expand All @@ -38,15 +51,14 @@ pub fn processRewardsAndPenalties(
}
}

// Populate cache.balances for reuse by the validator monitor and
// more importantly processEffectiveBalanceUpdates() doesn't need to
// get from tree view state which has to commit.
var new_balances: std.ArrayList(u64) = .fromOwnedSlice(balances);
try state.setBalances(&new_balances);

if (cache.balances) |*old_balances| {
old_balances.deinit(cache.allocator);
}
// Populate cache.balances for reuse by the validator monitor and
// more importantly processEffectiveBalanceUpdates() doesn't need to
// get from tree view state which has to commit.
cache.balances = new_balances;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const std = @import("std");
const Node = @import("persistent_merkle_tree").Node;
const preset = @import("preset").preset;
const TestCachedBeaconState = @import("../test_utils/root.zig").TestCachedBeaconState;
const processRewardsAndPenalties = @import("process_rewards_and_penalties.zig").processRewardsAndPenalties;

Expand Down Expand Up @@ -70,3 +71,29 @@ test "processRewardsAndPenalties maps compact slashing penalties to validator in
try std.testing.expectEqual(first_balance_without_slashing, try updated_balances.get(0));
try std.testing.expectEqual(slashed_balance_without_slashing - slashing_penalty, try updated_balances.get(slashed_index));
}

test "processRewardsAndPenalties should reserve cached balance capacity for pending deposits" {
const allocator = std.testing.allocator;
const pool_size = 200_000;
var pool = try Node.Pool.init(.{ .page_allocator = allocator, .allocator = allocator, .pool_size = pool_size });
defer pool.deinit();

const validator_count = 256;
var test_state = try TestCachedBeaconState.init(allocator, &pool, validator_count);
defer test_state.deinit();

const cache = test_state.epoch_transition_cache;
try processRewardsAndPenalties(
.electra,
test_state.cached_state.config,
test_state.cached_state.epoch_cache,
test_state.cached_state.state.castToFork(.electra),
cache,
null,
);

const balances = cache.balances.?;
try std.testing.expectEqual(validator_count, balances.items.len);
const spare_capacity = balances.unusedCapacitySlice().len;
try std.testing.expect(spare_capacity >= preset.MAX_PENDING_DEPOSITS_PER_EPOCH);
}
Loading