@aztec/txe 0.70.0 → 0.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +5 -3
- package/dest/node/txe_node.d.ts +16 -11
- package/dest/node/txe_node.d.ts.map +1 -1
- package/dest/node/txe_node.js +76 -48
- package/dest/oracle/txe_oracle.d.ts +14 -26
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +69 -71
- package/dest/txe_service/txe_service.d.ts +10 -14
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +23 -32
- package/package.json +14 -14
- package/src/index.ts +4 -2
- package/src/node/txe_node.ts +115 -63
- package/src/oracle/txe_oracle.ts +105 -80
- package/src/txe_service/txe_service.ts +39 -32
package/src/node/txe_node.ts
CHANGED
|
@@ -2,9 +2,11 @@ import { createLogger } from '@aztec/aztec.js';
|
|
|
2
2
|
import {
|
|
3
3
|
type AztecNode,
|
|
4
4
|
type EpochProofQuote,
|
|
5
|
-
type
|
|
5
|
+
type GetContractClassLogsResponse,
|
|
6
|
+
type GetPublicLogsResponse,
|
|
6
7
|
type InBlock,
|
|
7
8
|
type L2Block,
|
|
9
|
+
L2BlockHash,
|
|
8
10
|
type L2BlockNumber,
|
|
9
11
|
type L2Tips,
|
|
10
12
|
type LogFilter,
|
|
@@ -18,10 +20,9 @@ import {
|
|
|
18
20
|
type Tx,
|
|
19
21
|
type TxEffect,
|
|
20
22
|
TxHash,
|
|
21
|
-
|
|
23
|
+
TxReceipt,
|
|
22
24
|
TxScopedL2Log,
|
|
23
25
|
type TxValidationResult,
|
|
24
|
-
type UnencryptedL2Log,
|
|
25
26
|
} from '@aztec/circuit-types';
|
|
26
27
|
import {
|
|
27
28
|
type ARCHIVE_HEIGHT,
|
|
@@ -35,31 +36,38 @@ import {
|
|
|
35
36
|
type NULLIFIER_TREE_HEIGHT,
|
|
36
37
|
type NodeInfo,
|
|
37
38
|
type PUBLIC_DATA_TREE_HEIGHT,
|
|
39
|
+
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
38
40
|
type PrivateLog,
|
|
39
41
|
type ProtocolContractAddresses,
|
|
42
|
+
type PublicLog,
|
|
40
43
|
} from '@aztec/circuits.js';
|
|
41
44
|
import { type L1ContractAddresses } from '@aztec/ethereum';
|
|
45
|
+
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
42
46
|
import { Fr } from '@aztec/foundation/fields';
|
|
47
|
+
import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
|
|
43
48
|
|
|
44
49
|
export class TXENode implements AztecNode {
|
|
45
50
|
#logsByTags = new Map<string, TxScopedL2Log[]>();
|
|
46
|
-
#txEffectsByTxHash = new Map<string, InBlock<TxEffect
|
|
51
|
+
#txEffectsByTxHash = new Map<string, InBlock<TxEffect>>();
|
|
52
|
+
#txReceiptsByTxHash = new Map<string, TxReceipt>();
|
|
47
53
|
#blockNumberToNullifiers = new Map<number, Fr[]>();
|
|
48
54
|
#noteIndex = 0;
|
|
49
55
|
|
|
50
|
-
#blockNumber: number;
|
|
51
56
|
#logger = createLogger('aztec:txe_node');
|
|
52
57
|
|
|
53
|
-
constructor(
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
constructor(
|
|
59
|
+
private blockNumber: number,
|
|
60
|
+
private version: number,
|
|
61
|
+
private chainId: number,
|
|
62
|
+
private trees: MerkleTrees,
|
|
63
|
+
) {}
|
|
56
64
|
|
|
57
65
|
/**
|
|
58
66
|
* Fetches the current block number.
|
|
59
67
|
* @returns The block number.
|
|
60
68
|
*/
|
|
61
69
|
getBlockNumber(): Promise<number> {
|
|
62
|
-
return Promise.resolve(this
|
|
70
|
+
return Promise.resolve(this.blockNumber);
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
/**
|
|
@@ -67,7 +75,7 @@ export class TXENode implements AztecNode {
|
|
|
67
75
|
* @param - The block number to set.
|
|
68
76
|
*/
|
|
69
77
|
setBlockNumber(blockNumber: number) {
|
|
70
|
-
this
|
|
78
|
+
this.blockNumber = blockNumber;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
/**
|
|
@@ -76,23 +84,42 @@ export class TXENode implements AztecNode {
|
|
|
76
84
|
* @returns The requested tx effect.
|
|
77
85
|
*/
|
|
78
86
|
getTxEffect(txHash: TxHash): Promise<InBlock<TxEffect> | undefined> {
|
|
79
|
-
const txEffect = this.#txEffectsByTxHash.get(
|
|
87
|
+
const txEffect = this.#txEffectsByTxHash.get(txHash.toString());
|
|
80
88
|
|
|
81
89
|
return Promise.resolve(txEffect);
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
/**
|
|
85
|
-
* Sets a tx effect for a given block number.
|
|
93
|
+
* Sets a tx effect and receipt for a given block number.
|
|
86
94
|
* @param blockNumber - The block number that this tx effect resides.
|
|
87
95
|
* @param txHash - The transaction hash of the transaction.
|
|
88
96
|
* @param effect - The tx effect to set.
|
|
89
97
|
*/
|
|
90
98
|
setTxEffect(blockNumber: number, txHash: TxHash, effect: TxEffect) {
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
// We are not creating real blocks on which membership proofs can be constructed - we instead define its hash as
|
|
100
|
+
// simply the hash of the block number.
|
|
101
|
+
const blockHash = poseidon2Hash([blockNumber]);
|
|
102
|
+
|
|
103
|
+
this.#txEffectsByTxHash.set(txHash.toString(), {
|
|
104
|
+
l2BlockHash: blockHash.toString(),
|
|
93
105
|
l2BlockNumber: blockNumber,
|
|
94
106
|
data: effect,
|
|
95
107
|
});
|
|
108
|
+
|
|
109
|
+
// We also set the receipt since we want to be able to serve `getTxReceipt` - we don't care about most values here,
|
|
110
|
+
// but we do need to be able to retrieve the block number of a given txHash.
|
|
111
|
+
this.#txReceiptsByTxHash.set(
|
|
112
|
+
txHash.toString(),
|
|
113
|
+
new TxReceipt(
|
|
114
|
+
txHash,
|
|
115
|
+
TxReceipt.statusFromRevertCode(effect.revertCode),
|
|
116
|
+
'',
|
|
117
|
+
undefined,
|
|
118
|
+
new L2BlockHash(blockHash.toBuffer()),
|
|
119
|
+
blockNumber,
|
|
120
|
+
undefined,
|
|
121
|
+
),
|
|
122
|
+
);
|
|
96
123
|
}
|
|
97
124
|
|
|
98
125
|
/**
|
|
@@ -167,45 +194,48 @@ export class TXENode implements AztecNode {
|
|
|
167
194
|
/**
|
|
168
195
|
* Adds public logs to the txe node, given a block
|
|
169
196
|
* @param blockNumber - The block number at which to add the public logs.
|
|
170
|
-
* @param
|
|
171
|
-
*/
|
|
172
|
-
addPublicLogsByTags(blockNumber: number,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
* @param publicLogs - The public logs to be added.
|
|
198
|
+
*/
|
|
199
|
+
addPublicLogsByTags(blockNumber: number, publicLogs: PublicLog[]) {
|
|
200
|
+
publicLogs.forEach(log => {
|
|
201
|
+
// Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
|
|
202
|
+
const firstFieldBuf = log.log[0].toBuffer();
|
|
203
|
+
if (
|
|
204
|
+
!firstFieldBuf.subarray(0, 24).equals(Buffer.alloc(24)) ||
|
|
205
|
+
firstFieldBuf[26] !== 0 ||
|
|
206
|
+
firstFieldBuf[29] !== 0
|
|
207
|
+
) {
|
|
208
|
+
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
209
|
+
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1], 0, ciphertextLen[0], ciphertextLen[1]]
|
|
210
|
+
this.#logger.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
177
211
|
return;
|
|
178
212
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
const tag = new Fr(correctedBuffer);
|
|
190
|
-
|
|
191
|
-
this.#logger.verbose(
|
|
192
|
-
`Found tagged unencrypted log with tag ${tag.toString()} in block ${this.getBlockNumber()}`,
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
|
|
196
|
-
const scopedLog = new TxScopedL2Log(
|
|
197
|
-
new TxHash(new Fr(blockNumber)),
|
|
198
|
-
this.#noteIndex,
|
|
199
|
-
blockNumber,
|
|
200
|
-
true,
|
|
201
|
-
log.toBuffer(),
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
currentLogs.push(scopedLog);
|
|
205
|
-
this.#logsByTags.set(tag.toString(), currentLogs);
|
|
206
|
-
} catch (err) {
|
|
207
|
-
this.#logger.warn(`Failed to add tagged log to store: ${err}`);
|
|
213
|
+
// Check that the length values line up with the log contents
|
|
214
|
+
const publicValuesLength = firstFieldBuf.subarray(-8).readUint16BE();
|
|
215
|
+
const privateValuesLength = firstFieldBuf.subarray(-8).readUint16BE(3);
|
|
216
|
+
// Add 1 for the first field holding lengths
|
|
217
|
+
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
218
|
+
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
219
|
+
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
220
|
+
this.#logger.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
221
|
+
return;
|
|
208
222
|
}
|
|
223
|
+
// The first elt stores lengths => tag is in fields[1]
|
|
224
|
+
const tag = log.log[1];
|
|
225
|
+
|
|
226
|
+
this.#logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.getBlockNumber()}`);
|
|
227
|
+
|
|
228
|
+
const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
|
|
229
|
+
const scopedLog = new TxScopedL2Log(
|
|
230
|
+
new TxHash(new Fr(blockNumber)),
|
|
231
|
+
this.#noteIndex,
|
|
232
|
+
blockNumber,
|
|
233
|
+
true,
|
|
234
|
+
log.toBuffer(),
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
currentLogs.push(scopedLog);
|
|
238
|
+
this.#logsByTags.set(tag.toString(), currentLogs);
|
|
209
239
|
});
|
|
210
240
|
}
|
|
211
241
|
/**
|
|
@@ -234,12 +264,29 @@ export class TXENode implements AztecNode {
|
|
|
234
264
|
* @param leafValue - The values to search for
|
|
235
265
|
* @returns The indexes of the given leaves in the given tree or undefined if not found.
|
|
236
266
|
*/
|
|
237
|
-
findLeavesIndexes(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
267
|
+
async findLeavesIndexes(
|
|
268
|
+
blockNumber: L2BlockNumber,
|
|
269
|
+
treeId: MerkleTreeId,
|
|
270
|
+
leafValues: Fr[],
|
|
241
271
|
): Promise<(bigint | undefined)[]> {
|
|
242
|
-
|
|
272
|
+
// Temporary workaround to be able to respond this query: the trees are currently stored in the TXE oracle, but we
|
|
273
|
+
// hold a reference to them.
|
|
274
|
+
// We should likely migrate this so that the trees are owned by the node.
|
|
275
|
+
|
|
276
|
+
// TODO: blockNumber is being passed as undefined, figure out why
|
|
277
|
+
if (blockNumber === 'latest' || blockNumber === undefined) {
|
|
278
|
+
blockNumber = await this.getBlockNumber();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const db =
|
|
282
|
+
blockNumber === (await this.getBlockNumber())
|
|
283
|
+
? await this.trees.getLatest()
|
|
284
|
+
: new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
|
|
285
|
+
|
|
286
|
+
return await db.findLeafIndices(
|
|
287
|
+
treeId,
|
|
288
|
+
leafValues.map(x => x.toBuffer()),
|
|
289
|
+
);
|
|
243
290
|
}
|
|
244
291
|
|
|
245
292
|
/**
|
|
@@ -420,7 +467,7 @@ export class TXENode implements AztecNode {
|
|
|
420
467
|
* @returns The rollup version.
|
|
421
468
|
*/
|
|
422
469
|
getVersion(): Promise<number> {
|
|
423
|
-
|
|
470
|
+
return Promise.resolve(this.version);
|
|
424
471
|
}
|
|
425
472
|
|
|
426
473
|
/**
|
|
@@ -428,7 +475,7 @@ export class TXENode implements AztecNode {
|
|
|
428
475
|
* @returns The chain id.
|
|
429
476
|
*/
|
|
430
477
|
getChainId(): Promise<number> {
|
|
431
|
-
|
|
478
|
+
return Promise.resolve(this.chainId);
|
|
432
479
|
}
|
|
433
480
|
|
|
434
481
|
/**
|
|
@@ -456,12 +503,12 @@ export class TXENode implements AztecNode {
|
|
|
456
503
|
}
|
|
457
504
|
|
|
458
505
|
/**
|
|
459
|
-
* Gets
|
|
506
|
+
* Gets public logs based on the provided filter.
|
|
460
507
|
* @param filter - The filter to apply to the logs.
|
|
461
508
|
* @returns The requested logs.
|
|
462
509
|
*/
|
|
463
|
-
|
|
464
|
-
throw new Error('TXE Node method
|
|
510
|
+
getPublicLogs(_filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
511
|
+
throw new Error('TXE Node method getPublicLogs not implemented');
|
|
465
512
|
}
|
|
466
513
|
|
|
467
514
|
/**
|
|
@@ -469,7 +516,7 @@ export class TXENode implements AztecNode {
|
|
|
469
516
|
* @param filter - The filter to apply to the logs.
|
|
470
517
|
* @returns The requested logs.
|
|
471
518
|
*/
|
|
472
|
-
getContractClassLogs(_filter: LogFilter): Promise<
|
|
519
|
+
getContractClassLogs(_filter: LogFilter): Promise<GetContractClassLogsResponse> {
|
|
473
520
|
throw new Error('TXE Node method getContractClassLogs not implemented');
|
|
474
521
|
}
|
|
475
522
|
|
|
@@ -490,8 +537,13 @@ export class TXENode implements AztecNode {
|
|
|
490
537
|
* @param txHash - The transaction hash.
|
|
491
538
|
* @returns A receipt of the transaction.
|
|
492
539
|
*/
|
|
493
|
-
getTxReceipt(
|
|
494
|
-
|
|
540
|
+
getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
|
|
541
|
+
const txEffect = this.#txReceiptsByTxHash.get(txHash.toString());
|
|
542
|
+
if (!txEffect) {
|
|
543
|
+
throw new Error('Unknown txHash');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return Promise.resolve(txEffect);
|
|
495
547
|
}
|
|
496
548
|
|
|
497
549
|
/**
|
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
PublicDataTreeLeaf,
|
|
36
36
|
type PublicDataTreeLeafPreimage,
|
|
37
37
|
type PublicDataWrite,
|
|
38
|
+
type PublicLog,
|
|
38
39
|
computeContractClassId,
|
|
39
40
|
computeTaggingSecretPoint,
|
|
40
41
|
deriveKeys,
|
|
@@ -84,7 +85,6 @@ import {
|
|
|
84
85
|
createSimulationError,
|
|
85
86
|
resolveAssertionMessageFromError,
|
|
86
87
|
} from '@aztec/simulator/server';
|
|
87
|
-
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
88
88
|
import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
|
|
89
89
|
|
|
90
90
|
import { TXENode } from '../node/txe_node.js';
|
|
@@ -95,7 +95,6 @@ import { TXEWorldStateDB } from '../util/txe_world_state_db.js';
|
|
|
95
95
|
export class TXE implements TypedOracle {
|
|
96
96
|
private blockNumber = 0;
|
|
97
97
|
private sideEffectCounter = 0;
|
|
98
|
-
private contractAddress: AztecAddress;
|
|
99
98
|
private msgSender: AztecAddress;
|
|
100
99
|
private functionSelector = FunctionSelector.fromField(new Fr(0));
|
|
101
100
|
private isStaticCall = false;
|
|
@@ -105,17 +104,17 @@ export class TXE implements TypedOracle {
|
|
|
105
104
|
private contractDataOracle: ContractDataOracle;
|
|
106
105
|
private simulatorOracle: SimulatorOracle;
|
|
107
106
|
|
|
108
|
-
private version: Fr = Fr.ONE;
|
|
109
|
-
private chainId: Fr = Fr.ONE;
|
|
110
|
-
|
|
111
107
|
private uniqueNoteHashesFromPublic: Fr[] = [];
|
|
112
108
|
private siloedNullifiersFromPublic: Fr[] = [];
|
|
113
109
|
private privateLogs: PrivateLog[] = [];
|
|
114
|
-
private publicLogs:
|
|
110
|
+
private publicLogs: PublicLog[] = [];
|
|
115
111
|
|
|
116
112
|
private committedBlocks = new Set<number>();
|
|
117
113
|
|
|
118
|
-
private
|
|
114
|
+
private VERSION = 1;
|
|
115
|
+
private CHAIN_ID = 1;
|
|
116
|
+
|
|
117
|
+
private node: TXENode;
|
|
119
118
|
|
|
120
119
|
private simulationProvider = new WASMSimulator();
|
|
121
120
|
|
|
@@ -123,16 +122,19 @@ export class TXE implements TypedOracle {
|
|
|
123
122
|
|
|
124
123
|
debug: LogFn;
|
|
125
124
|
|
|
126
|
-
constructor(
|
|
125
|
+
private constructor(
|
|
127
126
|
private logger: Logger,
|
|
128
127
|
private trees: MerkleTrees,
|
|
129
128
|
private executionCache: HashedValuesCache,
|
|
130
129
|
private keyStore: KeyStore,
|
|
131
130
|
private txeDatabase: TXEDatabase,
|
|
131
|
+
private contractAddress: AztecAddress,
|
|
132
132
|
) {
|
|
133
133
|
this.noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
134
134
|
this.contractDataOracle = new ContractDataOracle(txeDatabase);
|
|
135
|
-
|
|
135
|
+
|
|
136
|
+
this.node = new TXENode(this.blockNumber, this.VERSION, this.CHAIN_ID, this.trees);
|
|
137
|
+
|
|
136
138
|
// Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404)
|
|
137
139
|
this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE);
|
|
138
140
|
this.simulatorOracle = new SimulatorOracle(
|
|
@@ -146,6 +148,16 @@ export class TXE implements TypedOracle {
|
|
|
146
148
|
this.debug = createDebugOnlyLogger('aztec:kv-pxe-database');
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
static async create(
|
|
152
|
+
logger: Logger,
|
|
153
|
+
trees: MerkleTrees,
|
|
154
|
+
executionCache: HashedValuesCache,
|
|
155
|
+
keyStore: KeyStore,
|
|
156
|
+
txeDatabase: TXEDatabase,
|
|
157
|
+
) {
|
|
158
|
+
return new TXE(logger, trees, executionCache, keyStore, txeDatabase, await AztecAddress.random());
|
|
159
|
+
}
|
|
160
|
+
|
|
149
161
|
// Utils
|
|
150
162
|
|
|
151
163
|
async #getTreesAt(blockNumber: number) {
|
|
@@ -156,12 +168,12 @@ export class TXE implements TypedOracle {
|
|
|
156
168
|
return db;
|
|
157
169
|
}
|
|
158
170
|
|
|
159
|
-
getChainId() {
|
|
160
|
-
return Promise.resolve(this.
|
|
171
|
+
getChainId(): Promise<Fr> {
|
|
172
|
+
return Promise.resolve(this.node.getChainId().then(id => new Fr(id)));
|
|
161
173
|
}
|
|
162
174
|
|
|
163
|
-
getVersion() {
|
|
164
|
-
return Promise.resolve(this.
|
|
175
|
+
getVersion(): Promise<Fr> {
|
|
176
|
+
return Promise.resolve(this.node.getVersion().then(v => new Fr(v)));
|
|
165
177
|
}
|
|
166
178
|
|
|
167
179
|
getMsgSender() {
|
|
@@ -232,8 +244,8 @@ export class TXE implements TypedOracle {
|
|
|
232
244
|
|
|
233
245
|
const stateReference = await db.getStateReference();
|
|
234
246
|
const inputs = PrivateContextInputs.empty();
|
|
235
|
-
inputs.txContext.chainId = this.
|
|
236
|
-
inputs.txContext.version = this.
|
|
247
|
+
inputs.txContext.chainId = new Fr(await this.node.getChainId());
|
|
248
|
+
inputs.txContext.version = new Fr(await this.node.getVersion());
|
|
237
249
|
inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
|
|
238
250
|
inputs.historicalHeader.state = stateReference;
|
|
239
251
|
inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
|
|
@@ -252,8 +264,8 @@ export class TXE implements TypedOracle {
|
|
|
252
264
|
const account = await this.txeDatabase.getAccount(address);
|
|
253
265
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
254
266
|
const schnorr = new Schnorr();
|
|
255
|
-
const signature = schnorr.constructSignature(messageHash.toBuffer(), privateKey)
|
|
256
|
-
const authWitness = new AuthWitness(messageHash, [...signature]);
|
|
267
|
+
const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
|
|
268
|
+
const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
|
|
257
269
|
return this.txeDatabase.addAuthWitness(authWitness.requestHash, authWitness.witness);
|
|
258
270
|
}
|
|
259
271
|
|
|
@@ -322,26 +334,13 @@ export class TXE implements TypedOracle {
|
|
|
322
334
|
this.privateLogs.push(...privateLogs);
|
|
323
335
|
}
|
|
324
336
|
|
|
325
|
-
addPublicLogs(logs:
|
|
337
|
+
addPublicLogs(logs: PublicLog[]) {
|
|
326
338
|
logs.forEach(log => {
|
|
327
|
-
if (log.data.length < 32 * 33) {
|
|
328
|
-
// TODO remove when #9835 and #9836 are fixed
|
|
329
|
-
this.logger.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`);
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
339
|
try {
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const initialOffset = 32;
|
|
338
|
-
for (let i = 0; i < 32; i++) {
|
|
339
|
-
const byte = Fr.fromBuffer(log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset)).toNumber();
|
|
340
|
-
correctedBuffer.writeUInt8(byte, i);
|
|
341
|
-
}
|
|
342
|
-
const tag = new Fr(correctedBuffer);
|
|
343
|
-
|
|
344
|
-
this.logger.verbose(`Found tagged unencrypted log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
340
|
+
// The first elt stores lengths => tag is in fields[1]
|
|
341
|
+
const tag = log.log[1];
|
|
342
|
+
|
|
343
|
+
this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
345
344
|
this.publicLogs.push(log);
|
|
346
345
|
} catch (err) {
|
|
347
346
|
this.logger.warn(`Failed to add tagged log to store: ${err}`);
|
|
@@ -371,10 +370,6 @@ export class TXE implements TypedOracle {
|
|
|
371
370
|
return Fr.random();
|
|
372
371
|
}
|
|
373
372
|
|
|
374
|
-
storeArrayInExecutionCache(values: Fr[]) {
|
|
375
|
-
return Promise.resolve(this.executionCache.store(values));
|
|
376
|
-
}
|
|
377
|
-
|
|
378
373
|
storeInExecutionCache(values: Fr[]) {
|
|
379
374
|
return Promise.resolve(this.executionCache.store(values));
|
|
380
375
|
}
|
|
@@ -406,11 +401,11 @@ export class TXE implements TypedOracle {
|
|
|
406
401
|
return [new Fr(index), ...siblingPath.toFields()];
|
|
407
402
|
}
|
|
408
403
|
|
|
409
|
-
async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
404
|
+
// async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr) {
|
|
405
|
+
// const committedDb = new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
|
|
406
|
+
// const result = await committedDb.getSiblingPath(treeId, leafIndex.toBigInt());
|
|
407
|
+
// return result.toFields();
|
|
408
|
+
// }
|
|
414
409
|
|
|
415
410
|
async getNullifierMembershipWitness(
|
|
416
411
|
blockNumber: number,
|
|
@@ -810,8 +805,8 @@ export class TXE implements TypedOracle {
|
|
|
810
805
|
const worldStateDb = new TXEWorldStateDB(db, new TXEPublicContractDataSource(this));
|
|
811
806
|
|
|
812
807
|
const globalVariables = GlobalVariables.empty();
|
|
813
|
-
globalVariables.chainId = this.
|
|
814
|
-
globalVariables.version = this.
|
|
808
|
+
globalVariables.chainId = new Fr(await this.node.getChainId());
|
|
809
|
+
globalVariables.version = new Fr(await this.node.getVersion());
|
|
815
810
|
globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
816
811
|
globalVariables.gasFees = new GasFees(1, 1);
|
|
817
812
|
|
|
@@ -830,23 +825,33 @@ export class TXE implements TypedOracle {
|
|
|
830
825
|
const simulator = new PublicTxSimulator(
|
|
831
826
|
db,
|
|
832
827
|
new TXEWorldStateDB(db, new TXEPublicContractDataSource(this)),
|
|
833
|
-
new NoopTelemetryClient(),
|
|
834
828
|
globalVariables,
|
|
835
829
|
);
|
|
836
830
|
|
|
831
|
+
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
832
|
+
const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
833
|
+
|
|
837
834
|
// When setting up a teardown call, we tell it that
|
|
838
835
|
// private execution used Gas(1, 1) so it can compute a tx fee.
|
|
839
836
|
const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty();
|
|
840
837
|
const tx = createTxForPublicCalls(
|
|
841
838
|
/*setupExecutionRequests=*/ [],
|
|
842
839
|
/*appExecutionRequests=*/ isTeardown ? [] : [executionRequest],
|
|
840
|
+
firstNullifier,
|
|
843
841
|
/*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined,
|
|
844
842
|
gasUsedByPrivate,
|
|
845
843
|
);
|
|
846
844
|
|
|
847
845
|
const result = await simulator.simulate(tx);
|
|
846
|
+
const noteHashes = result.avmProvingRequest.inputs.output.accumulatedData.noteHashes.filter(s => !s.isEmpty());
|
|
848
847
|
|
|
849
|
-
this.
|
|
848
|
+
await this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
849
|
+
|
|
850
|
+
this.addPublicLogs(
|
|
851
|
+
result.avmProvingRequest.inputs.output.accumulatedData.publicLogs.filter(
|
|
852
|
+
log => !log.contractAddress.equals(AztecAddress.ZERO),
|
|
853
|
+
),
|
|
854
|
+
);
|
|
850
855
|
|
|
851
856
|
return Promise.resolve(result);
|
|
852
857
|
}
|
|
@@ -898,7 +903,11 @@ export class TXE implements TypedOracle {
|
|
|
898
903
|
const sideEffects = executionResult.avmProvingRequest.inputs.output.accumulatedData;
|
|
899
904
|
const publicDataWrites = sideEffects.publicDataWrites.filter(s => !s.isEmpty());
|
|
900
905
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
901
|
-
|
|
906
|
+
|
|
907
|
+
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
908
|
+
const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
909
|
+
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty()).filter(s => !s.equals(firstNullifier));
|
|
910
|
+
|
|
902
911
|
await this.addPublicDataWrites(publicDataWrites);
|
|
903
912
|
await this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
904
913
|
await this.addSiloedNullifiers(nullifiers);
|
|
@@ -952,7 +961,7 @@ export class TXE implements TypedOracle {
|
|
|
952
961
|
async #calculateAppTaggingSecret(contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress) {
|
|
953
962
|
const senderCompleteAddress = await this.getCompleteAddress(sender);
|
|
954
963
|
const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
|
|
955
|
-
const secretPoint = computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
|
|
964
|
+
const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
|
|
956
965
|
// Silo the secret to the app so it can't be used to track other app's notes
|
|
957
966
|
const appSecret = poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]);
|
|
958
967
|
return appSecret;
|
|
@@ -974,6 +983,19 @@ export class TXE implements TypedOracle {
|
|
|
974
983
|
return Promise.resolve();
|
|
975
984
|
}
|
|
976
985
|
|
|
986
|
+
deliverNote(
|
|
987
|
+
_contractAddress: AztecAddress,
|
|
988
|
+
_storageSlot: Fr,
|
|
989
|
+
_nonce: Fr,
|
|
990
|
+
_content: Fr[],
|
|
991
|
+
_noteHash: Fr,
|
|
992
|
+
_nullifier: Fr,
|
|
993
|
+
_txHash: Fr,
|
|
994
|
+
_recipient: AztecAddress,
|
|
995
|
+
): Promise<void> {
|
|
996
|
+
throw new Error('deliverNote');
|
|
997
|
+
}
|
|
998
|
+
|
|
977
999
|
// AVM oracles
|
|
978
1000
|
|
|
979
1001
|
async avmOpcodeCall(targetContractAddress: AztecAddress, args: Fr[], isStaticCall: boolean): Promise<PublicTxResult> {
|
|
@@ -999,7 +1021,11 @@ export class TXE implements TypedOracle {
|
|
|
999
1021
|
const sideEffects = executionResult.avmProvingRequest.inputs.output.accumulatedData;
|
|
1000
1022
|
const publicDataWrites = sideEffects.publicDataWrites.filter(s => !s.isEmpty());
|
|
1001
1023
|
const noteHashes = sideEffects.noteHashes.filter(s => !s.isEmpty());
|
|
1002
|
-
const
|
|
1024
|
+
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
1025
|
+
const firstNullifier = usedTxRequestHashForNonces
|
|
1026
|
+
? this.getTxRequestHash()
|
|
1027
|
+
: this.noteCache.getAllNullifiers()[0];
|
|
1028
|
+
const nullifiers = sideEffects.nullifiers.filter(s => !s.isEmpty()).filter(s => !s.equals(firstNullifier));
|
|
1003
1029
|
await this.addPublicDataWrites(publicDataWrites);
|
|
1004
1030
|
await this.addUniqueNoteHashes(noteHashes);
|
|
1005
1031
|
await this.addSiloedNullifiers(nullifiers);
|
|
@@ -1058,36 +1084,35 @@ export class TXE implements TypedOracle {
|
|
|
1058
1084
|
return preimage.value;
|
|
1059
1085
|
}
|
|
1060
1086
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
* @param key - A field element representing the key to store the data under.
|
|
1066
|
-
* @param values - An array of field elements representing the data to store.
|
|
1067
|
-
*/
|
|
1068
|
-
store(contract: AztecAddress, key: Fr, values: Fr[]): Promise<void> {
|
|
1069
|
-
if (!contract.equals(this.contractAddress)) {
|
|
1070
|
-
// TODO(#10727): instead of this check check that this.contractAddress is allowed to process notes for contract
|
|
1071
|
-
throw new Error(
|
|
1072
|
-
`Contract address ${contract} does not match the oracle's contract address ${this.contractAddress}`,
|
|
1073
|
-
);
|
|
1087
|
+
dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise<void> {
|
|
1088
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
1089
|
+
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
1090
|
+
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
1074
1091
|
}
|
|
1075
|
-
return this.txeDatabase.
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1092
|
+
return this.txeDatabase.dbStore(this.contractAddress, slot, values);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
dbLoad(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
|
|
1096
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
1097
|
+
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
1098
|
+
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
1099
|
+
}
|
|
1100
|
+
return this.txeDatabase.dbLoad(this.contractAddress, slot);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
dbDelete(contractAddress: AztecAddress, slot: Fr): Promise<void> {
|
|
1104
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
1105
|
+
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
1106
|
+
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
1107
|
+
}
|
|
1108
|
+
return this.txeDatabase.dbDelete(this.contractAddress, slot);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
dbCopy(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
|
|
1112
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
1113
|
+
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
1114
|
+
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
1090
1115
|
}
|
|
1091
|
-
return this.txeDatabase.
|
|
1116
|
+
return this.txeDatabase.dbCopy(this.contractAddress, srcSlot, dstSlot, numEntries);
|
|
1092
1117
|
}
|
|
1093
1118
|
}
|