Skip to content

Commit

Permalink
Merge 09a6736 into 46c74f8
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro authored May 7, 2024
2 parents 46c74f8 + 09a6736 commit ab3e2f1
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 10 deletions.
12 changes: 12 additions & 0 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ describe('e2e_avm_simulator', () => {
tx = await avmContract.methods.assert_nullifier_exists(nullifier).send().wait();
expect(tx.status).toEqual(TxStatus.MINED);
});

it('Emit and check in separate enqueued calls but same tx', async () => {
const nullifier = new Fr(123456);

// This will create 1 tx with 2 public calls in it.
await new BatchCall(wallet, [
avmContract.methods.new_nullifier(nullifier).request(),
avmContract.methods.assert_nullifier_exists(nullifier).request(),
])
.send()
.wait();
});
});
});

Expand Down
4 changes: 3 additions & 1 deletion yarn-project/prover-client/src/mocks/test_context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type BlockProver, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types';
import { type Gas, GlobalVariables, Header, type TxContext } from '@aztec/circuits.js';
import { type Gas, GlobalVariables, Header, type Nullifier, type TxContext } from '@aztec/circuits.js';
import { type Fr } from '@aztec/foundation/fields';
import { type DebugLogger } from '@aztec/foundation/log';
import { openTmpStore } from '@aztec/kv-store/utils';
Expand Down Expand Up @@ -129,6 +129,7 @@ export class TestContext {
_globalVariables: GlobalVariables,
availableGas: Gas,
_txContext: TxContext,
_pendingNullifiers: Nullifier[],
transactionFee?: Fr,
_sideEffectCounter?: number,
) => {
Expand Down Expand Up @@ -166,6 +167,7 @@ export class TestContext {
globalVariables: GlobalVariables,
availableGas: Gas,
txContext: TxContext,
pendingNullifiers: Nullifier[],
transactionFee?: Fr,
sideEffectCounter?: number,
) => Promise<PublicExecutionResult>,
Expand Down
27 changes: 19 additions & 8 deletions yarn-project/simulator/src/avm/journal/nullifiers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AztecAddress } from '@aztec/circuits.js';
import { siloNullifier } from '@aztec/circuits.js/hash';
import { Fr } from '@aztec/foundation/fields';

Expand All @@ -10,7 +11,7 @@ import type { CommitmentsDB } from '../../index.js';
*/
export class Nullifiers {
/** Cached nullifiers. */
private cache: NullifierCache;
public cache: NullifierCache;
/** Parent's nullifier cache. Checked on cache-miss. */
private readonly parentCache: NullifierCache | undefined;
/** Reference to node storage. Checked on parent cache-miss. */
Expand Down Expand Up @@ -95,6 +96,7 @@ export class NullifierCache {
* each entry being a nullifier.
*/
private cachePerContract: Map<bigint, Set<bigint>> = new Map();
private siloedNullifiers: Set<bigint> = new Set();

/**
* Check whether a nullifier exists in the cache.
Expand All @@ -104,8 +106,10 @@ export class NullifierCache {
* @returns whether the nullifier is found in the cache
*/
public exists(storageAddress: Fr, nullifier: Fr): boolean {
const exists = this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt());
return exists ? true : false;
const exists =
this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()) ||
this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(storageAddress), nullifier).toBigInt());
return !!exists;
}

/**
Expand All @@ -115,20 +119,25 @@ export class NullifierCache {
* @param nullifier - the nullifier to stage
*/
public append(storageAddress: Fr, nullifier: Fr) {
if (this.exists(storageAddress, nullifier)) {
throw new NullifierCollisionError(
`Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
);
}

let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt());
// If this contract's nullifier set has no cached nullifiers, create a new Set to store them
if (!nullifiersForContract) {
nullifiersForContract = new Set();
this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract);
}
if (nullifiersForContract.has(nullifier.toBigInt())) {
throw new NullifierCollisionError(
`Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
);
}
nullifiersForContract.add(nullifier.toBigInt());
}

public appendSiloed(siloedNullifier: Fr) {
this.siloedNullifiers.add(siloedNullifier.toBigInt());
}

/**
* Merge another cache's nullifiers into this instance's.
*
Expand All @@ -139,6 +148,8 @@ export class NullifierCache {
* @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
*/
public acceptAndMerge(incomingNullifiers: NullifierCache) {
// Merge siloed nullifiers.
this.siloedNullifiers = new Set([...this.siloedNullifiers, ...incomingNullifiers.siloedNullifiers]);
// Iterate over all contracts with staged writes in the child.
for (const [incomingAddress, incomingCacheAtContract] of incomingNullifiers.cachePerContract) {
const thisCacheAtContract = this.cachePerContract.get(incomingAddress);
Expand Down
7 changes: 7 additions & 0 deletions yarn-project/simulator/src/public/abstract_phase_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,15 @@ export abstract class AbstractPhaseManager {
// TODO(6052): Extract correct new counter from nested calls
const sideEffectCounter = lastSideEffectCounter(tx) + 1;
const availableGas = this.getAvailableGas(tx, kernelOutput);
const pendingNullifiers = this.getSiloedPendingNullifiers(kernelOutput);

const result = isExecutionRequest
? await this.publicExecutor.simulate(
current,
this.globalVariables,
availableGas,
tx.data.constants.txContext,
pendingNullifiers,
transactionFee,
sideEffectCounter,
)
Expand Down Expand Up @@ -323,6 +325,11 @@ export abstract class AbstractPhaseManager {
return [publicKernelInputs, kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns];
}

/** Returns all pending private and public nullifiers. */
private getSiloedPendingNullifiers(ko: PublicKernelCircuitPublicInputs) {
return [...ko.end.newNullifiers, ...ko.endNonRevertibleData.newNullifiers].filter(n => !n.isEmpty());
}

protected getAvailableGas(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs) {
return tx.data.constants.txContext.gasSettings
.getLimits() // No need to subtract teardown limits since they are already included in end.gasUsed
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Gas,
type GlobalVariables,
type Header,
type Nullifier,
PublicCircuitPublicInputs,
type TxContext,
} from '@aztec/circuits.js';
Expand Down Expand Up @@ -78,6 +79,9 @@ async function executeTopLevelPublicFunctionAvm(
// or modify the PersistableStateManager to manage rollbacks across enqueued-calls and transactions.
const worldStateJournal = new AvmPersistableStateManager(hostStorage);
const startSideEffectCounter = executionContext.execution.callContext.sideEffectCounter;
for (const nullifier of executionContext.pendingNullifiers) {
worldStateJournal.nullifiers.cache.appendSiloed(nullifier.value);
}
worldStateJournal.trace.accessCounter = startSideEffectCounter;

const executionEnv = createAvmExecutionEnvironment(
Expand Down Expand Up @@ -289,6 +293,7 @@ export class PublicExecutor {
globalVariables: GlobalVariables,
availableGas: Gas,
txContext: TxContext,
pendingNullifiers: Nullifier[],
transactionFee: Fr = Fr.ZERO,
sideEffectCounter: number = 0,
): Promise<PublicExecutionResult> {
Expand All @@ -308,6 +313,7 @@ export class PublicExecutor {
availableGas,
transactionFee,
txContext.gasSettings,
pendingNullifiers,
);

const executionResult = await executePublicFunction(context, /*nested=*/ false);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/public/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ describe('ACIR public execution simulator', () => {
});

const simulate = (execution: PublicExecution, globalVariables: GlobalVariables) =>
executor.simulate(execution, globalVariables, Gas.test(), makeTxContext(), Fr.ZERO);
executor.simulate(execution, globalVariables, Gas.test(), makeTxContext(), /*pendingNullifiers=*/ [], Fr.ZERO);

describe('Token contract', () => {
let recipient: AztecAddress;
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/simulator/src/public/public_execution_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type GasSettings,
type GlobalVariables,
type Header,
type Nullifier,
PublicContextInputs,
} from '@aztec/circuits.js';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
Expand Down Expand Up @@ -45,6 +46,7 @@ export class PublicExecutionContext extends TypedOracle {
public readonly availableGas: Gas,
public readonly transactionFee: Fr,
public readonly gasSettings: GasSettings,
public readonly pendingNullifiers: Nullifier[],
// Unencrypted logs emitted during this call AND any nested calls
// Useful for maintaining correct ordering in ts
private allUnencryptedLogs: UnencryptedL2Log[] = [],
Expand Down Expand Up @@ -239,6 +241,7 @@ export class PublicExecutionContext extends TypedOracle {
this.availableGas,
this.transactionFee,
this.gasSettings,
/*pendingNullifiers=*/ [],
this.allUnencryptedLogs,
this.log,
);
Expand Down
1 change: 1 addition & 0 deletions yarn-project/simulator/src/public/public_processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ describe('public_processor', () => {
expect.anything(), // GlobalVariables
Gas.from(availableGas),
expect.anything(), // TxContext
expect.anything(), // pendingNullifiers
new Fr(txFee),
expect.anything(), // SideEffectCounter
];
Expand Down

0 comments on commit ab3e2f1

Please sign in to comment.