@proto-kit/protocol 0.1.1-develop.1315 → 0.1.1-develop.1343

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 (154) hide show
  1. package/dist/hooks/AccountStateHook.d.ts +3 -3
  2. package/dist/hooks/AccountStateHook.d.ts.map +1 -1
  3. package/dist/hooks/AccountStateHook.js +6 -2
  4. package/dist/hooks/AccountStateHook.js.map +1 -1
  5. package/dist/hooks/LastStateRootBlockHook.d.ts +3 -4
  6. package/dist/hooks/LastStateRootBlockHook.d.ts.map +1 -1
  7. package/dist/hooks/LastStateRootBlockHook.js +4 -4
  8. package/dist/hooks/LastStateRootBlockHook.js.map +1 -1
  9. package/dist/hooks/NoopBlockHook.d.ts +3 -4
  10. package/dist/hooks/NoopBlockHook.d.ts.map +1 -1
  11. package/dist/hooks/NoopBlockHook.js +1 -1
  12. package/dist/hooks/NoopBlockHook.js.map +1 -1
  13. package/dist/hooks/NoopTransactionHook.d.ts +2 -2
  14. package/dist/hooks/NoopTransactionHook.d.ts.map +1 -1
  15. package/dist/hooks/NoopTransactionHook.js +4 -1
  16. package/dist/hooks/NoopTransactionHook.js.map +1 -1
  17. package/dist/index.d.ts +6 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +6 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/model/AppliedStateTransitionBatch.d.ts +114 -0
  22. package/dist/model/AppliedStateTransitionBatch.d.ts.map +1 -0
  23. package/dist/model/AppliedStateTransitionBatch.js +16 -0
  24. package/dist/model/AppliedStateTransitionBatch.js.map +1 -0
  25. package/dist/model/StateTransition.d.ts +1 -0
  26. package/dist/model/StateTransition.d.ts.map +1 -1
  27. package/dist/model/StateTransition.js +5 -0
  28. package/dist/model/StateTransition.js.map +1 -1
  29. package/dist/model/StateTransitionProvableBatch.d.ts +249 -97
  30. package/dist/model/StateTransitionProvableBatch.d.ts.map +1 -1
  31. package/dist/model/StateTransitionProvableBatch.js +72 -65
  32. package/dist/model/StateTransitionProvableBatch.js.map +1 -1
  33. package/dist/model/transaction/RuntimeTransaction.d.ts +1 -0
  34. package/dist/model/transaction/RuntimeTransaction.d.ts.map +1 -1
  35. package/dist/model/transaction/RuntimeTransaction.js +3 -0
  36. package/dist/model/transaction/RuntimeTransaction.js.map +1 -1
  37. package/dist/protocol/ProvableBlockHook.d.ts +13 -3
  38. package/dist/protocol/ProvableBlockHook.d.ts.map +1 -1
  39. package/dist/protocol/ProvableBlockHook.js +16 -0
  40. package/dist/protocol/ProvableBlockHook.js.map +1 -1
  41. package/dist/protocol/ProvableTransactionHook.d.ts +29 -2
  42. package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -1
  43. package/dist/protocol/ProvableTransactionHook.js +9 -0
  44. package/dist/protocol/ProvableTransactionHook.js.map +1 -1
  45. package/dist/prover/accumulators/AppliedBatchHashList.d.ts +18 -0
  46. package/dist/prover/accumulators/AppliedBatchHashList.d.ts.map +1 -0
  47. package/dist/prover/accumulators/AppliedBatchHashList.js +25 -0
  48. package/dist/prover/accumulators/AppliedBatchHashList.js.map +1 -0
  49. package/dist/{utils → prover/accumulators}/StateTransitionReductionList.d.ts +3 -2
  50. package/dist/prover/accumulators/StateTransitionReductionList.d.ts.map +1 -0
  51. package/dist/{utils → prover/accumulators}/StateTransitionReductionList.js +6 -3
  52. package/dist/prover/accumulators/StateTransitionReductionList.js.map +1 -0
  53. package/dist/prover/accumulators/TransactionHashList.d.ts +6 -0
  54. package/dist/prover/accumulators/TransactionHashList.d.ts.map +1 -0
  55. package/dist/prover/accumulators/TransactionHashList.js +8 -0
  56. package/dist/prover/accumulators/TransactionHashList.js.map +1 -0
  57. package/dist/prover/accumulators/WitnessedRootHashList.d.ts +137 -0
  58. package/dist/prover/accumulators/WitnessedRootHashList.d.ts.map +1 -0
  59. package/dist/prover/accumulators/WitnessedRootHashList.js +50 -0
  60. package/dist/prover/accumulators/WitnessedRootHashList.js.map +1 -0
  61. package/dist/prover/block/BlockProvable.d.ts +579 -35
  62. package/dist/prover/block/BlockProvable.d.ts.map +1 -1
  63. package/dist/prover/block/BlockProvable.js +55 -3
  64. package/dist/prover/block/BlockProvable.js.map +1 -1
  65. package/dist/prover/block/BlockProver.d.ts +52 -50
  66. package/dist/prover/block/BlockProver.d.ts.map +1 -1
  67. package/dist/prover/block/BlockProver.js +289 -209
  68. package/dist/prover/block/BlockProver.js.map +1 -1
  69. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts +55 -13
  70. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts.map +1 -1
  71. package/dist/prover/block/accummulators/BlockHashMerkleTree.js +11 -3
  72. package/dist/prover/block/accummulators/BlockHashMerkleTree.js.map +1 -1
  73. package/dist/prover/statetransition/StateTransitionProvable.d.ts +107 -106
  74. package/dist/prover/statetransition/StateTransitionProvable.d.ts.map +1 -1
  75. package/dist/prover/statetransition/StateTransitionProvable.js +8 -8
  76. package/dist/prover/statetransition/StateTransitionProvable.js.map +1 -1
  77. package/dist/prover/statetransition/StateTransitionProver.d.ts +14 -11
  78. package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -1
  79. package/dist/prover/statetransition/StateTransitionProver.js +116 -62
  80. package/dist/prover/statetransition/StateTransitionProver.js.map +1 -1
  81. package/dist/settlement/contracts/DispatchContractProtocolModule.d.ts +1 -1
  82. package/dist/settlement/contracts/DispatchSmartContract.d.ts +1 -1
  83. package/dist/settlement/contracts/SettlementSmartContract.d.ts.map +1 -1
  84. package/dist/settlement/contracts/SettlementSmartContract.js +1 -0
  85. package/dist/settlement/contracts/SettlementSmartContract.js.map +1 -1
  86. package/dist/state/assert/assert.d.ts.map +1 -1
  87. package/dist/state/assert/assert.js +5 -3
  88. package/dist/state/assert/assert.js.map +1 -1
  89. package/dist/state/context/RuntimeMethodExecutionContext.d.ts +3 -3
  90. package/dist/state/context/RuntimeMethodExecutionContext.d.ts.map +1 -1
  91. package/dist/state/context/RuntimeMethodExecutionContext.js +7 -4
  92. package/dist/state/context/RuntimeMethodExecutionContext.js.map +1 -1
  93. package/dist/utils/FieldOptions.d.ts +62 -0
  94. package/dist/utils/FieldOptions.d.ts.map +1 -0
  95. package/dist/utils/FieldOptions.js +13 -0
  96. package/dist/utils/FieldOptions.js.map +1 -0
  97. package/dist/utils/ProvableHashList.d.ts +21 -2
  98. package/dist/utils/ProvableHashList.d.ts.map +1 -1
  99. package/dist/utils/ProvableHashList.js +37 -2
  100. package/dist/utils/ProvableHashList.js.map +1 -1
  101. package/dist/utils/ProvableReductionHashList.d.ts +7 -3
  102. package/dist/utils/ProvableReductionHashList.d.ts.map +1 -1
  103. package/dist/utils/ProvableReductionHashList.js +8 -5
  104. package/dist/utils/ProvableReductionHashList.js.map +1 -1
  105. package/dist/utils/utils.d.ts +10 -1
  106. package/dist/utils/utils.d.ts.map +1 -1
  107. package/dist/utils/utils.js +6 -0
  108. package/dist/utils/utils.js.map +1 -1
  109. package/package.json +2 -2
  110. package/src/hooks/AccountStateHook.ts +12 -3
  111. package/src/hooks/LastStateRootBlockHook.ts +7 -8
  112. package/src/hooks/NoopBlockHook.ts +7 -4
  113. package/src/hooks/NoopTransactionHook.ts +5 -2
  114. package/src/index.ts +6 -1
  115. package/src/model/AppliedStateTransitionBatch.ts +16 -0
  116. package/src/model/StateTransition.ts +6 -0
  117. package/src/model/StateTransitionProvableBatch.ts +94 -105
  118. package/src/model/transaction/RuntimeTransaction.ts +4 -0
  119. package/src/protocol/ProvableBlockHook.ts +51 -3
  120. package/src/protocol/ProvableTransactionHook.ts +67 -3
  121. package/src/prover/accumulators/AppliedBatchHashList.ts +32 -0
  122. package/src/{utils → prover/accumulators}/StateTransitionReductionList.ts +7 -4
  123. package/src/prover/accumulators/TransactionHashList.ts +9 -0
  124. package/src/prover/accumulators/WitnessedRootHashList.ts +61 -0
  125. package/src/prover/block/BlockProvable.ts +128 -9
  126. package/src/prover/block/BlockProver.ts +531 -383
  127. package/src/prover/block/accummulators/BlockHashMerkleTree.ts +11 -3
  128. package/src/prover/statetransition/StateTransitionProvable.ts +17 -11
  129. package/src/prover/statetransition/StateTransitionProver.ts +219 -144
  130. package/src/settlement/contracts/SettlementSmartContract.ts +4 -0
  131. package/src/state/assert/assert.ts +6 -3
  132. package/src/state/context/RuntimeMethodExecutionContext.ts +15 -7
  133. package/src/utils/FieldOptions.ts +13 -0
  134. package/src/utils/ProvableHashList.ts +77 -2
  135. package/src/utils/ProvableReductionHashList.ts +12 -3
  136. package/src/utils/utils.ts +18 -1
  137. package/test/BlockProver.test.ts +2 -0
  138. package/test/TestingProtocol.ts +5 -0
  139. package/test/model/StateTransitionProvableBatch.test.ts +137 -0
  140. package/test/prover/block/BlockProver.test.ts +18 -0
  141. package/test/prover/statetransition/StateTransitionProver.test.ts +240 -0
  142. package/test/utils/ProvableHashList.test.ts +44 -0
  143. package/test/utils/ProvableReductionHashList.test.ts +1 -1
  144. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts +0 -16
  145. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts.map +0 -1
  146. package/dist/prover/statetransition/StateTransitionWitnessProvider.js +0 -16
  147. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts +0 -7
  148. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts.map +0 -1
  149. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.js +0 -19
  150. package/dist/state/context/ProtocolMethodExecutionContext.d.ts +0 -22
  151. package/dist/state/context/ProtocolMethodExecutionContext.d.ts.map +0 -1
  152. package/dist/state/context/ProtocolMethodExecutionContext.js +0 -28
  153. package/dist/utils/StateTransitionReductionList.d.ts.map +0 -1
  154. package/dist/utils/StateTransitionReductionList.js.map +0 -1
@@ -1,8 +1,6 @@
1
1
  import {
2
2
  Bool,
3
- DynamicProof,
4
3
  Field,
5
- Poseidon,
6
4
  Proof,
7
5
  Provable,
8
6
  SelfProof,
@@ -15,6 +13,7 @@ import {
15
13
  CompilableModule,
16
14
  CompileArtifact,
17
15
  CompileRegistry,
16
+ log,
18
17
  MAX_FIELD,
19
18
  PlainZkProgram,
20
19
  provableMethod,
@@ -22,7 +21,6 @@ import {
22
21
  ZkProgrammable,
23
22
  } from "@proto-kit/common";
24
23
 
25
- import { DefaultProvableHashList } from "../../utils/ProvableHashList";
26
24
  import { MethodPublicOutput } from "../../model/MethodPublicOutput";
27
25
  import { ProtocolModule } from "../../protocol/ProtocolModule";
28
26
  import {
@@ -36,24 +34,43 @@ import {
36
34
  ProvableStateTransition,
37
35
  StateTransition,
38
36
  } from "../../model/StateTransition";
39
- import { ProvableTransactionHook } from "../../protocol/ProvableTransactionHook";
40
- import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethodExecutionContext";
41
- import { ProvableBlockHook } from "../../protocol/ProvableBlockHook";
37
+ import {
38
+ AfterTransactionHookArguments,
39
+ BeforeTransactionHookArguments,
40
+ ProvableTransactionHook,
41
+ toProvableHookBlockState,
42
+ } from "../../protocol/ProvableTransactionHook";
43
+ import {
44
+ RuntimeMethodExecutionContext,
45
+ RuntimeMethodExecutionData,
46
+ } from "../../state/context/RuntimeMethodExecutionContext";
47
+ import {
48
+ AfterBlockHookArguments,
49
+ BeforeBlockHookArguments,
50
+ ProvableBlockHook,
51
+ toAfterTransactionHookArgument,
52
+ toBeforeTransactionHookArgument,
53
+ } from "../../protocol/ProvableBlockHook";
42
54
  import { NetworkState } from "../../model/network/NetworkState";
43
55
  import { SignedTransaction } from "../../model/transaction/SignedTransaction";
44
- import {
45
- MinaActions,
46
- MinaActionsHashList,
47
- } from "../../utils/MinaPrefixedProvableHashList";
48
- import { StateTransitionReductionList } from "../../utils/StateTransitionReductionList";
56
+ import { MinaActions } from "../../utils/MinaPrefixedProvableHashList";
57
+ import { StateTransitionReductionList } from "../accumulators/StateTransitionReductionList";
58
+ import { assertEqualsIf } from "../../utils/utils";
59
+ import { WitnessedRootWitness } from "../accumulators/WitnessedRootHashList";
60
+ import { StateServiceProvider } from "../../state/StateServiceProvider";
61
+ import { AppliedStateTransitionBatch } from "../../model/AppliedStateTransitionBatch";
49
62
 
50
63
  import {
51
64
  BlockProvable,
52
- BlockProverExecutionData,
53
65
  BlockProverProof,
54
66
  BlockProverPublicInput,
55
67
  BlockProverPublicOutput,
56
68
  DynamicRuntimeProof,
69
+ BlockProverMultiTransactionExecutionData,
70
+ BlockProverTransactionArguments,
71
+ BlockProverSingleTransactionExecutionData,
72
+ BlockProverState,
73
+ BlockProverStateCommitments,
57
74
  } from "./BlockProvable";
58
75
  import {
59
76
  BlockHashMerkleTreeWitness,
@@ -67,12 +84,6 @@ import {
67
84
  import { RuntimeVerificationKeyRootService } from "./services/RuntimeVerificationKeyRootService";
68
85
 
69
86
  const errors = {
70
- stateProofNotStartingAtZero: () =>
71
- "StateProof not starting ST-commitment at zero",
72
-
73
- stateTransitionsHashNotEqual: () =>
74
- "StateTransition list commitments are not equal",
75
-
76
87
  propertyNotMatchingStep: (propertyName: string, step: string) =>
77
88
  `${propertyName} not matching: ${step}`,
78
89
 
@@ -89,48 +100,14 @@ const errors = {
89
100
 
90
101
  invalidZkProgramTreeRoot: () =>
91
102
  "Root hash of the provided zkProgram config witness is invalid",
92
-
93
- invalidZkProgramConfigMethodId: () =>
94
- "Method id of the provided zkProgram config does not match the executed transaction method id",
95
103
  };
96
104
 
97
- // Should be equal to BlockProver.PublicInput
98
- export interface BlockProverState {
99
- /**
100
- * The current state root of the block prover
101
- */
102
- stateRoot: Field;
103
-
104
- /**
105
- * The current commitment of the transaction-list which
106
- * will at the end equal the bundle hash
107
- */
108
- transactionsHash: Field;
109
-
110
- /**
111
- * The network state which gives access to values such as blockHeight
112
- * This value is the same for the whole batch (L2 block)
113
- */
114
- networkStateHash: Field;
115
-
116
- /**
117
- * The root of the merkle tree encoding all block hashes,
118
- * see `BlockHashMerkleTree`
119
- */
120
- blockHashRoot: Field;
121
-
122
- /**
123
- * A variant of the transactionsHash that is never reset.
124
- * Thought for usage in the sequence state mempool.
125
- * In comparison, transactionsHash restarts at 0 for every new block
126
- */
127
- eternalTransactionsHash: Field;
128
-
129
- incomingMessagesHash: Field;
130
- }
105
+ type ApplyTransactionArguments = Omit<
106
+ BlockProverTransactionArguments,
107
+ "verificationKeyAttestation"
108
+ >;
131
109
 
132
110
  export type BlockProof = Proof<BlockProverPublicInput, BlockProverPublicOutput>;
133
- export type RuntimeProof = Proof<void, MethodPublicOutput>;
134
111
 
135
112
  export class BlockProverProgrammable extends ZkProgrammable<
136
113
  BlockProverPublicInput,
@@ -142,9 +119,9 @@ export class BlockProverProgrammable extends ZkProgrammable<
142
119
  StateTransitionProverPublicInput,
143
120
  StateTransitionProverPublicOutput
144
121
  >,
145
- public readonly runtime: ZkProgrammable<undefined, MethodPublicOutput>,
146
122
  private readonly transactionHooks: ProvableTransactionHook<unknown>[],
147
123
  private readonly blockHooks: ProvableBlockHook<unknown>[],
124
+ private readonly stateServiceProvider: StateServiceProvider,
148
125
  private readonly verificationKeyService: MinimalVKTreeService
149
126
  ) {
150
127
  super();
@@ -158,78 +135,80 @@ export class BlockProverProgrammable extends ZkProgrammable<
158
135
 
159
136
  /**
160
137
  * Applies and checks the two proofs and applies the corresponding state
161
- * changes to the given state
138
+ * changes to the given state.
139
+ *
140
+ * The rough high level workflow of this function:
141
+ * 1. Execute beforeTransaction hooks, pushing the ST batch
142
+ * 2. Add Transaction to bundle, meaning appending it to all the respective commitments
143
+ * 3. Push the runtime ST batch
144
+ * 4. Execute afterTransaction hooks, pushing the ST batch
145
+ * 5. Some consistency checks and signature verification
162
146
  *
163
- * @param state The from-state of the BlockProver
164
- * @param stateTransitionProof
165
- * @param runtimeProof
147
+ * @param fromState The from-state of the BlockProver
148
+ * @param runtimeOutput
166
149
  * @param executionData
167
- * @param verificationKey
150
+ * @param networkState
168
151
  * @returns The new BlockProver-state to be used as public output
169
152
  */
170
153
  public async applyTransaction(
171
- state: BlockProverState,
172
- stateTransitionProof: Proof<
173
- StateTransitionProverPublicInput,
174
- StateTransitionProverPublicOutput
175
- >,
176
- runtimeProof: DynamicRuntimeProof,
177
- executionData: BlockProverExecutionData,
178
- verificationKey: VerificationKey
154
+ fromState: BlockProverState,
155
+ runtimeOutput: MethodPublicOutput,
156
+ executionData: ApplyTransactionArguments,
157
+ networkState: NetworkState
179
158
  ): Promise<BlockProverState> {
180
- const { transaction, networkState, signature } = executionData;
159
+ const { transaction, signature } = executionData;
181
160
 
182
- const { isMessage } = runtimeProof.publicOutput;
183
-
184
- runtimeProof.verify(verificationKey);
185
- stateTransitionProof.verify();
161
+ let state = { ...fromState };
186
162
 
187
- const stateTo = { ...state };
163
+ const { isMessage } = runtimeOutput;
188
164
 
189
- // Checks for the stateTransitionProof and appProof matching
190
- stateTransitionProof.publicInput.stateTransitionsHash.assertEquals(
191
- Field(0),
192
- errors.stateProofNotStartingAtZero()
193
- );
194
- stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
195
- Field(0),
196
- errors.stateProofNotStartingAtZero()
165
+ const beforeTxHookArguments = toBeforeTransactionHookArgument(
166
+ executionData,
167
+ networkState,
168
+ state
197
169
  );
198
170
 
199
- runtimeProof.publicOutput.stateTransitionsHash.assertEquals(
200
- stateTransitionProof.publicOutput.stateTransitionsHash,
201
- errors.stateTransitionsHashNotEqual()
171
+ // Apply beforeTransaction hook state transitions
172
+ const beforeBatch = await this.executeTransactionHooks(
173
+ async (module, args) => await module.beforeTransaction(args),
174
+ beforeTxHookArguments
202
175
  );
203
176
 
204
- // Assert from state roots
205
- state.stateRoot.assertEquals(
206
- stateTransitionProof.publicInput.stateRoot,
207
- errors.propertyNotMatching("from state root")
208
- );
209
- state.stateRoot.assertEquals(
210
- stateTransitionProof.publicInput.protocolStateRoot,
211
- errors.propertyNotMatching("from protocol state root")
177
+ state = this.addTransactionToBundle(
178
+ state,
179
+ runtimeOutput.isMessage,
180
+ transaction
212
181
  );
213
182
 
214
- // Apply protocol state transitions
215
- await this.assertProtocolTransitions(
216
- stateTransitionProof,
183
+ state.pendingSTBatches.push(beforeBatch);
184
+
185
+ state.pendingSTBatches.push({
186
+ batchHash: runtimeOutput.stateTransitionsHash,
187
+ applied: runtimeOutput.status,
188
+ });
189
+
190
+ // Apply afterTransaction hook state transitions
191
+ const afterTxHookArguments = toAfterTransactionHookArgument(
217
192
  executionData,
218
- runtimeProof
193
+ networkState,
194
+ state,
195
+ runtimeOutput
219
196
  );
220
197
 
221
- // Apply state if status success
222
- stateTo.stateRoot = Provable.if(
223
- runtimeProof.publicOutput.status,
224
- stateTransitionProof.publicOutput.stateRoot,
225
- stateTransitionProof.publicOutput.protocolStateRoot
198
+ // Switch to different state set for afterTx hooks
199
+ this.stateServiceProvider.popCurrentStateService();
200
+
201
+ const afterBatch = await this.executeTransactionHooks(
202
+ async (module, args) => await module.afterTransaction(args),
203
+ afterTxHookArguments
226
204
  );
205
+ state.pendingSTBatches.push(afterBatch);
227
206
 
228
207
  // Check transaction integrity against appProof
229
208
  const blockTransactionHash = transaction.hash();
230
209
 
231
210
  blockTransactionHash.assertEquals(
232
- runtimeProof.publicOutput.transactionHash,
211
+ runtimeOutput.transactionHash,
233
212
  "Transactions provided in AppProof and BlockProof do not match"
234
213
  );
235
214
 
@@ -246,236 +225,333 @@ export class BlockProverProgrammable extends ZkProgrammable<
246
225
  transaction.assertTransactionType(isMessage);
247
226
 
248
227
  // Check network state integrity against appProof
249
- state.networkStateHash.assertEquals(
250
- runtimeProof.publicOutput.networkStateHash,
251
- "Network state does not match state used in AppProof"
252
- );
253
- state.networkStateHash.assertEquals(
254
- networkState.hash(),
255
- "Network state provided to BlockProver does not match the publicInput"
256
- );
228
+ state.networkState
229
+ .hash()
230
+ .assertEquals(
231
+ runtimeOutput.networkStateHash,
232
+ "Network state does not match state used in AppProof"
233
+ );
257
234
 
258
- return stateTo;
235
+ return state;
259
236
  }
260
237
 
261
238
  // eslint-disable-next-line max-len
262
239
  // TODO How does this interact with the RuntimeMethodExecutionContext when executing runtimemethods?
263
240
 
264
- public async assertProtocolTransitions(
265
- stateTransitionProof: Proof<
266
- StateTransitionProverPublicInput,
267
- StateTransitionProverPublicOutput
268
- >,
269
- executionData: BlockProverExecutionData,
270
- runtimeProof: DynamicProof<void, MethodPublicOutput>
241
+ /**
242
+ * Constructs a AppliedBatch based on a list of STs and the flag whether to
243
+ * be applied or not. The AppliedBatch is a condensed commitment to a batch
244
+ * of STs.
245
+ */
246
+ private constructBatch(
247
+ stateTransitions: StateTransition<any>[],
248
+ applied: Bool
271
249
  ) {
272
- const executionContext = container.resolve(RuntimeMethodExecutionContext);
273
- executionContext.clear();
274
-
275
- // Setup context for potential calls to runtime methods.
276
- // This way they can use this.transaction etc. while still having provable
277
- // integrity between data
278
- executionContext.setup({
279
- // That is why we should probably hide it from the transaction context inputs
280
- transaction: executionData.transaction,
281
- networkState: executionData.networkState,
282
- });
283
- executionContext.beforeMethod("", "", []);
284
-
285
- for (const module of this.transactionHooks) {
286
- // eslint-disable-next-line no-await-in-loop
287
- await module.onTransaction(executionData);
288
- }
289
-
290
- executionContext.afterMethod();
291
-
292
- const { stateTransitions, status, statusMessage } =
293
- executionContext.current().result;
294
-
295
- status.assertTrue(statusMessage);
296
-
297
250
  const transitions = stateTransitions.map((transition) =>
298
251
  transition.toProvable()
299
252
  );
300
253
 
301
- const hashList = new StateTransitionReductionList(
302
- ProvableStateTransition,
303
- stateTransitionProof.publicInput.protocolTransitionsHash
304
- );
305
-
254
+ const hashList = new StateTransitionReductionList(ProvableStateTransition);
306
255
  transitions.forEach((transition) => {
307
256
  hashList.push(transition);
308
257
  });
309
258
 
310
- stateTransitionProof.publicOutput.protocolTransitionsHash.assertEquals(
311
- hashList.commitment,
312
- "ProtocolTransitionsHash not matching the generated protocol transitions"
313
- );
259
+ return new AppliedStateTransitionBatch({
260
+ batchHash: hashList.commitment,
261
+ applied,
262
+ });
314
263
  }
315
264
 
316
- private async executeBlockHooks(
317
- state: BlockProverState,
318
- inputNetworkState: NetworkState,
319
- type: "afterBlock" | "beforeBlock"
320
- ): Promise<{
321
- networkState: NetworkState;
322
- stateTransitions: StateTransition<unknown>[];
323
- }> {
265
+ private async executeTransactionHooks<
266
+ T extends BeforeTransactionHookArguments | AfterTransactionHookArguments,
267
+ >(
268
+ hook: (module: ProvableTransactionHook<unknown>, args: T) => Promise<void>,
269
+ hookArguments: T
270
+ ) {
271
+ const { batch } = await this.executeHooks(hookArguments, async () => {
272
+ for (const module of this.transactionHooks) {
273
+ // eslint-disable-next-line no-await-in-loop
274
+ await hook(module, hookArguments);
275
+ }
276
+ });
277
+ return batch;
278
+ }
279
+
280
+ private async executeHooks<T>(
281
+ contextArguments: RuntimeMethodExecutionData,
282
+ method: () => Promise<T>
283
+ ) {
324
284
  const executionContext = container.resolve(RuntimeMethodExecutionContext);
325
285
  executionContext.clear();
286
+
287
+ // Setup context for potential calls to runtime methods.
288
+ // This way they can use this.transaction etc. while still having provable
289
+ // integrity between data
290
+ executionContext.setup(contextArguments);
326
291
  executionContext.beforeMethod("", "", []);
327
292
 
328
- const resultingNetworkState = await this.blockHooks.reduce<
329
- Promise<NetworkState>
330
- >(async (networkStatePromise, blockHook) => {
331
- const networkState = await networkStatePromise;
332
- // Setup context for potential calls to runtime methods.
333
- // With the special case that we set the new networkstate for every hook
334
- // We also have to put in a dummy transaction for network.transaction
335
- executionContext.setup({
336
- transaction: RuntimeTransaction.dummyTransaction(),
337
- networkState,
338
- });
339
-
340
- if (type === "beforeBlock") {
341
- return await blockHook.beforeBlock(networkState, state);
342
- }
343
- if (type === "afterBlock") {
344
- return await blockHook.afterBlock(networkState, state);
345
- }
346
- throw new Error("Unreachable");
347
- }, Promise.resolve(inputNetworkState));
293
+ const result = await method();
348
294
 
349
295
  executionContext.afterMethod();
350
296
 
351
297
  const { stateTransitions, status, statusMessage } =
352
298
  executionContext.current().result;
353
299
 
354
- status.assertTrue(`Block hook call failed: ${statusMessage ?? "-"}`);
300
+ status.assertTrue(`Transaction hook call failed: ${statusMessage ?? "-"}`);
355
301
 
356
302
  return {
357
- networkState: resultingNetworkState,
358
- stateTransitions,
303
+ batch: this.constructBatch(stateTransitions, Bool(true)),
304
+ result,
359
305
  };
360
306
  }
361
307
 
362
- private addTransactionToBundle(
363
- state: BlockProverState,
364
- isMessage: Bool,
365
- transaction: RuntimeTransaction
366
- ): BlockProverState {
367
- const stateTo = {
368
- ...state,
308
+ public async executeBlockHooks<
309
+ T extends BeforeBlockHookArguments | AfterBlockHookArguments,
310
+ >(
311
+ hook: (
312
+ module: ProvableBlockHook<unknown>,
313
+ networkState: NetworkState,
314
+ args: T
315
+ ) => Promise<NetworkState>,
316
+ hookArguments: T,
317
+ inputNetworkState: NetworkState
318
+ ) {
319
+ const transaction = RuntimeTransaction.dummyTransaction();
320
+ const startingInputs = {
321
+ transaction,
322
+ networkState: inputNetworkState,
369
323
  };
370
324
 
325
+ return await this.executeHooks(startingInputs, async () => {
326
+ const executionContext = container.resolve(RuntimeMethodExecutionContext);
327
+
328
+ return await this.blockHooks.reduce<Promise<NetworkState>>(
329
+ async (networkStatePromise, blockHook) => {
330
+ const networkState = await networkStatePromise;
331
+
332
+ // Setup context for potential calls to runtime methods.
333
+ // With the special case that we set the new networkstate for every hook
334
+ // We also have to put in a dummy transaction for network.transaction
335
+ executionContext.setup({
336
+ transaction: RuntimeTransaction.dummyTransaction(),
337
+ networkState,
338
+ });
339
+
340
+ return await hook(blockHook, networkState, hookArguments);
341
+ },
342
+ Promise.resolve(inputNetworkState)
343
+ );
344
+ });
345
+ }
346
+
347
+ public addTransactionToBundle<
348
+ T extends Pick<
349
+ BlockProverState,
350
+ "transactionList" | "eternalTransactionsList" | "incomingMessages"
351
+ >,
352
+ >(state: T, isMessage: Bool, transaction: RuntimeTransaction): T {
371
353
  const transactionHash = transaction.hash();
372
354
 
373
355
  // Append tx to transaction list
374
- const transactionList = new DefaultProvableHashList(
375
- Field,
376
- state.transactionsHash
377
- );
378
-
379
- transactionList.pushIf(transactionHash, isMessage.not());
380
- stateTo.transactionsHash = transactionList.commitment;
356
+ state.transactionList.pushIf(transactionHash, isMessage.not());
381
357
 
382
358
  // Append tx to eternal transaction list
383
359
  // TODO Change that to the a sequence-state compatible transaction struct
384
- const eternalTransactionList = new DefaultProvableHashList(
385
- Field,
386
- state.eternalTransactionsHash
387
- );
388
-
389
- eternalTransactionList.pushIf(transactionHash, isMessage.not());
390
- stateTo.eternalTransactionsHash = eternalTransactionList.commitment;
360
+ state.eternalTransactionsList.pushIf(transactionHash, isMessage.not());
391
361
 
392
362
  // Append tx to incomingMessagesHash
393
363
  const actionHash = MinaActions.actionHash(transaction.hashData());
394
364
 
395
- const incomingMessagesList = new MinaActionsHashList(
396
- state.incomingMessagesHash
397
- );
398
- incomingMessagesList.pushIf(actionHash, isMessage);
365
+ state.incomingMessages.pushIf(actionHash, isMessage);
399
366
 
400
- stateTo.incomingMessagesHash = incomingMessagesList.commitment;
367
+ return state;
368
+ }
401
369
 
402
- return stateTo;
370
+ private verifyVerificationKeyAttestation(
371
+ attestation: RuntimeVerificationKeyAttestation,
372
+ methodId: Field
373
+ ): VerificationKey {
374
+ // Verify the [methodId, vk] tuple against the baked-in vk tree root
375
+ const { verificationKey, witness: verificationKeyTreeWitness } =
376
+ attestation;
377
+
378
+ const root = Field(this.verificationKeyService.getRoot());
379
+ const calculatedRoot = verificationKeyTreeWitness.calculateRoot(
380
+ new MethodVKConfigData({
381
+ methodId: methodId,
382
+ vkHash: verificationKey.hash,
383
+ }).hash()
384
+ );
385
+ root.assertEquals(calculatedRoot, errors.invalidZkProgramTreeRoot());
386
+
387
+ return verificationKey;
403
388
  }
404
389
 
405
- @provableMethod()
406
- public async proveTransaction(
407
- publicInput: BlockProverPublicInput,
408
- stateProof: StateTransitionProof,
390
+ public async proveTransactionInternal(
391
+ fromState: BlockProverState,
409
392
  runtimeProof: DynamicRuntimeProof,
410
- executionData: BlockProverExecutionData,
411
- verificationKeyWitness: RuntimeVerificationKeyAttestation
412
- ): Promise<BlockProverPublicOutput> {
413
- const state: BlockProverState = {
414
- ...publicInput,
415
- };
393
+ { transaction, networkState }: BlockProverSingleTransactionExecutionData
394
+ ): Promise<BlockProverState> {
395
+ const verificationKey = this.verifyVerificationKeyAttestation(
396
+ transaction.verificationKeyAttestation,
397
+ transaction.transaction.methodId
398
+ );
416
399
 
417
- state.networkStateHash.assertEquals(
418
- executionData.networkState.hash(),
419
- "ExecutionData Networkstate doesn't equal public input hash"
400
+ runtimeProof.verify(verificationKey);
401
+
402
+ return await this.applyTransaction(
403
+ fromState,
404
+ runtimeProof.publicOutput,
405
+ transaction,
406
+ networkState
420
407
  );
408
+ }
421
409
 
410
+ private staticChecks(publicInput: BlockProverPublicInput) {
422
411
  publicInput.blockNumber.assertEquals(
423
412
  MAX_FIELD,
424
413
  "blockNumber has to be MAX for transaction proofs"
425
414
  );
415
+ }
426
416
 
427
- // Verify the [methodId, vk] tuple against the baked-in vk tree root
428
- const { verificationKey, witness: verificationKeyTreeWitness } =
429
- verificationKeyWitness;
430
-
431
- const root = Field(this.verificationKeyService.getRoot());
432
- const calculatedRoot = verificationKeyTreeWitness.calculateRoot(
433
- new MethodVKConfigData({
434
- methodId: executionData.transaction.methodId,
435
- vkHash: verificationKey.hash,
436
- }).hash()
417
+ @provableMethod()
418
+ public async proveTransaction(
419
+ publicInput: BlockProverPublicInput,
420
+ runtimeProof: DynamicRuntimeProof,
421
+ executionData: BlockProverSingleTransactionExecutionData
422
+ ): Promise<BlockProverPublicOutput> {
423
+ const state = BlockProverStateCommitments.toBlockProverState(
424
+ publicInput,
425
+ executionData.networkState
437
426
  );
438
- root.assertEquals(calculatedRoot, errors.invalidZkProgramTreeRoot());
439
427
 
440
- const bundleInclusionState = this.addTransactionToBundle(
428
+ this.staticChecks(publicInput);
429
+
430
+ const stateTo = await this.proveTransactionInternal(
441
431
  state,
442
- runtimeProof.publicOutput.isMessage,
443
- executionData.transaction
432
+ runtimeProof,
433
+ executionData
444
434
  );
445
435
 
446
- const stateTo = await this.applyTransaction(
447
- bundleInclusionState,
448
- stateProof,
449
- runtimeProof,
450
- executionData,
451
- verificationKey
436
+ return new BlockProverPublicOutput({
437
+ ...BlockProverStateCommitments.fromBlockProverState(stateTo),
438
+ closed: Bool(false),
439
+ });
440
+ }
441
+
442
+ @provableMethod()
443
+ public async proveTransactions(
444
+ publicInput: BlockProverPublicInput,
445
+ runtimeProof1: DynamicRuntimeProof,
446
+ runtimeProof2: DynamicRuntimeProof,
447
+ executionData: BlockProverMultiTransactionExecutionData
448
+ ): Promise<BlockProverPublicOutput> {
449
+ const state = BlockProverStateCommitments.toBlockProverState(
450
+ publicInput,
451
+ executionData.networkState
452
452
  );
453
453
 
454
+ this.staticChecks(publicInput);
455
+
456
+ const state1 = await this.proveTransactionInternal(state, runtimeProof1, {
457
+ transaction: executionData.transaction1,
458
+ networkState: executionData.networkState,
459
+ });
460
+
461
+ // Switch to next state record for 2nd tx beforeTx hook
462
+ // TODO Can be prevented by merging 1st afterTx + 2nd beforeTx
463
+ this.stateServiceProvider.popCurrentStateService();
464
+
465
+ const stateTo = await this.proveTransactionInternal(state1, runtimeProof2, {
466
+ transaction: executionData.transaction2,
467
+ networkState: executionData.networkState,
468
+ });
469
+
454
470
  return new BlockProverPublicOutput({
455
- ...stateTo,
456
- blockNumber: publicInput.blockNumber,
471
+ ...BlockProverStateCommitments.fromBlockProverState(stateTo),
457
472
  closed: Bool(false),
458
473
  });
459
474
  }
460
475
 
461
- private assertSTProofInput(
476
+ public includeSTProof(
462
477
  stateTransitionProof: StateTransitionProof,
463
- stateRoot: Field
464
- ) {
465
- stateTransitionProof.publicInput.stateTransitionsHash.assertEquals(
478
+ apply: Bool,
479
+ stateRoot: Field,
480
+ pendingSTBatchesHash: Field,
481
+ witnessedRootsHash: Field
482
+ ): {
483
+ stateRoot: Field;
484
+ pendingSTBatchesHash: Field;
485
+ witnessedRootsHash: Field;
486
+ } {
487
+ assertEqualsIf(
488
+ stateTransitionProof.publicInput.currentBatchStateHash,
466
489
  Field(0),
467
- errors.stateProofNotStartingAtZero()
490
+ apply,
491
+ "State for STProof has to be empty at the start"
468
492
  );
469
- stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
493
+ assertEqualsIf(
494
+ stateTransitionProof.publicOutput.currentBatchStateHash,
470
495
  Field(0),
471
- errors.stateProofNotStartingAtZero()
496
+ apply,
497
+ "State for STProof has to be empty at the end"
498
+ );
499
+
500
+ assertEqualsIf(
501
+ stateTransitionProof.publicInput.batchesHash,
502
+ Field(0),
503
+ apply,
504
+ "Batcheshash doesn't start at 0"
472
505
  );
473
506
 
474
507
  // Assert from state roots
475
- stateRoot.assertEquals(
476
- stateTransitionProof.publicInput.stateRoot,
508
+ assertEqualsIf(
509
+ stateRoot,
510
+ stateTransitionProof.publicInput.root,
511
+ apply,
512
+ errors.propertyNotMatching("from state root")
513
+ );
514
+ // Assert the stBatchesHash executed is the same
515
+ assertEqualsIf(
516
+ pendingSTBatchesHash,
517
+ stateTransitionProof.publicOutput.batchesHash,
518
+ apply,
519
+ "Pending STBatches are not the same that have been executed by the ST proof"
520
+ );
521
+
522
+ // Assert root Accumulator
523
+ assertEqualsIf(
524
+ Field(0),
525
+ stateTransitionProof.publicInput.witnessedRootsHash,
526
+ apply,
477
527
  errors.propertyNotMatching("from state root")
478
528
  );
529
+ // Assert the witnessedRootsHash created is the same
530
+ assertEqualsIf(
531
+ witnessedRootsHash,
532
+ stateTransitionProof.publicOutput.witnessedRootsHash,
533
+ apply,
534
+ "Root accumulator Commitment is not the same that have been executed by the ST proof"
535
+ );
536
+
537
+ // update root only if we didn't defer
538
+ const newRoot = Provable.if(
539
+ apply,
540
+ stateTransitionProof.publicOutput.root,
541
+ stateRoot
542
+ );
543
+ // Reset only if we didn't defer
544
+ const newBatchesHash = Provable.if(apply, Field(0), pendingSTBatchesHash);
545
+ const newWitnessedRootsHash = Provable.if(
546
+ apply,
547
+ Field(0),
548
+ witnessedRootsHash
549
+ );
550
+ return {
551
+ stateRoot: newRoot,
552
+ pendingSTBatchesHash: newBatchesHash,
553
+ witnessedRootsHash: newWitnessedRootsHash,
554
+ };
479
555
  }
480
556
 
481
557
  @provableMethod()
@@ -483,27 +559,18 @@ export class BlockProverProgrammable extends ZkProgrammable<
483
559
  publicInput: BlockProverPublicInput,
484
560
  networkState: NetworkState,
485
561
  blockWitness: BlockHashMerkleTreeWitness,
486
- // stateTransitionProof: StateTransitionProof,
562
+ stateTransitionProof: StateTransitionProof,
563
+ deferSTProof: Bool,
564
+ afterBlockRootWitness: WitnessedRootWitness,
487
565
  transactionProof: BlockProverProof
488
566
  ): Promise<BlockProverPublicOutput> {
489
- const state: BlockProverState = {
490
- ...publicInput,
491
- };
492
-
493
567
  // 1. Make assertions about the inputs
494
568
  publicInput.transactionsHash.assertEquals(
495
569
  Field(0),
496
570
  "Transactionshash has to start at 0"
497
571
  );
498
- publicInput.networkStateHash.assertEquals(
499
- networkState.hash(),
500
- "Wrong NetworkState supplied"
501
- );
502
572
 
503
- transactionProof.publicInput.transactionsHash.assertEquals(
504
- Field(0),
505
- "TransactionProof transactionshash has to start at 0"
506
- );
573
+ // TransactionProof format checks
507
574
  transactionProof.publicInput.blockHashRoot.assertEquals(
508
575
  Field(0),
509
576
  "TransactionProof cannot carry the blockHashRoot - publicInput"
@@ -516,25 +583,11 @@ export class BlockProverProgrammable extends ZkProgrammable<
516
583
  transactionProof.publicOutput.networkStateHash,
517
584
  "TransactionProof cannot alter the network state"
518
585
  );
519
- transactionProof.publicInput.eternalTransactionsHash.assertEquals(
520
- state.eternalTransactionsHash,
521
- "TransactionProof starting eternalTransactionHash not matching"
522
- );
523
- transactionProof.publicInput.incomingMessagesHash.assertEquals(
524
- state.incomingMessagesHash,
525
- "TransactionProof starting incomingMessagesHash not matching"
526
- );
527
586
 
528
- // TODO Reintroduce ST Proofs
529
- // Verify ST Proof only if STs have been emitted,
530
- // otherwise we can input a dummy proof
531
- // const stsEmitted = stateTransitionProof.publicOutput.stateTransitionsHash
532
- // .equals(0)
533
- // .and(stateTransitionProof.publicOutput.protocolTransitionsHash.equals(0))
534
- // .not();
535
- // Provable.log("VerifyIf 1", stsEmitted);
536
- // stateTransitionProof.verifyIf(Bool(false));
537
- // stateTransitionProof.verifyIf(stsEmitted);
587
+ const state = BlockProverStateCommitments.toBlockProverState(
588
+ publicInput,
589
+ networkState
590
+ );
538
591
 
539
592
  // Verify Transaction proof if it has at least 1 tx - i.e. the
540
593
  // input and output doesn't match fully
@@ -545,87 +598,75 @@ export class BlockProverProgrammable extends ZkProgrammable<
545
598
  transactionProof.publicInput,
546
599
  txProofOutput.closed
547
600
  );
548
- Provable.log("VerifyIf 2", isEmptyTransition.not());
549
- transactionProof.verifyIf(isEmptyTransition.not());
601
+ const skipTransactionProofVerification = isEmptyTransition;
602
+ const verifyTransactionProof = isEmptyTransition.not();
603
+ log.provable.debug("VerifyIf TxProof", verifyTransactionProof);
604
+ transactionProof.verifyIf(verifyTransactionProof);
550
605
 
551
606
  // 2. Execute beforeBlock hooks
607
+ const beforeBlockArgs = toProvableHookBlockState(state);
552
608
  const beforeBlockResult = await this.executeBlockHooks(
553
- state,
554
- networkState,
555
- "beforeBlock"
609
+ async (module, networkStateArg, args) =>
610
+ await module.beforeBlock(networkStateArg, args),
611
+ beforeBlockArgs,
612
+ networkState
556
613
  );
557
614
 
558
- // const beforeBlockHashList = new StateTransitionReductionList(
559
- // ProvableStateTransition
560
- // );
561
- // beforeBlockResult.stateTransitions.forEach((st) => {
562
- // beforeBlockHashList.push(st.toProvable());
563
- // });
564
-
565
- // We are reusing protocolSTs here as beforeBlock STs
566
- // TODO Not possible atm bcs we can't have a seperation between protocol/runtime state roots,
567
- // which we would for both before and after to be able to emit STs
568
-
569
- // stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
570
- // beforeBlockHashList.commitment
571
- // );
572
- // state.stateRoot = stateTransitionProof.publicInput.protocolStateRoot;
573
-
574
- // TODO Only for now
575
- // beforeBlockHashList.commitment.assertEquals(
576
- // Field(0),
577
- // "beforeBlock() cannot emit state transitions yet"
578
- // );
615
+ state.pendingSTBatches.push(beforeBlockResult.batch);
579
616
 
580
617
  // 4. Apply TX-type BlockProof
581
- transactionProof.publicInput.networkStateHash.assertEquals(
582
- beforeBlockResult.networkState.hash(),
583
- "TransactionProof networkstate hash not matching beforeBlock hook result"
584
- );
618
+ transactionProof.publicInput.networkStateHash
619
+ .equals(beforeBlockResult.result.hash())
620
+ .or(skipTransactionProofVerification)
621
+ .assertTrue(
622
+ "TransactionProof networkstate hash not matching beforeBlock hook result"
623
+ );
585
624
  transactionProof.publicInput.stateRoot.assertEquals(
586
- state.stateRoot,
587
- "TransactionProof input state root not matching blockprover state root"
625
+ transactionProof.publicOutput.stateRoot,
626
+ "TransactionProofs can't change the state root"
588
627
  );
589
628
 
590
- state.stateRoot = transactionProof.publicOutput.stateRoot;
591
- state.transactionsHash = transactionProof.publicOutput.transactionsHash;
592
- state.eternalTransactionsHash =
593
- transactionProof.publicOutput.eternalTransactionsHash;
594
- state.incomingMessagesHash =
595
- transactionProof.publicOutput.incomingMessagesHash;
596
-
597
- // 5. Execute afterBlock hooks
598
- // this.assertSTProofInput(stateTransitionProof, state.stateRoot);
599
-
600
- const afterBlockResult = await this.executeBlockHooks(
601
- state,
602
- beforeBlockResult.networkState,
603
- "afterBlock"
629
+ // Check that the transaction proof's STs start after the beforeBlock hook
630
+ transactionProof.publicInput.pendingSTBatchesHash.assertEquals(
631
+ state.pendingSTBatches.commitment,
632
+ "Transaction proof doesn't start their STs after the beforeBlockHook"
604
633
  );
605
-
606
- const afterBlockHashList = new StateTransitionReductionList(
607
- ProvableStateTransition
608
- );
609
- afterBlockResult.stateTransitions.forEach((st) => {
610
- afterBlockHashList.push(st.toProvable());
634
+ // Fast-forward the stBatchHashList to after all transactions appended
635
+ state.pendingSTBatches.commitment =
636
+ transactionProof.publicOutput.pendingSTBatchesHash;
637
+
638
+ // Fast-forward block content commitments by the results of the aggregated transaction proof
639
+ // Implicitly, the 'from' values here are asserted against the publicInput, since the hashlists
640
+ // are created out of the public input
641
+ state.transactionList.fastForward({
642
+ from: transactionProof.publicInput.transactionsHash,
643
+ to: transactionProof.publicOutput.transactionsHash,
644
+ });
645
+ state.eternalTransactionsList.fastForward({
646
+ from: transactionProof.publicInput.eternalTransactionsHash,
647
+ to: transactionProof.publicOutput.eternalTransactionsHash,
648
+ });
649
+ state.incomingMessages.fastForward({
650
+ from: transactionProof.publicInput.incomingMessagesHash,
651
+ to: transactionProof.publicOutput.incomingMessagesHash,
611
652
  });
612
653
 
613
- state.networkStateHash = afterBlockResult.networkState.hash();
614
-
615
- // We are reusing runtime STs here as afterBlock STs
616
- // stateTransitionProof.publicInput.protocolTransitionsHash.assertEquals(
617
- // afterBlockHashList.commitment,
618
- // "STProof from-ST-hash not matching generated ST-hash from afterBlock hooks"
619
- // );
620
- // state.stateRoot = Provable.if(
621
- // stsEmitted,
622
- // stateTransitionProof.publicOutput.stateRoot,
623
- // state.stateRoot
624
- // );
654
+ // Witness root
655
+ const isEmpty = state.pendingSTBatches.commitment.equals(0);
656
+ isEmpty
657
+ .implies(state.stateRoot.equals(afterBlockRootWitness.witnessedRoot))
658
+ .assertTrue();
625
659
 
626
- // 6. Close block
660
+ state.witnessedRoots.witnessRoot(
661
+ {
662
+ appliedBatchListState: state.pendingSTBatches.commitment,
663
+ root: afterBlockRootWitness.witnessedRoot,
664
+ },
665
+ afterBlockRootWitness.preimage,
666
+ isEmpty.not()
667
+ );
627
668
 
628
- // Calculate the new block index
669
+ // 5. Calculate the new block tree hash
629
670
  const blockIndex = blockWitness.calculateIndex();
630
671
 
631
672
  blockIndex.assertEquals(publicInput.blockNumber);
@@ -639,15 +680,60 @@ export class BlockProverProgrammable extends ZkProgrammable<
639
680
 
640
681
  state.blockHashRoot = blockWitness.calculateRoot(
641
682
  new BlockHashTreeEntry({
642
- // Mirroring UnprovenBlock.hash()
643
- blockHash: Poseidon.hash([blockIndex, state.transactionsHash]),
683
+ block: {
684
+ index: blockIndex,
685
+ transactionListHash: state.transactionList.commitment,
686
+ },
644
687
  closed: Bool(true),
645
688
  }).hash()
646
689
  );
647
690
 
691
+ // 6. Execute afterBlock hooks
692
+
693
+ // Switch state service to afterBlock one
694
+ this.stateServiceProvider.popCurrentStateService();
695
+
696
+ const afterBlockHookArgs = toProvableHookBlockState(state);
697
+ const afterBlockResult = await this.executeBlockHooks(
698
+ async (module, networkStateArg, args) =>
699
+ await module.afterBlock(networkStateArg, args),
700
+ {
701
+ ...afterBlockHookArgs,
702
+ stateRoot: afterBlockRootWitness.witnessedRoot,
703
+ },
704
+ beforeBlockResult.result
705
+ );
706
+
707
+ state.pendingSTBatches.push(afterBlockResult.batch);
708
+
709
+ state.networkState = afterBlockResult.result;
710
+
711
+ // 7. Close block
712
+
713
+ // Verify ST Proof only if STs have been emitted,
714
+ // and we don't defer the verification of the STs
715
+ // otherwise we can input a dummy proof
716
+ const batchesEmpty = state.pendingSTBatches.commitment.equals(Field(0));
717
+ const verifyStProof = deferSTProof.not().and(batchesEmpty.not());
718
+ log.provable.debug("Verify STProof", verifyStProof);
719
+ stateTransitionProof.verifyIf(verifyStProof);
720
+
721
+ // Apply STProof if not deferred
722
+ const stateProofResult = this.includeSTProof(
723
+ stateTransitionProof,
724
+ verifyStProof,
725
+ state.stateRoot,
726
+ state.pendingSTBatches.commitment,
727
+ state.witnessedRoots.commitment
728
+ );
729
+ state.stateRoot = stateProofResult.stateRoot;
730
+ state.pendingSTBatches.commitment = stateProofResult.pendingSTBatchesHash;
731
+ state.witnessedRoots.commitment = stateProofResult.witnessedRootsHash;
732
+
733
+ state.blockNumber = blockIndex.add(1);
734
+
648
735
  return new BlockProverPublicOutput({
649
- ...state,
650
- blockNumber: blockIndex.add(1),
736
+ ...BlockProverStateCommitments.fromBlockProverState(state),
651
737
  closed: Bool(true),
652
738
  });
653
739
  }
@@ -732,6 +818,26 @@ export class BlockProverProgrammable extends ZkProgrammable<
732
818
  )
733
819
  );
734
820
 
821
+ // Check pendingSTBatchesHash
822
+ publicInput.pendingSTBatchesHash.assertEquals(
823
+ proof1.publicInput.pendingSTBatchesHash,
824
+ errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
825
+ );
826
+ proof1.publicOutput.pendingSTBatchesHash.assertEquals(
827
+ proof2.publicInput.pendingSTBatchesHash,
828
+ errors.transactionsHashNotMatching("proof1.to -> proof2.from")
829
+ );
830
+
831
+ // Check witnessedRootsHash
832
+ publicInput.witnessedRootsHash.assertEquals(
833
+ proof1.publicInput.witnessedRootsHash,
834
+ errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
835
+ );
836
+ proof1.publicOutput.witnessedRootsHash.assertEquals(
837
+ proof2.publicInput.witnessedRootsHash,
838
+ errors.transactionsHashNotMatching("proof1.to -> proof2.from")
839
+ );
840
+
735
841
  // Assert closed indicator matches
736
842
  // (i.e. we can only merge TX-Type and Block-Type with each other)
737
843
  proof1.publicOutput.closed.assertEquals(
@@ -787,6 +893,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
787
893
  incomingMessagesHash: proof2.publicOutput.incomingMessagesHash,
788
894
  closed: isValidClosedMerge,
789
895
  blockNumber: proof2.publicOutput.blockNumber,
896
+ pendingSTBatchesHash: proof2.publicOutput.pendingSTBatchesHash,
897
+ witnessedRootsHash: proof2.publicOutput.witnessedRootsHash,
790
898
  });
791
899
  }
792
900
 
@@ -802,6 +910,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
802
910
  const { prover, stateTransitionProver } = this;
803
911
  const StateTransitionProofClass = stateTransitionProver.zkProgram[0].Proof;
804
912
  const proveTransaction = prover.proveTransaction.bind(prover);
913
+ const proveTransactions = prover.proveTransactions.bind(prover);
805
914
  const proveBlock = prover.proveBlock.bind(prover);
806
915
  const merge = prover.merge.bind(prover);
807
916
 
@@ -813,25 +922,41 @@ export class BlockProverProgrammable extends ZkProgrammable<
813
922
  methods: {
814
923
  proveTransaction: {
815
924
  privateInputs: [
816
- StateTransitionProofClass,
817
925
  DynamicRuntimeProof,
818
- BlockProverExecutionData,
819
- RuntimeVerificationKeyAttestation,
926
+ BlockProverSingleTransactionExecutionData,
820
927
  ],
821
928
 
822
929
  async method(
823
930
  publicInput: BlockProverPublicInput,
824
- stateProof: StateTransitionProof,
825
- appProof: DynamicRuntimeProof,
826
- executionData: BlockProverExecutionData,
827
- verificationKeyAttestation: RuntimeVerificationKeyAttestation
931
+ runtimeProof: DynamicRuntimeProof,
932
+ executionData: BlockProverSingleTransactionExecutionData
828
933
  ) {
829
934
  return await proveTransaction(
830
935
  publicInput,
831
- stateProof,
832
- appProof,
833
- executionData,
834
- verificationKeyAttestation
936
+ runtimeProof,
937
+ executionData
938
+ );
939
+ },
940
+ },
941
+
942
+ proveTransactions: {
943
+ privateInputs: [
944
+ DynamicRuntimeProof,
945
+ DynamicRuntimeProof,
946
+ BlockProverMultiTransactionExecutionData,
947
+ ],
948
+
949
+ async method(
950
+ publicInput: BlockProverPublicInput,
951
+ runtimeProof1: DynamicRuntimeProof,
952
+ runtimeProof2: DynamicRuntimeProof,
953
+ executionData: BlockProverMultiTransactionExecutionData
954
+ ) {
955
+ return await proveTransactions(
956
+ publicInput,
957
+ runtimeProof1,
958
+ runtimeProof2,
959
+ executionData
835
960
  );
836
961
  },
837
962
  },
@@ -840,21 +965,27 @@ export class BlockProverProgrammable extends ZkProgrammable<
840
965
  privateInputs: [
841
966
  NetworkState,
842
967
  BlockHashMerkleTreeWitness,
843
- // StateTransitionProofClass,
968
+ StateTransitionProofClass,
969
+ Bool,
970
+ WitnessedRootWitness,
844
971
  SelfProof<BlockProverPublicInput, BlockProverPublicOutput>,
845
972
  ],
846
973
  async method(
847
974
  publicInput: BlockProverPublicInput,
848
975
  networkState: NetworkState,
849
976
  blockWitness: BlockHashMerkleTreeWitness,
850
- // stateTransitionProof: StateTransitionProof,
977
+ stateTransitionProof: StateTransitionProof,
978
+ deferSTs: Bool,
979
+ afterBlockRootWitness: WitnessedRootWitness,
851
980
  transactionProof: BlockProverProof
852
981
  ) {
853
982
  return await proveBlock(
854
983
  publicInput,
855
984
  networkState,
856
985
  blockWitness,
857
- // stateTransitionProof,
986
+ stateTransitionProof,
987
+ deferSTs,
988
+ afterBlockRootWitness,
858
989
  transactionProof
859
990
  );
860
991
  },
@@ -879,6 +1010,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
879
1010
 
880
1011
  const methods = {
881
1012
  proveTransaction: program.proveTransaction,
1013
+ proveTransactions: program.proveTransactions,
882
1014
  proveBlock: program.proveBlock,
883
1015
  merge: program.merge,
884
1016
  };
@@ -924,15 +1056,17 @@ export class BlockProver
924
1056
  transactionHooks: ProvableTransactionHook<unknown>[],
925
1057
  @injectAll("ProvableBlockHook")
926
1058
  blockHooks: ProvableBlockHook<unknown>[],
1059
+ @inject("StateServiceProvider")
1060
+ stateServiceProvider: StateServiceProvider,
927
1061
  verificationKeyService: RuntimeVerificationKeyRootService
928
1062
  ) {
929
1063
  super();
930
1064
  this.zkProgrammable = new BlockProverProgrammable(
931
1065
  this,
932
1066
  stateTransitionProver.zkProgrammable,
933
- runtime.zkProgrammable,
934
1067
  transactionHooks,
935
1068
  blockHooks,
1069
+ stateServiceProvider,
936
1070
  verificationKeyService
937
1071
  );
938
1072
  }
@@ -950,17 +1084,27 @@ export class BlockProver
950
1084
 
951
1085
  public proveTransaction(
952
1086
  publicInput: BlockProverPublicInput,
953
- stateProof: StateTransitionProof,
954
- appProof: DynamicRuntimeProof,
955
- executionData: BlockProverExecutionData,
956
- verificationKeyAttestation: RuntimeVerificationKeyAttestation
1087
+ runtimeProof: DynamicRuntimeProof,
1088
+ executionData: BlockProverSingleTransactionExecutionData
957
1089
  ): Promise<BlockProverPublicOutput> {
958
1090
  return this.zkProgrammable.proveTransaction(
959
1091
  publicInput,
960
- stateProof,
961
- appProof,
962
- executionData,
963
- verificationKeyAttestation
1092
+ runtimeProof,
1093
+ executionData
1094
+ );
1095
+ }
1096
+
1097
+ public proveTransactions(
1098
+ publicInput: BlockProverPublicInput,
1099
+ runtimeProof1: DynamicRuntimeProof,
1100
+ runtimeProof2: DynamicRuntimeProof,
1101
+ executionData: BlockProverMultiTransactionExecutionData
1102
+ ): Promise<BlockProverPublicOutput> {
1103
+ return this.zkProgrammable.proveTransactions(
1104
+ publicInput,
1105
+ runtimeProof1,
1106
+ runtimeProof2,
1107
+ executionData
964
1108
  );
965
1109
  }
966
1110
 
@@ -968,14 +1112,18 @@ export class BlockProver
968
1112
  publicInput: BlockProverPublicInput,
969
1113
  networkState: NetworkState,
970
1114
  blockWitness: BlockHashMerkleTreeWitness,
971
- // stateTransitionProof: StateTransitionProof,
1115
+ stateTransitionProof: StateTransitionProof,
1116
+ deferSTs: Bool,
1117
+ afterBlockRootWitness: WitnessedRootWitness,
972
1118
  transactionProof: BlockProverProof
973
1119
  ): Promise<BlockProverPublicOutput> {
974
1120
  return this.zkProgrammable.proveBlock(
975
1121
  publicInput,
976
1122
  networkState,
977
1123
  blockWitness,
978
- // stateTransitionProof,
1124
+ stateTransitionProof,
1125
+ deferSTs,
1126
+ afterBlockRootWitness,
979
1127
  transactionProof
980
1128
  );
981
1129
  }