forked from tigerbeetle/viewstamped-replication-made-famous
-
Notifications
You must be signed in to change notification settings - Fork 0
/
state_machine.zig
75 lines (64 loc) · 2.3 KB
/
state_machine.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
const std = @import("std");
const log = std.log.scoped(.state_machine);
pub const StateMachine = struct {
pub const Operation = enum(u8) {
/// Operations reserved by VR protocol (for all state machines):
reserved,
init,
register,
hash,
};
state: u128,
pub fn init(seed: u64) StateMachine {
return .{ .state = hash(0, std.mem.asBytes(&seed)) };
}
pub fn prepare(
state_machine: *StateMachine,
realtime: i64,
operation: Operation,
input: []u8,
) void {
_ = state_machine;
_ = realtime;
_ = operation;
_ = input;
// TODO: use realtime in some way to test the system
}
pub fn commit(
state_machine: *StateMachine,
client: u128,
operation: Operation,
input: []const u8,
output: []u8,
) usize {
switch (operation) {
.reserved, .init => unreachable,
.register => return 0,
// TODO: instead of always using the first 32 bytes of the output
// buffer, get tricky and use a random but deterministic slice
// of it, filling the rest with 0s.
.hash => {
// Fold the input into our current state, creating a hash chain.
// Hash the input with the client ID since small inputs may collide across clients.
const client_input = hash(client, input);
const new_state = hash(state_machine.state, std.mem.asBytes(&client_input));
log.debug("state={x} input={x} input.len={} new state={x}", .{
state_machine.state,
client_input,
input.len,
new_state,
});
state_machine.state = new_state;
std.mem.copy(u8, output, std.mem.asBytes(&state_machine.state));
return @sizeOf(@TypeOf(state_machine.state));
},
}
}
pub fn hash(state: u128, input: []const u8) u128 {
var key: [32]u8 = [_]u8{0} ** 32;
std.mem.copy(u8, key[0..16], std.mem.asBytes(&state));
var target: [32]u8 = undefined;
std.crypto.hash.Blake3.hash(input, &target, .{ .key = key });
return @bitCast(u128, target[0..16].*);
}
};