@aztec/txe 0.0.1-commit.9372f48 → 0.0.1-commit.967fc6998
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 +7 -8
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +99 -30
- package/dest/rpc_translator.d.ts +6 -6
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +39 -15
- package/dest/state_machine/archiver.d.ts +1 -1
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +2 -0
- package/dest/state_machine/dummy_p2p_client.d.ts +16 -12
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +28 -16
- package/dest/state_machine/index.d.ts +5 -5
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +15 -10
- package/dest/state_machine/mock_epoch_cache.d.ts +3 -1
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +4 -0
- package/dest/txe_session.d.ts +9 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +79 -20
- 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/dest/utils/block_creation.d.ts +1 -1
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +3 -1
- 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 +111 -75
- package/src/rpc_translator.ts +35 -9
- package/src/state_machine/archiver.ts +2 -0
- package/src/state_machine/dummy_p2p_client.ts +40 -22
- package/src/state_machine/index.ts +25 -9
- package/src/state_machine/mock_epoch_cache.ts +5 -0
- package/src/txe_session.ts +82 -68
- package/src/util/txe_public_contract_data_source.ts +10 -36
- package/src/utils/block_creation.ts +3 -1
- 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,
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
SenderAddressBookStore,
|
|
23
25
|
SenderTaggingStore,
|
|
24
26
|
enrichPublicSimulationError,
|
|
25
|
-
syncState,
|
|
26
27
|
} from '@aztec/pxe/server';
|
|
27
28
|
import {
|
|
28
29
|
ExecutionNoteCache,
|
|
@@ -84,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
|
|
|
84
85
|
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
85
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
86
87
|
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
87
|
-
import type { TXEContractStore } from '../util/txe_contract_store.js';
|
|
88
88
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
89
89
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
90
90
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
@@ -97,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
97
97
|
|
|
98
98
|
constructor(
|
|
99
99
|
private stateMachine: TXEStateMachine,
|
|
100
|
-
private contractStore:
|
|
100
|
+
private contractStore: ContractStore,
|
|
101
101
|
private noteStore: NoteStore,
|
|
102
102
|
private keyStore: KeyStore,
|
|
103
103
|
private addressStore: AddressStore,
|
|
@@ -107,7 +107,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
107
107
|
private senderAddressBookStore: SenderAddressBookStore,
|
|
108
108
|
private capsuleStore: CapsuleStore,
|
|
109
109
|
private privateEventStore: PrivateEventStore,
|
|
110
|
-
private jobId: string,
|
|
111
110
|
private nextBlockTimestamp: bigint,
|
|
112
111
|
private version: Fr,
|
|
113
112
|
private chainId: Fr,
|
|
@@ -132,13 +131,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
135
|
-
|
|
134
|
+
utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
136
135
|
if (!LogLevels[level]) {
|
|
137
|
-
throw new Error(`Invalid
|
|
136
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
138
137
|
}
|
|
139
138
|
const levelName = LogLevels[level];
|
|
140
139
|
|
|
141
140
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
|
|
141
|
+
return Promise.resolve();
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
txeGetDefaultAddress(): AztecAddress {
|
|
@@ -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}`,
|
|
@@ -297,12 +317,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
297
317
|
throw new Error(message);
|
|
298
318
|
}
|
|
299
319
|
|
|
320
|
+
// When `from` is the zero address (e.g. when deploying a new account contract), we return an
|
|
321
|
+
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
322
|
+
const effectiveScopes = from.isZero() ? [] : [from];
|
|
323
|
+
|
|
300
324
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
301
|
-
const utilityExecutor = async (call: FunctionCall) => {
|
|
302
|
-
await this.executeUtilityCall(call);
|
|
325
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
|
|
326
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
303
327
|
};
|
|
304
328
|
|
|
305
|
-
await
|
|
329
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
330
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
331
|
+
targetContractAddress,
|
|
332
|
+
functionSelector,
|
|
333
|
+
utilityExecutor,
|
|
334
|
+
blockHeader,
|
|
335
|
+
jobId,
|
|
336
|
+
effectiveScopes,
|
|
337
|
+
);
|
|
306
338
|
|
|
307
339
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
308
340
|
|
|
@@ -314,8 +346,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
314
346
|
|
|
315
347
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
316
348
|
|
|
317
|
-
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
318
|
-
|
|
319
349
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
320
350
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
321
351
|
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
@@ -327,42 +357,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
327
357
|
|
|
328
358
|
const simulator = new WASMSimulator();
|
|
329
359
|
|
|
330
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
360
|
+
const privateExecutionOracle = new PrivateExecutionOracle({
|
|
331
361
|
argsHash,
|
|
332
362
|
txContext,
|
|
333
363
|
callContext,
|
|
334
|
-
|
|
335
|
-
blockHeader,
|
|
364
|
+
anchorBlockHeader: blockHeader,
|
|
336
365
|
utilityExecutor,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
[],
|
|
341
|
-
HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
366
|
+
authWitnesses: Array.from(this.authwits.values()),
|
|
367
|
+
capsules: [],
|
|
368
|
+
executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
342
369
|
noteCache,
|
|
343
370
|
taggingIndexCache,
|
|
344
|
-
this.contractStore,
|
|
345
|
-
this.noteStore,
|
|
346
|
-
this.keyStore,
|
|
347
|
-
this.addressStore,
|
|
348
|
-
this.stateMachine.node,
|
|
349
|
-
this.senderTaggingStore,
|
|
350
|
-
this.recipientTaggingStore,
|
|
351
|
-
this.senderAddressBookStore,
|
|
352
|
-
this.capsuleStore,
|
|
353
|
-
this.privateEventStore,
|
|
354
|
-
this.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
*/
|
|
363
|
-
from,
|
|
371
|
+
contractStore: this.contractStore,
|
|
372
|
+
noteStore: this.noteStore,
|
|
373
|
+
keyStore: this.keyStore,
|
|
374
|
+
addressStore: this.addressStore,
|
|
375
|
+
aztecNode: this.stateMachine.node,
|
|
376
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
377
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
378
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
379
|
+
capsuleStore: this.capsuleStore,
|
|
380
|
+
privateEventStore: this.privateEventStore,
|
|
381
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
382
|
+
jobId,
|
|
383
|
+
totalPublicCalldataCount: 0,
|
|
384
|
+
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
385
|
+
scopes: effectiveScopes,
|
|
386
|
+
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
387
|
+
// contract would perform, including setting senderForTags.
|
|
388
|
+
senderForTags: from,
|
|
364
389
|
simulator,
|
|
365
|
-
);
|
|
390
|
+
});
|
|
366
391
|
|
|
367
392
|
// Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
|
|
368
393
|
let result: PrivateExecutionResult;
|
|
@@ -401,7 +426,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
401
426
|
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
402
427
|
const { publicInputs } = await generateSimulatedProvingResult(
|
|
403
428
|
result,
|
|
404
|
-
this.contractStore,
|
|
429
|
+
(addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
|
|
430
|
+
this.stateMachine.node,
|
|
405
431
|
minRevertibleSideEffectCounter,
|
|
406
432
|
);
|
|
407
433
|
|
|
@@ -584,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
584
610
|
constantData,
|
|
585
611
|
/*gasUsed=*/ new Gas(0, 0),
|
|
586
612
|
/*feePayer=*/ AztecAddress.zero(),
|
|
587
|
-
/*
|
|
613
|
+
/*expirationTimestamp=*/ 0n,
|
|
588
614
|
inputsForPublic,
|
|
589
615
|
undefined,
|
|
590
616
|
);
|
|
@@ -652,10 +678,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
652
678
|
return returnValues ?? [];
|
|
653
679
|
}
|
|
654
680
|
|
|
655
|
-
async
|
|
681
|
+
async txeExecuteUtilityFunction(
|
|
656
682
|
targetContractAddress: AztecAddress,
|
|
657
683
|
functionSelector: FunctionSelector,
|
|
658
684
|
args: Fr[],
|
|
685
|
+
jobId: string,
|
|
659
686
|
) {
|
|
660
687
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
661
688
|
if (!artifact) {
|
|
@@ -663,25 +690,33 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
663
690
|
}
|
|
664
691
|
|
|
665
692
|
// Sync notes before executing utility function to discover notes from previous transactions
|
|
666
|
-
await
|
|
667
|
-
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
const call = new FunctionCall(
|
|
671
|
-
artifact.name,
|
|
693
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
694
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
672
695
|
targetContractAddress,
|
|
673
696
|
functionSelector,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
697
|
+
async (call, execScopes) => {
|
|
698
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
699
|
+
},
|
|
700
|
+
blockHeader,
|
|
701
|
+
jobId,
|
|
702
|
+
'ALL_SCOPES',
|
|
679
703
|
);
|
|
680
704
|
|
|
681
|
-
|
|
705
|
+
const call = FunctionCall.from({
|
|
706
|
+
name: artifact.name,
|
|
707
|
+
to: targetContractAddress,
|
|
708
|
+
selector: functionSelector,
|
|
709
|
+
type: FunctionType.UTILITY,
|
|
710
|
+
hideMsgSender: false,
|
|
711
|
+
isStatic: false,
|
|
712
|
+
args,
|
|
713
|
+
returnTypes: [],
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
|
|
682
717
|
}
|
|
683
718
|
|
|
684
|
-
private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
|
|
719
|
+
private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
|
|
685
720
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
686
721
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
687
722
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -694,22 +729,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
694
729
|
|
|
695
730
|
try {
|
|
696
731
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
697
|
-
const oracle = new UtilityExecutionOracle(
|
|
698
|
-
call.to,
|
|
699
|
-
[],
|
|
700
|
-
[],
|
|
732
|
+
const oracle = new UtilityExecutionOracle({
|
|
733
|
+
contractAddress: call.to,
|
|
734
|
+
authWitnesses: [],
|
|
735
|
+
capsules: [],
|
|
701
736
|
anchorBlockHeader,
|
|
702
|
-
this.contractStore,
|
|
703
|
-
this.noteStore,
|
|
704
|
-
this.keyStore,
|
|
705
|
-
this.addressStore,
|
|
706
|
-
this.stateMachine.node,
|
|
707
|
-
this.recipientTaggingStore,
|
|
708
|
-
this.senderAddressBookStore,
|
|
709
|
-
this.capsuleStore,
|
|
710
|
-
this.privateEventStore,
|
|
711
|
-
|
|
712
|
-
|
|
737
|
+
contractStore: this.contractStore,
|
|
738
|
+
noteStore: this.noteStore,
|
|
739
|
+
keyStore: this.keyStore,
|
|
740
|
+
addressStore: this.addressStore,
|
|
741
|
+
aztecNode: this.stateMachine.node,
|
|
742
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
743
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
744
|
+
capsuleStore: this.capsuleStore,
|
|
745
|
+
privateEventStore: this.privateEventStore,
|
|
746
|
+
jobId,
|
|
747
|
+
scopes,
|
|
748
|
+
});
|
|
713
749
|
const acirExecutionResult = await new WASMSimulator()
|
|
714
750
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
715
751
|
.catch((err: Error) => {
|
|
@@ -725,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
725
761
|
);
|
|
726
762
|
});
|
|
727
763
|
|
|
728
|
-
this.logger.verbose(`Utility
|
|
764
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
729
765
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
730
766
|
} catch (err) {
|
|
731
|
-
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'));
|
|
732
768
|
}
|
|
733
769
|
}
|
|
734
770
|
|
package/src/rpc_translator.ts
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
toSingle,
|
|
31
31
|
} from './util/encoding.js';
|
|
32
32
|
|
|
33
|
-
const MAX_EVENT_LEN =
|
|
33
|
+
const MAX_EVENT_LEN = 10; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
|
|
34
34
|
const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
|
|
35
35
|
|
|
36
36
|
export class UnavailableOracleError extends Error {
|
|
@@ -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) {
|
|
@@ -328,7 +335,7 @@ export class RPCTranslator {
|
|
|
328
335
|
|
|
329
336
|
// When the argument is a slice, noir automatically adds a length field to oracle call.
|
|
330
337
|
// When the argument is an array, we add the field length manually to the signature.
|
|
331
|
-
|
|
338
|
+
async utilityLog(
|
|
332
339
|
foreignLevel: ForeignCallSingle,
|
|
333
340
|
foreignMessage: ForeignCallArray,
|
|
334
341
|
_foreignLength: ForeignCallSingle,
|
|
@@ -340,7 +347,7 @@ export class RPCTranslator {
|
|
|
340
347
|
.join('');
|
|
341
348
|
const fields = fromArray(foreignFields);
|
|
342
349
|
|
|
343
|
-
this.handlerAsMisc().
|
|
350
|
+
await this.handlerAsMisc().utilityLog(level, message, fields);
|
|
344
351
|
|
|
345
352
|
return toForeignCallResult([]);
|
|
346
353
|
}
|
|
@@ -545,12 +552,23 @@ export class RPCTranslator {
|
|
|
545
552
|
);
|
|
546
553
|
}
|
|
547
554
|
|
|
548
|
-
async
|
|
555
|
+
async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
|
|
549
556
|
const address = addressFromSingle(foreignAddress);
|
|
550
557
|
|
|
551
|
-
const
|
|
558
|
+
const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
|
|
552
559
|
|
|
553
|
-
return
|
|
560
|
+
// We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
|
|
561
|
+
// with two fields: `some` (a boolean) and `value` (a field array in this case).
|
|
562
|
+
if (result === undefined) {
|
|
563
|
+
// No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
|
|
564
|
+
return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
|
|
565
|
+
} else {
|
|
566
|
+
// Data was found so we set `some` to 1 and return it along with `value`.
|
|
567
|
+
return toForeignCallResult([
|
|
568
|
+
toSingle(new Fr(1)),
|
|
569
|
+
toArray([...result.publicKeys.toFields(), result.partialAddress]),
|
|
570
|
+
]);
|
|
571
|
+
}
|
|
554
572
|
}
|
|
555
573
|
|
|
556
574
|
async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
|
|
@@ -838,7 +856,7 @@ export class RPCTranslator {
|
|
|
838
856
|
|
|
839
857
|
// AVM opcodes
|
|
840
858
|
|
|
841
|
-
|
|
859
|
+
avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
|
|
842
860
|
// TODO(#8811): Implement
|
|
843
861
|
return toForeignCallResult([]);
|
|
844
862
|
}
|
|
@@ -1027,12 +1045,15 @@ export class RPCTranslator {
|
|
|
1027
1045
|
args,
|
|
1028
1046
|
argsHash,
|
|
1029
1047
|
isStaticCall,
|
|
1048
|
+
this.stateHandler.getCurrentJob(),
|
|
1030
1049
|
);
|
|
1031
1050
|
|
|
1051
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1052
|
+
await this.stateHandler.cycleJob();
|
|
1032
1053
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1033
1054
|
}
|
|
1034
1055
|
|
|
1035
|
-
async
|
|
1056
|
+
async txeExecuteUtilityFunction(
|
|
1036
1057
|
foreignTargetContractAddress: ForeignCallSingle,
|
|
1037
1058
|
foreignFunctionSelector: ForeignCallSingle,
|
|
1038
1059
|
foreignArgs: ForeignCallArray,
|
|
@@ -1041,12 +1062,15 @@ export class RPCTranslator {
|
|
|
1041
1062
|
const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
|
|
1042
1063
|
const args = fromArray(foreignArgs);
|
|
1043
1064
|
|
|
1044
|
-
const returnValues = await this.handlerAsTxe().
|
|
1065
|
+
const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
|
|
1045
1066
|
targetContractAddress,
|
|
1046
1067
|
functionSelector,
|
|
1047
1068
|
args,
|
|
1069
|
+
this.stateHandler.getCurrentJob(),
|
|
1048
1070
|
);
|
|
1049
1071
|
|
|
1072
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1073
|
+
await this.stateHandler.cycleJob();
|
|
1050
1074
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1051
1075
|
}
|
|
1052
1076
|
|
|
@@ -1063,6 +1087,8 @@ export class RPCTranslator {
|
|
|
1063
1087
|
|
|
1064
1088
|
const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
|
|
1065
1089
|
|
|
1090
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1091
|
+
await this.stateHandler.cycleJob();
|
|
1066
1092
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1067
1093
|
}
|
|
1068
1094
|
|