@proto-kit/protocol 0.1.1-develop.191 → 0.1.1-develop.239

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 (97) hide show
  1. package/dist/blockmodules/AccountStateModule.d.ts +38 -0
  2. package/dist/blockmodules/AccountStateModule.d.ts.map +1 -0
  3. package/dist/blockmodules/AccountStateModule.js +38 -0
  4. package/dist/blockmodules/NoopTransactionHook.d.ts +6 -0
  5. package/dist/blockmodules/NoopTransactionHook.d.ts.map +1 -0
  6. package/dist/blockmodules/NoopTransactionHook.js +5 -0
  7. package/dist/index.d.ts +12 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +12 -0
  10. package/dist/model/Option.d.ts +8 -8
  11. package/dist/model/Option.d.ts.map +1 -1
  12. package/dist/model/Option.js +7 -15
  13. package/dist/model/StateTransition.d.ts.map +1 -1
  14. package/dist/model/StateTransitionProvableBatch.d.ts +59 -1
  15. package/dist/model/StateTransitionProvableBatch.d.ts.map +1 -1
  16. package/dist/model/StateTransitionProvableBatch.js +58 -4
  17. package/dist/protocol/Protocol.d.ts +21 -6
  18. package/dist/protocol/Protocol.d.ts.map +1 -1
  19. package/dist/protocol/Protocol.js +44 -1
  20. package/dist/protocol/ProtocolModule.d.ts +2 -3
  21. package/dist/protocol/ProtocolModule.d.ts.map +1 -1
  22. package/dist/protocol/ProtocolModule.js +1 -3
  23. package/dist/protocol/ProvableTransactionHook.d.ts +6 -0
  24. package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -0
  25. package/dist/protocol/ProvableTransactionHook.js +3 -0
  26. package/dist/protocol/TransitioningProtocolModule.d.ts +5 -0
  27. package/dist/protocol/TransitioningProtocolModule.d.ts.map +1 -0
  28. package/dist/protocol/TransitioningProtocolModule.js +3 -0
  29. package/dist/prover/block/BlockProvable.d.ts +2 -2
  30. package/dist/prover/block/BlockProvable.d.ts.map +1 -1
  31. package/dist/prover/block/BlockProver.d.ts +25 -11
  32. package/dist/prover/block/BlockProver.d.ts.map +1 -1
  33. package/dist/prover/block/BlockProver.js +74 -17
  34. package/dist/prover/statetransition/StateTransitionProvable.d.ts +18 -2
  35. package/dist/prover/statetransition/StateTransitionProvable.d.ts.map +1 -1
  36. package/dist/prover/statetransition/StateTransitionProvable.js +2 -0
  37. package/dist/prover/statetransition/StateTransitionProver.d.ts +16 -6
  38. package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -1
  39. package/dist/prover/statetransition/StateTransitionProver.js +45 -13
  40. package/dist/state/State.d.ts +60 -0
  41. package/dist/state/State.d.ts.map +1 -0
  42. package/dist/state/State.js +116 -0
  43. package/dist/state/StateMap.d.ts +37 -0
  44. package/dist/state/StateMap.d.ts.map +1 -0
  45. package/dist/state/StateMap.js +56 -0
  46. package/dist/state/StateService.d.ts +6 -0
  47. package/dist/state/StateService.d.ts.map +1 -0
  48. package/dist/state/StateService.js +1 -0
  49. package/dist/state/StateServiceProvider.d.ts +10 -0
  50. package/dist/state/StateServiceProvider.d.ts.map +1 -0
  51. package/dist/state/StateServiceProvider.js +42 -0
  52. package/dist/state/assert/assert.d.ts +12 -0
  53. package/dist/state/assert/assert.d.ts.map +1 -0
  54. package/dist/state/assert/assert.js +23 -0
  55. package/dist/state/context/ProtocolMethodExecutionContext.d.ts +22 -0
  56. package/dist/state/context/ProtocolMethodExecutionContext.d.ts.map +1 -0
  57. package/dist/state/context/ProtocolMethodExecutionContext.js +28 -0
  58. package/dist/state/context/RuntimeMethodExecutionContext.d.ts +60 -0
  59. package/dist/state/context/RuntimeMethodExecutionContext.d.ts.map +1 -0
  60. package/dist/state/context/RuntimeMethodExecutionContext.js +105 -0
  61. package/dist/state/context/TransitionMethodExecutionContext.d.ts +23 -0
  62. package/dist/state/context/TransitionMethodExecutionContext.d.ts.map +1 -0
  63. package/dist/state/context/TransitionMethodExecutionContext.js +6 -0
  64. package/dist/state/protocol/ProtocolState.d.ts +7 -0
  65. package/dist/state/protocol/ProtocolState.d.ts.map +1 -0
  66. package/dist/state/protocol/ProtocolState.js +42 -0
  67. package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts +26 -0
  68. package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts.map +1 -0
  69. package/dist/utils/merkletree/MemoryMerkleTreeStorage.js +79 -0
  70. package/package.json +5 -3
  71. package/src/blockmodules/AccountStateModule.ts +31 -0
  72. package/src/blockmodules/NoopTransactionHook.ts +7 -0
  73. package/src/index.ts +12 -0
  74. package/src/model/Option.ts +18 -22
  75. package/src/model/StateTransition.ts +1 -1
  76. package/src/model/StateTransitionProvableBatch.ts +86 -5
  77. package/src/protocol/Protocol.ts +85 -23
  78. package/src/protocol/ProtocolModule.ts +1 -7
  79. package/src/protocol/ProvableTransactionHook.ts +7 -0
  80. package/src/protocol/TransitioningProtocolModule.ts +5 -0
  81. package/src/prover/block/BlockProvable.ts +2 -2
  82. package/src/prover/block/BlockProver.ts +139 -21
  83. package/src/prover/statetransition/StateTransitionProvable.ts +4 -2
  84. package/src/prover/statetransition/StateTransitionProver.ts +93 -13
  85. package/src/state/State.ts +160 -0
  86. package/src/state/StateMap.ts +74 -0
  87. package/src/state/StateService.ts +6 -0
  88. package/src/state/StateServiceProvider.ts +37 -0
  89. package/src/state/assert/assert.test.ts +49 -0
  90. package/src/state/assert/assert.ts +28 -0
  91. package/src/state/context/ProtocolMethodExecutionContext.ts +36 -0
  92. package/src/state/context/RuntimeMethodExecutionContext.ts +124 -0
  93. package/src/state/context/TransitionMethodExecutionContext.ts +27 -0
  94. package/src/state/protocol/ProtocolState.ts +63 -0
  95. package/test/BlockProver.test.ts +139 -36
  96. package/test/Protocol.test.ts +22 -5
  97. package/test/StateTransition.test.ts +1 -1
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable max-lines */
2
2
  import { Experimental, Field, type Proof, Provable, SelfProof } from "snarkyjs";
3
- import { inject, injectable } from "tsyringe";
3
+ import { container, inject, injectable, injectAll } from "tsyringe";
4
4
  import {
5
+ AreProofsEnabled,
5
6
  PlainZkProgram,
6
7
  provableMethod,
7
8
  WithZkProgrammable,
@@ -25,6 +26,10 @@ import {
25
26
  BlockProverPublicInput,
26
27
  BlockProverPublicOutput,
27
28
  } from "./BlockProvable";
29
+ import { ProvableStateTransition } from "../../model/StateTransition";
30
+ import { ProvableTransactionHook } from "../../protocol/ProvableTransactionHook";
31
+ import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethodExecutionContext";
32
+ import { Protocol, ProtocolModulesRecord } from "../../protocol/Protocol";
28
33
 
29
34
  const errors = {
30
35
  stateProofNotStartingAtZero: () =>
@@ -58,28 +63,27 @@ export interface BlockProverState {
58
63
  networkStateHash: Field;
59
64
  }
60
65
 
61
- /**
62
- * BlockProver class, which aggregates a AppChainProof and
63
- * a StateTransitionProof into a single BlockProof, that can
64
- * then be merged to be committed to the base-layer contract
65
- */
66
- @injectable()
67
- export class BlockProver
68
- extends ProtocolModule<BlockProverPublicInput, BlockProverPublicOutput>
69
- implements BlockProvable
70
- {
66
+ export class BlockProverProgrammable extends ZkProgrammable<
67
+ BlockProverPublicInput,
68
+ BlockProverPublicOutput
69
+ > {
71
70
  public constructor(
72
- @inject("StateTransitionProver")
73
- private readonly stateTransitionProver: ZkProgrammable<
71
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
72
+ private readonly prover: BlockProver,
73
+ public readonly stateTransitionProver: ZkProgrammable<
74
74
  StateTransitionProverPublicInput,
75
75
  StateTransitionProverPublicOutput
76
76
  >,
77
- @inject("Runtime")
78
- private readonly runtime: WithZkProgrammable<void, MethodPublicOutput>
77
+ public readonly runtime: ZkProgrammable<undefined, MethodPublicOutput>,
78
+ private readonly blockModules: ProvableTransactionHook[]
79
79
  ) {
80
80
  super();
81
81
  }
82
82
 
83
+ public get appChain(): AreProofsEnabled | undefined {
84
+ return this.prover.appChain;
85
+ }
86
+
83
87
  /**
84
88
  * Applies and checks the two proofs and applies the corresponding state
85
89
  * changes to the given state
@@ -87,6 +91,7 @@ export class BlockProver
87
91
  * @param state The from-state of the BlockProver
88
92
  * @param stateTransitionProof
89
93
  * @param appProof
94
+ * @param executionData
90
95
  * @returns The new BlockProver-state to be used as public output
91
96
  */
92
97
  public applyTransaction(
@@ -96,8 +101,10 @@ export class BlockProver
96
101
  StateTransitionProverPublicOutput
97
102
  >,
98
103
  appProof: Proof<void, MethodPublicOutput>,
99
- { transaction, networkState }: BlockProverExecutionData
104
+ executionData: BlockProverExecutionData
100
105
  ): BlockProverState {
106
+ const { transaction, networkState } = executionData;
107
+
101
108
  appProof.verify();
102
109
  stateTransitionProof.verify();
103
110
 
@@ -128,6 +135,9 @@ export class BlockProver
128
135
  stateTransitionProof.publicInput.stateRoot
129
136
  );
130
137
 
138
+ // Apply protocol state transitions
139
+ this.assertProtocolTransitions(stateTransitionProof, executionData);
140
+
131
141
  // Check transaction signature
132
142
  transaction
133
143
  .validateSignature()
@@ -169,6 +179,61 @@ export class BlockProver
169
179
  return stateTo;
170
180
  }
171
181
 
182
+ // eslint-disable-next-line no-warning-comments, max-len
183
+ // TODO How does this interact with the RuntimeMethodExecutionContext when executing runtimemethods?
184
+
185
+ public assertProtocolTransitions(
186
+ stateTransitionProof: Proof<
187
+ StateTransitionProverPublicInput,
188
+ StateTransitionProverPublicOutput
189
+ >,
190
+ executionData: BlockProverExecutionData
191
+ ) {
192
+ const executionContext = container.resolve(RuntimeMethodExecutionContext);
193
+ executionContext.clear();
194
+
195
+ // Setup context for potential calls to runtime methods.
196
+ // This way they can use this.transaction etc. while still having provable
197
+ // integrity between data
198
+ executionContext.setup({
199
+ transaction: RuntimeTransaction.fromProtocolTransaction(
200
+ executionData.transaction
201
+ ),
202
+
203
+ networkState: executionData.networkState,
204
+ });
205
+ executionContext.beforeMethod("", "", []);
206
+
207
+ this.blockModules.forEach((module) => {
208
+ module.onTransaction(executionData);
209
+ });
210
+
211
+ executionContext.afterMethod();
212
+
213
+ const { stateTransitions, status, statusMessage } =
214
+ executionContext.current().result;
215
+
216
+ status.assertTrue(statusMessage);
217
+
218
+ const transitions = stateTransitions.map((transition) =>
219
+ transition.toProvable()
220
+ );
221
+
222
+ const hashList = new DefaultProvableHashList(
223
+ ProvableStateTransition,
224
+ stateTransitionProof.publicInput.protocolTransitionsHash
225
+ );
226
+
227
+ transitions.forEach((transition) => {
228
+ hashList.push(transition);
229
+ });
230
+
231
+ stateTransitionProof.publicOutput.protocolTransitionsHash.assertEquals(
232
+ hashList.commitment,
233
+ "ProtocolTransitionsHash not matching the generated protocol transitions"
234
+ );
235
+ }
236
+
172
237
  @provableMethod()
173
238
  public proveTransaction(
174
239
  publicInput: BlockProverPublicInput,
@@ -239,12 +304,12 @@ export class BlockProver
239
304
  BlockProverPublicInput,
240
305
  BlockProverPublicOutput
241
306
  > {
242
- const StateTransitionProofClass =
243
- this.stateTransitionProver.zkProgram.Proof;
244
- const RuntimeProofClass = this.runtime.zkProgrammable.zkProgram.Proof;
307
+ const { prover, stateTransitionProver, runtime } = this;
308
+ const StateTransitionProofClass = stateTransitionProver.zkProgram.Proof;
309
+ const RuntimeProofClass = runtime.zkProgram.Proof;
245
310
 
246
- const proveTransaction = this.proveTransaction.bind(this);
247
- const merge = this.merge.bind(this);
311
+ const proveTransaction = prover.proveTransaction.bind(prover);
312
+ const merge = prover.merge.bind(prover);
248
313
 
249
314
  const program = Experimental.ZkProgram({
250
315
  publicInput: BlockProverPublicInput,
@@ -305,3 +370,56 @@ export class BlockProver
305
370
  };
306
371
  }
307
372
  }
373
+
374
+ /**
375
+ * BlockProver class, which aggregates a AppChainProof and
376
+ * a StateTransitionProof into a single BlockProof, that can
377
+ * then be merged to be committed to the base-layer contract
378
+ */
379
+ @injectable()
380
+ export class BlockProver extends ProtocolModule implements BlockProvable {
381
+ public zkProgrammable: BlockProverProgrammable;
382
+
383
+ public constructor(
384
+ @inject("StateTransitionProver")
385
+ public readonly stateTransitionProver: WithZkProgrammable<
386
+ StateTransitionProverPublicInput,
387
+ StateTransitionProverPublicOutput
388
+ >,
389
+ @inject("Runtime")
390
+ public readonly runtime: WithZkProgrammable<undefined, MethodPublicOutput>,
391
+ @injectAll("ProvableTransactionHook")
392
+ transactionHooks: ProvableTransactionHook[]
393
+ ) {
394
+ super();
395
+ this.zkProgrammable = new BlockProverProgrammable(
396
+ this,
397
+ stateTransitionProver.zkProgrammable,
398
+ runtime.zkProgrammable,
399
+ transactionHooks
400
+ // protocol.dependencyContainer.resolveAll("P rovableTransactionHook")
401
+ );
402
+ }
403
+
404
+ public merge(
405
+ publicInput: BlockProverPublicInput,
406
+ proof1: BlockProverProof,
407
+ proof2: BlockProverProof
408
+ ): BlockProverPublicOutput {
409
+ return this.zkProgrammable.merge(publicInput, proof1, proof2);
410
+ }
411
+
412
+ public proveTransaction(
413
+ publicInput: BlockProverPublicInput,
414
+ stateProof: StateTransitionProof,
415
+ appProof: Proof<void, MethodPublicOutput>,
416
+ executionData: BlockProverExecutionData
417
+ ): BlockProverPublicOutput {
418
+ return this.zkProgrammable.proveTransaction(
419
+ publicInput,
420
+ stateProof,
421
+ appProof,
422
+ executionData
423
+ );
424
+ }
425
+ }
@@ -1,5 +1,5 @@
1
1
  import { Field, Proof, Struct } from "snarkyjs";
2
- import { ZkProgrammable } from "@proto-kit/common";
2
+ import { WithZkProgrammable, ZkProgrammable } from "@proto-kit/common";
3
3
 
4
4
  import { StateTransitionProvableBatch } from "../../model/StateTransitionProvableBatch";
5
5
 
@@ -7,11 +7,13 @@ import { StateTransitionWitnessProviderReference } from "./StateTransitionWitnes
7
7
 
8
8
  export class StateTransitionProverPublicInput extends Struct({
9
9
  stateTransitionsHash: Field,
10
+ protocolTransitionsHash: Field,
10
11
  stateRoot: Field,
11
12
  }) {}
12
13
 
13
14
  export class StateTransitionProverPublicOutput extends Struct({
14
15
  stateTransitionsHash: Field,
16
+ protocolTransitionsHash: Field,
15
17
  stateRoot: Field,
16
18
  }) {}
17
19
 
@@ -21,7 +23,7 @@ export type StateTransitionProof = Proof<
21
23
  >;
22
24
 
23
25
  export interface StateTransitionProvable
24
- extends ZkProgrammable<
26
+ extends WithZkProgrammable<
25
27
  StateTransitionProverPublicInput,
26
28
  StateTransitionProverPublicOutput
27
29
  > {
@@ -1,6 +1,12 @@
1
+ /* eslint-disable max-lines */
1
2
  import { Experimental, Field, Provable, SelfProof } from "snarkyjs";
2
3
  import { injectable } from "tsyringe";
3
- import { PlainZkProgram, provableMethod } from "@proto-kit/common";
4
+ import {
5
+ AreProofsEnabled,
6
+ PlainZkProgram,
7
+ provableMethod,
8
+ ZkProgrammable,
9
+ } from "@proto-kit/common";
4
10
 
5
11
  import {
6
12
  MerkleTreeUtils,
@@ -11,7 +17,10 @@ import {
11
17
  ProvableHashList,
12
18
  } from "../../utils/ProvableHashList";
13
19
  import { ProvableStateTransition } from "../../model/StateTransition";
14
- import { StateTransitionProvableBatch } from "../../model/StateTransitionProvableBatch";
20
+ import {
21
+ ProvableStateTransitionType,
22
+ StateTransitionProvableBatch,
23
+ } from "../../model/StateTransitionProvableBatch";
15
24
  import { constants } from "../../Constants";
16
25
  import { ProtocolModule } from "../../protocol/ProtocolModule";
17
26
 
@@ -30,6 +39,9 @@ const errors = {
30
39
  stateTransitionsHashNotMatching: (step: string) =>
31
40
  `State transitions hash not matching ${step}`,
32
41
 
42
+ protocolTransitionsHashNotMatching: (step: string) =>
43
+ `Protocol transitions hash not matching ${step}`,
44
+
33
45
  merkleWitnessNotCorrect: (index: number) =>
34
46
  `MerkleWitness not valid for StateTransition (${index})`,
35
47
 
@@ -44,6 +56,7 @@ const errors = {
44
56
  interface StateTransitionProverExecutionState {
45
57
  stateRoot: Field;
46
58
  stateTransitionList: ProvableHashList<ProvableStateTransition>;
59
+ protocolTransitionList: ProvableHashList<ProvableStateTransition>;
47
60
  }
48
61
 
49
62
  const StateTransitionSelfProofClass = SelfProof<
@@ -55,21 +68,22 @@ const StateTransitionSelfProofClass = SelfProof<
55
68
  * StateTransitionProver is the prover that proves the application of some state
56
69
  * transitions and checks and updates their merkle-tree entries
57
70
  */
58
- @injectable()
59
- export class StateTransitionProver
60
- extends ProtocolModule<
61
- StateTransitionProverPublicInput,
62
- StateTransitionProverPublicOutput
63
- >
64
- implements StateTransitionProvable
65
- {
71
+ export class StateTransitionProverProgrammable extends ZkProgrammable<
72
+ StateTransitionProverPublicInput,
73
+ StateTransitionProverPublicOutput
74
+ > {
66
75
  public constructor(
67
- // Injected
76
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
77
+ private readonly stateTransitionProver: StateTransitionProver,
68
78
  public readonly witnessProviderReference: StateTransitionWitnessProviderReference
69
79
  ) {
70
80
  super();
71
81
  }
72
82
 
83
+ public get appChain(): AreProofsEnabled | undefined {
84
+ return this.stateTransitionProver.appChain;
85
+ }
86
+
73
87
  public zkProgramFactory(): PlainZkProgram<
74
88
  StateTransitionProverPublicInput,
75
89
  StateTransitionProverPublicOutput
@@ -141,6 +155,7 @@ export class StateTransitionProver
141
155
  public applyTransitions(
142
156
  stateRoot: Field,
143
157
  stateTransitionCommitmentFrom: Field,
158
+ protocolTransitionCommitmentFrom: Field,
144
159
  transitionBatch: StateTransitionProvableBatch
145
160
  ): StateTransitionProverExecutionState {
146
161
  const state: StateTransitionProverExecutionState = {
@@ -150,15 +165,21 @@ export class StateTransitionProver
150
165
  ProvableStateTransition,
151
166
  stateTransitionCommitmentFrom
152
167
  ),
168
+
169
+ protocolTransitionList: new DefaultProvableHashList(
170
+ ProvableStateTransition,
171
+ protocolTransitionCommitmentFrom
172
+ ),
153
173
  };
154
174
 
155
175
  const transitions = transitionBatch.batch;
176
+ const types = transitionBatch.transitionTypes;
156
177
  for (
157
178
  let index = 0;
158
179
  index < constants.stateTransitionProverBatchSize;
159
180
  index++
160
181
  ) {
161
- this.applyTransition(state, transitions[index], index);
182
+ this.applyTransition(state, transitions[index], types[index], index);
162
183
  }
163
184
 
164
185
  return state;
@@ -171,6 +192,7 @@ export class StateTransitionProver
171
192
  public applyTransition(
172
193
  state: StateTransitionProverExecutionState,
173
194
  transition: ProvableStateTransition,
195
+ type: ProvableStateTransitionType,
174
196
  index = 0
175
197
  ) {
176
198
  const treeWitness = Provable.witness(RollupMerkleWitness, () =>
@@ -187,19 +209,28 @@ export class StateTransitionProver
187
209
  .or(transition.from.isSome.not())
188
210
  .assertTrue(errors.merkleWitnessNotCorrect(index));
189
211
 
212
+ const t = Date.now();
190
213
  const newRoot = MerkleTreeUtils.computeRoot(
191
214
  treeWitness,
192
215
  transition.to.value
193
216
  );
217
+ Provable.log("Compute root took", Date.now() - t, "ms");
218
+
194
219
  state.stateRoot = Provable.if(
195
220
  transition.to.isSome,
196
221
  newRoot,
197
222
  state.stateRoot
198
223
  );
199
224
 
225
+ const isNotDummy = transition.path.equals(Field(0)).not();
226
+
200
227
  state.stateTransitionList.pushIf(
201
228
  transition,
202
- transition.path.equals(Field(0)).not()
229
+ isNotDummy.and(type.isNormal())
230
+ );
231
+ state.protocolTransitionList.pushIf(
232
+ transition,
233
+ isNotDummy.and(type.isProtocol())
203
234
  );
204
235
  }
205
236
 
@@ -214,12 +245,14 @@ export class StateTransitionProver
214
245
  const result = this.applyTransitions(
215
246
  publicInput.stateRoot,
216
247
  publicInput.stateTransitionsHash,
248
+ publicInput.protocolTransitionsHash,
217
249
  batch
218
250
  );
219
251
 
220
252
  return new StateTransitionProverPublicOutput({
221
253
  stateRoot: result.stateRoot,
222
254
  stateTransitionsHash: result.stateTransitionList.commitment,
255
+ protocolTransitionsHash: result.protocolTransitionList.commitment,
223
256
  });
224
257
  }
225
258
 
@@ -252,9 +285,56 @@ export class StateTransitionProver
252
285
  errors.stateTransitionsHashNotMatching("proof1.to -> proof2.from")
253
286
  );
254
287
 
288
+ // Check Protocol ST list
289
+ publicInput.protocolTransitionsHash.assertEquals(
290
+ proof1.publicInput.protocolTransitionsHash,
291
+ errors.protocolTransitionsHashNotMatching(
292
+ "publicInput.from -> proof1.from"
293
+ )
294
+ );
295
+ proof1.publicOutput.protocolTransitionsHash.assertEquals(
296
+ proof2.publicInput.protocolTransitionsHash,
297
+ errors.protocolTransitionsHashNotMatching("proof1.to -> proof2.from")
298
+ );
299
+
255
300
  return new StateTransitionProverPublicInput({
256
301
  stateRoot: proof2.publicOutput.stateRoot,
257
302
  stateTransitionsHash: proof2.publicOutput.stateTransitionsHash,
303
+ protocolTransitionsHash: proof2.publicOutput.protocolTransitionsHash,
258
304
  });
259
305
  }
260
306
  }
307
+
308
+ @injectable()
309
+ export class StateTransitionProver
310
+ extends ProtocolModule
311
+ implements StateTransitionProvable
312
+ {
313
+ public readonly zkProgrammable: StateTransitionProverProgrammable;
314
+
315
+ public constructor(
316
+ // Injected
317
+ public readonly witnessProviderReference: StateTransitionWitnessProviderReference
318
+ ) {
319
+ super();
320
+ this.zkProgrammable = new StateTransitionProverProgrammable(
321
+ this,
322
+ witnessProviderReference
323
+ );
324
+ }
325
+
326
+ public runBatch(
327
+ publicInput: StateTransitionProverPublicInput,
328
+ batch: StateTransitionProvableBatch
329
+ ): StateTransitionProverPublicOutput {
330
+ return this.zkProgrammable.runBatch(publicInput, batch);
331
+ }
332
+
333
+ public merge(
334
+ publicInput: StateTransitionProverPublicInput,
335
+ proof1: StateTransitionProof,
336
+ proof2: StateTransitionProof
337
+ ): StateTransitionProverPublicOutput {
338
+ return this.zkProgrammable.merge(publicInput, proof1, proof2);
339
+ }
340
+ }
@@ -0,0 +1,160 @@
1
+ import { Mixin } from "ts-mixer";
2
+ import { Bool, Field, Provable, type FlexibleProvablePure } from "snarkyjs";
3
+ import { container } from "tsyringe";
4
+ import { dummyValue } from "@proto-kit/common";
5
+
6
+ import { Path } from "../model/Path";
7
+ import { Option } from "../model/Option";
8
+ import { StateTransition } from "../model/StateTransition";
9
+
10
+ import { StateServiceProvider } from "./StateServiceProvider";
11
+ import { RuntimeMethodExecutionContext } from "./context/RuntimeMethodExecutionContext";
12
+
13
+ export class WithPath {
14
+ public path?: Field;
15
+
16
+ public hasPathOrFail(): asserts this is { path: Path } {
17
+ if (!this.path) {
18
+ throw new Error(
19
+ "Could not find 'path', did you forget to add '@state' to your state property?"
20
+ );
21
+ }
22
+ }
23
+ }
24
+
25
+ export class WithStateServiceProvider {
26
+ public stateServiceProvider?: StateServiceProvider;
27
+
28
+ public hasStateServiceOrFail(): asserts this is {
29
+ stateServiceProvider: StateServiceProvider;
30
+ } {
31
+ if (!this.stateServiceProvider) {
32
+ throw new Error(
33
+ "Could not find 'stateServiceProvider', did you forget to add '@state' to your state property?"
34
+ );
35
+ }
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Utilities for runtime module state, such as get/set
41
+ */
42
+ export class State<Value> extends Mixin(WithPath, WithStateServiceProvider) {
43
+ /**
44
+ * Creates a new state wrapper for the provided value type.
45
+ *
46
+ * @param valueType - Type of value to be stored (e.g. UInt64, Struct, ...)
47
+ * @returns New state for the given value type.
48
+ */
49
+ public static from<Value>(valueType: FlexibleProvablePure<Value>) {
50
+ return new State<Value>(valueType);
51
+ }
52
+
53
+ public constructor(public valueType: FlexibleProvablePure<Value>) {
54
+ super();
55
+ }
56
+
57
+ private getState(): { value: Value; isSome: Bool } {
58
+ this.hasStateServiceOrFail();
59
+ this.hasPathOrFail();
60
+
61
+ const { path, stateServiceProvider, valueType } = this;
62
+
63
+ const { stateTransitions } = container
64
+ .resolve(RuntimeMethodExecutionContext)
65
+ .current().result;
66
+
67
+ // First try to find a match inside already created stateTransitions
68
+ const previousMutatingTransitions = stateTransitions.filter((transition) =>
69
+ transition.path.equals(path).and(transition.to.isSome).toBoolean()
70
+ );
71
+ const pmtLength = previousMutatingTransitions.length;
72
+
73
+ let value =
74
+ pmtLength > 0
75
+ ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
76
+ (previousMutatingTransitions[pmtLength - 1].to.value as Value)
77
+ : undefined;
78
+
79
+ if (value !== undefined) {
80
+ return { value, isSome: Bool(true) };
81
+ }
82
+
83
+ // If the value is still undefined, look it up in the stateService
84
+ const fields = stateServiceProvider.stateService.get(path);
85
+ if (fields) {
86
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
87
+ value = valueType.fromFields(fields) as Value;
88
+ }
89
+
90
+ if (value !== undefined) {
91
+ return { value, isSome: Bool(true) };
92
+ }
93
+ return { value: dummyValue(valueType), isSome: Bool(false) };
94
+ }
95
+
96
+ /**
97
+ * Provides an in-circuit witness for the current state representation,
98
+ * and constructs an Option out of it.
99
+ *
100
+ * @returns Optional value of the current state
101
+ */
102
+ private witnessState() {
103
+ // get the value from storage, or return a dummy value instead
104
+ const value = Provable.witness(this.valueType, () => this.getState().value);
105
+
106
+ // check if the value exists in the storage or not
107
+ const isSome = Provable.witness(Bool, () => this.getState().isSome);
108
+
109
+ return Option.from(isSome, value, this.valueType);
110
+ }
111
+
112
+ /**
113
+ * Retrieves the current state and creates a state transition
114
+ * anchoring the use of the current state value in the circuit.
115
+ *
116
+ * @returns Option representation of the current state.
117
+ */
118
+ public get(): Option<Value> {
119
+ const option = this.witnessState();
120
+
121
+ this.hasPathOrFail();
122
+
123
+ const stateTransition = StateTransition.from(this.path, option);
124
+
125
+ container
126
+ .resolve(RuntimeMethodExecutionContext)
127
+ .addStateTransition(stateTransition);
128
+
129
+ return option;
130
+ }
131
+
132
+ /**
133
+ * Sets a new state value by creating a state transition from
134
+ * the current value to the newly set value.
135
+ *
136
+ * The newly set value isn't available via state.get(), since the
137
+ * state transitions are not applied within the same circuit.
138
+ * You can however store and access your new value in
139
+ * a separate circuit variable.
140
+ *
141
+ * @param value - Value to be set as the current state
142
+ */
143
+ public set(value: Value) {
144
+ // link the transition to the current state
145
+ const fromOption = this.witnessState();
146
+ const toOption = Option.from(Bool(true), value, this.valueType);
147
+
148
+ this.hasPathOrFail();
149
+
150
+ const stateTransition = StateTransition.fromTo(
151
+ this.path,
152
+ fromOption,
153
+ toOption
154
+ );
155
+
156
+ container
157
+ .resolve(RuntimeMethodExecutionContext)
158
+ .addStateTransition(stateTransition);
159
+ }
160
+ }
@@ -0,0 +1,74 @@
1
+ import type { Field, FlexibleProvablePure } from "snarkyjs";
2
+ import { Mixin } from "ts-mixer";
3
+
4
+ import { Path } from "../model/Path";
5
+ import { Option } from "../model/Option";
6
+
7
+ import { State, WithStateServiceProvider, WithPath } from "./State";
8
+
9
+ /**
10
+ * Map-like wrapper for state
11
+ */
12
+ // eslint-disable-next-line new-cap
13
+ export class StateMap<KeyType, ValueType> extends Mixin(
14
+ WithPath,
15
+ WithStateServiceProvider
16
+ ) {
17
+ /**
18
+ * Create a new state map with the given key and value types
19
+ *
20
+ * @param keyType - Type to be used as a key
21
+ * @param valueType - Type to be stored as a value
22
+ * @returns State map with provided key and value types.
23
+ */
24
+ public static from<KeyType, ValueType>(
25
+ keyType: FlexibleProvablePure<KeyType>,
26
+ valueType: FlexibleProvablePure<ValueType>
27
+ ): StateMap<KeyType, ValueType> {
28
+ return new StateMap<KeyType, ValueType>(keyType, valueType);
29
+ }
30
+
31
+ public constructor(
32
+ public keyType: FlexibleProvablePure<KeyType>,
33
+ public valueType: FlexibleProvablePure<ValueType>
34
+ ) {
35
+ super();
36
+ }
37
+
38
+ public getPath(key: KeyType): Field {
39
+ this.hasPathOrFail();
40
+ return Path.fromKey(this.path, this.keyType, key);
41
+ }
42
+
43
+ /**
44
+ * Obtains a value for the provided key in the current state map.
45
+ *
46
+ * @param key - Key to obtain the state for
47
+ * @returns Value for the provided key.
48
+ */
49
+ public get(key: KeyType): Option<ValueType> {
50
+ const state = State.from(this.valueType);
51
+ this.hasPathOrFail();
52
+ this.hasStateServiceOrFail();
53
+
54
+ state.path = this.getPath(key);
55
+ state.stateServiceProvider = this.stateServiceProvider;
56
+ return state.get();
57
+ }
58
+
59
+ /**
60
+ * Sets a value for the given key in the current state map.
61
+ *
62
+ * @param key - Key to store the value under
63
+ * @param value - Value to be stored under the given key
64
+ */
65
+ public set(key: KeyType, value: ValueType): void {
66
+ const state = State.from(this.valueType);
67
+ this.hasPathOrFail();
68
+ this.hasStateServiceOrFail();
69
+
70
+ state.path = Path.fromKey(this.path, this.keyType, key);
71
+ state.stateServiceProvider = this.stateServiceProvider;
72
+ state.set(value);
73
+ }
74
+ }