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

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 (110) hide show
  1. package/dist/blockmodules/AccountStateModule.d.ts +1 -1
  2. package/dist/blockmodules/AccountStateModule.d.ts.map +1 -1
  3. package/dist/blockmodules/BlockHeightHook.d.ts +7 -0
  4. package/dist/blockmodules/BlockHeightHook.d.ts.map +1 -0
  5. package/dist/blockmodules/BlockHeightHook.js +16 -0
  6. package/dist/blockmodules/NoopBlockHook.d.ts +7 -0
  7. package/dist/blockmodules/NoopBlockHook.d.ts.map +1 -0
  8. package/dist/blockmodules/NoopBlockHook.js +9 -0
  9. package/dist/blockmodules/NoopTransactionHook.d.ts +1 -1
  10. package/dist/blockmodules/NoopTransactionHook.d.ts.map +1 -1
  11. package/dist/blockmodules/NoopTransactionHook.js +1 -2
  12. package/dist/hooks/AccountStateHook.d.ts +38 -0
  13. package/dist/hooks/AccountStateHook.d.ts.map +1 -0
  14. package/dist/hooks/AccountStateHook.js +36 -0
  15. package/dist/hooks/BlockHeightHook.d.ts +7 -0
  16. package/dist/hooks/BlockHeightHook.d.ts.map +1 -0
  17. package/dist/hooks/BlockHeightHook.js +14 -0
  18. package/dist/hooks/NoopBlockHook.d.ts +7 -0
  19. package/dist/hooks/NoopBlockHook.d.ts.map +1 -0
  20. package/dist/hooks/NoopBlockHook.js +9 -0
  21. package/dist/hooks/NoopTransactionHook.d.ts +6 -0
  22. package/dist/hooks/NoopTransactionHook.d.ts.map +1 -0
  23. package/dist/hooks/NoopTransactionHook.js +4 -0
  24. package/dist/hooks/TransactionFeeHook.d.ts +16 -0
  25. package/dist/hooks/TransactionFeeHook.d.ts.map +1 -0
  26. package/dist/hooks/TransactionFeeHook.js +39 -0
  27. package/dist/index.d.ts +4 -4
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4 -4
  30. package/dist/model/Option.d.ts +29 -22
  31. package/dist/model/Option.d.ts.map +1 -1
  32. package/dist/model/Option.js +51 -45
  33. package/dist/model/StateTransition.d.ts +4 -2
  34. package/dist/model/StateTransition.d.ts.map +1 -1
  35. package/dist/model/StateTransition.js +2 -2
  36. package/dist/model/network/NetworkState.d.ts +1 -40
  37. package/dist/model/network/NetworkState.d.ts.map +1 -1
  38. package/dist/model/network/NetworkState.js +9 -10
  39. package/dist/protocol/Protocol.d.ts +4 -18
  40. package/dist/protocol/Protocol.d.ts.map +1 -1
  41. package/dist/protocol/Protocol.js +20 -9
  42. package/dist/protocol/ProtocolModule.d.ts +2 -2
  43. package/dist/protocol/ProtocolModule.d.ts.map +1 -1
  44. package/dist/protocol/ProtocolModule.js +1 -1
  45. package/dist/protocol/ProvableBlockHook.d.ts +16 -0
  46. package/dist/protocol/ProvableBlockHook.d.ts.map +1 -0
  47. package/dist/protocol/ProvableBlockHook.js +4 -0
  48. package/dist/protocol/ProvableTransactionHook.d.ts +2 -1
  49. package/dist/protocol/ProvableTransactionHook.d.ts.map +1 -1
  50. package/dist/protocol/TransitioningProtocolModule.d.ts +4 -0
  51. package/dist/protocol/TransitioningProtocolModule.d.ts.map +1 -1
  52. package/dist/protocol/TransitioningProtocolModule.js +4 -0
  53. package/dist/prover/block/BlockProvable.d.ts +21 -6
  54. package/dist/prover/block/BlockProvable.d.ts.map +1 -1
  55. package/dist/prover/block/BlockProvable.js +3 -1
  56. package/dist/prover/block/BlockProver.d.ts +9 -4
  57. package/dist/prover/block/BlockProver.d.ts.map +1 -1
  58. package/dist/prover/block/BlockProver.js +66 -16
  59. package/dist/prover/block/BlockTransactionPosition.d.ts +36 -0
  60. package/dist/prover/block/BlockTransactionPosition.d.ts.map +1 -0
  61. package/dist/prover/block/BlockTransactionPosition.js +25 -0
  62. package/dist/prover/statetransition/StateTransitionProver.d.ts +1 -1
  63. package/dist/prover/statetransition/StateTransitionProver.d.ts.map +1 -1
  64. package/dist/prover/statetransition/StateTransitionProver.js +4 -5
  65. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts +3 -3
  66. package/dist/prover/statetransition/StateTransitionWitnessProvider.d.ts.map +1 -1
  67. package/dist/prover/statetransition/StateTransitionWitnessProvider.js +2 -2
  68. package/dist/state/State.d.ts +8 -1
  69. package/dist/state/State.d.ts.map +1 -1
  70. package/dist/state/State.js +11 -4
  71. package/dist/state/StateServiceProvider.d.ts +0 -2
  72. package/dist/state/StateServiceProvider.d.ts.map +1 -1
  73. package/dist/state/StateServiceProvider.js +5 -17
  74. package/package.json +3 -2
  75. package/src/blockmodules/AccountStateModule.ts +2 -2
  76. package/src/blockmodules/BlockHeightHook.ts +21 -0
  77. package/src/blockmodules/NoopBlockHook.ts +16 -0
  78. package/src/blockmodules/NoopTransactionHook.ts +3 -4
  79. package/src/index.ts +4 -4
  80. package/src/model/Option.ts +71 -56
  81. package/src/model/StateTransition.ts +2 -2
  82. package/src/model/network/NetworkState.ts +9 -9
  83. package/src/protocol/Protocol.ts +33 -32
  84. package/src/protocol/ProtocolModule.ts +3 -3
  85. package/src/protocol/ProvableBlockHook.ts +22 -0
  86. package/src/protocol/ProvableTransactionHook.ts +4 -1
  87. package/src/protocol/TransitioningProtocolModule.ts +4 -0
  88. package/src/prover/block/BlockProvable.ts +4 -2
  89. package/src/prover/block/BlockProver.ts +134 -21
  90. package/src/prover/block/BlockTransactionPosition.ts +34 -0
  91. package/src/prover/statetransition/StateTransitionProver.ts +6 -13
  92. package/src/prover/statetransition/StateTransitionWitnessProvider.ts +4 -5
  93. package/src/state/State.ts +11 -4
  94. package/src/state/StateServiceProvider.ts +2 -10
  95. package/test/Option.test.ts +64 -0
  96. package/test/StateTransition.test.ts +1 -1
  97. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts +0 -11
  98. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.d.ts.map +0 -1
  99. package/dist/utils/merkletree/InMemoryMerkleTreeStorage.js +0 -12
  100. package/dist/utils/merkletree/MerkleTreeStore.d.ts +0 -11
  101. package/dist/utils/merkletree/MerkleTreeStore.d.ts.map +0 -1
  102. package/dist/utils/merkletree/MerkleTreeStore.js +0 -1
  103. package/dist/utils/merkletree/RollupMerkleTree.d.ts +0 -132
  104. package/dist/utils/merkletree/RollupMerkleTree.d.ts.map +0 -1
  105. package/dist/utils/merkletree/RollupMerkleTree.js +0 -251
  106. package/src/utils/merkletree/InMemoryMerkleTreeStorage.ts +0 -17
  107. package/src/utils/merkletree/MerkleTreeStore.ts +0 -15
  108. package/src/utils/merkletree/RollupMerkleTree.ts +0 -275
  109. package/src/utils/merkletree/VirtualMerkleTreeStore.ts +0 -21
  110. package/test/utils/MerkleTree.test.ts +0 -82
@@ -17,10 +17,67 @@ export class ProvableOption extends Struct({
17
17
  }
18
18
  }
19
19
 
20
+ export abstract class OptionBase {
21
+ protected constructor(public isSome: Bool, public isForcedSome: Bool) {}
22
+
23
+ protected abstract encodeValueToFields(): Field[];
24
+
25
+ protected abstract clone(): OptionBase;
26
+
27
+ /**
28
+ * @returns Tree representation of the current value
29
+ */
30
+ public get treeValue() {
31
+ const treeValue = Poseidon.hash(this.encodeValueToFields());
32
+
33
+ return Provable.if(
34
+ this.isSome.and(this.isForcedSome.not()),
35
+ treeValue,
36
+ Field(0)
37
+ );
38
+ }
39
+
40
+ public forceSome() {
41
+ this.isForcedSome = Provable.if(this.isSome, Bool(false), Bool(true));
42
+ this.isSome = Bool(true);
43
+ }
44
+
45
+ /**
46
+ * Returns the `to`-value as decoded as a list of fields
47
+ * Not in circuit
48
+ */
49
+ public toFields(): Field[] {
50
+ if (this.isSome.toBoolean()) {
51
+ return this.encodeValueToFields();
52
+ }
53
+ return [Field(0)];
54
+ }
55
+
56
+ /**
57
+ * @returns Provable representation of the current option.
58
+ */
59
+ public toProvable() {
60
+ return new ProvableOption({
61
+ isSome: this.isSome,
62
+ value: this.treeValue,
63
+ });
64
+ }
65
+
66
+ public toJSON() {
67
+ const value = this.encodeValueToFields().map((field) => field.toString());
68
+
69
+ return {
70
+ isSome: this.isSome.toBoolean(),
71
+ isForcedSome: this.isForcedSome.toBoolean(),
72
+ value,
73
+ };
74
+ }
75
+ }
76
+
20
77
  /**
21
78
  * Option facilitating in-circuit values that may or may not exist.
22
79
  */
23
- export class Option<Value> {
80
+ export class Option<Value> extends OptionBase {
24
81
  /**
25
82
  * Creates a new Option from the provided parameters
26
83
  *
@@ -58,57 +115,28 @@ export class Option<Value> {
58
115
  return new Option(Bool(false), Field(0), Field);
59
116
  }
60
117
 
61
- public isForcedSome = Bool(false);
62
-
63
118
  public constructor(
64
- public isSome: Bool,
119
+ isSome: Bool,
65
120
  public value: Value,
66
- public valueType: FlexibleProvablePure<Value>
67
- ) {}
68
-
69
- public clone() {
70
- return new Option(this.isSome, this.value, this.valueType);
121
+ public valueType: FlexibleProvablePure<Value>,
122
+ isForcedSome = Bool(false)
123
+ ) {
124
+ super(isSome, isForcedSome);
71
125
  }
72
126
 
73
- public forceSome() {
74
- this.isForcedSome = Provable.if(this.isSome, Bool(false), Bool(true));
75
- this.isSome = Bool(true);
127
+ public encodeValueToFields(): Field[] {
128
+ return this.valueType.toFields(this.value);
76
129
  }
77
130
 
78
- /**
79
- * @returns Tree representation of the current value
80
- */
81
- public get treeValue() {
82
- const treeValue = Poseidon.hash(this.valueType.toFields(this.value));
83
-
84
- return Provable.if(
85
- this.isSome.and(this.isForcedSome.not()),
86
- treeValue,
87
- Field(0)
131
+ public clone(): Option<Value> {
132
+ return new Option(
133
+ this.isSome,
134
+ this.value,
135
+ this.valueType,
136
+ this.isForcedSome
88
137
  );
89
138
  }
90
139
 
91
- /**
92
- * Returns the `to`-value as decoded as a list of fields
93
- * Not in circuit
94
- */
95
- public toFields(): Field[] {
96
- if (this.isSome.toBoolean()) {
97
- return this.valueType.toFields(this.value);
98
- }
99
- return [Field(0)];
100
- }
101
-
102
- /**
103
- * @returns Provable representation of the current option.
104
- */
105
- public toProvable() {
106
- return new ProvableOption({
107
- isSome: this.isSome,
108
- value: this.treeValue,
109
- });
110
- }
111
-
112
140
  /**
113
141
  * @returns Returns the value of this option if it isSome,
114
142
  * otherwise returns the given defaultValue
@@ -121,17 +149,4 @@ export class Option<Value> {
121
149
  defaultValue
122
150
  );
123
151
  }
124
-
125
- public toJSON() {
126
- const valueContent = this.valueType
127
- .toFields(this.value)
128
- .map((field) => field.toString())
129
- .reduce((a, b) => `${a}, ${b}`);
130
-
131
- return {
132
- isSome: this.isSome.toBoolean(),
133
-
134
- value: `[${valueContent}]`,
135
- };
136
- }
137
152
  }
@@ -73,8 +73,8 @@ export class StateTransition<Value> {
73
73
  public toJSON() {
74
74
  return {
75
75
  path: this.path.toString(),
76
- from: this.from.toJSON(),
77
- to: this.to.toJSON(),
76
+ from: this.fromValue.toJSON(),
77
+ to: this.toValue.toJSON(),
78
78
  };
79
79
  }
80
80
  }
@@ -4,18 +4,18 @@ export class CurrentBlock extends Struct({
4
4
  height: UInt64,
5
5
  }) {}
6
6
 
7
- export class PreviousBlock extends Struct({
8
- rootHash: Field,
9
- }) {}
10
-
11
7
  export class NetworkState extends Struct({
12
8
  block: CurrentBlock,
13
- previous: PreviousBlock,
14
9
  }) {
15
10
  public hash(): Field {
16
- return Poseidon.hash([
17
- ...CurrentBlock.toFields(this.block),
18
- ...PreviousBlock.toFields(this.previous),
19
- ]);
11
+ return Poseidon.hash(CurrentBlock.toFields(this.block));
12
+ }
13
+
14
+ public static empty(){
15
+ return new NetworkState({
16
+ block: {
17
+ height: UInt64.zero,
18
+ },
19
+ })
20
20
  }
21
21
  }
@@ -22,15 +22,23 @@ import { ProvableTransactionHook } from "./ProvableTransactionHook";
22
22
  import { NoopTransactionHook } from "../blockmodules/NoopTransactionHook";
23
23
  import { ProtocolEnvironment } from "./ProtocolEnvironment";
24
24
  import { AccountStateModule } from "../blockmodules/AccountStateModule";
25
+ import { ProvableBlockHook } from "./ProvableBlockHook";
26
+ import { NoopBlockHook } from "../blockmodules/NoopBlockHook";
27
+ import { BlockHeightHook } from "../blockmodules/BlockHeightHook";
28
+
29
+ const PROTOCOL_INJECTION_TOKENS = {
30
+ ProvableTransactionHook: "ProvableTransactionHook",
31
+ ProvableBlockHook: "ProvableBlockHook",
32
+ };
25
33
 
26
34
  export type GenericProtocolModuleRecord = ModulesRecord<
27
35
  TypedClass<ProtocolModule<unknown>>
28
36
  >;
29
37
 
30
- interface BlockProverType extends ProtocolModule<object>, BlockProvable {}
38
+ interface BlockProverType extends ProtocolModule, BlockProvable {}
31
39
 
32
40
  interface StateTransitionProverType
33
- extends ProtocolModule<object>,
41
+ extends ProtocolModule,
34
42
  StateTransitionProvable {}
35
43
 
36
44
  export interface ProtocolCustomModulesRecord {
@@ -126,67 +134,60 @@ export class Protocol<Modules extends ProtocolModulesRecord>
126
134
  // Register the BlockModules seperately since we need to
127
135
  // inject them differently later
128
136
  let atLeastOneTransactionHookRegistered = false;
137
+ let atLeastOneBlockHookRegistered = false;
129
138
  Object.entries(this.definition.modules).forEach(([key, value]) => {
130
139
  if (Object.prototype.isPrototypeOf.call(ProvableTransactionHook, value)) {
131
140
  this.container.register(
132
- "ProvableTransactionHook",
141
+ PROTOCOL_INJECTION_TOKENS.ProvableTransactionHook,
133
142
  { useToken: key },
134
143
  { lifecycle: Lifecycle.ContainerScoped }
135
144
  );
136
145
  atLeastOneTransactionHookRegistered = true;
137
146
  }
147
+ if (Object.prototype.isPrototypeOf.call(ProvableBlockHook, value)) {
148
+ this.container.register(
149
+ PROTOCOL_INJECTION_TOKENS.ProvableBlockHook,
150
+ { useToken: key },
151
+ { lifecycle: Lifecycle.ContainerScoped }
152
+ );
153
+ atLeastOneBlockHookRegistered = true;
154
+ }
138
155
  });
139
156
 
140
157
  // We need this so that tsyringe doesn't throw when no hooks are registered
141
158
  if (!atLeastOneTransactionHookRegistered) {
142
159
  this.container.register(
143
- "ProvableTransactionHook",
160
+ PROTOCOL_INJECTION_TOKENS.ProvableTransactionHook,
144
161
  { useClass: NoopTransactionHook },
145
162
  { lifecycle: Lifecycle.ContainerScoped }
146
163
  );
147
164
  }
165
+ if (!atLeastOneBlockHookRegistered) {
166
+ this.container.register(
167
+ PROTOCOL_INJECTION_TOKENS.ProvableBlockHook,
168
+ { useClass: NoopBlockHook },
169
+ { lifecycle: Lifecycle.ContainerScoped }
170
+ );
171
+ }
148
172
  }
149
173
  }
150
174
 
151
175
  export const VanillaProtocol = {
152
176
  create() {
153
- return VanillaProtocol.from(
154
- {},
155
- {
156
- BlockProver: {},
157
- StateTransitionProver: {},
158
- AccountState: {},
159
- }
160
- );
177
+ return VanillaProtocol.from({});
161
178
  },
162
179
 
163
180
  from<AdditonalModules extends GenericProtocolModuleRecord>(
164
- additionalModules: AdditonalModules,
165
- config: ModulesConfig<
166
- AdditonalModules & {
167
- StateTransitionProver: typeof StateTransitionProver;
168
- BlockProver: typeof BlockProver;
169
- AccountState: typeof AccountStateModule;
170
- }
171
- >
172
- ): TypedClass<
173
- Protocol<
174
- AdditonalModules & {
175
- StateTransitionProver: typeof StateTransitionProver;
176
- BlockProver: typeof BlockProver;
177
- AccountState: typeof AccountStateModule;
178
- }
179
- >
180
- > {
181
- return Protocol.from({
181
+ additionalModules: AdditonalModules
182
+ ): TypedClass<Protocol<ProtocolModulesRecord>> {
183
+ return Protocol.from<ProtocolModulesRecord>({
182
184
  modules: {
183
185
  StateTransitionProver,
184
186
  BlockProver,
185
187
  AccountState: AccountStateModule,
188
+ BlockHeight: BlockHeightHook,
186
189
  ...additionalModules,
187
190
  },
188
-
189
- config,
190
191
  });
191
192
  },
192
193
  };
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  AreProofsEnabled,
3
3
  ChildContainerProvider,
4
- ConfigurableModule,
5
- noop,
4
+ ConfigurableModule, NoConfig,
5
+ noop
6
6
  } from "@proto-kit/common";
7
7
 
8
8
  import { ProtocolEnvironment } from "./ProtocolEnvironment";
9
9
 
10
10
  export abstract class ProtocolModule<
11
- Config
11
+ Config = NoConfig
12
12
  > extends ConfigurableModule<Config> {
13
13
  public protocol?: ProtocolEnvironment;
14
14
 
@@ -0,0 +1,22 @@
1
+ import type { BlockProverState } from "../prover/block/BlockProver";
2
+ import { NetworkState } from "../model/network/NetworkState";
3
+
4
+ import { TransitioningProtocolModule } from "./TransitioningProtocolModule";
5
+
6
+ export interface BeforeBlockParameters {
7
+ state: BlockProverState;
8
+ networkState: NetworkState;
9
+ }
10
+
11
+ export interface AfterBlockParameters {
12
+ state: BlockProverState;
13
+ networkState: NetworkState;
14
+ }
15
+
16
+ // Purpose is to validate transition from -> to network state
17
+ export abstract class ProvableBlockHook<
18
+ Config
19
+ > extends TransitioningProtocolModule<Config> {
20
+ public abstract beforeBlock(blockData: BeforeBlockParameters): NetworkState;
21
+ public abstract afterBlock(blockData: AfterBlockParameters): NetworkState;
22
+ }
@@ -1,7 +1,10 @@
1
1
  import { BlockProverExecutionData } from "../prover/block/BlockProvable";
2
2
 
3
3
  import { TransitioningProtocolModule } from "./TransitioningProtocolModule";
4
+ import { NoConfig } from "@proto-kit/common";
4
5
 
5
- export abstract class ProvableTransactionHook<Config> extends TransitioningProtocolModule<Config> {
6
+ export abstract class ProvableTransactionHook<
7
+ Config = NoConfig
8
+ > extends TransitioningProtocolModule<Config> {
6
9
  public abstract onTransaction(executionData: BlockProverExecutionData): void;
7
10
  }
@@ -1,5 +1,9 @@
1
1
  import { ProtocolModule } from "./ProtocolModule";
2
2
 
3
+ /**
4
+ * A Protocolmodule that enables it's implementing module to access to
5
+ * StateTransitions and state
6
+ */
3
7
  export abstract class TransitioningProtocolModule<
4
8
  Config
5
9
  > extends ProtocolModule<Config> {
@@ -1,10 +1,11 @@
1
- import { Field, Proof, Struct } from "o1js";
1
+ import { Bool, Field, Proof, Struct } from "o1js";
2
2
  import { WithZkProgrammable } from "@proto-kit/common";
3
3
 
4
4
  import { StateTransitionProof } from "../statetransition/StateTransitionProvable";
5
5
  import { MethodPublicOutput } from "../../model/MethodPublicOutput";
6
6
  import { ProtocolTransaction } from "../../model/transaction/ProtocolTransaction";
7
7
  import { NetworkState } from "../../model/network/NetworkState";
8
+ import { BlockTransactionPosition } from "./BlockTransactionPosition";
8
9
 
9
10
  export class BlockProverPublicInput extends Struct({
10
11
  transactionsHash: Field,
@@ -15,6 +16,7 @@ export class BlockProverPublicInput extends Struct({
15
16
  export class BlockProverPublicOutput extends Struct({
16
17
  transactionsHash: Field,
17
18
  stateRoot: Field,
19
+ networkStateHash: Field,
18
20
  }) {}
19
21
 
20
22
  export type BlockProverProof = Proof<
@@ -25,7 +27,7 @@ export type BlockProverProof = Proof<
25
27
  export class BlockProverExecutionData extends Struct({
26
28
  transaction: ProtocolTransaction,
27
29
  networkState: NetworkState,
28
- // accountstate
30
+ transactionPosition: BlockTransactionPosition,
29
31
  }) {}
30
32
 
31
33
  export interface BlockProvable
@@ -1,5 +1,13 @@
1
1
  /* eslint-disable max-lines */
2
- import { Experimental, Field, type Proof, Provable, SelfProof } from "o1js";
2
+ import {
3
+ Bool,
4
+ Experimental,
5
+ Field,
6
+ type Proof,
7
+ Provable,
8
+ SelfProof,
9
+ Struct,
10
+ } from "o1js";
3
11
  import { container, inject, injectable, injectAll } from "tsyringe";
4
12
  import {
5
13
  AreProofsEnabled,
@@ -29,7 +37,9 @@ import {
29
37
  import { ProvableStateTransition } from "../../model/StateTransition";
30
38
  import { ProvableTransactionHook } from "../../protocol/ProvableTransactionHook";
31
39
  import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethodExecutionContext";
32
- import { Protocol, ProtocolModulesRecord } from "../../protocol/Protocol";
40
+ import { ProvableBlockHook } from "../../protocol/ProvableBlockHook";
41
+ import { NetworkState } from "../../model/network/NetworkState";
42
+ import { BlockTransactionPosition } from "./BlockTransactionPosition";
33
43
 
34
44
  const errors = {
35
45
  stateProofNotStartingAtZero: () =>
@@ -75,7 +85,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
75
85
  StateTransitionProverPublicOutput
76
86
  >,
77
87
  public readonly runtime: ZkProgrammable<undefined, MethodPublicOutput>,
78
- private readonly blockModules: ProvableTransactionHook<unknown>[]
88
+ private readonly transactionHooks: ProvableTransactionHook<unknown>[],
89
+ private readonly blockHooks: ProvableBlockHook<unknown>[]
79
90
  ) {
80
91
  super();
81
92
  }
@@ -165,17 +176,6 @@ export class BlockProverProgrammable extends ZkProgrammable<
165
176
  "Network state provided to BlockProver does not match the publicInput"
166
177
  );
167
178
 
168
- // Append tx to transaction list
169
- const transactionList = new DefaultProvableHashList(
170
- Field,
171
- state.transactionsHash
172
- );
173
-
174
- const { transactionHash } = appProof.publicOutput;
175
- transactionList.push(transactionHash);
176
-
177
- stateTo.transactionsHash = transactionList.commitment;
178
-
179
179
  return stateTo;
180
180
  }
181
181
 
@@ -204,7 +204,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
204
204
  });
205
205
  executionContext.beforeMethod("", "", []);
206
206
 
207
- this.blockModules.forEach((module) => {
207
+ this.transactionHooks.forEach((module) => {
208
208
  module.onTransaction(executionData);
209
209
  });
210
210
 
@@ -234,6 +234,83 @@ export class BlockProverProgrammable extends ZkProgrammable<
234
234
  );
235
235
  }
236
236
 
237
+ private getBeforeBlockNetworkState(
238
+ state: BlockProverState,
239
+ networkState: NetworkState
240
+ ) {
241
+ return this.blockHooks.reduce<NetworkState>((networkState, blockHook) => {
242
+ return blockHook.beforeBlock({
243
+ state,
244
+ networkState,
245
+ });
246
+ }, networkState);
247
+ }
248
+
249
+ private getAfterBlockNetworkState(
250
+ state: BlockProverState,
251
+ networkState: NetworkState
252
+ ) {
253
+ return this.blockHooks.reduce<NetworkState>((networkState, blockHook) => {
254
+ return blockHook.afterBlock({
255
+ state,
256
+ networkState,
257
+ });
258
+ }, networkState);
259
+ }
260
+
261
+ private addTransactionToBundle(
262
+ state: BlockProverState,
263
+ stateTransitionProof: StateTransitionProof,
264
+ appProof: Proof<void, MethodPublicOutput>,
265
+ executionData: BlockProverExecutionData
266
+ ): {
267
+ state: BlockProverState;
268
+ networkState: NetworkState;
269
+ bundleOpened: Bool;
270
+ bundleClosed: Bool;
271
+ } {
272
+ const { transactionPosition, networkState } = executionData;
273
+ const stateTo = {
274
+ ...state,
275
+ };
276
+
277
+ // Execute beforeBlook hooks and apply if it is the first tx of the bundle
278
+ const beforeHookResult = this.getBeforeBlockNetworkState(
279
+ state,
280
+ networkState
281
+ );
282
+ const bundleOpened = transactionPosition.equals(
283
+ BlockTransactionPosition.fromPositionType("FIRST")
284
+ );
285
+ const resultingNetworkState = new NetworkState(
286
+ Provable.if(bundleOpened, NetworkState, beforeHookResult, networkState)
287
+ );
288
+ stateTo.networkStateHash = resultingNetworkState.hash();
289
+
290
+ // TODO Modify bundle merkle tree as per specs
291
+
292
+ // Append tx to transaction list
293
+ const transactionList = new DefaultProvableHashList(
294
+ Field,
295
+ state.transactionsHash
296
+ );
297
+
298
+ const { transactionHash } = appProof.publicOutput;
299
+ transactionList.push(transactionHash);
300
+
301
+ stateTo.transactionsHash = transactionList.commitment;
302
+
303
+ return {
304
+ state: stateTo,
305
+ networkState: resultingNetworkState,
306
+ bundleOpened,
307
+
308
+ bundleClosed: transactionPosition.equals(
309
+ BlockTransactionPosition.fromPositionType("LAST")
310
+ ),
311
+ };
312
+ }
313
+
237
314
  @provableMethod()
238
315
  public proveTransaction(
239
316
  publicInput: BlockProverPublicInput,
@@ -247,16 +324,46 @@ export class BlockProverProgrammable extends ZkProgrammable<
247
324
  networkStateHash: publicInput.networkStateHash,
248
325
  };
249
326
 
250
- const stateTo = this.applyTransaction(
327
+ const bundleInclusionResult = this.addTransactionToBundle(
251
328
  state,
252
329
  stateProof,
253
330
  appProof,
254
331
  executionData
255
332
  );
256
333
 
334
+ const stateTo = this.applyTransaction(
335
+ bundleInclusionResult.state,
336
+ stateProof,
337
+ appProof,
338
+ {
339
+ transaction: executionData.transaction,
340
+ transactionPosition: executionData.transactionPosition,
341
+ networkState: bundleInclusionResult.networkState,
342
+ }
343
+ );
344
+
345
+ // Apply afterBlock hooks
346
+ const afterBlockNetworkState = this.getAfterBlockNetworkState(
347
+ stateTo,
348
+ bundleInclusionResult.networkState
349
+ );
350
+ const bundleClosed = executionData.transactionPosition.equals(
351
+ BlockTransactionPosition.fromPositionType("LAST")
352
+ );
353
+
354
+ // We only need the hash here since this computed networkstate
355
+ // is only used as an input in the next bundle
356
+ const resultingNetworkStateHash = Provable.if(
357
+ bundleClosed,
358
+ afterBlockNetworkState.hash(),
359
+ stateTo.networkStateHash
360
+ );
361
+
257
362
  return new BlockProverPublicOutput({
258
363
  stateRoot: stateTo.stateRoot,
259
364
  transactionsHash: stateTo.transactionsHash,
365
+ // eslint-disable-next-line putout/putout
366
+ networkStateHash: resultingNetworkStateHash,
260
367
  });
261
368
  }
262
369
 
@@ -294,7 +401,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
294
401
  proof1.publicInput.networkStateHash,
295
402
  errors.transactionsHashNotMatching("publicInput.from -> proof1.from")
296
403
  );
297
- publicInput.networkStateHash.assertEquals(
404
+ proof1.publicOutput.networkStateHash.assertEquals(
298
405
  proof2.publicInput.networkStateHash,
299
406
  errors.transactionsHashNotMatching("proof1.to -> proof2.from")
300
407
  );
@@ -302,6 +409,7 @@ export class BlockProverProgrammable extends ZkProgrammable<
302
409
  return new BlockProverPublicOutput({
303
410
  stateRoot: proof2.publicOutput.stateRoot,
304
411
  transactionsHash: proof2.publicOutput.transactionsHash,
412
+ networkStateHash: proof2.publicOutput.networkStateHash,
305
413
  });
306
414
  }
307
415
 
@@ -387,7 +495,10 @@ export class BlockProverProgrammable extends ZkProgrammable<
387
495
  * then be merged to be committed to the base-layer contract
388
496
  */
389
497
  @injectable()
390
- export class BlockProver extends ProtocolModule<object> implements BlockProvable {
498
+ export class BlockProver
499
+ extends ProtocolModule
500
+ implements BlockProvable
501
+ {
391
502
  public zkProgrammable: BlockProverProgrammable;
392
503
 
393
504
  public constructor(
@@ -399,15 +510,17 @@ export class BlockProver extends ProtocolModule<object> implements BlockProvable
399
510
  @inject("Runtime")
400
511
  public readonly runtime: WithZkProgrammable<undefined, MethodPublicOutput>,
401
512
  @injectAll("ProvableTransactionHook")
402
- transactionHooks: ProvableTransactionHook<unknown>[]
513
+ transactionHooks: ProvableTransactionHook<unknown>[],
514
+ @injectAll("ProvableBlockHook")
515
+ blockHooks: ProvableBlockHook<unknown>[]
403
516
  ) {
404
517
  super();
405
518
  this.zkProgrammable = new BlockProverProgrammable(
406
519
  this,
407
520
  stateTransitionProver.zkProgrammable,
408
521
  runtime.zkProgrammable,
409
- transactionHooks
410
- // protocol.dependencyContainer.resolveAll("P rovableTransactionHook")
522
+ transactionHooks,
523
+ blockHooks
411
524
  );
412
525
  }
413
526
 
@@ -0,0 +1,34 @@
1
+ import { Bool, Field, Struct } from "o1js";
2
+ import { match } from "ts-pattern";
3
+
4
+ export type BlockTransactionPositionType = "FIRST" | "LAST" | "MIDDLE";
5
+
6
+ export class BlockTransactionPosition extends Struct({
7
+ type: Field,
8
+ }) {
9
+ private static readonly fieldMapping: Record<
10
+ BlockTransactionPositionType,
11
+ number
12
+ > = {
13
+ FIRST: 0,
14
+ MIDDLE: 1,
15
+ LAST: 2,
16
+ };
17
+
18
+ public static fromPositionType(type: BlockTransactionPositionType) {
19
+ return new BlockTransactionPosition({
20
+ type: Field(BlockTransactionPosition.fieldMapping[type]).toConstant(),
21
+ });
22
+ }
23
+
24
+ public static positionTypeFromIndex(index: number, bundleLength: number) {
25
+ return match<number, BlockTransactionPositionType>(index)
26
+ .with(0, () => "FIRST")
27
+ .with(bundleLength - 1, () => "LAST")
28
+ .otherwise(() => "MIDDLE");
29
+ }
30
+
31
+ public equals(type: BlockTransactionPosition): Bool {
32
+ return this.type.equals(type.type);
33
+ }
34
+ }