-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprotocol.tla
194 lines (162 loc) · 7.51 KB
/
protocol.tla
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
---- MODULE protocol ----
EXTENDS TLC, Naturals, FiniteSets, Sequences, Utils, Definitions
\* Define the set of users
CONSTANT Users
\* Define the process ids
MinerProccessId == 10000
NodeProccessId == 10001
UserProccessId == 1
(*--algorithm protocol
variables
\* A compact zk-SNARK proof that summarizes the mnerkle tree of all note commitments.
noteCommitmentProof = "";
\* A compact zk-SNARK proof that summarizes the mnerkle tree of all nullifiers.
nullifierProof = "";
\* The blockchain accepted tip block
tip_block = [height |-> 1, transactions |-> <<>>];
\* Transaction pool for miners
txPool = {};
\* The proposed block from a mniner
proposed_block;
define
\* The height of the blockchain always increases
HeightAlwaysIncreases == [][tip_block'.height > tip_block.height]_tip_block
\* Transactions in the transaction pool are eventually processed
TransactionsEventuallyProcessed ==
(Cardinality(txPool) > 0) => <> (Cardinality(txPool) = 0)
\* For each transaction in the transaction pool, the nullifier is unique
NoDoubleSpending ==
\A tx \in txPool :
\A action1, action2 \in tx.actions :
action1 /= action2 => action1.nullifier /= action2.nullifier
end define;
\* Mine transactions and add them to the blockchain.
fair process Miner = MinerProccessId
begin
Mine:
\* As soon as we have transactions
await Cardinality(txPool) > 0;
\* Add transactions to a block and propose it to the blockchain
proposed_block := [height |-> tip_block.height + 1, txs |-> txPool];
\* Clear the transaction pool
txPool := {};
end process;
\* For each user, create transactions and add them to the transaction pool.
fair process User \in UserProccessId .. Cardinality(Users)
variables
tx_,
actions;
begin
CreateTx:
await txPool = {};
actions := {[
nullifier |-> RandomHash(4),
commitment |-> RandomHash(4),
value |-> 10,
receiver |-> "receiver"
]};
\* need nullifir?
tx_ := OrchardTransaction(actions, GenerateZKProof(actions, noteCommitmentProof));
txPool := {tx_};
end process;
\* Verify proposed block and it's transactions. Update the note commitment and nullifier trees.
fair process Node = NodeProccessId
begin
Verify:
\* Wait for a block proposal
await proposed_block # defaultInitValue;
if VerifyBlockHeader(proposed_block, tip_block) then
with tx \in proposed_block.txs do
if VerifyZKProof(tx.proof, noteCommitmentProof, nullifierProof) then
with action \in tx.actions do
\* Update the note commitment and nullifier trees, generate new compact proofs for them.
noteCommitmentProof := GenerateZKProof(action.nullifier, noteCommitmentProof);
nullifierProof := GenerateZKProof(action.commitment, nullifierProof);
end with;
end if;
end with;
end if;
\* Valid or not, discard the proposed block after verification.
proposed_block := defaultInitValue;
end process;
end algorithm; *)
\* BEGIN TRANSLATION (chksum(pcal) = "866057ab" /\ chksum(tla) = "316214bf")
CONSTANT defaultInitValue
VARIABLES noteCommitmentProof, nullifierProof, tip_block, txPool,
proposed_block, pc
(* define statement *)
HeightAlwaysIncreases == [][tip_block'.height > tip_block.height]_tip_block
TransactionsEventuallyProcessed ==
(Cardinality(txPool) > 0) => <> (Cardinality(txPool) = 0)
NoDoubleSpending ==
\A tx \in txPool :
\A action1, action2 \in tx.actions :
action1 /= action2 => action1.nullifier /= action2.nullifier
VARIABLES tx_, actions
vars == << noteCommitmentProof, nullifierProof, tip_block, txPool,
proposed_block, pc, tx_, actions >>
ProcSet == {MinerProccessId} \cup (UserProccessId .. Cardinality(Users)) \cup {NodeProccessId}
Init == (* Global variables *)
/\ noteCommitmentProof = ""
/\ nullifierProof = ""
/\ tip_block = [height |-> 1, transactions |-> <<>>]
/\ txPool = {}
/\ proposed_block = defaultInitValue
(* Process User *)
/\ tx_ = [self \in UserProccessId .. Cardinality(Users) |-> defaultInitValue]
/\ actions = [self \in UserProccessId .. Cardinality(Users) |-> defaultInitValue]
/\ pc = [self \in ProcSet |-> CASE self = MinerProccessId -> "Mine"
[] self \in UserProccessId .. Cardinality(Users) -> "CreateTx"
[] self = NodeProccessId -> "Verify"]
Mine == /\ pc[MinerProccessId] = "Mine"
/\ Cardinality(txPool) > 0
/\ proposed_block' = [height |-> tip_block.height + 1, txs |-> txPool]
/\ txPool' = {}
/\ pc' = [pc EXCEPT ![MinerProccessId] = "Done"]
/\ UNCHANGED << noteCommitmentProof, nullifierProof, tip_block, tx_,
actions >>
Miner == Mine
CreateTx(self) == /\ pc[self] = "CreateTx"
/\ txPool = {}
/\ actions' = [actions EXCEPT ![self] = {[
nullifier |-> RandomHash(4),
commitment |-> RandomHash(4),
value |-> 10,
receiver |-> "receiver"
]}]
/\ tx_' = [tx_ EXCEPT ![self] = OrchardTransaction(actions'[self], GenerateZKProof(actions'[self], noteCommitmentProof))]
/\ txPool' = {tx_'[self]}
/\ pc' = [pc EXCEPT ![self] = "Done"]
/\ UNCHANGED << noteCommitmentProof, nullifierProof,
tip_block, proposed_block >>
User(self) == CreateTx(self)
Verify == /\ pc[NodeProccessId] = "Verify"
/\ proposed_block # defaultInitValue
/\ IF VerifyBlockHeader(proposed_block, tip_block)
THEN /\ \E tx \in proposed_block.txs:
IF VerifyZKProof(tx.proof, noteCommitmentProof, nullifierProof)
THEN /\ \E action \in tx.actions:
/\ noteCommitmentProof' = GenerateZKProof(action.nullifier, noteCommitmentProof)
/\ nullifierProof' = GenerateZKProof(action.commitment, nullifierProof)
ELSE /\ TRUE
/\ UNCHANGED << noteCommitmentProof,
nullifierProof >>
ELSE /\ TRUE
/\ UNCHANGED << noteCommitmentProof, nullifierProof >>
/\ proposed_block' = defaultInitValue
/\ pc' = [pc EXCEPT ![NodeProccessId] = "Done"]
/\ UNCHANGED << tip_block, txPool, tx_, actions >>
Node == Verify
(* Allow infinite stuttering to prevent deadlock on termination. *)
Terminating == /\ \A self \in ProcSet: pc[self] = "Done"
/\ UNCHANGED vars
Next == Miner \/ Node
\/ (\E self \in UserProccessId .. Cardinality(Users): User(self))
\/ Terminating
Spec == /\ Init /\ [][Next]_vars
/\ WF_vars(Miner)
/\ \A self \in UserProccessId .. Cardinality(Users) : WF_vars(User(self))
/\ WF_vars(Node)
Termination == <>(\A self \in ProcSet: pc[self] = "Done")
\* END TRANSLATION
====