tigerbeetle-node 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +302 -101
- package/dist/index.d.ts +70 -72
- package/dist/index.js +70 -72
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
- package/scripts/download_node_headers.sh +14 -7
- package/src/index.ts +6 -10
- package/src/node.zig +6 -3
- package/src/tigerbeetle/scripts/benchmark.sh +4 -4
- package/src/tigerbeetle/scripts/confirm_image.sh +44 -0
- package/src/tigerbeetle/scripts/fuzz_loop.sh +15 -0
- package/src/tigerbeetle/scripts/fuzz_unique_errors.sh +7 -0
- package/src/tigerbeetle/scripts/install.sh +19 -4
- package/src/tigerbeetle/scripts/install_zig.bat +5 -1
- package/src/tigerbeetle/scripts/install_zig.sh +24 -14
- package/src/tigerbeetle/scripts/pre-commit.sh +9 -0
- package/src/tigerbeetle/scripts/shellcheck.sh +5 -0
- package/src/tigerbeetle/scripts/tests_on_alpine.sh +10 -0
- package/src/tigerbeetle/scripts/tests_on_ubuntu.sh +14 -0
- package/src/tigerbeetle/scripts/validate_docs.sh +17 -0
- package/src/tigerbeetle/src/benchmark.zig +29 -13
- package/src/tigerbeetle/src/c/tb_client/context.zig +248 -47
- package/src/tigerbeetle/src/c/tb_client/echo_client.zig +108 -0
- package/src/tigerbeetle/src/c/tb_client/packet.zig +2 -2
- package/src/tigerbeetle/src/c/tb_client/signal.zig +2 -4
- package/src/tigerbeetle/src/c/tb_client/thread.zig +17 -257
- package/src/tigerbeetle/src/c/tb_client.h +118 -84
- package/src/tigerbeetle/src/c/tb_client.zig +88 -23
- package/src/tigerbeetle/src/c/tb_client_header_test.zig +135 -0
- package/src/tigerbeetle/src/c/test.zig +371 -1
- package/src/tigerbeetle/src/cli.zig +37 -7
- package/src/tigerbeetle/src/config.zig +58 -17
- package/src/tigerbeetle/src/demo.zig +5 -2
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +1 -1
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +13 -0
- package/src/tigerbeetle/src/ewah.zig +11 -33
- package/src/tigerbeetle/src/ewah_benchmark.zig +8 -9
- package/src/tigerbeetle/src/io/linux.zig +1 -1
- package/src/tigerbeetle/src/lsm/README.md +308 -0
- package/src/tigerbeetle/src/lsm/binary_search.zig +137 -10
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +43 -0
- package/src/tigerbeetle/src/lsm/compaction.zig +376 -397
- package/src/tigerbeetle/src/lsm/composite_key.zig +2 -0
- package/src/tigerbeetle/src/lsm/eytzinger.zig +1 -1
- package/src/tigerbeetle/src/{eytzinger_benchmark.zig → lsm/eytzinger_benchmark.zig} +34 -21
- package/src/tigerbeetle/src/lsm/forest.zig +21 -447
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +414 -0
- package/src/tigerbeetle/src/lsm/grid.zig +170 -76
- package/src/tigerbeetle/src/lsm/groove.zig +197 -133
- package/src/tigerbeetle/src/lsm/k_way_merge.zig +40 -18
- package/src/tigerbeetle/src/lsm/level_iterator.zig +28 -9
- package/src/tigerbeetle/src/lsm/manifest.zig +93 -180
- package/src/tigerbeetle/src/lsm/manifest_level.zig +161 -454
- package/src/tigerbeetle/src/lsm/manifest_log.zig +243 -356
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +665 -0
- package/src/tigerbeetle/src/lsm/node_pool.zig +4 -0
- package/src/tigerbeetle/src/lsm/posted_groove.zig +65 -76
- package/src/tigerbeetle/src/lsm/segmented_array.zig +580 -251
- package/src/tigerbeetle/src/lsm/segmented_array_benchmark.zig +148 -0
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +9 -0
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +62 -12
- package/src/tigerbeetle/src/lsm/table.zig +115 -68
- package/src/tigerbeetle/src/lsm/table_immutable.zig +30 -23
- package/src/tigerbeetle/src/lsm/table_iterator.zig +27 -17
- package/src/tigerbeetle/src/lsm/table_mutable.zig +63 -12
- package/src/tigerbeetle/src/lsm/test.zig +61 -56
- package/src/tigerbeetle/src/lsm/tree.zig +450 -407
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +461 -0
- package/src/tigerbeetle/src/main.zig +83 -8
- package/src/tigerbeetle/src/message_bus.zig +20 -9
- package/src/tigerbeetle/src/message_pool.zig +22 -19
- package/src/tigerbeetle/src/ring_buffer.zig +7 -3
- package/src/tigerbeetle/src/simulator.zig +179 -119
- package/src/tigerbeetle/src/state_machine.zig +381 -246
- package/src/tigerbeetle/src/static_allocator.zig +65 -0
- package/src/tigerbeetle/src/storage.zig +3 -7
- package/src/tigerbeetle/src/test/accounting/auditor.zig +577 -0
- package/src/tigerbeetle/src/test/accounting/workload.zig +823 -0
- package/src/tigerbeetle/src/test/cluster.zig +33 -81
- package/src/tigerbeetle/src/test/conductor.zig +366 -0
- package/src/tigerbeetle/src/test/fuzz.zig +121 -0
- package/src/tigerbeetle/src/test/id.zig +89 -0
- package/src/tigerbeetle/src/test/network.zig +45 -19
- package/src/tigerbeetle/src/test/packet_simulator.zig +40 -29
- package/src/tigerbeetle/src/test/priority_queue.zig +645 -0
- package/src/tigerbeetle/src/test/state_checker.zig +91 -69
- package/src/tigerbeetle/src/test/state_machine.zig +11 -35
- package/src/tigerbeetle/src/test/storage.zig +470 -106
- package/src/tigerbeetle/src/test/storage_checker.zig +204 -0
- package/src/tigerbeetle/src/tigerbeetle.zig +15 -16
- package/src/tigerbeetle/src/unit_tests.zig +13 -1
- package/src/tigerbeetle/src/util.zig +97 -11
- package/src/tigerbeetle/src/vopr.zig +495 -0
- package/src/tigerbeetle/src/vsr/client.zig +21 -3
- package/src/tigerbeetle/src/vsr/journal.zig +293 -212
- package/src/tigerbeetle/src/vsr/replica.zig +1086 -515
- package/src/tigerbeetle/src/vsr/superblock.zig +382 -637
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +14 -16
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +416 -153
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +332 -0
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +349 -0
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +62 -12
- package/src/tigerbeetle/src/vsr/superblock_quorums.zig +394 -0
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +312 -0
- package/src/tigerbeetle/src/vsr.zig +94 -60
- package/src/tigerbeetle/scripts/vopr.bat +0 -48
- package/src/tigerbeetle/scripts/vopr.sh +0 -33
- package/src/tigerbeetle/src/benchmark_array_search.zig +0 -317
- package/src/tigerbeetle/src/benchmarks/perf.zig +0 -299
|
@@ -5,6 +5,7 @@ const mem = std.mem;
|
|
|
5
5
|
const log = std.log.scoped(.state_machine);
|
|
6
6
|
|
|
7
7
|
const tb = @import("tigerbeetle.zig");
|
|
8
|
+
const snapshot_latest = @import("lsm/tree.zig").snapshot_latest;
|
|
8
9
|
|
|
9
10
|
const Account = tb.Account;
|
|
10
11
|
const AccountFlags = tb.AccountFlags;
|
|
@@ -18,7 +19,9 @@ const CreateTransfersResult = tb.CreateTransfersResult;
|
|
|
18
19
|
const CreateAccountResult = tb.CreateAccountResult;
|
|
19
20
|
const CreateTransferResult = tb.CreateTransferResult;
|
|
20
21
|
|
|
21
|
-
pub fn StateMachineType(comptime Storage: type
|
|
22
|
+
pub fn StateMachineType(comptime Storage: type, comptime constants_: struct {
|
|
23
|
+
message_body_size_max: usize,
|
|
24
|
+
}) type {
|
|
22
25
|
return struct {
|
|
23
26
|
const StateMachine = @This();
|
|
24
27
|
|
|
@@ -63,11 +66,35 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
63
66
|
lookup_transfers,
|
|
64
67
|
};
|
|
65
68
|
|
|
69
|
+
pub const constants = struct {
|
|
70
|
+
/// The maximum number of objects within a batch, by operation.
|
|
71
|
+
pub const batch_max = struct {
|
|
72
|
+
pub const create_accounts = operation_batch_max(.create_accounts);
|
|
73
|
+
pub const create_transfers = operation_batch_max(.create_transfers);
|
|
74
|
+
pub const lookup_accounts = operation_batch_max(.lookup_accounts);
|
|
75
|
+
pub const lookup_transfers = operation_batch_max(.lookup_transfers);
|
|
76
|
+
|
|
77
|
+
comptime {
|
|
78
|
+
assert(create_accounts > 0);
|
|
79
|
+
assert(create_transfers > 0);
|
|
80
|
+
assert(lookup_accounts > 0);
|
|
81
|
+
assert(lookup_transfers > 0);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fn operation_batch_max(comptime operation: Operation) usize {
|
|
85
|
+
return @divFloor(constants_.message_body_size_max, std.math.max(
|
|
86
|
+
@sizeOf(Event(operation)),
|
|
87
|
+
@sizeOf(Result(operation)),
|
|
88
|
+
));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
66
93
|
pub const Options = struct {
|
|
67
94
|
lsm_forest_node_count: u32,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
95
|
+
cache_entries_accounts: u32,
|
|
96
|
+
cache_entries_transfers: u32,
|
|
97
|
+
cache_entries_posted: u32,
|
|
71
98
|
};
|
|
72
99
|
|
|
73
100
|
prepare_timestamp: u64,
|
|
@@ -92,20 +119,7 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
92
119
|
allocator,
|
|
93
120
|
grid,
|
|
94
121
|
options.lsm_forest_node_count,
|
|
95
|
-
|
|
96
|
-
.accounts = .{
|
|
97
|
-
.cache_size = options.cache_size_accounts,
|
|
98
|
-
.commit_count_max = 8191,
|
|
99
|
-
},
|
|
100
|
-
.transfers = .{
|
|
101
|
-
.cache_size = options.cache_size_transfers,
|
|
102
|
-
.commit_count_max = 8191 * 2,
|
|
103
|
-
},
|
|
104
|
-
.posted = .{
|
|
105
|
-
.cache_size = options.cache_size_posted,
|
|
106
|
-
.commit_count_max = 8191 * 2,
|
|
107
|
-
},
|
|
108
|
-
},
|
|
122
|
+
forest_options(options),
|
|
109
123
|
);
|
|
110
124
|
errdefer forest.deinit(allocator);
|
|
111
125
|
|
|
@@ -207,11 +221,10 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
207
221
|
self.prefetch_input = input;
|
|
208
222
|
self.prefetch_callback = callback;
|
|
209
223
|
|
|
210
|
-
//
|
|
211
|
-
|
|
212
|
-
self.forest.grooves.
|
|
213
|
-
self.forest.grooves.
|
|
214
|
-
self.forest.grooves.posted.prefetch_clear();
|
|
224
|
+
// TODO(Snapshots) Pass in the target snapshot.
|
|
225
|
+
self.forest.grooves.accounts.prefetch_setup(null);
|
|
226
|
+
self.forest.grooves.transfers.prefetch_setup(null);
|
|
227
|
+
self.forest.grooves.posted.prefetch_setup(null);
|
|
215
228
|
|
|
216
229
|
return switch (operation) {
|
|
217
230
|
.reserved, .root, .register => unreachable,
|
|
@@ -348,11 +361,11 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
348
361
|
client: u128,
|
|
349
362
|
op: u64,
|
|
350
363
|
operation: Operation,
|
|
351
|
-
input: []const u8,
|
|
352
|
-
output: []u8,
|
|
364
|
+
input: []align(16) const u8,
|
|
365
|
+
output: []align(16) u8,
|
|
353
366
|
) usize {
|
|
354
367
|
_ = client;
|
|
355
|
-
|
|
368
|
+
assert(op != 0);
|
|
356
369
|
|
|
357
370
|
const result = switch (operation) {
|
|
358
371
|
.root => unreachable,
|
|
@@ -367,10 +380,6 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
367
380
|
return result;
|
|
368
381
|
}
|
|
369
382
|
|
|
370
|
-
pub fn tick(self: *StateMachine) void {
|
|
371
|
-
self.forest.tick();
|
|
372
|
-
}
|
|
373
|
-
|
|
374
383
|
pub fn compact(self: *StateMachine, callback: fn (*StateMachine) void, op: u64) void {
|
|
375
384
|
assert(self.compact_callback == null);
|
|
376
385
|
assert(self.checkpoint_callback == null);
|
|
@@ -404,8 +413,8 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
404
413
|
fn execute(
|
|
405
414
|
self: *StateMachine,
|
|
406
415
|
comptime operation: Operation,
|
|
407
|
-
input: []const u8,
|
|
408
|
-
output: []u8,
|
|
416
|
+
input: []align(16) const u8,
|
|
417
|
+
output: []align(16) u8,
|
|
409
418
|
) usize {
|
|
410
419
|
comptime assert(operation != .lookup_accounts and operation != .lookup_transfers);
|
|
411
420
|
|
|
@@ -417,14 +426,21 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
417
426
|
var chain_broken = false;
|
|
418
427
|
|
|
419
428
|
for (events) |*event, index| {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
429
|
+
const result = blk: {
|
|
430
|
+
if (event.flags.linked) {
|
|
431
|
+
if (chain == null) {
|
|
432
|
+
chain = index;
|
|
433
|
+
assert(chain_broken == false);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (index == events.len - 1) break :blk .linked_event_chain_open;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
break :blk if (chain_broken) .linked_event_failed else switch (operation) {
|
|
440
|
+
.create_accounts => self.create_account(event),
|
|
441
|
+
.create_transfers => self.create_transfer(event),
|
|
442
|
+
else => unreachable,
|
|
443
|
+
};
|
|
428
444
|
};
|
|
429
445
|
log.debug("{s} {}/{}: {}: {}", .{
|
|
430
446
|
@tagName(operation),
|
|
@@ -449,19 +465,17 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
449
465
|
count += 1;
|
|
450
466
|
}
|
|
451
467
|
} else {
|
|
452
|
-
assert(result == .linked_event_failed);
|
|
468
|
+
assert(result == .linked_event_failed or result == .linked_event_chain_open);
|
|
453
469
|
}
|
|
454
470
|
}
|
|
455
471
|
results[count] = .{ .index = @intCast(u32, index), .result = result };
|
|
456
472
|
count += 1;
|
|
457
473
|
}
|
|
458
|
-
if (!event.flags.linked
|
|
474
|
+
if (chain != null and (!event.flags.linked or result == .linked_event_chain_open)) {
|
|
459
475
|
chain = null;
|
|
460
476
|
chain_broken = false;
|
|
461
477
|
}
|
|
462
478
|
}
|
|
463
|
-
// TODO client.zig: Validate that batch chains are always well-formed and closed.
|
|
464
|
-
// This is programming error and we should raise an exception for this in the client ASAP.
|
|
465
479
|
assert(chain == null);
|
|
466
480
|
assert(chain_broken == false);
|
|
467
481
|
|
|
@@ -505,6 +519,7 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
505
519
|
assert(index == chain_start_index);
|
|
506
520
|
}
|
|
507
521
|
|
|
522
|
+
// Accounts that do not fit in the response are omitted.
|
|
508
523
|
fn execute_lookup_accounts(self: *StateMachine, input: []const u8, output: []u8) usize {
|
|
509
524
|
const batch = mem.bytesAsSlice(u128, input);
|
|
510
525
|
const output_len = @divFloor(output.len, @sizeOf(Account)) * @sizeOf(Account);
|
|
@@ -519,6 +534,7 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
519
534
|
return results_count * @sizeOf(Account);
|
|
520
535
|
}
|
|
521
536
|
|
|
537
|
+
// Transfers that do not fit in the response are omitted.
|
|
522
538
|
fn execute_lookup_transfers(self: *StateMachine, input: []const u8, output: []u8) usize {
|
|
523
539
|
const batch = mem.bytesAsSlice(u128, input);
|
|
524
540
|
const output_len = @divFloor(output.len, @sizeOf(Transfer)) * @sizeOf(Transfer);
|
|
@@ -548,16 +564,14 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
548
564
|
return .mutually_exclusive_flags;
|
|
549
565
|
}
|
|
550
566
|
|
|
551
|
-
if (
|
|
552
|
-
if (
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (a.debits_exceed_credits(0)) return .exceeds_credits;
|
|
556
|
-
if (a.credits_exceed_debits(0)) return .exceeds_debits;
|
|
567
|
+
if (a.debits_pending != 0) return .debits_pending_must_be_zero;
|
|
568
|
+
if (a.debits_posted != 0) return .debits_posted_must_be_zero;
|
|
569
|
+
if (a.credits_pending != 0) return .credits_pending_must_be_zero;
|
|
570
|
+
if (a.credits_posted != 0) return .credits_posted_must_be_zero;
|
|
557
571
|
|
|
558
572
|
if (self.get_account(a.id)) |e| return create_account_exists(a, e);
|
|
559
573
|
|
|
560
|
-
self.forest.grooves.accounts.
|
|
574
|
+
self.forest.grooves.accounts.put_no_clobber(a);
|
|
561
575
|
|
|
562
576
|
self.commit_timestamp = a.timestamp;
|
|
563
577
|
return .ok;
|
|
@@ -574,10 +588,6 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
574
588
|
assert(zeroed_48_bytes(a.reserved) and zeroed_48_bytes(e.reserved));
|
|
575
589
|
if (a.ledger != e.ledger) return .exists_with_different_ledger;
|
|
576
590
|
if (a.code != e.code) return .exists_with_different_code;
|
|
577
|
-
if (a.debits_pending != e.debits_pending) return .exists_with_different_debits_pending;
|
|
578
|
-
if (a.debits_posted != e.debits_posted) return .exists_with_different_debits_posted;
|
|
579
|
-
if (a.credits_pending != e.credits_pending) return .exists_with_different_credits_pending;
|
|
580
|
-
if (a.credits_posted != e.credits_posted) return .exists_with_different_credits_posted;
|
|
581
591
|
return .exists;
|
|
582
592
|
}
|
|
583
593
|
|
|
@@ -643,6 +653,7 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
643
653
|
if (sum_overflows(t.amount, cr.credits_pending + cr.credits_posted)) {
|
|
644
654
|
return .overflows_credits;
|
|
645
655
|
}
|
|
656
|
+
if (sum_overflows(t.timestamp, t.timeout)) return .overflows_timeout;
|
|
646
657
|
|
|
647
658
|
if (dr.debits_exceed_credits(t.amount)) return .exceeds_credits;
|
|
648
659
|
if (cr.credits_exceed_debits(t.amount)) return .exceeds_debits;
|
|
@@ -899,6 +910,91 @@ pub fn StateMachineType(comptime Storage: type) type {
|
|
|
899
910
|
fn get_posted(self: *const StateMachine, pending_id: u128) ?bool {
|
|
900
911
|
return self.forest.grooves.posted.get(pending_id);
|
|
901
912
|
}
|
|
913
|
+
|
|
914
|
+
pub fn forest_options(options: Options) Forest.GroovesOptions {
|
|
915
|
+
const batch_accounts_max = @intCast(u32, constants.batch_max.create_accounts);
|
|
916
|
+
const batch_transfers_max = @intCast(u32, constants.batch_max.create_transfers);
|
|
917
|
+
assert(batch_accounts_max == constants.batch_max.lookup_accounts);
|
|
918
|
+
assert(batch_transfers_max == constants.batch_max.lookup_transfers);
|
|
919
|
+
|
|
920
|
+
return .{
|
|
921
|
+
.accounts = .{
|
|
922
|
+
.cache_entries_max = options.cache_entries_accounts,
|
|
923
|
+
.prefetch_entries_max = std.math.max(
|
|
924
|
+
// create_account()/lookup_account() looks up 1 account per item.
|
|
925
|
+
batch_accounts_max,
|
|
926
|
+
// create_transfer()/post_or_void_pending_transfer() looks up 2
|
|
927
|
+
// accounts for every transfer.
|
|
928
|
+
2 * batch_transfers_max,
|
|
929
|
+
),
|
|
930
|
+
.tree_options_object = .{
|
|
931
|
+
.commit_entries_max = math.max(
|
|
932
|
+
batch_accounts_max,
|
|
933
|
+
// ×2 because creating a transfer will update 2 accounts.
|
|
934
|
+
2 * batch_transfers_max,
|
|
935
|
+
),
|
|
936
|
+
},
|
|
937
|
+
.tree_options_id = .{ .commit_entries_max = batch_accounts_max },
|
|
938
|
+
.tree_options_index = .{
|
|
939
|
+
.user_data = .{ .commit_entries_max = batch_accounts_max },
|
|
940
|
+
.ledger = .{ .commit_entries_max = batch_accounts_max },
|
|
941
|
+
.code = .{ .commit_entries_max = batch_accounts_max },
|
|
942
|
+
// Transfers mutate the secondary indices for debits/credits pending/posted.
|
|
943
|
+
//
|
|
944
|
+
// * Each mutation results in a remove and an insert: the ×2 multiplier.
|
|
945
|
+
// * Each transfer modifies two accounts. However, this does not
|
|
946
|
+
// necessitate an additional ×2 multiplier — the credits of the debit
|
|
947
|
+
// account and the debits of the credit account are not modified.
|
|
948
|
+
.debits_pending = .{
|
|
949
|
+
.commit_entries_max = math.max(
|
|
950
|
+
batch_accounts_max,
|
|
951
|
+
2 * batch_transfers_max,
|
|
952
|
+
),
|
|
953
|
+
},
|
|
954
|
+
.debits_posted = .{
|
|
955
|
+
.commit_entries_max = math.max(
|
|
956
|
+
batch_accounts_max,
|
|
957
|
+
2 * batch_transfers_max,
|
|
958
|
+
),
|
|
959
|
+
},
|
|
960
|
+
.credits_pending = .{
|
|
961
|
+
.commit_entries_max = math.max(
|
|
962
|
+
batch_accounts_max,
|
|
963
|
+
2 * batch_transfers_max,
|
|
964
|
+
),
|
|
965
|
+
},
|
|
966
|
+
.credits_posted = .{
|
|
967
|
+
.commit_entries_max = math.max(
|
|
968
|
+
batch_accounts_max,
|
|
969
|
+
2 * batch_transfers_max,
|
|
970
|
+
),
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
.transfers = .{
|
|
975
|
+
.cache_entries_max = options.cache_entries_transfers,
|
|
976
|
+
// *2 to fetch pending and post/void transfer.
|
|
977
|
+
.prefetch_entries_max = 2 * batch_transfers_max,
|
|
978
|
+
.tree_options_object = .{ .commit_entries_max = batch_transfers_max },
|
|
979
|
+
.tree_options_id = .{ .commit_entries_max = batch_transfers_max },
|
|
980
|
+
.tree_options_index = .{
|
|
981
|
+
.debit_account_id = .{ .commit_entries_max = batch_transfers_max },
|
|
982
|
+
.credit_account_id = .{ .commit_entries_max = batch_transfers_max },
|
|
983
|
+
.user_data = .{ .commit_entries_max = batch_transfers_max },
|
|
984
|
+
.pending_id = .{ .commit_entries_max = batch_transfers_max },
|
|
985
|
+
.timeout = .{ .commit_entries_max = batch_transfers_max },
|
|
986
|
+
.ledger = .{ .commit_entries_max = batch_transfers_max },
|
|
987
|
+
.code = .{ .commit_entries_max = batch_transfers_max },
|
|
988
|
+
.amount = .{ .commit_entries_max = batch_transfers_max },
|
|
989
|
+
},
|
|
990
|
+
},
|
|
991
|
+
.posted = .{
|
|
992
|
+
.cache_entries_max = options.cache_entries_posted,
|
|
993
|
+
.prefetch_entries_max = batch_transfers_max,
|
|
994
|
+
.commit_entries_max = batch_transfers_max,
|
|
995
|
+
},
|
|
996
|
+
};
|
|
997
|
+
}
|
|
902
998
|
};
|
|
903
999
|
}
|
|
904
1000
|
|
|
@@ -962,7 +1058,11 @@ const TestContext = struct {
|
|
|
962
1058
|
const MessagePool = @import("message_pool.zig").MessagePool;
|
|
963
1059
|
const SuperBlock = @import("vsr/superblock.zig").SuperBlockType(Storage);
|
|
964
1060
|
const Grid = @import("lsm/grid.zig").GridType(Storage);
|
|
965
|
-
const StateMachine = StateMachineType(Storage
|
|
1061
|
+
const StateMachine = StateMachineType(Storage, .{
|
|
1062
|
+
// Overestimate the batch size (in order to overprovision commit_entries_max)
|
|
1063
|
+
// because the test never compacts.
|
|
1064
|
+
.message_body_size_max = 1000 * @sizeOf(Account),
|
|
1065
|
+
});
|
|
966
1066
|
|
|
967
1067
|
storage: Storage,
|
|
968
1068
|
message_pool: MessagePool,
|
|
@@ -970,36 +1070,41 @@ const TestContext = struct {
|
|
|
970
1070
|
grid: Grid,
|
|
971
1071
|
state_machine: StateMachine,
|
|
972
1072
|
|
|
973
|
-
fn init(ctx: *TestContext, allocator: mem.Allocator
|
|
1073
|
+
fn init(ctx: *TestContext, allocator: mem.Allocator) !void {
|
|
974
1074
|
ctx.storage = try Storage.init(
|
|
975
1075
|
allocator,
|
|
976
1076
|
4096,
|
|
977
1077
|
.{
|
|
978
|
-
.seed = 0,
|
|
979
1078
|
.read_latency_min = 0,
|
|
980
1079
|
.read_latency_mean = 0,
|
|
981
1080
|
.write_latency_min = 0,
|
|
982
1081
|
.write_latency_mean = 0,
|
|
983
|
-
.read_fault_probability = 0,
|
|
984
|
-
.write_fault_probability = 0,
|
|
985
|
-
},
|
|
986
|
-
0,
|
|
987
|
-
.{
|
|
988
|
-
.first_offset = 0,
|
|
989
|
-
.period = 0,
|
|
990
1082
|
},
|
|
991
1083
|
);
|
|
992
1084
|
errdefer ctx.storage.deinit(allocator);
|
|
993
1085
|
|
|
994
|
-
ctx.message_pool = .{
|
|
1086
|
+
ctx.message_pool = .{
|
|
1087
|
+
.free_list = null,
|
|
1088
|
+
.messages_max = 0,
|
|
1089
|
+
};
|
|
1090
|
+
errdefer ctx.message_pool.deinit(allocator);
|
|
995
1091
|
|
|
996
1092
|
ctx.superblock = try SuperBlock.init(allocator, &ctx.storage, &ctx.message_pool);
|
|
997
1093
|
errdefer ctx.superblock.deinit(allocator);
|
|
998
1094
|
|
|
1095
|
+
// Pretend that the superblock is open so that the Forest can initialize.
|
|
1096
|
+
ctx.superblock.opened = true;
|
|
1097
|
+
ctx.superblock.working.vsr_state.commit_min = 0;
|
|
1098
|
+
|
|
999
1099
|
ctx.grid = try Grid.init(allocator, &ctx.superblock);
|
|
1000
1100
|
errdefer ctx.grid.deinit(allocator);
|
|
1001
1101
|
|
|
1002
|
-
ctx.state_machine = try StateMachine.init(allocator, &ctx.grid,
|
|
1102
|
+
ctx.state_machine = try StateMachine.init(allocator, &ctx.grid, .{
|
|
1103
|
+
.lsm_forest_node_count = 1,
|
|
1104
|
+
.cache_entries_accounts = 2048,
|
|
1105
|
+
.cache_entries_transfers = 2048,
|
|
1106
|
+
.cache_entries_posted = 2048,
|
|
1107
|
+
});
|
|
1003
1108
|
errdefer ctx.state_machine.deinit(allocator);
|
|
1004
1109
|
}
|
|
1005
1110
|
|
|
@@ -1024,10 +1129,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1024
1129
|
.user_data = 2,
|
|
1025
1130
|
.ledger = 3,
|
|
1026
1131
|
.code = 4,
|
|
1027
|
-
.debits_pending = 5,
|
|
1028
|
-
.debits_posted = 6,
|
|
1029
|
-
.credits_pending = 7,
|
|
1030
|
-
.credits_posted = 8,
|
|
1031
1132
|
.timestamp = 1,
|
|
1032
1133
|
}),
|
|
1033
1134
|
},
|
|
@@ -1044,10 +1145,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1044
1145
|
.debits_must_not_exceed_credits = true,
|
|
1045
1146
|
.credits_must_not_exceed_debits = true,
|
|
1046
1147
|
},
|
|
1047
|
-
.debits_pending =
|
|
1048
|
-
.debits_posted =
|
|
1049
|
-
.credits_pending =
|
|
1050
|
-
.credits_posted =
|
|
1148
|
+
.debits_pending = 1,
|
|
1149
|
+
.debits_posted = 1,
|
|
1150
|
+
.credits_pending = 1,
|
|
1151
|
+
.credits_posted = 1,
|
|
1051
1152
|
.timestamp = 2,
|
|
1052
1153
|
}),
|
|
1053
1154
|
},
|
|
@@ -1064,10 +1165,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1064
1165
|
.debits_must_not_exceed_credits = true,
|
|
1065
1166
|
.credits_must_not_exceed_debits = true,
|
|
1066
1167
|
},
|
|
1067
|
-
.debits_pending =
|
|
1068
|
-
.debits_posted =
|
|
1069
|
-
.credits_pending =
|
|
1070
|
-
.credits_posted =
|
|
1168
|
+
.debits_pending = 1,
|
|
1169
|
+
.debits_posted = 1,
|
|
1170
|
+
.credits_pending = 1,
|
|
1171
|
+
.credits_posted = 1,
|
|
1071
1172
|
.timestamp = 2,
|
|
1072
1173
|
}),
|
|
1073
1174
|
},
|
|
@@ -1083,10 +1184,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1083
1184
|
.debits_must_not_exceed_credits = true,
|
|
1084
1185
|
.credits_must_not_exceed_debits = true,
|
|
1085
1186
|
},
|
|
1086
|
-
.debits_pending =
|
|
1087
|
-
.debits_posted =
|
|
1088
|
-
.credits_pending =
|
|
1089
|
-
.credits_posted =
|
|
1187
|
+
.debits_pending = 1,
|
|
1188
|
+
.debits_posted = 1,
|
|
1189
|
+
.credits_pending = 1,
|
|
1190
|
+
.credits_posted = 1,
|
|
1090
1191
|
.timestamp = 2,
|
|
1091
1192
|
}),
|
|
1092
1193
|
},
|
|
@@ -1102,10 +1203,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1102
1203
|
.debits_must_not_exceed_credits = true,
|
|
1103
1204
|
.credits_must_not_exceed_debits = true,
|
|
1104
1205
|
},
|
|
1105
|
-
.debits_pending =
|
|
1106
|
-
.debits_posted =
|
|
1107
|
-
.credits_pending =
|
|
1108
|
-
.credits_posted =
|
|
1206
|
+
.debits_pending = 1,
|
|
1207
|
+
.debits_posted = 1,
|
|
1208
|
+
.credits_pending = 1,
|
|
1209
|
+
.credits_posted = 1,
|
|
1109
1210
|
.timestamp = 2,
|
|
1110
1211
|
}),
|
|
1111
1212
|
},
|
|
@@ -1121,10 +1222,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1121
1222
|
.debits_must_not_exceed_credits = true,
|
|
1122
1223
|
.credits_must_not_exceed_debits = true,
|
|
1123
1224
|
},
|
|
1124
|
-
.debits_pending =
|
|
1125
|
-
.debits_posted =
|
|
1126
|
-
.credits_pending =
|
|
1127
|
-
.credits_posted =
|
|
1225
|
+
.debits_pending = 1,
|
|
1226
|
+
.debits_posted = 1,
|
|
1227
|
+
.credits_pending = 1,
|
|
1228
|
+
.credits_posted = 1,
|
|
1128
1229
|
.timestamp = 2,
|
|
1129
1230
|
}),
|
|
1130
1231
|
},
|
|
@@ -1139,10 +1240,10 @@ test "create/lookup/rollback accounts" {
|
|
|
1139
1240
|
.debits_must_not_exceed_credits = true,
|
|
1140
1241
|
.credits_must_not_exceed_debits = true,
|
|
1141
1242
|
},
|
|
1142
|
-
.debits_pending =
|
|
1143
|
-
.debits_posted =
|
|
1144
|
-
.credits_pending =
|
|
1145
|
-
.credits_posted =
|
|
1243
|
+
.debits_pending = 1,
|
|
1244
|
+
.debits_posted = 1,
|
|
1245
|
+
.credits_pending = 1,
|
|
1246
|
+
.credits_posted = 1,
|
|
1146
1247
|
.timestamp = 2,
|
|
1147
1248
|
}),
|
|
1148
1249
|
},
|
|
@@ -1165,7 +1266,7 @@ test "create/lookup/rollback accounts" {
|
|
|
1165
1266
|
}),
|
|
1166
1267
|
},
|
|
1167
1268
|
.{
|
|
1168
|
-
.result = .
|
|
1269
|
+
.result = .debits_pending_must_be_zero,
|
|
1169
1270
|
.object = mem.zeroInit(Account, .{
|
|
1170
1271
|
.id = 1,
|
|
1171
1272
|
.user_data = 20,
|
|
@@ -1174,32 +1275,31 @@ test "create/lookup/rollback accounts" {
|
|
|
1174
1275
|
.flags = .{
|
|
1175
1276
|
.debits_must_not_exceed_credits = true,
|
|
1176
1277
|
},
|
|
1177
|
-
.debits_pending =
|
|
1178
|
-
.debits_posted =
|
|
1179
|
-
.credits_pending =
|
|
1180
|
-
.credits_posted =
|
|
1278
|
+
.debits_pending = 1,
|
|
1279
|
+
.debits_posted = 1,
|
|
1280
|
+
.credits_pending = 1,
|
|
1281
|
+
.credits_posted = 1,
|
|
1181
1282
|
.timestamp = 2,
|
|
1182
1283
|
}),
|
|
1183
1284
|
},
|
|
1184
1285
|
.{
|
|
1185
|
-
.result = .
|
|
1286
|
+
.result = .debits_posted_must_be_zero,
|
|
1186
1287
|
.object = mem.zeroInit(Account, .{
|
|
1187
1288
|
.id = 1,
|
|
1188
1289
|
.user_data = 20,
|
|
1189
1290
|
.ledger = 30,
|
|
1190
1291
|
.code = 40,
|
|
1191
1292
|
.flags = .{
|
|
1192
|
-
.
|
|
1293
|
+
.debits_must_not_exceed_credits = true,
|
|
1193
1294
|
},
|
|
1194
|
-
.
|
|
1195
|
-
.
|
|
1196
|
-
.
|
|
1197
|
-
.credits_posted = 80,
|
|
1295
|
+
.debits_posted = 1,
|
|
1296
|
+
.credits_pending = 1,
|
|
1297
|
+
.credits_posted = 1,
|
|
1198
1298
|
.timestamp = 2,
|
|
1199
1299
|
}),
|
|
1200
1300
|
},
|
|
1201
1301
|
.{
|
|
1202
|
-
.result = .
|
|
1302
|
+
.result = .credits_pending_must_be_zero,
|
|
1203
1303
|
.object = mem.zeroInit(Account, .{
|
|
1204
1304
|
.id = 1,
|
|
1205
1305
|
.user_data = 20,
|
|
@@ -1208,27 +1308,22 @@ test "create/lookup/rollback accounts" {
|
|
|
1208
1308
|
.flags = .{
|
|
1209
1309
|
.debits_must_not_exceed_credits = true,
|
|
1210
1310
|
},
|
|
1211
|
-
.debits_pending = 50,
|
|
1212
|
-
.debits_posted = 60,
|
|
1213
1311
|
.credits_pending = 1,
|
|
1214
|
-
.credits_posted =
|
|
1312
|
+
.credits_posted = 1,
|
|
1215
1313
|
.timestamp = 2,
|
|
1216
1314
|
}),
|
|
1217
1315
|
},
|
|
1218
1316
|
.{
|
|
1219
|
-
.result = .
|
|
1317
|
+
.result = .credits_posted_must_be_zero,
|
|
1220
1318
|
.object = mem.zeroInit(Account, .{
|
|
1221
1319
|
.id = 1,
|
|
1222
1320
|
.user_data = 20,
|
|
1223
1321
|
.ledger = 30,
|
|
1224
1322
|
.code = 40,
|
|
1225
1323
|
.flags = .{
|
|
1226
|
-
.
|
|
1324
|
+
.debits_must_not_exceed_credits = true,
|
|
1227
1325
|
},
|
|
1228
|
-
.
|
|
1229
|
-
.debits_posted = 60,
|
|
1230
|
-
.credits_pending = 1,
|
|
1231
|
-
.credits_posted = 109,
|
|
1326
|
+
.credits_posted = 1,
|
|
1232
1327
|
.timestamp = 2,
|
|
1233
1328
|
}),
|
|
1234
1329
|
},
|
|
@@ -1242,10 +1337,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1242
1337
|
.flags = .{
|
|
1243
1338
|
.credits_must_not_exceed_debits = true,
|
|
1244
1339
|
},
|
|
1245
|
-
.debits_pending = 50,
|
|
1246
|
-
.debits_posted = 60,
|
|
1247
|
-
.credits_pending = 0,
|
|
1248
|
-
.credits_posted = 0,
|
|
1249
1340
|
.timestamp = 2,
|
|
1250
1341
|
}),
|
|
1251
1342
|
},
|
|
@@ -1256,10 +1347,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1256
1347
|
.user_data = 20,
|
|
1257
1348
|
.ledger = 30,
|
|
1258
1349
|
.code = 40,
|
|
1259
|
-
.debits_pending = 50,
|
|
1260
|
-
.debits_posted = 60,
|
|
1261
|
-
.credits_pending = 70,
|
|
1262
|
-
.credits_posted = 80,
|
|
1263
1350
|
.timestamp = 2,
|
|
1264
1351
|
}),
|
|
1265
1352
|
},
|
|
@@ -1270,10 +1357,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1270
1357
|
.user_data = 2,
|
|
1271
1358
|
.ledger = 30,
|
|
1272
1359
|
.code = 40,
|
|
1273
|
-
.debits_pending = 50,
|
|
1274
|
-
.debits_posted = 60,
|
|
1275
|
-
.credits_pending = 70,
|
|
1276
|
-
.credits_posted = 80,
|
|
1277
1360
|
.timestamp = 2,
|
|
1278
1361
|
}),
|
|
1279
1362
|
},
|
|
@@ -1284,66 +1367,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1284
1367
|
.user_data = 2,
|
|
1285
1368
|
.ledger = 3,
|
|
1286
1369
|
.code = 40,
|
|
1287
|
-
.debits_pending = 50,
|
|
1288
|
-
.debits_posted = 60,
|
|
1289
|
-
.credits_pending = 70,
|
|
1290
|
-
.credits_posted = 80,
|
|
1291
|
-
.timestamp = 2,
|
|
1292
|
-
}),
|
|
1293
|
-
},
|
|
1294
|
-
.{
|
|
1295
|
-
.result = .exists_with_different_debits_pending,
|
|
1296
|
-
.object = mem.zeroInit(Account, .{
|
|
1297
|
-
.id = 1,
|
|
1298
|
-
.user_data = 2,
|
|
1299
|
-
.ledger = 3,
|
|
1300
|
-
.code = 4,
|
|
1301
|
-
.debits_pending = 50,
|
|
1302
|
-
.debits_posted = 60,
|
|
1303
|
-
.credits_pending = 70,
|
|
1304
|
-
.credits_posted = 80,
|
|
1305
|
-
.timestamp = 2,
|
|
1306
|
-
}),
|
|
1307
|
-
},
|
|
1308
|
-
.{
|
|
1309
|
-
.result = .exists_with_different_debits_posted,
|
|
1310
|
-
.object = mem.zeroInit(Account, .{
|
|
1311
|
-
.id = 1,
|
|
1312
|
-
.user_data = 2,
|
|
1313
|
-
.ledger = 3,
|
|
1314
|
-
.code = 4,
|
|
1315
|
-
.debits_pending = 5,
|
|
1316
|
-
.debits_posted = 60,
|
|
1317
|
-
.credits_pending = 70,
|
|
1318
|
-
.credits_posted = 80,
|
|
1319
|
-
.timestamp = 2,
|
|
1320
|
-
}),
|
|
1321
|
-
},
|
|
1322
|
-
.{
|
|
1323
|
-
.result = .exists_with_different_credits_pending,
|
|
1324
|
-
.object = mem.zeroInit(Account, .{
|
|
1325
|
-
.id = 1,
|
|
1326
|
-
.user_data = 2,
|
|
1327
|
-
.ledger = 3,
|
|
1328
|
-
.code = 4,
|
|
1329
|
-
.debits_pending = 5,
|
|
1330
|
-
.debits_posted = 6,
|
|
1331
|
-
.credits_pending = 70,
|
|
1332
|
-
.credits_posted = 80,
|
|
1333
|
-
.timestamp = 2,
|
|
1334
|
-
}),
|
|
1335
|
-
},
|
|
1336
|
-
.{
|
|
1337
|
-
.result = .exists_with_different_credits_posted,
|
|
1338
|
-
.object = mem.zeroInit(Account, .{
|
|
1339
|
-
.id = 1,
|
|
1340
|
-
.user_data = 2,
|
|
1341
|
-
.ledger = 3,
|
|
1342
|
-
.code = 4,
|
|
1343
|
-
.debits_pending = 5,
|
|
1344
|
-
.debits_posted = 6,
|
|
1345
|
-
.credits_pending = 7,
|
|
1346
|
-
.credits_posted = 80,
|
|
1347
1370
|
.timestamp = 2,
|
|
1348
1371
|
}),
|
|
1349
1372
|
},
|
|
@@ -1354,22 +1377,13 @@ test "create/lookup/rollback accounts" {
|
|
|
1354
1377
|
.user_data = 2,
|
|
1355
1378
|
.ledger = 3,
|
|
1356
1379
|
.code = 4,
|
|
1357
|
-
.debits_pending = 5,
|
|
1358
|
-
.debits_posted = 6,
|
|
1359
|
-
.credits_pending = 7,
|
|
1360
|
-
.credits_posted = 8,
|
|
1361
1380
|
.timestamp = 2,
|
|
1362
1381
|
}),
|
|
1363
1382
|
},
|
|
1364
1383
|
};
|
|
1365
1384
|
|
|
1366
1385
|
var context: TestContext = undefined;
|
|
1367
|
-
try context.init(testing.allocator
|
|
1368
|
-
.lsm_forest_node_count = 1,
|
|
1369
|
-
.cache_size_accounts = vectors.len,
|
|
1370
|
-
.cache_size_transfers = 0,
|
|
1371
|
-
.cache_size_posted = 0,
|
|
1372
|
-
});
|
|
1386
|
+
try context.init(testing.allocator);
|
|
1373
1387
|
defer context.deinit(testing.allocator);
|
|
1374
1388
|
|
|
1375
1389
|
const state_machine = &context.state_machine;
|
|
@@ -1391,10 +1405,6 @@ test "create/lookup/rollback accounts" {
|
|
|
1391
1405
|
}
|
|
1392
1406
|
|
|
1393
1407
|
test "linked accounts" {
|
|
1394
|
-
const accounts_max = 5;
|
|
1395
|
-
const transfers_max = 0;
|
|
1396
|
-
const transfers_pending_max = 0;
|
|
1397
|
-
|
|
1398
1408
|
var accounts = [_]Account{
|
|
1399
1409
|
// An individual event (successful):
|
|
1400
1410
|
mem.zeroInit(Account, .{ .id = 7, .code = 1, .ledger = 1 }),
|
|
@@ -1430,23 +1440,18 @@ test "linked accounts" {
|
|
|
1430
1440
|
};
|
|
1431
1441
|
|
|
1432
1442
|
var context: TestContext = undefined;
|
|
1433
|
-
try context.init(testing.allocator
|
|
1434
|
-
.lsm_forest_node_count = 1,
|
|
1435
|
-
.cache_size_accounts = accounts_max,
|
|
1436
|
-
.cache_size_transfers = transfers_max,
|
|
1437
|
-
.cache_size_posted = transfers_pending_max,
|
|
1438
|
-
});
|
|
1443
|
+
try context.init(testing.allocator);
|
|
1439
1444
|
defer context.deinit(testing.allocator);
|
|
1440
1445
|
|
|
1441
1446
|
const state_machine = &context.state_machine;
|
|
1442
1447
|
|
|
1443
1448
|
const input = mem.asBytes(&accounts);
|
|
1444
1449
|
|
|
1445
|
-
const output = try testing.allocator.
|
|
1450
|
+
const output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
1446
1451
|
defer testing.allocator.free(output);
|
|
1447
1452
|
|
|
1448
1453
|
_ = state_machine.prepare(.create_accounts, input);
|
|
1449
|
-
const size = state_machine.commit(0,
|
|
1454
|
+
const size = state_machine.commit(0, 1, .create_accounts, input, output);
|
|
1450
1455
|
const results = mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1451
1456
|
|
|
1452
1457
|
try expectEqualSlices(
|
|
@@ -1474,6 +1479,124 @@ test "linked accounts" {
|
|
|
1474
1479
|
// All our rollback handlers appear to be commutative.
|
|
1475
1480
|
}
|
|
1476
1481
|
|
|
1482
|
+
test "linked_event_chain_open" {
|
|
1483
|
+
var accounts = [_]Account{
|
|
1484
|
+
// A chain of 3 events (the last event in the chain closes the chain with linked=false):
|
|
1485
|
+
mem.zeroInit(Account, .{ .id = 1, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1486
|
+
mem.zeroInit(Account, .{ .id = 2, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1487
|
+
mem.zeroInit(Account, .{ .id = 3, .code = 1, .ledger = 1 }),
|
|
1488
|
+
|
|
1489
|
+
// An open chain of 2 events:
|
|
1490
|
+
mem.zeroInit(Account, .{ .id = 4, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1491
|
+
mem.zeroInit(Account, .{ .id = 5, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
var context: TestContext = undefined;
|
|
1495
|
+
try context.init(testing.allocator);
|
|
1496
|
+
defer context.deinit(testing.allocator);
|
|
1497
|
+
|
|
1498
|
+
const state_machine = &context.state_machine;
|
|
1499
|
+
|
|
1500
|
+
const input = mem.asBytes(&accounts);
|
|
1501
|
+
|
|
1502
|
+
const output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
1503
|
+
defer testing.allocator.free(output);
|
|
1504
|
+
|
|
1505
|
+
_ = state_machine.prepare(.create_accounts, input);
|
|
1506
|
+
const size = state_machine.commit(0, 1, .create_accounts, input, output);
|
|
1507
|
+
const results = mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1508
|
+
|
|
1509
|
+
try expectEqualSlices(
|
|
1510
|
+
CreateAccountsResult,
|
|
1511
|
+
&[_]CreateAccountsResult{
|
|
1512
|
+
.{ .index = 3, .result = .linked_event_failed },
|
|
1513
|
+
.{ .index = 4, .result = .linked_event_chain_open },
|
|
1514
|
+
},
|
|
1515
|
+
results,
|
|
1516
|
+
);
|
|
1517
|
+
|
|
1518
|
+
try expectEqual(accounts[0], state_machine.get_account(accounts[0].id).?.*);
|
|
1519
|
+
try expectEqual(accounts[1], state_machine.get_account(accounts[1].id).?.*);
|
|
1520
|
+
try expectEqual(accounts[2], state_machine.get_account(accounts[2].id).?.*);
|
|
1521
|
+
|
|
1522
|
+
try expectEqual(@as(?*const Account, null), state_machine.get_account(accounts[3].id));
|
|
1523
|
+
try expectEqual(@as(?*const Account, null), state_machine.get_account(accounts[4].id));
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
test "linked_event_chain_open for an already failed batch" {
|
|
1527
|
+
var accounts = [_]Account{
|
|
1528
|
+
// An individual event (successful):
|
|
1529
|
+
mem.zeroInit(Account, .{ .id = 1, .code = 1, .ledger = 1 }),
|
|
1530
|
+
|
|
1531
|
+
// An open chain of 3 events (the second one fails):
|
|
1532
|
+
mem.zeroInit(Account, .{ .id = 2, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1533
|
+
mem.zeroInit(Account, .{ .id = 1, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1534
|
+
mem.zeroInit(Account, .{ .id = 3, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1537
|
+
var context: TestContext = undefined;
|
|
1538
|
+
try context.init(testing.allocator);
|
|
1539
|
+
defer context.deinit(testing.allocator);
|
|
1540
|
+
|
|
1541
|
+
const state_machine = &context.state_machine;
|
|
1542
|
+
|
|
1543
|
+
const input = mem.asBytes(&accounts);
|
|
1544
|
+
|
|
1545
|
+
const output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
1546
|
+
defer testing.allocator.free(output);
|
|
1547
|
+
|
|
1548
|
+
_ = state_machine.prepare(.create_accounts, input);
|
|
1549
|
+
const size = state_machine.commit(0, 1, .create_accounts, input, output);
|
|
1550
|
+
const results = mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1551
|
+
|
|
1552
|
+
try expectEqualSlices(
|
|
1553
|
+
CreateAccountsResult,
|
|
1554
|
+
&[_]CreateAccountsResult{
|
|
1555
|
+
.{ .index = 1, .result = .linked_event_failed },
|
|
1556
|
+
.{ .index = 2, .result = .exists_with_different_flags },
|
|
1557
|
+
.{ .index = 3, .result = .linked_event_chain_open },
|
|
1558
|
+
},
|
|
1559
|
+
results,
|
|
1560
|
+
);
|
|
1561
|
+
|
|
1562
|
+
try expectEqual(accounts[0], state_machine.get_account(accounts[0].id).?.*);
|
|
1563
|
+
|
|
1564
|
+
try expectEqual(@as(?*const Account, null), state_machine.get_account(accounts[1].id));
|
|
1565
|
+
try expectEqual(@as(?*const Account, null), state_machine.get_account(accounts[3].id));
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
test "linked_event_chain_open for a batch of 1" {
|
|
1569
|
+
var accounts = [_]Account{
|
|
1570
|
+
// Just one event with linked = true
|
|
1571
|
+
mem.zeroInit(Account, .{ .id = 1, .code = 1, .ledger = 1, .flags = .{ .linked = true } }),
|
|
1572
|
+
};
|
|
1573
|
+
|
|
1574
|
+
var context: TestContext = undefined;
|
|
1575
|
+
try context.init(testing.allocator);
|
|
1576
|
+
defer context.deinit(testing.allocator);
|
|
1577
|
+
|
|
1578
|
+
const state_machine = &context.state_machine;
|
|
1579
|
+
|
|
1580
|
+
const input = mem.asBytes(&accounts);
|
|
1581
|
+
|
|
1582
|
+
const output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
1583
|
+
defer testing.allocator.free(output);
|
|
1584
|
+
|
|
1585
|
+
_ = state_machine.prepare(.create_accounts, input);
|
|
1586
|
+
const size = state_machine.commit(0, 1, .create_accounts, input, output);
|
|
1587
|
+
const results = mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1588
|
+
|
|
1589
|
+
try expectEqualSlices(
|
|
1590
|
+
CreateAccountsResult,
|
|
1591
|
+
&[_]CreateAccountsResult{
|
|
1592
|
+
.{ .index = 0, .result = .linked_event_chain_open },
|
|
1593
|
+
},
|
|
1594
|
+
results,
|
|
1595
|
+
);
|
|
1596
|
+
|
|
1597
|
+
try expectEqual(@as(?*const Account, null), state_machine.get_account(accounts[0].id));
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1477
1600
|
// The goal is to ensure that:
|
|
1478
1601
|
// 1. all CreateTransferResult enums are covered, with
|
|
1479
1602
|
// 2. enums tested in the order that they are defined, for easier auditing of coverage, and that
|
|
@@ -1518,34 +1641,26 @@ test "create/lookup/rollback transfers" {
|
|
|
1518
1641
|
};
|
|
1519
1642
|
|
|
1520
1643
|
var context: TestContext = undefined;
|
|
1521
|
-
try context.init(testing.allocator
|
|
1522
|
-
.lsm_forest_node_count = 1,
|
|
1523
|
-
.cache_size_accounts = accounts.len,
|
|
1524
|
-
.cache_size_transfers = 1,
|
|
1525
|
-
.cache_size_posted = 0,
|
|
1526
|
-
});
|
|
1644
|
+
try context.init(testing.allocator);
|
|
1527
1645
|
defer context.deinit(testing.allocator);
|
|
1528
1646
|
|
|
1529
1647
|
const state_machine = &context.state_machine;
|
|
1530
1648
|
|
|
1531
1649
|
const input = mem.asBytes(&accounts);
|
|
1532
1650
|
|
|
1533
|
-
const output = try testing.allocator.
|
|
1651
|
+
const output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
1534
1652
|
defer testing.allocator.free(output);
|
|
1535
1653
|
|
|
1536
1654
|
_ = state_machine.prepare(.create_accounts, input);
|
|
1537
|
-
const size = state_machine.commit(0, 0, .create_accounts, input, output);
|
|
1538
|
-
|
|
1539
|
-
const errors = mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1540
|
-
try expect(errors.len == 0);
|
|
1541
1655
|
|
|
1542
1656
|
for (accounts) |account| {
|
|
1657
|
+
state_machine.forest.grooves.accounts.put(&account);
|
|
1543
1658
|
try expectEqual(account, state_machine.get_account(account.id).?.*);
|
|
1544
1659
|
}
|
|
1545
1660
|
|
|
1546
1661
|
const Vector = struct { result: CreateTransferResult, object: Transfer };
|
|
1547
1662
|
|
|
1548
|
-
const timestamp: u64 =
|
|
1663
|
+
const timestamp: u64 = state_machine.prepare_timestamp + 1;
|
|
1549
1664
|
const vectors = [_]Vector{
|
|
1550
1665
|
.{
|
|
1551
1666
|
.result = .reserved_flag,
|
|
@@ -1719,7 +1834,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1719
1834
|
.id = 1,
|
|
1720
1835
|
.debit_account_id = 100,
|
|
1721
1836
|
.credit_account_id = 200,
|
|
1722
|
-
.timeout = 1,
|
|
1837
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1723
1838
|
.ledger = 0,
|
|
1724
1839
|
.code = 0,
|
|
1725
1840
|
.amount = 0,
|
|
@@ -1732,7 +1847,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1732
1847
|
.id = 1,
|
|
1733
1848
|
.debit_account_id = 100,
|
|
1734
1849
|
.credit_account_id = 200,
|
|
1735
|
-
.timeout = 1,
|
|
1850
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1736
1851
|
.ledger = 0,
|
|
1737
1852
|
.code = 0,
|
|
1738
1853
|
.flags = .{ .pending = true },
|
|
@@ -1746,7 +1861,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1746
1861
|
.id = 1,
|
|
1747
1862
|
.debit_account_id = 100,
|
|
1748
1863
|
.credit_account_id = 200,
|
|
1749
|
-
.timeout = 1,
|
|
1864
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1750
1865
|
.ledger = 100,
|
|
1751
1866
|
.code = 0,
|
|
1752
1867
|
.flags = .{ .pending = true },
|
|
@@ -1760,7 +1875,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1760
1875
|
.id = 1,
|
|
1761
1876
|
.debit_account_id = 100,
|
|
1762
1877
|
.credit_account_id = 200,
|
|
1763
|
-
.timeout = 1,
|
|
1878
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1764
1879
|
.ledger = 100,
|
|
1765
1880
|
.code = 1,
|
|
1766
1881
|
.flags = .{ .pending = true },
|
|
@@ -1774,7 +1889,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1774
1889
|
.id = 1,
|
|
1775
1890
|
.debit_account_id = 100,
|
|
1776
1891
|
.credit_account_id = 200,
|
|
1777
|
-
.timeout = 1,
|
|
1892
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1778
1893
|
.ledger = 100,
|
|
1779
1894
|
.code = 1,
|
|
1780
1895
|
.flags = .{ .pending = true },
|
|
@@ -1788,7 +1903,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1788
1903
|
.id = 1,
|
|
1789
1904
|
.debit_account_id = 1,
|
|
1790
1905
|
.credit_account_id = 200,
|
|
1791
|
-
.timeout = 1,
|
|
1906
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1792
1907
|
.ledger = 100,
|
|
1793
1908
|
.code = 1,
|
|
1794
1909
|
.flags = .{ .pending = true },
|
|
@@ -1802,9 +1917,11 @@ test "create/lookup/rollback transfers" {
|
|
|
1802
1917
|
.id = 1,
|
|
1803
1918
|
.debit_account_id = 1,
|
|
1804
1919
|
.credit_account_id = 2,
|
|
1920
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1805
1921
|
.ledger = 100,
|
|
1806
1922
|
.code = 1,
|
|
1807
1923
|
.amount = 1,
|
|
1924
|
+
.flags = .{ .pending = true },
|
|
1808
1925
|
.timestamp = timestamp,
|
|
1809
1926
|
}),
|
|
1810
1927
|
},
|
|
@@ -1814,9 +1931,11 @@ test "create/lookup/rollback transfers" {
|
|
|
1814
1931
|
.id = 1,
|
|
1815
1932
|
.debit_account_id = 1,
|
|
1816
1933
|
.credit_account_id = 3,
|
|
1934
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1817
1935
|
.ledger = 100,
|
|
1818
1936
|
.code = 1,
|
|
1819
1937
|
.amount = 1,
|
|
1938
|
+
.flags = .{ .pending = true },
|
|
1820
1939
|
.timestamp = timestamp,
|
|
1821
1940
|
}),
|
|
1822
1941
|
},
|
|
@@ -1826,7 +1945,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1826
1945
|
.id = 1,
|
|
1827
1946
|
.debit_account_id = 1,
|
|
1828
1947
|
.credit_account_id = 3,
|
|
1829
|
-
.timeout =
|
|
1948
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1830
1949
|
.ledger = 1,
|
|
1831
1950
|
.code = 1,
|
|
1832
1951
|
.flags = .{ .pending = true },
|
|
@@ -1840,7 +1959,7 @@ test "create/lookup/rollback transfers" {
|
|
|
1840
1959
|
.id = 1,
|
|
1841
1960
|
.debit_account_id = 1,
|
|
1842
1961
|
.credit_account_id = 3,
|
|
1843
|
-
.timeout =
|
|
1962
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1844
1963
|
.ledger = 1,
|
|
1845
1964
|
.code = 1,
|
|
1846
1965
|
.flags = .{ .pending = true },
|
|
@@ -1854,8 +1973,10 @@ test "create/lookup/rollback transfers" {
|
|
|
1854
1973
|
.id = 1,
|
|
1855
1974
|
.debit_account_id = 1,
|
|
1856
1975
|
.credit_account_id = 3,
|
|
1976
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1857
1977
|
.ledger = 1,
|
|
1858
1978
|
.code = 1,
|
|
1979
|
+
.flags = .{ .pending = true },
|
|
1859
1980
|
.amount = math.maxInt(u64) - accounts[1 - 1].debits_posted + 1,
|
|
1860
1981
|
.timestamp = timestamp,
|
|
1861
1982
|
}),
|
|
@@ -1866,8 +1987,10 @@ test "create/lookup/rollback transfers" {
|
|
|
1866
1987
|
.id = 1,
|
|
1867
1988
|
.debit_account_id = 1,
|
|
1868
1989
|
.credit_account_id = 3,
|
|
1990
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1869
1991
|
.ledger = 1,
|
|
1870
1992
|
.code = 1,
|
|
1993
|
+
.flags = .{ .pending = true },
|
|
1871
1994
|
.amount = math.maxInt(u64) - accounts[3 - 1].credits_posted + 1,
|
|
1872
1995
|
.timestamp = timestamp,
|
|
1873
1996
|
}),
|
|
@@ -1878,8 +2001,10 @@ test "create/lookup/rollback transfers" {
|
|
|
1878
2001
|
.id = 1,
|
|
1879
2002
|
.debit_account_id = 1,
|
|
1880
2003
|
.credit_account_id = 3,
|
|
2004
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1881
2005
|
.ledger = 1,
|
|
1882
2006
|
.code = 1,
|
|
2007
|
+
.flags = .{ .pending = true },
|
|
1883
2008
|
.amount = math.maxInt(u64) -
|
|
1884
2009
|
accounts[1 - 1].debits_pending -
|
|
1885
2010
|
accounts[1 - 1].debits_posted + 1,
|
|
@@ -1892,14 +2017,32 @@ test "create/lookup/rollback transfers" {
|
|
|
1892
2017
|
.id = 1,
|
|
1893
2018
|
.debit_account_id = 1,
|
|
1894
2019
|
.credit_account_id = 3,
|
|
2020
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
1895
2021
|
.ledger = 1,
|
|
1896
2022
|
.code = 1,
|
|
2023
|
+
.flags = .{ .pending = true },
|
|
1897
2024
|
.amount = math.maxInt(u64) -
|
|
1898
2025
|
accounts[3 - 1].credits_pending -
|
|
1899
2026
|
accounts[3 - 1].credits_posted + 1,
|
|
1900
2027
|
.timestamp = timestamp,
|
|
1901
2028
|
}),
|
|
1902
2029
|
},
|
|
2030
|
+
.{
|
|
2031
|
+
.result = .overflows_timeout,
|
|
2032
|
+
.object = mem.zeroInit(Transfer, .{
|
|
2033
|
+
.id = 1,
|
|
2034
|
+
.debit_account_id = 4,
|
|
2035
|
+
.credit_account_id = 5,
|
|
2036
|
+
.timeout = (std.math.maxInt(u64) - timestamp) + 1,
|
|
2037
|
+
.ledger = 1,
|
|
2038
|
+
.code = 1,
|
|
2039
|
+
.flags = .{ .pending = true },
|
|
2040
|
+
.amount = accounts[4 - 1].credits_posted -
|
|
2041
|
+
accounts[4 - 1].debits_pending -
|
|
2042
|
+
accounts[4 - 1].debits_posted + 1,
|
|
2043
|
+
.timestamp = timestamp,
|
|
2044
|
+
}),
|
|
2045
|
+
},
|
|
1903
2046
|
.{
|
|
1904
2047
|
.result = .exceeds_credits,
|
|
1905
2048
|
.object = mem.zeroInit(Transfer, .{
|
|
@@ -2132,11 +2275,6 @@ test "create/lookup/rollback transfers" {
|
|
|
2132
2275
|
try test_account_balances(state_machine, 1, 100, 200, 0, 0);
|
|
2133
2276
|
try test_account_balances(state_machine, 3, 0, 0, 110, 210);
|
|
2134
2277
|
try expect(state_machine.get_transfer(1) == null);
|
|
2135
|
-
|
|
2136
|
-
for (accounts) |account| {
|
|
2137
|
-
state_machine.create_account_rollback(&account);
|
|
2138
|
-
try expect(state_machine.get_account(account.id) == null);
|
|
2139
|
-
}
|
|
2140
2278
|
}
|
|
2141
2279
|
|
|
2142
2280
|
test "create/lookup/rollback 2-phase transfers" {
|
|
@@ -2198,12 +2336,7 @@ test "create/lookup/rollback 2-phase transfers" {
|
|
|
2198
2336
|
};
|
|
2199
2337
|
|
|
2200
2338
|
var context: TestContext = undefined;
|
|
2201
|
-
try context.init(testing.allocator
|
|
2202
|
-
.lsm_forest_node_count = 1,
|
|
2203
|
-
.cache_size_accounts = accounts.len,
|
|
2204
|
-
.cache_size_transfers = 100,
|
|
2205
|
-
.cache_size_posted = 1,
|
|
2206
|
-
});
|
|
2339
|
+
try context.init(testing.allocator);
|
|
2207
2340
|
defer context.deinit(testing.allocator);
|
|
2208
2341
|
|
|
2209
2342
|
const state_machine = &context.state_machine;
|
|
@@ -2211,12 +2344,12 @@ test "create/lookup/rollback 2-phase transfers" {
|
|
|
2211
2344
|
// Create accounts:
|
|
2212
2345
|
const accounts_input = mem.asBytes(&accounts);
|
|
2213
2346
|
|
|
2214
|
-
const accounts_output = try testing.allocator.
|
|
2347
|
+
const accounts_output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
2215
2348
|
defer testing.allocator.free(accounts_output);
|
|
2216
2349
|
|
|
2217
2350
|
const accounts_timestamp = state_machine.prepare(.create_accounts, accounts_input);
|
|
2218
2351
|
{
|
|
2219
|
-
const size = state_machine.commit(0,
|
|
2352
|
+
const size = state_machine.commit(0, 1, .create_accounts, accounts_input, accounts_output);
|
|
2220
2353
|
const errors = mem.bytesAsSlice(CreateAccountsResult, accounts_output[0..size]);
|
|
2221
2354
|
try expectEqual(@as(usize, 0), errors.len);
|
|
2222
2355
|
}
|
|
@@ -2227,13 +2360,13 @@ test "create/lookup/rollback 2-phase transfers" {
|
|
|
2227
2360
|
// Create pending transfers:
|
|
2228
2361
|
const transfers_input = mem.asBytes(&transfers);
|
|
2229
2362
|
|
|
2230
|
-
const transfers_output = try testing.allocator.
|
|
2363
|
+
const transfers_output = try testing.allocator.alignedAlloc(u8, 16, 4096);
|
|
2231
2364
|
defer testing.allocator.free(transfers_output);
|
|
2232
2365
|
|
|
2233
2366
|
const transfers_timestamp = state_machine.prepare(.create_transfers, transfers_input);
|
|
2234
2367
|
try testing.expect(transfers_timestamp > accounts_timestamp);
|
|
2235
2368
|
{
|
|
2236
|
-
const size = state_machine.commit(0,
|
|
2369
|
+
const size = state_machine.commit(0, 2, .create_transfers, transfers_input, transfers_output);
|
|
2237
2370
|
const errors = mem.bytesAsSlice(CreateTransfersResult, transfers_output[0..size]);
|
|
2238
2371
|
try expectEqual(@as(usize, 0), errors.len);
|
|
2239
2372
|
}
|
|
@@ -2901,7 +3034,9 @@ fn test_equal_n_bytes(comptime n: usize) !void {
|
|
|
2901
3034
|
|
|
2902
3035
|
test "StateMachine: ref all decls" {
|
|
2903
3036
|
const Storage = @import("storage.zig").Storage;
|
|
2904
|
-
const StateMachine = StateMachineType(Storage
|
|
3037
|
+
const StateMachine = StateMachineType(Storage, .{
|
|
3038
|
+
.message_body_size_max = 1000 * @sizeOf(Account),
|
|
3039
|
+
});
|
|
2905
3040
|
|
|
2906
3041
|
std.testing.refAllDecls(StateMachine);
|
|
2907
3042
|
}
|