Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 13 additions & 20 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,38 +890,35 @@ fn handle_black_box_function(avm_instrs: &mut Vec<AvmInstruction>, operation: &B
),
}
}

/// Emit a storage write opcode
/// The current implementation writes an array of values into storage ( contiguous slots in memory )
fn handle_storage_write(
avm_instrs: &mut Vec<AvmInstruction>,
destinations: &Vec<ValueOrArray>,
inputs: &Vec<ValueOrArray>,
) {
assert!(inputs.len() == 2);
assert!(destinations.len() == 1);
assert!(destinations.is_empty());

let slot_offset_maybe = inputs[0];
let slot_offset = match slot_offset_maybe {
ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0,
_ => panic!("ForeignCall address destination should be a single value"),
_ => panic!("Storage write address destination should be a single value"),
};

let src_offset_maybe = inputs[1];
let (src_offset, src_size) = match src_offset_maybe {
ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size),
_ => panic!("Storage write address inputs should be an array of values"),
let src_offset = match src_offset_maybe {
ValueOrArray::MemoryAddress(offset) => offset.0,
_ => panic!("Storage write address inputs should be a single value"),
};

avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::SSTORE,
indirect: Some(ZEROTH_OPERAND_INDIRECT),
indirect: Some(ALL_DIRECT),
operands: vec![
AvmOperand::U32 {
value: src_offset as u32,
},
AvmOperand::U32 {
value: src_size as u32,
},
AvmOperand::U32 {
value: slot_offset as u32,
},
Expand All @@ -937,32 +934,28 @@ fn handle_storage_read(
destinations: &Vec<ValueOrArray>,
inputs: &Vec<ValueOrArray>,
) {
// For the foreign calls we want to handle, we do not want inputs, as they are getters
assert!(inputs.len() == 2); // output, len - but we dont use this len - its for the oracle
assert!(inputs.len() == 1);
assert!(destinations.len() == 1);

let slot_offset_maybe = inputs[0];
let slot_offset = match slot_offset_maybe {
ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0,
_ => panic!("ForeignCall address destination should be a single value"),
_ => panic!("Storage read address destination should be a single value"),
};

let dest_offset_maybe = destinations[0];
let (dest_offset, src_size) = match dest_offset_maybe {
ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size),
_ => panic!("Storage write address inputs should be an array of values"),
let dest_offset = match dest_offset_maybe {
ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0,
_ => panic!("Storage read address inputs should be a single value"),
};

avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::SLOAD,
indirect: Some(SECOND_OPERAND_INDIRECT),
indirect: Some(ALL_DIRECT),
operands: vec![
AvmOperand::U32 {
value: slot_offset as u32,
},
AvmOperand::U32 {
value: src_size as u32,
},
AvmOperand::U32 {
value: dest_offset as u32,
},
Expand Down
24 changes: 17 additions & 7 deletions noir-projects/aztec-nr/aztec/src/oracle/storage.nr
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
use dep::protocol_types::traits::{Deserialize, Serialize};

#[oracle(storageRead)]
fn storage_read_oracle<N>(_storage_slot: Field, _number_of_elements: Field) -> [Field; N] {}
fn storage_read_oracle(_storage_slot: Field) -> Field {}

unconstrained fn storage_read_oracle_wrapper<N>(_storage_slot: Field) -> [Field; N] {
storage_read_oracle(_storage_slot, N)
unconstrained fn storage_read_oracle_wrapper(storage_slot: Field) -> Field {
storage_read_oracle(storage_slot)
}

pub fn storage_read<N>(storage_slot: Field) -> [Field; N] {
storage_read_oracle_wrapper(storage_slot)
let mut ret: [Field; N] = [0; N];
for i in 0..N {
ret[i] = storage_read_oracle_wrapper(storage_slot + (i as Field));
}
ret
}

#[oracle(storageWrite)]
fn storage_write_oracle<N>(_storage_slot: Field, _values: [Field; N]) -> [Field; N] {}
fn storage_write_oracle(_storage_slot: Field, _value: Field) {}

unconstrained pub fn storage_write<N>(storage_slot: Field, fields: [Field; N]) {
let _hash = storage_write_oracle(storage_slot, fields);
unconstrained fn storage_write_oracle_wrapper(storage_slot: Field, value: Field) {
storage_write_oracle(storage_slot, value);
}

pub fn storage_write<N>(storage_slot: Field, fields: [Field; N]) {
for i in 0..N {
storage_write_oracle_wrapper(storage_slot + (i as Field), fields[i]);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
use dep::aztec::protocol_types::traits::{Serialize, Deserialize};

struct Note {
a: Field,
b: Field,
}

impl Serialize<2> for Note {
fn serialize(self) -> [Field; 2] {
[self.a, self.b]
}
}

impl Deserialize<2> for Note {
fn deserialize(wire: [Field; 2]) -> Note {
Note {a: wire[0], b: wire[1]}
}
}

contract AvmTest {
use crate::Note;

// Libs
use dep::aztec::state_vars::PublicMutable;
use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH};
Expand All @@ -12,18 +33,35 @@ contract AvmTest {
fn constructor() {}

struct Storage {
owner: PublicMutable<AztecAddress>
single: PublicMutable<Field>,
list: PublicMutable<Note>,
}

#[aztec(public-vm)]
fn setStorageSingle(a: Field) {
storage.single.write(a);
}

#[aztec(public-vm)]
fn readStorageSingle() -> pub Field {
storage.single.read()
}

#[aztec(public-vm)]
fn setReadStorageSingle(a: Field) -> pub Field {
storage.single.write(a);
storage.single.read()
}

#[aztec(public-vm)]
fn setAdmin() {
storage.owner.write(context.sender());
fn setStorageList(a: Field, b: Field) {
storage.list.write(Note { a, b });
}

#[aztec(public-vm)]
fn setAndRead() -> pub AztecAddress {
storage.owner.write(context.sender());
storage.owner.read()
fn readStorageList() -> pub [Field; 2] {
let note: Note = storage.list.read();
note.serialize()
}

#[aztec(public-vm)]
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

exports[`GasToken returns canonical protocol contract 1`] = `
{
"address": AztecAddress<0x01ffec73ac535628f98088b70f766f47989801a0dfc754cf4996f505cfd8f082>,
"address": AztecAddress<0x0b990cd3da37d6d83cd1dc2cca06ee3cae22877ec9040b817c9ce3ae47634683>,
"instance": {
"address": AztecAddress<0x01ffec73ac535628f98088b70f766f47989801a0dfc754cf4996f505cfd8f082>,
"contractClassId": Fr<0x2c32fd0ebccda2e20057f37fa2e6085c07d9a1236a72a54f58c724418f7b4438>,
"address": AztecAddress<0x0b990cd3da37d6d83cd1dc2cca06ee3cae22877ec9040b817c9ce3ae47634683>,
"contractClassId": Fr<0x136acc115d2b9c3acc18236bb2b72077c0cd855963de8c24f27c3c69120385c9>,
"initializationHash": Fr<0x0bf6e812f14bb029f7cb9c8da8367dd97c068e788d4f21007fd97014eba8cf9f>,
"portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>,
"publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>,
Expand All @@ -18,7 +18,7 @@ exports[`GasToken returns canonical protocol contract 1`] = `
exports[`GasToken returns canonical protocol contract 2`] = `
{
"artifactHash": Fr<0x076fb6d7493b075a880eeed90fec7c4c01e0a24d442522449e4d56c26357205f>,
"id": Fr<0x2c32fd0ebccda2e20057f37fa2e6085c07d9a1236a72a54f58c724418f7b4438>,
"id": Fr<0x136acc115d2b9c3acc18236bb2b72077c0cd855963de8c24f27c3c69120385c9>,
"privateFunctions": [
{
"isInternal": false,
Expand All @@ -27,7 +27,7 @@ exports[`GasToken returns canonical protocol contract 2`] = `
},
],
"privateFunctionsRoot": Fr<0x13b29c3f4a96eb14d5d3539a6308ff9736ad5d67e3f61ffbb7da908e14980828>,
"publicBytecodeCommitment": Fr<0x1c5e1c199e3affad8f3d3ec7db3e3b40639b3c0ef82351506ceb25cde3b04924>,
"publicBytecodeCommitment": Fr<0x1db9d13c128a3c6f7d736161ca3cfeb78b19e5018c3765e90c760aedc7959e26>,
"version": 1,
}
`;
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/simulator/src/acvm/acvm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ORACLE_NAMES } from './oracle/index.js';
*/
type ACIRCallback = Record<
ORACLE_NAMES,
(...args: ForeignCallInput[]) => ForeignCallOutput | Promise<ForeignCallOutput>
(...args: ForeignCallInput[]) => ForeignCallOutput | Promise<ForeignCallOutput> | Promise<void>
>;

/**
Expand Down Expand Up @@ -102,7 +102,8 @@ export async function acvm(
}

const result = await oracleFunction.call(callback, ...args);
return [result];
// void functions return undefined, which is mapped to an empty array.
return result === undefined ? [] : [result];
} catch (err) {
let typedError: Error;
if (err instanceof Error) {
Expand Down
11 changes: 5 additions & 6 deletions yarn-project/simulator/src/acvm/oracle/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,13 @@ export class Oracle {
return toACVMField(portalContactAddress);
}

async storageRead([startStorageSlot]: ACVMField[], [numberOfElements]: ACVMField[]): Promise<ACVMField[]> {
const values = await this.typedOracle.storageRead(fromACVMField(startStorageSlot), +numberOfElements);
return values.map(toACVMField);
async storageRead([storageSlot]: ACVMField[]): Promise<ACVMField> {
const value = await this.typedOracle.storageRead(fromACVMField(storageSlot));
return toACVMField(value);
}

async storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]): Promise<ACVMField[]> {
const newValues = await this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField));
return newValues.map(toACVMField);
async storageWrite([storageSlot]: ACVMField[], [value]: ACVMField[]): Promise<void> {
await this.typedOracle.storageWrite(fromACVMField(storageSlot), fromACVMField(value));
}

emitEncryptedLog(
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/simulator/src/acvm/oracle/typed_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,11 @@ export abstract class TypedOracle {
throw new Error('Not available.');
}

storageRead(_startStorageSlot: Fr, _numberOfElements: number): Promise<Fr[]> {
storageRead(_storageSlot: Fr): Promise<Fr> {
throw new Error('Not available.');
}

storageWrite(_startStorageSlot: Fr, _values: Fr[]): Promise<Fr[]> {
storageWrite(_storageSlot: Fr, _value: Fr): Promise<void> {
throw new Error('Not available.');
}

Expand Down
Loading