@aztec/txe 0.0.1-commit.9b94fc1 → 0.0.1-commit.9ee6fcc6
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/constants.d.ts +3 -0
- package/dest/constants.d.ts.map +1 -0
- package/dest/constants.js +2 -0
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +91 -56
- package/dest/oracle/interfaces.d.ts +33 -29
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +16 -16
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +20 -22
- package/dest/oracle/txe_oracle_top_level_context.d.ts +37 -27
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +211 -98
- package/dest/rpc_translator.d.ts +96 -79
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +362 -173
- package/dest/state_machine/archiver.d.ts +21 -52
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +66 -99
- package/dest/state_machine/dummy_p2p_client.d.ts +20 -15
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +42 -25
- package/dest/state_machine/global_variable_builder.d.ts +6 -5
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +13 -1
- package/dest/state_machine/index.d.ts +9 -7
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +44 -23
- package/dest/state_machine/mock_epoch_cache.d.ts +25 -8
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +46 -9
- package/dest/state_machine/synchronizer.d.ts +6 -5
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +8 -7
- package/dest/txe_session.d.ts +27 -15
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +170 -55
- package/dest/util/encoding.d.ts +686 -19
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +1 -1
- package/dest/util/txe_account_store.d.ts +10 -0
- package/dest/util/txe_account_store.d.ts.map +1 -0
- package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
- package/dest/util/txe_public_contract_data_source.d.ts +8 -8
- package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
- package/dest/util/txe_public_contract_data_source.js +13 -32
- package/dest/utils/block_creation.d.ts +21 -6
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +38 -4
- package/dest/utils/tx_effect_creation.d.ts +3 -3
- package/dest/utils/tx_effect_creation.d.ts.map +1 -1
- package/dest/utils/tx_effect_creation.js +4 -7
- package/package.json +18 -18
- package/src/constants.ts +3 -0
- package/src/index.ts +103 -63
- package/src/oracle/interfaces.ts +36 -32
- package/src/oracle/txe_oracle_public_context.ts +21 -28
- package/src/oracle/txe_oracle_top_level_context.ts +256 -138
- package/src/rpc_translator.ts +419 -191
- package/src/state_machine/archiver.ts +62 -117
- package/src/state_machine/dummy_p2p_client.ts +58 -33
- package/src/state_machine/global_variable_builder.ts +21 -4
- package/src/state_machine/index.ts +65 -21
- package/src/state_machine/mock_epoch_cache.ts +57 -14
- package/src/state_machine/synchronizer.ts +9 -8
- package/src/txe_session.ts +236 -104
- package/src/util/encoding.ts +1 -1
- package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
- package/src/util/txe_public_contract_data_source.ts +20 -47
- package/src/utils/block_creation.ts +49 -15
- package/src/utils/tx_effect_creation.ts +5 -12
- package/dest/util/txe_account_data_provider.d.ts +0 -10
- package/dest/util/txe_account_data_provider.d.ts.map +0 -1
- package/dest/util/txe_contract_data_provider.d.ts +0 -12
- package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
- package/dest/util/txe_contract_data_provider.js +0 -22
- package/src/util/txe_contract_data_provider.ts +0 -36
|
@@ -1,89 +1,107 @@
|
|
|
1
1
|
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Schnorr } from '@aztec/foundation/crypto/schnorr';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
5
|
import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
6
7
|
import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
|
|
7
8
|
import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
|
|
8
9
|
import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
|
|
9
|
-
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor
|
|
10
|
-
import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
10
|
+
import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
|
|
11
|
+
import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
11
12
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
12
13
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
13
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
14
|
-
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
15
15
|
import { computePartialAddress } from '@aztec/stdlib/contract';
|
|
16
16
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
17
17
|
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
18
18
|
import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
19
19
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
20
|
-
import {
|
|
20
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
21
21
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
22
22
|
import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
23
23
|
import { ForkCheckpoint } from '@aztec/world-state';
|
|
24
|
+
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
24
25
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
25
|
-
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees,
|
|
26
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
26
27
|
export class TXEOracleTopLevelContext {
|
|
27
28
|
stateMachine;
|
|
28
|
-
|
|
29
|
+
contractStore;
|
|
30
|
+
noteStore;
|
|
29
31
|
keyStore;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
addressStore;
|
|
33
|
+
accountStore;
|
|
34
|
+
senderTaggingStore;
|
|
35
|
+
recipientTaggingStore;
|
|
36
|
+
senderAddressBookStore;
|
|
37
|
+
capsuleStore;
|
|
38
|
+
privateEventStore;
|
|
33
39
|
nextBlockTimestamp;
|
|
34
40
|
version;
|
|
35
41
|
chainId;
|
|
36
42
|
authwits;
|
|
43
|
+
contractSyncService;
|
|
37
44
|
isMisc;
|
|
38
45
|
isTxe;
|
|
39
46
|
logger;
|
|
40
|
-
constructor(stateMachine,
|
|
47
|
+
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits, contractSyncService){
|
|
41
48
|
this.stateMachine = stateMachine;
|
|
42
|
-
this.
|
|
49
|
+
this.contractStore = contractStore;
|
|
50
|
+
this.noteStore = noteStore;
|
|
43
51
|
this.keyStore = keyStore;
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
52
|
+
this.addressStore = addressStore;
|
|
53
|
+
this.accountStore = accountStore;
|
|
54
|
+
this.senderTaggingStore = senderTaggingStore;
|
|
55
|
+
this.recipientTaggingStore = recipientTaggingStore;
|
|
56
|
+
this.senderAddressBookStore = senderAddressBookStore;
|
|
57
|
+
this.capsuleStore = capsuleStore;
|
|
58
|
+
this.privateEventStore = privateEventStore;
|
|
47
59
|
this.nextBlockTimestamp = nextBlockTimestamp;
|
|
48
60
|
this.version = version;
|
|
49
61
|
this.chainId = chainId;
|
|
50
62
|
this.authwits = authwits;
|
|
63
|
+
this.contractSyncService = contractSyncService;
|
|
51
64
|
this.isMisc = true;
|
|
52
65
|
this.isTxe = true;
|
|
53
66
|
this.logger = createLogger('txe:top_level_context');
|
|
54
67
|
this.logger.debug('Entering Top Level Context');
|
|
55
68
|
}
|
|
56
|
-
|
|
69
|
+
assertCompatibleOracleVersion(version) {
|
|
57
70
|
if (version !== ORACLE_VERSION) {
|
|
58
71
|
throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
|
|
59
72
|
}
|
|
60
73
|
}
|
|
61
74
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
62
75
|
// setup.
|
|
63
|
-
|
|
76
|
+
getRandomField() {
|
|
64
77
|
return Fr.random();
|
|
65
78
|
}
|
|
66
79
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
67
|
-
|
|
80
|
+
log(level, message, fields) {
|
|
68
81
|
if (!LogLevels[level]) {
|
|
69
|
-
throw new Error(`Invalid
|
|
82
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
70
83
|
}
|
|
71
84
|
const levelName = LogLevels[level];
|
|
72
85
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
|
|
73
86
|
module: `${this.logger.module}:debug_log`
|
|
74
87
|
});
|
|
88
|
+
return Promise.resolve();
|
|
75
89
|
}
|
|
76
|
-
|
|
77
|
-
return
|
|
90
|
+
getDefaultAddress() {
|
|
91
|
+
return DEFAULT_ADDRESS;
|
|
78
92
|
}
|
|
79
|
-
|
|
93
|
+
async getNextBlockNumber() {
|
|
94
|
+
return BlockNumber(await this.getLastBlockNumber() + 1);
|
|
95
|
+
}
|
|
96
|
+
getNextBlockTimestamp() {
|
|
80
97
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
81
98
|
}
|
|
82
|
-
async
|
|
99
|
+
async getLastBlockTimestamp() {
|
|
83
100
|
return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
|
|
84
101
|
}
|
|
85
|
-
async
|
|
86
|
-
const
|
|
102
|
+
async getLastTxEffects() {
|
|
103
|
+
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
104
|
+
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
87
105
|
if (block.body.txEffects.length != 1) {
|
|
88
106
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
89
107
|
throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
|
|
@@ -95,17 +113,39 @@ export class TXEOracleTopLevelContext {
|
|
|
95
113
|
nullifiers: txEffects.nullifiers
|
|
96
114
|
};
|
|
97
115
|
}
|
|
98
|
-
async
|
|
116
|
+
async syncContractNonOracleMethod(contractAddress, scope, jobId) {
|
|
117
|
+
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
118
|
+
this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
122
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
|
|
123
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
124
|
+
}, blockHeader, jobId, [
|
|
125
|
+
scope
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
async getPrivateEvents(selector, contractAddress, scope) {
|
|
129
|
+
return (await this.privateEventStore.getPrivateEvents(selector, {
|
|
130
|
+
contractAddress,
|
|
131
|
+
scopes: [
|
|
132
|
+
scope
|
|
133
|
+
],
|
|
134
|
+
fromBlock: 0,
|
|
135
|
+
toBlock: await this.getLastBlockNumber() + 1
|
|
136
|
+
})).map((e)=>e.packedEvent);
|
|
137
|
+
}
|
|
138
|
+
async advanceBlocksBy(blocks) {
|
|
99
139
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
100
140
|
for(let i = 0; i < blocks; i++){
|
|
101
141
|
await this.mineBlock();
|
|
102
142
|
}
|
|
103
143
|
}
|
|
104
|
-
|
|
144
|
+
advanceTimestampBy(duration) {
|
|
105
145
|
this.logger.debug(`time traveling ${duration} seconds`);
|
|
106
146
|
this.nextBlockTimestamp += duration;
|
|
107
147
|
}
|
|
108
|
-
async
|
|
148
|
+
async deploy(artifact, instance, secret) {
|
|
109
149
|
// Emit deployment nullifier
|
|
110
150
|
await this.mineBlock({
|
|
111
151
|
nullifiers: [
|
|
@@ -113,34 +153,34 @@ export class TXEOracleTopLevelContext {
|
|
|
113
153
|
]
|
|
114
154
|
});
|
|
115
155
|
if (!secret.equals(Fr.ZERO)) {
|
|
116
|
-
await this.
|
|
156
|
+
await this.addAccount(artifact, instance, secret);
|
|
117
157
|
} else {
|
|
118
|
-
await this.
|
|
119
|
-
await this.
|
|
158
|
+
await this.contractStore.addContractInstance(instance);
|
|
159
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
120
160
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
121
161
|
}
|
|
122
162
|
}
|
|
123
|
-
async
|
|
163
|
+
async addAccount(artifact, instance, secret) {
|
|
124
164
|
const partialAddress = await computePartialAddress(instance);
|
|
125
165
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
126
|
-
await this.
|
|
127
|
-
await this.
|
|
166
|
+
await this.contractStore.addContractInstance(instance);
|
|
167
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
128
168
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
129
|
-
await this.
|
|
130
|
-
await this.
|
|
169
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
170
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
131
171
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
132
172
|
return completeAddress;
|
|
133
173
|
}
|
|
134
|
-
async
|
|
135
|
-
// This is a
|
|
174
|
+
async createAccount(secret) {
|
|
175
|
+
// This is a foot gun !
|
|
136
176
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
137
|
-
await this.
|
|
138
|
-
await this.
|
|
177
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
178
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
139
179
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
140
180
|
return completeAddress;
|
|
141
181
|
}
|
|
142
|
-
async
|
|
143
|
-
const account = await this.
|
|
182
|
+
async addAuthWitness(address, messageHash) {
|
|
183
|
+
const account = await this.accountStore.getAccount(address);
|
|
144
184
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
145
185
|
const schnorr = new Schnorr();
|
|
146
186
|
const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
|
|
@@ -150,7 +190,7 @@ export class TXEOracleTopLevelContext {
|
|
|
150
190
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
151
191
|
}
|
|
152
192
|
async mineBlock(options = {}) {
|
|
153
|
-
const blockNumber = await this.
|
|
193
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
154
194
|
const txEffect = TxEffect.empty();
|
|
155
195
|
txEffect.nullifiers = [
|
|
156
196
|
getSingleTxBlockRequestHash(blockNumber),
|
|
@@ -159,42 +199,86 @@ export class TXEOracleTopLevelContext {
|
|
|
159
199
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
160
200
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
161
201
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
162
|
-
const
|
|
202
|
+
const globals = makeGlobalVariables(undefined, {
|
|
163
203
|
blockNumber,
|
|
164
204
|
timestamp: this.nextBlockTimestamp,
|
|
165
205
|
version: this.version,
|
|
166
206
|
chainId: this.chainId
|
|
167
|
-
})
|
|
207
|
+
});
|
|
208
|
+
const block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
168
209
|
txEffect
|
|
169
|
-
])
|
|
210
|
+
]);
|
|
170
211
|
await forkedWorldTrees.close();
|
|
171
212
|
this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
|
|
172
213
|
await this.stateMachine.handleL2Block(block);
|
|
173
214
|
}
|
|
174
|
-
async
|
|
175
|
-
this.logger.verbose(`Executing external function ${await this.
|
|
176
|
-
const artifact = await this.
|
|
215
|
+
async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
|
|
216
|
+
this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
217
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
177
218
|
if (!artifact) {
|
|
178
219
|
const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
|
|
179
220
|
throw new Error(message);
|
|
180
221
|
}
|
|
181
|
-
|
|
222
|
+
// When `from` is the zero address (e.g. when deploying a new account contract), we return an
|
|
223
|
+
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
224
|
+
const effectiveScopes = from.isZero() ? [] : [
|
|
225
|
+
from
|
|
226
|
+
];
|
|
227
|
+
// Sync notes before executing private function to discover notes from previous transactions
|
|
228
|
+
const utilityExecutor = async (call, execScopes)=>{
|
|
229
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
230
|
+
};
|
|
231
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
232
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
|
|
233
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
182
234
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
183
235
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
184
236
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
185
237
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
186
238
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
187
|
-
const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
|
|
188
239
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
189
240
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
241
|
+
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
242
|
+
// Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
|
|
243
|
+
// marking all side effects as revertible.
|
|
244
|
+
const minRevertibleSideEffectCounter = 1;
|
|
245
|
+
await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
|
|
190
246
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
191
247
|
const simulator = new WASMSimulator();
|
|
192
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
248
|
+
const privateExecutionOracle = new PrivateExecutionOracle({
|
|
249
|
+
argsHash,
|
|
250
|
+
txContext,
|
|
251
|
+
callContext,
|
|
252
|
+
anchorBlockHeader: blockHeader,
|
|
253
|
+
utilityExecutor,
|
|
254
|
+
authWitnesses: Array.from(this.authwits.values()),
|
|
255
|
+
capsules: [],
|
|
256
|
+
executionCache: HashedValuesCache.create([
|
|
257
|
+
new HashedValues(args, argsHash)
|
|
258
|
+
]),
|
|
259
|
+
noteCache,
|
|
260
|
+
taggingIndexCache,
|
|
261
|
+
contractStore: this.contractStore,
|
|
262
|
+
noteStore: this.noteStore,
|
|
263
|
+
keyStore: this.keyStore,
|
|
264
|
+
addressStore: this.addressStore,
|
|
265
|
+
aztecNode: this.stateMachine.node,
|
|
266
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
267
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
268
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
269
|
+
capsuleStore: this.capsuleStore,
|
|
270
|
+
privateEventStore: this.privateEventStore,
|
|
271
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
272
|
+
jobId,
|
|
273
|
+
totalPublicCalldataCount: 0,
|
|
274
|
+
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
275
|
+
scopes: effectiveScopes,
|
|
276
|
+
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
277
|
+
// contract would perform, including setting senderForTags.
|
|
278
|
+
senderForTags: from,
|
|
279
|
+
simulator,
|
|
280
|
+
messageContextService: this.stateMachine.messageContextService
|
|
281
|
+
});
|
|
198
282
|
// 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.
|
|
199
283
|
let result;
|
|
200
284
|
let executionResult;
|
|
@@ -206,21 +290,19 @@ export class TXEOracleTopLevelContext {
|
|
|
206
290
|
r.publicInputs.publicTeardownCallRequest
|
|
207
291
|
]));
|
|
208
292
|
const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
|
|
209
|
-
const calldata = await privateExecutionOracle.
|
|
293
|
+
const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
|
|
210
294
|
return new HashedValues(calldata, r.calldataHash);
|
|
211
295
|
}));
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
|
|
296
|
+
noteCache.finish();
|
|
297
|
+
const nonceGenerator = noteCache.getNonceGenerator();
|
|
298
|
+
result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
|
|
216
299
|
} catch (err) {
|
|
217
300
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
218
301
|
}
|
|
219
|
-
// According to the protocol rules,
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
const
|
|
223
|
-
const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
|
|
302
|
+
// According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
|
|
303
|
+
// the nonce generator for the note hashes.
|
|
304
|
+
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
305
|
+
const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
|
|
224
306
|
const globals = makeGlobalVariables();
|
|
225
307
|
globals.blockNumber = blockNumber;
|
|
226
308
|
globals.timestamp = this.nextBlockTimestamp;
|
|
@@ -228,7 +310,8 @@ export class TXEOracleTopLevelContext {
|
|
|
228
310
|
globals.version = this.version;
|
|
229
311
|
globals.gasFees = GasFees.empty();
|
|
230
312
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
231
|
-
const
|
|
313
|
+
const bindings = this.logger.getBindings();
|
|
314
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
|
|
232
315
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
233
316
|
const config = PublicSimulatorConfig.from({
|
|
234
317
|
skipFeeEnforcement: true,
|
|
@@ -237,7 +320,7 @@ export class TXEOracleTopLevelContext {
|
|
|
237
320
|
collectStatistics: false,
|
|
238
321
|
collectCallMetadata: true
|
|
239
322
|
});
|
|
240
|
-
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new
|
|
323
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
|
|
241
324
|
const tx = await Tx.create({
|
|
242
325
|
data: publicInputs,
|
|
243
326
|
chonkProof: ChonkProof.empty(),
|
|
@@ -258,7 +341,7 @@ export class TXEOracleTopLevelContext {
|
|
|
258
341
|
} else if (!processedTx.revertCode.isOK()) {
|
|
259
342
|
if (processedTx.revertReason) {
|
|
260
343
|
try {
|
|
261
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
344
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
262
345
|
// eslint-disable-next-line no-empty
|
|
263
346
|
} catch {}
|
|
264
347
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -280,22 +363,21 @@ export class TXEOracleTopLevelContext {
|
|
|
280
363
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
281
364
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
282
365
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
283
|
-
const
|
|
366
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
284
367
|
txEffect
|
|
285
368
|
]);
|
|
286
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
287
369
|
await this.stateMachine.handleL2Block(l2Block);
|
|
288
370
|
await forkedWorldTrees.close();
|
|
289
371
|
return executionResult.returnValues ?? [];
|
|
290
372
|
}
|
|
291
|
-
async
|
|
292
|
-
this.logger.verbose(`Executing public function ${await this.
|
|
293
|
-
const blockNumber = await this.
|
|
373
|
+
async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
|
|
374
|
+
this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
375
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
294
376
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
295
377
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
296
378
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
297
379
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
298
|
-
const anchorBlockHeader = await this.
|
|
380
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
299
381
|
const calldataHash = await computeCalldataHash(calldata);
|
|
300
382
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
301
383
|
const globals = makeGlobalVariables();
|
|
@@ -305,7 +387,8 @@ export class TXEOracleTopLevelContext {
|
|
|
305
387
|
globals.version = this.version;
|
|
306
388
|
globals.gasFees = GasFees.empty();
|
|
307
389
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
308
|
-
const
|
|
390
|
+
const bindings2 = this.logger.getBindings();
|
|
391
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
|
|
309
392
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
310
393
|
const config = PublicSimulatorConfig.from({
|
|
311
394
|
skipFeeEnforcement: true,
|
|
@@ -314,23 +397,21 @@ export class TXEOracleTopLevelContext {
|
|
|
314
397
|
collectStatistics: false,
|
|
315
398
|
collectCallMetadata: true
|
|
316
399
|
});
|
|
317
|
-
const simulator = new
|
|
318
|
-
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
|
|
400
|
+
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
401
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
|
|
319
402
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
320
403
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
321
404
|
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
322
405
|
// unique.
|
|
323
406
|
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
324
|
-
|
|
325
|
-
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
326
|
-
}
|
|
407
|
+
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
327
408
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
328
409
|
// may require producing reverts.
|
|
329
410
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
330
411
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
331
412
|
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
332
413
|
const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
|
|
333
|
-
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*
|
|
414
|
+
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
|
|
334
415
|
const tx = await Tx.create({
|
|
335
416
|
data: txData,
|
|
336
417
|
chonkProof: ChonkProof.empty(),
|
|
@@ -353,7 +434,7 @@ export class TXEOracleTopLevelContext {
|
|
|
353
434
|
} else if (!processedTx.revertCode.isOK()) {
|
|
354
435
|
if (processedTx.revertReason) {
|
|
355
436
|
try {
|
|
356
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
437
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
357
438
|
// eslint-disable-next-line no-empty
|
|
358
439
|
} catch {}
|
|
359
440
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -376,25 +457,37 @@ export class TXEOracleTopLevelContext {
|
|
|
376
457
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
377
458
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
378
459
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
379
|
-
const
|
|
460
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
380
461
|
txEffect
|
|
381
462
|
]);
|
|
382
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
383
463
|
await this.stateMachine.handleL2Block(l2Block);
|
|
384
464
|
await forkedWorldTrees.close();
|
|
385
465
|
return returnValues ?? [];
|
|
386
466
|
}
|
|
387
|
-
async
|
|
388
|
-
const artifact = await this.
|
|
467
|
+
async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
|
|
468
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
389
469
|
if (!artifact) {
|
|
390
470
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
391
471
|
}
|
|
392
|
-
|
|
472
|
+
// Sync notes before executing utility function to discover notes from previous transactions
|
|
473
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
474
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
|
|
475
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
476
|
+
}, blockHeader, jobId, 'ALL_SCOPES');
|
|
477
|
+
const call = FunctionCall.from({
|
|
393
478
|
name: artifact.name,
|
|
479
|
+
to: targetContractAddress,
|
|
394
480
|
selector: functionSelector,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
481
|
+
type: FunctionType.UTILITY,
|
|
482
|
+
hideMsgSender: false,
|
|
483
|
+
isStatic: false,
|
|
484
|
+
args,
|
|
485
|
+
returnTypes: []
|
|
486
|
+
});
|
|
487
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
|
|
488
|
+
}
|
|
489
|
+
async executeUtilityCall(call, scopes, jobId) {
|
|
490
|
+
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
398
491
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
399
492
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
400
493
|
}
|
|
@@ -403,8 +496,27 @@ export class TXEOracleTopLevelContext {
|
|
|
403
496
|
selector: call.selector
|
|
404
497
|
});
|
|
405
498
|
try {
|
|
406
|
-
const
|
|
407
|
-
const
|
|
499
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
500
|
+
const oracle = new UtilityExecutionOracle({
|
|
501
|
+
contractAddress: call.to,
|
|
502
|
+
authWitnesses: [],
|
|
503
|
+
capsules: [],
|
|
504
|
+
anchorBlockHeader,
|
|
505
|
+
contractStore: this.contractStore,
|
|
506
|
+
noteStore: this.noteStore,
|
|
507
|
+
keyStore: this.keyStore,
|
|
508
|
+
addressStore: this.addressStore,
|
|
509
|
+
aztecNode: this.stateMachine.node,
|
|
510
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
511
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
512
|
+
capsuleStore: this.capsuleStore,
|
|
513
|
+
privateEventStore: this.privateEventStore,
|
|
514
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
515
|
+
contractSyncService: this.contractSyncService,
|
|
516
|
+
jobId,
|
|
517
|
+
scopes
|
|
518
|
+
});
|
|
519
|
+
const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
|
|
408
520
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
409
521
|
throw new ExecutionError(err.message, {
|
|
410
522
|
contractAddress: call.to,
|
|
@@ -413,10 +525,10 @@ export class TXEOracleTopLevelContext {
|
|
|
413
525
|
cause: err
|
|
414
526
|
});
|
|
415
527
|
});
|
|
416
|
-
this.logger.verbose(`Utility
|
|
528
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
417
529
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
418
530
|
} catch (err) {
|
|
419
|
-
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility
|
|
531
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
|
|
420
532
|
}
|
|
421
533
|
}
|
|
422
534
|
close() {
|
|
@@ -427,6 +539,7 @@ export class TXEOracleTopLevelContext {
|
|
|
427
539
|
];
|
|
428
540
|
}
|
|
429
541
|
async getLastBlockNumber() {
|
|
430
|
-
|
|
542
|
+
const header = await this.stateMachine.node.getBlockHeader('latest');
|
|
543
|
+
return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
431
544
|
}
|
|
432
545
|
}
|