Skip to content

Commit

Permalink
feat: accured substate instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
Maddiaa0 committed Jan 24, 2024
1 parent d9fe24b commit 22cf306
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 31 deletions.
23 changes: 14 additions & 9 deletions yarn-project/acir-simulator/src/avm/journal/journal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ describe('journal', () => {
describe('UTXOs', () => {
it('Should maintain commitments', () => {
const utxo = new Fr(1);
journal.writeCommitment(utxo);
journal.writeNoteHash(utxo);

const journalUpdates = journal.flush();
expect(journalUpdates.newCommitments).toEqual([utxo]);
expect(journalUpdates.newNoteHashes).toEqual([utxo]);
});

it('Should maintain l1 messages', () => {
const utxo = new Fr(1);
const utxo = [new Fr(1)];
journal.writeL1Message(utxo);

const journalUpdates = journal.flush();
Expand Down Expand Up @@ -123,16 +123,20 @@ describe('journal', () => {
const valueT1 = new Fr(2);
const commitment = new Fr(10);
const commitmentT1 = new Fr(20);
const logs = [new Fr(1), new Fr(2)];
const logsT1 = [new Fr(3), new Fr(4)];

journal.writeStorage(contractAddress, key, value);
journal.writeCommitment(commitment);
journal.writeL1Message(commitment);
journal.writeNoteHash(commitment);
journal.writeLog(logs);
journal.writeL1Message(logs);
journal.writeNullifier(commitment);

const journal1 = new AvmJournal(journal.hostStorage, journal);
journal.writeStorage(contractAddress, key, valueT1);
journal.writeCommitment(commitmentT1);
journal.writeL1Message(commitmentT1);
journal.writeNoteHash(commitmentT1);
journal.writeLog(logsT1);
journal.writeL1Message(logsT1);
journal.writeNullifier(commitmentT1);

journal1.mergeWithParent();
Expand All @@ -143,8 +147,9 @@ describe('journal', () => {

// Check that the UTXOs are merged
const journalUpdates: JournalData = journal.flush();
expect(journalUpdates.newCommitments).toEqual([commitment, commitmentT1]);
expect(journalUpdates.newL1Messages).toEqual([commitment, commitmentT1]);
expect(journalUpdates.newNoteHashes).toEqual([commitment, commitmentT1]);
expect(journalUpdates.newLogs).toEqual([logs, logsT1]);
expect(journalUpdates.newL1Messages).toEqual([logs, logsT1]);
expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]);
});

Expand Down
39 changes: 17 additions & 22 deletions yarn-project/acir-simulator/src/avm/journal/journal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import { HostStorage } from './host_storage.js';
* Data held within the journal
*/
export type JournalData = {
newCommitments: Fr[];

newL1Messages: Fr[];

newNoteHashes: Fr[];
newNullifiers: Fr[];
newL1Messages: Fr[][];
newLogs: Fr[][];
/** contract address -\> key -\> value */
storageWrites: Map<bigint, Map<bigint, Fr>>;
};
Expand All @@ -34,11 +33,11 @@ export class AvmJournal {
private storageReads: Map<bigint, Map<bigint, Fr>> = new Map();

// New written state
private newCommitments: Fr[] = [];
private newNoteHashes: Fr[] = [];
private newNullifiers: Fr[] = [];
private newL1Message: Fr[] = [];

// New Substrate
// New Substate
private newL1Message: Fr[][] = [];
private newLogs: Fr[][] = [];

// contract address -> key -> value
Expand Down Expand Up @@ -102,27 +101,22 @@ export class AvmJournal {
return this.hostStorage.publicStateDb.storageRead(contractAddress, key);
}

/** -
* @param commitment -
*/
public writeCommitment(commitment: Fr) {
this.newCommitments.push(commitment);
public writeNoteHash(noteHash: Fr) {
this.newNoteHashes.push(noteHash);
}

/** -
* @param message -
*/
public writeL1Message(message: Fr) {
public writeL1Message(message: Fr[]) {
this.newL1Message.push(message);
}

/** -
* @param nullifier -
*/
public writeNullifier(nullifier: Fr) {
this.newNullifiers.push(nullifier);
}

public writeLog(log: Fr[]) {
this.newLogs.push(log);
}

/**
* Merge Journal into parent
* - Utxo objects are concatenated
Expand All @@ -136,7 +130,7 @@ export class AvmJournal {
const incomingFlush = this.flush();

// Merge UTXOs
this.parentJournal.newCommitments = this.parentJournal.newCommitments.concat(incomingFlush.newCommitments);
this.parentJournal.newNoteHashes = this.parentJournal.newNoteHashes.concat(incomingFlush.newNoteHashes);
this.parentJournal.newL1Message = this.parentJournal.newL1Message.concat(incomingFlush.newL1Messages);
this.parentJournal.newNullifiers = this.parentJournal.newNullifiers.concat(incomingFlush.newNullifiers);

Expand All @@ -150,9 +144,10 @@ export class AvmJournal {
*/
public flush(): JournalData {
return {
newCommitments: this.newCommitments,
newL1Messages: this.newL1Message,
newNoteHashes: this.newNoteHashes,
newNullifiers: this.newNullifiers,
newL1Messages: this.newL1Message,
newLogs: this.newLogs,
storageWrites: this.storageWrites,
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Fr } from '@aztec/foundation/fields';

import { mock } from 'jest-mock-extended';

import { AvmMachineState } from '../avm_machine_state.js';
import { initExecutionEnvironment } from '../fixtures/index.js';
import { HostStorage } from '../journal/host_storage.js';
import { AvmJournal } from '../journal/journal.js';
import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, SendL2ToL1Message } from './accrued_substate.js';
import { StaticCallStorageAlterError } from './storage.js';

describe('Accrued Substate', () => {
let journal: AvmJournal;
let machineState: AvmMachineState;

beforeEach(async () => {
const hostStorage = mock<HostStorage>();
journal = new AvmJournal(hostStorage);
machineState = new AvmMachineState(initExecutionEnvironment());
});

it('Should append a new note hash correctly', async () => {
const value = new Fr(69n);
machineState.writeMemory(0, value);

await new EmitNoteHash(0).execute(machineState, journal);

const journalState = journal.flush();
expect(journalState.newNoteHashes).toEqual([value]);
});

it('Should append a new nullifier correctly', async () => {
const value = new Fr(69n);
machineState.writeMemory(0, value);

await new EmitNullifier(0).execute(machineState, journal);

const journalState = journal.flush();
expect(journalState.newNullifiers).toEqual([value]);
});

it('Should append unencrypted logs correctly', async () => {
const startOffset = 0;
const length = 2;

const values = [new Fr(69n), new Fr(420n)];
machineState.writeMemoryChunk(0, values);

await new EmitUnencryptedLog(startOffset, length).execute(machineState, journal);

const journalState = journal.flush();
expect(journalState.newLogs).toEqual([values]);
});

it('Should append l1 to l2 messages correctly', async () => {
const startOffset = 0;
const length = 2;

const values = [new Fr(69n), new Fr(420n)];
machineState.writeMemoryChunk(0, values);

await new SendL2ToL1Message(startOffset, length).execute(machineState, journal);

const journalState = journal.flush();
expect(journalState.newLogs).toEqual([values]);
});

it('All substate instructions should fail within a static call', async () => {
const executionEnvironment = initExecutionEnvironment({ isStaticCall: true });
machineState = new AvmMachineState(executionEnvironment);

const instructions = [
new EmitNoteHash(0),
new EmitNullifier(0),
new EmitUnencryptedLog(0, 1),
new SendL2ToL1Message(0, 1),
];

for (const instruction of instructions) {
const inst = () => instruction.execute(machineState, journal);
await expect(inst()).rejects.toThrowError(StaticCallStorageAlterError);
}
});
});
88 changes: 88 additions & 0 deletions yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { AvmMachineState } from '../avm_machine_state.js';
import { AvmJournal } from '../journal/journal.js';
import { Instruction } from './instruction.js';
import { StaticCallStorageAlterError } from './storage.js';

export class EmitNoteHash extends Instruction {
static type: string = 'EMITNOTEHASH';
static numberOfOperands = 1;

constructor(private noteHashOffset: number) {
super();
}

async execute(machineState: AvmMachineState, journal: AvmJournal): Promise<void> {
if (machineState.executionEnvironment.isStaticCall) {
throw new StaticCallStorageAlterError();
}

const noteHash = machineState.readMemory(this.noteHashOffset);

journal.writeNoteHash(noteHash);

this.incrementPc(machineState);
}
}

export class EmitNullifier extends Instruction {
static type: string = 'EMITNULLIFIER';
static numberOfOperands = 1;

constructor(private nullifierOffset: number) {
super();
}

async execute(machineState: AvmMachineState, journal: AvmJournal): Promise<void> {
if (machineState.executionEnvironment.isStaticCall) {
throw new StaticCallStorageAlterError();
}

const nullifier = machineState.readMemory(this.nullifierOffset);

journal.writeNullifier(nullifier);

this.incrementPc(machineState);
}
}

export class EmitUnencryptedLog extends Instruction {
static type: string = 'EMITUNENCRYPTEDLOG';
static numberOfOperands = 2;

constructor(private logOffset: number, private logSize: number) {
super();
}

async execute(machineState: AvmMachineState, journal: AvmJournal): Promise<void> {
if (machineState.executionEnvironment.isStaticCall) {
throw new StaticCallStorageAlterError();
}

const log = machineState.readMemoryChunk(this.logOffset, this.logSize);

journal.writeLog(log);

this.incrementPc(machineState);
}
}

export class SendL2ToL1Message extends Instruction {
static type: string = 'EMITUNENCRYPTEDLOG';
static numberOfOperands = 2;

constructor(private msgOffset: number, private msgSize: number) {
super();
}

async execute(machineState: AvmMachineState, journal: AvmJournal): Promise<void> {
if (machineState.executionEnvironment.isStaticCall) {
throw new StaticCallStorageAlterError();
}

const msg = machineState.readMemoryChunk(this.msgOffset, this.msgSize);

journal.writeLog(msg);

this.incrementPc(machineState);
}
}

0 comments on commit 22cf306

Please sign in to comment.