Skip to content

Commit

Permalink
first PoC
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Apr 5, 2024
1 parent c672541 commit 1ca2df4
Show file tree
Hide file tree
Showing 16 changed files with 399 additions and 281 deletions.
3 changes: 0 additions & 3 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
BinaryIntOp::Xor => AvmOpcode::XOR,
BinaryIntOp::Shl => AvmOpcode::SHL,
BinaryIntOp::Shr => AvmOpcode::SHR,
_ => panic!(
"Transpiler doesn't know how to process {:?}", brillig_instr
),
};
avm_instrs.push(AvmInstruction {
opcode: avm_opcode,
Expand Down
1 change: 0 additions & 1 deletion avm-transpiler/src/transpile_contract.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use base64::Engine;
use log::info;
use regex::Regex;
use serde::{Deserialize, Serialize};

use acvm::acir::circuit::Program;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ contract AvmTest {
// Libs
use dep::aztec::prelude::Map;
use dep::aztec::state_vars::PublicMutable;
use dep::aztec::history::nullifier_inclusion::prove_nullifier_inclusion;
use dep::aztec::protocol_types::{
address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH,
contract_instance::ContractInstance
contract_instance::ContractInstance,
hash::silo_nullifier,
};
use dep::aztec::oracle::get_contract_instance::{get_contract_instance_avm, get_contract_instance_internal_avm};
use dep::aztec::protocol_types::abis::function_selector::FunctionSelector;
Expand Down Expand Up @@ -187,6 +189,18 @@ contract AvmTest {
123456
}

#[aztec(public)]
fn new_nullifier_acvm(nullifier: Field) -> pub Field {
context.push_new_nullifier(nullifier, 0);
}

#[aztec(public)]
fn assert_unsiloed_nullifier_acvm(nullifier: Field) {
// ACVM requires siloed nullifier.
let siloed_nullifier = silo_nullifier(context.this_address(), nullifier);
prove_nullifier_inclusion(siloed_nullifier, context);
}

#[aztec(public-vm)]
fn call_acvm_from_avm() -> pub Field {
let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(
Expand All @@ -207,6 +221,15 @@ contract AvmTest {
data_to_return[0]
}

#[aztec(public-vm)]
fn avm_to_acvm_call(selector: FunctionSelector, args: Field) {
context.call_public_function(
context.this_address(),
selector,
[args]
);
}

/************************************************************************
* Contract instance
************************************************************************/
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/end-to-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"clean": "rm -rf ./dest .tsbuildinfo",
"formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src",
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
"test": "DEBUG='aztec:*' NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --runInBand --testTimeout=60000 --forceExit",
"test:all-logs": "DEBUG='aztec:*' NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --runInBand --testTimeout=60000 --forceExit",
"test": "DEBUG='aztec:*,-*avm_simulator:memory,-*avm_simulator:core*' NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --runInBand --testTimeout=60000 --forceExit",
"test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"",
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --no-cache --runInBand --config jest.integration.config.json"
},
Expand Down
42 changes: 35 additions & 7 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AztecAddress, Fr, TxStatus, type Wallet } from '@aztec/aztec.js';
import { AztecAddress, Fr, FunctionSelector, TxStatus, type Wallet } from '@aztec/aztec.js';
import { AvmInitializerTestContract, AvmTestContract } from '@aztec/noir-contracts.js';

import { jest } from '@jest/globals';
Expand Down Expand Up @@ -64,6 +64,40 @@ describe('e2e_avm_simulator', () => {
expect(tx.status).toEqual(TxStatus.MINED);
});
});

describe('ACVM interoperability', () => {
it('Can execute ACVM function among AVM functions', async () => {
expect(await avmContract.methods.constant_field_acvm().simulate()).toEqual([123456n, 0n, 0n, 0n]);
});

it('Can call AVM function from ACVM', async () => {
expect(await avmContract.methods.call_avm_from_acvm().simulate()).toEqual([123456n, 0n, 0n, 0n]);
});

it('Can call ACVM function from AVM', async () => {
expect(await avmContract.methods.call_acvm_from_avm().simulate()).toEqual([123456n, 0n, 0n, 0n]);
});

// Cannot work because ACVM does not support pending nullifiers.
// it('AVM->ACVM nullifiers work (pending)', async () => {
// await avmContract.methods.avm_to_acvm_nullifier().send().wait();
// });

it('AVM sees settled nullifiers by ACVM', async () => {
const nullifier = new Fr(123456);
await avmContract.methods.new_nullifier(nullifier).send().wait();
await avmContract.methods.assert_unsiloed_nullifier_acvm(nullifier).send().wait();
});

it('AVM nested call to ACVM sees settled nullifiers', async () => {
const nullifier = new Fr(123456);
await avmContract.methods.new_nullifier(nullifier).send().wait();
await avmContract.methods
.avm_to_acvm_call(FunctionSelector.fromSignature('assert_unsiloed_nullifier_acvm(Field)'), nullifier)
.send()
.wait();
});
});
});

describe('AvmInitializerTestContract', () => {
Expand All @@ -79,10 +113,4 @@ describe('e2e_avm_simulator', () => {
});
});
});

describe('ACVM interoperability', () => {
it('Can execute ACVM function among AVM functions', async () => {
expect(await avmContact.methods.constant_field_acvm().simulate()).toEqual(123456n);
});
});
});
8 changes: 4 additions & 4 deletions yarn-project/simulator/src/avm/avm_execution_environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ export class AvmExecutionEnvironment {
}

public deriveEnvironmentForNestedCall(
address: AztecAddress,
targetAddress: AztecAddress,
calldata: Fr[],
temporaryFunctionSelector: FunctionSelector = FunctionSelector.empty(),
): AvmExecutionEnvironment {
return new AvmExecutionEnvironment(
address,
/*storageAddress=*/ address,
targetAddress,
/*storageAddress=*/ targetAddress,
this.origin,
this.sender,
this.address,
this.portal,
this.feePerL1Gas,
this.feePerL2Gas,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/avm/avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AvmTestContractArtifact } from '@aztec/noir-contracts.js';
import { jest } from '@jest/globals';
import { strict as assert } from 'assert';

import { isAvmBytecode } from '../public/transitional_adaptors.js';
import { AvmMachineState } from './avm_machine_state.js';
import { TypeTag } from './avm_memory_types.js';
import { AvmSimulator } from './avm_simulator.js';
Expand All @@ -23,7 +24,6 @@ import {
} from './fixtures/index.js';
import { Add, CalldataCopy, Return } from './opcodes/index.js';
import { encodeToBytecode } from './serialization/bytecode_serialization.js';
import { isAvmBytecode } from './temporary_executor_migration.js';

describe('AVM simulator: injected bytecode', () => {
let calldata: Fr[];
Expand Down
20 changes: 13 additions & 7 deletions yarn-project/simulator/src/avm/journal/journal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { type HostStorage } from './host_storage.js';
import { Nullifiers } from './nullifiers.js';
import { PublicStorage } from './public_storage.js';
import { WorldStateAccessTrace } from './trace.js';
import { type TracedL1toL2MessageCheck, type TracedNoteHashCheck, type TracedNullifierCheck } from './trace_types.js';
import {
type TracedL1toL2MessageCheck,
type TracedNoteHashCheck,
type TracedNullifier,
type TracedNullifierCheck,
} from './trace_types.js';

/**
* Data held within the journal
Expand All @@ -16,7 +21,7 @@ export type JournalData = {
noteHashChecks: TracedNoteHashCheck[];
newNoteHashes: Fr[];
nullifierChecks: TracedNullifierCheck[];
newNullifiers: Fr[];
newNullifiers: TracedNullifier[];
l1ToL2MessageChecks: TracedL1toL2MessageCheck[];

newL1Messages: L2ToL1Message[];
Expand Down Expand Up @@ -44,18 +49,19 @@ export class AvmPersistableStateManager {
/** Reference to node storage */
public readonly hostStorage: HostStorage;

// TODO: make members private once this is not used in transitional_adaptors.ts.
/** World State */
/** Public storage, including cached writes */
private publicStorage: PublicStorage;
public publicStorage: PublicStorage;
/** Nullifier set, including cached/recently-emitted nullifiers */
private nullifiers: Nullifiers;
public nullifiers: Nullifiers;

/** World State Access Trace */
private trace: WorldStateAccessTrace;
public trace: WorldStateAccessTrace;

/** Accrued Substate **/
private newL1Messages: L2ToL1Message[] = [];
private newLogs: UnencryptedL2Log[] = [];
public newL1Messages: L2ToL1Message[] = [];
public newLogs: UnencryptedL2Log[] = [];

constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) {
this.hostStorage = hostStorage;
Expand Down
29 changes: 16 additions & 13 deletions yarn-project/simulator/src/avm/journal/trace.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Fr } from '@aztec/foundation/fields';

import { type TracedL1toL2MessageCheck, type TracedNoteHashCheck, type TracedNullifierCheck } from './trace_types.js';
import {
type TracedL1toL2MessageCheck,
type TracedNoteHashCheck,
type TracedNullifier,
type TracedNullifierCheck,
} from './trace_types.js';

export class WorldStateAccessTrace {
public accessCounter: number;
Expand All @@ -15,8 +20,7 @@ export class WorldStateAccessTrace {
//public newNoteHashes: TracedNoteHash[] = [];
public newNoteHashes: Fr[] = [];
public nullifierChecks: TracedNullifierCheck[] = [];
//public newNullifiers: TracedNullifier[] = [];
public newNullifiers: Fr[] = [];
public newNullifiers: TracedNullifier[] = [];
public l1ToL2MessageChecks: TracedL1toL2MessageCheck[] = [];
//public archiveChecks: TracedArchiveLeafCheck[] = [];

Expand Down Expand Up @@ -105,17 +109,16 @@ export class WorldStateAccessTrace {
this.incrementAccessCounter();
}

public traceNewNullifier(_storageAddress: Fr, nullifier: Fr) {
public traceNewNullifier(storageAddress: Fr, nullifier: Fr) {
// TODO(4805): check if some threshold is reached for max new nullifier
//const traced: TracedNullifier = {
// callPointer: Fr.ZERO,
// storageAddress,
// nullifier,
// counter: new Fr(this.accessCounter),
// endLifetime: Fr.ZERO,
//};
//this.newNullifiers.push(traced);
this.newNullifiers.push(nullifier);
const tracedNullifier: TracedNullifier = {
callPointer: Fr.ZERO,
storageAddress,
nullifier,
counter: new Fr(this.accessCounter),
endLifetime: Fr.ZERO,
};
this.newNullifiers.push(tracedNullifier);
this.incrementAccessCounter();
}

Expand Down
14 changes: 7 additions & 7 deletions yarn-project/simulator/src/avm/journal/trace_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ export type TracedNullifierCheck = {
leafIndex: Fr;
};

//export type TracedNullifier = {
// callPointer: Fr;
// storageAddress: Fr;
// nullifier: Fr;
// counter: Fr;
// endLifetime: Fr;
//};
export type TracedNullifier = {
callPointer: Fr;
storageAddress: Fr;
nullifier: Fr;
counter: Fr;
endLifetime: Fr;
};

export type TracedL1toL2MessageCheck = {
//callPointer: Fr;
Expand Down
25 changes: 14 additions & 11 deletions yarn-project/simulator/src/avm/opcodes/external_calls.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { jest } from '@jest/globals';
import { mock } from 'jest-mock-extended';

import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from '../../index.js';
import { markBytecodeAsAvm } from '../../public/transitional_adaptors.js';
import { type AvmContext } from '../avm_context.js';
import { Field, Uint8 } from '../avm_memory_types.js';
import { adjustCalldataIndex, initContext } from '../fixtures/index.js';
Expand Down Expand Up @@ -72,16 +73,18 @@ describe('External Calls', () => {
const successOffset = 7;

const otherContextInstructionsL2GasCost = 780; // Includes the cost of the call itself
const otherContextInstructionsBytecode = encodeToBytecode([
new CalldataCopy(
/*indirect=*/ 0,
/*csOffset=*/ adjustCalldataIndex(0),
/*copySize=*/ argsSize,
/*dstOffset=*/ 0,
),
new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 0),
new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2),
]);
const otherContextInstructionsBytecode = markBytecodeAsAvm(
encodeToBytecode([
new CalldataCopy(
/*indirect=*/ 0,
/*csOffset=*/ adjustCalldataIndex(0),
/*copySize=*/ argsSize,
/*dstOffset=*/ 0,
),
new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 0),
new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2),
]),
);

const { l1GasLeft: initialL1Gas, l2GasLeft: initialL2Gas, daGasLeft: initialDaGas } = context.machineState;

Expand Down Expand Up @@ -227,7 +230,7 @@ describe('External Calls', () => {
new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0),
];

const otherContextInstructionsBytecode = encodeToBytecode(otherContextInstructions);
const otherContextInstructionsBytecode = markBytecodeAsAvm(encodeToBytecode(otherContextInstructions));

jest
.spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode')
Expand Down
26 changes: 22 additions & 4 deletions yarn-project/simulator/src/avm/opcodes/external_calls.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { FunctionSelector } from '@aztec/circuits.js';
import { padArrayEnd } from '@aztec/foundation/collection';

import { executePublicFunction } from '../../public/executor.js';
import {
adjustAvmContextFromPublicExecutionResult,
convertPublicExecutionResult,
createPublicExecutionContext,
} from '../../public/transitional_adaptors.js';
import type { AvmContext } from '../avm_context.js';
import { gasLeftToGas, sumGas } from '../avm_gas.js';
import { Field, Uint8 } from '../avm_memory_types.js';
import { AvmSimulator } from '../avm_simulator.js';
import { type AvmContractCallResults } from '../avm_message_call_result.js';
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
import { Addressing } from './addressing_mode.js';
import { Instruction } from './instruction.js';
Expand Down Expand Up @@ -61,15 +67,27 @@ abstract class ExternalCall extends Instruction {
const totalGas = sumGas(this.gasCost(memoryOperations), allocatedGas);
context.machineState.consumeGas(totalGas);

// TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone.
const nestedContext = context.createNestedContractCallContext(
callAddress.toFr(),
calldata,
allocatedGas,
this.type,
FunctionSelector.fromField(functionSelector),
);
const pxContext = createPublicExecutionContext(nestedContext, calldata);
const pxResults = await executePublicFunction(pxContext, /*nested=*/ true);
const nestedCallResults: AvmContractCallResults = convertPublicExecutionResult(pxResults);
adjustAvmContextFromPublicExecutionResult(nestedContext, pxResults);
const nestedPersistableState = nestedContext.persistableState;
// const nestedContext = context.createNestedContractCallContext(
// callAddress.toFr(),
// calldata,
// FunctionSelector.fromField(functionSelector),
// );
// const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
// const nestedPersistableState = nestedContext.persistableState;

const nestedCallResults = await new AvmSimulator(nestedContext).execute();
const success = !nestedCallResults.reverted;

// We only take as much data as was specified in the return size and pad with zeroes if the return data is smaller
Expand All @@ -90,9 +108,9 @@ abstract class ExternalCall extends Instruction {

// TODO: Should we merge the changes from a nested call in the case of a STATIC call?
if (success) {
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
context.persistableState.acceptNestedCallState(nestedPersistableState);
} else {
context.persistableState.rejectNestedCallState(nestedContext.persistableState);
context.persistableState.rejectNestedCallState(nestedPersistableState);
}

memory.assert(memoryOperations);
Expand Down
Loading

0 comments on commit 1ca2df4

Please sign in to comment.