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