@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.
Files changed (150) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +45 -0
  3. package/dist/Constants.d.ts +4 -0
  4. package/dist/Constants.d.ts.map +1 -0
  5. package/dist/Constants.js +3 -0
  6. package/dist/config/ConfigurableModule.d.ts +18 -0
  7. package/dist/config/ConfigurableModule.d.ts.map +1 -0
  8. package/dist/config/ConfigurableModule.js +20 -0
  9. package/dist/config/ConfigurationAggregator.d.ts +10 -0
  10. package/dist/config/ConfigurationAggregator.d.ts.map +1 -0
  11. package/dist/config/ConfigurationAggregator.js +35 -0
  12. package/dist/config/ConfigurationReceiver.d.ts +25 -0
  13. package/dist/config/ConfigurationReceiver.d.ts.map +1 -0
  14. package/dist/config/ConfigurationReceiver.js +36 -0
  15. package/dist/config/ModuleContainer.d.ts +44 -0
  16. package/dist/config/ModuleContainer.d.ts.map +1 -0
  17. package/dist/config/ModuleContainer.js +89 -0
  18. package/dist/config/types.d.ts +2 -0
  19. package/dist/config/types.d.ts.map +1 -0
  20. package/dist/config/types.js +1 -0
  21. package/dist/index.d.ts +24 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +23 -0
  24. package/dist/model/MethodPublicInput.d.ts +51 -0
  25. package/dist/model/MethodPublicInput.d.ts.map +1 -0
  26. package/dist/model/MethodPublicInput.js +11 -0
  27. package/dist/model/MethodPublicOutput.d.ts +59 -0
  28. package/dist/model/MethodPublicOutput.d.ts.map +1 -0
  29. package/dist/model/MethodPublicOutput.js +12 -0
  30. package/dist/model/Option.d.ts +94 -0
  31. package/dist/model/Option.d.ts.map +1 -0
  32. package/dist/model/Option.js +96 -0
  33. package/dist/model/Path.d.ts +31 -0
  34. package/dist/model/Path.d.ts.map +1 -0
  35. package/dist/model/Path.js +44 -0
  36. package/dist/model/StateTransition.d.ts +85 -0
  37. package/dist/model/StateTransition.d.ts.map +1 -0
  38. package/dist/model/StateTransition.js +58 -0
  39. package/dist/model/StateTransitionProvableBatch.d.ts +57 -0
  40. package/dist/model/StateTransitionProvableBatch.d.ts.map +1 -0
  41. package/dist/model/StateTransitionProvableBatch.js +21 -0
  42. package/dist/model/network/NetworkState.d.ts +64 -0
  43. package/dist/model/network/NetworkState.d.ts.map +1 -0
  44. package/dist/model/network/NetworkState.js +14 -0
  45. package/dist/model/transaction/ProtocolTransaction.d.ts +70 -0
  46. package/dist/model/transaction/ProtocolTransaction.d.ts.map +1 -0
  47. package/dist/model/transaction/ProtocolTransaction.js +18 -0
  48. package/dist/model/transaction/RuntimeTransaction.d.ts +55 -0
  49. package/dist/model/transaction/RuntimeTransaction.d.ts.map +1 -0
  50. package/dist/model/transaction/RuntimeTransaction.js +26 -0
  51. package/dist/protocol/Protocol.d.ts +37 -0
  52. package/dist/protocol/Protocol.d.ts.map +1 -0
  53. package/dist/protocol/Protocol.js +50 -0
  54. package/dist/protocol/ProtocolModule.d.ts +9 -0
  55. package/dist/protocol/ProtocolModule.d.ts.map +1 -0
  56. package/dist/protocol/ProtocolModule.js +10 -0
  57. package/dist/prover/block/BlockProvable.d.ts +149 -0
  58. package/dist/prover/block/BlockProvable.d.ts.map +1 -0
  59. package/dist/prover/block/BlockProvable.js +20 -0
  60. package/dist/prover/block/BlockProver.d.ts +48 -0
  61. package/dist/prover/block/BlockProver.d.ts.map +1 -0
  62. package/dist/prover/block/BlockProver.js +171 -0
  63. package/dist/prover/block/BlockScopedModule.d.ts +3 -0
  64. package/dist/prover/block/BlockScopedModule.d.ts.map +1 -0
  65. package/dist/prover/block/BlockScopedModule.js +6 -0
  66. package/dist/prover/statetransition/StateTransitionProvable.d.ts +84 -0
  67. package/dist/prover/statetransition/StateTransitionProvable.d.ts.map +1 -0
  68. package/dist/prover/statetransition/StateTransitionProvable.js +11 -0
  69. package/dist/prover/statetransition/StateTransitionProver.d.ts +39 -0
  70. package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -0
  71. package/dist/prover/statetransition/StateTransitionProver.js +157 -0
  72. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts +16 -0
  73. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts.map +1 -0
  74. package/dist/prover/statetransition/StateTransitionWitnessProvider.js +17 -0
  75. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts +7 -0
  76. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.d.ts.map +1 -0
  77. package/dist/prover/statetransition/StateTransitionWitnessProviderReference.js +20 -0
  78. package/dist/src/model/Option.d.ts +158 -0
  79. package/dist/src/model/Option.d.ts.map +1 -0
  80. package/dist/src/model/Option.js +53 -0
  81. package/dist/src/model/Path.d.ts +35 -0
  82. package/dist/src/model/Path.d.ts.map +1 -0
  83. package/dist/src/model/Path.js +51 -0
  84. package/dist/src/model/StateTransition.d.ts +201 -0
  85. package/dist/src/model/StateTransition.d.ts.map +1 -0
  86. package/dist/src/model/StateTransition.js +43 -0
  87. package/dist/src/utils/PrefixedHashList.d.ts +15 -0
  88. package/dist/src/utils/PrefixedHashList.d.ts.map +1 -0
  89. package/dist/src/utils/PrefixedHashList.js +28 -0
  90. package/dist/src/utils/ProvableHashList.d.ts +30 -0
  91. package/dist/src/utils/ProvableHashList.d.ts.map +1 -0
  92. package/dist/src/utils/ProvableHashList.js +43 -0
  93. package/dist/utils/PrefixedHashList.d.ts +14 -0
  94. package/dist/utils/PrefixedHashList.d.ts.map +1 -0
  95. package/dist/utils/PrefixedHashList.js +12 -0
  96. package/dist/utils/PrefixedProvableHashList.d.ts +8 -0
  97. package/dist/utils/PrefixedProvableHashList.d.ts.map +1 -0
  98. package/dist/utils/PrefixedProvableHashList.js +12 -0
  99. package/dist/utils/ProvableHashList.d.ts +27 -0
  100. package/dist/utils/ProvableHashList.d.ts.map +1 -0
  101. package/dist/utils/ProvableHashList.js +43 -0
  102. package/dist/utils/Utils.d.ts +17 -0
  103. package/dist/utils/Utils.d.ts.map +1 -0
  104. package/dist/utils/Utils.js +63 -0
  105. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts +25 -0
  106. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts.map +1 -0
  107. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.js +72 -0
  108. package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts +26 -0
  109. package/dist/utils/merkletree/MemoryMerkleTreeStorage.d.ts.map +1 -0
  110. package/dist/utils/merkletree/MemoryMerkleTreeStorage.js +79 -0
  111. package/dist/utils/merkletree/MerkleTreeStore.d.ts +11 -0
  112. package/dist/utils/merkletree/MerkleTreeStore.d.ts.map +1 -0
  113. package/dist/utils/merkletree/MerkleTreeStore.js +1 -0
  114. package/dist/utils/merkletree/RollupMerkleTree.d.ts +130 -0
  115. package/dist/utils/merkletree/RollupMerkleTree.d.ts.map +1 -0
  116. package/dist/utils/merkletree/RollupMerkleTree.js +244 -0
  117. package/jest.config.cjs +1 -0
  118. package/package.json +35 -0
  119. package/src/Constants.ts +3 -0
  120. package/src/index.ts +23 -0
  121. package/src/model/MethodPublicOutput.ts +12 -0
  122. package/src/model/Option.test.ts +21 -0
  123. package/src/model/Option.ts +133 -0
  124. package/src/model/Path.ts +52 -0
  125. package/src/model/StateTransition.ts +72 -0
  126. package/src/model/StateTransitionProvableBatch.ts +31 -0
  127. package/src/model/Transaction.ts +29 -0
  128. package/src/model/network/NetworkState.ts +15 -0
  129. package/src/model/transaction/ProtocolTransaction.ts +25 -0
  130. package/src/model/transaction/RuntimeTransaction.ts +34 -0
  131. package/src/protocol/Protocol.ts +129 -0
  132. package/src/protocol/ProtocolModule.ts +27 -0
  133. package/src/prover/block/BlockProvable.ts +45 -0
  134. package/src/prover/block/BlockProver.ts +302 -0
  135. package/src/prover/statetransition/StateTransitionProvable.ts +40 -0
  136. package/src/prover/statetransition/StateTransitionProver.ts +270 -0
  137. package/src/prover/statetransition/StateTransitionWitnessProvider.ts +24 -0
  138. package/src/prover/statetransition/StateTransitionWitnessProviderReference.ts +17 -0
  139. package/src/utils/PrefixedProvableHashList.ts +21 -0
  140. package/src/utils/ProvableHashList.ts +50 -0
  141. package/src/utils/merkletree/InMemoryMerkleTreeStorage.ts +99 -0
  142. package/src/utils/merkletree/MerkleTreeStore.ts +15 -0
  143. package/src/utils/merkletree/RollupMerkleTree.ts +250 -0
  144. package/src/utils/merkletree/VirtualMerkleTreeStore.ts +21 -0
  145. package/src/utils/utils.ts +103 -0
  146. package/test/BlockProver.test.ts +127 -0
  147. package/test/Protocol.test.ts +27 -0
  148. package/test/StateTransition.test.ts +182 -0
  149. package/tsconfig.json +8 -0
  150. 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
+ }