Skip to content

Commit

Permalink
load private tests and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
rahul-kothari committed Nov 6, 2023
1 parent a7354dc commit ca6a589
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 34 deletions.
51 changes: 51 additions & 0 deletions docs/docs/dev_docs/testing/cheat_codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ public async warp(to: number): Promise<void>
// Loads the value stored at the given slot in the public storage of the given contract.
public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise<Fr>

// Loads the value stored at the given slot in the private storage of the given contract.
public async loadPrivate(owner: AztecAddress, contract: AztecAddress, slot: Fr | bigint): Promise<Note[]>

// Computes the slot value for a given map and key.
public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr
```
Expand Down Expand Up @@ -519,6 +522,54 @@ const slot = cc.aztec.computeSlotInMap(1n, key);
const value = await cc.aztec.loadPublic(address, slot);
```

### loadPrivate

#### Function Signature

```ts
public async loadPrivate(owner: AztecAddress, contract: AztecAddress, slot: Fr | bigint): Promise<Note[]>
```

#### Description

Loads the value stored at the given slot in the private storage of the given contract.

Note: One Field element occupies a storage slot. Hence, structs with multiple field elements will be spread over multiple sequential slots. Using loadPublic will only load a single field of the struct (depending on the size of the attributes within it).

#### Example
```rust

notes: Map::new(
context,
1, // Storage slot
|context, slot| {
Set::new(context, slot, ValueNoteMethods)
},
),

struct Storage {
...
balances: Map<Set<ValueNote, VALUE_NOTE_LEN>>,
}

impl Storage {
fn init() -> Self {
Storage {
...
balances: Map::new(context, 3, |context, slot| {
Set::new(context, slot, ValueNoteMethods)
}),
}
}
}

contract Token {
...
}
```

#include_code load_private_cheatcode yarn-project/end-to-end/src/e2e_cheat_codes.test.ts bash

## Participate

Keep up with the latest discussion and join the conversation in the [Aztec forum](https://discourse.aztec.network).
Expand Down
136 changes: 102 additions & 34 deletions yarn-project/end-to-end/src/e2e_cheat_codes.test.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,51 @@
import { CheatCodes, EthAddress, TxStatus, Wallet } from '@aztec/aztec.js';
import {
AztecAddress,
CheatCodes,
CompleteAddress,
EthAddress,
ExtendedNote,
Fr,
Note,
PXE,
TxStatus,
Wallet,
computeMessageSecretHash,
} from '@aztec/aztec.js';
import { RollupAbi } from '@aztec/l1-artifacts';
import { TestContract } from '@aztec/noir-contracts/types';
import { TestContract, TokenContract } from '@aztec/noir-contracts/types';

import { Account, Chain, HttpTransport, PublicClient, WalletClient, getAddress, getContract, parseEther } from 'viem';

import { setup } from './fixtures/utils.js';

describe('e2e_cheat_codes', () => {
let wallet: Wallet;
let admin: CompleteAddress;
let cc: CheatCodes;
let pxe: PXE;
let teardown: () => Promise<void>;

let walletClient: WalletClient<HttpTransport, Chain, Account>;
let publicClient: PublicClient<HttpTransport, Chain>;
let rollupAddress: EthAddress;
let token: TokenContract;

beforeAll(async () => {
let deployL1ContractsValues;
({ teardown, wallet, cheatCodes: cc, deployL1ContractsValues } = await setup());
let accounts;
({ teardown, wallet, accounts, cheatCodes: cc, deployL1ContractsValues, pxe } = await setup());

walletClient = deployL1ContractsValues.walletClient;
publicClient = deployL1ContractsValues.publicClient;
rollupAddress = deployL1ContractsValues.l1ContractAddresses.rollupAddress;
admin = accounts[0];

token = await TokenContract.deploy(wallet, admin).send().deployed();
}, 100_000);

afterAll(() => teardown());

describe('L1 only', () => {
describe('L1 cheatcodes', () => {
describe('mine', () => {
it(`mine block`, async () => {
const blockNumber = await cc.eth.blockNumber();
Expand Down Expand Up @@ -129,39 +148,88 @@ describe('e2e_cheat_codes', () => {
expect(e.message).toContain('No Signer available');
}
});
});

it('can modify L2 block time', async () => {
const contract = await TestContract.deploy(wallet).send().deployed();
describe('L2 cheatcodes', () => {
describe('warp L2 Block Time', () => {
it('can modify L2 block time', async () => {
const contract = await TestContract.deploy(wallet).send().deployed();

// now update time:
const timestamp = await cc.eth.timestamp();
const newTimestamp = timestamp + 100_000_000;
await cc.aztec.warp(newTimestamp);

// ensure rollup contract is correctly updated
const rollup = getContract({ address: getAddress(rollupAddress.toString()), abi: RollupAbi, publicClient });
expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp);
expect(Number(await rollup.read.lastWarpedBlockTs())).toEqual(newTimestamp);

const txIsTimeEqual = contract.methods.is_time_equal(newTimestamp).send();
const isTimeEqualReceipt = await txIsTimeEqual.wait({ interval: 0.1 });
expect(isTimeEqualReceipt.status).toBe(TxStatus.MINED);

// Since last rollup block was warped, txs for this rollup will have time incremented by 1
// See https://github.com/AztecProtocol/aztec-packages/issues/1614 for details
const txTimeNotEqual = contract.methods.is_time_equal(newTimestamp + 1).send();
const isTimeNotEqualReceipt = await txTimeNotEqual.wait({ interval: 0.1 });
expect(isTimeNotEqualReceipt.status).toBe(TxStatus.MINED);
// block is published at t >= newTimestamp + 1.
expect(Number(await rollup.read.lastBlockTs())).toBeGreaterThanOrEqual(newTimestamp + 1);
}, 50_000);

it('should throw if setting L2 block time to a past timestamp', async () => {
const timestamp = await cc.eth.timestamp();
const pastTimestamp = timestamp - 1000;
await expect(async () => await cc.aztec.warp(pastTimestamp)).rejects.toThrow(
`Error setting next block timestamp: Timestamp error: ${pastTimestamp} is lower than or equal to previous block's timestamp`,
);
});
});

// now update time:
const timestamp = await cc.eth.timestamp();
const newTimestamp = timestamp + 100_000_000;
await cc.aztec.warp(newTimestamp);

// ensure rollup contract is correctly updated
const rollup = getContract({ address: getAddress(rollupAddress.toString()), abi: RollupAbi, publicClient });
expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp);
expect(Number(await rollup.read.lastWarpedBlockTs())).toEqual(newTimestamp);

const txIsTimeEqual = contract.methods.is_time_equal(newTimestamp).send();
const isTimeEqualReceipt = await txIsTimeEqual.wait({ interval: 0.1 });
expect(isTimeEqualReceipt.status).toBe(TxStatus.MINED);

// Since last rollup block was warped, txs for this rollup will have time incremented by 1
// See https://github.com/AztecProtocol/aztec-packages/issues/1614 for details
const txTimeNotEqual = contract.methods.is_time_equal(newTimestamp + 1).send();
const isTimeNotEqualReceipt = await txTimeNotEqual.wait({ interval: 0.1 });
expect(isTimeNotEqualReceipt.status).toBe(TxStatus.MINED);
// block is published at t >= newTimestamp + 1.
expect(Number(await rollup.read.lastBlockTs())).toBeGreaterThanOrEqual(newTimestamp + 1);
}, 50_000);
it('load public', async () => {
expect(AztecAddress.fromField(await cc.aztec.loadPublic(token.address, 1n))).toBe(admin.address);
});

it('should throw if setting L2 block time to a past timestamp', async () => {
const timestamp = await cc.eth.timestamp();
const pastTimestamp = timestamp - 1000;
await expect(async () => await cc.aztec.warp(pastTimestamp)).rejects.toThrow(
`Error setting next block timestamp: Timestamp error: ${pastTimestamp} is lower than or equal to previous block's timestamp`,
);
it('load public returns 0 for non existent value', async () => {
const storageSlot = Fr.random();
expect(await cc.aztec.loadPublic(token.address, storageSlot)).toBe(0n);
});

it('load private works as expected for no notes', async () => {
const notes = await cc.aztec.loadPrivate(admin.address, token.address, 5n);
const values = notes.map(note => note.items[0]);
const balance = values.reduce((sum, current) => sum + current.toBigInt(), 0n);
expect(balance).toEqual(0n);
});

it('load private', async () => {
// mint note and redeem.
const mintAmount = 100n;
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait();

const note = new Note([new Fr(mintAmount), secretHash]);
const pendingShieldStorageSlot = new Fr(5n);
const extendedNote = new ExtendedNote(
note,
admin.address,
token.address,
pendingShieldStorageSlot,
receipt.txHash,
);
await pxe.addNote(extendedNote);
await token.methods.redeem_shield(admin.address, mintAmount, secret).send().wait();

// docs:start:load_private_cheatcode
const privateBalanceBaseStorageSlot = 3n;
const ownerSlot = cc.aztec.computeSlotInMap(privateBalanceBaseStorageSlot, admin.address);
const notes = await cc.aztec.loadPrivate(admin.address, token.address, ownerSlot);
const values = notes.map(note => note.items[0]);
const balance = values.reduce((sum, current) => sum + current.toBigInt(), 0n);
expect(balance).toEqual(mintAmount);
// docs:end:load_private_cheatcode
}, 50_000);
});
});

0 comments on commit ca6a589

Please sign in to comment.