@aztec/txe 0.0.1-commit.7cf39cb55 → 0.0.1-commit.808bf7f90
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 +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +82 -50
- package/dest/oracle/interfaces.d.ts +4 -3
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.d.ts +6 -7
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +28 -18
- package/dest/rpc_translator.d.ts +3 -3
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +16 -4
- package/dest/state_machine/dummy_p2p_client.d.ts +5 -4
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +6 -3
- package/dest/state_machine/index.d.ts +1 -1
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +1 -1
- package/dest/txe_session.d.ts +9 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +18 -16
- package/dest/util/txe_public_contract_data_source.d.ts +2 -3
- package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
- package/dest/util/txe_public_contract_data_source.js +5 -22
- package/package.json +15 -15
- package/src/index.ts +83 -49
- package/src/oracle/interfaces.ts +6 -1
- package/src/oracle/txe_oracle_top_level_context.ts +40 -19
- package/src/rpc_translator.ts +18 -3
- package/src/state_machine/dummy_p2p_client.ts +10 -6
- package/src/state_machine/index.ts +1 -0
- package/src/txe_session.ts +25 -17
- package/src/util/txe_public_contract_data_source.ts +10 -36
- package/dest/util/txe_contract_store.d.ts +0 -12
- package/dest/util/txe_contract_store.d.ts.map +0 -1
- package/dest/util/txe_contract_store.js +0 -22
- package/src/util/txe_contract_store.ts +0 -36
package/src/index.ts
CHANGED
|
@@ -9,9 +9,12 @@ import { Fr } from '@aztec/aztec.js/fields';
|
|
|
9
9
|
import { PublicKeys, deriveKeys } from '@aztec/aztec.js/keys';
|
|
10
10
|
import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
11
11
|
import type { Logger } from '@aztec/foundation/log';
|
|
12
|
-
import {
|
|
12
|
+
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
13
|
+
import { protocolContractNames } from '@aztec/protocol-contracts';
|
|
13
14
|
import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
|
|
15
|
+
import { ContractStore } from '@aztec/pxe/server';
|
|
14
16
|
import { computeArtifactHash } from '@aztec/stdlib/contract';
|
|
17
|
+
import type { ContractArtifactWithHash } from '@aztec/stdlib/contract';
|
|
15
18
|
import type { ApiSchemaFor } from '@aztec/stdlib/schemas';
|
|
16
19
|
import { zodFor } from '@aztec/stdlib/schemas';
|
|
17
20
|
|
|
@@ -33,18 +36,24 @@ import {
|
|
|
33
36
|
fromSingle,
|
|
34
37
|
toSingle,
|
|
35
38
|
} from './util/encoding.js';
|
|
36
|
-
import type { ContractArtifactWithHash } from './util/txe_contract_store.js';
|
|
37
39
|
|
|
38
40
|
const sessions = new Map<number, TXESession>();
|
|
39
41
|
|
|
40
42
|
/*
|
|
41
43
|
* TXE typically has to load the same contract artifacts over and over again for multiple tests,
|
|
42
|
-
* so we cache them here to avoid
|
|
44
|
+
* so we cache them here to avoid loading from disk repeatedly.
|
|
45
|
+
*
|
|
46
|
+
* The in-flight map coalesces concurrent requests for the same cache key so that
|
|
47
|
+
* computeArtifactHash (very expensive) is only run once even under parallelism.
|
|
43
48
|
*/
|
|
44
49
|
const TXEArtifactsCache = new Map<
|
|
45
50
|
string,
|
|
46
51
|
{ artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }
|
|
47
52
|
>();
|
|
53
|
+
const TXEArtifactsCacheInFlight = new Map<
|
|
54
|
+
string,
|
|
55
|
+
Promise<{ artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }>
|
|
56
|
+
>();
|
|
48
57
|
|
|
49
58
|
type TXEForeignCallInput = {
|
|
50
59
|
session_id: number;
|
|
@@ -68,7 +77,7 @@ const TXEForeignCallInputSchema = zodFor<TXEForeignCallInput>()(
|
|
|
68
77
|
);
|
|
69
78
|
|
|
70
79
|
class TXEDispatcher {
|
|
71
|
-
private
|
|
80
|
+
private contractStore!: ContractStore;
|
|
72
81
|
|
|
73
82
|
constructor(private logger: Logger) {}
|
|
74
83
|
|
|
@@ -135,29 +144,36 @@ class TXEDispatcher {
|
|
|
135
144
|
this.logger.debug(`Using cached artifact for ${cacheKey}`);
|
|
136
145
|
({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
|
|
137
146
|
} else {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
147
|
+
if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
|
|
148
|
+
this.logger.debug(`Loading compiled artifact ${artifactPath}`);
|
|
149
|
+
const compute = async () => {
|
|
150
|
+
const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8')) as NoirCompiledContract;
|
|
151
|
+
const artifactWithoutHash = loadContractArtifact(artifactJSON);
|
|
152
|
+
const computedArtifact: ContractArtifactWithHash = {
|
|
153
|
+
...artifactWithoutHash,
|
|
154
|
+
// Artifact hash is *very* expensive to compute, so we do it here once
|
|
155
|
+
// and the TXE contract data provider can cache it
|
|
156
|
+
artifactHash: await computeArtifactHash(artifactWithoutHash),
|
|
157
|
+
};
|
|
158
|
+
this.logger.debug(
|
|
159
|
+
`Deploy ${computedArtifact.name} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
|
|
160
|
+
);
|
|
161
|
+
const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
|
|
162
|
+
constructorArgs: decodedArgs,
|
|
163
|
+
skipArgsDecoding: true,
|
|
164
|
+
salt: Fr.ONE,
|
|
165
|
+
publicKeys,
|
|
166
|
+
constructorArtifact: initializer ? initializer : undefined,
|
|
167
|
+
deployer: AztecAddress.ZERO,
|
|
168
|
+
});
|
|
169
|
+
const result = { artifact: computedArtifact, instance: computedInstance };
|
|
170
|
+
TXEArtifactsCache.set(cacheKey, result);
|
|
171
|
+
TXEArtifactsCacheInFlight.delete(cacheKey);
|
|
172
|
+
return result;
|
|
173
|
+
};
|
|
174
|
+
TXEArtifactsCacheInFlight.set(cacheKey, compute());
|
|
175
|
+
}
|
|
176
|
+
({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
inputs.splice(0, 1, artifact, instance, toSingle(secret));
|
|
@@ -175,23 +191,35 @@ class TXEDispatcher {
|
|
|
175
191
|
this.logger.debug(`Using cached artifact for ${cacheKey}`);
|
|
176
192
|
({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
|
|
177
193
|
} else {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
|
|
195
|
+
const compute = async () => {
|
|
196
|
+
const keys = await deriveKeys(secret);
|
|
197
|
+
const args = [
|
|
198
|
+
keys.publicKeys.masterIncomingViewingPublicKey.x,
|
|
199
|
+
keys.publicKeys.masterIncomingViewingPublicKey.y,
|
|
200
|
+
];
|
|
201
|
+
const computedArtifact: ContractArtifactWithHash = {
|
|
202
|
+
...SchnorrAccountContractArtifact,
|
|
203
|
+
// Artifact hash is *very* expensive to compute, so we do it here once
|
|
204
|
+
// and the TXE contract data provider can cache it
|
|
205
|
+
artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact),
|
|
206
|
+
};
|
|
207
|
+
const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
|
|
208
|
+
constructorArgs: args,
|
|
209
|
+
skipArgsDecoding: true,
|
|
210
|
+
salt: Fr.ONE,
|
|
211
|
+
publicKeys: keys.publicKeys,
|
|
212
|
+
constructorArtifact: 'constructor',
|
|
213
|
+
deployer: AztecAddress.ZERO,
|
|
214
|
+
});
|
|
215
|
+
const result = { artifact: computedArtifact, instance: computedInstance };
|
|
216
|
+
TXEArtifactsCache.set(cacheKey, result);
|
|
217
|
+
TXEArtifactsCacheInFlight.delete(cacheKey);
|
|
218
|
+
return result;
|
|
219
|
+
};
|
|
220
|
+
TXEArtifactsCacheInFlight.set(cacheKey, compute());
|
|
221
|
+
}
|
|
222
|
+
({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
|
|
195
223
|
}
|
|
196
224
|
|
|
197
225
|
inputs.splice(0, 0, artifact, instance);
|
|
@@ -204,12 +232,18 @@ class TXEDispatcher {
|
|
|
204
232
|
|
|
205
233
|
if (!sessions.has(sessionId)) {
|
|
206
234
|
this.logger.debug(`Creating new session ${sessionId}`);
|
|
207
|
-
if (!this.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
);
|
|
235
|
+
if (!this.contractStore) {
|
|
236
|
+
const kvStore = await openTmpStore('txe-contracts');
|
|
237
|
+
this.contractStore = new ContractStore(kvStore);
|
|
238
|
+
const provider = new BundledProtocolContractsProvider();
|
|
239
|
+
for (const name of protocolContractNames) {
|
|
240
|
+
const { instance, artifact } = await provider.getProtocolContractArtifact(name);
|
|
241
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
242
|
+
await this.contractStore.addContractInstance(instance);
|
|
243
|
+
}
|
|
244
|
+
this.logger.debug('Registered protocol contracts in shared contract store');
|
|
211
245
|
}
|
|
212
|
-
sessions.set(sessionId, await TXESession.init(this.
|
|
246
|
+
sessions.set(sessionId, await TXESession.init(this.contractStore));
|
|
213
247
|
}
|
|
214
248
|
|
|
215
249
|
switch (functionName) {
|
package/src/oracle/interfaces.ts
CHANGED
|
@@ -71,11 +71,13 @@ export interface ITxeExecutionOracle {
|
|
|
71
71
|
args: Fr[],
|
|
72
72
|
argsHash: Fr,
|
|
73
73
|
isStaticCall: boolean,
|
|
74
|
+
jobId: string,
|
|
74
75
|
): Promise<Fr[]>;
|
|
75
|
-
|
|
76
|
+
txeExecuteUtilityFunction(
|
|
76
77
|
targetContractAddress: AztecAddress,
|
|
77
78
|
functionSelector: FunctionSelector,
|
|
78
79
|
args: Fr[],
|
|
80
|
+
jobId: string,
|
|
79
81
|
): Promise<Fr[]>;
|
|
80
82
|
txePublicCallNewFlow(
|
|
81
83
|
from: AztecAddress,
|
|
@@ -83,4 +85,7 @@ export interface ITxeExecutionOracle {
|
|
|
83
85
|
calldata: Fr[],
|
|
84
86
|
isStaticCall: boolean,
|
|
85
87
|
): Promise<Fr[]>;
|
|
88
|
+
// TODO(F-335): Drop this from here as it's not a real oracle handler - it's only called from
|
|
89
|
+
// RPCTranslator::txeGetPrivateEvents and never from Noir.
|
|
90
|
+
syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string): Promise<void>;
|
|
86
91
|
}
|
|
@@ -12,9 +12,11 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
12
12
|
import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
13
13
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
14
14
|
import type { KeyStore } from '@aztec/key-store';
|
|
15
|
+
import type { AccessScopes } from '@aztec/pxe/client/lazy';
|
|
15
16
|
import {
|
|
16
17
|
AddressStore,
|
|
17
18
|
CapsuleStore,
|
|
19
|
+
type ContractStore,
|
|
18
20
|
NoteStore,
|
|
19
21
|
ORACLE_VERSION,
|
|
20
22
|
PrivateEventStore,
|
|
@@ -83,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
|
|
|
83
85
|
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
84
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
85
87
|
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
86
|
-
import type { TXEContractStore } from '../util/txe_contract_store.js';
|
|
87
88
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
88
89
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
89
90
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
@@ -96,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
96
97
|
|
|
97
98
|
constructor(
|
|
98
99
|
private stateMachine: TXEStateMachine,
|
|
99
|
-
private contractStore:
|
|
100
|
+
private contractStore: ContractStore,
|
|
100
101
|
private noteStore: NoteStore,
|
|
101
102
|
private keyStore: KeyStore,
|
|
102
103
|
private addressStore: AddressStore,
|
|
@@ -106,7 +107,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
106
107
|
private senderAddressBookStore: SenderAddressBookStore,
|
|
107
108
|
private capsuleStore: CapsuleStore,
|
|
108
109
|
private privateEventStore: PrivateEventStore,
|
|
109
|
-
private jobId: string,
|
|
110
110
|
private nextBlockTimestamp: bigint,
|
|
111
111
|
private version: Fr,
|
|
112
112
|
private chainId: Fr,
|
|
@@ -171,6 +171,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
171
171
|
return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
175
|
+
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
176
|
+
this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
181
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
182
|
+
contractAddress,
|
|
183
|
+
null,
|
|
184
|
+
async (call, execScopes) => {
|
|
185
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
186
|
+
},
|
|
187
|
+
blockHeader,
|
|
188
|
+
jobId,
|
|
189
|
+
[scope],
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
174
193
|
async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
175
194
|
return (
|
|
176
195
|
await this.privateEventStore.getPrivateEvents(selector, {
|
|
@@ -210,7 +229,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
210
229
|
await this.txeAddAccount(artifact, instance, secret);
|
|
211
230
|
} else {
|
|
212
231
|
await this.contractStore.addContractInstance(instance);
|
|
213
|
-
await this.contractStore.addContractArtifact(
|
|
232
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
214
233
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
215
234
|
}
|
|
216
235
|
}
|
|
@@ -220,7 +239,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
220
239
|
|
|
221
240
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
222
241
|
await this.contractStore.addContractInstance(instance);
|
|
223
|
-
await this.contractStore.addContractArtifact(
|
|
242
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
224
243
|
|
|
225
244
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
226
245
|
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
@@ -284,6 +303,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
284
303
|
args: Fr[],
|
|
285
304
|
argsHash: Fr = Fr.zero(),
|
|
286
305
|
isStaticCall: boolean = false,
|
|
306
|
+
jobId: string,
|
|
287
307
|
) {
|
|
288
308
|
this.logger.verbose(
|
|
289
309
|
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -302,8 +322,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
302
322
|
const effectiveScopes = from.isZero() ? [] : [from];
|
|
303
323
|
|
|
304
324
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
305
|
-
const utilityExecutor = async (call: FunctionCall, execScopes:
|
|
306
|
-
await this.executeUtilityCall(call, execScopes);
|
|
325
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
|
|
326
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
307
327
|
};
|
|
308
328
|
|
|
309
329
|
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
@@ -312,7 +332,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
312
332
|
functionSelector,
|
|
313
333
|
utilityExecutor,
|
|
314
334
|
blockHeader,
|
|
315
|
-
|
|
335
|
+
jobId,
|
|
316
336
|
effectiveScopes,
|
|
317
337
|
);
|
|
318
338
|
|
|
@@ -359,7 +379,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
359
379
|
capsuleStore: this.capsuleStore,
|
|
360
380
|
privateEventStore: this.privateEventStore,
|
|
361
381
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
362
|
-
jobId
|
|
382
|
+
jobId,
|
|
363
383
|
totalPublicCalldataCount: 0,
|
|
364
384
|
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
365
385
|
scopes: effectiveScopes,
|
|
@@ -590,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
590
610
|
constantData,
|
|
591
611
|
/*gasUsed=*/ new Gas(0, 0),
|
|
592
612
|
/*feePayer=*/ AztecAddress.zero(),
|
|
593
|
-
/*
|
|
613
|
+
/*expirationTimestamp=*/ 0n,
|
|
594
614
|
inputsForPublic,
|
|
595
615
|
undefined,
|
|
596
616
|
);
|
|
@@ -658,10 +678,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
658
678
|
return returnValues ?? [];
|
|
659
679
|
}
|
|
660
680
|
|
|
661
|
-
async
|
|
681
|
+
async txeExecuteUtilityFunction(
|
|
662
682
|
targetContractAddress: AztecAddress,
|
|
663
683
|
functionSelector: FunctionSelector,
|
|
664
684
|
args: Fr[],
|
|
685
|
+
jobId: string,
|
|
665
686
|
) {
|
|
666
687
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
667
688
|
if (!artifact) {
|
|
@@ -674,11 +695,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
674
695
|
targetContractAddress,
|
|
675
696
|
functionSelector,
|
|
676
697
|
async (call, execScopes) => {
|
|
677
|
-
await this.executeUtilityCall(call, execScopes);
|
|
698
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
678
699
|
},
|
|
679
700
|
blockHeader,
|
|
680
|
-
|
|
681
|
-
|
|
701
|
+
jobId,
|
|
702
|
+
'ALL_SCOPES',
|
|
682
703
|
);
|
|
683
704
|
|
|
684
705
|
const call = FunctionCall.from({
|
|
@@ -692,10 +713,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
692
713
|
returnTypes: [],
|
|
693
714
|
});
|
|
694
715
|
|
|
695
|
-
return this.executeUtilityCall(call,
|
|
716
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
|
|
696
717
|
}
|
|
697
718
|
|
|
698
|
-
private async executeUtilityCall(call: FunctionCall, scopes:
|
|
719
|
+
private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
|
|
699
720
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
700
721
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
701
722
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -722,7 +743,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
722
743
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
723
744
|
capsuleStore: this.capsuleStore,
|
|
724
745
|
privateEventStore: this.privateEventStore,
|
|
725
|
-
jobId
|
|
746
|
+
jobId,
|
|
726
747
|
scopes,
|
|
727
748
|
});
|
|
728
749
|
const acirExecutionResult = await new WASMSimulator()
|
|
@@ -740,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
740
761
|
);
|
|
741
762
|
});
|
|
742
763
|
|
|
743
|
-
this.logger.verbose(`Utility
|
|
764
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
744
765
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
745
766
|
} catch (err) {
|
|
746
|
-
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility
|
|
767
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
|
|
747
768
|
}
|
|
748
769
|
}
|
|
749
770
|
|
package/src/rpc_translator.ts
CHANGED
|
@@ -285,6 +285,13 @@ export class RPCTranslator {
|
|
|
285
285
|
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
286
286
|
const scope = addressFromSingle(foreignScope);
|
|
287
287
|
|
|
288
|
+
// TODO(F-335): Avoid doing the following 2 calls here.
|
|
289
|
+
{
|
|
290
|
+
await this.handlerAsTxe().syncContractNonOracleMethod(contractAddress, scope, this.stateHandler.getCurrentJob());
|
|
291
|
+
// We cycle job to commit the stores after the contract sync.
|
|
292
|
+
await this.stateHandler.cycleJob();
|
|
293
|
+
}
|
|
294
|
+
|
|
288
295
|
const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
|
|
289
296
|
|
|
290
297
|
if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
|
|
@@ -849,7 +856,7 @@ export class RPCTranslator {
|
|
|
849
856
|
|
|
850
857
|
// AVM opcodes
|
|
851
858
|
|
|
852
|
-
|
|
859
|
+
avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
|
|
853
860
|
// TODO(#8811): Implement
|
|
854
861
|
return toForeignCallResult([]);
|
|
855
862
|
}
|
|
@@ -1038,12 +1045,15 @@ export class RPCTranslator {
|
|
|
1038
1045
|
args,
|
|
1039
1046
|
argsHash,
|
|
1040
1047
|
isStaticCall,
|
|
1048
|
+
this.stateHandler.getCurrentJob(),
|
|
1041
1049
|
);
|
|
1042
1050
|
|
|
1051
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1052
|
+
await this.stateHandler.cycleJob();
|
|
1043
1053
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1044
1054
|
}
|
|
1045
1055
|
|
|
1046
|
-
async
|
|
1056
|
+
async txeExecuteUtilityFunction(
|
|
1047
1057
|
foreignTargetContractAddress: ForeignCallSingle,
|
|
1048
1058
|
foreignFunctionSelector: ForeignCallSingle,
|
|
1049
1059
|
foreignArgs: ForeignCallArray,
|
|
@@ -1052,12 +1062,15 @@ export class RPCTranslator {
|
|
|
1052
1062
|
const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
|
|
1053
1063
|
const args = fromArray(foreignArgs);
|
|
1054
1064
|
|
|
1055
|
-
const returnValues = await this.handlerAsTxe().
|
|
1065
|
+
const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
|
|
1056
1066
|
targetContractAddress,
|
|
1057
1067
|
functionSelector,
|
|
1058
1068
|
args,
|
|
1069
|
+
this.stateHandler.getCurrentJob(),
|
|
1059
1070
|
);
|
|
1060
1071
|
|
|
1072
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1073
|
+
await this.stateHandler.cycleJob();
|
|
1061
1074
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1062
1075
|
}
|
|
1063
1076
|
|
|
@@ -1074,6 +1087,8 @@ export class RPCTranslator {
|
|
|
1074
1087
|
|
|
1075
1088
|
const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
|
|
1076
1089
|
|
|
1090
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1091
|
+
await this.stateHandler.cycleJob();
|
|
1077
1092
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1078
1093
|
}
|
|
1079
1094
|
|
|
@@ -16,8 +16,8 @@ import type {
|
|
|
16
16
|
StatusMessage,
|
|
17
17
|
} from '@aztec/p2p';
|
|
18
18
|
import type { EthAddress, L2BlockStreamEvent, L2Tips } from '@aztec/stdlib/block';
|
|
19
|
-
import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
20
|
-
import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
|
|
19
|
+
import type { ITxProvider, PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
20
|
+
import type { BlockProposal, CheckpointAttestation, CheckpointProposal, TopicType } from '@aztec/stdlib/p2p';
|
|
21
21
|
import type { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
|
|
22
22
|
|
|
23
23
|
export class DummyP2P implements P2P {
|
|
@@ -41,6 +41,10 @@ export class DummyP2P implements P2P {
|
|
|
41
41
|
throw new Error('DummyP2P does not implement "getPeers"');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
public getGossipMeshPeerCount(_topicType: TopicType): Promise<number> {
|
|
45
|
+
return Promise.resolve(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
public broadcastProposal(_proposal: BlockProposal): Promise<void> {
|
|
45
49
|
throw new Error('DummyP2P does not implement "broadcastProposal"');
|
|
46
50
|
}
|
|
@@ -131,6 +135,10 @@ export class DummyP2P implements P2P {
|
|
|
131
135
|
throw new Error('DummyP2P does not implement "isP2PClient"');
|
|
132
136
|
}
|
|
133
137
|
|
|
138
|
+
public getTxProvider(): ITxProvider {
|
|
139
|
+
throw new Error('DummyP2P does not implement "getTxProvider"');
|
|
140
|
+
}
|
|
141
|
+
|
|
134
142
|
public getTxsByHash(_txHashes: TxHash[]): Promise<Tx[]> {
|
|
135
143
|
throw new Error('DummyP2P does not implement "getTxsByHash"');
|
|
136
144
|
}
|
|
@@ -171,10 +179,6 @@ export class DummyP2P implements P2P {
|
|
|
171
179
|
throw new Error('DummyP2P does not implement "hasTxsInPool"');
|
|
172
180
|
}
|
|
173
181
|
|
|
174
|
-
public addTxsToPool(_txs: Tx[]): Promise<number> {
|
|
175
|
-
throw new Error('DummyP2P does not implement "addTxs"');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
182
|
public getSyncedLatestBlockNum(): Promise<number> {
|
|
179
183
|
throw new Error('DummyP2P does not implement "getSyncedLatestBlockNum"');
|
|
180
184
|
}
|
package/src/txe_session.ts
CHANGED
|
@@ -3,11 +3,12 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { KeyStore } from '@aztec/key-store';
|
|
5
5
|
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
6
|
-
import type {
|
|
6
|
+
import type { AccessScopes } from '@aztec/pxe/client/lazy';
|
|
7
7
|
import {
|
|
8
8
|
AddressStore,
|
|
9
9
|
AnchorBlockStore,
|
|
10
10
|
CapsuleStore,
|
|
11
|
+
ContractStore,
|
|
11
12
|
JobCoordinator,
|
|
12
13
|
NoteService,
|
|
13
14
|
NoteStore,
|
|
@@ -54,7 +55,6 @@ import { TXEArchiver } from './state_machine/archiver.js';
|
|
|
54
55
|
import { TXEStateMachine } from './state_machine/index.js';
|
|
55
56
|
import type { ForeignCallArgs, ForeignCallResult } from './util/encoding.js';
|
|
56
57
|
import { TXEAccountStore } from './util/txe_account_store.js';
|
|
57
|
-
import { TXEContractStore } from './util/txe_contract_store.js';
|
|
58
58
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
|
|
59
59
|
import { makeTxEffect } from './utils/tx_effect_creation.js';
|
|
60
60
|
|
|
@@ -113,6 +113,10 @@ export interface TXESessionStateHandler {
|
|
|
113
113
|
enterPublicState(contractAddress?: AztecAddress): Promise<void>;
|
|
114
114
|
enterPrivateState(contractAddress?: AztecAddress, anchorBlockNumber?: BlockNumber): Promise<PrivateContextInputs>;
|
|
115
115
|
enterUtilityState(contractAddress?: AztecAddress): Promise<void>;
|
|
116
|
+
|
|
117
|
+
// TODO(F-335): Exposing the job info is abstraction breakage - drop the following 2 functions.
|
|
118
|
+
cycleJob(): Promise<string>;
|
|
119
|
+
getCurrentJob(): string;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
/**
|
|
@@ -131,7 +135,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
131
135
|
| IPrivateExecutionOracle
|
|
132
136
|
| IAvmExecutionOracle
|
|
133
137
|
| ITxeExecutionOracle,
|
|
134
|
-
private contractStore:
|
|
138
|
+
private contractStore: ContractStore,
|
|
135
139
|
private noteStore: NoteStore,
|
|
136
140
|
private keyStore: KeyStore,
|
|
137
141
|
private addressStore: AddressStore,
|
|
@@ -148,12 +152,11 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
148
152
|
private nextBlockTimestamp: bigint,
|
|
149
153
|
) {}
|
|
150
154
|
|
|
151
|
-
static async init(
|
|
155
|
+
static async init(contractStore: ContractStore) {
|
|
152
156
|
const store = await openTmpStore('txe-session');
|
|
153
157
|
|
|
154
158
|
const addressStore = new AddressStore(store);
|
|
155
159
|
const privateEventStore = new PrivateEventStore(store);
|
|
156
|
-
const contractStore = new TXEContractStore(store);
|
|
157
160
|
const noteStore = new NoteStore(store);
|
|
158
161
|
const senderTaggingStore = new SenderTaggingStore(store);
|
|
159
162
|
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
@@ -172,12 +175,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
172
175
|
noteStore,
|
|
173
176
|
]);
|
|
174
177
|
|
|
175
|
-
// Register protocol contracts.
|
|
176
|
-
for (const { contractClass, instance, artifact } of protocolContracts) {
|
|
177
|
-
await contractStore.addContractArtifact(contractClass.id, artifact);
|
|
178
|
-
await contractStore.addContractInstance(instance);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
178
|
const archiver = new TXEArchiver(store);
|
|
182
179
|
const anchorBlockStore = new AnchorBlockStore(store);
|
|
183
180
|
const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
|
|
@@ -200,7 +197,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
200
197
|
senderAddressBookStore,
|
|
201
198
|
capsuleStore,
|
|
202
199
|
privateEventStore,
|
|
203
|
-
initialJobId,
|
|
204
200
|
nextBlockTimestamp,
|
|
205
201
|
version,
|
|
206
202
|
chainId,
|
|
@@ -261,6 +257,17 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
261
257
|
}
|
|
262
258
|
}
|
|
263
259
|
|
|
260
|
+
getCurrentJob(): string {
|
|
261
|
+
return this.currentJobId;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Commits the current job and begins a new one. Returns the new job ID. */
|
|
265
|
+
async cycleJob(): Promise<string> {
|
|
266
|
+
await this.jobCoordinator.commitJob(this.currentJobId);
|
|
267
|
+
this.currentJobId = this.jobCoordinator.beginJob();
|
|
268
|
+
return this.currentJobId;
|
|
269
|
+
}
|
|
270
|
+
|
|
264
271
|
async enterTopLevelState() {
|
|
265
272
|
switch (this.state.name) {
|
|
266
273
|
case 'PRIVATE': {
|
|
@@ -284,8 +291,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
// Commit all staged stores from the job that was just completed, then begin a new job
|
|
287
|
-
await this.
|
|
288
|
-
this.currentJobId = this.jobCoordinator.beginJob();
|
|
294
|
+
await this.cycleJob();
|
|
289
295
|
|
|
290
296
|
this.oracleHandler = new TXEOracleTopLevelContext(
|
|
291
297
|
this.stateMachine,
|
|
@@ -299,7 +305,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
299
305
|
this.senderAddressBookStore,
|
|
300
306
|
this.capsuleStore,
|
|
301
307
|
this.privateEventStore,
|
|
302
|
-
this.currentJobId,
|
|
303
308
|
this.nextBlockTimestamp,
|
|
304
309
|
this.version,
|
|
305
310
|
this.chainId,
|
|
@@ -323,6 +328,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
323
328
|
|
|
324
329
|
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
325
330
|
contractAddress,
|
|
331
|
+
'ALL_SCOPES',
|
|
326
332
|
);
|
|
327
333
|
const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
|
|
328
334
|
|
|
@@ -362,6 +368,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
362
368
|
privateEventStore: this.privateEventStore,
|
|
363
369
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
364
370
|
jobId: this.currentJobId,
|
|
371
|
+
scopes: 'ALL_SCOPES',
|
|
365
372
|
});
|
|
366
373
|
|
|
367
374
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
@@ -414,7 +421,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
414
421
|
this.stateMachine.node,
|
|
415
422
|
anchorBlockHeader,
|
|
416
423
|
this.currentJobId,
|
|
417
|
-
).syncNoteNullifiers(contractAddress);
|
|
424
|
+
).syncNoteNullifiers(contractAddress, 'ALL_SCOPES');
|
|
418
425
|
|
|
419
426
|
this.oracleHandler = new UtilityExecutionOracle({
|
|
420
427
|
contractAddress,
|
|
@@ -431,6 +438,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
431
438
|
capsuleStore: this.capsuleStore,
|
|
432
439
|
privateEventStore: this.privateEventStore,
|
|
433
440
|
jobId: this.currentJobId,
|
|
441
|
+
scopes: 'ALL_SCOPES',
|
|
434
442
|
});
|
|
435
443
|
|
|
436
444
|
this.state = { name: 'UTILITY' };
|
|
@@ -499,7 +507,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
499
507
|
}
|
|
500
508
|
|
|
501
509
|
private utilityExecutorForContractSync(anchorBlock: any) {
|
|
502
|
-
return async (call: FunctionCall, scopes:
|
|
510
|
+
return async (call: FunctionCall, scopes: AccessScopes) => {
|
|
503
511
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
504
512
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
505
513
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|