@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
|
@@ -6,15 +6,24 @@ import {
|
|
|
6
6
|
DEFAULT_TEARDOWN_L2_GAS_LIMIT,
|
|
7
7
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
8
8
|
} from '@aztec/constants';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
10
|
+
import { Schnorr } from '@aztec/foundation/crypto/schnorr';
|
|
11
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
11
12
|
import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
12
13
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
13
14
|
import type { KeyStore } from '@aztec/key-store';
|
|
15
|
+
import type { AccessScopes } from '@aztec/pxe/client/lazy';
|
|
14
16
|
import {
|
|
15
|
-
|
|
17
|
+
AddressStore,
|
|
18
|
+
CapsuleStore,
|
|
19
|
+
type ContractStore,
|
|
20
|
+
type ContractSyncService,
|
|
21
|
+
NoteStore,
|
|
16
22
|
ORACLE_VERSION,
|
|
17
|
-
|
|
23
|
+
PrivateEventStore,
|
|
24
|
+
RecipientTaggingStore,
|
|
25
|
+
SenderAddressBookStore,
|
|
26
|
+
SenderTaggingStore,
|
|
18
27
|
enrichPublicSimulationError,
|
|
19
28
|
} from '@aztec/pxe/server';
|
|
20
29
|
import {
|
|
@@ -38,16 +47,15 @@ import {
|
|
|
38
47
|
witnessMapToFields,
|
|
39
48
|
} from '@aztec/simulator/client';
|
|
40
49
|
import {
|
|
50
|
+
CppPublicTxSimulator,
|
|
41
51
|
GuardedMerkleTreeOperations,
|
|
42
52
|
PublicContractsDB,
|
|
43
53
|
PublicProcessor,
|
|
44
|
-
PublicTxSimulator,
|
|
45
54
|
} from '@aztec/simulator/server';
|
|
46
|
-
import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
55
|
+
import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
47
56
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
48
57
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
49
58
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
50
|
-
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
51
59
|
import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
|
|
52
60
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
53
61
|
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
@@ -58,7 +66,7 @@ import {
|
|
|
58
66
|
PublicCallRequest,
|
|
59
67
|
} from '@aztec/stdlib/kernel';
|
|
60
68
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
61
|
-
import {
|
|
69
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
62
70
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
63
71
|
import {
|
|
64
72
|
CallContext,
|
|
@@ -75,15 +83,11 @@ import {
|
|
|
75
83
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
76
84
|
import { ForkCheckpoint } from '@aztec/world-state';
|
|
77
85
|
|
|
86
|
+
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
78
87
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
79
|
-
import type {
|
|
80
|
-
import type { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
|
|
88
|
+
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
81
89
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
82
|
-
import {
|
|
83
|
-
getSingleTxBlockRequestHash,
|
|
84
|
-
insertTxEffectIntoWorldTrees,
|
|
85
|
-
makeTXEBlockHeader,
|
|
86
|
-
} from '../utils/block_creation.js';
|
|
90
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
87
91
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
88
92
|
|
|
89
93
|
export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
|
|
@@ -94,21 +98,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
94
98
|
|
|
95
99
|
constructor(
|
|
96
100
|
private stateMachine: TXEStateMachine,
|
|
97
|
-
private
|
|
101
|
+
private contractStore: ContractStore,
|
|
102
|
+
private noteStore: NoteStore,
|
|
98
103
|
private keyStore: KeyStore,
|
|
99
|
-
private
|
|
100
|
-
private
|
|
101
|
-
private
|
|
104
|
+
private addressStore: AddressStore,
|
|
105
|
+
private accountStore: TXEAccountStore,
|
|
106
|
+
private senderTaggingStore: SenderTaggingStore,
|
|
107
|
+
private recipientTaggingStore: RecipientTaggingStore,
|
|
108
|
+
private senderAddressBookStore: SenderAddressBookStore,
|
|
109
|
+
private capsuleStore: CapsuleStore,
|
|
110
|
+
private privateEventStore: PrivateEventStore,
|
|
102
111
|
private nextBlockTimestamp: bigint,
|
|
103
112
|
private version: Fr,
|
|
104
113
|
private chainId: Fr,
|
|
105
114
|
private authwits: Map<string, AuthWitness>,
|
|
115
|
+
private readonly contractSyncService: ContractSyncService,
|
|
106
116
|
) {
|
|
107
117
|
this.logger = createLogger('txe:top_level_context');
|
|
108
118
|
this.logger.debug('Entering Top Level Context');
|
|
109
119
|
}
|
|
110
120
|
|
|
111
|
-
|
|
121
|
+
assertCompatibleOracleVersion(version: number): void {
|
|
112
122
|
if (version !== ORACLE_VERSION) {
|
|
113
123
|
throw new Error(
|
|
114
124
|
`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
|
|
@@ -118,34 +128,40 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
118
128
|
|
|
119
129
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
120
130
|
// setup.
|
|
121
|
-
|
|
131
|
+
getRandomField(): Fr {
|
|
122
132
|
return Fr.random();
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
126
|
-
|
|
136
|
+
log(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
127
137
|
if (!LogLevels[level]) {
|
|
128
|
-
throw new Error(`Invalid
|
|
138
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
129
139
|
}
|
|
130
140
|
const levelName = LogLevels[level];
|
|
131
141
|
|
|
132
142
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
|
|
143
|
+
return Promise.resolve();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getDefaultAddress(): AztecAddress {
|
|
147
|
+
return DEFAULT_ADDRESS;
|
|
133
148
|
}
|
|
134
149
|
|
|
135
|
-
async
|
|
136
|
-
return (await this.getLastBlockNumber()) + 1;
|
|
150
|
+
async getNextBlockNumber(): Promise<BlockNumber> {
|
|
151
|
+
return BlockNumber((await this.getLastBlockNumber()) + 1);
|
|
137
152
|
}
|
|
138
153
|
|
|
139
|
-
|
|
154
|
+
getNextBlockTimestamp(): Promise<bigint> {
|
|
140
155
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
141
156
|
}
|
|
142
157
|
|
|
143
|
-
async
|
|
158
|
+
async getLastBlockTimestamp() {
|
|
144
159
|
return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
|
|
145
160
|
}
|
|
146
161
|
|
|
147
|
-
async
|
|
148
|
-
const
|
|
162
|
+
async getLastTxEffects() {
|
|
163
|
+
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
164
|
+
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
149
165
|
|
|
150
166
|
if (block!.body.txEffects.length != 1) {
|
|
151
167
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
@@ -157,7 +173,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
157
173
|
return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
|
|
158
174
|
}
|
|
159
175
|
|
|
160
|
-
async
|
|
176
|
+
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
177
|
+
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
178
|
+
this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
183
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
184
|
+
contractAddress,
|
|
185
|
+
null,
|
|
186
|
+
async (call, execScopes) => {
|
|
187
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
188
|
+
},
|
|
189
|
+
blockHeader,
|
|
190
|
+
jobId,
|
|
191
|
+
[scope],
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
196
|
+
return (
|
|
197
|
+
await this.privateEventStore.getPrivateEvents(selector, {
|
|
198
|
+
contractAddress,
|
|
199
|
+
scopes: [scope],
|
|
200
|
+
fromBlock: 0,
|
|
201
|
+
toBlock: (await this.getLastBlockNumber()) + 1,
|
|
202
|
+
})
|
|
203
|
+
).map(e => e.packedEvent);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async advanceBlocksBy(blocks: number) {
|
|
161
207
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
162
208
|
|
|
163
209
|
for (let i = 0; i < blocks; i++) {
|
|
@@ -165,12 +211,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
165
211
|
}
|
|
166
212
|
}
|
|
167
213
|
|
|
168
|
-
|
|
214
|
+
advanceTimestampBy(duration: UInt64) {
|
|
169
215
|
this.logger.debug(`time traveling ${duration} seconds`);
|
|
170
216
|
this.nextBlockTimestamp += duration;
|
|
171
217
|
}
|
|
172
218
|
|
|
173
|
-
async
|
|
219
|
+
async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
|
|
174
220
|
// Emit deployment nullifier
|
|
175
221
|
await this.mineBlock({
|
|
176
222
|
nullifiers: [
|
|
@@ -182,41 +228,41 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
182
228
|
});
|
|
183
229
|
|
|
184
230
|
if (!secret.equals(Fr.ZERO)) {
|
|
185
|
-
await this.
|
|
231
|
+
await this.addAccount(artifact, instance, secret);
|
|
186
232
|
} else {
|
|
187
|
-
await this.
|
|
188
|
-
await this.
|
|
233
|
+
await this.contractStore.addContractInstance(instance);
|
|
234
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
189
235
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
190
236
|
}
|
|
191
237
|
}
|
|
192
238
|
|
|
193
|
-
async
|
|
239
|
+
async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
|
|
194
240
|
const partialAddress = await computePartialAddress(instance);
|
|
195
241
|
|
|
196
242
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
197
|
-
await this.
|
|
198
|
-
await this.
|
|
243
|
+
await this.contractStore.addContractInstance(instance);
|
|
244
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
199
245
|
|
|
200
246
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
201
|
-
await this.
|
|
202
|
-
await this.
|
|
247
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
248
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
203
249
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
204
250
|
|
|
205
251
|
return completeAddress;
|
|
206
252
|
}
|
|
207
253
|
|
|
208
|
-
async
|
|
209
|
-
// This is a
|
|
254
|
+
async createAccount(secret: Fr) {
|
|
255
|
+
// This is a foot gun !
|
|
210
256
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
211
|
-
await this.
|
|
212
|
-
await this.
|
|
257
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
258
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
213
259
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
214
260
|
|
|
215
261
|
return completeAddress;
|
|
216
262
|
}
|
|
217
263
|
|
|
218
|
-
async
|
|
219
|
-
const account = await this.
|
|
264
|
+
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
265
|
+
const account = await this.accountStore.getAccount(address);
|
|
220
266
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
221
267
|
|
|
222
268
|
const schnorr = new Schnorr();
|
|
@@ -228,7 +274,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
228
274
|
}
|
|
229
275
|
|
|
230
276
|
async mineBlock(options: { nullifiers?: Fr[] } = {}) {
|
|
231
|
-
const blockNumber = await this.
|
|
277
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
232
278
|
|
|
233
279
|
const txEffect = TxEffect.empty();
|
|
234
280
|
txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
|
|
@@ -237,19 +283,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
237
283
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
238
284
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
239
285
|
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
version: this.version,
|
|
248
|
-
chainId: this.chainId,
|
|
249
|
-
}),
|
|
250
|
-
),
|
|
251
|
-
new Body([txEffect]),
|
|
252
|
-
);
|
|
286
|
+
const globals = makeGlobalVariables(undefined, {
|
|
287
|
+
blockNumber,
|
|
288
|
+
timestamp: this.nextBlockTimestamp,
|
|
289
|
+
version: this.version,
|
|
290
|
+
chainId: this.chainId,
|
|
291
|
+
});
|
|
292
|
+
const block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
|
|
253
293
|
|
|
254
294
|
await forkedWorldTrees.close();
|
|
255
295
|
|
|
@@ -258,19 +298,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
258
298
|
await this.stateMachine.handleL2Block(block);
|
|
259
299
|
}
|
|
260
300
|
|
|
261
|
-
async
|
|
301
|
+
async privateCallNewFlow(
|
|
262
302
|
from: AztecAddress,
|
|
263
303
|
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
264
304
|
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
265
305
|
args: Fr[],
|
|
266
306
|
argsHash: Fr = Fr.zero(),
|
|
267
307
|
isStaticCall: boolean = false,
|
|
308
|
+
jobId: string,
|
|
268
309
|
) {
|
|
269
310
|
this.logger.verbose(
|
|
270
|
-
`Executing external function ${await this.
|
|
311
|
+
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
271
312
|
);
|
|
272
313
|
|
|
273
|
-
const artifact = await this.
|
|
314
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
274
315
|
if (!artifact) {
|
|
275
316
|
const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
|
|
276
317
|
? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
|
|
@@ -278,51 +319,78 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
278
319
|
throw new Error(message);
|
|
279
320
|
}
|
|
280
321
|
|
|
281
|
-
|
|
322
|
+
// When `from` is the zero address (e.g. when deploying a new account contract), we return an
|
|
323
|
+
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
324
|
+
const effectiveScopes = from.isZero() ? [] : [from];
|
|
325
|
+
|
|
326
|
+
// Sync notes before executing private function to discover notes from previous transactions
|
|
327
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
|
|
328
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
332
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
333
|
+
targetContractAddress,
|
|
334
|
+
functionSelector,
|
|
335
|
+
utilityExecutor,
|
|
336
|
+
blockHeader,
|
|
337
|
+
jobId,
|
|
338
|
+
effectiveScopes,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
282
342
|
|
|
283
343
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
284
344
|
|
|
285
345
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
286
|
-
|
|
287
346
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
288
|
-
|
|
289
347
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
290
348
|
|
|
291
349
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
292
350
|
|
|
293
|
-
const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
|
|
294
|
-
|
|
295
351
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
296
352
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
353
|
+
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
354
|
+
// Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
|
|
355
|
+
// marking all side effects as revertible.
|
|
356
|
+
const minRevertibleSideEffectCounter = 1;
|
|
357
|
+
await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
|
|
297
358
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
298
359
|
|
|
299
360
|
const simulator = new WASMSimulator();
|
|
300
361
|
|
|
301
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
362
|
+
const privateExecutionOracle = new PrivateExecutionOracle({
|
|
302
363
|
argsHash,
|
|
303
364
|
txContext,
|
|
304
365
|
callContext,
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
[],
|
|
311
|
-
HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
366
|
+
anchorBlockHeader: blockHeader,
|
|
367
|
+
utilityExecutor,
|
|
368
|
+
authWitnesses: Array.from(this.authwits.values()),
|
|
369
|
+
capsules: [],
|
|
370
|
+
executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
312
371
|
noteCache,
|
|
313
372
|
taggingIndexCache,
|
|
314
|
-
this.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
373
|
+
contractStore: this.contractStore,
|
|
374
|
+
noteStore: this.noteStore,
|
|
375
|
+
keyStore: this.keyStore,
|
|
376
|
+
addressStore: this.addressStore,
|
|
377
|
+
aztecNode: this.stateMachine.node,
|
|
378
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
379
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
380
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
381
|
+
capsuleStore: this.capsuleStore,
|
|
382
|
+
privateEventStore: this.privateEventStore,
|
|
383
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
384
|
+
jobId,
|
|
385
|
+
totalPublicCalldataCount: 0,
|
|
386
|
+
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
387
|
+
scopes: effectiveScopes,
|
|
388
|
+
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
389
|
+
// contract would perform, including setting senderForTags.
|
|
390
|
+
senderForTags: from,
|
|
324
391
|
simulator,
|
|
325
|
-
|
|
392
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
393
|
+
});
|
|
326
394
|
|
|
327
395
|
// 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.
|
|
328
396
|
let result: PrivateExecutionResult;
|
|
@@ -344,24 +412,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
344
412
|
);
|
|
345
413
|
const publicFunctionsCalldata = await Promise.all(
|
|
346
414
|
publicCallRequests.map(async r => {
|
|
347
|
-
const calldata = await privateExecutionOracle.
|
|
415
|
+
const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
|
|
348
416
|
return new HashedValues(calldata, r.calldataHash);
|
|
349
417
|
}),
|
|
350
418
|
);
|
|
351
419
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
|
|
420
|
+
noteCache.finish();
|
|
421
|
+
const nonceGenerator = noteCache.getNonceGenerator();
|
|
422
|
+
result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
|
|
356
423
|
} catch (err) {
|
|
357
424
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
358
425
|
}
|
|
359
426
|
|
|
360
|
-
// According to the protocol rules,
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
const
|
|
364
|
-
|
|
427
|
+
// According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
|
|
428
|
+
// the nonce generator for the note hashes.
|
|
429
|
+
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
430
|
+
const { publicInputs } = await generateSimulatedProvingResult(
|
|
431
|
+
result,
|
|
432
|
+
(addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
|
|
433
|
+
this.stateMachine.node,
|
|
434
|
+
minRevertibleSideEffectCounter,
|
|
435
|
+
);
|
|
365
436
|
|
|
366
437
|
const globals = makeGlobalVariables();
|
|
367
438
|
globals.blockNumber = blockNumber;
|
|
@@ -372,7 +443,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
372
443
|
|
|
373
444
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
374
445
|
|
|
375
|
-
const
|
|
446
|
+
const bindings = this.logger.getBindings();
|
|
447
|
+
const contractsDB = new PublicContractsDB(
|
|
448
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
449
|
+
bindings,
|
|
450
|
+
);
|
|
376
451
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
377
452
|
const config = PublicSimulatorConfig.from({
|
|
378
453
|
skipFeeEnforcement: true,
|
|
@@ -385,8 +460,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
385
460
|
globals,
|
|
386
461
|
guardedMerkleTrees,
|
|
387
462
|
contractsDB,
|
|
388
|
-
new
|
|
463
|
+
new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
|
|
389
464
|
new TestDateProvider(),
|
|
465
|
+
undefined,
|
|
466
|
+
createLogger('simulator:public-processor', bindings),
|
|
390
467
|
);
|
|
391
468
|
|
|
392
469
|
const tx = await Tx.create({
|
|
@@ -411,7 +488,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
411
488
|
} else if (!processedTx.revertCode.isOK()) {
|
|
412
489
|
if (processedTx.revertReason) {
|
|
413
490
|
try {
|
|
414
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
491
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
415
492
|
// eslint-disable-next-line no-empty
|
|
416
493
|
} catch {}
|
|
417
494
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -440,13 +517,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
440
517
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
441
518
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
442
519
|
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
const l2Block = new L2Block(
|
|
446
|
-
makeAppendOnlyTreeSnapshot(),
|
|
447
|
-
await makeTXEBlockHeader(forkedWorldTrees, globals),
|
|
448
|
-
body,
|
|
449
|
-
);
|
|
520
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
|
|
450
521
|
|
|
451
522
|
await this.stateMachine.handleL2Block(l2Block);
|
|
452
523
|
|
|
@@ -455,17 +526,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
455
526
|
return executionResult.returnValues ?? [];
|
|
456
527
|
}
|
|
457
528
|
|
|
458
|
-
async
|
|
529
|
+
async publicCallNewFlow(
|
|
459
530
|
from: AztecAddress,
|
|
460
531
|
targetContractAddress: AztecAddress,
|
|
461
532
|
calldata: Fr[],
|
|
462
533
|
isStaticCall: boolean,
|
|
463
534
|
) {
|
|
464
535
|
this.logger.verbose(
|
|
465
|
-
`Executing public function ${await this.
|
|
536
|
+
`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
466
537
|
);
|
|
467
538
|
|
|
468
|
-
const blockNumber = await this.
|
|
539
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
469
540
|
|
|
470
541
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
471
542
|
|
|
@@ -475,7 +546,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
475
546
|
|
|
476
547
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
477
548
|
|
|
478
|
-
const anchorBlockHeader = await this.
|
|
549
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
479
550
|
|
|
480
551
|
const calldataHash = await computeCalldataHash(calldata);
|
|
481
552
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
@@ -489,7 +560,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
489
560
|
|
|
490
561
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
491
562
|
|
|
492
|
-
const
|
|
563
|
+
const bindings2 = this.logger.getBindings();
|
|
564
|
+
const contractsDB = new PublicContractsDB(
|
|
565
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
566
|
+
bindings2,
|
|
567
|
+
);
|
|
493
568
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
494
569
|
const config = PublicSimulatorConfig.from({
|
|
495
570
|
skipFeeEnforcement: true,
|
|
@@ -498,17 +573,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
498
573
|
collectStatistics: false,
|
|
499
574
|
collectCallMetadata: true,
|
|
500
575
|
});
|
|
501
|
-
const simulator = new
|
|
502
|
-
const processor = new PublicProcessor(
|
|
576
|
+
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
577
|
+
const processor = new PublicProcessor(
|
|
578
|
+
globals,
|
|
579
|
+
guardedMerkleTrees,
|
|
580
|
+
contractsDB,
|
|
581
|
+
simulator,
|
|
582
|
+
new TestDateProvider(),
|
|
583
|
+
undefined,
|
|
584
|
+
createLogger('simulator:public-processor', bindings2),
|
|
585
|
+
);
|
|
503
586
|
|
|
504
587
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
505
588
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
506
589
|
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
507
590
|
// unique.
|
|
508
591
|
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
509
|
-
|
|
510
|
-
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
511
|
-
}
|
|
592
|
+
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
512
593
|
|
|
513
594
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
514
595
|
// may require producing reverts.
|
|
@@ -532,7 +613,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
532
613
|
constantData,
|
|
533
614
|
/*gasUsed=*/ new Gas(0, 0),
|
|
534
615
|
/*feePayer=*/ AztecAddress.zero(),
|
|
535
|
-
/*
|
|
616
|
+
/*expirationTimestamp=*/ 0n,
|
|
536
617
|
inputsForPublic,
|
|
537
618
|
undefined,
|
|
538
619
|
);
|
|
@@ -559,7 +640,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
559
640
|
} else if (!processedTx.revertCode.isOK()) {
|
|
560
641
|
if (processedTx.revertReason) {
|
|
561
642
|
try {
|
|
562
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
643
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
563
644
|
// eslint-disable-next-line no-empty
|
|
564
645
|
} catch {}
|
|
565
646
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -591,13 +672,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
591
672
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
592
673
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
593
674
|
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
const l2Block = new L2Block(
|
|
597
|
-
makeAppendOnlyTreeSnapshot(),
|
|
598
|
-
await makeTXEBlockHeader(forkedWorldTrees, globals),
|
|
599
|
-
body,
|
|
600
|
-
);
|
|
675
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
|
|
601
676
|
|
|
602
677
|
await this.stateMachine.handleL2Block(l2Block);
|
|
603
678
|
|
|
@@ -606,23 +681,46 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
606
681
|
return returnValues ?? [];
|
|
607
682
|
}
|
|
608
683
|
|
|
609
|
-
async
|
|
684
|
+
async executeUtilityFunction(
|
|
610
685
|
targetContractAddress: AztecAddress,
|
|
611
686
|
functionSelector: FunctionSelector,
|
|
612
687
|
args: Fr[],
|
|
688
|
+
jobId: string,
|
|
613
689
|
) {
|
|
614
|
-
const artifact = await this.
|
|
690
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
615
691
|
if (!artifact) {
|
|
616
692
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
617
693
|
}
|
|
618
694
|
|
|
619
|
-
|
|
695
|
+
// Sync notes before executing utility function to discover notes from previous transactions
|
|
696
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
697
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
698
|
+
targetContractAddress,
|
|
699
|
+
functionSelector,
|
|
700
|
+
async (call, execScopes) => {
|
|
701
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
702
|
+
},
|
|
703
|
+
blockHeader,
|
|
704
|
+
jobId,
|
|
705
|
+
'ALL_SCOPES',
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
const call = FunctionCall.from({
|
|
620
709
|
name: artifact.name,
|
|
621
|
-
selector: functionSelector,
|
|
622
710
|
to: targetContractAddress,
|
|
623
|
-
|
|
711
|
+
selector: functionSelector,
|
|
712
|
+
type: FunctionType.UTILITY,
|
|
713
|
+
hideMsgSender: false,
|
|
714
|
+
isStatic: false,
|
|
715
|
+
args,
|
|
716
|
+
returnTypes: [],
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
|
|
720
|
+
}
|
|
624
721
|
|
|
625
|
-
|
|
722
|
+
private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
|
|
723
|
+
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
626
724
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
627
725
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
628
726
|
}
|
|
@@ -633,9 +731,28 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
633
731
|
});
|
|
634
732
|
|
|
635
733
|
try {
|
|
636
|
-
const
|
|
734
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
735
|
+
const oracle = new UtilityExecutionOracle({
|
|
736
|
+
contractAddress: call.to,
|
|
737
|
+
authWitnesses: [],
|
|
738
|
+
capsules: [],
|
|
739
|
+
anchorBlockHeader,
|
|
740
|
+
contractStore: this.contractStore,
|
|
741
|
+
noteStore: this.noteStore,
|
|
742
|
+
keyStore: this.keyStore,
|
|
743
|
+
addressStore: this.addressStore,
|
|
744
|
+
aztecNode: this.stateMachine.node,
|
|
745
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
746
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
747
|
+
capsuleStore: this.capsuleStore,
|
|
748
|
+
privateEventStore: this.privateEventStore,
|
|
749
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
750
|
+
contractSyncService: this.contractSyncService,
|
|
751
|
+
jobId,
|
|
752
|
+
scopes,
|
|
753
|
+
});
|
|
637
754
|
const acirExecutionResult = await new WASMSimulator()
|
|
638
|
-
.executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
755
|
+
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
639
756
|
.catch((err: Error) => {
|
|
640
757
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
641
758
|
throw new ExecutionError(
|
|
@@ -649,10 +766,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
649
766
|
);
|
|
650
767
|
});
|
|
651
768
|
|
|
652
|
-
this.logger.verbose(`Utility
|
|
769
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
653
770
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
654
771
|
} catch (err) {
|
|
655
|
-
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility
|
|
772
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
|
|
656
773
|
}
|
|
657
774
|
}
|
|
658
775
|
|
|
@@ -661,7 +778,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
661
778
|
return [this.nextBlockTimestamp, this.authwits];
|
|
662
779
|
}
|
|
663
780
|
|
|
664
|
-
private async getLastBlockNumber(): Promise<
|
|
665
|
-
|
|
781
|
+
private async getLastBlockNumber(): Promise<BlockNumber> {
|
|
782
|
+
const header = await this.stateMachine.node.getBlockHeader('latest');
|
|
783
|
+
return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
666
784
|
}
|
|
667
785
|
}
|