@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.
- package/dist/blockmodules/AccountStateModule.d.ts +38 -0
- package/dist/blockmodules/AccountStateModule.d.ts.map +1 -0
- package/dist/blockmodules/AccountStateModule.js +38 -0
- package/dist/blockmodules/NoopTransactionHook.d.ts +6 -0
- package/dist/blockmodules/NoopTransactionHook.d.ts.map +1 -0
- package/dist/blockmodules/NoopTransactionHook.js +5 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/model/Option.d.ts +8 -8
- package/dist/model/Option.d.ts.map +1 -1
- package/dist/model/Option.js +7 -15
- package/dist/model/StateTransition.d.ts.map +1 -1
- package/dist/model/StateTransitionProvableBatch.d.ts +59 -1
- package/dist/model/StateTransitionProvableBatch.d.ts.map +1 -1
- package/dist/model/StateTransitionProvableBatch.js +58 -4
- package/dist/protocol/Protocol.d.ts +21 -6
- package/dist/protocol/Protocol.d.ts.map +1 -1
- package/dist/protocol/Protocol.js +44 -1
- package/dist/protocol/ProtocolModule.d.ts +2 -3
- package/dist/protocol/ProtocolModule.d.ts.map +1 -1
- package/dist/protocol/ProtocolModule.js +1 -3
- package/dist/protocol/ProvableTransactionHook.d.ts +6 -0
- package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -0
- package/dist/protocol/ProvableTransactionHook.js +3 -0
- package/dist/protocol/TransitioningProtocolModule.d.ts +5 -0
- package/dist/protocol/TransitioningProtocolModule.d.ts.map +1 -0
- package/dist/protocol/TransitioningProtocolModule.js +3 -0
- package/dist/prover/block/BlockProvable.d.ts +2 -2
- package/dist/prover/block/BlockProvable.d.ts.map +1 -1
- package/dist/prover/block/BlockProver.d.ts +25 -11
- package/dist/prover/block/BlockProver.d.ts.map +1 -1
- package/dist/prover/block/BlockProver.js +74 -17
- package/dist/prover/statetransition/StateTransitionProvable.d.ts +18 -2
- package/dist/prover/statetransition/StateTransitionProvable.d.ts.map +1 -1
- package/dist/prover/statetransition/StateTransitionProvable.js +2 -0
- package/dist/prover/statetransition/StateTransitionProver.d.ts +16 -6
- package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -1
- package/dist/prover/statetransition/StateTransitionProver.js +45 -13
- package/dist/state/State.d.ts +60 -0
- package/dist/state/State.d.ts.map +1 -0
- package/dist/state/State.js +116 -0
- package/dist/state/StateMap.d.ts +37 -0
- package/dist/state/StateMap.d.ts.map +1 -0
- package/dist/state/StateMap.js +56 -0
- package/dist/state/StateService.d.ts +6 -0
- package/dist/state/StateService.d.ts.map +1 -0
- package/dist/state/StateService.js +1 -0
- package/dist/state/StateServiceProvider.d.ts +10 -0
- package/dist/state/StateServiceProvider.d.ts.map +1 -0
- package/dist/state/StateServiceProvider.js +42 -0
- package/dist/state/assert/assert.d.ts +12 -0
- package/dist/state/assert/assert.d.ts.map +1 -0
- package/dist/state/assert/assert.js +23 -0
- package/dist/state/context/ProtocolMethodExecutionContext.d.ts +22 -0
- package/dist/state/context/ProtocolMethodExecutionContext.d.ts.map +1 -0
- package/dist/state/context/ProtocolMethodExecutionContext.js +28 -0
- package/dist/state/context/RuntimeMethodExecutionContext.d.ts +60 -0
- package/dist/state/context/RuntimeMethodExecutionContext.d.ts.map +1 -0
- package/dist/state/context/RuntimeMethodExecutionContext.js +105 -0
- package/dist/state/context/TransitionMethodExecutionContext.d.ts +23 -0
- package/dist/state/context/TransitionMethodExecutionContext.d.ts.map +1 -0
- package/dist/state/context/TransitionMethodExecutionContext.js +6 -0
- package/dist/state/protocol/ProtocolState.d.ts +7 -0
- package/dist/state/protocol/ProtocolState.d.ts.map +1 -0
- package/dist/state/protocol/ProtocolState.js +42 -0
- package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts +26 -0
- package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts.map +1 -0
- package/dist/utils/merkletree/MemoryMerkleTreeStorage.js +79 -0
- package/package.json +5 -3
- package/src/blockmodules/AccountStateModule.ts +31 -0
- package/src/blockmodules/NoopTransactionHook.ts +7 -0
- package/src/index.ts +12 -0
- package/src/model/Option.ts +18 -22
- package/src/model/StateTransition.ts +1 -1
- package/src/model/StateTransitionProvableBatch.ts +86 -5
- package/src/protocol/Protocol.ts +85 -23
- package/src/protocol/ProtocolModule.ts +1 -7
- package/src/protocol/ProvableTransactionHook.ts +7 -0
- package/src/protocol/TransitioningProtocolModule.ts +5 -0
- package/src/prover/block/BlockProvable.ts +2 -2
- package/src/prover/block/BlockProver.ts +139 -21
- package/src/prover/statetransition/StateTransitionProvable.ts +4 -2
- package/src/prover/statetransition/StateTransitionProver.ts +93 -13
- package/src/state/State.ts +160 -0
- package/src/state/StateMap.ts +74 -0
- package/src/state/StateService.ts +6 -0
- package/src/state/StateServiceProvider.ts +37 -0
- package/src/state/assert/assert.test.ts +49 -0
- package/src/state/assert/assert.ts +28 -0
- package/src/state/context/ProtocolMethodExecutionContext.ts +36 -0
- package/src/state/context/RuntimeMethodExecutionContext.ts +124 -0
- package/src/state/context/TransitionMethodExecutionContext.ts +27 -0
- package/src/state/protocol/ProtocolState.ts +63 -0
- package/test/BlockProver.test.ts +139 -36
- package/test/Protocol.test.ts +22 -5
- 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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
@
|
|
73
|
-
private readonly
|
|
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
|
-
|
|
78
|
-
private readonly
|
|
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
|
-
|
|
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
|
|
243
|
-
|
|
244
|
-
const RuntimeProofClass =
|
|
307
|
+
const { prover, stateTransitionProver, runtime } = this;
|
|
308
|
+
const StateTransitionProofClass = stateTransitionProver.zkProgram.Proof;
|
|
309
|
+
const RuntimeProofClass = runtime.zkProgram.Proof;
|
|
245
310
|
|
|
246
|
-
const proveTransaction =
|
|
247
|
-
const merge =
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
StateTransitionProverPublicOutput
|
|
63
|
-
>
|
|
64
|
-
implements StateTransitionProvable
|
|
65
|
-
{
|
|
71
|
+
export class StateTransitionProverProgrammable extends ZkProgrammable<
|
|
72
|
+
StateTransitionProverPublicInput,
|
|
73
|
+
StateTransitionProverPublicOutput
|
|
74
|
+
> {
|
|
66
75
|
public constructor(
|
|
67
|
-
//
|
|
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
|
-
|
|
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
|
+
}
|