@aztec/sequencer-client 0.34.0 → 0.35.0

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/dest/client/sequencer-client.d.ts.map +1 -1
  2. package/dest/client/sequencer-client.js +3 -3
  3. package/dest/config.d.ts.map +1 -1
  4. package/dest/config.js +84 -7
  5. package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
  6. package/dest/global_variable_builder/global_builder.js +4 -3
  7. package/dest/index.d.ts +0 -1
  8. package/dest/index.d.ts.map +1 -1
  9. package/dest/index.js +1 -2
  10. package/dest/sequencer/sequencer.d.ts +6 -7
  11. package/dest/sequencer/sequencer.d.ts.map +1 -1
  12. package/dest/sequencer/sequencer.js +10 -11
  13. package/dest/tx_validator/aggregate_tx_validator.d.ts +7 -0
  14. package/dest/tx_validator/aggregate_tx_validator.d.ts.map +1 -0
  15. package/dest/tx_validator/aggregate_tx_validator.js +23 -0
  16. package/dest/tx_validator/double_spend_validator.d.ts +11 -0
  17. package/dest/tx_validator/double_spend_validator.d.ts.map +1 -0
  18. package/dest/tx_validator/double_spend_validator.js +50 -0
  19. package/dest/tx_validator/gas_validator.d.ts +12 -0
  20. package/dest/tx_validator/gas_validator.d.ts.map +1 -0
  21. package/dest/tx_validator/gas_validator.js +62 -0
  22. package/dest/tx_validator/metadata_validator.d.ts +8 -0
  23. package/dest/tx_validator/metadata_validator.d.ts.map +1 -0
  24. package/dest/tx_validator/metadata_validator.js +50 -0
  25. package/dest/tx_validator/phases_validator.d.ts +13 -0
  26. package/dest/tx_validator/phases_validator.d.ts.map +1 -0
  27. package/dest/tx_validator/phases_validator.js +73 -0
  28. package/dest/tx_validator/tx_validator_factory.d.ts +13 -0
  29. package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -0
  30. package/dest/tx_validator/tx_validator_factory.js +21 -0
  31. package/package.json +14 -13
  32. package/src/client/sequencer-client.ts +2 -3
  33. package/src/config.ts +93 -7
  34. package/src/global_variable_builder/global_builder.ts +3 -2
  35. package/src/index.ts +0 -1
  36. package/src/sequencer/sequencer.ts +27 -20
  37. package/src/tx_validator/aggregate_tx_validator.ts +24 -0
  38. package/src/tx_validator/double_spend_validator.ts +65 -0
  39. package/src/tx_validator/gas_validator.ts +81 -0
  40. package/src/tx_validator/metadata_validator.ts +60 -0
  41. package/src/tx_validator/phases_validator.ts +101 -0
  42. package/src/tx_validator/tx_validator_factory.ts +37 -0
  43. package/dest/sequencer/abstract_phase_manager.d.ts +0 -77
  44. package/dest/sequencer/abstract_phase_manager.d.ts.map +0 -1
  45. package/dest/sequencer/abstract_phase_manager.js +0 -307
  46. package/dest/sequencer/app_logic_phase_manager.d.ts +0 -28
  47. package/dest/sequencer/app_logic_phase_manager.d.ts.map +0 -1
  48. package/dest/sequencer/app_logic_phase_manager.js +0 -41
  49. package/dest/sequencer/hints_builder.d.ts +0 -23
  50. package/dest/sequencer/hints_builder.d.ts.map +0 -1
  51. package/dest/sequencer/hints_builder.js +0 -62
  52. package/dest/sequencer/phase_manager_factory.d.ts +0 -18
  53. package/dest/sequencer/phase_manager_factory.d.ts.map +0 -1
  54. package/dest/sequencer/phase_manager_factory.js +0 -56
  55. package/dest/sequencer/public_processor.d.ts +0 -54
  56. package/dest/sequencer/public_processor.d.ts.map +0 -1
  57. package/dest/sequencer/public_processor.js +0 -142
  58. package/dest/sequencer/setup_phase_manager.d.ts +0 -28
  59. package/dest/sequencer/setup_phase_manager.d.ts.map +0 -1
  60. package/dest/sequencer/setup_phase_manager.js +0 -30
  61. package/dest/sequencer/tail_phase_manager.d.ts +0 -29
  62. package/dest/sequencer/tail_phase_manager.d.ts.map +0 -1
  63. package/dest/sequencer/tail_phase_manager.js +0 -52
  64. package/dest/sequencer/teardown_phase_manager.d.ts +0 -28
  65. package/dest/sequencer/teardown_phase_manager.d.ts.map +0 -1
  66. package/dest/sequencer/teardown_phase_manager.js +0 -30
  67. package/dest/sequencer/tx_validator.d.ts +0 -29
  68. package/dest/sequencer/tx_validator.d.ts.map +0 -1
  69. package/dest/sequencer/tx_validator.js +0 -174
  70. package/dest/sequencer/tx_validator_factory.d.ts +0 -12
  71. package/dest/sequencer/tx_validator_factory.d.ts.map +0 -1
  72. package/dest/sequencer/tx_validator_factory.js +0 -17
  73. package/dest/sequencer/utils.d.ts +0 -8
  74. package/dest/sequencer/utils.d.ts.map +0 -1
  75. package/dest/sequencer/utils.js +0 -29
  76. package/dest/simulator/index.d.ts +0 -31
  77. package/dest/simulator/index.d.ts.map +0 -1
  78. package/dest/simulator/index.js +0 -2
  79. package/dest/simulator/public_executor.d.ts +0 -79
  80. package/dest/simulator/public_executor.d.ts.map +0 -1
  81. package/dest/simulator/public_executor.js +0 -198
  82. package/dest/simulator/public_kernel.d.ts +0 -37
  83. package/dest/simulator/public_kernel.d.ts.map +0 -1
  84. package/dest/simulator/public_kernel.js +0 -97
  85. package/src/sequencer/abstract_phase_manager.ts +0 -549
  86. package/src/sequencer/app_logic_phase_manager.ts +0 -62
  87. package/src/sequencer/hints_builder.ts +0 -119
  88. package/src/sequencer/phase_manager_factory.ts +0 -126
  89. package/src/sequencer/public_processor.ts +0 -209
  90. package/src/sequencer/setup_phase_manager.ts +0 -50
  91. package/src/sequencer/tail_phase_manager.ts +0 -111
  92. package/src/sequencer/teardown_phase_manager.ts +0 -50
  93. package/src/sequencer/tx_validator.ts +0 -265
  94. package/src/sequencer/tx_validator_factory.ts +0 -32
  95. package/src/sequencer/utils.ts +0 -31
  96. package/src/simulator/index.ts +0 -36
  97. package/src/simulator/public_executor.ts +0 -267
  98. package/src/simulator/public_kernel.ts +0 -139
@@ -1,265 +0,0 @@
1
- import { type ProcessedTx, Tx } from '@aztec/circuit-types';
2
- import {
3
- type AztecAddress,
4
- type EthAddress,
5
- Fr,
6
- type GlobalVariables,
7
- type PublicCallRequest,
8
- } from '@aztec/circuits.js';
9
- import { pedersenHash } from '@aztec/foundation/crypto';
10
- import { type Logger, createDebugLogger } from '@aztec/foundation/log';
11
- import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';
12
- import { type ContractDataSource } from '@aztec/types/contracts';
13
-
14
- import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
15
-
16
- /** A source of what nullifiers have been committed to the state trees */
17
- export interface NullifierSource {
18
- getNullifierIndex: (nullifier: Fr) => Promise<bigint | undefined>;
19
- }
20
-
21
- /** Provides a view into public contract state */
22
- export interface PublicStateSource {
23
- storageRead: (contractAddress: AztecAddress, slot: Fr) => Promise<Fr>;
24
- }
25
-
26
- // prefer symbols over booleans so it's clear what the intention is
27
- // vs returning true/false is tied to the function name
28
- // eg. isDoubleSpend vs isValidChain assign different meanings to booleans
29
- const VALID_TX = Symbol('valid_tx');
30
- const INVALID_TX = Symbol('invalid_tx');
31
-
32
- type TxValidationStatus = typeof VALID_TX | typeof INVALID_TX;
33
-
34
- // the storage slot associated with "storage.balances"
35
- const GAS_TOKEN_BALANCES_SLOT = new Fr(1);
36
-
37
- type FeeValidationConfig = {
38
- gasPortalAddress: EthAddress;
39
- allowedFeePaymentContractClasses: Fr[];
40
- allowedFeePaymentContractInstances: AztecAddress[];
41
- };
42
-
43
- export class TxValidator {
44
- #log: Logger;
45
- #globalVariables: GlobalVariables;
46
- #nullifierSource: NullifierSource;
47
- #publicStateSource: PublicStateSource;
48
- #contractDataSource: ContractDataSource;
49
- #feeValidationConfig: FeeValidationConfig;
50
-
51
- constructor(
52
- nullifierSource: NullifierSource,
53
- publicStateSource: PublicStateSource,
54
- contractDataSource: ContractDataSource,
55
- globalVariables: GlobalVariables,
56
- feeValidationConfig: FeeValidationConfig,
57
- log = createDebugLogger('aztec:sequencer:tx_validator'),
58
- ) {
59
- this.#nullifierSource = nullifierSource;
60
- this.#publicStateSource = publicStateSource;
61
- this.#contractDataSource = contractDataSource;
62
- this.#globalVariables = globalVariables;
63
- this.#feeValidationConfig = feeValidationConfig;
64
- this.#log = log;
65
- }
66
-
67
- /**
68
- * Validates a list of transactions.
69
- * @param txs - The transactions to validate.
70
- * @returns A tuple of valid and invalid transactions.
71
- */
72
- public async validateTxs<T extends Tx | ProcessedTx>(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> {
73
- const validTxs: T[] = [];
74
- const invalidTxs: T[] = [];
75
- const thisBlockNullifiers = new Set<bigint>();
76
-
77
- for (const tx of txs) {
78
- if (this.#validateMetadata(tx) === INVALID_TX) {
79
- invalidTxs.push(tx);
80
- continue;
81
- }
82
-
83
- if ((await this.#validateNullifiers(tx, thisBlockNullifiers)) === INVALID_TX) {
84
- invalidTxs.push(tx);
85
- continue;
86
- }
87
-
88
- // skip already processed transactions
89
- if (tx instanceof Tx) {
90
- if ((await this.#validateFee(tx)) === INVALID_TX) {
91
- invalidTxs.push(tx);
92
- continue;
93
- }
94
- if ((await this.#validateGasBalance(tx)) === INVALID_TX) {
95
- invalidTxs.push(tx);
96
- continue;
97
- }
98
- }
99
-
100
- if (this.#validateMaxBlockNumber(tx) === INVALID_TX) {
101
- invalidTxs.push(tx);
102
- continue;
103
- }
104
-
105
- validTxs.push(tx);
106
- }
107
-
108
- return [validTxs, invalidTxs];
109
- }
110
-
111
- /**
112
- * It rejects transactions with the wrong chain id.
113
- * @param tx - The transaction.
114
- * @returns Whether the transaction is valid.
115
- */
116
- #validateMetadata(tx: Tx | ProcessedTx): TxValidationStatus {
117
- if (!tx.data.constants.txContext.chainId.equals(this.#globalVariables.chainId)) {
118
- this.#log.warn(
119
- `Rejecting tx ${Tx.getHash(
120
- tx,
121
- )} because of incorrect chain ${tx.data.constants.txContext.chainId.toString()} != ${this.#globalVariables.chainId.toString()}`,
122
- );
123
- return INVALID_TX;
124
- }
125
-
126
- return VALID_TX;
127
- }
128
-
129
- /**
130
- * It looks for duplicate nullifiers:
131
- * - in the same transaction
132
- * - in the same block
133
- * - in the nullifier tree
134
- *
135
- * Nullifiers prevent double spends in a private context.
136
- *
137
- * @param tx - The transaction.
138
- * @returns Whether this is a problematic double spend that the L1 contract would reject.
139
- */
140
- async #validateNullifiers(tx: Tx | ProcessedTx, thisBlockNullifiers: Set<bigint>): Promise<TxValidationStatus> {
141
- const newNullifiers = tx.data.getNonEmptyNullifiers().map(x => x.toBigInt());
142
-
143
- // Ditch this tx if it has repeated nullifiers
144
- const uniqueNullifiers = new Set(newNullifiers);
145
- if (uniqueNullifiers.size !== newNullifiers.length) {
146
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for emitting duplicate nullifiers`);
147
- return INVALID_TX;
148
- }
149
-
150
- for (const nullifier of newNullifiers) {
151
- if (thisBlockNullifiers.has(nullifier)) {
152
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier in the same block`);
153
- return INVALID_TX;
154
- }
155
-
156
- thisBlockNullifiers.add(nullifier);
157
- }
158
-
159
- const nullifierIndexes = await Promise.all(
160
- newNullifiers.map(n => this.#nullifierSource.getNullifierIndex(new Fr(n))),
161
- );
162
-
163
- const hasDuplicates = nullifierIndexes.some(index => index !== undefined);
164
- if (hasDuplicates) {
165
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating nullifiers present in state trees`);
166
- return INVALID_TX;
167
- }
168
-
169
- return VALID_TX;
170
- }
171
-
172
- async #validateGasBalance(tx: Tx): Promise<TxValidationStatus> {
173
- if (!tx.data.forPublic || !tx.data.forPublic.needsTeardown) {
174
- return VALID_TX;
175
- }
176
-
177
- const teardownFn = TxValidator.#extractFeeExecutionCall(tx)!;
178
-
179
- // TODO(#1204) if a generator index is used for the derived storage slot of a map, update it here as well
180
- const slot = pedersenHash([GAS_TOKEN_BALANCES_SLOT, teardownFn.callContext.msgSender]);
181
- const gasBalance = await this.#publicStateSource.storageRead(
182
- getCanonicalGasTokenAddress(this.#feeValidationConfig.gasPortalAddress),
183
- slot,
184
- );
185
-
186
- // TODO(#5004) calculate fee needed based on tx limits and gas prices
187
- const gasAmountNeeded = new Fr(1);
188
- if (gasBalance.lt(gasAmountNeeded)) {
189
- this.#log.warn(
190
- `Rejecting tx ${Tx.getHash(
191
- tx,
192
- )} because it should pay for gas but has insufficient balance ${gasBalance.toShortString()} < ${gasAmountNeeded.toShortString()}`,
193
- );
194
- return INVALID_TX;
195
- }
196
-
197
- return VALID_TX;
198
- }
199
-
200
- #validateMaxBlockNumber(tx: Tx | ProcessedTx): TxValidationStatus {
201
- const target =
202
- tx instanceof Tx
203
- ? tx.data.forRollup?.rollupValidationRequests || tx.data.forPublic!.validationRequests.forRollup
204
- : tx.data.rollupValidationRequests;
205
- const maxBlockNumber = target.maxBlockNumber;
206
-
207
- if (maxBlockNumber.isSome && maxBlockNumber.value < this.#globalVariables.blockNumber) {
208
- this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for low max block number`);
209
- return INVALID_TX;
210
- } else {
211
- return VALID_TX;
212
- }
213
- }
214
-
215
- async #validateFee(tx: Tx): Promise<TxValidationStatus> {
216
- if (!tx.data.forPublic || !tx.data.forPublic.needsTeardown) {
217
- // TODO check if fees are mandatory and reject this tx
218
- this.#log.debug(`Tx ${Tx.getHash(tx)} doesn't pay for gas`);
219
- return VALID_TX;
220
- }
221
-
222
- const teardownFn = TxValidator.#extractFeeExecutionCall(tx);
223
- if (!teardownFn) {
224
- this.#log.warn(
225
- `Rejecting tx ${Tx.getHash(tx)} because it should pay for gas but has no enqueued teardown function call`,
226
- );
227
- return INVALID_TX;
228
- }
229
-
230
- const fpcAddress = teardownFn.contractAddress;
231
- const contractClass = await this.#contractDataSource.getContract(fpcAddress);
232
-
233
- if (!contractClass) {
234
- return INVALID_TX;
235
- }
236
-
237
- if (fpcAddress.equals(getCanonicalGasTokenAddress(this.#feeValidationConfig.gasPortalAddress))) {
238
- return VALID_TX;
239
- }
240
-
241
- for (const allowedContract of this.#feeValidationConfig.allowedFeePaymentContractInstances) {
242
- if (fpcAddress.equals(allowedContract)) {
243
- return VALID_TX;
244
- }
245
- }
246
-
247
- for (const allowedContractClass of this.#feeValidationConfig.allowedFeePaymentContractClasses) {
248
- if (contractClass.contractClassId.equals(allowedContractClass)) {
249
- return VALID_TX;
250
- }
251
- }
252
-
253
- return INVALID_TX;
254
- }
255
-
256
- static #extractFeeExecutionCall(tx: Tx): PublicCallRequest | undefined {
257
- const {
258
- // TODO what if there's more than one function call?
259
- // if we're to enshrine that teardown = 1 function call, then we should turn this into a single function call
260
- [PublicKernelPhase.TEARDOWN]: [teardownFn],
261
- } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx.data, tx.enqueuedPublicFunctionCalls);
262
-
263
- return teardownFn;
264
- }
265
- }
@@ -1,32 +0,0 @@
1
- import { type AztecAddress, type EthAddress, type Fr, type GlobalVariables } from '@aztec/circuits.js';
2
- import { type ContractDataSource } from '@aztec/types/contracts';
3
- import { type MerkleTreeOperations } from '@aztec/world-state';
4
-
5
- import { WorldStateDB, WorldStatePublicDB } from '../simulator/public_executor.js';
6
- import { TxValidator } from './tx_validator.js';
7
-
8
- export class TxValidatorFactory {
9
- constructor(
10
- private merkleTreeDb: MerkleTreeOperations,
11
- private contractDataSource: ContractDataSource,
12
- private gasPortalAddress: EthAddress,
13
- ) {}
14
-
15
- buildTxValidator(
16
- globalVariables: GlobalVariables,
17
- allowedFeePaymentContractClasses: Fr[],
18
- allowedFeePaymentContractInstances: AztecAddress[],
19
- ): TxValidator {
20
- return new TxValidator(
21
- new WorldStateDB(this.merkleTreeDb),
22
- new WorldStatePublicDB(this.merkleTreeDb),
23
- this.contractDataSource,
24
- globalVariables,
25
- {
26
- allowedFeePaymentContractClasses,
27
- allowedFeePaymentContractInstances,
28
- gasPortalAddress: this.gasPortalAddress,
29
- },
30
- );
31
- }
32
- }
@@ -1,31 +0,0 @@
1
- import { type Tx } from '@aztec/circuit-types';
2
- import { CallRequest } from '@aztec/circuits.js';
3
-
4
- /**
5
- * Looks at the side effects of a transaction and returns the highest counter
6
- * @param tx - A transaction
7
- * @returns The highest side effect counter in the transaction so far
8
- */
9
- export function lastSideEffectCounter(tx: Tx): number {
10
- const data = tx.data.forPublic!;
11
- const sideEffectCounters = [
12
- ...data.endNonRevertibleData.newNoteHashes,
13
- ...data.endNonRevertibleData.newNullifiers,
14
- ...data.endNonRevertibleData.publicCallStack,
15
- ...data.end.newNoteHashes,
16
- ...data.end.newNullifiers,
17
- ...data.end.publicCallStack,
18
- ];
19
-
20
- let max = 0;
21
- for (const sideEffect of sideEffectCounters) {
22
- if (sideEffect instanceof CallRequest) {
23
- // look at both start and end counters because for enqueued public calls start > 0 while end === 0
24
- max = Math.max(max, sideEffect.startSideEffectCounter.toNumber(), sideEffect.endSideEffectCounter.toNumber());
25
- } else {
26
- max = Math.max(max, sideEffect.counter.toNumber());
27
- }
28
- }
29
-
30
- return max;
31
- }
@@ -1,36 +0,0 @@
1
- import {
2
- type KernelCircuitPublicInputs,
3
- type PublicKernelCircuitPrivateInputs,
4
- type PublicKernelCircuitPublicInputs,
5
- type PublicKernelTailCircuitPrivateInputs,
6
- } from '@aztec/circuits.js';
7
-
8
- /**
9
- * Circuit simulator for the public kernel circuits.
10
- */
11
- export interface PublicKernelCircuitSimulator {
12
- /**
13
- * Simulates the public kernel setup circuit from its inputs.
14
- * @param inputs - Inputs to the circuit.
15
- * @returns The public inputs as outputs of the simulation.
16
- */
17
- publicKernelCircuitSetup(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
18
- /**
19
- * Simulates the public kernel app logic circuit from its inputs.
20
- * @param inputs - Inputs to the circuit.
21
- * @returns The public inputs as outputs of the simulation.
22
- */
23
- publicKernelCircuitAppLogic(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
24
- /**
25
- * Simulates the public kernel teardown circuit from its inputs.
26
- * @param inputs - Inputs to the circuit.
27
- * @returns The public inputs as outputs of the simulation.
28
- */
29
- publicKernelCircuitTeardown(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
30
- /**
31
- * Simulates the public kernel tail circuit from its inputs.
32
- * @param inputs - Inputs to the circuit.
33
- * @returns The public inputs as outputs of the simulation.
34
- */
35
- publicKernelCircuitTail(inputs: PublicKernelTailCircuitPrivateInputs): Promise<KernelCircuitPublicInputs>;
36
- }
@@ -1,267 +0,0 @@
1
- import { MerkleTreeId, NullifierMembershipWitness, type Tx } from '@aztec/circuit-types';
2
- import {
3
- type AztecAddress,
4
- ContractClassRegisteredEvent,
5
- ContractInstanceDeployedEvent,
6
- type EthAddress,
7
- Fr,
8
- type FunctionSelector,
9
- type L1_TO_L2_MSG_TREE_HEIGHT,
10
- type NULLIFIER_TREE_HEIGHT,
11
- type NullifierLeafPreimage,
12
- type PublicDataTreeLeafPreimage,
13
- } from '@aztec/circuits.js';
14
- import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
15
- import { createDebugLogger } from '@aztec/foundation/log';
16
- import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
17
- import {
18
- type CommitmentsDB,
19
- MessageLoadOracleInputs,
20
- type PublicContractsDB,
21
- type PublicStateDB,
22
- } from '@aztec/simulator';
23
- import {
24
- type ContractClassPublic,
25
- type ContractDataSource,
26
- type ContractInstanceWithAddress,
27
- } from '@aztec/types/contracts';
28
- import { type MerkleTreeOperations } from '@aztec/world-state';
29
-
30
- /**
31
- * Implements the PublicContractsDB using a ContractDataSource.
32
- * Progressively records contracts in transaction as they are processed in a block.
33
- */
34
- export class ContractsDataSourcePublicDB implements PublicContractsDB {
35
- private instanceCache = new Map<string, ContractInstanceWithAddress>();
36
- private classCache = new Map<string, ContractClassPublic>();
37
-
38
- private log = createDebugLogger('aztec:sequencer:contracts-data-source');
39
-
40
- constructor(private db: ContractDataSource) {}
41
-
42
- /**
43
- * Add new contracts from a transaction
44
- * @param tx - The transaction to add contracts from.
45
- */
46
- public addNewContracts(tx: Tx): Promise<void> {
47
- // Extract contract class and instance data from logs and add to cache for this block
48
- const logs = tx.unencryptedLogs.unrollLogs();
49
- ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e => {
50
- this.log.debug(`Adding class ${e.contractClassId.toString()} to public execution contract cache`);
51
- this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic());
52
- });
53
- ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => {
54
- this.log.debug(
55
- `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to public execution contract cache`,
56
- );
57
- this.instanceCache.set(e.address.toString(), e.toContractInstance());
58
- });
59
-
60
- return Promise.resolve();
61
- }
62
-
63
- /**
64
- * Removes new contracts added from transactions
65
- * @param tx - The tx's contracts to be removed
66
- */
67
- public removeNewContracts(tx: Tx): Promise<void> {
68
- // TODO(@spalladino): Can this inadvertently delete a valid contract added by another tx?
69
- // Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts,
70
- // wouldn't that accidentally remove the contract added on the first one?
71
- const logs = tx.unencryptedLogs.unrollLogs();
72
- ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e =>
73
- this.classCache.delete(e.contractClassId.toString()),
74
- );
75
- ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => this.instanceCache.delete(e.address.toString()));
76
- return Promise.resolve();
77
- }
78
-
79
- public async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
80
- return this.instanceCache.get(address.toString()) ?? (await this.db.getContract(address));
81
- }
82
-
83
- public async getContractClass(contractClassId: Fr): Promise<ContractClassPublic | undefined> {
84
- return this.classCache.get(contractClassId.toString()) ?? (await this.db.getContractClass(contractClassId));
85
- }
86
-
87
- async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
88
- const instance = await this.getContractInstance(address);
89
- if (!instance) {
90
- throw new Error(`Contract ${address.toString()} not found`);
91
- }
92
- const contractClass = await this.getContractClass(instance.contractClassId);
93
- if (!contractClass) {
94
- throw new Error(`Contract class ${instance.contractClassId.toString()} for ${address.toString()} not found`);
95
- }
96
- return contractClass.publicFunctions.find(f => f.selector.equals(selector))?.bytecode;
97
- }
98
-
99
- async getPortalContractAddress(address: AztecAddress): Promise<EthAddress | undefined> {
100
- const contract = await this.getContractInstance(address);
101
- return contract?.portalContractAddress;
102
- }
103
- }
104
-
105
- /**
106
- * Implements the PublicStateDB using a world-state database.
107
- */
108
- export class WorldStatePublicDB implements PublicStateDB {
109
- private committedWriteCache: Map<bigint, Fr> = new Map();
110
- private checkpointedWriteCache: Map<bigint, Fr> = new Map();
111
- private uncommittedWriteCache: Map<bigint, Fr> = new Map();
112
-
113
- constructor(private db: MerkleTreeOperations) {}
114
-
115
- /**
116
- * Reads a value from public storage, returning zero if none.
117
- * @param contract - Owner of the storage.
118
- * @param slot - Slot to read in the contract storage.
119
- * @returns The current value in the storage slot.
120
- */
121
- public async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
122
- const leafSlot = computePublicDataTreeLeafSlot(contract, slot).value;
123
- const uncommitted = this.uncommittedWriteCache.get(leafSlot);
124
- if (uncommitted !== undefined) {
125
- return uncommitted;
126
- }
127
- const checkpointed = this.checkpointedWriteCache.get(leafSlot);
128
- if (checkpointed !== undefined) {
129
- return checkpointed;
130
- }
131
- const committed = this.committedWriteCache.get(leafSlot);
132
- if (committed !== undefined) {
133
- return committed;
134
- }
135
-
136
- const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
137
- if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
138
- return Fr.ZERO;
139
- }
140
-
141
- const preimage = (await this.db.getLeafPreimage(
142
- MerkleTreeId.PUBLIC_DATA_TREE,
143
- lowLeafResult.index,
144
- )) as PublicDataTreeLeafPreimage;
145
-
146
- return preimage.value;
147
- }
148
-
149
- /**
150
- * Records a write to public storage.
151
- * @param contract - Owner of the storage.
152
- * @param slot - Slot to read in the contract storage.
153
- * @param newValue - The new value to store.
154
- */
155
- public storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<void> {
156
- const index = computePublicDataTreeLeafSlot(contract, slot).value;
157
- this.uncommittedWriteCache.set(index, newValue);
158
- return Promise.resolve();
159
- }
160
-
161
- /**
162
- * Commit the pending changes to the DB.
163
- * @returns Nothing.
164
- */
165
- commit(): Promise<void> {
166
- for (const [k, v] of this.checkpointedWriteCache) {
167
- this.committedWriteCache.set(k, v);
168
- }
169
- // uncommitted writes take precedence over checkpointed writes
170
- // since they are the most recent
171
- for (const [k, v] of this.uncommittedWriteCache) {
172
- this.committedWriteCache.set(k, v);
173
- }
174
- return this.rollbackToCommit();
175
- }
176
-
177
- /**
178
- * Rollback the pending changes.
179
- * @returns Nothing.
180
- */
181
- async rollbackToCommit(): Promise<void> {
182
- await this.rollbackToCheckpoint();
183
- this.checkpointedWriteCache = new Map<bigint, Fr>();
184
- return Promise.resolve();
185
- }
186
-
187
- checkpoint(): Promise<void> {
188
- for (const [k, v] of this.uncommittedWriteCache) {
189
- this.checkpointedWriteCache.set(k, v);
190
- }
191
- return this.rollbackToCheckpoint();
192
- }
193
-
194
- rollbackToCheckpoint(): Promise<void> {
195
- this.uncommittedWriteCache = new Map<bigint, Fr>();
196
- return Promise.resolve();
197
- }
198
- }
199
-
200
- /**
201
- * Implements WorldState db using a world state database.
202
- */
203
- export class WorldStateDB implements CommitmentsDB {
204
- constructor(private db: MerkleTreeOperations) {}
205
-
206
- public async getNullifierMembershipWitnessAtLatestBlock(
207
- nullifier: Fr,
208
- ): Promise<NullifierMembershipWitness | undefined> {
209
- const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
210
- if (!index) {
211
- return undefined;
212
- }
213
-
214
- const leafPreimagePromise = this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
215
- const siblingPathPromise = this.db.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
216
- MerkleTreeId.NULLIFIER_TREE,
217
- BigInt(index),
218
- );
219
-
220
- const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
221
-
222
- if (!leafPreimage) {
223
- return undefined;
224
- }
225
-
226
- return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath);
227
- }
228
-
229
- public async getL1ToL2MembershipWitness(
230
- contractAddress: AztecAddress,
231
- messageHash: Fr,
232
- secret: Fr,
233
- ): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> {
234
- let nullifierIndex: bigint | undefined;
235
- let messageIndex: bigint | undefined;
236
- let startIndex = 0n;
237
-
238
- // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> we need to check
239
- // for nullifiers because messages can have duplicates.
240
- do {
241
- messageIndex = (await this.db.findLeafIndexAfter(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageHash, startIndex))!;
242
- if (messageIndex === undefined) {
243
- throw new Error(`No non-nullified L1 to L2 message found for message hash ${messageHash.toString()}`);
244
- }
245
-
246
- const messageNullifier = computeL1ToL2MessageNullifier(contractAddress, messageHash, secret, messageIndex);
247
- nullifierIndex = await this.getNullifierIndex(messageNullifier);
248
-
249
- startIndex = messageIndex + 1n;
250
- } while (nullifierIndex !== undefined);
251
-
252
- const siblingPath = await this.db.getSiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>(
253
- MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
254
- messageIndex,
255
- );
256
-
257
- return new MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>(messageIndex, siblingPath);
258
- }
259
-
260
- public async getCommitmentIndex(commitment: Fr): Promise<bigint | undefined> {
261
- return await this.db.findLeafIndex(MerkleTreeId.NOTE_HASH_TREE, commitment);
262
- }
263
-
264
- public async getNullifierIndex(nullifier: Fr): Promise<bigint | undefined> {
265
- return await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
266
- }
267
- }