Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: process note logs in aztec-nr #10651

Merged
merged 30 commits into from
Jan 16, 2025
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a124c6a
Sketching out initial approach
nventuro Dec 12, 2024
ec92180
Success!
nventuro Dec 13, 2024
2f52d31
IT LIVES
nventuro Dec 13, 2024
a443446
Misc doc improvements
nventuro Dec 13, 2024
dae83d7
Some more minor comments
nventuro Dec 13, 2024
40d2dae
Remove old ts code
nventuro Dec 14, 2024
893ad80
noir formatting
nventuro Dec 14, 2024
4c88865
Merge branch 'master' into nv/process_note_logs
nventuro Jan 8, 2025
206444f
It works!
nventuro Jan 9, 2025
51a7f0b
Add some docs
nventuro Jan 9, 2025
212219a
Merge branch 'master' into nv/process_note_logs
nventuro Jan 9, 2025
646f5ff
Handle no note contracts
nventuro Jan 9, 2025
b771c98
Fix macro
nventuro Jan 9, 2025
ebf7412
Merge branch 'master' into nv/process_note_logs
nventuro Jan 9, 2025
eccd8b6
Fix import
nventuro Jan 9, 2025
da8408f
Remove extra file
nventuro Jan 10, 2025
d5fe202
Apply suggestions from code review
nventuro Jan 10, 2025
96af47d
Rename foreach
nventuro Jan 10, 2025
48fe292
Move files around
nventuro Jan 10, 2025
7f46d5a
Merge branch 'master' into nv/process_note_logs
nventuro Jan 10, 2025
30cbc8a
If I have to nargo fmt one more time
nventuro Jan 10, 2025
5205cc4
Oh god
nventuro Jan 10, 2025
76bbd1b
zzz
nventuro Jan 10, 2025
d44ec2e
kill me now
nventuro Jan 10, 2025
8b7d508
Add node methods to txe node
nventuro Jan 13, 2025
ff0127c
Merge branch 'master' into nv/process_note_logs
nventuro Jan 13, 2025
8f56981
Add sim prov
nventuro Jan 13, 2025
72ea7c4
Fix build error
nventuro Jan 13, 2025
36c29e8
fix: simulator oracle test
benesjan Jan 15, 2025
d8b24ab
Merge branch 'master' into nv/process_note_logs
benesjan Jan 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 36 additions & 89 deletions yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
type TxEffect,
TxHash,
TxScopedL2Log,
randomContractArtifact,
randomContractInstanceWithAddress,
randomInBlock,
wrapInBlock,
} from '@aztec/circuit-types';
Expand All @@ -23,6 +25,7 @@ import {
computeTaggingSecretPoint,
deriveKeys,
} from '@aztec/circuits.js';
import { type FunctionArtifact, FunctionType } from '@aztec/foundation/abi';
import { pedersenHash, poseidon2Hash } from '@aztec/foundation/crypto';
import { KeyStore } from '@aztec/key-store';
import { openTmpStore } from '@aztec/kv-store/lmdb';
Expand All @@ -34,7 +37,6 @@ import times from 'lodash.times';

import { type PxeDatabase } from '../database/index.js';
import { KVPxeDatabase } from '../database/kv_pxe_database.js';
import { type NoteDao } from '../database/note_dao.js';
import { ContractDataOracle } from '../index.js';
import { SimulatorOracle } from './index.js';
import { WINDOW_HALF_SIZE } from './tagging_utils.js';
Expand Down Expand Up @@ -466,21 +468,41 @@ describe('Simulator oracle', () => {
let getNotesSpy: any;
let removeNullifiedNotesSpy: any;
let simulator: MockProxy<AcirSimulator>;
let runUnconstrainedSpy: any;

let processLogFuncArtifact: FunctionArtifact;

beforeEach(async () => {
// Set up process_log function artifact --> it is never executed as simulator.runUnconstrained(...) is mocked
processLogFuncArtifact = {
name: 'process_log',
functionType: FunctionType.UNCONSTRAINED,
isInternal: false,
parameters: [],
returnTypes: [],
errorTypes: {},
isInitializer: false,
isStatic: false,
bytecode: Buffer.alloc(0),
debugSymbols: '',
};

// Set up contract instance and artifact
const contractInstance = randomContractInstanceWithAddress();
const contractArtifact = randomContractArtifact();
contractArtifact.functions = [processLogFuncArtifact];
await database.addContractInstance(contractInstance);
await database.addContractArtifact(contractInstance.contractClassId, contractArtifact);
contractAddress = contractInstance.address;

beforeEach(() => {
addNotesSpy = jest.spyOn(database, 'addNotes');
getNotesSpy = jest.spyOn(database, 'getNotes');
removeNullifiedNotesSpy = jest.spyOn(database, 'removeNullifiedNotes');
removeNullifiedNotesSpy.mockImplementation(() => Promise.resolve([]));
simulator = mock<AcirSimulator>();
simulator.computeNoteHashAndOptionallyANullifier.mockImplementation((...args: any) =>
Promise.resolve({
noteHash: Fr.random(),
uniqueNoteHash: pedersenHash(args[5].items), // args[5] is note
siloedNoteHash: Fr.random(),
innerNullifier: Fr.random(),
}),
);
simulator.runUnconstrained.mockImplementation(() => Promise.resolve({}));

runUnconstrainedSpy = jest.spyOn(simulator, 'runUnconstrained');
});

afterEach(() => {
Expand Down Expand Up @@ -544,32 +566,7 @@ describe('Simulator oracle', () => {
);
return taggedLogs;
}

it('should store an incoming note that belongs to us', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the tests test less, but that is fine as the complexity has moved to the contract out of PXE.

Instead of testing that the note has actually been added to the db, I just test that a process_log func has been called on the contract.

Given the above I felt like it made not sense to have these 3 tests anymore so I reduced them to only 1.

const request = new MockNoteRequest(
getRandomNoteLogPayload(Fr.random(), contractAddress),
4,
0,
2,
recipient.address,
);
const taggedLogs = mockTaggedLogs([request]);

await simulatorOracle.processTaggedLogs(taggedLogs, recipient.address, simulator);

expect(addNotesSpy).toHaveBeenCalledTimes(1);
expect(addNotesSpy).toHaveBeenCalledWith(
[
expect.objectContaining({
...request.snippetOfNoteDao,
index: request.indexWithinNoteHashTree,
}),
],
recipient.address,
);
}, 25_000);

it('should store multiple notes that belong to us', async () => {
it('should call processLog on multiple notes', async () => {
const requests = [
new MockNoteRequest(getRandomNoteLogPayload(Fr.random(), contractAddress), 1, 1, 1, recipient.address),
new MockNoteRequest(
Expand All @@ -594,25 +591,9 @@ describe('Simulator oracle', () => {

await simulatorOracle.processTaggedLogs(taggedLogs, recipient.address, simulator);

expect(addNotesSpy).toHaveBeenCalledTimes(1);
expect(addNotesSpy).toHaveBeenCalledWith(
// Incoming should contain notes from requests 0, 2, 4 because in those requests we set owner address point.
[
expect.objectContaining({
...requests[0].snippetOfNoteDao,
index: requests[0].indexWithinNoteHashTree,
}),
expect.objectContaining({
...requests[2].snippetOfNoteDao,
index: requests[2].indexWithinNoteHashTree,
}),
expect.objectContaining({
...requests[4].snippetOfNoteDao,
index: requests[4].indexWithinNoteHashTree,
}),
],
recipient.address,
);
// We test that a call to `processLog` is made with the correct function artifact and contract address
expect(runUnconstrainedSpy).toHaveBeenCalledTimes(3);
expect(runUnconstrainedSpy).toHaveBeenCalledWith(expect.anything(), processLogFuncArtifact, contractAddress, []);
}, 30_000);

it('should not store notes that do not belong to us', async () => {
Expand All @@ -629,40 +610,6 @@ describe('Simulator oracle', () => {
expect(addNotesSpy).toHaveBeenCalledTimes(0);
});

it('should be able to recover two note payloads containing the same note', async () => {
const note = getRandomNoteLogPayload(Fr.random(), contractAddress);
const note2 = getRandomNoteLogPayload(Fr.random(), contractAddress);
// All note payloads except one have the same contract address, storage slot, and the actual note.
const requests = [
new MockNoteRequest(note, 3, 0, 0, recipient.address),
new MockNoteRequest(note, 4, 0, 2, recipient.address),
new MockNoteRequest(note, 4, 2, 0, recipient.address),
new MockNoteRequest(note2, 5, 2, 1, recipient.address),
new MockNoteRequest(note, 6, 2, 3, recipient.address),
];

const taggedLogs = mockTaggedLogs(requests);

await simulatorOracle.processTaggedLogs(taggedLogs, recipient.address, simulator);

// Check notes
{
const addedNotes: NoteDao[] = addNotesSpy.mock.calls[0][0];
expect(addedNotes.map(dao => dao)).toEqual([
expect.objectContaining({ ...requests[0].snippetOfNoteDao, index: requests[0].indexWithinNoteHashTree }),
expect.objectContaining({ ...requests[1].snippetOfNoteDao, index: requests[1].indexWithinNoteHashTree }),
expect.objectContaining({ ...requests[2].snippetOfNoteDao, index: requests[2].indexWithinNoteHashTree }),
expect.objectContaining({ ...requests[3].snippetOfNoteDao, index: requests[3].indexWithinNoteHashTree }),
expect.objectContaining({ ...requests[4].snippetOfNoteDao, index: requests[4].indexWithinNoteHashTree }),
]);

// Check that every note has a different nonce.
const nonceSet = new Set<bigint>();
addedNotes.forEach(info => nonceSet.add(info.nonce.value));
expect(nonceSet.size).toBe(requests.length);
}
});

it('should remove nullified notes', async () => {
const requests = [
new MockNoteRequest(getRandomNoteLogPayload(Fr.random(), contractAddress), 1, 1, 1, recipient.address),
Expand Down
Loading