@proto-kit/protocol 0.1.1-develop.457 → 0.1.1-develop.600

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.
Files changed (98) hide show
  1. package/dist/blockmodules/AccountStateModule.d.ts.map +1 -1
  2. package/dist/blockmodules/AccountStateModule.js +10 -3
  3. package/dist/blockmodules/BlockHeightHook.d.ts +3 -3
  4. package/dist/blockmodules/BlockHeightHook.d.ts.map +1 -1
  5. package/dist/blockmodules/BlockHeightHook.js +5 -4
  6. package/dist/blockmodules/LastStateRootBlockHook.d.ts +8 -0
  7. package/dist/blockmodules/LastStateRootBlockHook.d.ts.map +1 -0
  8. package/dist/blockmodules/LastStateRootBlockHook.js +15 -0
  9. package/dist/blockmodules/NoopBlockHook.d.ts +6 -4
  10. package/dist/blockmodules/NoopBlockHook.d.ts.map +1 -1
  11. package/dist/blockmodules/NoopBlockHook.js +4 -4
  12. package/dist/blockmodules/NoopSettlementHook.d.ts +6 -0
  13. package/dist/blockmodules/NoopSettlementHook.d.ts.map +1 -0
  14. package/dist/blockmodules/NoopSettlementHook.js +18 -0
  15. package/dist/hooks/AccountStateHook.d.ts.map +1 -1
  16. package/dist/hooks/AccountStateHook.js +7 -2
  17. package/dist/hooks/BlockHeightHook.d.ts.map +1 -1
  18. package/dist/index.d.ts +9 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -3
  21. package/dist/model/MethodPublicOutput.d.ts +8 -0
  22. package/dist/model/MethodPublicOutput.d.ts.map +1 -1
  23. package/dist/model/MethodPublicOutput.js +1 -0
  24. package/dist/model/network/NetworkState.d.ts +40 -0
  25. package/dist/model/network/NetworkState.d.ts.map +1 -1
  26. package/dist/model/network/NetworkState.js +14 -2
  27. package/dist/model/transaction/RuntimeTransaction.d.ts +45 -20
  28. package/dist/model/transaction/RuntimeTransaction.d.ts.map +1 -1
  29. package/dist/model/transaction/RuntimeTransaction.js +68 -11
  30. package/dist/model/transaction/SignedTransaction.d.ts +71 -0
  31. package/dist/model/transaction/SignedTransaction.d.ts.map +1 -0
  32. package/dist/model/transaction/SignedTransaction.js +33 -0
  33. package/dist/model/transaction/ValueOption.d.ts +119 -0
  34. package/dist/model/transaction/ValueOption.d.ts.map +1 -0
  35. package/dist/model/transaction/ValueOption.js +24 -0
  36. package/dist/protocol/Protocol.d.ts +7 -3
  37. package/dist/protocol/Protocol.d.ts.map +1 -1
  38. package/dist/protocol/Protocol.js +26 -16
  39. package/dist/protocol/ProvableBlockHook.d.ts +2 -10
  40. package/dist/protocol/ProvableBlockHook.d.ts.map +1 -1
  41. package/dist/protocol/ProvableBlockHook.js +1 -1
  42. package/dist/protocol/ProvableTransactionHook.d.ts +1 -1
  43. package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -1
  44. package/dist/protocol/TransitioningProtocolModule.d.ts +3 -2
  45. package/dist/protocol/TransitioningProtocolModule.d.ts.map +1 -1
  46. package/dist/protocol/TransitioningProtocolModule.js +3 -2
  47. package/dist/prover/block/BlockProvable.d.ts +106 -28
  48. package/dist/prover/block/BlockProvable.d.ts.map +1 -1
  49. package/dist/prover/block/BlockProvable.js +23 -5
  50. package/dist/prover/block/BlockProver.d.ts +29 -8
  51. package/dist/prover/block/BlockProver.d.ts.map +1 -1
  52. package/dist/prover/block/BlockProver.js +241 -77
  53. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts +45 -0
  54. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts.map +1 -0
  55. package/dist/prover/block/accummulators/BlockHashMerkleTree.js +16 -0
  56. package/dist/settlement/ProvableSettlementHook.d.ts +26 -0
  57. package/dist/settlement/ProvableSettlementHook.d.ts.map +1 -0
  58. package/dist/settlement/ProvableSettlementHook.js +3 -0
  59. package/dist/settlement/SettlementContract.d.ts +230 -0
  60. package/dist/settlement/SettlementContract.d.ts.map +1 -0
  61. package/dist/settlement/SettlementContract.js +346 -0
  62. package/dist/settlement/modules/NetworkStateSettlementModule.d.ts +11 -0
  63. package/dist/settlement/modules/NetworkStateSettlementModule.d.ts.map +1 -0
  64. package/dist/settlement/modules/NetworkStateSettlementModule.js +12 -0
  65. package/dist/state/context/RuntimeMethodExecutionContext.d.ts +75 -1
  66. package/dist/state/context/RuntimeMethodExecutionContext.d.ts.map +1 -1
  67. package/dist/state/context/RuntimeMethodExecutionContext.js +19 -1
  68. package/dist/utils/MinaPrefixedProvableHashList.d.ts +24 -0
  69. package/dist/utils/MinaPrefixedProvableHashList.d.ts.map +1 -0
  70. package/dist/utils/MinaPrefixedProvableHashList.js +51 -0
  71. package/package.json +2 -2
  72. package/src/blockmodules/AccountStateModule.ts +17 -6
  73. package/src/blockmodules/BlockHeightHook.ts +5 -8
  74. package/src/blockmodules/LastStateRootBlockHook.ts +26 -0
  75. package/src/blockmodules/NoopBlockHook.ts +15 -11
  76. package/src/blockmodules/NoopSettlementHook.ts +21 -0
  77. package/src/blockmodules/SequenceStateTransactionModule.ts +25 -0
  78. package/src/index.ts +9 -3
  79. package/src/model/MethodPublicOutput.ts +3 -2
  80. package/src/model/network/NetworkState.ts +15 -3
  81. package/src/model/transaction/RuntimeTransaction.ts +90 -16
  82. package/src/model/transaction/SignedTransaction.ts +54 -0
  83. package/src/model/transaction/ValueOption.ts +28 -0
  84. package/src/protocol/Protocol.ts +49 -31
  85. package/src/protocol/ProvableBlockHook.ts +10 -13
  86. package/src/protocol/ProvableTransactionHook.ts +2 -1
  87. package/src/protocol/TransitioningProtocolModule.ts +3 -2
  88. package/src/prover/block/BlockProvable.ts +39 -6
  89. package/src/prover/block/BlockProver.ts +473 -143
  90. package/src/prover/block/accummulators/BlockHashMerkleTree.ts +16 -0
  91. package/src/settlement/ProvableSettlementHook.ts +37 -0
  92. package/src/settlement/SettlementContract.ts +444 -0
  93. package/src/settlement/modules/NetworkStateSettlementModule.ts +39 -0
  94. package/src/state/context/RuntimeMethodExecutionContext.ts +18 -1
  95. package/src/utils/MinaPrefixedProvableHashList.ts +72 -0
  96. package/test/BlockProver.test.ts +2 -3
  97. package/src/model/transaction/ProtocolTransaction.ts +0 -25
  98. package/src/prover/block/BlockTransactionPosition.ts +0 -34
@@ -2,15 +2,15 @@
2
2
  import {
3
3
  Bool,
4
4
  Experimental,
5
- Field,
5
+ Field, Poseidon,
6
6
  type Proof,
7
7
  Provable,
8
- SelfProof,
9
- Struct,
8
+ SelfProof
10
9
  } from "o1js";
11
10
  import { container, inject, injectable, injectAll } from "tsyringe";
12
11
  import {
13
12
  AreProofsEnabled,
13
+ hashWithPrefix,
14
14
  PlainZkProgram,
15
15
  provableMethod,
16
16
  WithZkProgrammable,
@@ -26,6 +26,16 @@ import {
26
26
  StateTransitionProverPublicOutput,
27
27
  } from "../statetransition/StateTransitionProvable";
28
28
  import { RuntimeTransaction } from "../../model/transaction/RuntimeTransaction";
29
+ import {
30
+ ProvableStateTransition,
31
+ StateTransition,
32
+ } from "../../model/StateTransition";
33
+ import { ProvableTransactionHook } from "../../protocol/ProvableTransactionHook";
34
+ import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethodExecutionContext";
35
+ import { ProvableBlockHook } from "../../protocol/ProvableBlockHook";
36
+ import { NetworkState } from "../../model/network/NetworkState";
37
+ import { SignedTransaction } from "../../model/transaction/SignedTransaction";
38
+ import { MinaActions, MinaActionsHashList } from "../../utils/MinaPrefixedProvableHashList";
29
39
 
30
40
  import {
31
41
  BlockProvable,
@@ -34,12 +44,10 @@ import {
34
44
  BlockProverPublicInput,
35
45
  BlockProverPublicOutput,
36
46
  } from "./BlockProvable";
37
- import { ProvableStateTransition } from "../../model/StateTransition";
38
- import { ProvableTransactionHook } from "../../protocol/ProvableTransactionHook";
39
- import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethodExecutionContext";
40
- import { ProvableBlockHook } from "../../protocol/ProvableBlockHook";
41
- import { NetworkState } from "../../model/network/NetworkState";
42
- import { BlockTransactionPosition } from "./BlockTransactionPosition";
47
+ import {
48
+ BlockHashMerkleTreeWitness,
49
+ BlockHashTreeEntry,
50
+ } from "./accummulators/BlockHashMerkleTree";
43
51
 
44
52
  const errors = {
45
53
  stateProofNotStartingAtZero: () =>
@@ -48,16 +56,26 @@ const errors = {
48
56
  stateTransitionsHashNotEqual: () =>
49
57
  "StateTransition list commitments are not equal",
50
58
 
59
+ propertyNotMatchingStep: (propertyName: string, step: string) =>
60
+ `${propertyName} not matching: ${step}`,
61
+
51
62
  propertyNotMatching: (propertyName: string) => `${propertyName} not matching`,
52
63
 
53
- stateRootNotMatching: (step: string) => `StateRoots not matching ${step}`,
64
+ stateRootNotMatching: (step: string) =>
65
+ errors.propertyNotMatchingStep("StateRoots", step),
54
66
 
55
67
  transactionsHashNotMatching: (step: string) =>
56
- `transactions hash not matching ${step}`,
68
+ errors.propertyNotMatchingStep("Transactions hash", step),
69
+
70
+ networkStateHashNotMatching: (step: string) =>
71
+ errors.propertyNotMatchingStep("Network state hash", step),
57
72
  };
58
73
 
74
+ // Should be equal to BlockProver.PublicInput
59
75
  export interface BlockProverState {
60
- // The current state root of the block prover
76
+ /**
77
+ * The current state root of the block prover
78
+ */
61
79
  stateRoot: Field;
62
80
 
63
81
  /**
@@ -71,8 +89,30 @@ export interface BlockProverState {
71
89
  * This value is the same for the whole batch (L2 block)
72
90
  */
73
91
  networkStateHash: Field;
92
+
93
+ /**
94
+ * The root of the merkle tree encoding all block hashes,
95
+ * see `BlockHashMerkleTree`
96
+ */
97
+ blockHashRoot: Field;
98
+
99
+ /**
100
+ * A variant of the transactionsHash that is never reset.
101
+ * Thought for usage in the sequence state mempool.
102
+ * In comparison, transactionsHash restarts at 0 for every new block
103
+ */
104
+ eternalTransactionsHash: Field;
105
+
106
+ incomingMessagesHash: Field;
74
107
  }
75
108
 
109
+ function maxField() {
110
+ return Field(Field.ORDER - 1n);
111
+ }
112
+
113
+ export type BlockProof = Proof<BlockProverPublicInput, BlockProverPublicOutput>;
114
+ export type RuntimeProof = Proof<void, MethodPublicOutput>;
115
+
76
116
  export class BlockProverProgrammable extends ZkProgrammable<
77
117
  BlockProverPublicInput,
78
118
  BlockProverPublicOutput
@@ -101,7 +141,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
101
141
  *
102
142
  * @param state The from-state of the BlockProver
103
143
  * @param stateTransitionProof
104
- * @param appProof
144
+ * @param runtimeProof
105
145
  * @param executionData
106
146
  * @returns The new BlockProver-state to be used as public output
107
147
  */
@@ -111,12 +151,14 @@ export class BlockProverProgrammable extends ZkProgrammable<
111
151
  StateTransitionProverPublicInput,
112
152
  StateTransitionProverPublicOutput
113
153
  >,
114
- appProof: Proof<void, MethodPublicOutput>,
154
+ runtimeProof: RuntimeProof,
115
155
  executionData: BlockProverExecutionData
116
156
  ): BlockProverState {
117
- const { transaction, networkState } = executionData;
157
+ const { transaction, networkState, signature } = executionData;
158
+
159
+ const isMessage = runtimeProof.publicOutput.isMessage;
118
160
 
119
- appProof.verify();
161
+ runtimeProof.verify();
120
162
  stateTransitionProof.verify();
121
163
 
122
164
  const stateTo = { ...state };
@@ -126,8 +168,12 @@ export class BlockProverProgrammable extends ZkProgrammable<
126
168
  Field(0),
127
169
  errors.stateProofNotStartingAtZero()
128
170
  );
171
+ stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
172
+ Field(0),
173
+ errors.stateProofNotStartingAtZero()
174
+ );
129
175
 
130
- appProof.publicOutput.stateTransitionsHash.assertEquals(
176
+ runtimeProof.publicOutput.stateTransitionsHash.assertEquals(
131
177
  stateTransitionProof.publicOutput.stateTransitionsHash,
132
178
  errors.stateTransitionsHashNotEqual()
133
179
  );
@@ -142,33 +188,43 @@ export class BlockProverProgrammable extends ZkProgrammable<
142
188
  errors.propertyNotMatching("from protocol state root")
143
189
  );
144
190
 
191
+ // Apply protocol state transitions
192
+ this.assertProtocolTransitions(
193
+ stateTransitionProof,
194
+ executionData,
195
+ runtimeProof
196
+ );
197
+
145
198
  // Apply state if status success
146
199
  stateTo.stateRoot = Provable.if(
147
- appProof.publicOutput.status,
200
+ runtimeProof.publicOutput.status,
148
201
  stateTransitionProof.publicOutput.stateRoot,
149
202
  stateTransitionProof.publicOutput.protocolStateRoot
150
203
  );
151
204
 
152
- // Apply protocol state transitions
153
- this.assertProtocolTransitions(stateTransitionProof, executionData);
154
-
155
- // Check transaction signature
156
- transaction
157
- .validateSignature()
158
- .assertTrue("Transaction signature not valid");
159
-
160
205
  // Check transaction integrity against appProof
161
- const blockTransactionHash =
162
- RuntimeTransaction.fromProtocolTransaction(transaction).hash();
206
+ const blockTransactionHash = transaction.hash();
163
207
 
164
208
  blockTransactionHash.assertEquals(
165
- appProof.publicOutput.transactionHash,
209
+ runtimeProof.publicOutput.transactionHash,
166
210
  "Transactions provided in AppProof and BlockProof do not match"
167
211
  );
168
212
 
213
+ // Check transaction signature
214
+ new SignedTransaction({
215
+ transaction,
216
+ signature,
217
+ })
218
+ .validateSignature()
219
+ .or(isMessage)
220
+ .assertTrue("Transaction signature not valid");
221
+
222
+ // Validate layout of transaction witness
223
+ transaction.assertTransactionType(isMessage);
224
+
169
225
  // Check network state integrity against appProof
170
226
  state.networkStateHash.assertEquals(
171
- appProof.publicOutput.networkStateHash,
227
+ runtimeProof.publicOutput.networkStateHash,
172
228
  "Network state does not match state used in AppProof"
173
229
  );
174
230
  state.networkStateHash.assertEquals(
@@ -187,7 +243,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
187
243
  StateTransitionProverPublicInput,
188
244
  StateTransitionProverPublicOutput
189
245
  >,
190
- executionData: BlockProverExecutionData
246
+ executionData: BlockProverExecutionData,
247
+ runtimeProof: Proof<void, MethodPublicOutput>
191
248
  ) {
192
249
  const executionContext = container.resolve(RuntimeMethodExecutionContext);
193
250
  executionContext.clear();
@@ -196,10 +253,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
196
253
  // This way they can use this.transaction etc. while still having provable
197
254
  // integrity between data
198
255
  executionContext.setup({
199
- transaction: RuntimeTransaction.fromProtocolTransaction(
200
- executionData.transaction
201
- ),
202
-
256
+ // That is why we should probably hide it from the transaction context inputs
257
+ transaction: executionData.transaction,
203
258
  networkState: executionData.networkState,
204
259
  });
205
260
  executionContext.beforeMethod("", "", []);
@@ -234,60 +289,62 @@ export class BlockProverProgrammable extends ZkProgrammable<
234
289
  );
235
290
  }
236
291
 
237
- private getBeforeBlockNetworkState(
292
+ private executeBlockHooks(
238
293
  state: BlockProverState,
239
- networkState: NetworkState
240
- ) {
241
- return this.blockHooks.reduce<NetworkState>((networkState, blockHook) => {
242
- return blockHook.beforeBlock({
243
- state,
244
- networkState,
245
- });
246
- }, networkState);
247
- }
294
+ inputNetworkState: NetworkState,
295
+ type: "afterBlock" | "beforeBlock"
296
+ ): {
297
+ networkState: NetworkState;
298
+ stateTransitions: StateTransition<unknown>[];
299
+ } {
300
+ const executionContext = container.resolve(RuntimeMethodExecutionContext);
301
+ executionContext.clear();
302
+ executionContext.beforeMethod("", "", []);
248
303
 
249
- private getAfterBlockNetworkState(
250
- state: BlockProverState,
251
- networkState: NetworkState
252
- ) {
253
- return this.blockHooks.reduce<NetworkState>((networkState, blockHook) => {
254
- return blockHook.afterBlock({
255
- state,
256
- networkState,
257
- });
258
- }, networkState);
304
+ const resultingNetworkState = this.blockHooks.reduce<NetworkState>(
305
+ (networkState, blockHook) => {
306
+ // Setup context for potential calls to runtime methods.
307
+ // With the special case that we set the new networkstate for every hook
308
+ // We also have to put in a dummy transaction for network.transaction
309
+ executionContext.setup({
310
+ transaction: RuntimeTransaction.dummyTransaction(),
311
+ networkState,
312
+ });
313
+
314
+ if (type === "beforeBlock") {
315
+ return blockHook.beforeBlock(networkState, state);
316
+ } else if (type === "afterBlock") {
317
+ return blockHook.afterBlock(networkState, state);
318
+ } else {
319
+ throw new Error("Unreachable");
320
+ }
321
+ },
322
+ inputNetworkState
323
+ );
324
+
325
+ executionContext.afterMethod();
326
+
327
+ const { stateTransitions, status, statusMessage } =
328
+ executionContext.current().result;
329
+
330
+ status.assertTrue(`Block hook call failed: ${statusMessage ?? "-"}`);
331
+
332
+ return {
333
+ networkState: resultingNetworkState,
334
+ stateTransitions,
335
+ };
259
336
  }
260
337
 
261
338
  private addTransactionToBundle(
262
339
  state: BlockProverState,
263
- stateTransitionProof: StateTransitionProof,
264
- appProof: Proof<void, MethodPublicOutput>,
265
- executionData: BlockProverExecutionData
266
- ): {
267
- state: BlockProverState;
268
- networkState: NetworkState;
269
- bundleOpened: Bool;
270
- bundleClosed: Bool;
271
- } {
272
- const { transactionPosition, networkState } = executionData;
340
+ isMessage: Bool,
341
+ transaction: RuntimeTransaction
342
+ ): BlockProverState {
273
343
  const stateTo = {
274
344
  ...state,
275
345
  };
276
346
 
277
- // Execute beforeBlook hooks and apply if it is the first tx of the bundle
278
- const beforeHookResult = this.getBeforeBlockNetworkState(
279
- state,
280
- networkState
281
- );
282
- const bundleOpened = transactionPosition.equals(
283
- BlockTransactionPosition.fromPositionType("FIRST")
284
- );
285
- const resultingNetworkState = new NetworkState(
286
- Provable.if(bundleOpened, NetworkState, beforeHookResult, networkState)
287
- );
288
- stateTo.networkStateHash = resultingNetworkState.hash();
289
-
290
- // TODO Modify bundle merkle tree as per specs
347
+ const transactionHash = transaction.hash();
291
348
 
292
349
  // Append tx to transaction list
293
350
  const transactionList = new DefaultProvableHashList(
@@ -295,75 +352,248 @@ export class BlockProverProgrammable extends ZkProgrammable<
295
352
  state.transactionsHash
296
353
  );
297
354
 
298
- const { transactionHash } = appProof.publicOutput;
299
- transactionList.push(transactionHash);
300
-
355
+ transactionList.pushIf(transactionHash, isMessage.not());
301
356
  stateTo.transactionsHash = transactionList.commitment;
302
357
 
303
- return {
304
- state: stateTo,
305
- networkState: resultingNetworkState,
306
- bundleOpened,
358
+ // Append tx to eternal transaction list
359
+ // eslint-disable-next-line no-warning-comments
360
+ // TODO Change that to the a sequence-state compatible transaction struct
361
+ const eternalTransactionList = new DefaultProvableHashList(
362
+ Field,
363
+ state.eternalTransactionsHash
364
+ );
307
365
 
308
- bundleClosed: transactionPosition.equals(
309
- BlockTransactionPosition.fromPositionType("LAST")
310
- ),
311
- };
366
+ eternalTransactionList.pushIf(transactionHash, isMessage.not());
367
+ stateTo.eternalTransactionsHash = eternalTransactionList.commitment;
368
+
369
+ // Append tx to incomingMessagesHash
370
+ const actionHash = MinaActions.actionHash(transaction.hashData());
371
+
372
+ const incomingMessagesList = new MinaActionsHashList(state.incomingMessagesHash);
373
+ incomingMessagesList.pushIf(actionHash, isMessage);
374
+
375
+ stateTo.incomingMessagesHash = incomingMessagesList.commitment;
376
+
377
+ return stateTo;
312
378
  }
313
379
 
314
380
  @provableMethod()
315
381
  public proveTransaction(
316
382
  publicInput: BlockProverPublicInput,
317
383
  stateProof: StateTransitionProof,
318
- appProof: Proof<void, MethodPublicOutput>,
384
+ runtimeProof: RuntimeProof,
319
385
  executionData: BlockProverExecutionData
320
386
  ): BlockProverPublicOutput {
321
387
  const state: BlockProverState = {
322
- transactionsHash: publicInput.transactionsHash,
323
- stateRoot: publicInput.stateRoot,
324
- networkStateHash: publicInput.networkStateHash,
388
+ ...publicInput,
325
389
  };
326
390
 
327
- const bundleInclusionResult = this.addTransactionToBundle(
391
+ state.networkStateHash.assertEquals(
392
+ executionData.networkState.hash(),
393
+ "ExecutionData Networkstate doesn't equal public input hash"
394
+ );
395
+
396
+ const bundleInclusionState = this.addTransactionToBundle(
328
397
  state,
329
- stateProof,
330
- appProof,
331
- executionData
398
+ runtimeProof.publicOutput.isMessage,
399
+ executionData.transaction
332
400
  );
333
401
 
334
402
  const stateTo = this.applyTransaction(
335
- bundleInclusionResult.state,
403
+ bundleInclusionState,
336
404
  stateProof,
337
- appProof,
338
- {
339
- transaction: executionData.transaction,
340
- transactionPosition: executionData.transactionPosition,
341
- networkState: bundleInclusionResult.networkState,
342
- }
405
+ runtimeProof,
406
+ executionData
407
+ );
408
+
409
+ return new BlockProverPublicOutput({
410
+ ...stateTo,
411
+ blockNumber: maxField(),
412
+ closed: Bool(false),
413
+ });
414
+ }
415
+
416
+ private assertSTProofInput(
417
+ stateTransitionProof: StateTransitionProof,
418
+ stateRoot: Field
419
+ ) {
420
+ stateTransitionProof.publicInput.stateTransitionsHash.assertEquals(
421
+ Field(0),
422
+ errors.stateProofNotStartingAtZero()
423
+ );
424
+ stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
425
+ Field(0),
426
+ errors.stateProofNotStartingAtZero()
427
+ );
428
+
429
+ // Assert from state roots
430
+ stateRoot.assertEquals(
431
+ stateTransitionProof.publicInput.stateRoot,
432
+ errors.propertyNotMatching("from state root")
433
+ );
434
+ }
435
+
436
+ @provableMethod()
437
+ public proveBlock(
438
+ publicInput: BlockProverPublicInput,
439
+ networkState: NetworkState,
440
+ blockWitness: BlockHashMerkleTreeWitness,
441
+ stateTransitionProof: StateTransitionProof,
442
+ transactionProof: BlockProverProof
443
+ ): BlockProverPublicOutput {
444
+ const state: BlockProverState = {
445
+ ...publicInput,
446
+ };
447
+
448
+ // 1. Make assertions about the inputs
449
+ publicInput.transactionsHash.assertEquals(
450
+ Field(0),
451
+ "Transactionshash has to start at 0"
452
+ );
453
+ publicInput.networkStateHash.assertEquals(
454
+ networkState.hash(),
455
+ "Wrong NetworkState supplied"
456
+ );
457
+
458
+ transactionProof.publicInput.transactionsHash.assertEquals(
459
+ Field(0),
460
+ "TransactionProof transactionshash has to start at 0"
461
+ );
462
+ transactionProof.publicInput.blockHashRoot.assertEquals(
463
+ Field(0),
464
+ "TransactionProof cannot carry the blockHashRoot - publicInput"
465
+ );
466
+ transactionProof.publicOutput.blockHashRoot.assertEquals(
467
+ Field(0),
468
+ "TransactionProof cannot carry the blockHashRoot - publicOutput"
469
+ );
470
+ transactionProof.publicInput.networkStateHash.assertEquals(
471
+ transactionProof.publicOutput.networkStateHash,
472
+ "TransactionProof cannot alter the network state"
473
+ );
474
+ transactionProof.publicInput.eternalTransactionsHash.assertEquals(
475
+ state.eternalTransactionsHash,
476
+ "TransactionProof starting eternalTransactionHash not matching"
477
+ );
478
+ transactionProof.publicInput.incomingMessagesHash.assertEquals(
479
+ state.incomingMessagesHash,
480
+ "TransactionProof starting incomingMessagesHash not matching"
481
+ );
482
+
483
+ // Verify ST Proof only if STs have been emitted,
484
+ // otherwise we can input a dummy proof
485
+ const stsEmitted = stateTransitionProof.publicOutput.stateTransitionsHash
486
+ .equals(0)
487
+ .and(stateTransitionProof.publicOutput.protocolTransitionsHash.equals(0))
488
+ .not();
489
+ stateTransitionProof.verifyIf(stsEmitted);
490
+
491
+ // Verify Transaction proof if it has at least 1 tx
492
+ // We have to compare the whole input and output because we can make no
493
+ // assumptions about the values, since it can be an arbitrary dummy-proof
494
+ const txProofOutput = transactionProof.publicOutput;
495
+ const verifyTransactionProof = txProofOutput.equals(
496
+ transactionProof.publicInput,
497
+ txProofOutput.closed,
498
+ txProofOutput.blockNumber
499
+ );
500
+ transactionProof.verifyIf(verifyTransactionProof);
501
+
502
+ // 2. Execute beforeBlock hooks
503
+ const beforeBlockResult = this.executeBlockHooks(
504
+ state,
505
+ networkState,
506
+ "beforeBlock"
507
+ );
508
+
509
+ const beforeBlockHashList = new DefaultProvableHashList(
510
+ ProvableStateTransition
511
+ );
512
+ beforeBlockResult.stateTransitions.forEach((st) => {
513
+ beforeBlockHashList.push(st.toProvable());
514
+ });
515
+
516
+ // We are reusing protocolSTs here as beforeBlock STs
517
+ // TODO Not possible atm bcs we can't have a seperation between protocol/runtime state roots,
518
+ // which we would for both before and after to be able to emit STs
519
+
520
+ // stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
521
+ // beforeBlockHashList.commitment
522
+ // );
523
+ // state.stateRoot = stateTransitionProof.publicInput.protocolStateRoot;
524
+
525
+ // TODO Only for now
526
+ beforeBlockHashList.commitment.assertEquals(
527
+ Field(0),
528
+ "beforeBlock() cannot emit state transitions yet"
529
+ );
530
+
531
+ // 4. Apply TX-type BlockProof
532
+ transactionProof.publicInput.networkStateHash.assertEquals(
533
+ beforeBlockResult.networkState.hash(),
534
+ "TransactionProof networkstate hash not matching beforeBlock hook result"
535
+ );
536
+ transactionProof.publicInput.stateRoot.assertEquals(
537
+ state.stateRoot,
538
+ "TransactionProof input state root not matching blockprover state root"
343
539
  );
344
540
 
345
- // Apply afterBlock hooks
346
- const afterBlockNetworkState = this.getAfterBlockNetworkState(
347
- stateTo,
348
- bundleInclusionResult.networkState
541
+ state.stateRoot = transactionProof.publicOutput.stateRoot;
542
+ state.transactionsHash = transactionProof.publicOutput.transactionsHash;
543
+ state.eternalTransactionsHash =
544
+ transactionProof.publicOutput.eternalTransactionsHash;
545
+ state.incomingMessagesHash =
546
+ transactionProof.publicOutput.incomingMessagesHash;
547
+
548
+ // 5. Execute afterBlock hooks
549
+ this.assertSTProofInput(stateTransitionProof, state.stateRoot);
550
+
551
+ const afterBlockResult = this.executeBlockHooks(
552
+ state,
553
+ beforeBlockResult.networkState,
554
+ "afterBlock"
349
555
  );
350
- const bundleClosed = executionData.transactionPosition.equals(
351
- BlockTransactionPosition.fromPositionType("LAST")
556
+
557
+ const afterBlockHashList = new DefaultProvableHashList(
558
+ ProvableStateTransition
352
559
  );
560
+ afterBlockResult.stateTransitions.forEach((st) => {
561
+ afterBlockHashList.push(st.toProvable());
562
+ });
563
+
564
+ state.networkStateHash = afterBlockResult.networkState.hash();
353
565
 
354
- // We only need the hash here since this computed networkstate
355
- // is only used as an input in the next bundle
356
- const resultingNetworkStateHash = Provable.if(
357
- bundleClosed,
358
- afterBlockNetworkState.hash(),
359
- stateTo.networkStateHash
566
+ // We are reusing runtime STs here as afterBlock STs
567
+ stateTransitionProof.publicInput.stateTransitionsHash.assertEquals(
568
+ afterBlockHashList.commitment,
569
+ "STProof from-ST-hash not matching generated ST-hash from afterBlock hooks"
570
+ );
571
+ state.stateRoot = stateTransitionProof.publicInput.stateRoot;
572
+
573
+ // 6. Close block
574
+
575
+ // Calculate the new block index
576
+ const blockIndex = blockWitness.calculateIndex();
577
+
578
+ blockWitness
579
+ .calculateRoot(Field(0))
580
+ .assertEquals(
581
+ publicInput.blockHashRoot,
582
+ "Supplied block hash witness not matching state root"
583
+ );
584
+
585
+ state.blockHashRoot = blockWitness.calculateRoot(
586
+ new BlockHashTreeEntry({
587
+ // Mirroring UnprovenBlock.hash()
588
+ blockHash: Poseidon.hash([blockIndex, state.transactionsHash]),
589
+ closed: Bool(true),
590
+ }).hash()
360
591
  );
361
592
 
362
593
  return new BlockProverPublicOutput({
363
- stateRoot: stateTo.stateRoot,
364
- transactionsHash: stateTo.transactionsHash,
365
- // eslint-disable-next-line putout/putout
366
- networkStateHash: resultingNetworkStateHash,
594
+ ...state,
595
+ blockNumber: blockIndex,
596
+ closed: Bool(true),
367
597
  });
368
598
  }
369
599
 
@@ -386,30 +616,117 @@ export class BlockProverProgrammable extends ZkProgrammable<
386
616
  errors.stateRootNotMatching("proof1.to -> proof2.from")
387
617
  );
388
618
 
389
- // Check transaction list
390
- publicInput.transactionsHash.assertEquals(
391
- proof1.publicInput.transactionsHash,
392
- errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
393
- );
394
- proof1.publicOutput.transactionsHash.assertEquals(
395
- proof2.publicInput.transactionsHash,
396
- errors.transactionsHashNotMatching("proof1.to -> proof2.from")
397
- );
619
+ // Check transaction list hash.
620
+ // Only assert them if these are tx proofs, skip for closed proofs
621
+ publicInput.transactionsHash
622
+ .equals(proof1.publicInput.transactionsHash)
623
+ .or(proof1.publicOutput.closed)
624
+ .assertTrue(
625
+ errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
626
+ );
627
+ proof1.publicOutput.transactionsHash
628
+ .equals(proof2.publicInput.transactionsHash)
629
+ .or(proof1.publicOutput.closed)
630
+ .assertTrue(
631
+ errors.transactionsHashNotMatching("proof1.to -> proof2.from")
632
+ );
398
633
 
399
634
  // Check networkhash
400
635
  publicInput.networkStateHash.assertEquals(
401
636
  proof1.publicInput.networkStateHash,
402
- errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
637
+ errors.networkStateHashNotMatching("publicInput.from -> proof1.from")
403
638
  );
404
639
  proof1.publicOutput.networkStateHash.assertEquals(
405
640
  proof2.publicInput.networkStateHash,
641
+ errors.networkStateHashNotMatching("proof1.to -> proof2.from")
642
+ );
643
+
644
+ // Check blockHashRoot
645
+ publicInput.blockHashRoot.assertEquals(
646
+ proof1.publicInput.blockHashRoot,
647
+ errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
648
+ );
649
+ proof1.publicOutput.blockHashRoot.assertEquals(
650
+ proof2.publicInput.blockHashRoot,
406
651
  errors.transactionsHashNotMatching("proof1.to -> proof2.from")
407
652
  );
408
653
 
654
+ // Check eternalTransactionsHash
655
+ publicInput.eternalTransactionsHash.assertEquals(
656
+ proof1.publicInput.eternalTransactionsHash,
657
+ errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
658
+ );
659
+ proof1.publicOutput.eternalTransactionsHash.assertEquals(
660
+ proof2.publicInput.eternalTransactionsHash,
661
+ errors.transactionsHashNotMatching("proof1.to -> proof2.from")
662
+ );
663
+
664
+ // Check incomingMessagesHash
665
+ publicInput.incomingMessagesHash.assertEquals(
666
+ proof1.publicInput.incomingMessagesHash,
667
+ errors.propertyNotMatchingStep(
668
+ "IncomingMessagesHash",
669
+ "publicInput.from -> proof1.from"
670
+ )
671
+ );
672
+ proof1.publicOutput.incomingMessagesHash.assertEquals(
673
+ proof2.publicInput.incomingMessagesHash,
674
+ errors.propertyNotMatchingStep(
675
+ "IncomingMessagesHash",
676
+ "proof1.to -> proof2.from"
677
+ )
678
+ );
679
+
680
+ // Assert closed indicator matches
681
+ // (i.e. we can only merge TX-Type and Block-Type with each other)
682
+ proof1.publicOutput.closed.assertEquals(
683
+ proof2.publicOutput.closed,
684
+ "Closed indicators not matching"
685
+ );
686
+
687
+ // Either
688
+ // blockNumbers are unset and proofs are unclosed or
689
+ // both blocks are closed, then they have to increment or
690
+ // one block is closed, then height has to be the same
691
+
692
+ // Imperative algo would look like
693
+ // if(proof1.height == MAX && proof2.height == MAX){
694
+ // assert !proof1.closed && !proof2.closed;
695
+ // }else if(proof1.closed && proof2.closed){
696
+ // assert proof1.height + 1 == proof2.height
697
+ // // next one is omitted for now
698
+ // }else if(proof1.closed || proof2.closed{
699
+ // assert proof1.height == proof2.height
700
+ // }
701
+
702
+ const proof1Height = proof1.publicOutput.blockNumber;
703
+ const proof1Closed = proof1.publicOutput.closed;
704
+ const proof2Height = proof2.publicOutput.blockNumber;
705
+ const proof2Closed = proof2.publicOutput.closed;
706
+
707
+ const isValidTransactionMerge = proof1Height
708
+ .equals(maxField())
709
+ .and(proof2Height.equals(proof1Height))
710
+ .and(proof1Closed.or(proof2Closed).not());
711
+
712
+ const isValidClosedMerge = proof1Closed
713
+ .and(proof2Closed)
714
+ .and(proof1Height.add(1).equals(proof2Height));
715
+
716
+ isValidTransactionMerge
717
+ .or(isValidClosedMerge)
718
+ .assertTrue("Invalid BlockProof merge");
719
+
409
720
  return new BlockProverPublicOutput({
410
721
  stateRoot: proof2.publicOutput.stateRoot,
411
722
  transactionsHash: proof2.publicOutput.transactionsHash,
412
723
  networkStateHash: proof2.publicOutput.networkStateHash,
724
+ blockHashRoot: proof2.publicOutput.blockHashRoot,
725
+ eternalTransactionsHash: proof2.publicOutput.eternalTransactionsHash,
726
+ incomingMessagesHash: proof2.publicOutput.incomingMessagesHash,
727
+ // Provable.if(isValidClosedMerge, Bool(true), Bool(false));
728
+ closed: isValidClosedMerge,
729
+ blockNumber: proof2Height,
413
730
  });
414
731
  }
415
732
 
@@ -495,10 +812,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
495
812
  * then be merged to be committed to the base-layer contract
496
813
  */
497
814
  @injectable()
498
- export class BlockProver
499
- extends ProtocolModule
500
- implements BlockProvable
501
- {
815
+ export class BlockProver extends ProtocolModule implements BlockProvable {
502
816
  public zkProgrammable: BlockProverProgrammable;
503
817
 
504
818
  public constructor(
@@ -524,14 +838,6 @@ export class BlockProver
524
838
  );
525
839
  }
526
840
 
527
- public merge(
528
- publicInput: BlockProverPublicInput,
529
- proof1: BlockProverProof,
530
- proof2: BlockProverProof
531
- ): BlockProverPublicOutput {
532
- return this.zkProgrammable.merge(publicInput, proof1, proof2);
533
- }
534
-
535
841
  public proveTransaction(
536
842
  publicInput: BlockProverPublicInput,
537
843
  stateProof: StateTransitionProof,
@@ -545,4 +851,28 @@ export class BlockProver
545
851
  executionData
546
852
  );
547
853
  }
854
+
855
+ public proveBlock(
856
+ publicInput: BlockProverPublicInput,
857
+ networkState: NetworkState,
858
+ blockWitness: BlockHashMerkleTreeWitness,
859
+ stateTransitionProof: StateTransitionProof,
860
+ transactionProof: BlockProverProof
861
+ ): BlockProverPublicOutput {
862
+ return this.zkProgrammable.proveBlock(
863
+ publicInput,
864
+ networkState,
865
+ blockWitness,
866
+ stateTransitionProof,
867
+ transactionProof
868
+ );
869
+ }
870
+
871
+ public merge(
872
+ publicInput: BlockProverPublicInput,
873
+ proof1: BlockProverProof,
874
+ proof2: BlockProverProof
875
+ ): BlockProverPublicOutput {
876
+ return this.zkProgrammable.merge(publicInput, proof1, proof2);
877
+ }
548
878
  }