@aztec/simulator 0.40.1 → 0.41.0
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/acvm/oracle/oracle.d.ts +4 -2
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +21 -18
- package/dest/acvm/oracle/typed_oracle.d.ts +6 -11
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +11 -5
- package/dest/avm/avm_execution_environment.d.ts +4 -3
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +7 -5
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +5 -4
- package/dest/avm/errors.d.ts +6 -0
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +10 -1
- package/dest/avm/fixtures/index.js +3 -3
- package/dest/avm/journal/journal.d.ts +2 -3
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +6 -11
- package/dest/avm/journal/nullifiers.d.ts +17 -5
- package/dest/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/avm/journal/nullifiers.js +27 -10
- package/dest/avm/journal/public_storage.d.ts +19 -6
- package/dest/avm/journal/public_storage.d.ts.map +1 -1
- package/dest/avm/journal/public_storage.js +30 -12
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +6 -7
- package/dest/avm/opcodes/external_calls.d.ts +2 -2
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +22 -11
- package/dest/avm/opcodes/storage.d.ts +0 -7
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +3 -12
- package/dest/client/client_execution_context.d.ts +35 -17
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +70 -33
- package/dest/client/db_oracle.d.ts +10 -11
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/execution_note_cache.d.ts +17 -0
- package/dest/client/execution_note_cache.d.ts.map +1 -1
- package/dest/client/execution_note_cache.js +25 -2
- package/dest/client/execution_result.d.ts +11 -0
- package/dest/client/execution_result.d.ts.map +1 -1
- package/dest/client/execution_result.js +21 -3
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +4 -1
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +6 -6
- package/dest/client/view_data_oracle.d.ts +10 -10
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +11 -11
- package/dest/common/index.d.ts +1 -0
- package/dest/common/index.d.ts.map +1 -1
- package/dest/common/index.js +2 -1
- package/dest/common/return_values.d.ts +11 -0
- package/dest/common/return_values.d.ts.map +1 -0
- package/dest/common/return_values.js +13 -0
- package/dest/mocks/fixtures.d.ts +2 -1
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +2 -3
- package/dest/public/abstract_phase_manager.d.ts +3 -3
- package/dest/public/abstract_phase_manager.d.ts.map +1 -1
- package/dest/public/abstract_phase_manager.js +17 -10
- package/dest/public/app_logic_phase_manager.d.ts +1 -1
- package/dest/public/execution.d.ts +2 -6
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +1 -1
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +11 -8
- package/dest/public/hints_builder.d.ts +2 -2
- package/dest/public/hints_builder.d.ts.map +1 -1
- package/dest/public/hints_builder.js +4 -4
- package/dest/public/public_processor.d.ts +2 -2
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +5 -5
- package/dest/public/setup_phase_manager.d.ts +1 -1
- package/dest/public/setup_phase_manager.js +2 -2
- package/dest/public/tail_phase_manager.d.ts +1 -1
- package/dest/public/tail_phase_manager.d.ts.map +1 -1
- package/dest/public/tail_phase_manager.js +4 -4
- package/dest/public/teardown_phase_manager.d.ts +1 -1
- package/dest/public/teardown_phase_manager.js +2 -2
- package/dest/public/transitional_adaptors.d.ts +2 -1
- package/dest/public/transitional_adaptors.d.ts.map +1 -1
- package/dest/public/transitional_adaptors.js +17 -3
- package/dest/public/utils.js +3 -3
- package/package.json +8 -8
- package/src/acvm/oracle/oracle.ts +26 -23
- package/src/acvm/oracle/typed_oracle.ts +15 -15
- package/src/avm/avm_execution_environment.ts +9 -5
- package/src/avm/avm_simulator.ts +5 -3
- package/src/avm/errors.ts +10 -0
- package/src/avm/fixtures/index.ts +2 -2
- package/src/avm/journal/journal.ts +10 -14
- package/src/avm/journal/nullifiers.ts +27 -14
- package/src/avm/journal/public_storage.ts +30 -16
- package/src/avm/opcodes/accrued_substate.ts +5 -6
- package/src/avm/opcodes/external_calls.ts +23 -9
- package/src/avm/opcodes/storage.ts +2 -12
- package/src/client/client_execution_context.ts +75 -37
- package/src/client/db_oracle.ts +10 -11
- package/src/client/execution_note_cache.ts +29 -1
- package/src/client/execution_result.ts +26 -2
- package/src/client/private_execution.ts +3 -0
- package/src/client/simulator.ts +4 -5
- package/src/client/view_data_oracle.ts +12 -12
- package/src/common/index.ts +1 -0
- package/src/common/return_values.ts +18 -0
- package/src/mocks/fixtures.ts +2 -2
- package/src/public/abstract_phase_manager.ts +21 -15
- package/src/public/execution.ts +2 -6
- package/src/public/executor.ts +14 -7
- package/src/public/hints_builder.ts +11 -3
- package/src/public/public_processor.ts +7 -7
- package/src/public/setup_phase_manager.ts +1 -1
- package/src/public/tail_phase_manager.ts +5 -7
- package/src/public/teardown_phase_manager.ts +1 -1
- package/src/public/transitional_adaptors.ts +17 -2
- package/src/public/utils.ts +2 -2
- package/dest/client/logs_cache.d.ts +0 -33
- package/dest/client/logs_cache.d.ts.map +0 -1
- package/dest/client/logs_cache.js +0 -59
- package/src/client/logs_cache.ts +0 -65
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
ContractStorageUpdateRequest,
|
|
7
7
|
EthAddress,
|
|
8
8
|
L2ToL1Message,
|
|
9
|
+
LogHash,
|
|
9
10
|
NoteHash,
|
|
10
11
|
Nullifier,
|
|
11
12
|
ReadRequest,
|
|
12
|
-
SideEffect,
|
|
13
13
|
} from '@aztec/circuits.js';
|
|
14
14
|
import { EventSelector } from '@aztec/foundation/abi';
|
|
15
15
|
import { Fr } from '@aztec/foundation/fields';
|
|
@@ -64,9 +64,8 @@ type PartialPublicExecutionResult = {
|
|
|
64
64
|
newNullifiers: Nullifier[];
|
|
65
65
|
contractStorageReads: ContractStorageRead[];
|
|
66
66
|
contractStorageUpdateRequests: ContractStorageUpdateRequest[];
|
|
67
|
-
unencryptedLogsHashes:
|
|
67
|
+
unencryptedLogsHashes: LogHash[];
|
|
68
68
|
unencryptedLogs: UnencryptedL2Log[];
|
|
69
|
-
unencryptedLogPreimagesLength: Fr;
|
|
70
69
|
allUnencryptedLogs: UnencryptedL2Log[];
|
|
71
70
|
nestedExecutions: PublicExecutionResult[];
|
|
72
71
|
};
|
|
@@ -119,8 +118,6 @@ export class AvmPersistableStateManager {
|
|
|
119
118
|
contractStorageUpdateRequests: [],
|
|
120
119
|
unencryptedLogsHashes: [],
|
|
121
120
|
unencryptedLogs: [],
|
|
122
|
-
// The length starts at 4 because it will always include the size.
|
|
123
|
-
unencryptedLogPreimagesLength: new Fr(4),
|
|
124
121
|
allUnencryptedLogs: [],
|
|
125
122
|
nestedExecutions: [],
|
|
126
123
|
};
|
|
@@ -141,7 +138,7 @@ export class AvmPersistableStateManager {
|
|
|
141
138
|
* @param value - the value being written to the slot
|
|
142
139
|
*/
|
|
143
140
|
public writeStorage(storageAddress: Fr, slot: Fr, value: Fr) {
|
|
144
|
-
this.log.debug(`
|
|
141
|
+
this.log.debug(`Storage write (address=${storageAddress}, slot=${slot}): value=${value}`);
|
|
145
142
|
// Cache storage writes for later reference/reads
|
|
146
143
|
this.publicStorage.write(storageAddress, slot, value);
|
|
147
144
|
|
|
@@ -172,7 +169,9 @@ export class AvmPersistableStateManager {
|
|
|
172
169
|
*/
|
|
173
170
|
public async readStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
|
|
174
171
|
const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
|
|
175
|
-
this.log.debug(
|
|
172
|
+
this.log.debug(
|
|
173
|
+
`Storage read (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
|
|
174
|
+
);
|
|
176
175
|
|
|
177
176
|
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
178
177
|
// The current info to the kernel kernel does not consider cached reads.
|
|
@@ -253,7 +252,9 @@ export class AvmPersistableStateManager {
|
|
|
253
252
|
*/
|
|
254
253
|
public async writeNullifier(storageAddress: Fr, nullifier: Fr) {
|
|
255
254
|
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
256
|
-
this.transitionalExecutionResult.newNullifiers.push(
|
|
255
|
+
this.transitionalExecutionResult.newNullifiers.push(
|
|
256
|
+
new Nullifier(nullifier, this.trace.accessCounter, /*noteHash=*/ Fr.ZERO),
|
|
257
|
+
);
|
|
257
258
|
|
|
258
259
|
this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`);
|
|
259
260
|
// Cache pending nullifiers for later access
|
|
@@ -307,12 +308,7 @@ export class AvmPersistableStateManager {
|
|
|
307
308
|
this.transitionalExecutionResult.allUnencryptedLogs.push(ulog);
|
|
308
309
|
// this duplicates exactly what happens in the trace just for the purpose of transitional integration with the kernel
|
|
309
310
|
this.transitionalExecutionResult.unencryptedLogsHashes.push(
|
|
310
|
-
new
|
|
311
|
-
);
|
|
312
|
-
// Duplicates computation performed in public_context.nr::emit_unencrypted_log
|
|
313
|
-
// 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4).
|
|
314
|
-
this.transitionalExecutionResult.unencryptedLogPreimagesLength = new Fr(
|
|
315
|
-
this.transitionalExecutionResult.unencryptedLogPreimagesLength.toNumber() + 44 + log.length * Fr.SIZE_IN_BYTES,
|
|
311
|
+
new LogHash(logHash, this.trace.accessCounter, new Fr(ulog.length)),
|
|
316
312
|
);
|
|
317
313
|
// TODO(6206): likely need to track this here and not just in the transitional logic.
|
|
318
314
|
|
|
@@ -12,21 +12,38 @@ import type { CommitmentsDB } from '../../index.js';
|
|
|
12
12
|
export class Nullifiers {
|
|
13
13
|
/** Cached nullifiers. */
|
|
14
14
|
public cache: NullifierCache;
|
|
15
|
-
/** Parent's nullifier cache. Checked on cache-miss. */
|
|
16
|
-
private readonly parentCache: NullifierCache | undefined;
|
|
17
|
-
/** Reference to node storage. Checked on parent cache-miss. */
|
|
18
|
-
private readonly hostNullifiers: CommitmentsDB;
|
|
19
15
|
|
|
20
|
-
constructor(
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
constructor(
|
|
17
|
+
/** Reference to node storage. Checked on parent cache-miss. */
|
|
18
|
+
private readonly hostNullifiers: CommitmentsDB,
|
|
19
|
+
/** Parent's nullifiers. Checked on this' cache-miss. */
|
|
20
|
+
private readonly parent?: Nullifiers | undefined,
|
|
21
|
+
) {
|
|
23
22
|
this.cache = new NullifierCache();
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Get a nullifier's existence in this' cache or parent's (recursively).
|
|
27
|
+
* DOES NOT CHECK HOST STORAGE!
|
|
28
|
+
* @param storageAddress - the address of the contract whose storage is being read from
|
|
29
|
+
* @param nullifier - the nullifier to check for
|
|
30
|
+
* @returns exists: whether the nullifier exists in cache here or in parent's
|
|
31
|
+
*/
|
|
32
|
+
private checkExistsHereOrParent(storageAddress: Fr, nullifier: Fr): boolean {
|
|
33
|
+
// First check this cache
|
|
34
|
+
let existsAsPending = this.cache.exists(storageAddress, nullifier);
|
|
35
|
+
// Then try parent's nullifier cache
|
|
36
|
+
if (!existsAsPending && this.parent) {
|
|
37
|
+
// Note: this will recurse to grandparent/etc until a cache-hit is encountered.
|
|
38
|
+
existsAsPending = this.parent.checkExistsHereOrParent(storageAddress, nullifier);
|
|
39
|
+
}
|
|
40
|
+
return existsAsPending;
|
|
41
|
+
}
|
|
42
|
+
|
|
26
43
|
/**
|
|
27
44
|
* Get a nullifier's existence status.
|
|
28
45
|
* 1. Check cache.
|
|
29
|
-
* 2. Check parent
|
|
46
|
+
* 2. Check parent cache.
|
|
30
47
|
* 3. Fall back to the host state.
|
|
31
48
|
* 4. Not found! Nullifier does not exist.
|
|
32
49
|
*
|
|
@@ -40,12 +57,8 @@ export class Nullifiers {
|
|
|
40
57
|
storageAddress: Fr,
|
|
41
58
|
nullifier: Fr,
|
|
42
59
|
): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
// Then check parent's cache
|
|
46
|
-
if (!existsAsPending && this.parentCache) {
|
|
47
|
-
existsAsPending = this.parentCache?.exists(storageAddress, nullifier);
|
|
48
|
-
}
|
|
60
|
+
// Check this cache and parent's (recursively)
|
|
61
|
+
const existsAsPending = this.checkExistsHereOrParent(storageAddress, nullifier);
|
|
49
62
|
// Finally try the host's Aztec state (a trip to the database)
|
|
50
63
|
// If the value is found in the database, it will be associated with a leaf index!
|
|
51
64
|
let leafIndex: bigint | undefined = undefined;
|
|
@@ -17,14 +17,13 @@ type PublicStorageReadResult = {
|
|
|
17
17
|
export class PublicStorage {
|
|
18
18
|
/** Cached storage writes. */
|
|
19
19
|
private cache: PublicStorageCache;
|
|
20
|
-
/** Parent's storage cache. Checked on cache-miss. */
|
|
21
|
-
private readonly parentCache: PublicStorageCache | undefined;
|
|
22
|
-
/** Reference to node storage. Checked on parent cache-miss. */
|
|
23
|
-
private readonly hostPublicStorage: PublicStateDB;
|
|
24
20
|
|
|
25
|
-
constructor(
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
constructor(
|
|
22
|
+
/** Reference to node storage. Checked on parent cache-miss. */
|
|
23
|
+
private readonly hostPublicStorage: PublicStateDB,
|
|
24
|
+
/** Parent's storage. Checked on this' cache-miss. */
|
|
25
|
+
private readonly parent?: PublicStorage,
|
|
26
|
+
) {
|
|
28
27
|
this.cache = new PublicStorageCache();
|
|
29
28
|
}
|
|
30
29
|
|
|
@@ -35,10 +34,29 @@ export class PublicStorage {
|
|
|
35
34
|
return this.cache;
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Read a storage value from this' cache or parent's (recursively).
|
|
39
|
+
* DOES NOT CHECK HOST STORAGE!
|
|
40
|
+
*
|
|
41
|
+
* @param storageAddress - the address of the contract whose storage is being read from
|
|
42
|
+
* @param slot - the slot in the contract's storage being read from
|
|
43
|
+
* @returns value: the latest value written according to this cache or the parent's. undefined on cache miss.
|
|
44
|
+
*/
|
|
45
|
+
public readHereOrParent(storageAddress: Fr, slot: Fr): Fr | undefined {
|
|
46
|
+
// First try check this storage cache
|
|
47
|
+
let value = this.cache.read(storageAddress, slot);
|
|
48
|
+
// Then try parent's storage cache
|
|
49
|
+
if (!value && this.parent) {
|
|
50
|
+
// Note: this will recurse to grandparent/etc until a cache-hit is encountered.
|
|
51
|
+
value = this.parent.readHereOrParent(storageAddress, slot);
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
/**
|
|
39
57
|
* Read a value from storage.
|
|
40
58
|
* 1. Check cache.
|
|
41
|
-
* 2. Check parent
|
|
59
|
+
* 2. Check parent cache.
|
|
42
60
|
* 3. Fall back to the host state.
|
|
43
61
|
* 4. Not found! Value has never been written to before. Flag it as non-existent and return value zero.
|
|
44
62
|
*
|
|
@@ -48,12 +66,8 @@ export class PublicStorage {
|
|
|
48
66
|
*/
|
|
49
67
|
public async read(storageAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
|
|
50
68
|
let cached = false;
|
|
51
|
-
//
|
|
52
|
-
let value = this.
|
|
53
|
-
// Then try parent's storage cache (if it exists / written to earlier in this TX)
|
|
54
|
-
if (!value && this.parentCache) {
|
|
55
|
-
value = this.parentCache?.read(storageAddress, slot);
|
|
56
|
-
}
|
|
69
|
+
// Check this cache and parent's (recursively)
|
|
70
|
+
let value = this.readHereOrParent(storageAddress, slot);
|
|
57
71
|
// Finally try the host's Aztec state (a trip to the database)
|
|
58
72
|
if (!value) {
|
|
59
73
|
value = await this.hostPublicStorage.storageRead(storageAddress, slot);
|
|
@@ -73,8 +87,8 @@ export class PublicStorage {
|
|
|
73
87
|
* @param slot - the slot in the contract's storage being written to
|
|
74
88
|
* @param value - the value being written to the slot
|
|
75
89
|
*/
|
|
76
|
-
public write(storageAddress: Fr,
|
|
77
|
-
this.cache.write(storageAddress,
|
|
90
|
+
public write(storageAddress: Fr, slot: Fr, value: Fr) {
|
|
91
|
+
this.cache.write(storageAddress, slot, value);
|
|
78
92
|
}
|
|
79
93
|
|
|
80
94
|
/**
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
2
|
import { Uint8 } from '../avm_memory_types.js';
|
|
3
|
-
import { InstructionExecutionError } from '../errors.js';
|
|
3
|
+
import { InstructionExecutionError, StaticCallAlterationError } from '../errors.js';
|
|
4
4
|
import { NullifierCollisionError } from '../journal/nullifiers.js';
|
|
5
5
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
6
6
|
import { Addressing } from './addressing_mode.js';
|
|
7
7
|
import { Instruction } from './instruction.js';
|
|
8
|
-
import { StaticCallStorageAlterError } from './storage.js';
|
|
9
8
|
|
|
10
9
|
export class NoteHashExists extends Instruction {
|
|
11
10
|
static type: string = 'NOTEHASHEXISTS';
|
|
@@ -65,7 +64,7 @@ export class EmitNoteHash extends Instruction {
|
|
|
65
64
|
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
66
65
|
|
|
67
66
|
if (context.environment.isStaticCall) {
|
|
68
|
-
throw new
|
|
67
|
+
throw new StaticCallAlterationError();
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
const noteHash = memory.get(this.noteHashOffset).toFr();
|
|
@@ -125,7 +124,7 @@ export class EmitNullifier extends Instruction {
|
|
|
125
124
|
|
|
126
125
|
public async execute(context: AvmContext): Promise<void> {
|
|
127
126
|
if (context.environment.isStaticCall) {
|
|
128
|
-
throw new
|
|
127
|
+
throw new StaticCallAlterationError();
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
const memoryOperations = { reads: 1, indirect: this.indirect };
|
|
@@ -210,7 +209,7 @@ export class EmitUnencryptedLog extends Instruction {
|
|
|
210
209
|
|
|
211
210
|
public async execute(context: AvmContext): Promise<void> {
|
|
212
211
|
if (context.environment.isStaticCall) {
|
|
213
|
-
throw new
|
|
212
|
+
throw new StaticCallAlterationError();
|
|
214
213
|
}
|
|
215
214
|
|
|
216
215
|
const memoryOperations = { reads: 1 + this.logSize, indirect: this.indirect };
|
|
@@ -244,7 +243,7 @@ export class SendL2ToL1Message extends Instruction {
|
|
|
244
243
|
|
|
245
244
|
public async execute(context: AvmContext): Promise<void> {
|
|
246
245
|
if (context.environment.isStaticCall) {
|
|
247
|
-
throw new
|
|
246
|
+
throw new StaticCallAlterationError();
|
|
248
247
|
}
|
|
249
248
|
|
|
250
249
|
const memoryOperations = { reads: 2, indirect: this.indirect };
|
|
@@ -3,7 +3,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
|
|
|
3
3
|
|
|
4
4
|
import { convertAvmResultsToPxResult, createPublicExecution } from '../../public/transitional_adaptors.js';
|
|
5
5
|
import type { AvmContext } from '../avm_context.js';
|
|
6
|
-
import { gasLeftToGas
|
|
6
|
+
import { gasLeftToGas } from '../avm_gas.js';
|
|
7
7
|
import { Field, Uint8 } from '../avm_memory_types.js';
|
|
8
8
|
import { type AvmContractCallResults } from '../avm_message_call_result.js';
|
|
9
9
|
import { AvmSimulator } from '../avm_simulator.js';
|
|
@@ -40,7 +40,7 @@ abstract class ExternalCall extends Instruction {
|
|
|
40
40
|
// Function selector is temporary since eventually public contract bytecode will be one blob
|
|
41
41
|
// containing all functions, and function selector will become an application-level mechanism
|
|
42
42
|
// (e.g. first few bytes of calldata + compiler-generated jump table)
|
|
43
|
-
private
|
|
43
|
+
private functionSelectorOffset: number,
|
|
44
44
|
) {
|
|
45
45
|
super();
|
|
46
46
|
}
|
|
@@ -57,21 +57,30 @@ abstract class ExternalCall extends Instruction {
|
|
|
57
57
|
const callAddress = memory.getAs<Field>(addrOffset);
|
|
58
58
|
const calldataSize = memory.get(argsSizeOffset).toNumber();
|
|
59
59
|
const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const
|
|
60
|
+
const functionSelector = memory.getAs<Field>(this.functionSelectorOffset).toFr();
|
|
61
|
+
// If we are already in a static call, we propagate the environment.
|
|
62
|
+
const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type;
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
// First we consume the gas for this operation.
|
|
65
65
|
const memoryOperations = { reads: calldataSize + 5, writes: 1 + this.retSize, indirect: this.indirect };
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
67
|
+
// Then we consume the gas allocated for the nested call. The excess will be refunded later.
|
|
68
|
+
// Gas allocation is capped by the amount of gas left in the current context.
|
|
69
|
+
// We have to do some dancing here because the gas allocation is a field,
|
|
70
|
+
// but in the machine state we track gas as a number.
|
|
71
|
+
const allocatedL2Gas = Number(BigIntMin(memory.get(gasOffset).toBigInt(), BigInt(context.machineState.l2GasLeft)));
|
|
72
|
+
const allocatedDaGas = Number(
|
|
73
|
+
BigIntMin(memory.get(gasOffset + 1).toBigInt(), BigInt(context.machineState.daGasLeft)),
|
|
74
|
+
);
|
|
75
|
+
const allocatedGas = { l2Gas: allocatedL2Gas, daGas: allocatedDaGas };
|
|
76
|
+
context.machineState.consumeGas(allocatedGas);
|
|
68
77
|
|
|
69
78
|
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
70
79
|
const nestedContext = context.createNestedContractCallContext(
|
|
71
80
|
callAddress.toFr(),
|
|
72
81
|
calldata,
|
|
73
82
|
allocatedGas,
|
|
74
|
-
|
|
83
|
+
callType,
|
|
75
84
|
FunctionSelector.fromField(functionSelector),
|
|
76
85
|
);
|
|
77
86
|
const startSideEffectCounter = nestedContext.persistableState.trace.accessCounter;
|
|
@@ -215,3 +224,8 @@ export class Revert extends Instruction {
|
|
|
215
224
|
memory.assert(memoryOperations);
|
|
216
225
|
}
|
|
217
226
|
}
|
|
227
|
+
|
|
228
|
+
/** Returns the smaller of two bigints. */
|
|
229
|
+
function BigIntMin(a: bigint, b: bigint): bigint {
|
|
230
|
+
return a < b ? a : b;
|
|
231
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
3
3
|
import type { AvmContext } from '../avm_context.js';
|
|
4
4
|
import { type Gas, getBaseGasCost, getMemoryGasCost, mulGas, sumGas } from '../avm_gas.js';
|
|
5
5
|
import { Field, type MemoryOperations } from '../avm_memory_types.js';
|
|
6
|
-
import {
|
|
6
|
+
import { StaticCallAlterationError } from '../errors.js';
|
|
7
7
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
8
8
|
import { Addressing } from './addressing_mode.js';
|
|
9
9
|
import { Instruction } from './instruction.js';
|
|
@@ -44,7 +44,7 @@ export class SStore extends BaseStorageInstruction {
|
|
|
44
44
|
|
|
45
45
|
public async execute(context: AvmContext): Promise<void> {
|
|
46
46
|
if (context.environment.isStaticCall) {
|
|
47
|
-
throw new
|
|
47
|
+
throw new StaticCallAlterationError();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const memoryOperations = { reads: this.size + 1, indirect: this.indirect };
|
|
@@ -100,13 +100,3 @@ export class SLoad extends BaseStorageInstruction {
|
|
|
100
100
|
memory.assert(memoryOperations);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Error is thrown when a static call attempts to alter storage
|
|
106
|
-
*/
|
|
107
|
-
export class StaticCallStorageAlterError extends InstructionExecutionError {
|
|
108
|
-
constructor() {
|
|
109
|
-
super('Static calls cannot alter storage');
|
|
110
|
-
this.name = 'StaticCallStorageAlterError';
|
|
111
|
-
}
|
|
112
|
-
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AuthWitness,
|
|
3
3
|
type AztecNode,
|
|
4
|
-
EncryptedFunctionL2Logs,
|
|
5
4
|
EncryptedL2Log,
|
|
6
5
|
L1NotePayload,
|
|
7
6
|
Note,
|
|
8
7
|
type NoteStatus,
|
|
9
8
|
TaggedNote,
|
|
10
|
-
UnencryptedFunctionL2Logs,
|
|
11
9
|
type UnencryptedL2Log,
|
|
12
10
|
} from '@aztec/circuit-types';
|
|
13
11
|
import {
|
|
@@ -22,8 +20,8 @@ import {
|
|
|
22
20
|
import { Aes128 } from '@aztec/circuits.js/barretenberg';
|
|
23
21
|
import { computePublicDataTreeLeafSlot, computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
|
|
24
22
|
import { type FunctionAbi, type FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi';
|
|
25
|
-
import {
|
|
26
|
-
import { Fr, type Point } from '@aztec/foundation/fields';
|
|
23
|
+
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
24
|
+
import { Fr, GrumpkinScalar, type Point } from '@aztec/foundation/fields';
|
|
27
25
|
import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log';
|
|
28
26
|
|
|
29
27
|
import { type NoteData, toACVMWitness } from '../acvm/index.js';
|
|
@@ -31,7 +29,6 @@ import { type PackedValuesCache } from '../common/packed_values_cache.js';
|
|
|
31
29
|
import { type DBOracle } from './db_oracle.js';
|
|
32
30
|
import { type ExecutionNoteCache } from './execution_note_cache.js';
|
|
33
31
|
import { CountedLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
|
|
34
|
-
import { type LogsCache } from './logs_cache.js';
|
|
35
32
|
import { pickNotes } from './pick_notes.js';
|
|
36
33
|
import { executePrivateFunction } from './private_execution.js';
|
|
37
34
|
import { ViewDataOracle } from './view_data_oracle.js';
|
|
@@ -59,6 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
59
56
|
*/
|
|
60
57
|
private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
|
|
61
58
|
private nullifiedNoteHashCounters: Map<number, number> = new Map();
|
|
59
|
+
private noteEncryptedLogs: CountedLog<EncryptedL2Log>[] = [];
|
|
62
60
|
private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
|
|
63
61
|
private unencryptedLogs: CountedLog<UnencryptedL2Log>[] = [];
|
|
64
62
|
private nestedExecutions: ExecutionResult[] = [];
|
|
@@ -76,7 +74,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
76
74
|
authWitnesses: AuthWitness[],
|
|
77
75
|
private readonly packedValuesCache: PackedValuesCache,
|
|
78
76
|
private readonly noteCache: ExecutionNoteCache,
|
|
79
|
-
private readonly logsCache: LogsCache,
|
|
80
77
|
db: DBOracle,
|
|
81
78
|
private node: AztecNode,
|
|
82
79
|
protected sideEffectCounter: number = 0,
|
|
@@ -133,31 +130,51 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
/**
|
|
136
|
-
* Return the encrypted logs emitted during this execution.
|
|
133
|
+
* Return the note encrypted logs emitted during this execution.
|
|
137
134
|
*/
|
|
138
|
-
public
|
|
139
|
-
return this.
|
|
135
|
+
public getNoteEncryptedLogs() {
|
|
136
|
+
return this.noteEncryptedLogs;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sometimes notes can be chopped after a nested execution is complete.
|
|
141
|
+
* This means finished nested executions still hold transient logs. This method removes them.
|
|
142
|
+
* TODO(Miranda): is there a cleaner solution?
|
|
143
|
+
*/
|
|
144
|
+
public chopNoteEncryptedLogs() {
|
|
145
|
+
// Do not return logs that have been chopped in the cache
|
|
146
|
+
const allNoteLogs = this.noteCache.getLogs();
|
|
147
|
+
this.noteEncryptedLogs = this.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
|
|
148
|
+
const chop = (thing: any) =>
|
|
149
|
+
thing.nestedExecutions.forEach((result: ExecutionResult) => {
|
|
150
|
+
if (!result.noteEncryptedLogs[0]?.isEmpty()) {
|
|
151
|
+
// The execution has note logs
|
|
152
|
+
result.noteEncryptedLogs = result.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
|
|
153
|
+
}
|
|
154
|
+
chop(result);
|
|
155
|
+
});
|
|
156
|
+
chop(this);
|
|
140
157
|
}
|
|
141
158
|
|
|
142
159
|
/**
|
|
143
|
-
* Return the encrypted logs emitted during this execution and nested executions.
|
|
160
|
+
* Return the note encrypted logs emitted during this execution and nested executions.
|
|
144
161
|
*/
|
|
145
|
-
public
|
|
146
|
-
return
|
|
162
|
+
public getAllNoteEncryptedLogs() {
|
|
163
|
+
return this.noteCache.getLogs();
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
/**
|
|
150
167
|
* Return the encrypted logs emitted during this execution.
|
|
151
168
|
*/
|
|
152
|
-
public
|
|
153
|
-
return this.
|
|
169
|
+
public getEncryptedLogs() {
|
|
170
|
+
return this.encryptedLogs;
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
/**
|
|
157
|
-
* Return the
|
|
174
|
+
* Return the encrypted logs emitted during this execution.
|
|
158
175
|
*/
|
|
159
|
-
public
|
|
160
|
-
return
|
|
176
|
+
public getUnencryptedLogs() {
|
|
177
|
+
return this.unencryptedLogs;
|
|
161
178
|
}
|
|
162
179
|
|
|
163
180
|
/**
|
|
@@ -337,29 +354,53 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
337
354
|
}
|
|
338
355
|
|
|
339
356
|
/**
|
|
340
|
-
*
|
|
357
|
+
* Emit encrypted data
|
|
358
|
+
* @param encryptedNote - The encrypted data.
|
|
359
|
+
* @param counter - The effects counter.
|
|
360
|
+
*/
|
|
361
|
+
public override emitEncryptedLog(encryptedData: Buffer, counter: number) {
|
|
362
|
+
const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedData), counter);
|
|
363
|
+
this.encryptedLogs.push(encryptedLog);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Emit encrypted note data
|
|
368
|
+
* @param noteHash - The note hash.
|
|
369
|
+
* @param encryptedNote - The encrypted note data.
|
|
370
|
+
* @param counter - The effects counter.
|
|
371
|
+
*/
|
|
372
|
+
public override emitEncryptedNoteLog(noteHash: Fr, encryptedNote: Buffer, counter: number) {
|
|
373
|
+
const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter);
|
|
374
|
+
this.noteEncryptedLogs.push(encryptedLog);
|
|
375
|
+
this.noteCache.addNewLog(encryptedLog, noteHash);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Encrypt a note
|
|
341
380
|
* @param contractAddress - The contract address of the note.
|
|
342
381
|
* @param storageSlot - The storage slot the note is at.
|
|
343
382
|
* @param noteTypeId - The type ID of the note.
|
|
344
|
-
* @param
|
|
345
|
-
* @param
|
|
383
|
+
* @param ivpk - The master incoming viewing public key.
|
|
384
|
+
* @param preimage - The note preimage.
|
|
346
385
|
*/
|
|
347
|
-
public override
|
|
386
|
+
public override computeEncryptedLog(
|
|
348
387
|
contractAddress: AztecAddress,
|
|
349
388
|
storageSlot: Fr,
|
|
350
389
|
noteTypeId: Fr,
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
counter: number,
|
|
390
|
+
ivpk: Point,
|
|
391
|
+
preimage: Fr[],
|
|
354
392
|
) {
|
|
355
|
-
const note = new Note(
|
|
393
|
+
const note = new Note(preimage);
|
|
356
394
|
const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
|
|
357
395
|
const taggedNote = new TaggedNote(l1NotePayload);
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
396
|
+
|
|
397
|
+
const ephSk = GrumpkinScalar.random();
|
|
398
|
+
|
|
399
|
+
// @todo Issue(#6410) Right now we are completely ignoring the outgoing log. Just drawing random data.
|
|
400
|
+
const ovsk = GrumpkinScalar.random();
|
|
401
|
+
const recipient = AztecAddress.random();
|
|
402
|
+
|
|
403
|
+
return taggedNote.encrypt(ephSk, recipient, ivpk, ovsk);
|
|
363
404
|
}
|
|
364
405
|
|
|
365
406
|
/**
|
|
@@ -368,7 +409,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
368
409
|
*/
|
|
369
410
|
public override emitUnencryptedLog(log: UnencryptedL2Log, counter: number) {
|
|
370
411
|
this.unencryptedLogs.push(new CountedLog(log, counter));
|
|
371
|
-
this.logsCache.addUnencryptedLog(log);
|
|
372
412
|
const text = log.toHumanReadable();
|
|
373
413
|
this.log.verbose(`Emitted unencrypted log: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`);
|
|
374
414
|
}
|
|
@@ -382,7 +422,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
382
422
|
*/
|
|
383
423
|
public override emitContractClassUnencryptedLog(log: UnencryptedL2Log, counter: number) {
|
|
384
424
|
this.unencryptedLogs.push(new CountedLog(log, counter));
|
|
385
|
-
this.logsCache.addUnencryptedLog(log);
|
|
386
425
|
const text = log.toHumanReadable();
|
|
387
426
|
this.log.verbose(
|
|
388
427
|
`Emitted unencrypted log from ContractClassRegisterer: "${
|
|
@@ -397,10 +436,10 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
397
436
|
childExecutionResult.callStackItem.publicInputs.newNoteHashes.some(item => !item.isEmpty()) ||
|
|
398
437
|
childExecutionResult.callStackItem.publicInputs.newNullifiers.some(item => !item.isEmpty()) ||
|
|
399
438
|
childExecutionResult.callStackItem.publicInputs.newL2ToL1Msgs.some(item => !item.isEmpty()) ||
|
|
400
|
-
|
|
401
|
-
|
|
439
|
+
childExecutionResult.callStackItem.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) ||
|
|
440
|
+
childExecutionResult.callStackItem.publicInputs.unencryptedLogsHashes.some(item => !item.isEmpty())
|
|
402
441
|
) {
|
|
403
|
-
throw new Error(`Static call cannot
|
|
442
|
+
throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`);
|
|
404
443
|
}
|
|
405
444
|
}
|
|
406
445
|
|
|
@@ -411,7 +450,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
411
450
|
* @param argsHash - The packed arguments to pass to the function.
|
|
412
451
|
* @param sideEffectCounter - The side effect counter at the start of the call.
|
|
413
452
|
* @param isStaticCall - Whether the call is a static call.
|
|
414
|
-
* @param
|
|
453
|
+
* @param isDelegateCall - Whether the call is a delegate call.
|
|
415
454
|
* @returns The execution result.
|
|
416
455
|
*/
|
|
417
456
|
override async callPrivateFunction(
|
|
@@ -450,7 +489,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
450
489
|
this.authWitnesses,
|
|
451
490
|
this.packedValuesCache,
|
|
452
491
|
this.noteCache,
|
|
453
|
-
this.logsCache,
|
|
454
492
|
this.db,
|
|
455
493
|
this.node,
|
|
456
494
|
sideEffectCounter,
|
package/src/client/db_oracle.ts
CHANGED
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
type NullifierMembershipWitness,
|
|
6
6
|
type PublicDataWitness,
|
|
7
7
|
} from '@aztec/circuit-types';
|
|
8
|
-
import { type CompleteAddress, type Header } from '@aztec/circuits.js';
|
|
8
|
+
import { type CompleteAddress, type Header, type KeyValidationRequest } from '@aztec/circuits.js';
|
|
9
9
|
import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi';
|
|
10
10
|
import { type AztecAddress } from '@aztec/foundation/aztec-address';
|
|
11
11
|
import { type Fr } from '@aztec/foundation/fields';
|
|
12
12
|
import { type ContractInstance } from '@aztec/types/contracts';
|
|
13
13
|
|
|
14
|
-
import { type NoteData
|
|
14
|
+
import { type NoteData } from '../acvm/index.js';
|
|
15
15
|
import { type CommitmentsDB } from '../public/db.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -45,10 +45,11 @@ export interface DBOracle extends CommitmentsDB {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Retrieve the complete address associated to a given address.
|
|
48
|
-
* @param
|
|
48
|
+
* @param account - The account address.
|
|
49
49
|
* @returns A complete address associated with the input address.
|
|
50
|
+
* @throws An error if the account is not registered in the database.
|
|
50
51
|
*/
|
|
51
|
-
getCompleteAddress(
|
|
52
|
+
getCompleteAddress(account: AztecAddress): Promise<CompleteAddress>;
|
|
52
53
|
|
|
53
54
|
/**
|
|
54
55
|
* Retrieve the auth witness for a given message hash.
|
|
@@ -65,14 +66,12 @@ export interface DBOracle extends CommitmentsDB {
|
|
|
65
66
|
popCapsule(): Promise<Fr[]>;
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
|
-
* Retrieve
|
|
69
|
-
*
|
|
70
|
-
* @
|
|
71
|
-
* @
|
|
72
|
-
* @returns A Promise that resolves to nullifier keys of a requested account and contract.
|
|
73
|
-
* @throws An error if the account is not registered in the database.
|
|
69
|
+
* Retrieve keys associated with a specific master public key and app address.
|
|
70
|
+
* @param pkMHash - The master public key hash.
|
|
71
|
+
* @returns A Promise that resolves to nullifier keys.
|
|
72
|
+
* @throws If the keys are not registered in the key store.
|
|
74
73
|
*/
|
|
75
|
-
|
|
74
|
+
getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise<KeyValidationRequest>;
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
77
|
* Retrieves a set of notes stored in the database for a given contract address and storage slot.
|