@proto-kit/protocol 0.1.1-develop.153
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/LICENSE.md +201 -0
- package/README.md +45 -0
- package/dist/Constants.d.ts +4 -0
- package/dist/Constants.d.ts.map +1 -0
- package/dist/Constants.js +3 -0
- package/dist/config/ConfigurableModule.d.ts +18 -0
- package/dist/config/ConfigurableModule.d.ts.map +1 -0
- package/dist/config/ConfigurableModule.js +20 -0
- package/dist/config/ConfigurationAggregator.d.ts +10 -0
- package/dist/config/ConfigurationAggregator.d.ts.map +1 -0
- package/dist/config/ConfigurationAggregator.js +35 -0
- package/dist/config/ConfigurationReceiver.d.ts +25 -0
- package/dist/config/ConfigurationReceiver.d.ts.map +1 -0
- package/dist/config/ConfigurationReceiver.js +36 -0
- package/dist/config/ModuleContainer.d.ts +44 -0
- package/dist/config/ModuleContainer.d.ts.map +1 -0
- package/dist/config/ModuleContainer.js +89 -0
- package/dist/config/types.d.ts +2 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/model/MethodPublicInput.d.ts +51 -0
- package/dist/model/MethodPublicInput.d.ts.map +1 -0
- package/dist/model/MethodPublicInput.js +11 -0
- package/dist/model/MethodPublicOutput.d.ts +59 -0
- package/dist/model/MethodPublicOutput.d.ts.map +1 -0
- package/dist/model/MethodPublicOutput.js +12 -0
- package/dist/model/Option.d.ts +94 -0
- package/dist/model/Option.d.ts.map +1 -0
- package/dist/model/Option.js +96 -0
- package/dist/model/Path.d.ts +31 -0
- package/dist/model/Path.d.ts.map +1 -0
- package/dist/model/Path.js +44 -0
- package/dist/model/StateTransition.d.ts +85 -0
- package/dist/model/StateTransition.d.ts.map +1 -0
- package/dist/model/StateTransition.js +58 -0
- package/dist/model/StateTransitionProvableBatch.d.ts +57 -0
- package/dist/model/StateTransitionProvableBatch.d.ts.map +1 -0
- package/dist/model/StateTransitionProvableBatch.js +21 -0
- package/dist/model/network/NetworkState.d.ts +64 -0
- package/dist/model/network/NetworkState.d.ts.map +1 -0
- package/dist/model/network/NetworkState.js +14 -0
- package/dist/model/transaction/ProtocolTransaction.d.ts +70 -0
- package/dist/model/transaction/ProtocolTransaction.d.ts.map +1 -0
- package/dist/model/transaction/ProtocolTransaction.js +18 -0
- package/dist/model/transaction/RuntimeTransaction.d.ts +55 -0
- package/dist/model/transaction/RuntimeTransaction.d.ts.map +1 -0
- package/dist/model/transaction/RuntimeTransaction.js +26 -0
- package/dist/protocol/Protocol.d.ts +37 -0
- package/dist/protocol/Protocol.d.ts.map +1 -0
- package/dist/protocol/Protocol.js +50 -0
- package/dist/protocol/ProtocolModule.d.ts +9 -0
- package/dist/protocol/ProtocolModule.d.ts.map +1 -0
- package/dist/protocol/ProtocolModule.js +10 -0
- package/dist/prover/block/BlockProvable.d.ts +149 -0
- package/dist/prover/block/BlockProvable.d.ts.map +1 -0
- package/dist/prover/block/BlockProvable.js +20 -0
- package/dist/prover/block/BlockProver.d.ts +48 -0
- package/dist/prover/block/BlockProver.d.ts.map +1 -0
- package/dist/prover/block/BlockProver.js +171 -0
- package/dist/prover/block/BlockScopedModule.d.ts +3 -0
- package/dist/prover/block/BlockScopedModule.d.ts.map +1 -0
- package/dist/prover/block/BlockScopedModule.js +6 -0
- package/dist/prover/statetransition/StateTransitionProvable.d.ts +84 -0
- package/dist/prover/statetransition/StateTransitionProvable.d.ts.map +1 -0
- package/dist/prover/statetransition/StateTransitionProvable.js +11 -0
- package/dist/prover/statetransition/StateTransitionProver.d.ts +39 -0
- package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -0
- package/dist/prover/statetransition/StateTransitionProver.js +157 -0
- package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts +16 -0
- package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts.map +1 -0
- package/dist/prover/statetransition/StateTransitionWitnessProvider.js +17 -0
- package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts +7 -0
- package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts.map +1 -0
- package/dist/prover/statetransition/StateTransitionWitnessProviderReference.js +20 -0
- package/dist/src/model/Option.d.ts +158 -0
- package/dist/src/model/Option.d.ts.map +1 -0
- package/dist/src/model/Option.js +53 -0
- package/dist/src/model/Path.d.ts +35 -0
- package/dist/src/model/Path.d.ts.map +1 -0
- package/dist/src/model/Path.js +51 -0
- package/dist/src/model/StateTransition.d.ts +201 -0
- package/dist/src/model/StateTransition.d.ts.map +1 -0
- package/dist/src/model/StateTransition.js +43 -0
- package/dist/src/utils/PrefixedHashList.d.ts +15 -0
- package/dist/src/utils/PrefixedHashList.d.ts.map +1 -0
- package/dist/src/utils/PrefixedHashList.js +28 -0
- package/dist/src/utils/ProvableHashList.d.ts +30 -0
- package/dist/src/utils/ProvableHashList.d.ts.map +1 -0
- package/dist/src/utils/ProvableHashList.js +43 -0
- package/dist/utils/PrefixedHashList.d.ts +14 -0
- package/dist/utils/PrefixedHashList.d.ts.map +1 -0
- package/dist/utils/PrefixedHashList.js +12 -0
- package/dist/utils/PrefixedProvableHashList.d.ts +8 -0
- package/dist/utils/PrefixedProvableHashList.d.ts.map +1 -0
- package/dist/utils/PrefixedProvableHashList.js +12 -0
- package/dist/utils/ProvableHashList.d.ts +27 -0
- package/dist/utils/ProvableHashList.d.ts.map +1 -0
- package/dist/utils/ProvableHashList.js +43 -0
- package/dist/utils/Utils.d.ts +17 -0
- package/dist/utils/Utils.d.ts.map +1 -0
- package/dist/utils/Utils.js +63 -0
- package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts +25 -0
- package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts.map +1 -0
- package/dist/utils/merkletree/InMemoryMerkleTreeStorage.js +72 -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/dist/utils/merkletree/MerkleTreeStore.d.ts +11 -0
- package/dist/utils/merkletree/MerkleTreeStore.d.ts.map +1 -0
- package/dist/utils/merkletree/MerkleTreeStore.js +1 -0
- package/dist/utils/merkletree/RollupMerkleTree.d.ts +130 -0
- package/dist/utils/merkletree/RollupMerkleTree.d.ts.map +1 -0
- package/dist/utils/merkletree/RollupMerkleTree.js +244 -0
- package/jest.config.cjs +1 -0
- package/package.json +35 -0
- package/src/Constants.ts +3 -0
- package/src/index.ts +23 -0
- package/src/model/MethodPublicOutput.ts +12 -0
- package/src/model/Option.test.ts +21 -0
- package/src/model/Option.ts +133 -0
- package/src/model/Path.ts +52 -0
- package/src/model/StateTransition.ts +72 -0
- package/src/model/StateTransitionProvableBatch.ts +31 -0
- package/src/model/Transaction.ts +29 -0
- package/src/model/network/NetworkState.ts +15 -0
- package/src/model/transaction/ProtocolTransaction.ts +25 -0
- package/src/model/transaction/RuntimeTransaction.ts +34 -0
- package/src/protocol/Protocol.ts +129 -0
- package/src/protocol/ProtocolModule.ts +27 -0
- package/src/prover/block/BlockProvable.ts +45 -0
- package/src/prover/block/BlockProver.ts +302 -0
- package/src/prover/statetransition/StateTransitionProvable.ts +40 -0
- package/src/prover/statetransition/StateTransitionProver.ts +270 -0
- package/src/prover/statetransition/StateTransitionWitnessProvider.ts +24 -0
- package/src/prover/statetransition/StateTransitionWitnessProviderReference.ts +17 -0
- package/src/utils/PrefixedProvableHashList.ts +21 -0
- package/src/utils/ProvableHashList.ts +50 -0
- package/src/utils/merkletree/InMemoryMerkleTreeStorage.ts +99 -0
- package/src/utils/merkletree/MerkleTreeStore.ts +15 -0
- package/src/utils/merkletree/RollupMerkleTree.ts +250 -0
- package/src/utils/merkletree/VirtualMerkleTreeStore.ts +21 -0
- package/src/utils/utils.ts +103 -0
- package/test/BlockProver.test.ts +127 -0
- package/test/Protocol.test.ts +27 -0
- package/test/StateTransition.test.ts +182 -0
- package/tsconfig.json +8 -0
- package/tsconfig.test.json +9 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { Experimental, Field, Provable, SelfProof } from "snarkyjs";
|
|
2
|
+
import { inject, injectable } from "tsyringe";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
MerkleTreeUtils,
|
|
6
|
+
RollupMerkleWitness,
|
|
7
|
+
} from "../../utils/merkletree/RollupMerkleTree.js";
|
|
8
|
+
import {
|
|
9
|
+
DefaultProvableHashList,
|
|
10
|
+
ProvableHashList,
|
|
11
|
+
} from "../../utils/ProvableHashList";
|
|
12
|
+
import { ProvableStateTransition } from "../../model/StateTransition";
|
|
13
|
+
import { StateTransitionProvableBatch } from "../../model/StateTransitionProvableBatch";
|
|
14
|
+
import { constants } from "../../Constants";
|
|
15
|
+
|
|
16
|
+
import { StateTransitionWitnessProvider } from "./StateTransitionWitnessProvider.js";
|
|
17
|
+
import {
|
|
18
|
+
AreProofsEnabled,
|
|
19
|
+
PlainZkProgram,
|
|
20
|
+
provableMethod,
|
|
21
|
+
} from "@proto-kit/common";
|
|
22
|
+
import {
|
|
23
|
+
StateTransitionProvable,
|
|
24
|
+
StateTransitionProverPublicInput,
|
|
25
|
+
StateTransitionProof,
|
|
26
|
+
StateTransitionProverPublicOutput,
|
|
27
|
+
} from "./StateTransitionProvable";
|
|
28
|
+
import { ProtocolModule } from "../../protocol/ProtocolModule";
|
|
29
|
+
import { StateTransitionWitnessProviderReference } from "./StateTransitionWitnessProviderReference";
|
|
30
|
+
|
|
31
|
+
const errors = {
|
|
32
|
+
stateRootNotMatching: (step: string) => `StateRoots not matching ${step}`,
|
|
33
|
+
|
|
34
|
+
stateTransitionsHashNotMatching: (step: string) =>
|
|
35
|
+
`State transitions hash not matching ${step}`,
|
|
36
|
+
|
|
37
|
+
merkleWitnessNotCorrect: (index: number) =>
|
|
38
|
+
`MerkleWitness not valid for StateTransition (${index})`,
|
|
39
|
+
|
|
40
|
+
noWitnessProviderSet: () =>
|
|
41
|
+
new Error(
|
|
42
|
+
"WitnessProvider not set, set it before you use StateTransitionProvider"
|
|
43
|
+
),
|
|
44
|
+
|
|
45
|
+
propertyNotMatching: (propertyName: string) => `${propertyName} not matching`,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
interface StateTransitionProverExecutionState {
|
|
49
|
+
stateRoot: Field;
|
|
50
|
+
stateTransitionList: ProvableHashList<ProvableStateTransition>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const StateTransitionSelfProofClass = SelfProof<
|
|
54
|
+
StateTransitionProverPublicInput,
|
|
55
|
+
StateTransitionProverPublicOutput
|
|
56
|
+
>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* StateTransitionProver is the prover that proves the application of some state
|
|
60
|
+
* transitions and checks and updates their merkle-tree entries
|
|
61
|
+
*/
|
|
62
|
+
@injectable()
|
|
63
|
+
export class StateTransitionProver
|
|
64
|
+
extends ProtocolModule<
|
|
65
|
+
StateTransitionProverPublicInput,
|
|
66
|
+
StateTransitionProverPublicOutput
|
|
67
|
+
>
|
|
68
|
+
implements StateTransitionProvable
|
|
69
|
+
{
|
|
70
|
+
public constructor(
|
|
71
|
+
// Injected
|
|
72
|
+
public readonly witnessProviderReference: StateTransitionWitnessProviderReference
|
|
73
|
+
) {
|
|
74
|
+
super();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public zkProgramFactory(): PlainZkProgram<
|
|
78
|
+
StateTransitionProverPublicInput,
|
|
79
|
+
StateTransitionProverPublicOutput
|
|
80
|
+
> {
|
|
81
|
+
const instance = this;
|
|
82
|
+
|
|
83
|
+
const program = Experimental.ZkProgram({
|
|
84
|
+
publicInput: StateTransitionProverPublicInput,
|
|
85
|
+
publicOutput: StateTransitionProverPublicOutput,
|
|
86
|
+
|
|
87
|
+
methods: {
|
|
88
|
+
proveBatch: {
|
|
89
|
+
privateInputs: [StateTransitionProvableBatch],
|
|
90
|
+
|
|
91
|
+
method(
|
|
92
|
+
publicInput: StateTransitionProverPublicInput,
|
|
93
|
+
batch: StateTransitionProvableBatch
|
|
94
|
+
) {
|
|
95
|
+
return instance.runBatch(publicInput, batch);
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
merge: {
|
|
100
|
+
privateInputs: [
|
|
101
|
+
StateTransitionSelfProofClass,
|
|
102
|
+
StateTransitionSelfProofClass,
|
|
103
|
+
],
|
|
104
|
+
|
|
105
|
+
method(
|
|
106
|
+
publicInput: StateTransitionProverPublicInput,
|
|
107
|
+
proof1: StateTransitionProof,
|
|
108
|
+
proof2: StateTransitionProof
|
|
109
|
+
) {
|
|
110
|
+
return instance.merge(publicInput, proof1, proof2);
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const methods = {
|
|
117
|
+
proveBatch: program.proveBatch.bind(program),
|
|
118
|
+
merge: program.merge.bind(program),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const SelfProofClass = Experimental.ZkProgram.Proof(program);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
compile: program.compile.bind(program),
|
|
125
|
+
verify: program.verify.bind(program),
|
|
126
|
+
Proof: SelfProofClass,
|
|
127
|
+
methods,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private get witnessProvider(): StateTransitionWitnessProvider {
|
|
132
|
+
const provider = this.witnessProviderReference.getWitnessProvider();
|
|
133
|
+
if (provider === undefined) {
|
|
134
|
+
throw errors.noWitnessProviderSet();
|
|
135
|
+
}
|
|
136
|
+
return provider;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Applies the state transitions to the current stateRoot
|
|
141
|
+
* and returns the new prover state
|
|
142
|
+
*/
|
|
143
|
+
public applyTransitions(
|
|
144
|
+
stateRoot: Field,
|
|
145
|
+
stateTransitionCommitmentFrom: Field,
|
|
146
|
+
transitionBatch: StateTransitionProvableBatch
|
|
147
|
+
): StateTransitionProverExecutionState {
|
|
148
|
+
const state: StateTransitionProverExecutionState = {
|
|
149
|
+
stateRoot,
|
|
150
|
+
|
|
151
|
+
stateTransitionList: new DefaultProvableHashList(
|
|
152
|
+
ProvableStateTransition,
|
|
153
|
+
stateTransitionCommitmentFrom
|
|
154
|
+
),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const transitions = transitionBatch.batch;
|
|
158
|
+
for (
|
|
159
|
+
let index = 0;
|
|
160
|
+
index < constants.stateTransitionProverBatchSize;
|
|
161
|
+
index++
|
|
162
|
+
) {
|
|
163
|
+
this.applyTransition(state, transitions[index], index);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return state;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Applies a single state transition to the given state
|
|
171
|
+
* and mutates it in place
|
|
172
|
+
*/
|
|
173
|
+
public applyTransition(
|
|
174
|
+
state: StateTransitionProverExecutionState,
|
|
175
|
+
transition: ProvableStateTransition,
|
|
176
|
+
index = 0
|
|
177
|
+
) {
|
|
178
|
+
const treeWitness = Provable.witness(RollupMerkleWitness, () =>
|
|
179
|
+
this.witnessProvider.getWitness(transition.path)
|
|
180
|
+
);
|
|
181
|
+
Provable.log(
|
|
182
|
+
`ST (${index})`,
|
|
183
|
+
state.stateRoot,
|
|
184
|
+
" value: ",
|
|
185
|
+
transition.from.value
|
|
186
|
+
);
|
|
187
|
+
const membershipValid = MerkleTreeUtils.checkMembership(
|
|
188
|
+
treeWitness,
|
|
189
|
+
state.stateRoot,
|
|
190
|
+
transition.path,
|
|
191
|
+
transition.from.value
|
|
192
|
+
);
|
|
193
|
+
membershipValid
|
|
194
|
+
.or(transition.from.isSome.not())
|
|
195
|
+
.assertTrue(errors.merkleWitnessNotCorrect(index));
|
|
196
|
+
|
|
197
|
+
const newRoot = MerkleTreeUtils.computeRoot(
|
|
198
|
+
treeWitness,
|
|
199
|
+
transition.to.value
|
|
200
|
+
);
|
|
201
|
+
state.stateRoot = Provable.if(
|
|
202
|
+
transition.to.isSome,
|
|
203
|
+
newRoot,
|
|
204
|
+
state.stateRoot
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
state.stateTransitionList.pushIf(
|
|
208
|
+
transition,
|
|
209
|
+
transition.path.equals(Field(0)).not()
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Applies a whole batch of StateTransitions at once
|
|
215
|
+
*/
|
|
216
|
+
@provableMethod()
|
|
217
|
+
public runBatch(
|
|
218
|
+
publicInput: StateTransitionProverPublicInput,
|
|
219
|
+
batch: StateTransitionProvableBatch
|
|
220
|
+
): StateTransitionProverPublicOutput {
|
|
221
|
+
Provable.log(publicInput);
|
|
222
|
+
const result = this.applyTransitions(
|
|
223
|
+
publicInput.stateRoot,
|
|
224
|
+
publicInput.stateTransitionsHash,
|
|
225
|
+
batch
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const output = new StateTransitionProverPublicOutput({
|
|
229
|
+
stateRoot: result.stateRoot,
|
|
230
|
+
stateTransitionsHash: result.stateTransitionList.commitment,
|
|
231
|
+
});
|
|
232
|
+
Provable.log(output);
|
|
233
|
+
return output;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@provableMethod()
|
|
237
|
+
public merge(
|
|
238
|
+
publicInput: StateTransitionProverPublicInput,
|
|
239
|
+
proof1: StateTransitionProof,
|
|
240
|
+
proof2: StateTransitionProof
|
|
241
|
+
): StateTransitionProverPublicOutput {
|
|
242
|
+
proof1.verify();
|
|
243
|
+
proof2.verify();
|
|
244
|
+
|
|
245
|
+
// Check state
|
|
246
|
+
publicInput.stateRoot.assertEquals(
|
|
247
|
+
proof1.publicInput.stateRoot,
|
|
248
|
+
errors.stateRootNotMatching("publicInput.from -> proof1.from")
|
|
249
|
+
);
|
|
250
|
+
proof1.publicOutput.stateRoot.assertEquals(
|
|
251
|
+
proof2.publicInput.stateRoot,
|
|
252
|
+
errors.stateRootNotMatching("proof1.to -> proof2.from")
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
// Check ST list
|
|
256
|
+
publicInput.stateTransitionsHash.assertEquals(
|
|
257
|
+
proof1.publicInput.stateTransitionsHash,
|
|
258
|
+
errors.stateTransitionsHashNotMatching("publicInput.from -> proof1.from")
|
|
259
|
+
);
|
|
260
|
+
proof1.publicOutput.stateTransitionsHash.assertEquals(
|
|
261
|
+
proof2.publicInput.stateTransitionsHash,
|
|
262
|
+
errors.stateTransitionsHashNotMatching("proof1.to -> proof2.from")
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
return new StateTransitionProverPublicInput({
|
|
266
|
+
stateRoot: proof2.publicOutput.stateRoot,
|
|
267
|
+
stateTransitionsHash: proof2.publicOutput.stateTransitionsHash,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Field } from "snarkyjs";
|
|
2
|
+
import { injectable } from "tsyringe";
|
|
3
|
+
|
|
4
|
+
import { RollupMerkleWitness } from "../../utils/merkletree/RollupMerkleTree.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Interface for providing merkle witnesses to the state-transition prover
|
|
8
|
+
*/
|
|
9
|
+
export interface StateTransitionWitnessProvider {
|
|
10
|
+
/**
|
|
11
|
+
* Provides the merkle witness corresponding to the given key
|
|
12
|
+
* @param key Merkle-tree key
|
|
13
|
+
*/
|
|
14
|
+
getWitness: (key: Field) => RollupMerkleWitness;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@injectable()
|
|
18
|
+
export class NoOpStateTransitionWitnessProvider
|
|
19
|
+
implements StateTransitionWitnessProvider
|
|
20
|
+
{
|
|
21
|
+
public getWitness(key: Field): RollupMerkleWitness {
|
|
22
|
+
return new RollupMerkleWitness({ path: [], isLeft: [] });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { injectable, Lifecycle, scoped } from "tsyringe";
|
|
2
|
+
import { StateTransitionWitnessProvider } from "./StateTransitionWitnessProvider";
|
|
3
|
+
|
|
4
|
+
@injectable()
|
|
5
|
+
@scoped(Lifecycle.ContainerScoped)
|
|
6
|
+
export class StateTransitionWitnessProviderReference {
|
|
7
|
+
|
|
8
|
+
private witnessProvider?: StateTransitionWitnessProvider;
|
|
9
|
+
|
|
10
|
+
public setWitnessProvider(provider: StateTransitionWitnessProvider) {
|
|
11
|
+
this.witnessProvider = provider;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public getWitnessProvider(): StateTransitionWitnessProvider | undefined {
|
|
15
|
+
return this.witnessProvider;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Field, FlexibleProvablePure, Poseidon } from "snarkyjs";
|
|
2
|
+
|
|
3
|
+
import { ProvableHashList } from "./ProvableHashList.js";
|
|
4
|
+
import { stringToField } from "./utils";
|
|
5
|
+
|
|
6
|
+
export class PrefixedProvableHashList<Value> extends ProvableHashList<Value> {
|
|
7
|
+
private readonly prefix: Field;
|
|
8
|
+
|
|
9
|
+
public constructor(
|
|
10
|
+
valueType: FlexibleProvablePure<Value>,
|
|
11
|
+
prefix: string,
|
|
12
|
+
internalCommitment: Field = Field(0)
|
|
13
|
+
) {
|
|
14
|
+
super(valueType, internalCommitment);
|
|
15
|
+
this.prefix = stringToField(prefix);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected hash(elements: Field[]): Field {
|
|
19
|
+
return Poseidon.hash([this.prefix, ...elements]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Field, Poseidon, FlexibleProvablePure, Bool, Provable } from "snarkyjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utilities for creating a hash list from a given value type.
|
|
5
|
+
*/
|
|
6
|
+
export abstract class ProvableHashList<Value> {
|
|
7
|
+
public constructor(
|
|
8
|
+
private readonly valueType: FlexibleProvablePure<Value>,
|
|
9
|
+
public commitment: Field = Field(0)
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
protected abstract hash(elements: Field[]): Field;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts the provided value to Field[] and appends it to
|
|
16
|
+
* the current hashlist.
|
|
17
|
+
*
|
|
18
|
+
* @param value - Value to be appended to the hash list
|
|
19
|
+
* @returns Current hash list.
|
|
20
|
+
*/
|
|
21
|
+
public push(value: Value) {
|
|
22
|
+
this.commitment = this.hash([
|
|
23
|
+
this.commitment,
|
|
24
|
+
...this.valueType.toFields(value),
|
|
25
|
+
]);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public pushIf(value: Value, condition: Bool) {
|
|
30
|
+
const newCommitment = this.hash([
|
|
31
|
+
this.commitment,
|
|
32
|
+
...this.valueType.toFields(value),
|
|
33
|
+
]);
|
|
34
|
+
this.commitment = Provable.if(condition, newCommitment, this.commitment);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @returns Traling hash of the current hashlist.
|
|
40
|
+
*/
|
|
41
|
+
public toField() {
|
|
42
|
+
return this.commitment;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class DefaultProvableHashList<Value> extends ProvableHashList<Value> {
|
|
47
|
+
public hash(elements: Field[]): Field {
|
|
48
|
+
return Poseidon.hash(elements);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// eslint-disable-next-line max-len
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-magic-numbers,@typescript-eslint/no-unnecessary-condition */
|
|
3
|
+
import { log } from "@proto-kit/common";
|
|
4
|
+
|
|
5
|
+
import { RollupMerkleTree } from "./RollupMerkleTree.js";
|
|
6
|
+
import { AsyncMerkleTreeStore, MerkleTreeStore } from "./MerkleTreeStore";
|
|
7
|
+
|
|
8
|
+
export class InMemoryMerkleTreeStorage implements MerkleTreeStore {
|
|
9
|
+
protected readonly nodes: {
|
|
10
|
+
[key: number]: {
|
|
11
|
+
[key: string]: bigint;
|
|
12
|
+
};
|
|
13
|
+
} = {};
|
|
14
|
+
|
|
15
|
+
public getNode(key: bigint, level: number): bigint | undefined {
|
|
16
|
+
return this.nodes[level]?.[key.toString()];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public setNode(key: bigint, level: number, value: bigint): void {
|
|
20
|
+
(this.nodes[level] ??= {})[key.toString()] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class CachedMerkleTreeStore extends InMemoryMerkleTreeStorage {
|
|
25
|
+
private writeCache: {
|
|
26
|
+
[key: number]: {
|
|
27
|
+
[key: string]: bigint;
|
|
28
|
+
};
|
|
29
|
+
} = {};
|
|
30
|
+
|
|
31
|
+
public constructor(private readonly parent: AsyncMerkleTreeStore) {
|
|
32
|
+
super();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public setNode(key: bigint, level: number, value: bigint) {
|
|
36
|
+
super.setNode(key, level, value);
|
|
37
|
+
(this.writeCache[level] ??= {})[key.toString()] = value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public getWrittenNodes(): {
|
|
41
|
+
[key: number]: {
|
|
42
|
+
[key: string]: bigint;
|
|
43
|
+
};
|
|
44
|
+
} {
|
|
45
|
+
return this.writeCache;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public resetWrittenNodes() {
|
|
49
|
+
this.writeCache = {};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async preloadKey(index: bigint): Promise<void> {
|
|
53
|
+
log.debug(`Preloading MT ${index}`);
|
|
54
|
+
// Algo from RollupMerkleTree.getWitness()
|
|
55
|
+
const { leafCount, height } = RollupMerkleTree;
|
|
56
|
+
|
|
57
|
+
if (index >= leafCount) {
|
|
58
|
+
index %= leafCount;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// eslint-disable-next-line no-warning-comments,max-len
|
|
62
|
+
// TODO Not practical at the moment. Improve pattern when implementing DB storage
|
|
63
|
+
for (let level = 0; level < height; level++) {
|
|
64
|
+
const key = index;
|
|
65
|
+
|
|
66
|
+
// eslint-disable-next-line no-await-in-loop
|
|
67
|
+
const value = await this.parent.getNode(key, level);
|
|
68
|
+
if (level === 0) {
|
|
69
|
+
log.debug(`Preloaded ${key} -> ${value ?? "-"}`);
|
|
70
|
+
}
|
|
71
|
+
if (value !== undefined) {
|
|
72
|
+
(this.nodes[level] ??= {})[key.toString()] = value;
|
|
73
|
+
}
|
|
74
|
+
index /= 2n;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async mergeIntoParent(): Promise<void> {
|
|
79
|
+
// In case no state got set we can skip this step
|
|
80
|
+
if (Object.keys(this.writeCache).length === 0) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.parent.openTransaction();
|
|
85
|
+
const { height } = RollupMerkleTree;
|
|
86
|
+
const nodes = this.getWrittenNodes();
|
|
87
|
+
|
|
88
|
+
const promises = Array.from({ length: height }).flatMap((ignored, level) =>
|
|
89
|
+
Object.entries(nodes[level]).map(async (entry) => {
|
|
90
|
+
await this.parent.setNode(BigInt(entry[0]), level, entry[1]);
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
await Promise.all(promises);
|
|
95
|
+
|
|
96
|
+
this.parent.commit();
|
|
97
|
+
this.resetWrittenNodes();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AsyncMerkleTreeStore {
|
|
2
|
+
openTransaction: () => void;
|
|
3
|
+
|
|
4
|
+
commit: () => void;
|
|
5
|
+
|
|
6
|
+
setNode: (key: bigint, level: number, value: bigint) => Promise<void>;
|
|
7
|
+
|
|
8
|
+
getNode: (key: bigint, level: number) => Promise<bigint | undefined>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface MerkleTreeStore {
|
|
12
|
+
setNode: (key: bigint, level: number, value: bigint) => void;
|
|
13
|
+
|
|
14
|
+
getNode: (key: bigint, level: number) => bigint | undefined;
|
|
15
|
+
}
|