Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use dep::protocol_types::address::AztecAddress;
use dep::protocol_types::{address::AztecAddress, traits::Deserialize};
use crate::oracle::storage::{raw_storage_read, storage_read};

struct UnconstrainedContext {
block_number: u32,
Expand Down Expand Up @@ -35,6 +36,14 @@ impl UnconstrainedContext {
fn chain_id(self) -> Field {
self.chain_id
}

unconstrained fn raw_storage_read<N>(self: Self, storage_slot: Field) -> [Field; N] {
storage_read(self.this_address(), storage_slot, self.block_number())
}

unconstrained fn storage_read<T, N>(self, storage_slot: Field) -> T where T: Deserialize<N> {
T::deserialize(self.raw_storage_read(storage_slot))
}
}

#[oracle(getContractAddress)]
Expand Down
42 changes: 29 additions & 13 deletions noir-projects/aztec-nr/aztec/src/oracle/storage.nr
Original file line number Diff line number Diff line change
@@ -1,42 +1,58 @@
use dep::protocol_types::traits::Deserialize;
use dep::protocol_types::{address::AztecAddress, traits::Deserialize};

#[oracle(storageRead)]
unconstrained fn storage_read_oracle<N>(storage_slot: Field, length: Field) -> [Field; N] {}

unconstrained pub fn raw_storage_read<N>(storage_slot: Field) -> [Field; N] {
storage_read_oracle(storage_slot, N)
unconstrained fn storage_read_oracle<N>(
address: Field,
storage_slot: Field,
block_number: Field,
length: Field
) -> [Field; N] {}

unconstrained pub fn raw_storage_read<N>(
address: AztecAddress,
storage_slot: Field,
block_number: u32
) -> [Field; N] {
storage_read_oracle(address.to_field(), storage_slot, block_number as Field, N)
}

unconstrained pub fn storage_read<T, N>(storage_slot: Field) -> T where T: Deserialize<N> {
T::deserialize(raw_storage_read(storage_slot))
unconstrained pub fn storage_read<T, N>(
address: AztecAddress,
storage_slot: Field,
block_number: u32
) -> T where T: Deserialize<N> {
T::deserialize(raw_storage_read(address, storage_slot, block_number))
}

mod tests {
use crate::oracle::storage::{raw_storage_read, storage_read};
use dep::protocol_types::address::AztecAddress;

use std::test::OracleMock;
use crate::test::mocks::mock_struct::MockStruct;

global address = AztecAddress::from_field(29);
global slot = 7;
global block_number = 17;

#[test]
fn test_raw_storage_read() {
let slot = 7;
let written = MockStruct { a: 13, b: 42 };

let _ = OracleMock::mock("storageRead").with_params((slot, 2)).returns(written.serialize());
let _ = OracleMock::mock("storageRead").returns(written.serialize());

let read: [Field; 2] = raw_storage_read(slot);
let read: [Field; 2] = raw_storage_read(address, slot, block_number);
assert_eq(read[0], 13);
assert_eq(read[1], 42);
}

#[test]
fn test_storage_read() {
let slot = 7;
let written = MockStruct { a: 13, b: 42 };

let _ = OracleMock::mock("storageRead").with_params((slot, 2)).returns(written.serialize());
let _ = OracleMock::mock("storageRead").returns(written.serialize());

let read: MockStruct = storage_read(slot);
let read: MockStruct = storage_read(address, slot, block_number);
assert_eq(read.a, 13);
assert_eq(read.b, 42);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ impl <T> PublicImmutable<T, &mut PublicContext> {

impl<T> PublicImmutable<T, UnconstrainedContext> {
unconstrained pub fn read<T_SERIALIZED_LEN>(self) -> T where T: Deserialize<T_SERIALIZED_LEN> {
storage_read(self.storage_slot)
self.context.storage_read(self.storage_slot)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ impl<T> PublicMutable<T, &mut PublicContext> {

impl<T> PublicMutable<T, UnconstrainedContext> {
unconstrained pub fn read<T_SERIALIZED_LEN>(self) -> T where T: Deserialize<T_SERIALIZED_LEN> {
storage_read(self.storage_slot)
self.context.storage_read(self.storage_slot)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<T> SharedImmutable<T, &mut PublicContext> {

impl<T> SharedImmutable<T, UnconstrainedContext> {
unconstrained pub fn read_public<T_SERIALIZED_LEN>(self) -> T where T: Deserialize<T_SERIALIZED_LEN> {
storage_read(self.storage_slot)
self.context.storage_read(self.storage_slot)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ pub fn setup_and_mint(with_account_contracts: bool) -> (&mut TestEnvironment, Az
pub fn check_public_balance(token_contract_address: AztecAddress, address: AztecAddress, address_amount: Field) {
let current_contract_address = cheatcodes::get_contract_address();
cheatcodes::set_contract_address(token_contract_address);
let block_number = cheatcodes::get_block_number();

let balances_slot = Token::storage().public_balances.slot;
let address_slot = derive_storage_slot_in_map(balances_slot, address);
let amount: U128 = storage_read(address_slot);
let amount: U128 = storage_read(token_contract_address, address_slot, block_number);
assert(amount.to_field() == address_amount, "Public balance is not correct");
cheatcodes::set_contract_address(current_contract_address);
}
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,11 @@ export class AztecNodeService implements AztecNode {
*
* @param contract - Address of the contract to query.
* @param slot - Slot to query.
* @param blockNumber - The block number at which to get the data or 'latest'.
* @returns Storage value at the given contract slot.
*/
public async getPublicStorageAt(contract: AztecAddress, slot: Fr): Promise<Fr> {
const committedDb = await this.#getWorldState('latest');
public async getPublicStorageAt(contract: AztecAddress, slot: Fr, blockNumber: L2BlockNumber): Promise<Fr> {
const committedDb = await this.#getWorldState(blockNumber);
const leafSlot = computePublicDataTreeLeafSlot(contract, slot);

const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/circuit-types/src/interfaces/aztec-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,10 @@ export interface AztecNode {
*
* @param contract - Address of the contract to query.
* @param slot - Slot to query.
* @param blockNumber - The block number at which to get the data or 'latest'.
* @returns Storage value at the given contract slot.
*/
getPublicStorageAt(contract: AztecAddress, slot: Fr): Promise<Fr>;
getPublicStorageAt(contract: AztecAddress, slot: Fr, blockNumber: L2BlockNumber): Promise<Fr>;

/**
* Returns the currently committed block header.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('benchmarks/process_history', () => {
const node = await AztecNodeService.createAndSync(nodeConfig);
// call getPublicStorageAt (which calls #getWorldState, which calls #syncWorldState) to force a sync with
// world state to ensure the node has caught up
await node.getPublicStorageAt(AztecAddress.random(), Fr.random());
await node.getPublicStorageAt(AztecAddress.random(), Fr.random(), 'latest');
return node;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('benchmarks/publish_rollup', () => {
// world state to ensure the node has caught up
context.logger.info(`Starting new aztec node`);
const node = await AztecNodeService.createAndSync({ ...context.config, disableSequencer: true });
await node.getPublicStorageAt(AztecAddress.random(), Fr.random());
await node.getPublicStorageAt(AztecAddress.random(), Fr.random(), 'latest');

// Spin up a new pxe and sync it, we'll use it to test sync times of new accounts for the last block
context.logger.info(`Starting new pxe`);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/noir-contracts.js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@
"engines": {
"node": ">=18"
}
}
}
2 changes: 1 addition & 1 deletion yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export class PXEService implements PXE {
if (!(await this.getContractInstance(contract))) {
throw new Error(`Contract ${contract.toString()} is not deployed`);
}
return await this.node.getPublicStorageAt(contract, slot);
return await this.node.getPublicStorageAt(contract, slot, 'latest');
}

public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
Expand Down
14 changes: 12 additions & 2 deletions yarn-project/simulator/src/acvm/oracle/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,18 @@ export class Oracle {
return message.toFields().map(toACVMField);
}

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

Expand Down
7 changes: 6 additions & 1 deletion yarn-project/simulator/src/acvm/oracle/typed_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,12 @@ export abstract class TypedOracle {
throw new OracleMethodNotAvailableError('getL1ToL2MembershipWitness');
}

storageRead(_startStorageSlot: Fr, _numberOfElements: number): Promise<Fr[]> {
storageRead(
_contractAddress: Fr,
_startStorageSlot: Fr,
_blockNumber: number,
_numberOfElements: number,
): Promise<Fr[]> {
throw new OracleMethodNotAvailableError('storageRead');
}

Expand Down
15 changes: 12 additions & 3 deletions yarn-project/simulator/src/client/client_execution_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -678,16 +678,25 @@ export class ClientExecutionContext extends ViewDataOracle {

/**
* Read the public storage data.
* @param contractAddress - The address to read storage from.
* @param startStorageSlot - The starting storage slot.
* @param blockNumber - The block number to read storage at.
* @param numberOfElements - Number of elements to read from the starting storage slot.
*/
public override async storageRead(startStorageSlot: Fr, numberOfElements: number): Promise<Fr[]> {
public override async storageRead(
contractAddress: Fr,
startStorageSlot: Fr,
blockNumber: number,
numberOfElements: number,
): Promise<Fr[]> {
const values = [];
for (let i = 0n; i < numberOfElements; i++) {
const storageSlot = new Fr(startStorageSlot.value + i);

const value = await this.aztecNode.getPublicStorageAt(this.callContext.storageContractAddress, storageSlot);
this.log.debug(`Oracle storage read: slot=${storageSlot.toString()} value=${value}`);
const value = await this.aztecNode.getPublicStorageAt(contractAddress, storageSlot, blockNumber);
this.log.debug(
`Oracle storage read: slot=${storageSlot.toString()} address-${contractAddress.toString()} value=${value}`,
);

values.push(value);
}
Expand Down
15 changes: 12 additions & 3 deletions yarn-project/simulator/src/client/view_data_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,25 @@ export class ViewDataOracle extends TypedOracle {

/**
* Read the public storage data.
* @param contractAddress - The address to read storage from.
* @param startStorageSlot - The starting storage slot.
* @param blockNumber - The block number to read storage at.
* @param numberOfElements - Number of elements to read from the starting storage slot.
*/
public override async storageRead(startStorageSlot: Fr, numberOfElements: number) {
public override async storageRead(
contractAddress: Fr,
startStorageSlot: Fr,
blockNumber: number,
numberOfElements: number,
) {
const values = [];
for (let i = 0n; i < numberOfElements; i++) {
const storageSlot = new Fr(startStorageSlot.value + i);
const value = await this.aztecNode.getPublicStorageAt(this.contractAddress, storageSlot);
const value = await this.aztecNode.getPublicStorageAt(contractAddress, storageSlot, blockNumber);

this.log.debug(`Oracle storage read: slot=${storageSlot.toString()} value=${value}`);
this.log.debug(
`Oracle storage read: slot=${storageSlot.toString()} address-${contractAddress.toString()} value=${value}`,
);
values.push(value);
}
return values;
Expand Down
9 changes: 7 additions & 2 deletions yarn-project/txe/src/oracle/txe_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,13 +434,18 @@ export class TXE implements TypedOracle {
throw new Error('Method not implemented.');
}

async storageRead(startStorageSlot: Fr, numberOfElements: number): Promise<Fr[]> {
async storageRead(
contractAddress: Fr,
startStorageSlot: Fr,
blockNumber: number, // TODO(#7230): use block number
numberOfElements: number,
): Promise<Fr[]> {
const db = this.trees.asLatest();

const values = [];
for (let i = 0n; i < numberOfElements; i++) {
const storageSlot = startStorageSlot.add(new Fr(i));
const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, storageSlot).toBigInt();
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, storageSlot).toBigInt();

const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);

Expand Down
9 changes: 8 additions & 1 deletion yarn-project/txe/src/txe_service/txe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,16 @@ export class TXEService {
return toForeignCallResult([]);
}

async storageRead(startStorageSlot: ForeignCallSingle, numberOfElements: ForeignCallSingle) {
async storageRead(
contractAddress: ForeignCallSingle,
startStorageSlot: ForeignCallSingle,
blockNumber: ForeignCallSingle,
numberOfElements: ForeignCallSingle,
) {
const values = await this.typedOracle.storageRead(
fromSingle(contractAddress),
fromSingle(startStorageSlot),
fromSingle(blockNumber).toNumber(),
fromSingle(numberOfElements).toNumber(),
);
return toForeignCallResult([toArray(values)]);
Expand Down