Skip to content

Commit 99cbb5d

Browse files
committed
fix(port): block #24580 — mechanical: standard-contracts regen + next-boundary re-grafts
Standard-contracts fixed-point regen on the final tree (next's bb, VK 4832; recipe: pin-standard-build + generate:data until no drift, 3 iterations). Next-boundary re-grafts forced by the v5-tip alignment (each restores an established next-only adaptation): - contract_function_simulator.ts / txe_oracle_top_level_context.ts: pass next-only txRequestSalt to PrivateExecutionOracle (request.salt / Fr.ZERO as before the restack). - contract_function_simulator.ts: PrivateExecutionStep.kind = CircuitKind.App (next's bb.js type). - txe_oracle_top_level_context.ts: CppPublicTxSimulator -> PublicTxSimulator (next superseded the cpp-variant class; same decision as block #24223). - sequencer-publisher.test.ts: v5 prune-suite mock gains next's L1TxState field; restored a closing brace lost in the base-sync union. - oracle_version.ts: ORACLE_VERSION_MINOR 4->5 (matches v5 noir side) + recorded interface hash for this tree's oracle surface (v5 interface + next-only salt), per the gate's instruction.
1 parent 4febe55 commit 99cbb5d

20 files changed

Lines changed: 224 additions & 145 deletions

noir-projects/aztec-nr/aztec/src/standard_addresses.nr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
use protocol_types::{address::AztecAddress, traits::FromField};
33

44
pub global STANDARD_AUTH_REGISTRY_ADDRESS: AztecAddress = AztecAddress::from_field(
5-
0x0292b01f4e566555534c40ed729eb023cc08afaca647b8c3642738449673480c,
5+
0x04fe1d86b5ae0f926883c34905a3c25cb30924138823a9883e2813d4f8b86ad9,
66
);
77

88
pub global STANDARD_MULTI_CALL_ENTRYPOINT_ADDRESS: AztecAddress = AztecAddress::from_field(
9-
0x18470168ca7a775b442cde110b668732f7b6390a505f3784b50f39993c5f3dce,
9+
0x21d17a596e8ae64c399cc7bffaf3f0346ae067a34948510f041dff8babed9e9a,
1010
);
1111

1212
pub global STANDARD_PUBLIC_CHECKS_ADDRESS: AztecAddress = AztecAddress::from_field(
13-
0x2d7745526508f5ceb278bb773a49f776842d1d2f0854c4a385bb661a2fabb9a8,
13+
0x2f96c5a68fc1d04b13b76167a254f0a1a906c2dc0b571fcbca107254f064b045,
1414
);
1515

1616
pub global STANDARD_HANDSHAKE_REGISTRY_ADDRESS: AztecAddress = AztecAddress::from_field(
17-
0x0bd62e76a9a3a103dae2e73040e05d3970ac900baff5637ae9f183396745ec7e,
17+
0x090d0f9525c99184e3741290b2695c5e3af23f51e96061b74b953111b0d4f59d,
1818
);
3.68 KB
Binary file not shown.

yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
MAX_PRIVATE_LOGS_PER_TX,
2121
MAX_TX_LIFETIME,
2222
PRIVATE_TX_L2_GAS_OVERHEAD,
23-
PUBLIC_DATA_WRITE_LENGTH,
2423
PUBLIC_TX_L2_GAS_OVERHEAD,
2524
TX_DA_GAS_OVERHEAD,
2625
} from '@aztec/constants';
@@ -315,7 +314,8 @@ export class ContractFunctionSimulator {
315314
);
316315
const simulatorTeardownTimer = new Timer();
317316

318-
const firstNullifier = noteCache.getNonceGenerator();
317+
noteCache.finish();
318+
const firstNullifierHint = noteCache.getNonceGenerator();
319319

320320
const publicCallRequests = collectNested([executionResult], r =>
321321
r.publicInputs.publicCallRequests
@@ -338,9 +338,9 @@ export class ContractFunctionSimulator {
338338
}
339339

340340
// Not to be confused with a PrivateCallExecutionResult. This is a superset
341-
// of the PrivateCallExecutionResult, containing also firstNullifier
341+
// of the PrivateCallExecutionResult, containing also firstNullifierHint
342342
// and publicFunctionsCalldata.
343-
return new PrivateExecutionResult(executionResult, firstNullifier, publicFunctionsCalldata);
343+
return new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
344344
} catch (err) {
345345
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
346346
}
@@ -588,10 +588,10 @@ export async function generateSimulatedProvingResult(
588588
execution.publicInputs.callContext.functionSelector,
589589
),
590590
timings: execution.profileResult?.timings ?? { witgen: 0, oracles: {} },
591+
kind: CircuitKind.App,
591592
bytecode: execution.acir,
592593
vk: execution.vk,
593594
witness: execution.partialWitness,
594-
kind: CircuitKind.App,
595595
});
596596
}
597597

@@ -657,12 +657,12 @@ export async function generateSimulatedProvingResult(
657657
siloedNullifiers,
658658
minRevertibleSideEffectCounter,
659659
);
660-
// The protocol nullifier is the nonce generator and the tx's first nullifier. It is injected by the
661-
// init kernel (at counter 1, index 0) rather than emitted by any private call, so it is absent from
662-
// the executed nullifiers above. Mirror the kernel here by prepending it as the first non-revertible
663-
// nullifier.
664660
const nonceGenerator = privateExecutionResult.firstNullifier;
665-
nonRevertibleNullifiers.unshift(nonceGenerator);
661+
if (nonRevertibleNullifiers.length === 0) {
662+
nonRevertibleNullifiers.push(nonceGenerator);
663+
} else if (!nonRevertibleNullifiers[0].equals(nonceGenerator)) {
664+
throw new Error('The first non revertible nullifier should be equal to the nonce generator. This is a bug!');
665+
}
666666

667667
if (isPrivateOnlyTx) {
668668
// We must make the note hashes unique by using the
@@ -925,11 +925,6 @@ function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccu
925925
);
926926
meteredL2Gas += numContractClassLogs * L2_GAS_PER_CONTRACT_CLASS_LOG;
927927

928-
if (isPrivateOnlyTx) {
929-
// The public data write that the private tx base rollup always performs to update the fee payer's balance.
930-
meteredDAFields += PUBLIC_DATA_WRITE_LENGTH;
931-
}
932-
933928
const meteredDAGas = meteredDAFields * DA_GAS_PER_FIELD;
934929

935930
if ((data as PrivateToPublicAccumulatedData).publicCallRequests) {

yarn-project/pxe/src/contract_function_simulator/execution_note_cache.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ export class ExecutionNoteCache {
4343

4444
private inRevertiblePhase = false;
4545

46+
/**
47+
* Whether the protocol nullifier was used for nonce generation.
48+
* We don't need to use the protocol nullifier if a non-revertible nullifier is emitted.
49+
*/
50+
private usedProtocolNullifierForNonces: boolean | undefined;
51+
4652
constructor(private readonly protocolNullifier: Fr) {}
4753

4854
/**
@@ -58,9 +64,12 @@ export class ExecutionNoteCache {
5864
this.inRevertiblePhase = true;
5965
this.minRevertibleSideEffectCounter = minRevertibleSideEffectCounter;
6066

61-
// The protocol nullifier is always the tx's first nullifier (injected by the kernel init), so it is the
62-
// nonce generator for every note hash.
63-
const nonceGenerator = this.protocolNullifier;
67+
const nullifiers = this.getEmittedNullifiers();
68+
// If there are no nullifiers emitted by private calls so far, we use the protocol nullifier as the nonce generator.
69+
// Note: There could still be nullifiers emitted after the counter is set, but those nullifiers are revertible, so
70+
// we don't want to use them as the nonce generator.
71+
this.usedProtocolNullifierForNonces = nullifiers.length === 0;
72+
const nonceGenerator = this.usedProtocolNullifierForNonces ? this.protocolNullifier : new Fr(nullifiers[0]);
6473

6574
// The existing pending notes are all non-revertible.
6675
// They cannot be squashed by nullifiers emitted after minRevertibleSideEffectCounter is set.
@@ -93,6 +102,14 @@ export class ExecutionNoteCache {
93102
return sideEffectCounter >= this.minRevertibleSideEffectCounter;
94103
}
95104

105+
public finish() {
106+
// If we never entered the revertible phase, and there are no nullifiers emitted, we need to use the protocol
107+
// nullifier as the nonce generator.
108+
if (!this.inRevertiblePhase) {
109+
this.usedProtocolNullifierForNonces = this.getEmittedNullifiers().length === 0;
110+
}
111+
}
112+
96113
/**
97114
* Add a new note to cache.
98115
* @param note - New note created during execution.
@@ -206,15 +223,19 @@ export class ExecutionNoteCache {
206223
}
207224

208225
/**
209-
* @returns All nullifiers of the transaction: the protocol nullifier (the kernel-injected first nullifier),
210-
* followed by those emitted by private calls.
226+
* @returns All nullifiers emitted by private calls in this transaction. If the protocol nullifier was used as the
227+
* nonce generator, it is injected as the first nullifier.
211228
*/
212229
getAllNullifiers(): Fr[] {
213-
return [this.protocolNullifier, ...this.getEmittedNullifiers()];
230+
if (this.usedProtocolNullifierForNonces === undefined) {
231+
throw new Error('usedProtocolNullifierForNonces is not set yet. Call finish() to complete the transaction.');
232+
}
233+
const allNullifiers = this.getEmittedNullifiers();
234+
return [...(this.usedProtocolNullifierForNonces ? [this.protocolNullifier] : []), ...allNullifiers];
214235
}
215236

216237
getNonceGenerator(): Fr {
217-
return this.protocolNullifier;
238+
return this.getAllNullifiers()[0];
218239
}
219240

220241
#recordNullifier(contractAddress: AztecAddress, siloedNullifier: bigint) {

yarn-project/pxe/src/contract_function_simulator/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ export {
2121
ETH_ADDRESS,
2222
EVENT_VALIDATION_REQUEST,
2323
FIELD,
24+
FIXED_ARRAY,
2425
FUNCTION_SELECTOR,
2526
LOG_RETRIEVAL_REQUEST,
2627
LOG_RETRIEVAL_RESPONSE,
2728
MEMBERSHIP_WITNESS,
28-
MESSAGE_CONTEXT,
2929
NOTE_SELECTOR,
3030
NOTE_VALIDATION_REQUEST,
3131
OPTION,
@@ -34,6 +34,7 @@ export {
3434
PROVIDED_SECRET,
3535
SLOT_NUMBER,
3636
STR,
37+
STRUCT,
3738
U32,
3839
tryFieldWidth,
3940
type InputSlot,
@@ -70,6 +71,7 @@ export { EventValidationRequest } from './noir-structs/event_validation_request.
7071
export type { LogRetrievalRequest } from './noir-structs/log_retrieval_request.js';
7172
export type { LogRetrievalResponse } from './noir-structs/log_retrieval_response.js';
7273
export { NoteValidationRequest } from './noir-structs/note_validation_request.js';
74+
export type { PendingTaggedLog } from './noir-structs/pending_tagged_log.js';
7375
export type { TxEffectData } from './noir-structs/tx_effect_data.js';
7476
export type { ProvidedSecret } from './noir-structs/provided_secret.js';
7577
export { ResolvedTx } from './noir-structs/resolved_tx.js';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Fr } from '@aztec/foundation/curves/bn254';
2+
3+
import type { ResolvedTx } from './resolved_tx.js';
4+
5+
/**
6+
* Represents a pending tagged log as it is stored in the pending tagged log array to which the fetchTaggedLogs oracle
7+
* inserts found private logs. A TS version of `pending_tagged_log.nr`.
8+
*/
9+
export type PendingTaggedLog = {
10+
log: Fr[];
11+
context: ResolvedTx;
12+
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Fr } from '@aztec/foundation/curves/bn254';
22
import type { AppTaggingSecretKind } from '@aztec/stdlib/logs';
33

4-
/** A tagging secret an app supplies explicitly to `getPendingTaggedLogs` when PXE cannot derive it internally. */
4+
/** A tagging secret an app supplies explicitly to `getPendingTaggedLogsV2` when PXE cannot derive it internally. */
55
export type ProvidedSecret = { secret: Fr; mode: AppTaggingSecretKind };

yarn-project/pxe/src/contract_function_simulator/oracle/legacy_oracle_registry.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* eslint-disable camelcase */
2-
import { MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_CIPHERTEXT_LEN } from '@aztec/constants';
2+
import { MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_CIPHERTEXT_LEN, PRIVATE_LOG_SIZE_IN_FIELDS } from '@aztec/constants';
33

44
import type { EphemeralArray } from '../noir-structs/ephemeral_array.js';
55
import type { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
6+
import type { PendingTaggedLog } from '../noir-structs/pending_tagged_log.js';
7+
import type { ResolvedTx } from '../noir-structs/resolved_tx.js';
68
import {
79
type InferDeserializedParams,
810
ORACLE_REGISTRY,
@@ -26,6 +28,19 @@ const LEGACY_LOG_RETRIEVAL_RESPONSE: TypeMapping<LegacyLogRetrievalResponse> = S
2628
{ name: 'firstNullifierInTx', type: FIELD },
2729
]);
2830

31+
// Block-less transaction context: the prefix of `ResolvedTx`'s wire carried by the original `getPendingTaggedLogs`
32+
// oracle. Known as `MessageContext` in the Aztec.nr versions that call that oracle.
33+
const LEGACY_MESSAGE_CONTEXT: TypeMapping<LegacyMessageContext> = STRUCT<LegacyMessageContext>([
34+
{ name: 'txHash', type: TX_HASH },
35+
{ name: 'uniqueNoteHashesInTx', type: FIXED_BOUNDED_VEC(FIELD, MAX_NOTE_HASHES_PER_TX) },
36+
{ name: 'firstNullifierInTx', type: FIELD },
37+
]);
38+
39+
const LEGACY_PENDING_TAGGED_LOG: TypeMapping<LegacyPendingTaggedLog> = STRUCT<LegacyPendingTaggedLog>([
40+
{ name: 'log', type: FIXED_BOUNDED_VEC(FIELD, PRIVATE_LOG_SIZE_IN_FIELDS) },
41+
{ name: 'context', type: LEGACY_MESSAGE_CONTEXT },
42+
]);
43+
2944
/**
3045
* Wire shapes that already-deployed contracts still call by their original oracle name, keyed by that retired name.
3146
* New Aztec.nr calls the current name in `ORACLE_REGISTRY`; old bytecode keeps calling the name compiled into it and
@@ -43,13 +58,28 @@ export const LEGACY_ORACLE_REGISTRY: Record<string, LegacyOracleEntry> = {
4358
mapping: result => result as unknown as EphemeralArray<EphemeralArray<LegacyLogRetrievalResponse>>,
4459
},
4560
}),
61+
aztec_utl_getPendingTaggedLogs: legacyOracle({
62+
modernOracle: 'aztec_utl_getPendingTaggedLogsV2',
63+
returnType: {
64+
legacyType: EPHEMERAL_ARRAY(LEGACY_PENDING_TAGGED_LOG),
65+
// We can map this directly, since `ResolvedTx` carries the legacy context's fields under the same names
66+
mapping: result => result as unknown as EphemeralArray<LegacyPendingTaggedLog>,
67+
},
68+
}),
4669
};
4770

4871
type LegacyLogRetrievalResponse = Pick<
4972
LogRetrievalResponse,
5073
'logPayload' | 'txHash' | 'uniqueNoteHashesInTx' | 'firstNullifierInTx'
5174
>;
5275

76+
type LegacyMessageContext = Pick<ResolvedTx, 'txHash' | 'uniqueNoteHashesInTx' | 'firstNullifierInTx'>;
77+
78+
type LegacyPendingTaggedLog = {
79+
log: PendingTaggedLog['log'];
80+
context: LegacyMessageContext;
81+
};
82+
5383
type Registry = typeof ORACLE_REGISTRY;
5484

5585
/** The handler return value type of a modern oracle entry. */

yarn-project/pxe/src/contract_function_simulator/oracle/oracle_registry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ export const ORACLE_REGISTRY = {
225225
returnType: BOUNDED_VEC(NOTE),
226226
}),
227227

228-
aztec_utl_getPendingTaggedLogs: makeEntry({
228+
aztec_utl_getPendingTaggedLogsV2: makeEntry({
229229
params: [
230230
{ name: 'scope', type: AZTEC_ADDRESS },
231231
{ name: 'providedSecrets', type: EPHEMERAL_ARRAY(PROVIDED_SECRET) },

yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution.test.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import type { EmbeddedCurvePoint } from '../noir-structs/embedded_curve_point.js
5555
import { EphemeralArray } from '../noir-structs/ephemeral_array.js';
5656
import { Option } from '../noir-structs/option.js';
5757
import type { ProvidedSecret } from '../noir-structs/provided_secret.js';
58+
import { ResolvedTx } from '../noir-structs/resolved_tx.js';
5859
import { TransientArrayService } from '../transient_array_service.js';
5960
import { UtilityExecutionOracle, type UtilityExecutionOracleArgs } from './utility_execution_oracle.js';
6061

@@ -449,8 +450,8 @@ describe('Utility Execution test suite', () => {
449450
});
450451

451452
// Pins the production oracle's default-authorization allowlist for cross-contract utility reads of the
452-
// standard HandshakeRegistry: only get_handshakes and get_app_siloed_secrets are allowed, everything else is
453-
// denied.
453+
// standard HandshakeRegistry: only get_non_interactive_handshakes and get_app_siloed_secrets are allowed,
454+
// everything else is denied.
454455
describe('cross-contract utility authorization', () => {
455456
const prepareNestedUtilityCall = async (
456457
targetContractAddress: AztecAddress,
@@ -493,7 +494,7 @@ describe('Utility Execution test suite', () => {
493494
nestedSimulator = makeNestedSimulator();
494495
utilityExecutionOracle = makeOracle({ simulator: nestedSimulator });
495496
defaultAuthorizedHandshakeRegistryReads = new Map<string, Fr[]>([
496-
['get_handshakes', []],
497+
['get_non_interactive_handshakes', []],
497498
['get_app_siloed_secrets', [Fr.random(), Fr.random()]],
498499
]);
499500
});
@@ -592,7 +593,7 @@ describe('Utility Execution test suite', () => {
592593
});
593594
});
594595

595-
describe('getPendingTaggedLogs', () => {
596+
describe('getPendingTaggedLogsV2', () => {
596597
const service = new EphemeralArrayService();
597598

598599
it("uses the provided secret's delivery mode when querying pending log tags", async () => {
@@ -630,7 +631,7 @@ describe('Utility Execution test suite', () => {
630631
);
631632
});
632633

633-
const result = await utilityExecutionOracle.getPendingTaggedLogs(
634+
const result = await utilityExecutionOracle.getPendingTaggedLogsV2(
634635
owner,
635636
EphemeralArray.fromValues(service, providedSecrets),
636637
);
@@ -644,11 +645,13 @@ describe('Utility Execution test suite', () => {
644645
expect(resultLogs).toEqual([
645646
{
646647
log: log.logData,
647-
context: {
648-
txHash: log.txHash,
649-
uniqueNoteHashesInTx: log.noteHashes,
650-
firstNullifierInTx: log.nullifiers[0],
651-
},
648+
context: new ResolvedTx(
649+
log.txHash,
650+
log.noteHashes,
651+
log.nullifiers[0],
652+
log.blockNumber,
653+
log.blockHash.toFr(),
654+
),
652655
},
653656
]);
654657
});

0 commit comments

Comments
 (0)