From e8148055d9f41f8685a239f5de69fafd6ff101b2 Mon Sep 17 00:00:00 2001 From: lodekeeper-z Date: Sat, 28 Mar 2026 12:45:07 +0000 Subject: [PATCH 1/2] test(stf): add unit tests for processDepositRequest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test coverage for Electra deposit request processing: - First request sets depositRequestsStartIndex from UNSET - Subsequent requests preserve existing start index - Pending deposit fields (amount, slot) match input request - Already-set start index is not overwritten 🤖 Generated with AI assistance --- .../block/process_deposit_request.zig | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/state_transition/block/process_deposit_request.zig b/src/state_transition/block/process_deposit_request.zig index 175fb5b2c..d7ea9e9c0 100644 --- a/src/state_transition/block/process_deposit_request.zig +++ b/src/state_transition/block/process_deposit_request.zig @@ -22,3 +22,121 @@ pub fn processDepositRequest(comptime fork: ForkSeq, state: *BeaconState(fork), var pending_deposits = try state.pendingDeposits(); try pending_deposits.pushValue(&pending_deposit); } + +// ─── Tests ────────────────────────────────────────────────────────────────── + +const std = @import("std"); +const testing = std.testing; +const Node = @import("persistent_merkle_tree").Node; +const TestCachedBeaconState = @import("../test_utils/generate_state.zig").TestCachedBeaconState; + +fn makeDepositRequest(index: u64) DepositRequest { + return DepositRequest{ + .pubkey = [_]u8{@as(u8, @intCast(index & 0xFF))} ** 48, + .withdrawal_credentials = [_]u8{0x01} ++ [_]u8{0} ** 11 ++ [_]u8{0xAA} ** 20, + .amount = 32_000_000_000, + .signature = [_]u8{0} ** 96, + .index = index, + }; +} + +test "processDepositRequest - first request sets depositRequestsStartIndex" { + const allocator = testing.allocator; + var pool = try Node.Pool.init(allocator, 256 * 5); + defer pool.deinit(); + + var test_state = try TestCachedBeaconState.init(allocator, &pool, 16); + defer test_state.deinit(); + + var state = test_state.cached_state.state.castToFork(.electra); + + // Set to UNSET value (as electra upgrade does) + try state.setDepositRequestsStartIndex(c.UNSET_DEPOSIT_REQUESTS_START_INDEX); + + const request = makeDepositRequest(42); + try processDepositRequest(.electra, state, &request); + + // Should have set the start index to the request's index + try testing.expectEqual(@as(u64, 42), try state.depositRequestsStartIndex()); + + // Should have appended one pending deposit + var pending = try state.pendingDeposits(); + try testing.expectEqual(@as(u64, 1), try pending.length()); +} + +test "processDepositRequest - subsequent request does not change start index" { + const allocator = testing.allocator; + var pool = try Node.Pool.init(allocator, 256 * 5); + defer pool.deinit(); + + var test_state = try TestCachedBeaconState.init(allocator, &pool, 16); + defer test_state.deinit(); + + var state = test_state.cached_state.state.castToFork(.electra); + + // Set to UNSET, then process first request + try state.setDepositRequestsStartIndex(c.UNSET_DEPOSIT_REQUESTS_START_INDEX); + const first = makeDepositRequest(10); + try processDepositRequest(.electra, state, &first); + + // Process second request with different index + const second = makeDepositRequest(20); + try processDepositRequest(.electra, state, &second); + + // Start index should still be 10 (from first request) + try testing.expectEqual(@as(u64, 10), try state.depositRequestsStartIndex()); + + // Should have two pending deposits + var pending = try state.pendingDeposits(); + try testing.expectEqual(@as(u64, 2), try pending.length()); +} + +test "processDepositRequest - pending deposit fields match request" { + const allocator = testing.allocator; + var pool = try Node.Pool.init(allocator, 256 * 5); + defer pool.deinit(); + + var test_state = try TestCachedBeaconState.init(allocator, &pool, 16); + defer test_state.deinit(); + + var state = test_state.cached_state.state.castToFork(.electra); + + // Use a non-UNSET start index so we skip that branch + try state.setDepositRequestsStartIndex(0); + + const request = makeDepositRequest(5); + try processDepositRequest(.electra, state, &request); + + var pending = try state.pendingDeposits(); + var deposit = try pending.get(0); + + // Verify all fields were copied correctly + // Verify amount and slot were correctly copied from the request + + const amount_view = try deposit.get("amount"); + try testing.expectEqual(@as(u64, 32_000_000_000), amount_view); + + const slot_view = try deposit.get("slot"); + const state_slot = try state.slot(); + try testing.expectEqual(state_slot, slot_view); +} + +test "processDepositRequest - already set start index is preserved" { + const allocator = testing.allocator; + var pool = try Node.Pool.init(allocator, 256 * 5); + defer pool.deinit(); + + var test_state = try TestCachedBeaconState.init(allocator, &pool, 16); + defer test_state.deinit(); + + var state = test_state.cached_state.state.castToFork(.electra); + + // Pre-set to a specific value (not UNSET) + try state.setDepositRequestsStartIndex(100); + + const request = makeDepositRequest(200); + try processDepositRequest(.electra, state, &request); + + // Start index should remain 100 + try testing.expectEqual(@as(u64, 100), try state.depositRequestsStartIndex()); +} From ff746b6e168a33402169b8af4f6f3e3f059026c7 Mon Sep 17 00:00:00 2001 From: lodekeeper-z Date: Sat, 28 Mar 2026 13:19:58 +0000 Subject: [PATCH 2/2] test: verify all PendingDeposit fields in processDepositRequest test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verify pubkey, withdrawal_credentials, and signature fields are copied correctly. Use request.amount instead of hardcoded value for resilience. Addresses review feedback from gemini-code-assist. 🤖 Generated with AI assistance --- .../block/process_deposit_request.zig | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/state_transition/block/process_deposit_request.zig b/src/state_transition/block/process_deposit_request.zig index d7ea9e9c0..55e4933af 100644 --- a/src/state_transition/block/process_deposit_request.zig +++ b/src/state_transition/block/process_deposit_request.zig @@ -110,11 +110,24 @@ test "processDepositRequest - pending deposit fields match request" { var pending = try state.pendingDeposits(); var deposit = try pending.get(0); - // Verify all fields were copied correctly - // Verify amount and slot were correctly copied from the request + // Verify all fields were copied correctly from the request + var actual_pubkey: [48]u8 = undefined; + var pubkey_view = try deposit.get("pubkey"); + _ = try pubkey_view.getAllInto(actual_pubkey[0..]); + try testing.expectEqualSlices(u8, &request.pubkey, &actual_pubkey); + + var actual_creds: [32]u8 = undefined; + var creds_view = try deposit.get("withdrawal_credentials"); + _ = try creds_view.getAllInto(actual_creds[0..]); + try testing.expectEqualSlices(u8, &request.withdrawal_credentials, &actual_creds); + + var actual_sig: [96]u8 = undefined; + var sig_view = try deposit.get("signature"); + _ = try sig_view.getAllInto(actual_sig[0..]); + try testing.expectEqualSlices(u8, &request.signature, &actual_sig); const amount_view = try deposit.get("amount"); - try testing.expectEqual(@as(u64, 32_000_000_000), amount_view); + try testing.expectEqual(request.amount, amount_view); const slot_view = try deposit.get("slot"); const state_slot = try state.slot();