@aztec/txe 0.0.1-commit.b655e406 → 0.0.1-commit.b6e433891
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/bin/index.d.ts +1 -1
- 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 +228 -106
- package/dest/rpc_translator.d.ts +98 -78
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +367 -171
- package/dest/state_machine/archiver.d.ts +21 -51
- 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 +21 -14
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +42 -22
- package/dest/state_machine/global_variable_builder.d.ts +6 -4
- 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 +30 -12
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +53 -15
- 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 +173 -56
- package/dest/util/encoding.d.ts +615 -16
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +1 -1
- package/dest/util/expected_failure_error.d.ts +1 -1
- package/dest/util/expected_failure_error.d.ts.map +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 +12 -29
- 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 -17
- 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 +272 -145
- package/src/rpc_translator.ts +422 -194
- package/src/state_machine/archiver.ts +63 -117
- package/src/state_machine/dummy_p2p_client.ts +59 -29
- package/src/state_machine/global_variable_builder.ts +22 -4
- package/src/state_machine/index.ts +64 -21
- package/src/state_machine/mock_epoch_cache.ts +67 -23
- package/src/state_machine/synchronizer.ts +9 -8
- package/src/txe_session.ts +239 -105
- 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 -45
- package/src/utils/block_creation.ts +49 -14
- 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,88 +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';
|
|
13
|
+
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
12
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
|
-
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
14
15
|
import { computePartialAddress } from '@aztec/stdlib/contract';
|
|
15
16
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
16
|
-
import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
|
|
17
|
+
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
17
18
|
import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
18
19
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
19
|
-
import {
|
|
20
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
20
21
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
21
22
|
import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
22
23
|
import { ForkCheckpoint } from '@aztec/world-state';
|
|
24
|
+
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
23
25
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
24
|
-
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees,
|
|
26
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
25
27
|
export class TXEOracleTopLevelContext {
|
|
26
28
|
stateMachine;
|
|
27
|
-
|
|
29
|
+
contractStore;
|
|
30
|
+
noteStore;
|
|
28
31
|
keyStore;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
addressStore;
|
|
33
|
+
accountStore;
|
|
34
|
+
senderTaggingStore;
|
|
35
|
+
recipientTaggingStore;
|
|
36
|
+
senderAddressBookStore;
|
|
37
|
+
capsuleStore;
|
|
38
|
+
privateEventStore;
|
|
32
39
|
nextBlockTimestamp;
|
|
33
40
|
version;
|
|
34
41
|
chainId;
|
|
35
42
|
authwits;
|
|
43
|
+
contractSyncService;
|
|
36
44
|
isMisc;
|
|
37
45
|
isTxe;
|
|
38
46
|
logger;
|
|
39
|
-
constructor(stateMachine,
|
|
47
|
+
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits, contractSyncService){
|
|
40
48
|
this.stateMachine = stateMachine;
|
|
41
|
-
this.
|
|
49
|
+
this.contractStore = contractStore;
|
|
50
|
+
this.noteStore = noteStore;
|
|
42
51
|
this.keyStore = keyStore;
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
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;
|
|
46
59
|
this.nextBlockTimestamp = nextBlockTimestamp;
|
|
47
60
|
this.version = version;
|
|
48
61
|
this.chainId = chainId;
|
|
49
62
|
this.authwits = authwits;
|
|
63
|
+
this.contractSyncService = contractSyncService;
|
|
50
64
|
this.isMisc = true;
|
|
51
65
|
this.isTxe = true;
|
|
52
66
|
this.logger = createLogger('txe:top_level_context');
|
|
53
67
|
this.logger.debug('Entering Top Level Context');
|
|
54
68
|
}
|
|
55
|
-
|
|
69
|
+
assertCompatibleOracleVersion(version) {
|
|
56
70
|
if (version !== ORACLE_VERSION) {
|
|
57
71
|
throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
|
|
58
72
|
}
|
|
59
73
|
}
|
|
60
74
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
61
75
|
// setup.
|
|
62
|
-
|
|
76
|
+
getRandomField() {
|
|
63
77
|
return Fr.random();
|
|
64
78
|
}
|
|
65
79
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
66
|
-
|
|
80
|
+
log(level, message, fields) {
|
|
67
81
|
if (!LogLevels[level]) {
|
|
68
|
-
throw new Error(`Invalid
|
|
82
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
69
83
|
}
|
|
70
84
|
const levelName = LogLevels[level];
|
|
71
85
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
|
|
72
86
|
module: `${this.logger.module}:debug_log`
|
|
73
87
|
});
|
|
88
|
+
return Promise.resolve();
|
|
74
89
|
}
|
|
75
|
-
|
|
76
|
-
return
|
|
90
|
+
getDefaultAddress() {
|
|
91
|
+
return DEFAULT_ADDRESS;
|
|
77
92
|
}
|
|
78
|
-
|
|
93
|
+
async getNextBlockNumber() {
|
|
94
|
+
return BlockNumber(await this.getLastBlockNumber() + 1);
|
|
95
|
+
}
|
|
96
|
+
getNextBlockTimestamp() {
|
|
79
97
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
80
98
|
}
|
|
81
|
-
async
|
|
99
|
+
async getLastBlockTimestamp() {
|
|
82
100
|
return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
|
|
83
101
|
}
|
|
84
|
-
async
|
|
85
|
-
const
|
|
102
|
+
async getLastTxEffects() {
|
|
103
|
+
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
104
|
+
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
86
105
|
if (block.body.txEffects.length != 1) {
|
|
87
106
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
88
107
|
throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
|
|
@@ -94,17 +113,39 @@ export class TXEOracleTopLevelContext {
|
|
|
94
113
|
nullifiers: txEffects.nullifiers
|
|
95
114
|
};
|
|
96
115
|
}
|
|
97
|
-
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) {
|
|
98
139
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
99
140
|
for(let i = 0; i < blocks; i++){
|
|
100
141
|
await this.mineBlock();
|
|
101
142
|
}
|
|
102
143
|
}
|
|
103
|
-
|
|
144
|
+
advanceTimestampBy(duration) {
|
|
104
145
|
this.logger.debug(`time traveling ${duration} seconds`);
|
|
105
146
|
this.nextBlockTimestamp += duration;
|
|
106
147
|
}
|
|
107
|
-
async
|
|
148
|
+
async deploy(artifact, instance, secret) {
|
|
108
149
|
// Emit deployment nullifier
|
|
109
150
|
await this.mineBlock({
|
|
110
151
|
nullifiers: [
|
|
@@ -112,34 +153,34 @@ export class TXEOracleTopLevelContext {
|
|
|
112
153
|
]
|
|
113
154
|
});
|
|
114
155
|
if (!secret.equals(Fr.ZERO)) {
|
|
115
|
-
await this.
|
|
156
|
+
await this.addAccount(artifact, instance, secret);
|
|
116
157
|
} else {
|
|
117
|
-
await this.
|
|
118
|
-
await this.
|
|
158
|
+
await this.contractStore.addContractInstance(instance);
|
|
159
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
119
160
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
120
161
|
}
|
|
121
162
|
}
|
|
122
|
-
async
|
|
163
|
+
async addAccount(artifact, instance, secret) {
|
|
123
164
|
const partialAddress = await computePartialAddress(instance);
|
|
124
165
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
125
|
-
await this.
|
|
126
|
-
await this.
|
|
166
|
+
await this.contractStore.addContractInstance(instance);
|
|
167
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
127
168
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
128
|
-
await this.
|
|
129
|
-
await this.
|
|
169
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
170
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
130
171
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
131
172
|
return completeAddress;
|
|
132
173
|
}
|
|
133
|
-
async
|
|
134
|
-
// This is a
|
|
174
|
+
async createAccount(secret) {
|
|
175
|
+
// This is a foot gun !
|
|
135
176
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
136
|
-
await this.
|
|
137
|
-
await this.
|
|
177
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
178
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
138
179
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
139
180
|
return completeAddress;
|
|
140
181
|
}
|
|
141
|
-
async
|
|
142
|
-
const account = await this.
|
|
182
|
+
async addAuthWitness(address, messageHash) {
|
|
183
|
+
const account = await this.accountStore.getAccount(address);
|
|
143
184
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
144
185
|
const schnorr = new Schnorr();
|
|
145
186
|
const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
|
|
@@ -149,7 +190,7 @@ export class TXEOracleTopLevelContext {
|
|
|
149
190
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
150
191
|
}
|
|
151
192
|
async mineBlock(options = {}) {
|
|
152
|
-
const blockNumber = await this.
|
|
193
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
153
194
|
const txEffect = TxEffect.empty();
|
|
154
195
|
txEffect.nullifiers = [
|
|
155
196
|
getSingleTxBlockRequestHash(blockNumber),
|
|
@@ -158,42 +199,86 @@ export class TXEOracleTopLevelContext {
|
|
|
158
199
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
159
200
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
160
201
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
161
|
-
const
|
|
202
|
+
const globals = makeGlobalVariables(undefined, {
|
|
162
203
|
blockNumber,
|
|
163
204
|
timestamp: this.nextBlockTimestamp,
|
|
164
205
|
version: this.version,
|
|
165
206
|
chainId: this.chainId
|
|
166
|
-
})
|
|
207
|
+
});
|
|
208
|
+
const block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
167
209
|
txEffect
|
|
168
|
-
])
|
|
210
|
+
]);
|
|
169
211
|
await forkedWorldTrees.close();
|
|
170
212
|
this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
|
|
171
213
|
await this.stateMachine.handleL2Block(block);
|
|
172
214
|
}
|
|
173
|
-
async
|
|
174
|
-
this.logger.verbose(`Executing external function ${await this.
|
|
175
|
-
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);
|
|
176
218
|
if (!artifact) {
|
|
177
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';
|
|
178
220
|
throw new Error(message);
|
|
179
221
|
}
|
|
180
|
-
|
|
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();
|
|
181
234
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
182
235
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
183
236
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
184
237
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
185
238
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
239
|
+
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
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);
|
|
189
246
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
190
247
|
const simulator = new WASMSimulator();
|
|
191
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
+
});
|
|
197
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.
|
|
198
283
|
let result;
|
|
199
284
|
let executionResult;
|
|
@@ -205,21 +290,19 @@ export class TXEOracleTopLevelContext {
|
|
|
205
290
|
r.publicInputs.publicTeardownCallRequest
|
|
206
291
|
]));
|
|
207
292
|
const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
|
|
208
|
-
const calldata = await privateExecutionOracle.
|
|
293
|
+
const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
|
|
209
294
|
return new HashedValues(calldata, r.calldataHash);
|
|
210
295
|
}));
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
|
|
296
|
+
noteCache.finish();
|
|
297
|
+
const nonceGenerator = noteCache.getNonceGenerator();
|
|
298
|
+
result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
|
|
215
299
|
} catch (err) {
|
|
216
300
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
217
301
|
}
|
|
218
|
-
// According to the protocol rules,
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
const
|
|
222
|
-
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);
|
|
223
306
|
const globals = makeGlobalVariables();
|
|
224
307
|
globals.blockNumber = blockNumber;
|
|
225
308
|
globals.timestamp = this.nextBlockTimestamp;
|
|
@@ -227,12 +310,17 @@ export class TXEOracleTopLevelContext {
|
|
|
227
310
|
globals.version = this.version;
|
|
228
311
|
globals.gasFees = GasFees.empty();
|
|
229
312
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
230
|
-
const
|
|
313
|
+
const bindings = this.logger.getBindings();
|
|
314
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
|
|
231
315
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
316
|
+
const config = PublicSimulatorConfig.from({
|
|
317
|
+
skipFeeEnforcement: true,
|
|
318
|
+
collectDebugLogs: true,
|
|
319
|
+
collectHints: false,
|
|
320
|
+
collectStatistics: false,
|
|
321
|
+
collectCallMetadata: true
|
|
322
|
+
});
|
|
323
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
|
|
236
324
|
const tx = await Tx.create({
|
|
237
325
|
data: publicInputs,
|
|
238
326
|
chonkProof: ChonkProof.empty(),
|
|
@@ -253,7 +341,7 @@ export class TXEOracleTopLevelContext {
|
|
|
253
341
|
} else if (!processedTx.revertCode.isOK()) {
|
|
254
342
|
if (processedTx.revertReason) {
|
|
255
343
|
try {
|
|
256
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
344
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
257
345
|
// eslint-disable-next-line no-empty
|
|
258
346
|
} catch {}
|
|
259
347
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -275,22 +363,21 @@ export class TXEOracleTopLevelContext {
|
|
|
275
363
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
276
364
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
277
365
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
278
|
-
const
|
|
366
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
279
367
|
txEffect
|
|
280
368
|
]);
|
|
281
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
282
369
|
await this.stateMachine.handleL2Block(l2Block);
|
|
283
370
|
await forkedWorldTrees.close();
|
|
284
371
|
return executionResult.returnValues ?? [];
|
|
285
372
|
}
|
|
286
|
-
async
|
|
287
|
-
this.logger.verbose(`Executing public function ${await this.
|
|
288
|
-
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();
|
|
289
376
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
290
377
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
291
378
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
292
379
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
293
|
-
const anchorBlockHeader = await this.
|
|
380
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
294
381
|
const calldataHash = await computeCalldataHash(calldata);
|
|
295
382
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
296
383
|
const globals = makeGlobalVariables();
|
|
@@ -300,28 +387,31 @@ export class TXEOracleTopLevelContext {
|
|
|
300
387
|
globals.version = this.version;
|
|
301
388
|
globals.gasFees = GasFees.empty();
|
|
302
389
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
303
|
-
const
|
|
390
|
+
const bindings2 = this.logger.getBindings();
|
|
391
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
|
|
304
392
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
393
|
+
const config = PublicSimulatorConfig.from({
|
|
394
|
+
skipFeeEnforcement: true,
|
|
395
|
+
collectDebugLogs: true,
|
|
396
|
+
collectHints: false,
|
|
397
|
+
collectStatistics: false,
|
|
398
|
+
collectCallMetadata: true
|
|
308
399
|
});
|
|
309
|
-
const
|
|
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));
|
|
310
402
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
311
403
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
312
404
|
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
313
405
|
// unique.
|
|
314
406
|
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
315
|
-
|
|
316
|
-
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
317
|
-
}
|
|
407
|
+
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
318
408
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
319
409
|
// may require producing reverts.
|
|
320
410
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
321
411
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
322
412
|
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
323
413
|
const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
|
|
324
|
-
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);
|
|
325
415
|
const tx = await Tx.create({
|
|
326
416
|
data: txData,
|
|
327
417
|
chonkProof: ChonkProof.empty(),
|
|
@@ -344,7 +434,7 @@ export class TXEOracleTopLevelContext {
|
|
|
344
434
|
} else if (!processedTx.revertCode.isOK()) {
|
|
345
435
|
if (processedTx.revertReason) {
|
|
346
436
|
try {
|
|
347
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
437
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
348
438
|
// eslint-disable-next-line no-empty
|
|
349
439
|
} catch {}
|
|
350
440
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -367,25 +457,37 @@ export class TXEOracleTopLevelContext {
|
|
|
367
457
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
368
458
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
369
459
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
370
|
-
const
|
|
460
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
371
461
|
txEffect
|
|
372
462
|
]);
|
|
373
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
374
463
|
await this.stateMachine.handleL2Block(l2Block);
|
|
375
464
|
await forkedWorldTrees.close();
|
|
376
465
|
return returnValues ?? [];
|
|
377
466
|
}
|
|
378
|
-
async
|
|
379
|
-
const artifact = await this.
|
|
467
|
+
async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
|
|
468
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
380
469
|
if (!artifact) {
|
|
381
470
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
382
471
|
}
|
|
383
|
-
|
|
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({
|
|
384
478
|
name: artifact.name,
|
|
479
|
+
to: targetContractAddress,
|
|
385
480
|
selector: functionSelector,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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);
|
|
389
491
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
390
492
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
391
493
|
}
|
|
@@ -394,8 +496,27 @@ export class TXEOracleTopLevelContext {
|
|
|
394
496
|
selector: call.selector
|
|
395
497
|
});
|
|
396
498
|
try {
|
|
397
|
-
const
|
|
398
|
-
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)=>{
|
|
399
520
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
400
521
|
throw new ExecutionError(err.message, {
|
|
401
522
|
contractAddress: call.to,
|
|
@@ -404,10 +525,10 @@ export class TXEOracleTopLevelContext {
|
|
|
404
525
|
cause: err
|
|
405
526
|
});
|
|
406
527
|
});
|
|
407
|
-
this.logger.verbose(`Utility
|
|
528
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
408
529
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
409
530
|
} catch (err) {
|
|
410
|
-
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'));
|
|
411
532
|
}
|
|
412
533
|
}
|
|
413
534
|
close() {
|
|
@@ -418,6 +539,7 @@ export class TXEOracleTopLevelContext {
|
|
|
418
539
|
];
|
|
419
540
|
}
|
|
420
541
|
async getLastBlockNumber() {
|
|
421
|
-
|
|
542
|
+
const header = await this.stateMachine.node.getBlockHeader('latest');
|
|
543
|
+
return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
422
544
|
}
|
|
423
545
|
}
|