tigerbeetle-node 0.4.2 → 0.5.2
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 +19 -5
- package/dist/benchmark.js.map +1 -1
- package/dist/index.d.ts +18 -16
- package/dist/index.js +35 -13
- package/dist/index.js.map +1 -1
- package/dist/test.js +12 -0
- package/dist/test.js.map +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.sh +2 -2
- package/src/benchmark.ts +2 -2
- package/src/index.ts +29 -4
- package/src/node.zig +120 -17
- package/src/test.ts +14 -0
- package/src/tigerbeetle/scripts/install.sh +1 -1
- package/src/tigerbeetle/scripts/install_zig.bat +109 -0
- package/src/tigerbeetle/scripts/install_zig.sh +4 -2
- package/src/tigerbeetle/scripts/lint.zig +8 -2
- package/src/tigerbeetle/scripts/vopr.bat +48 -0
- package/src/tigerbeetle/src/benchmark.zig +10 -8
- package/src/tigerbeetle/src/cli.zig +6 -4
- package/src/tigerbeetle/src/config.zig +2 -2
- package/src/tigerbeetle/src/demo.zig +119 -89
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +5 -3
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +2 -3
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_04_create_transfers_two_phase_commit.zig +5 -3
- package/src/tigerbeetle/src/demo_05_accept_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_06_reject_transfers.zig +5 -3
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +7 -0
- package/src/tigerbeetle/src/io/benchmark.zig +238 -0
- package/src/tigerbeetle/src/{io_darwin.zig → io/darwin.zig} +89 -124
- package/src/tigerbeetle/src/io/linux.zig +933 -0
- package/src/tigerbeetle/src/io/test.zig +621 -0
- package/src/tigerbeetle/src/io.zig +7 -1328
- package/src/tigerbeetle/src/main.zig +18 -10
- package/src/tigerbeetle/src/message_bus.zig +43 -60
- package/src/tigerbeetle/src/message_pool.zig +3 -2
- package/src/tigerbeetle/src/ring_buffer.zig +135 -68
- package/src/tigerbeetle/src/simulator.zig +41 -37
- package/src/tigerbeetle/src/state_machine.zig +851 -26
- package/src/tigerbeetle/src/storage.zig +49 -46
- package/src/tigerbeetle/src/test/cluster.zig +2 -2
- package/src/tigerbeetle/src/test/message_bus.zig +6 -6
- package/src/tigerbeetle/src/test/network.zig +3 -3
- package/src/tigerbeetle/src/test/packet_simulator.zig +32 -29
- package/src/tigerbeetle/src/test/state_checker.zig +2 -2
- package/src/tigerbeetle/src/test/state_machine.zig +4 -0
- package/src/tigerbeetle/src/test/storage.zig +39 -19
- package/src/tigerbeetle/src/test/time.zig +2 -2
- package/src/tigerbeetle/src/tigerbeetle.zig +6 -129
- package/src/tigerbeetle/src/time.zig +6 -5
- package/src/tigerbeetle/src/vsr/client.zig +11 -11
- package/src/tigerbeetle/src/vsr/clock.zig +26 -43
- package/src/tigerbeetle/src/vsr/journal.zig +7 -6
- package/src/tigerbeetle/src/vsr/marzullo.zig +6 -3
- package/src/tigerbeetle/src/vsr/replica.zig +51 -48
- package/src/tigerbeetle/src/vsr.zig +24 -20
- package/src/translate.zig +55 -55
|
@@ -2,7 +2,25 @@ const std = @import("std");
|
|
|
2
2
|
const assert = std.debug.assert;
|
|
3
3
|
const log = std.log.scoped(.state_machine);
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const tb = @import("tigerbeetle.zig");
|
|
6
|
+
|
|
7
|
+
const Account = tb.Account;
|
|
8
|
+
const AccountFlags = tb.AccountFlags;
|
|
9
|
+
|
|
10
|
+
const Transfer = tb.Transfer;
|
|
11
|
+
const TransferFlags = tb.TransferFlags;
|
|
12
|
+
|
|
13
|
+
const Commit = tb.Commit;
|
|
14
|
+
const CommitFlags = tb.CommitFlags;
|
|
15
|
+
|
|
16
|
+
const CreateAccountsResult = tb.CreateAccountsResult;
|
|
17
|
+
const CreateTransfersResult = tb.CreateTransfersResult;
|
|
18
|
+
const CommitTransfersResult = tb.CommitTransfersResult;
|
|
19
|
+
|
|
20
|
+
const CreateAccountResult = tb.CreateAccountResult;
|
|
21
|
+
const CreateTransferResult = tb.CreateTransferResult;
|
|
22
|
+
const CommitTransferResult = tb.CommitTransferResult;
|
|
23
|
+
const LookupAccountResult = tb.LookupAccountResult;
|
|
6
24
|
|
|
7
25
|
const HashMapAccounts = std.AutoHashMap(u128, Account);
|
|
8
26
|
const HashMapTransfers = std.AutoHashMap(u128, Transfer);
|
|
@@ -20,13 +38,10 @@ pub const StateMachine = struct {
|
|
|
20
38
|
create_transfers,
|
|
21
39
|
commit_transfers,
|
|
22
40
|
lookup_accounts,
|
|
23
|
-
|
|
24
|
-
pub fn jsonStringify(self: Command, options: StringifyOptions, writer: anytype) !void {
|
|
25
|
-
try std.fmt.format(writer, "\"{}\"", .{@tagName(self)});
|
|
26
|
-
}
|
|
41
|
+
lookup_transfers,
|
|
27
42
|
};
|
|
28
43
|
|
|
29
|
-
allocator:
|
|
44
|
+
allocator: std.mem.Allocator,
|
|
30
45
|
prepare_timestamp: u64,
|
|
31
46
|
commit_timestamp: u64,
|
|
32
47
|
accounts: HashMapAccounts,
|
|
@@ -34,22 +49,22 @@ pub const StateMachine = struct {
|
|
|
34
49
|
commits: HashMapCommits,
|
|
35
50
|
|
|
36
51
|
pub fn init(
|
|
37
|
-
allocator:
|
|
52
|
+
allocator: std.mem.Allocator,
|
|
38
53
|
accounts_max: usize,
|
|
39
54
|
transfers_max: usize,
|
|
40
55
|
commits_max: usize,
|
|
41
56
|
) !StateMachine {
|
|
42
57
|
var accounts = HashMapAccounts.init(allocator);
|
|
43
58
|
errdefer accounts.deinit();
|
|
44
|
-
try accounts.
|
|
59
|
+
try accounts.ensureTotalCapacity(@intCast(u32, accounts_max));
|
|
45
60
|
|
|
46
61
|
var transfers = HashMapTransfers.init(allocator);
|
|
47
62
|
errdefer transfers.deinit();
|
|
48
|
-
try transfers.
|
|
63
|
+
try transfers.ensureTotalCapacity(@intCast(u32, transfers_max));
|
|
49
64
|
|
|
50
65
|
var commits = HashMapCommits.init(allocator);
|
|
51
66
|
errdefer commits.deinit();
|
|
52
|
-
try commits.
|
|
67
|
+
try commits.ensureTotalCapacity(@intCast(u32, commits_max));
|
|
53
68
|
|
|
54
69
|
// TODO After recovery, set prepare_timestamp max(wall clock, op timestamp).
|
|
55
70
|
// TODO After recovery, set commit_timestamp max(wall clock, commit timestamp).
|
|
@@ -76,6 +91,7 @@ pub const StateMachine = struct {
|
|
|
76
91
|
.create_transfers => Transfer,
|
|
77
92
|
.commit_transfers => Commit,
|
|
78
93
|
.lookup_accounts => u128,
|
|
94
|
+
.lookup_transfers => u128,
|
|
79
95
|
else => unreachable,
|
|
80
96
|
};
|
|
81
97
|
}
|
|
@@ -86,6 +102,7 @@ pub const StateMachine = struct {
|
|
|
86
102
|
.create_transfers => CreateTransfersResult,
|
|
87
103
|
.commit_transfers => CommitTransfersResult,
|
|
88
104
|
.lookup_accounts => Account,
|
|
105
|
+
.lookup_transfers => Transfer,
|
|
89
106
|
else => unreachable,
|
|
90
107
|
};
|
|
91
108
|
}
|
|
@@ -98,6 +115,7 @@ pub const StateMachine = struct {
|
|
|
98
115
|
.create_transfers => self.prepare_timestamps(realtime, .create_transfers, input),
|
|
99
116
|
.commit_transfers => self.prepare_timestamps(realtime, .commit_transfers, input),
|
|
100
117
|
.lookup_accounts => {},
|
|
118
|
+
.lookup_transfers => {},
|
|
101
119
|
else => unreachable,
|
|
102
120
|
}
|
|
103
121
|
}
|
|
@@ -136,6 +154,8 @@ pub const StateMachine = struct {
|
|
|
136
154
|
input: []const u8,
|
|
137
155
|
output: []u8,
|
|
138
156
|
) usize {
|
|
157
|
+
_ = client;
|
|
158
|
+
|
|
139
159
|
return switch (operation) {
|
|
140
160
|
.init => unreachable,
|
|
141
161
|
.register => 0,
|
|
@@ -143,6 +163,7 @@ pub const StateMachine = struct {
|
|
|
143
163
|
.create_transfers => self.execute(.create_transfers, input, output),
|
|
144
164
|
.commit_transfers => self.execute(.commit_transfers, input, output),
|
|
145
165
|
.lookup_accounts => self.execute_lookup_accounts(input, output),
|
|
166
|
+
.lookup_transfers => self.execute_lookup_transfers(input, output),
|
|
146
167
|
else => unreachable,
|
|
147
168
|
};
|
|
148
169
|
}
|
|
@@ -153,7 +174,7 @@ pub const StateMachine = struct {
|
|
|
153
174
|
input: []const u8,
|
|
154
175
|
output: []u8,
|
|
155
176
|
) usize {
|
|
156
|
-
comptime assert(operation != .lookup_accounts);
|
|
177
|
+
comptime assert(operation != .lookup_accounts and operation != .lookup_transfers);
|
|
157
178
|
|
|
158
179
|
const events = std.mem.bytesAsSlice(Event(operation), input);
|
|
159
180
|
var results = std.mem.bytesAsSlice(Result(operation), output);
|
|
@@ -255,10 +276,10 @@ pub const StateMachine = struct {
|
|
|
255
276
|
|
|
256
277
|
fn execute_lookup_accounts(self: *StateMachine, input: []const u8, output: []u8) usize {
|
|
257
278
|
const batch = std.mem.bytesAsSlice(u128, input);
|
|
258
|
-
|
|
259
|
-
|
|
279
|
+
const output_len = @divFloor(output.len, @sizeOf(Account)) * @sizeOf(Account);
|
|
280
|
+
const results = std.mem.bytesAsSlice(Account, output[0..output_len]);
|
|
260
281
|
var results_count: usize = 0;
|
|
261
|
-
for (batch) |id
|
|
282
|
+
for (batch) |id| {
|
|
262
283
|
if (self.get_account(id)) |result| {
|
|
263
284
|
results[results_count] = result.*;
|
|
264
285
|
results_count += 1;
|
|
@@ -267,6 +288,20 @@ pub const StateMachine = struct {
|
|
|
267
288
|
return results_count * @sizeOf(Account);
|
|
268
289
|
}
|
|
269
290
|
|
|
291
|
+
fn execute_lookup_transfers(self: *StateMachine, input: []const u8, output: []u8) usize {
|
|
292
|
+
const batch = std.mem.bytesAsSlice(u128, input);
|
|
293
|
+
const output_len = @divFloor(output.len, @sizeOf(Transfer)) * @sizeOf(Transfer);
|
|
294
|
+
const results = std.mem.bytesAsSlice(Transfer, output[0..output_len]);
|
|
295
|
+
var results_count: usize = 0;
|
|
296
|
+
for (batch) |id| {
|
|
297
|
+
if (self.get_transfer(id)) |result| {
|
|
298
|
+
results[results_count] = result.*;
|
|
299
|
+
results_count += 1;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return results_count * @sizeOf(Transfer);
|
|
303
|
+
}
|
|
304
|
+
|
|
270
305
|
fn create_account(self: *StateMachine, a: Account) CreateAccountResult {
|
|
271
306
|
assert(a.timestamp > self.commit_timestamp);
|
|
272
307
|
|
|
@@ -339,8 +374,7 @@ pub const StateMachine = struct {
|
|
|
339
374
|
const exists = insert.value_ptr.*;
|
|
340
375
|
if (exists.debit_account_id != t.debit_account_id) {
|
|
341
376
|
return .exists_with_different_debit_account_id;
|
|
342
|
-
}
|
|
343
|
-
if (exists.credit_account_id != t.credit_account_id) {
|
|
377
|
+
} else if (exists.credit_account_id != t.credit_account_id) {
|
|
344
378
|
return .exists_with_different_credit_account_id;
|
|
345
379
|
}
|
|
346
380
|
if (exists.amount != t.amount) return .exists_with_different_amount;
|
|
@@ -437,6 +471,7 @@ pub const StateMachine = struct {
|
|
|
437
471
|
}
|
|
438
472
|
|
|
439
473
|
fn commit_transfer_rollback(self: *StateMachine, c: Commit) void {
|
|
474
|
+
assert(self.get_commit(c.id) != null);
|
|
440
475
|
var t = self.get_transfer(c.id).?;
|
|
441
476
|
var dr = self.get_account(t.debit_account_id).?;
|
|
442
477
|
var cr = self.get_account(t.credit_account_id).?;
|
|
@@ -516,30 +551,188 @@ fn equal_48_bytes(a: [48]u8, b: [48]u8) bool {
|
|
|
516
551
|
|
|
517
552
|
const testing = std.testing;
|
|
518
553
|
|
|
554
|
+
test "create/lookup accounts" {
|
|
555
|
+
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
556
|
+
defer arena.deinit();
|
|
557
|
+
|
|
558
|
+
const allocator = arena.allocator();
|
|
559
|
+
|
|
560
|
+
const Vector = struct { result: CreateAccountResult, object: Account };
|
|
561
|
+
|
|
562
|
+
const vectors = [_]Vector{
|
|
563
|
+
Vector{
|
|
564
|
+
.result = .reserved_flag_padding,
|
|
565
|
+
.object = std.mem.zeroInit(Account, .{
|
|
566
|
+
.id = 1,
|
|
567
|
+
.timestamp = 1,
|
|
568
|
+
.flags = .{ .padding = 1 },
|
|
569
|
+
}),
|
|
570
|
+
},
|
|
571
|
+
Vector{
|
|
572
|
+
.result = .reserved_field,
|
|
573
|
+
.object = std.mem.zeroInit(Account, .{
|
|
574
|
+
.id = 2,
|
|
575
|
+
.timestamp = 1,
|
|
576
|
+
.reserved = [_]u8{1} ** 48,
|
|
577
|
+
}),
|
|
578
|
+
},
|
|
579
|
+
Vector{
|
|
580
|
+
.result = .exceeds_credits,
|
|
581
|
+
.object = std.mem.zeroInit(Account, .{
|
|
582
|
+
.id = 3,
|
|
583
|
+
.timestamp = 1,
|
|
584
|
+
.debits_reserved = 10,
|
|
585
|
+
.flags = .{ .debits_must_not_exceed_credits = true },
|
|
586
|
+
}),
|
|
587
|
+
},
|
|
588
|
+
Vector{
|
|
589
|
+
.result = .exceeds_credits,
|
|
590
|
+
.object = std.mem.zeroInit(Account, .{
|
|
591
|
+
.id = 4,
|
|
592
|
+
.timestamp = 1,
|
|
593
|
+
.debits_accepted = 10,
|
|
594
|
+
.flags = .{ .debits_must_not_exceed_credits = true },
|
|
595
|
+
}),
|
|
596
|
+
},
|
|
597
|
+
Vector{
|
|
598
|
+
.result = .exceeds_debits,
|
|
599
|
+
.object = std.mem.zeroInit(Account, .{
|
|
600
|
+
.id = 5,
|
|
601
|
+
.timestamp = 1,
|
|
602
|
+
.credits_reserved = 10,
|
|
603
|
+
.flags = .{ .credits_must_not_exceed_debits = true },
|
|
604
|
+
}),
|
|
605
|
+
},
|
|
606
|
+
Vector{
|
|
607
|
+
.result = .exceeds_debits,
|
|
608
|
+
.object = std.mem.zeroInit(Account, .{
|
|
609
|
+
.id = 6,
|
|
610
|
+
.timestamp = 1,
|
|
611
|
+
.credits_accepted = 10,
|
|
612
|
+
.flags = .{ .credits_must_not_exceed_debits = true },
|
|
613
|
+
}),
|
|
614
|
+
},
|
|
615
|
+
Vector{
|
|
616
|
+
.result = .ok,
|
|
617
|
+
.object = std.mem.zeroInit(Account, .{
|
|
618
|
+
.id = 7,
|
|
619
|
+
.timestamp = 1,
|
|
620
|
+
}),
|
|
621
|
+
},
|
|
622
|
+
Vector{
|
|
623
|
+
.result = .exists,
|
|
624
|
+
.object = std.mem.zeroInit(Account, .{
|
|
625
|
+
.id = 7,
|
|
626
|
+
.timestamp = 2,
|
|
627
|
+
}),
|
|
628
|
+
},
|
|
629
|
+
Vector{
|
|
630
|
+
.result = .ok,
|
|
631
|
+
.object = std.mem.zeroInit(Account, .{
|
|
632
|
+
.id = 8,
|
|
633
|
+
.timestamp = 2,
|
|
634
|
+
.user_data = 'U',
|
|
635
|
+
.unit = 9,
|
|
636
|
+
}),
|
|
637
|
+
},
|
|
638
|
+
Vector{
|
|
639
|
+
.result = .exists_with_different_unit,
|
|
640
|
+
.object = std.mem.zeroInit(Account, .{
|
|
641
|
+
.id = 8,
|
|
642
|
+
.timestamp = 3,
|
|
643
|
+
.user_data = 'U',
|
|
644
|
+
.unit = 10,
|
|
645
|
+
}),
|
|
646
|
+
},
|
|
647
|
+
Vector{
|
|
648
|
+
.result = .ok,
|
|
649
|
+
.object = std.mem.zeroInit(Account, .{
|
|
650
|
+
.id = 9,
|
|
651
|
+
.timestamp = 3,
|
|
652
|
+
.code = 9,
|
|
653
|
+
.user_data = 'U',
|
|
654
|
+
}),
|
|
655
|
+
},
|
|
656
|
+
Vector{
|
|
657
|
+
.result = .exists_with_different_code,
|
|
658
|
+
.object = std.mem.zeroInit(Account, .{
|
|
659
|
+
.id = 9,
|
|
660
|
+
.timestamp = 4,
|
|
661
|
+
.code = 10,
|
|
662
|
+
.user_data = 'D',
|
|
663
|
+
}),
|
|
664
|
+
},
|
|
665
|
+
Vector{
|
|
666
|
+
.result = .ok,
|
|
667
|
+
.object = std.mem.zeroInit(Account, .{
|
|
668
|
+
.id = 10,
|
|
669
|
+
.timestamp = 4,
|
|
670
|
+
.flags = .{ .credits_must_not_exceed_debits = true },
|
|
671
|
+
}),
|
|
672
|
+
},
|
|
673
|
+
Vector{
|
|
674
|
+
.result = .exists_with_different_flags,
|
|
675
|
+
.object = std.mem.zeroInit(Account, .{
|
|
676
|
+
.id = 10,
|
|
677
|
+
.timestamp = 5,
|
|
678
|
+
.flags = .{ .debits_must_not_exceed_credits = true },
|
|
679
|
+
}),
|
|
680
|
+
},
|
|
681
|
+
Vector{
|
|
682
|
+
.result = .ok,
|
|
683
|
+
.object = std.mem.zeroInit(Account, .{
|
|
684
|
+
.id = 11,
|
|
685
|
+
.timestamp = 5,
|
|
686
|
+
.user_data = 'U',
|
|
687
|
+
}),
|
|
688
|
+
},
|
|
689
|
+
Vector{
|
|
690
|
+
.result = .exists_with_different_user_data,
|
|
691
|
+
.object = std.mem.zeroInit(Account, .{
|
|
692
|
+
.id = 11,
|
|
693
|
+
.timestamp = 6,
|
|
694
|
+
.user_data = 'D',
|
|
695
|
+
}),
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
var state_machine = try StateMachine.init(allocator, vectors.len, 0, 0);
|
|
700
|
+
defer state_machine.deinit();
|
|
701
|
+
|
|
702
|
+
for (vectors) |vector| {
|
|
703
|
+
try testing.expectEqual(vector.result, state_machine.create_account(vector.object));
|
|
704
|
+
if (vector.result == .ok) {
|
|
705
|
+
try testing.expectEqual(vector.object, state_machine.get_account(vector.object.id).?.*);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
519
710
|
test "linked accounts" {
|
|
520
711
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
521
712
|
defer arena.deinit();
|
|
522
|
-
|
|
713
|
+
|
|
714
|
+
const allocator = arena.allocator();
|
|
523
715
|
|
|
524
716
|
const accounts_max = 5;
|
|
525
717
|
const transfers_max = 0;
|
|
526
718
|
const commits_max = 0;
|
|
527
719
|
|
|
528
|
-
var state_machine = try StateMachine.init(allocator, accounts_max, transfers_max, commits_max);
|
|
529
|
-
defer state_machine.deinit();
|
|
530
|
-
|
|
531
720
|
var accounts = [_]Account{
|
|
532
721
|
// An individual event (successful):
|
|
533
722
|
std.mem.zeroInit(Account, .{ .id = 7, .code = 200 }),
|
|
534
723
|
|
|
535
724
|
// A chain of 4 events (the last event in the chain closes the chain with linked=false):
|
|
536
|
-
|
|
537
|
-
std.mem.zeroInit(Account, .{ .id =
|
|
538
|
-
|
|
539
|
-
std.mem.zeroInit(Account, .{ .id =
|
|
725
|
+
// Commit/rollback:
|
|
726
|
+
std.mem.zeroInit(Account, .{ .id = 0, .flags = .{ .linked = true } }),
|
|
727
|
+
// Commit/rollback:
|
|
728
|
+
std.mem.zeroInit(Account, .{ .id = 1, .flags = .{ .linked = true } }),
|
|
729
|
+
// Fail with .exists:
|
|
730
|
+
std.mem.zeroInit(Account, .{ .id = 0, .flags = .{ .linked = true } }),
|
|
731
|
+
// Fail without committing.
|
|
732
|
+
std.mem.zeroInit(Account, .{ .id = 2 }),
|
|
540
733
|
|
|
541
734
|
// An individual event (successful):
|
|
542
|
-
// This should not see any effect from the failed chain above
|
|
735
|
+
// This should not see any effect from the failed chain above:
|
|
543
736
|
std.mem.zeroInit(Account, .{ .id = 0, .code = 200 }),
|
|
544
737
|
|
|
545
738
|
// A chain of 2 events (the first event fails the chain):
|
|
@@ -558,10 +751,12 @@ test "linked accounts" {
|
|
|
558
751
|
std.mem.zeroInit(Account, .{ .id = 3 }),
|
|
559
752
|
};
|
|
560
753
|
|
|
754
|
+
var state_machine = try StateMachine.init(allocator, accounts_max, transfers_max, commits_max);
|
|
755
|
+
defer state_machine.deinit();
|
|
756
|
+
|
|
561
757
|
const input = std.mem.asBytes(&accounts);
|
|
562
758
|
const output = try allocator.alloc(u8, 4096);
|
|
563
759
|
|
|
564
|
-
// Use a timestamp of 0 since this is just a test
|
|
565
760
|
state_machine.prepare(0, .create_accounts, input);
|
|
566
761
|
const size = state_machine.commit(0, .create_accounts, input, output);
|
|
567
762
|
const results = std.mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
@@ -594,6 +789,636 @@ test "linked accounts" {
|
|
|
594
789
|
// All our rollback handlers appear to be commutative.
|
|
595
790
|
}
|
|
596
791
|
|
|
792
|
+
test "create/lookup/rollback transfers" {
|
|
793
|
+
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
794
|
+
defer arena.deinit();
|
|
795
|
+
|
|
796
|
+
const allocator = arena.allocator();
|
|
797
|
+
|
|
798
|
+
var accounts = [_]Account{
|
|
799
|
+
std.mem.zeroInit(Account, .{ .id = 1 }),
|
|
800
|
+
std.mem.zeroInit(Account, .{ .id = 2 }),
|
|
801
|
+
std.mem.zeroInit(Account, .{ .id = 3, .unit = 1 }),
|
|
802
|
+
std.mem.zeroInit(Account, .{ .id = 4, .unit = 2 }),
|
|
803
|
+
std.mem.zeroInit(Account, .{ .id = 5, .flags = .{ .debits_must_not_exceed_credits = true } }),
|
|
804
|
+
std.mem.zeroInit(Account, .{ .id = 6, .flags = .{ .credits_must_not_exceed_debits = true } }),
|
|
805
|
+
std.mem.zeroInit(Account, .{ .id = 7 }),
|
|
806
|
+
std.mem.zeroInit(Account, .{ .id = 8 }),
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
var state_machine = try StateMachine.init(allocator, accounts.len, 1, 0);
|
|
810
|
+
defer state_machine.deinit();
|
|
811
|
+
|
|
812
|
+
const input = std.mem.asBytes(&accounts);
|
|
813
|
+
const output = try allocator.alloc(u8, 4096);
|
|
814
|
+
|
|
815
|
+
state_machine.prepare(0, .create_accounts, input);
|
|
816
|
+
const size = state_machine.commit(0, .create_accounts, input, output);
|
|
817
|
+
|
|
818
|
+
const errors = std.mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
819
|
+
try testing.expectEqual(@as(usize, 0), errors.len);
|
|
820
|
+
|
|
821
|
+
for (accounts) |account| {
|
|
822
|
+
try testing.expectEqual(account, state_machine.get_account(account.id).?.*);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const Vector = struct { result: CreateTransferResult, object: Transfer };
|
|
826
|
+
|
|
827
|
+
const timestamp: u64 = (state_machine.commit_timestamp + 1);
|
|
828
|
+
const vectors = [_]Vector{
|
|
829
|
+
Vector{
|
|
830
|
+
.result = .amount_is_zero,
|
|
831
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
832
|
+
.id = 1,
|
|
833
|
+
.timestamp = timestamp,
|
|
834
|
+
}),
|
|
835
|
+
},
|
|
836
|
+
Vector{
|
|
837
|
+
.result = .reserved_flag_padding,
|
|
838
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
839
|
+
.id = 2,
|
|
840
|
+
.timestamp = timestamp,
|
|
841
|
+
.flags = .{ .padding = 1 },
|
|
842
|
+
}),
|
|
843
|
+
},
|
|
844
|
+
Vector{
|
|
845
|
+
.result = .two_phase_commit_must_timeout,
|
|
846
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
847
|
+
.id = 3,
|
|
848
|
+
.timestamp = timestamp,
|
|
849
|
+
.flags = .{ .two_phase_commit = true },
|
|
850
|
+
}),
|
|
851
|
+
},
|
|
852
|
+
Vector{
|
|
853
|
+
.result = .timeout_reserved_for_two_phase_commit,
|
|
854
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
855
|
+
.id = 4,
|
|
856
|
+
.timestamp = timestamp,
|
|
857
|
+
.timeout = 1,
|
|
858
|
+
}),
|
|
859
|
+
},
|
|
860
|
+
Vector{
|
|
861
|
+
.result = .reserved_field,
|
|
862
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
863
|
+
.id = 5,
|
|
864
|
+
.timestamp = timestamp,
|
|
865
|
+
.flags = .{ .condition = false },
|
|
866
|
+
.reserved = [_]u8{1} ** 32,
|
|
867
|
+
}),
|
|
868
|
+
},
|
|
869
|
+
Vector{
|
|
870
|
+
.result = .accounts_are_the_same,
|
|
871
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
872
|
+
.id = 6,
|
|
873
|
+
.timestamp = timestamp,
|
|
874
|
+
.amount = 10,
|
|
875
|
+
.debit_account_id = 1,
|
|
876
|
+
.credit_account_id = 1,
|
|
877
|
+
}),
|
|
878
|
+
},
|
|
879
|
+
Vector{
|
|
880
|
+
.result = .debit_account_not_found,
|
|
881
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
882
|
+
.id = 7,
|
|
883
|
+
.timestamp = timestamp,
|
|
884
|
+
.amount = 10,
|
|
885
|
+
.debit_account_id = 100,
|
|
886
|
+
.credit_account_id = 1,
|
|
887
|
+
}),
|
|
888
|
+
},
|
|
889
|
+
Vector{
|
|
890
|
+
.result = .credit_account_not_found,
|
|
891
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
892
|
+
.id = 8,
|
|
893
|
+
.timestamp = timestamp,
|
|
894
|
+
.amount = 10,
|
|
895
|
+
.debit_account_id = 1,
|
|
896
|
+
.credit_account_id = 100,
|
|
897
|
+
}),
|
|
898
|
+
},
|
|
899
|
+
Vector{
|
|
900
|
+
.result = .accounts_have_different_units,
|
|
901
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
902
|
+
.id = 9,
|
|
903
|
+
.timestamp = timestamp,
|
|
904
|
+
.amount = 10,
|
|
905
|
+
.debit_account_id = 3,
|
|
906
|
+
.credit_account_id = 4,
|
|
907
|
+
}),
|
|
908
|
+
},
|
|
909
|
+
Vector{
|
|
910
|
+
.result = .exceeds_credits,
|
|
911
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
912
|
+
.id = 10,
|
|
913
|
+
.timestamp = timestamp,
|
|
914
|
+
.amount = 1000,
|
|
915
|
+
.debit_account_id = 5,
|
|
916
|
+
.credit_account_id = 1,
|
|
917
|
+
}),
|
|
918
|
+
},
|
|
919
|
+
Vector{
|
|
920
|
+
.result = .exceeds_debits,
|
|
921
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
922
|
+
.id = 11,
|
|
923
|
+
.timestamp = timestamp,
|
|
924
|
+
.amount = 1000,
|
|
925
|
+
.debit_account_id = 1,
|
|
926
|
+
.credit_account_id = 6,
|
|
927
|
+
}),
|
|
928
|
+
},
|
|
929
|
+
Vector{
|
|
930
|
+
.result = .ok,
|
|
931
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
932
|
+
.id = 12,
|
|
933
|
+
.timestamp = timestamp,
|
|
934
|
+
.amount = 10,
|
|
935
|
+
.debit_account_id = 7,
|
|
936
|
+
.credit_account_id = 8,
|
|
937
|
+
}),
|
|
938
|
+
},
|
|
939
|
+
Vector{
|
|
940
|
+
.result = .exists,
|
|
941
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
942
|
+
.id = 12,
|
|
943
|
+
.timestamp = timestamp + 1,
|
|
944
|
+
.amount = 10,
|
|
945
|
+
.debit_account_id = 7,
|
|
946
|
+
.credit_account_id = 8,
|
|
947
|
+
}),
|
|
948
|
+
},
|
|
949
|
+
Vector{
|
|
950
|
+
.result = .exists_with_different_debit_account_id,
|
|
951
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
952
|
+
.id = 12,
|
|
953
|
+
.timestamp = timestamp + 1,
|
|
954
|
+
.amount = 10,
|
|
955
|
+
.debit_account_id = 8,
|
|
956
|
+
.credit_account_id = 7,
|
|
957
|
+
}),
|
|
958
|
+
},
|
|
959
|
+
Vector{
|
|
960
|
+
.result = .exists_with_different_credit_account_id,
|
|
961
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
962
|
+
.id = 12,
|
|
963
|
+
.timestamp = timestamp + 1,
|
|
964
|
+
.amount = 10,
|
|
965
|
+
.debit_account_id = 7,
|
|
966
|
+
.credit_account_id = 1,
|
|
967
|
+
}),
|
|
968
|
+
},
|
|
969
|
+
Vector{
|
|
970
|
+
.result = .exists_with_different_amount,
|
|
971
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
972
|
+
.id = 12,
|
|
973
|
+
.timestamp = timestamp + 1,
|
|
974
|
+
.amount = 11,
|
|
975
|
+
.debit_account_id = 7,
|
|
976
|
+
.credit_account_id = 8,
|
|
977
|
+
}),
|
|
978
|
+
},
|
|
979
|
+
Vector{
|
|
980
|
+
.result = .exists_with_different_flags,
|
|
981
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
982
|
+
.id = 12,
|
|
983
|
+
.timestamp = timestamp + 1,
|
|
984
|
+
.amount = 10,
|
|
985
|
+
.debit_account_id = 7,
|
|
986
|
+
.credit_account_id = 8,
|
|
987
|
+
.flags = .{ .condition = true },
|
|
988
|
+
}),
|
|
989
|
+
},
|
|
990
|
+
Vector{
|
|
991
|
+
.result = .exists_with_different_user_data,
|
|
992
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
993
|
+
.id = 12,
|
|
994
|
+
.timestamp = timestamp + 1,
|
|
995
|
+
.amount = 10,
|
|
996
|
+
.debit_account_id = 7,
|
|
997
|
+
.credit_account_id = 8,
|
|
998
|
+
.user_data = 'A',
|
|
999
|
+
}),
|
|
1000
|
+
},
|
|
1001
|
+
Vector{
|
|
1002
|
+
.result = .ok,
|
|
1003
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1004
|
+
.id = 13,
|
|
1005
|
+
.timestamp = timestamp + 1,
|
|
1006
|
+
.amount = 10,
|
|
1007
|
+
.debit_account_id = 7,
|
|
1008
|
+
.credit_account_id = 8,
|
|
1009
|
+
.flags = .{ .condition = true },
|
|
1010
|
+
.reserved = [_]u8{1} ** 32,
|
|
1011
|
+
}),
|
|
1012
|
+
},
|
|
1013
|
+
Vector{
|
|
1014
|
+
.result = .exists_with_different_reserved_field,
|
|
1015
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1016
|
+
.id = 13,
|
|
1017
|
+
.timestamp = timestamp + 2,
|
|
1018
|
+
.amount = 10,
|
|
1019
|
+
.debit_account_id = 7,
|
|
1020
|
+
.credit_account_id = 8,
|
|
1021
|
+
.flags = .{ .condition = true },
|
|
1022
|
+
.reserved = [_]u8{2} ** 32,
|
|
1023
|
+
}),
|
|
1024
|
+
},
|
|
1025
|
+
Vector{
|
|
1026
|
+
.result = .timeout_reserved_for_two_phase_commit,
|
|
1027
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1028
|
+
.id = 13,
|
|
1029
|
+
.timestamp = timestamp + 2,
|
|
1030
|
+
.amount = 10,
|
|
1031
|
+
.debit_account_id = 7,
|
|
1032
|
+
.credit_account_id = 8,
|
|
1033
|
+
.flags = .{ .condition = true },
|
|
1034
|
+
.reserved = [_]u8{1} ** 32,
|
|
1035
|
+
.timeout = 10,
|
|
1036
|
+
}),
|
|
1037
|
+
},
|
|
1038
|
+
Vector{
|
|
1039
|
+
.result = .two_phase_commit_must_timeout,
|
|
1040
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1041
|
+
.id = 14,
|
|
1042
|
+
.timestamp = timestamp + 2,
|
|
1043
|
+
.amount = 10,
|
|
1044
|
+
.debit_account_id = 7,
|
|
1045
|
+
.credit_account_id = 8,
|
|
1046
|
+
.flags = .{ .two_phase_commit = true },
|
|
1047
|
+
.timeout = 0,
|
|
1048
|
+
}),
|
|
1049
|
+
},
|
|
1050
|
+
Vector{
|
|
1051
|
+
.result = .ok,
|
|
1052
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1053
|
+
.id = 15,
|
|
1054
|
+
.timestamp = timestamp + 2,
|
|
1055
|
+
.amount = 10,
|
|
1056
|
+
.debit_account_id = 7,
|
|
1057
|
+
.credit_account_id = 8,
|
|
1058
|
+
.flags = .{ .two_phase_commit = true },
|
|
1059
|
+
.timeout = 20,
|
|
1060
|
+
}),
|
|
1061
|
+
},
|
|
1062
|
+
Vector{
|
|
1063
|
+
.result = .exists_with_different_timeout,
|
|
1064
|
+
.object = std.mem.zeroInit(Transfer, .{
|
|
1065
|
+
.id = 15,
|
|
1066
|
+
.timestamp = timestamp + 3,
|
|
1067
|
+
.amount = 10,
|
|
1068
|
+
.debit_account_id = 7,
|
|
1069
|
+
.credit_account_id = 8,
|
|
1070
|
+
.flags = .{ .two_phase_commit = true },
|
|
1071
|
+
.timeout = 25,
|
|
1072
|
+
}),
|
|
1073
|
+
},
|
|
1074
|
+
};
|
|
1075
|
+
|
|
1076
|
+
for (vectors) |vector| {
|
|
1077
|
+
try testing.expectEqual(vector.result, state_machine.create_transfer(vector.object));
|
|
1078
|
+
if (vector.result == .ok) {
|
|
1079
|
+
try testing.expectEqual(vector.object, state_machine.get_transfer(vector.object.id).?.*);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// 2 phase commit [reserved]:
|
|
1084
|
+
try testing.expectEqual(@as(u64, 10), state_machine.get_account(7).?.*.debits_reserved);
|
|
1085
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(7).?.*.credits_reserved);
|
|
1086
|
+
try testing.expectEqual(@as(u64, 10), state_machine.get_account(8).?.*.credits_reserved);
|
|
1087
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(8).?.*.debits_reserved);
|
|
1088
|
+
// 1 phase commit [accepted]:
|
|
1089
|
+
try testing.expectEqual(@as(u64, 20), state_machine.get_account(7).?.*.debits_accepted);
|
|
1090
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(7).?.*.credits_accepted);
|
|
1091
|
+
try testing.expectEqual(@as(u64, 20), state_machine.get_account(8).?.*.credits_accepted);
|
|
1092
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(8).?.*.debits_accepted);
|
|
1093
|
+
|
|
1094
|
+
// Rollback transfer with id [12], amount of 10:
|
|
1095
|
+
state_machine.create_transfer_rollback(state_machine.get_transfer(vectors[11].object.id).?.*);
|
|
1096
|
+
try testing.expectEqual(@as(u64, 10), state_machine.get_account(7).?.*.debits_accepted);
|
|
1097
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(7).?.*.credits_accepted);
|
|
1098
|
+
try testing.expectEqual(@as(u64, 10), state_machine.get_account(8).?.*.credits_accepted);
|
|
1099
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(8).?.*.debits_accepted);
|
|
1100
|
+
try testing.expect(state_machine.get_transfer(vectors[11].object.id) == null);
|
|
1101
|
+
|
|
1102
|
+
// Rollback transfer with id [15], amount of 10:
|
|
1103
|
+
state_machine.create_transfer_rollback(state_machine.get_transfer(vectors[22].object.id).?.*);
|
|
1104
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(7).?.*.debits_reserved);
|
|
1105
|
+
try testing.expectEqual(@as(u64, 0), state_machine.get_account(8).?.*.credits_reserved);
|
|
1106
|
+
try testing.expect(state_machine.get_transfer(vectors[22].object.id) == null);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
test "create/lookup/rollback commits" {
|
|
1110
|
+
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
1111
|
+
defer arena.deinit();
|
|
1112
|
+
|
|
1113
|
+
const allocator = arena.allocator();
|
|
1114
|
+
|
|
1115
|
+
const Vector = struct { result: CommitTransferResult, object: Commit };
|
|
1116
|
+
|
|
1117
|
+
var accounts = [_]Account{
|
|
1118
|
+
std.mem.zeroInit(Account, .{ .id = 1 }),
|
|
1119
|
+
std.mem.zeroInit(Account, .{ .id = 2 }),
|
|
1120
|
+
std.mem.zeroInit(Account, .{ .id = 3 }),
|
|
1121
|
+
std.mem.zeroInit(Account, .{ .id = 4 }),
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
var transfers = [_]Transfer{
|
|
1125
|
+
std.mem.zeroInit(Transfer, .{
|
|
1126
|
+
.id = 1,
|
|
1127
|
+
.amount = 15,
|
|
1128
|
+
.debit_account_id = 1,
|
|
1129
|
+
.credit_account_id = 2,
|
|
1130
|
+
}),
|
|
1131
|
+
std.mem.zeroInit(Transfer, .{
|
|
1132
|
+
.id = 2,
|
|
1133
|
+
.amount = 15,
|
|
1134
|
+
.debit_account_id = 1,
|
|
1135
|
+
.credit_account_id = 2,
|
|
1136
|
+
.flags = .{ .two_phase_commit = true },
|
|
1137
|
+
.timeout = 25,
|
|
1138
|
+
}),
|
|
1139
|
+
std.mem.zeroInit(Transfer, .{
|
|
1140
|
+
.id = 3,
|
|
1141
|
+
.amount = 15,
|
|
1142
|
+
.debit_account_id = 1,
|
|
1143
|
+
.credit_account_id = 2,
|
|
1144
|
+
.flags = .{ .two_phase_commit = true },
|
|
1145
|
+
.timeout = 25,
|
|
1146
|
+
}),
|
|
1147
|
+
std.mem.zeroInit(Transfer, .{
|
|
1148
|
+
.id = 4,
|
|
1149
|
+
.amount = 15,
|
|
1150
|
+
.debit_account_id = 1,
|
|
1151
|
+
.credit_account_id = 2,
|
|
1152
|
+
.flags = .{ .two_phase_commit = true },
|
|
1153
|
+
.timeout = 1,
|
|
1154
|
+
}),
|
|
1155
|
+
std.mem.zeroInit(Transfer, .{
|
|
1156
|
+
.id = 5,
|
|
1157
|
+
.amount = 15,
|
|
1158
|
+
.debit_account_id = 1,
|
|
1159
|
+
.credit_account_id = 2,
|
|
1160
|
+
.flags = .{
|
|
1161
|
+
.two_phase_commit = true,
|
|
1162
|
+
.condition = true,
|
|
1163
|
+
},
|
|
1164
|
+
.timeout = 25,
|
|
1165
|
+
}),
|
|
1166
|
+
std.mem.zeroInit(Transfer, .{
|
|
1167
|
+
.id = 6,
|
|
1168
|
+
.amount = 15,
|
|
1169
|
+
.debit_account_id = 1,
|
|
1170
|
+
.credit_account_id = 2,
|
|
1171
|
+
.flags = .{
|
|
1172
|
+
.two_phase_commit = true,
|
|
1173
|
+
.condition = false,
|
|
1174
|
+
},
|
|
1175
|
+
.timeout = 25,
|
|
1176
|
+
}),
|
|
1177
|
+
std.mem.zeroInit(Transfer, .{
|
|
1178
|
+
.id = 7,
|
|
1179
|
+
.amount = 15,
|
|
1180
|
+
.debit_account_id = 3,
|
|
1181
|
+
.credit_account_id = 4,
|
|
1182
|
+
.flags = .{ .two_phase_commit = true },
|
|
1183
|
+
.timeout = 25,
|
|
1184
|
+
}),
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
var state_machine = try StateMachine.init(allocator, accounts.len, transfers.len, 1);
|
|
1188
|
+
defer state_machine.deinit();
|
|
1189
|
+
|
|
1190
|
+
const input = std.mem.asBytes(&accounts);
|
|
1191
|
+
const output = try allocator.alloc(u8, 4096);
|
|
1192
|
+
|
|
1193
|
+
// Accounts:
|
|
1194
|
+
state_machine.prepare(0, .create_accounts, input);
|
|
1195
|
+
const size = state_machine.commit(0, .create_accounts, input, output);
|
|
1196
|
+
{
|
|
1197
|
+
const errors = std.mem.bytesAsSlice(CreateAccountsResult, output[0..size]);
|
|
1198
|
+
try testing.expectEqual(@as(usize, 0), errors.len);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
for (accounts) |account| {
|
|
1202
|
+
try testing.expectEqual(account, state_machine.get_account(account.id).?.*);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Transfers:
|
|
1206
|
+
const object_transfers = std.mem.asBytes(&transfers);
|
|
1207
|
+
const output_transfers = try allocator.alloc(u8, 4096);
|
|
1208
|
+
|
|
1209
|
+
state_machine.prepare(0, .create_transfers, object_transfers);
|
|
1210
|
+
const size_transfers = state_machine.commit(
|
|
1211
|
+
0,
|
|
1212
|
+
.create_transfers,
|
|
1213
|
+
object_transfers,
|
|
1214
|
+
output_transfers,
|
|
1215
|
+
);
|
|
1216
|
+
const errors = std.mem.bytesAsSlice(CreateTransfersResult, output_transfers[0..size_transfers]);
|
|
1217
|
+
try testing.expectEqual(@as(usize, 0), errors.len);
|
|
1218
|
+
|
|
1219
|
+
for (transfers) |transfer| {
|
|
1220
|
+
try testing.expectEqual(transfer, state_machine.get_transfer(transfer.id).?.*);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// Commits:
|
|
1224
|
+
const timestamp: u64 = (state_machine.commit_timestamp + 1);
|
|
1225
|
+
const vectors = [_]Vector{
|
|
1226
|
+
Vector{
|
|
1227
|
+
.result = .reserved_field,
|
|
1228
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1229
|
+
.id = 1,
|
|
1230
|
+
.timestamp = timestamp,
|
|
1231
|
+
.reserved = [_]u8{1} ** 32,
|
|
1232
|
+
}),
|
|
1233
|
+
},
|
|
1234
|
+
Vector{
|
|
1235
|
+
.result = .reserved_flag_padding,
|
|
1236
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1237
|
+
.id = 1,
|
|
1238
|
+
.timestamp = timestamp,
|
|
1239
|
+
.flags = .{ .padding = 1 },
|
|
1240
|
+
}),
|
|
1241
|
+
},
|
|
1242
|
+
Vector{
|
|
1243
|
+
.result = .transfer_not_found,
|
|
1244
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1245
|
+
.id = 777,
|
|
1246
|
+
.timestamp = timestamp,
|
|
1247
|
+
}),
|
|
1248
|
+
},
|
|
1249
|
+
Vector{
|
|
1250
|
+
.result = .transfer_not_two_phase_commit,
|
|
1251
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1252
|
+
.id = 1,
|
|
1253
|
+
.timestamp = timestamp,
|
|
1254
|
+
}),
|
|
1255
|
+
},
|
|
1256
|
+
Vector{
|
|
1257
|
+
.result = .ok,
|
|
1258
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1259
|
+
.id = 2,
|
|
1260
|
+
.timestamp = timestamp,
|
|
1261
|
+
}),
|
|
1262
|
+
},
|
|
1263
|
+
Vector{
|
|
1264
|
+
.result = .already_committed_but_accepted,
|
|
1265
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1266
|
+
.id = 2,
|
|
1267
|
+
.timestamp = timestamp + 1,
|
|
1268
|
+
.flags = .{ .reject = true },
|
|
1269
|
+
}),
|
|
1270
|
+
},
|
|
1271
|
+
Vector{
|
|
1272
|
+
.result = .already_committed,
|
|
1273
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1274
|
+
.id = 2,
|
|
1275
|
+
.timestamp = timestamp + 1,
|
|
1276
|
+
}),
|
|
1277
|
+
},
|
|
1278
|
+
Vector{
|
|
1279
|
+
.result = .ok,
|
|
1280
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1281
|
+
.id = 3,
|
|
1282
|
+
.timestamp = timestamp + 1,
|
|
1283
|
+
.flags = .{ .reject = true },
|
|
1284
|
+
}),
|
|
1285
|
+
},
|
|
1286
|
+
Vector{
|
|
1287
|
+
.result = .already_committed_but_rejected,
|
|
1288
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1289
|
+
.id = 3,
|
|
1290
|
+
.timestamp = timestamp + 2,
|
|
1291
|
+
}),
|
|
1292
|
+
},
|
|
1293
|
+
Vector{
|
|
1294
|
+
.result = .transfer_expired,
|
|
1295
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1296
|
+
.id = 4,
|
|
1297
|
+
.timestamp = timestamp + 2,
|
|
1298
|
+
}),
|
|
1299
|
+
},
|
|
1300
|
+
Vector{
|
|
1301
|
+
.result = .condition_requires_preimage,
|
|
1302
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1303
|
+
.id = 5,
|
|
1304
|
+
.timestamp = timestamp + 2,
|
|
1305
|
+
}),
|
|
1306
|
+
},
|
|
1307
|
+
Vector{
|
|
1308
|
+
.result = .preimage_invalid,
|
|
1309
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1310
|
+
.id = 5,
|
|
1311
|
+
.timestamp = timestamp + 2,
|
|
1312
|
+
.flags = .{ .preimage = true },
|
|
1313
|
+
.reserved = [_]u8{1} ** 32,
|
|
1314
|
+
}),
|
|
1315
|
+
},
|
|
1316
|
+
Vector{
|
|
1317
|
+
.result = .preimage_requires_condition,
|
|
1318
|
+
.object = std.mem.zeroInit(Commit, .{
|
|
1319
|
+
.id = 6,
|
|
1320
|
+
.timestamp = timestamp + 2,
|
|
1321
|
+
.flags = .{ .preimage = true },
|
|
1322
|
+
}),
|
|
1323
|
+
},
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1326
|
+
// Test balances BEFORE commit
|
|
1327
|
+
// Account 1:
|
|
1328
|
+
const account_1_before = state_machine.get_account(1).?.*;
|
|
1329
|
+
try testing.expectEqual(@as(u64, 15), account_1_before.debits_accepted);
|
|
1330
|
+
try testing.expectEqual(@as(u64, 75), account_1_before.debits_reserved);
|
|
1331
|
+
try testing.expectEqual(@as(u64, 0), account_1_before.credits_accepted);
|
|
1332
|
+
try testing.expectEqual(@as(u64, 0), account_1_before.credits_reserved);
|
|
1333
|
+
// Account 2:
|
|
1334
|
+
const account_2_before = state_machine.get_account(2).?.*;
|
|
1335
|
+
try testing.expectEqual(@as(u64, 0), account_2_before.debits_accepted);
|
|
1336
|
+
try testing.expectEqual(@as(u64, 0), account_2_before.debits_reserved);
|
|
1337
|
+
try testing.expectEqual(@as(u64, 15), account_2_before.credits_accepted);
|
|
1338
|
+
try testing.expectEqual(@as(u64, 75), account_2_before.credits_reserved);
|
|
1339
|
+
|
|
1340
|
+
for (vectors) |vector| {
|
|
1341
|
+
try testing.expectEqual(vector.result, state_machine.commit_transfer(vector.object));
|
|
1342
|
+
if (vector.result == .ok) {
|
|
1343
|
+
try testing.expectEqual(vector.object, state_machine.get_commit(vector.object.id).?.*);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Test balances AFTER commit
|
|
1348
|
+
// Account 1:
|
|
1349
|
+
const account_1_after = state_machine.get_account(1).?.*;
|
|
1350
|
+
try testing.expectEqual(@as(u64, 30), account_1_after.debits_accepted);
|
|
1351
|
+
// +15 (acceptance applied):
|
|
1352
|
+
try testing.expectEqual(@as(u64, 45), account_1_after.debits_reserved);
|
|
1353
|
+
// -15 (reserved moved):
|
|
1354
|
+
try testing.expectEqual(@as(u64, 0), account_1_after.credits_accepted);
|
|
1355
|
+
try testing.expectEqual(@as(u64, 0), account_1_after.credits_reserved);
|
|
1356
|
+
// Account 2:
|
|
1357
|
+
const account_2_after = state_machine.get_account(2).?.*;
|
|
1358
|
+
try testing.expectEqual(@as(u64, 0), account_2_after.debits_accepted);
|
|
1359
|
+
try testing.expectEqual(@as(u64, 0), account_2_after.debits_reserved);
|
|
1360
|
+
// +15 (acceptance applied):
|
|
1361
|
+
try testing.expectEqual(@as(u64, 30), account_2_after.credits_accepted);
|
|
1362
|
+
// -15 (reserved moved):
|
|
1363
|
+
try testing.expectEqual(@as(u64, 45), account_2_after.credits_reserved);
|
|
1364
|
+
|
|
1365
|
+
// Test COMMIT with invalid debit/credit accounts
|
|
1366
|
+
state_machine.create_account_rollback(accounts[3]);
|
|
1367
|
+
try testing.expect(state_machine.get_account(accounts[3].id) == null);
|
|
1368
|
+
try testing.expectEqual(
|
|
1369
|
+
state_machine.commit_transfer(std.mem.zeroInit(Commit, .{
|
|
1370
|
+
.id = 7,
|
|
1371
|
+
.timestamp = timestamp + 2,
|
|
1372
|
+
})),
|
|
1373
|
+
.credit_account_not_found,
|
|
1374
|
+
);
|
|
1375
|
+
state_machine.create_account_rollback(accounts[2]);
|
|
1376
|
+
try testing.expect(state_machine.get_account(accounts[2].id) == null);
|
|
1377
|
+
try testing.expectEqual(
|
|
1378
|
+
state_machine.commit_transfer(std.mem.zeroInit(Commit, .{
|
|
1379
|
+
.id = 7,
|
|
1380
|
+
.timestamp = timestamp + 2,
|
|
1381
|
+
})),
|
|
1382
|
+
.debit_account_not_found,
|
|
1383
|
+
);
|
|
1384
|
+
|
|
1385
|
+
// Rollback [id=2] not rejected:
|
|
1386
|
+
state_machine.commit_transfer_rollback(vectors[4].object);
|
|
1387
|
+
|
|
1388
|
+
// Account 1:
|
|
1389
|
+
const account_1_rollback = state_machine.get_account(1).?.*;
|
|
1390
|
+
// -15 (rollback):
|
|
1391
|
+
try testing.expectEqual(@as(u64, 15), account_1_rollback.debits_accepted);
|
|
1392
|
+
try testing.expectEqual(@as(u64, 60), account_1_rollback.debits_reserved);
|
|
1393
|
+
try testing.expectEqual(@as(u64, 0), account_1_rollback.credits_accepted);
|
|
1394
|
+
try testing.expectEqual(@as(u64, 0), account_1_rollback.credits_reserved);
|
|
1395
|
+
// Account 2:
|
|
1396
|
+
const account_2_rollback = state_machine.get_account(2).?.*;
|
|
1397
|
+
try testing.expectEqual(@as(u64, 0), account_2_rollback.debits_accepted);
|
|
1398
|
+
try testing.expectEqual(@as(u64, 0), account_2_rollback.debits_reserved);
|
|
1399
|
+
// -15 (rollback):
|
|
1400
|
+
try testing.expectEqual(@as(u64, 15), account_2_rollback.credits_accepted);
|
|
1401
|
+
try testing.expectEqual(@as(u64, 60), account_2_rollback.credits_reserved);
|
|
1402
|
+
|
|
1403
|
+
// Rollback [id=3] rejected:
|
|
1404
|
+
state_machine.commit_transfer_rollback(vectors[7].object);
|
|
1405
|
+
// Account 1:
|
|
1406
|
+
const account_1_rollback_reject = state_machine.get_account(1).?.*;
|
|
1407
|
+
try testing.expectEqual(@as(u64, 15), account_1_rollback_reject.debits_accepted);
|
|
1408
|
+
// Remains unchanged:
|
|
1409
|
+
try testing.expectEqual(@as(u64, 75), account_1_rollback_reject.debits_reserved);
|
|
1410
|
+
// +15 rolled back:
|
|
1411
|
+
try testing.expectEqual(@as(u64, 0), account_1_rollback_reject.credits_accepted);
|
|
1412
|
+
try testing.expectEqual(@as(u64, 0), account_1_rollback_reject.credits_reserved);
|
|
1413
|
+
// Account 2:
|
|
1414
|
+
const account_2_rollback_reject = state_machine.get_account(2).?.*;
|
|
1415
|
+
try testing.expectEqual(@as(u64, 0), account_2_rollback_reject.debits_accepted);
|
|
1416
|
+
try testing.expectEqual(@as(u64, 0), account_2_rollback_reject.debits_reserved);
|
|
1417
|
+
try testing.expectEqual(@as(u64, 15), account_2_rollback_reject.credits_accepted);
|
|
1418
|
+
// +15 rolled back"
|
|
1419
|
+
try testing.expectEqual(@as(u64, 75), account_2_rollback_reject.credits_reserved);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
597
1422
|
fn test_routine_zeroed(comptime len: usize) !void {
|
|
598
1423
|
const routine = switch (len) {
|
|
599
1424
|
32 => zeroed_32_bytes,
|