@proto-kit/protocol 0.1.1-develop.456 → 0.1.1-develop.600

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 (98) hide show
  1. package/dist/blockmodules/AccountStateModule.d.ts.map +1 -1
  2. package/dist/blockmodules/AccountStateModule.js +10 -3
  3. package/dist/blockmodules/BlockHeightHook.d.ts +3 -3
  4. package/dist/blockmodules/BlockHeightHook.d.ts.map +1 -1
  5. package/dist/blockmodules/BlockHeightHook.js +5 -6
  6. package/dist/blockmodules/LastStateRootBlockHook.d.ts +8 -0
  7. package/dist/blockmodules/LastStateRootBlockHook.d.ts.map +1 -0
  8. package/dist/blockmodules/LastStateRootBlockHook.js +15 -0
  9. package/dist/blockmodules/NoopBlockHook.d.ts +6 -4
  10. package/dist/blockmodules/NoopBlockHook.d.ts.map +1 -1
  11. package/dist/blockmodules/NoopBlockHook.js +4 -4
  12. package/dist/blockmodules/NoopSettlementHook.d.ts +6 -0
  13. package/dist/blockmodules/NoopSettlementHook.d.ts.map +1 -0
  14. package/dist/blockmodules/NoopSettlementHook.js +18 -0
  15. package/dist/hooks/AccountStateHook.d.ts.map +1 -1
  16. package/dist/hooks/AccountStateHook.js +7 -2
  17. package/dist/hooks/BlockHeightHook.d.ts.map +1 -1
  18. package/dist/index.d.ts +9 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -3
  21. package/dist/model/MethodPublicOutput.d.ts +8 -0
  22. package/dist/model/MethodPublicOutput.d.ts.map +1 -1
  23. package/dist/model/MethodPublicOutput.js +1 -0
  24. package/dist/model/network/NetworkState.d.ts +40 -0
  25. package/dist/model/network/NetworkState.d.ts.map +1 -1
  26. package/dist/model/network/NetworkState.js +14 -2
  27. package/dist/model/transaction/RuntimeTransaction.d.ts +45 -20
  28. package/dist/model/transaction/RuntimeTransaction.d.ts.map +1 -1
  29. package/dist/model/transaction/RuntimeTransaction.js +68 -11
  30. package/dist/model/transaction/SignedTransaction.d.ts +71 -0
  31. package/dist/model/transaction/SignedTransaction.d.ts.map +1 -0
  32. package/dist/model/transaction/SignedTransaction.js +33 -0
  33. package/dist/model/transaction/ValueOption.d.ts +119 -0
  34. package/dist/model/transaction/ValueOption.d.ts.map +1 -0
  35. package/dist/model/transaction/ValueOption.js +24 -0
  36. package/dist/protocol/Protocol.d.ts +7 -3
  37. package/dist/protocol/Protocol.d.ts.map +1 -1
  38. package/dist/protocol/Protocol.js +26 -16
  39. package/dist/protocol/ProvableBlockHook.d.ts +2 -10
  40. package/dist/protocol/ProvableBlockHook.d.ts.map +1 -1
  41. package/dist/protocol/ProvableBlockHook.js +1 -1
  42. package/dist/protocol/ProvableTransactionHook.d.ts +1 -1
  43. package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -1
  44. package/dist/protocol/TransitioningProtocolModule.d.ts +3 -2
  45. package/dist/protocol/TransitioningProtocolModule.d.ts.map +1 -1
  46. package/dist/protocol/TransitioningProtocolModule.js +3 -2
  47. package/dist/prover/block/BlockProvable.d.ts +106 -28
  48. package/dist/prover/block/BlockProvable.d.ts.map +1 -1
  49. package/dist/prover/block/BlockProvable.js +23 -5
  50. package/dist/prover/block/BlockProver.d.ts +29 -8
  51. package/dist/prover/block/BlockProver.d.ts.map +1 -1
  52. package/dist/prover/block/BlockProver.js +241 -77
  53. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts +45 -0
  54. package/dist/prover/block/accummulators/BlockHashMerkleTree.d.ts.map +1 -0
  55. package/dist/prover/block/accummulators/BlockHashMerkleTree.js +16 -0
  56. package/dist/settlement/ProvableSettlementHook.d.ts +26 -0
  57. package/dist/settlement/ProvableSettlementHook.d.ts.map +1 -0
  58. package/dist/settlement/ProvableSettlementHook.js +3 -0
  59. package/dist/settlement/SettlementContract.d.ts +230 -0
  60. package/dist/settlement/SettlementContract.d.ts.map +1 -0
  61. package/dist/settlement/SettlementContract.js +346 -0
  62. package/dist/settlement/modules/NetworkStateSettlementModule.d.ts +11 -0
  63. package/dist/settlement/modules/NetworkStateSettlementModule.d.ts.map +1 -0
  64. package/dist/settlement/modules/NetworkStateSettlementModule.js +12 -0
  65. package/dist/state/context/RuntimeMethodExecutionContext.d.ts +75 -1
  66. package/dist/state/context/RuntimeMethodExecutionContext.d.ts.map +1 -1
  67. package/dist/state/context/RuntimeMethodExecutionContext.js +19 -1
  68. package/dist/utils/MinaPrefixedProvableHashList.d.ts +24 -0
  69. package/dist/utils/MinaPrefixedProvableHashList.d.ts.map +1 -0
  70. package/dist/utils/MinaPrefixedProvableHashList.js +51 -0
  71. package/package.json +2 -2
  72. package/src/blockmodules/AccountStateModule.ts +17 -6
  73. package/src/blockmodules/BlockHeightHook.ts +5 -8
  74. package/src/blockmodules/LastStateRootBlockHook.ts +26 -0
  75. package/src/blockmodules/NoopBlockHook.ts +15 -11
  76. package/src/blockmodules/NoopSettlementHook.ts +21 -0
  77. package/src/blockmodules/SequenceStateTransactionModule.ts +25 -0
  78. package/src/index.ts +9 -3
  79. package/src/model/MethodPublicOutput.ts +3 -2
  80. package/src/model/network/NetworkState.ts +15 -3
  81. package/src/model/transaction/RuntimeTransaction.ts +90 -16
  82. package/src/model/transaction/SignedTransaction.ts +54 -0
  83. package/src/model/transaction/ValueOption.ts +28 -0
  84. package/src/protocol/Protocol.ts +49 -31
  85. package/src/protocol/ProvableBlockHook.ts +10 -13
  86. package/src/protocol/ProvableTransactionHook.ts +2 -1
  87. package/src/protocol/TransitioningProtocolModule.ts +3 -2
  88. package/src/prover/block/BlockProvable.ts +39 -6
  89. package/src/prover/block/BlockProver.ts +473 -143
  90. package/src/prover/block/accummulators/BlockHashMerkleTree.ts +16 -0
  91. package/src/settlement/ProvableSettlementHook.ts +37 -0
  92. package/src/settlement/SettlementContract.ts +444 -0
  93. package/src/settlement/modules/NetworkStateSettlementModule.ts +39 -0
  94. package/src/state/context/RuntimeMethodExecutionContext.ts +18 -1
  95. package/src/utils/MinaPrefixedProvableHashList.ts +72 -0
  96. package/test/BlockProver.test.ts +2 -3
  97. package/src/model/transaction/ProtocolTransaction.ts +0 -25
  98. package/src/prover/block/BlockTransactionPosition.ts +0 -34
@@ -0,0 +1,16 @@
1
+ import { createMerkleTree } from "@proto-kit/common";
2
+ import { Bool, Field, Poseidon, Provable, Struct } from "o1js";
3
+
4
+ export class BlockHashMerkleTree extends createMerkleTree(16) {}
5
+ export class BlockHashMerkleTreeWitness extends BlockHashMerkleTree.WITNESS {}
6
+
7
+ export class BlockHashTreeEntry extends Struct({
8
+ blockHash: Field,
9
+ closed: Bool,
10
+ // TODO We could add startingEternalTransactionsHash here to offer
11
+ // a more trivial connection to the sequence state
12
+ }) {
13
+ public hash(): Field {
14
+ return Poseidon.hash([this.blockHash, ...this.closed.toFields()]);
15
+ }
16
+ }
@@ -0,0 +1,37 @@
1
+ import { Field, UInt32 } from "o1js";
2
+
3
+ import type { BlockProof } from "../prover/block/BlockProver";
4
+ import { ProtocolModule } from "../protocol/ProtocolModule";
5
+ import { NetworkState } from "../model/network/NetworkState";
6
+
7
+ import type { SettlementContract } from "./SettlementContract";
8
+
9
+ export type SettlementStateRecord = {
10
+ sequencerKey: Field;
11
+ lastSettlementL1Block: UInt32;
12
+
13
+ stateRoot: Field;
14
+ networkStateHash: Field;
15
+ blockHashRoot: Field;
16
+
17
+ promisedMessagesHash: Field;
18
+ honoredMessagesHash: Field;
19
+ };
20
+
21
+ export type SettlementHookInputs = {
22
+ blockProof: BlockProof;
23
+ fromNetworkState: NetworkState;
24
+ toNetworkState: NetworkState;
25
+ newPromisedMessagesHash: Field;
26
+ contractState: SettlementStateRecord;
27
+ currentL1Block: UInt32;
28
+ };
29
+
30
+ export abstract class ProvableSettlementHook<
31
+ Config
32
+ > extends ProtocolModule<Config> {
33
+ public abstract beforeSettlement(
34
+ smartContract: SettlementContract,
35
+ inputs: SettlementHookInputs
36
+ ): void;
37
+ }
@@ -0,0 +1,444 @@
1
+ import {
2
+ AccountUpdate,
3
+ Bool,
4
+ Field,
5
+ method,
6
+ Mina,
7
+ Poseidon,
8
+ Proof,
9
+ Provable,
10
+ ProvableExtended,
11
+ PublicKey,
12
+ Reducer,
13
+ Signature,
14
+ SmartContract,
15
+ State,
16
+ state,
17
+ Struct,
18
+ TokenId,
19
+ UInt32,
20
+ UInt64,
21
+ } from "o1js";
22
+ import {
23
+ EMPTY_PUBLICKEY,
24
+ prefixToField,
25
+ RollupMerkleTree,
26
+ RollupMerkleTreeWitness,
27
+ } from "@proto-kit/common";
28
+ import { inject, injectable, injectAll } from "tsyringe";
29
+
30
+ import { ProtocolModule } from "../protocol/ProtocolModule";
31
+ import { BlockProver } from "../prover/block/BlockProver";
32
+ import {
33
+ BlockProvable,
34
+ BlockProverPublicInput,
35
+ BlockProverPublicOutput,
36
+ } from "../prover/block/BlockProvable";
37
+ import { NetworkState } from "../model/network/NetworkState";
38
+ import { BlockHashMerkleTree } from "../prover/block/accummulators/BlockHashMerkleTree";
39
+ import { RuntimeTransaction } from "../model/transaction/RuntimeTransaction";
40
+ import { Path } from "../model/Path";
41
+ import { MinaActions, MinaEvents } from "../utils/MinaPrefixedProvableHashList";
42
+
43
+ import {
44
+ ProvableSettlementHook,
45
+ SettlementHookInputs,
46
+ SettlementStateRecord,
47
+ } from "./ProvableSettlementHook";
48
+
49
+ class LazyBlockProof extends Proof<
50
+ BlockProverPublicInput,
51
+ BlockProverPublicOutput
52
+ > {
53
+ public static publicInputType = BlockProverPublicInput;
54
+
55
+ public static publicOutputType = BlockProverPublicOutput;
56
+
57
+ public static tag: () => { name: string } = () => {
58
+ throw new Error("Tag not initialized yet");
59
+ };
60
+ }
61
+
62
+ export type SettlementMethodIdMapping = Record<`${string}.${string}`, bigint>;
63
+
64
+ export class Deposit extends Struct({
65
+ address: PublicKey,
66
+ amount: UInt64,
67
+ }) {}
68
+
69
+ export class Withdrawal extends Struct({
70
+ address: PublicKey,
71
+ amount: UInt64,
72
+ }) {
73
+ static dummy() {
74
+ return new Withdrawal({
75
+ address: EMPTY_PUBLICKEY,
76
+ amount: UInt64.from(0),
77
+ });
78
+ }
79
+ }
80
+
81
+ export const OUTGOING_MESSAGE_BATCH_SIZE = 1;
82
+
83
+ export class OutgoingMessageArgument extends Struct({
84
+ witness: RollupMerkleTreeWitness,
85
+ value: Withdrawal,
86
+ }) {
87
+ public static dummy(): OutgoingMessageArgument {
88
+ return new OutgoingMessageArgument({
89
+ witness: RollupMerkleTreeWitness.dummy(),
90
+ value: Withdrawal.dummy(),
91
+ });
92
+ }
93
+ }
94
+
95
+ export class OutgoingMessageArgumentBatch extends Struct({
96
+ arguments: Provable.Array(
97
+ OutgoingMessageArgument,
98
+ OUTGOING_MESSAGE_BATCH_SIZE
99
+ ),
100
+
101
+ isDummys: Provable.Array(Bool, OUTGOING_MESSAGE_BATCH_SIZE),
102
+ }) {
103
+ public static fromMessages(providedArguments: OutgoingMessageArgument[]) {
104
+ const batch = providedArguments.slice();
105
+ const isDummys = batch.map(() => Bool(false));
106
+
107
+ while (batch.length < OUTGOING_MESSAGE_BATCH_SIZE) {
108
+ batch.push(OutgoingMessageArgument.dummy());
109
+ isDummys.push(Bool(true));
110
+ }
111
+
112
+ return new OutgoingMessageArgumentBatch({
113
+ arguments: batch,
114
+ isDummys,
115
+ });
116
+ }
117
+ }
118
+
119
+ // Some random prefix for the sequencer signature
120
+ export const BATCH_SIGNATURE_PREFIX = prefixToField("pk-batchSignature");
121
+
122
+ export const ACTIONS_EMPTY_HASH = Reducer.initialActionState;
123
+
124
+ export class SettlementContract extends SmartContract {
125
+ @state(Field) public sequencerKey = State<Field>();
126
+ @state(UInt32) public lastSettlementL1Block = State<UInt32>();
127
+
128
+ @state(Field) public stateRoot = State<Field>();
129
+ @state(Field) public networkStateHash = State<Field>();
130
+ @state(Field) public blockHashRoot = State<Field>();
131
+
132
+ @state(Field) public promisedMessagesHash = State<Field>();
133
+ @state(Field) public honoredMessagesHash = State<Field>();
134
+
135
+ @state(Field) public outgoingMessageCursor = State<Field>();
136
+
137
+ public constructor(
138
+ address: PublicKey,
139
+ private readonly methodIdMappings: Record<string, bigint>,
140
+ private readonly hooks: ProvableSettlementHook<unknown>[],
141
+ private readonly withdrawalStatePath: [string, string],
142
+ private readonly incomingMessagesPaths: Record<
143
+ string,
144
+ `${string}.${string}`
145
+ >,
146
+ // 24 hours
147
+ private readonly escapeHatchSlotsInterval = (60 / 3) * 24
148
+ ) {
149
+ super(address);
150
+ }
151
+
152
+ @method
153
+ public initialize(sequencer: PublicKey) {
154
+ this.sequencerKey.getAndAssertEquals().assertEquals(Field(0));
155
+ this.stateRoot.getAndAssertEquals().assertEquals(Field(0));
156
+ this.blockHashRoot.getAndAssertEquals().assertEquals(Field(0));
157
+ this.networkStateHash.getAndAssertEquals().assertEquals(Field(0));
158
+ this.promisedMessagesHash.getAndAssertEquals().assertEquals(Field(0));
159
+ this.honoredMessagesHash.getAndAssertEquals().assertEquals(Field(0));
160
+
161
+ this.sequencerKey.set(sequencer.x);
162
+ this.stateRoot.set(Field(RollupMerkleTree.EMPTY_ROOT));
163
+ this.blockHashRoot.set(Field(BlockHashMerkleTree.EMPTY_ROOT));
164
+ this.networkStateHash.set(NetworkState.empty().hash());
165
+ this.promisedMessagesHash.set(ACTIONS_EMPTY_HASH);
166
+ this.honoredMessagesHash.set(ACTIONS_EMPTY_HASH);
167
+ }
168
+
169
+ @method
170
+ public settle(
171
+ blockProof: LazyBlockProof,
172
+ signature: Signature,
173
+ publicKey: PublicKey,
174
+ inputNetworkState: NetworkState,
175
+ outputNetworkState: NetworkState,
176
+ newPromisedMessagesHash: Field
177
+ ) {
178
+ // Verify the blockproof
179
+ blockProof.verify();
180
+
181
+ // Get and assert on-chain values
182
+ const stateRoot = this.stateRoot.getAndAssertEquals();
183
+ const networkStateHash = this.networkStateHash.getAndAssertEquals();
184
+ const blockHashRoot = this.blockHashRoot.getAndAssertEquals();
185
+ const sequencerKey = this.sequencerKey.getAndAssertEquals();
186
+ const promisedMessagesHash = this.promisedMessagesHash.getAndAssertEquals();
187
+ const honoredMessagesHash = this.honoredMessagesHash.getAndAssertEquals();
188
+ const lastSettlementL1Block =
189
+ this.lastSettlementL1Block.getAndAssertEquals();
190
+
191
+ // Get block height and use the lower bound for all ops
192
+ const minBlockIncluded = this.network.globalSlotSinceGenesis.get();
193
+ this.network.globalSlotSinceGenesis.assertBetween(
194
+ minBlockIncluded,
195
+ minBlockIncluded.add(20)
196
+ );
197
+
198
+ // Check signature/escape catch
199
+ publicKey.x.assertEquals(
200
+ sequencerKey,
201
+ "Sequencer public key witness not matching"
202
+ );
203
+ const signatureValid = signature.verify(publicKey, [
204
+ BATCH_SIGNATURE_PREFIX,
205
+ lastSettlementL1Block.value,
206
+ ]);
207
+ const escapeHatchActivated = lastSettlementL1Block
208
+ .add(UInt32.from(this.escapeHatchSlotsInterval))
209
+ .lessThan(minBlockIncluded);
210
+ signatureValid
211
+ .or(escapeHatchActivated)
212
+ .assertTrue(
213
+ "Sequencer signature not valid and escape hatch not activated"
214
+ );
215
+
216
+ // Assert correctness of networkState witness
217
+ inputNetworkState
218
+ .hash()
219
+ .assertEquals(networkStateHash, "InputNetworkState witness not valid");
220
+ outputNetworkState
221
+ .hash()
222
+ .assertEquals(
223
+ blockProof.publicOutput.networkStateHash,
224
+ "OutputNetworkState witness not valid"
225
+ );
226
+
227
+ blockProof.publicOutput.closed.assertEquals(
228
+ Bool(true),
229
+ "Supplied proof is not a closed BlockProof"
230
+ );
231
+
232
+ // Execute onSettlementHooks for additional checks
233
+ const stateRecord: SettlementStateRecord = {
234
+ blockHashRoot,
235
+ stateRoot,
236
+ networkStateHash,
237
+ honoredMessagesHash,
238
+ lastSettlementL1Block,
239
+ promisedMessagesHash,
240
+ sequencerKey,
241
+ };
242
+ const inputs: SettlementHookInputs = {
243
+ blockProof,
244
+ contractState: stateRecord,
245
+ newPromisedMessagesHash,
246
+ fromNetworkState: inputNetworkState,
247
+ toNetworkState: outputNetworkState,
248
+ currentL1Block: minBlockIncluded,
249
+ };
250
+ this.hooks.forEach((hook) => {
251
+ hook.beforeSettlement(this, inputs);
252
+ });
253
+
254
+ // Apply blockProof
255
+ stateRoot.assertEquals(
256
+ blockProof.publicInput.stateRoot,
257
+ "Input state root not matching"
258
+ );
259
+ networkStateHash.assertEquals(
260
+ blockProof.publicInput.networkStateHash,
261
+ "Input networkStateHash not matching"
262
+ );
263
+ blockHashRoot.assertEquals(
264
+ blockProof.publicInput.blockHashRoot,
265
+ "Input blockHashRoot not matching"
266
+ );
267
+ this.stateRoot.set(blockProof.publicOutput.stateRoot);
268
+ this.networkStateHash.set(blockProof.publicOutput.networkStateHash);
269
+ this.blockHashRoot.set(blockProof.publicOutput.blockHashRoot);
270
+
271
+ // Assert and apply deposit commitments
272
+ promisedMessagesHash.assertEquals(
273
+ blockProof.publicOutput.incomingMessagesHash,
274
+ "Promised messages not honored"
275
+ );
276
+ this.honoredMessagesHash.set(promisedMessagesHash);
277
+
278
+ // Assert and apply new promisedMessagesHash
279
+ this.self.account.actionState.assertEquals(newPromisedMessagesHash);
280
+ this.promisedMessagesHash.set(newPromisedMessagesHash);
281
+
282
+ this.lastSettlementL1Block.set(minBlockIncluded);
283
+ }
284
+
285
+ private dispatchMessage<Type>(
286
+ methodId: Field,
287
+ value: Type,
288
+ valueType: ProvableExtended<Type>
289
+ ) {
290
+ const args = valueType.toFields(value);
291
+ // Should be the same as RuntimeTransaction.hash
292
+ const argsHash = Poseidon.hash(args);
293
+ const runtimeTransaction = RuntimeTransaction.fromMessage({
294
+ methodId,
295
+ argsHash,
296
+ });
297
+
298
+ // Append tx to incomingMessagesHash
299
+ const actionData = runtimeTransaction.hashData();
300
+ const actionHash = MinaActions.actionHash(actionData);
301
+
302
+ this.self.body.actions = {
303
+ hash: actionHash,
304
+ data: [actionData],
305
+ };
306
+
307
+ const eventHash = MinaEvents.eventHash(args);
308
+ this.self.body.events = {
309
+ hash: eventHash,
310
+ data: [args],
311
+ };
312
+ }
313
+
314
+ @method
315
+ public deposit(amount: UInt64) {
316
+ // Save this, since otherwise it would be a second witness later,
317
+ // which could be a different values than the first
318
+ const sender = this.sender;
319
+
320
+ // Credit the amount to the bridge contract
321
+ this.self.balance.addInPlace(amount);
322
+
323
+ const action = new Deposit({
324
+ address: sender,
325
+ amount,
326
+ });
327
+ const methodId = Field(
328
+ this.methodIdMappings[this.incomingMessagesPaths["deposit"]]
329
+ );
330
+ this.dispatchMessage(methodId.toConstant(), action, Deposit);
331
+ }
332
+
333
+ @method
334
+ public rollupOutgoingMessages(batch: OutgoingMessageArgumentBatch) {
335
+ let counter = this.outgoingMessageCursor.getAndAssertEquals();
336
+ const stateRoot = this.stateRoot.getAndAssertEquals();
337
+
338
+ const [withdrawalModule, withdrawalStateName] = this.withdrawalStatePath;
339
+ const mapPath = Path.fromProperty(withdrawalModule, withdrawalStateName);
340
+
341
+ let accountCreationFeePaid = Field(0);
342
+
343
+ for (let i = 0; i < OUTGOING_MESSAGE_BATCH_SIZE; i++) {
344
+ const args = batch.arguments[i];
345
+
346
+ // Check witness
347
+ const path = Path.fromKey(mapPath, Field, counter);
348
+
349
+ args.witness
350
+ .checkMembership(
351
+ stateRoot,
352
+ path,
353
+ Poseidon.hash(Withdrawal.toFields(args.value))
354
+ )
355
+ .assertTrue("Provided Withdrawal witness not valid");
356
+
357
+ // Process message
358
+ const { address, amount } = args.value;
359
+ const isDummy = address.equals(this.address);
360
+
361
+ const tokenAu = this.token.mint({ address, amount });
362
+ const isNewAccount = tokenAu.account.isNew.getAndAssertEquals();
363
+ tokenAu.body.balanceChange.magnitude =
364
+ tokenAu.body.balanceChange.magnitude.sub(
365
+ Provable.if(
366
+ isNewAccount,
367
+ Mina.accountCreationFee().toConstant(),
368
+ UInt64.zero
369
+ )
370
+ );
371
+
372
+ accountCreationFeePaid = accountCreationFeePaid.add(
373
+ Provable.if(isNewAccount, Field(1e9), Field(0))
374
+ );
375
+
376
+ counter = counter.add(Provable.if(isDummy, Field(0), Field(1)));
377
+ }
378
+
379
+ this.balance.subInPlace(UInt64.from(accountCreationFeePaid));
380
+
381
+ this.outgoingMessageCursor.set(counter);
382
+ }
383
+
384
+ @method
385
+ public redeem(additionUpdate: AccountUpdate) {
386
+ additionUpdate.body.tokenId.assertEquals(
387
+ TokenId.default,
388
+ "Tokenid not default token"
389
+ );
390
+ additionUpdate.body.balanceChange.sgn
391
+ .isPositive()
392
+ .assertTrue("Sign not correct");
393
+ const amount = additionUpdate.body.balanceChange.magnitude;
394
+
395
+ // Burn tokens
396
+ this.token.burn({
397
+ address: additionUpdate.publicKey,
398
+ amount,
399
+ });
400
+
401
+ // Send mina
402
+ this.approve(additionUpdate);
403
+ this.balance.subInPlace(amount);
404
+ }
405
+ }
406
+
407
+ export interface SettlementContractModuleConfig {
408
+ withdrawalStatePath: `${string}.${string}`;
409
+ withdrawalMethodPath: `${string}.${string}`;
410
+ incomingMessagesMethods: Record<string, `${string}.${string}`>;
411
+ }
412
+
413
+ @injectable()
414
+ export class SettlementContractModule extends ProtocolModule<SettlementContractModuleConfig> {
415
+ public constructor(
416
+ @injectAll("ProvableSettlementHook")
417
+ private readonly hooks: ProvableSettlementHook<unknown>[],
418
+ @inject("BlockProver")
419
+ private readonly blockProver: BlockProvable
420
+ ) {
421
+ super();
422
+ LazyBlockProof.tag = blockProver.zkProgrammable.zkProgram.Proof.tag;
423
+ }
424
+
425
+ public getContractClass(): typeof SettlementContract {
426
+ return SettlementContract;
427
+ }
428
+
429
+ public createContract(
430
+ address: PublicKey,
431
+ methodIdMappings: SettlementMethodIdMapping
432
+ ): SettlementContract {
433
+ // We know that this returns [string, string], but TS can't infer that
434
+ const withdrawalPath = this.config.withdrawalStatePath.split(".");
435
+
436
+ return new SettlementContract(
437
+ address,
438
+ methodIdMappings,
439
+ this.hooks,
440
+ [withdrawalPath[0], withdrawalPath[1]],
441
+ this.config.incomingMessagesMethods
442
+ );
443
+ }
444
+ }
@@ -0,0 +1,39 @@
1
+ import { UInt64 } from "o1js";
2
+
3
+ import {
4
+ ProvableSettlementHook,
5
+ SettlementHookInputs,
6
+ } from "../ProvableSettlementHook";
7
+ import { SettlementContract } from "../SettlementContract";
8
+
9
+ type NetworkStateSettlementModuleConfig = {
10
+ blocksPerL1Block: UInt64;
11
+ };
12
+
13
+ export class NetworkStateSettlementModule extends ProvableSettlementHook<NetworkStateSettlementModuleConfig> {
14
+ public beforeSettlement(
15
+ smartContract: SettlementContract,
16
+ {
17
+ blockProof,
18
+ fromNetworkState,
19
+ toNetworkState,
20
+ contractState,
21
+ currentL1Block,
22
+ }: SettlementHookInputs
23
+ ): void {
24
+ const { lastSettlementL1Block } = contractState;
25
+
26
+ const blocksPerL1Block = this.config.blocksPerL1Block.toConstant();
27
+
28
+ const numL1Blocks = currentL1Block.sub(lastSettlementL1Block);
29
+ const expectedHeightDiff = numL1Blocks.toUInt64().mul(blocksPerL1Block);
30
+
31
+ const actualHeightDiff = toNetworkState.block.height.sub(
32
+ fromNetworkState.block.height
33
+ );
34
+
35
+ const acceptableDerivation = numL1Blocks.mul(1).div(10);
36
+
37
+ // TODO Check within bounds efficiently
38
+ }
39
+ }
@@ -1,4 +1,4 @@
1
- import { Bool } from "o1js";
1
+ import { Bool, Provable, Struct } from "o1js";
2
2
  import { singleton } from "tsyringe";
3
3
  import {
4
4
  ProvableMethodExecutionContext,
@@ -29,6 +29,11 @@ export interface RuntimeMethodExecutionData {
29
29
  networkState: NetworkState;
30
30
  }
31
31
 
32
+ export class RuntimeMethodExecutionDataStruct extends Struct({
33
+ transaction: RuntimeTransaction,
34
+ networkState: NetworkState,
35
+ }) {}
36
+
32
37
  /**
33
38
  * Execution context used to wrap runtime module methods,
34
39
  * allowing them to post relevant information (such as execution status)
@@ -93,6 +98,18 @@ export class RuntimeMethodExecutionContext extends ProvableMethodExecutionContex
93
98
  this.input = input;
94
99
  }
95
100
 
101
+ public witnessInput(): RuntimeMethodExecutionDataStruct {
102
+ this.assertSetupCalled();
103
+ return Provable.witness(RuntimeMethodExecutionDataStruct, () => {
104
+ // TODO Is that right? Or this.current().input
105
+ const { transaction, networkState } = this.input!;
106
+ return new RuntimeMethodExecutionDataStruct({
107
+ networkState,
108
+ transaction,
109
+ });
110
+ });
111
+ }
112
+
96
113
  public setSimulated(simulated: boolean) {
97
114
  this.isSimulated = simulated;
98
115
  }
@@ -0,0 +1,72 @@
1
+ import { Field, FlexibleProvablePure, Poseidon } from "o1js";
2
+ import { hashWithPrefix, prefixToField } from "@proto-kit/common";
3
+
4
+ import { ProvableHashList } from "./ProvableHashList";
5
+
6
+ function salt(prefix: string) {
7
+ return Poseidon.update(
8
+ [Field(0), Field(0), Field(0)],
9
+ [prefixToField(prefix)]
10
+ ) as [Field, Field, Field];
11
+ }
12
+
13
+ export const MINA_EVENT_PREFIXES = {
14
+ event: "MinaZkappEvent******",
15
+ events: "MinaZkappEvents*****",
16
+ sequenceEvents: "MinaZkappSeqEvents**",
17
+ } as const;
18
+
19
+ export function emptyActions(): Field {
20
+ return salt("MinaZkappActionsEmpty")[0];
21
+ }
22
+
23
+ export function emptyEvents(): Field {
24
+ return salt("MinaZkappEventsEmpty")[0];
25
+ }
26
+
27
+ export class MinaActions {
28
+ static actionHash(
29
+ action: Field[],
30
+ previousHash: Field = emptyActions()
31
+ ): Field {
32
+ const actionDataHash = hashWithPrefix(MINA_EVENT_PREFIXES.event, action);
33
+ return hashWithPrefix(MINA_EVENT_PREFIXES.sequenceEvents, [
34
+ previousHash,
35
+ actionDataHash,
36
+ ]);
37
+ }
38
+ }
39
+
40
+ export class MinaEvents {
41
+ static eventHash(event: Field[], previousHash: Field = emptyEvents()): Field {
42
+ const actionDataHash = hashWithPrefix(MINA_EVENT_PREFIXES.event, event);
43
+ return hashWithPrefix(MINA_EVENT_PREFIXES.events, [
44
+ previousHash,
45
+ actionDataHash,
46
+ ]);
47
+ }
48
+ }
49
+
50
+ export class MinaPrefixedProvableHashList<
51
+ Value
52
+ > extends ProvableHashList<Value> {
53
+ public constructor(
54
+ valueType: FlexibleProvablePure<Value>,
55
+ public readonly prefix: string,
56
+ internalCommitment: Field = Field(0)
57
+ ) {
58
+ super(valueType, internalCommitment);
59
+ }
60
+
61
+ protected hash(elements: Field[]): Field {
62
+ const init = salt(this.prefix);
63
+ const digest = Poseidon.update(init, elements);
64
+ return digest[0];
65
+ }
66
+ }
67
+
68
+ export class MinaActionsHashList extends MinaPrefixedProvableHashList<Field> {
69
+ public constructor(internalCommitment: Field = Field(0)) {
70
+ super(Field, MINA_EVENT_PREFIXES.sequenceEvents, internalCommitment);
71
+ }
72
+ }
@@ -22,13 +22,12 @@ import { UnsignedTransaction } from "@proto-kit/sequencer";
22
22
  import { AccountStateModule } from "../src/blockmodules/AccountStateModule";
23
23
  import { container } from "tsyringe";
24
24
  import {
25
- BlockModule,
26
25
  DefaultProvableHashList,
27
26
  MethodPublicOutput,
28
27
  NetworkState,
29
28
  Protocol,
30
29
  ProtocolMethodExecutionContext,
31
- ProtocolTransaction,
30
+ SignedTransaction,
32
31
  ProvableStateTransition,
33
32
  RuntimeTransaction,
34
33
  StateTransitionProver,
@@ -101,7 +100,7 @@ describe("blockProver", () => {
101
100
  fromStateRoot: Field,
102
101
  toStateRoot: Field,
103
102
  protocolHash: Field,
104
- tx: ProtocolTransaction,
103
+ tx: SignedTransaction,
105
104
  networkState: NetworkState
106
105
  ): BlockProverProofPair {
107
106
  const transactionHash =
@@ -1,25 +0,0 @@
1
- import { Bool, Field, PublicKey, Signature, Struct, UInt64 } from "o1js";
2
-
3
- export class ProtocolTransaction extends Struct({
4
- methodId: Field,
5
- nonce: UInt64,
6
- sender: PublicKey,
7
- argsHash: Field,
8
- signature: Signature,
9
- }) {
10
- public static getSignatureData(args: {
11
- methodId: Field;
12
- nonce: UInt64;
13
- argsHash: Field;
14
- }): Field[] {
15
- return [args.methodId, ...args.nonce.toFields(), args.argsHash];
16
- }
17
-
18
- public getSignatureData(): Field[] {
19
- return ProtocolTransaction.getSignatureData(this);
20
- }
21
-
22
- public validateSignature(): Bool {
23
- return this.signature.verify(this.sender, this.getSignatureData());
24
- }
25
- }