From bda3737e7d6d282f707525d4d25f35551524e66a Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Wed, 16 Aug 2023 11:28:11 +0000 Subject: [PATCH 1/9] add cheatcode docs --- docs/docs/dev_docs/testing/cheat_codes.md | 449 ++++++++++++++++++++++ 1 file changed, 449 insertions(+) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index e69de29bb2d..92765a467b2 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -0,0 +1,449 @@ +--- +title: Testing Cheat Codes +--- + +## Introduction + +Most of the time, simply testing your smart contract isn't enough. To manipulate the state of the Aztec blockchain, as well as test for specific reverts and events, the sandbox is shipped with a set of cheatcodes. + +Cheatcodes allow you to change the time of the L2 block, load certain state or more easily manipulate L1 instead of having to write dedicated RPC calls to anvil. + +:::info Prerequisites +If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recommend reading up on that since Aztec Sandbox uses Anvil as the local L1 instance. +::: + +### Aims + +The guide will cover how to manipulate the state of the: +- L1 blockchain +- Aztec network. +### Why is this useful? + + + +### Dependencies + +For this guide, the following Aztec packages are used: +- @aztec/aztec.js + +### Initialisation +```js +import { createAztecRpcClient, CheatCodes } from '@aztec/aztec.js'; +const aztecRpcUrl = 'http://localhost:8080'; +const aztecRpcClient = createAztecRpcClient(aztecRpcUrl); +const cc = CheatCodes.create(aztecRpcUrl, aztecRpcClient); +``` + +There are two properties of the CheatCodes class - `l1` and `l2` for cheatcodes relating to the L1 and L2 (Aztec) respectively. + +## L1 related cheatcodes +These are cheatcodes exposed from anvil. But instead of having to know the right RPC calls to make and format the curl request appropirately, there are convenient wrappers exposed to developers. + +### Interface +``` +// Fetch current block number of L1 +public async blockNumber(): Promise + +// Fetch chain ID of L1 +public async chainId(): Promise + +// Fetch current timestamp on L1 +public async timestamp(): Promise + +// Mine a given number of blocks on L1. Mines 1 block by default +public async mine(numberOfBlocks = 1): Promise + +// Set the timestamp for the next block on L1. +public async setNextBlockTimestamp(timestamp: number): Promise + +// Dumps the current L1 chain state to a given file. Can be used with `loadChainState()` to first create a forked version of mainnet on anvil (to for example interact with uniswap), save the chain state to a file, and later load it to the sandbox' anvil instance. +public async dumpChainState(fileName: string): Promise + +// Loads the L1 chain state from a file. You may use `dumpChainState()` to save the state of the L1 chain to a file and later load it. +public async loadChainState(fileName: string): Promise + +// Load the value at a storage slot of a contract address on L1 +public async load(contract: EthAddress, slot: bigint): Promise + +// Set the value at a storage slot of a contract address on L1 (e.g. modify a storage variable on your portal contract or even the rollup contract). +public async store(contract: EthAddress, slot: bigint, value: bigint): Promise + +// Computes the slot value for a given map and key on L1. A convenient wrapper to find the appropriate storage slot to load or overwrite the state. +public keccak256(baseSlot: bigint, key: bigint): bigint + +// Send transactions on L1 impersonating an externally owned account or contract. +public async startPrank(who: EthAddress): Promise + +// Stop impersonating an account on L1 that you are currently impersonating. +public async stopPrank(who: EthAddress): Promise + +// Set the bytecode for a L1 contract +public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise + +// Get the bytecode for a L1 contract +public async getBytecode(contract: EthAddress): Promise<`0x${string}`> +``` + +### blockNumber + +#### Function Signature +```js +public async blockNumber(): Promise +``` + +#### Description +Fetches the current L1 block number + +#### Example +```js +const blockNumber = await cc.l1.blockNumber() +``` + +### chainId + +#### Function Signature +```js +public async chainId(): Promise +``` + +#### Description +Fetches the L1 chain ID + +#### Example +```js +const chainId = await cc.l1.chainId() +``` + +### timestamp + +#### Function Signature +```js +public async timestamp(): Promise +``` + +#### Description +Fetches the current L1 timestamp + +#### Example +```js +const timestamp = await cc.l1.timestamp() +``` + +### mine + +#### Function Signature +```js +public async mine(numberOfBlocks = 1): Promise +``` + +#### Description +Mines the specified number of blocks on L1 (default 1) + +#### Example +```js +const blockNum = await cc.l1.blockNumber(); +await cc.l1.mine(10) // mines 10 blocks +const newBlockNum = await cc.l1.blockNumber(); // = blockNum + 10. +``` + +### setNextBlockTimestamp + +#### Function Signature +```js +public async setNextBlockTimestamp(timestamp: number): Promise +``` + +#### Description +Sets the timestamp (unix format in seconds) for the next mined block on L1 +Remember that timestamp can only be set in the future and not in the past. + +#### Example +```js +await cc.l1.setNextBlockTimestamp(1692183270) // Set next block timestamp to 16 Aug 2023 10:54:30 GMT +// next transaction you will do will have the timestamp as 1692183270 +``` + +### dumpChainState + +#### Function Signature +```js +public async dumpChainState(fileName: string): Promise +``` + +#### Description +Dumps the current L1 chain state to a file +Returns a hex string representing the complete state of the chain. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. + +#### Example +```js +await cc.l1.dumpChainState('chain-state.json') +``` + +### loadChainState + +#### Function Signature +```js +public async loadChainState(fileName: string): Promise +``` + +#### Description +Loads the L1 chain state from a file. +When given a hex string previously returned by `cc.l1.dumpChainState()`, merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. + +#### Example +```js +await cc.l1.loadChainState('chain-state.json') +``` + +### load + +#### Function Signature +```js +public async load(contract: EthAddress, slot: bigint): Promise +``` + +#### Description +Loads the value at a storage slot of a L1 contract + +#### Example +``` +/// contract LeetContract { +/// uint256 private leet = 1337; // slot 0 +/// } + +const value = await cc.l1.load(EthAddress.from(leetContractAddress), BigInt(0)); +console.log(value); // 1337 +``` + +### store + +#### Function Signature +```js +public async store(contract: EthAddress, slot: bigint, value: bigint): Promise +``` + +#### Description +Stores the value in storage slot on a L1 contract + +#### Example +``` +/// contract LeetContract { +/// uint256 private leet = 1337; // slot 0 +/// } + +await cc.l1.store(EthAddress.from(leetContractAddress), BigInt(0), BigInt(1000)); +const value = await cc.l1.load(EthAddress.from(leetContractAddress), BigInt(0)); +console.log(value); // 1000 +``` + +### keccak256 + +#### Function Signature +```js +public keccak256(baseSlot: bigint, key: bigint): bigint +``` + +#### Description +Computes the storage slot for a map key + +#### Example +``` +/// contract LeetContract { +/// uint256 private leet = 1337; // slot 0 +/// mapping(address => uint256) public balances; // base slot 1 +/// } + +// find the storage slot for key `0xdead` in the balance map. +const address = BigInt('0x000000000000000000000000000000000000dead'); +const slot = cc.l1.keccak256(BigInt(1), key) +// store balance of 0xdead as 100 +await cc.l1.store(contractAddress, slot, 100n); +``` + +### startPrank + +#### Function Signature +```js +public async startPrank(who: EthAddress): Promise +``` + +#### Description +Start impersonating an L1 account +Sets msg.sender for all subsequent calls until stopPrank is called. + +#### Example +```js +await cc.l1.startPrank(EthAddress.fromString(address)); +``` + +### stopPrank + +#### Function Signature +```js +public async stopPrank(who: EthAddress): Promise +``` + +#### Description +Stop impersonating an L1 account +Stops an active prank started by startPrank, resetting msg.sender to the values before startPrank was called. + +#### Example +```js +await cc.l1.stopPrank(EthAddress.fromString(address)) +``` + +### getBytecode + +#### Function Signature +```js +public async getBytecode(contract: EthAddress): Promise<`0x${string}`> +``` + +#### Description +Get the bytecode for an L1 contract + +#### Example +```js +const bytecode = await cc.l1.getBytecode(contract) // 0x6080604052348015610010... +``` + +### etch + +#### Function Signature +```js +public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise +``` + +#### Description +Set the bytecode for an L1 contract + +#### Example +```js +const bytecode = `0x6080604052348015610010...` +await cc.l1.etch(contract, bytecode) +console.log(await cc.l1.getBytecode(contract)) // 0x6080604052348015610010... +``` + +## L2 related cheatcodes +These are cheatcodes specific to manipulating the state of Aztec rollup. + +### Interface +``` +// Get the current L2 block number +public async blockNumber(): Promise + +// Set time of the next execution on L2. It also modifies time on L1 for next execution and stores this time as the last rollup block on the rollup contract. +public async warp(to: number): Promise + +// 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 + +// Computes the slot value for a given map and key. +public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr +``` + +### blockNumber + +#### Function Signature +```js +public async blockNumber(): Promise +``` + +#### Description +Get the current L2 block number + +#### Example +```js +const blockNumber = await cc.l2.blockNumber() +``` + +### warp + +#### Function Signature +```js +public async warp(to: number): Promise +``` + +#### Description +Set time of the next execution on L2 and L1 for next execution. +Like with the corresponding L1 cheatcode, time can only be set in the future, not the past. + +#### Example +```js +const timestamp = await cc.l1.timestamp(); +const newTimestamp = timestamp + 100_000_000; +await cc.l2.warp(newTimestamp); + +// any noir contract calls that make use of current timestamp now will have `newTimestamp` +``` + +### loadPublic + +#### Function Signature +```js +public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise +``` + +#### Description +Loads the value stored at the given slot in the public storage of the given contract. + +#### Example +``` +/// struct Storage { +/// current_value: PublicState, +/// } +/// +/// impl Storage { +/// fn init() -> Self { +/// Storage { +/// current_value: PublicState::new(1, FieldSerialisationMethods), +/// } +/// } +/// } +/// +/// contract Hello { +/// ... +/// } + +const value = await cc.l2.loadPublic(contract, 1n) // current_value is stored in slot 1 +``` + +### computeSlotInMap + +#### Function Signature +```js +public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr +``` + +#### Description +Compute storage slot for a map key. +The baseSlot is specified in the noir contract. + +#### Example +``` +/// struct Storage { +/// balances: Map, +/// } +/// +/// impl Storage { +/// fn init() -> Self { +/// Storage { +/// balances: Map::new(1, |slot| EasyPrivateUint::new(slot)), +/// } +/// } +/// } +/// +/// contract Token { +/// ... +/// } + +const slot = cc.l2.computeSlotInMap(1n, key) +``` +## Participate + +Keep up with the latest discussion and join the conversation in the [Aztec forum](https://discourse.aztec.network). + +You can also use the above link to request for more cheatcodes. + +import Disclaimer from "../misc/common/\_disclaimer.mdx"; + \ No newline at end of file From 52ef038d39b360329cd578195d4c7ba73b36b113 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Thu, 17 Aug 2023 11:36:58 +0100 Subject: [PATCH 2/9] Apply suggestions from code review Co-authored-by: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> --- docs/docs/dev_docs/testing/cheat_codes.md | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index 92765a467b2..c2cbefc5a0f 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -1,5 +1,5 @@ --- -title: Testing Cheat Codes +title: Cheat Codes --- ## Introduction @@ -15,7 +15,7 @@ If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recom ### Aims The guide will cover how to manipulate the state of the: -- L1 blockchain +- L1 blockchain; - Aztec network. ### Why is this useful? @@ -31,13 +31,13 @@ For this guide, the following Aztec packages are used: import { createAztecRpcClient, CheatCodes } from '@aztec/aztec.js'; const aztecRpcUrl = 'http://localhost:8080'; const aztecRpcClient = createAztecRpcClient(aztecRpcUrl); -const cc = CheatCodes.create(aztecRpcUrl, aztecRpcClient); +const cc = await CheatCodes.create(aztecRpcUrl, aztecRpcClient); ``` There are two properties of the CheatCodes class - `l1` and `l2` for cheatcodes relating to the L1 and L2 (Aztec) respectively. ## L1 related cheatcodes -These are cheatcodes exposed from anvil. But instead of having to know the right RPC calls to make and format the curl request appropirately, there are convenient wrappers exposed to developers. +These are cheatcodes exposed from anvil conveniently wrapped for ease of use in the Sandbox. ### Interface ``` @@ -71,7 +71,7 @@ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise // Stop impersonating an account on L1 that you are currently impersonating. @@ -92,7 +92,7 @@ public async blockNumber(): Promise ``` #### Description -Fetches the current L1 block number +Fetches the current L1 block number. #### Example ```js @@ -122,7 +122,7 @@ public async timestamp(): Promise ``` #### Description -Fetches the current L1 timestamp +Fetches the current L1 timestamp. #### Example ```js @@ -137,7 +137,7 @@ public async mine(numberOfBlocks = 1): Promise ``` #### Description -Mines the specified number of blocks on L1 (default 1) +Mines the specified number of blocks on L1 (default 1). #### Example ```js @@ -154,7 +154,7 @@ public async setNextBlockTimestamp(timestamp: number): Promise ``` #### Description -Sets the timestamp (unix format in seconds) for the next mined block on L1 +Sets the timestamp (unix format in seconds) for the next mined block on L1. Remember that timestamp can only be set in the future and not in the past. #### Example @@ -171,7 +171,7 @@ public async dumpChainState(fileName: string): Promise ``` #### Description -Dumps the current L1 chain state to a file +Dumps the current L1 chain state to a file. Returns a hex string representing the complete state of the chain. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. #### Example @@ -203,7 +203,7 @@ public async load(contract: EthAddress, slot: bigint): Promise ``` #### Description -Loads the value at a storage slot of a L1 contract +Loads the value at a storage slot of a L1 contract. #### Example ``` @@ -223,7 +223,7 @@ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise ``` #### Description -Start impersonating an L1 account +Start impersonating an L1 account. Sets msg.sender for all subsequent calls until stopPrank is called. #### Example @@ -284,7 +284,7 @@ public async stopPrank(who: EthAddress): Promise ``` #### Description -Stop impersonating an L1 account +Stop impersonating an L1 account. Stops an active prank started by startPrank, resetting msg.sender to the values before startPrank was called. #### Example @@ -300,7 +300,7 @@ public async getBytecode(contract: EthAddress): Promise<`0x${string}`> ``` #### Description -Get the bytecode for an L1 contract +Get the bytecode for an L1 contract. #### Example ```js @@ -315,7 +315,7 @@ public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise ``` #### Description -Set the bytecode for an L1 contract +Set the bytecode for an L1 contract. #### Example ```js @@ -350,7 +350,7 @@ public async blockNumber(): Promise ``` #### Description -Get the current L2 block number +Get the current L2 block number. #### Example ```js @@ -365,7 +365,7 @@ public async warp(to: number): Promise ``` #### Description -Set time of the next execution on L2 and L1 for next execution. +Sets the time of L1 and the time of the next L2 block. Like with the corresponding L1 cheatcode, time can only be set in the future, not the past. #### Example @@ -374,7 +374,7 @@ const timestamp = await cc.l1.timestamp(); const newTimestamp = timestamp + 100_000_000; await cc.l2.warp(newTimestamp); -// any noir contract calls that make use of current timestamp now will have `newTimestamp` +// any noir contract calls that make use of current timestamp and is executed in the next rollup block will now read `newTimestamp` ``` ### loadPublic From d75aaec25a340da150219d58f8d9353b0ee4fdce Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Thu, 17 Aug 2023 15:19:44 +0000 Subject: [PATCH 3/9] prank->impersonate, add throw tests, respond to PR comments --- docs/docs/dev_docs/testing/cheat_codes.md | 85 ++++++++++--------- .../aztec.js/src/utils/cheat_codes.ts | 8 +- .../end-to-end/src/e2e_cheat_codes.test.ts | 22 ++++- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index c2cbefc5a0f..b5b403a549a 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -4,7 +4,7 @@ title: Cheat Codes ## Introduction -Most of the time, simply testing your smart contract isn't enough. To manipulate the state of the Aztec blockchain, as well as test for specific reverts and events, the sandbox is shipped with a set of cheatcodes. +To help with testing, the sandbox is shipped with a set of cheatcodes. Cheatcodes allow you to change the time of the L2 block, load certain state or more easily manipulate L1 instead of having to write dedicated RPC calls to anvil. @@ -17,9 +17,6 @@ If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recom The guide will cover how to manipulate the state of the: - L1 blockchain; - Aztec network. -### Why is this useful? - - ### Dependencies @@ -56,7 +53,7 @@ public async mine(numberOfBlocks = 1): Promise // Set the timestamp for the next block on L1. public async setNextBlockTimestamp(timestamp: number): Promise -// Dumps the current L1 chain state to a given file. Can be used with `loadChainState()` to first create a forked version of mainnet on anvil (to for example interact with uniswap), save the chain state to a file, and later load it to the sandbox' anvil instance. +// Dumps the current L1 chain state to a given file. public async dumpChainState(fileName: string): Promise // Loads the L1 chain state from a file. You may use `dumpChainState()` to save the state of the L1 chain to a file and later load it. @@ -72,10 +69,10 @@ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise +public async startImpersonating(who: EthAddress): Promise // Stop impersonating an account on L1 that you are currently impersonating. -public async stopPrank(who: EthAddress): Promise +public async stopImpersonating(who: EthAddress): Promise // Set the bytecode for a L1 contract public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise @@ -159,7 +156,8 @@ Remember that timestamp can only be set in the future and not in the past. #### Example ```js -await cc.l1.setNextBlockTimestamp(1692183270) // Set next block timestamp to 16 Aug 2023 10:54:30 GMT +// // Set next block timestamp to 16 Aug 2023 10:54:30 GMT +await cc.l1.setNextBlockTimestamp(1692183270) // next transaction you will do will have the timestamp as 1692183270 ``` @@ -172,7 +170,8 @@ public async dumpChainState(fileName: string): Promise #### Description Dumps the current L1 chain state to a file. -Returns a hex string representing the complete state of the chain. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. +Stores a hex string representing the complete state of the chain in a file with the provided path. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. +When combined with `loadChainState()` cheatcode, it can be let you easily import the current state of mainnet into the Anvil instance of the sandbox, to use Uniswap for example. #### Example ```js @@ -187,8 +186,8 @@ public async loadChainState(fileName: string): Promise ``` #### Description -Loads the L1 chain state from a file. -When given a hex string previously returned by `cc.l1.dumpChainState()`, merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. +Loads the L1 chain state from a file which contains a hex string representing an L1 state. +When given a file previously written to by `cc.l1.dumpChainState()`, it merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. #### Example ```js @@ -211,7 +210,8 @@ Loads the value at a storage slot of a L1 contract. /// uint256 private leet = 1337; // slot 0 /// } -const value = await cc.l1.load(EthAddress.from(leetContractAddress), BigInt(0)); +const leetContractAddress = EthAddress.fromString('0x1234...'); +const value = await cc.l1.load(leetContractAddress, BigInt(0)); console.log(value); // 1337 ``` @@ -231,8 +231,9 @@ Stores the value in storage slot on a L1 contract. /// uint256 private leet = 1337; // slot 0 /// } -await cc.l1.store(EthAddress.from(leetContractAddress), BigInt(0), BigInt(1000)); -const value = await cc.l1.load(EthAddress.from(leetContractAddress), BigInt(0)); +const leetContractAddress = EthAddress.fromString('0x1234...'); +await cc.l1.store(leetContractAddress, BigInt(0), BigInt(1000)); +const value = await cc.l1.load(leetContractAddress, BigInt(0)); console.log(value); // 1000 ``` @@ -260,36 +261,36 @@ const slot = cc.l1.keccak256(1n, address); await cc.l1.store(contractAddress, slot, 100n); ``` -### startPrank +### startImpersonating #### Function Signature ```js -public async startPrank(who: EthAddress): Promise +public async startImpersonating(who: EthAddress): Promise ``` #### Description Start impersonating an L1 account. -Sets msg.sender for all subsequent calls until stopPrank is called. +This allows you to use this address as a sender. #### Example ```js -await cc.l1.startPrank(EthAddress.fromString(address)); +await cc.l1.startImpersonating(EthAddress.fromString(address)); ``` -### stopPrank +### stopImpersonating #### Function Signature ```js -public async stopPrank(who: EthAddress): Promise +public async stopImpersonating(who: EthAddress): Promise ``` #### Description Stop impersonating an L1 account. -Stops an active prank started by startPrank, resetting msg.sender to the values before startPrank was called. +Stops an active impersonation started by startImpersonating. #### Example ```js -await cc.l1.stopPrank(EthAddress.fromString(address)) +await cc.l1.stopImpersonating(EthAddress.fromString(address)) ``` ### getBytecode @@ -377,67 +378,75 @@ await cc.l2.warp(newTimestamp); // any noir contract calls that make use of current timestamp and is executed in the next rollup block will now read `newTimestamp` ``` -### loadPublic +### computeSlotInMap #### Function Signature ```js -public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise +public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr ``` #### Description -Loads the value stored at the given slot in the public storage of the given contract. +Compute storage slot for a map key. +The baseSlot is specified in the noir contract. -#### Example +#### Example ``` /// struct Storage { -/// current_value: PublicState, +/// // highlight-next-line:PublicState +/// balances: Map>, /// } /// /// impl Storage { /// fn init() -> Self { /// Storage { -/// current_value: PublicState::new(1, FieldSerialisationMethods), +/// balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), /// } /// } /// } /// -/// contract Hello { +/// +/// contract Token { /// ... /// } -const value = await cc.l2.loadPublic(contract, 1n) // current_value is stored in slot 1 +const slot = cc.l2.computeSlotInMap(1n, key) ``` -### computeSlotInMap +### loadPublic #### Function Signature ```js -public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr +public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise ``` #### Description -Compute storage slot for a map key. -The baseSlot is specified in the noir contract. +Loads the value stored at the given slot in the public storage of the given contract. -#### Example +Note: One Field element occupies a storage slot. So structs with multiple field elements won't fit in a single slot. So using loadPublic would only load a part of the struct (depending on the size of the attributes within it). + +#### Example ``` /// struct Storage { -/// balances: Map, +/// // highlight-next-line:PublicState +/// balances: Map>, /// } /// /// impl Storage { /// fn init() -> Self { /// Storage { -/// balances: Map::new(1, |slot| EasyPrivateUint::new(slot)), +/// balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), /// } /// } /// } /// +/// /// contract Token { /// ... /// } +const address = AztecAddress.fromString("0x123...") const slot = cc.l2.computeSlotInMap(1n, key) +const value = await cc.l2.loadPublic(address, slot); ``` ## Participate @@ -445,5 +454,5 @@ Keep up with the latest discussion and join the conversation in the [Aztec forum You can also use the above link to request for more cheatcodes. -import Disclaimer from "../misc/common/\_disclaimer.mdx"; +import Disclaimer from "../../misc/common/\_disclaimer.mdx"; \ No newline at end of file diff --git a/yarn-project/aztec.js/src/utils/cheat_codes.ts b/yarn-project/aztec.js/src/utils/cheat_codes.ts index 07368e789c8..47dbee5d1af 100644 --- a/yarn-project/aztec.js/src/utils/cheat_codes.ts +++ b/yarn-project/aztec.js/src/utils/cheat_codes.ts @@ -169,9 +169,9 @@ export class L1CheatCodes { * Send transactions impersonating an externally owned account or contract. * @param who - The address to impersonate */ - public async startPrank(who: EthAddress): Promise { + public async startImpersonating(who: EthAddress): Promise { const res = await this.rpcCall('anvil_impersonateAccount', [who.toString()]); - if (res.error) throw new Error(`Error pranking ${who}: ${res.error.message}`); + if (res.error) throw new Error(`Error impersonating ${who}: ${res.error.message}`); this.logger(`Impersonating ${who}`); } @@ -179,9 +179,9 @@ export class L1CheatCodes { * Stop impersonating an account that you are currently impersonating. * @param who - The address to stop impersonating */ - public async stopPrank(who: EthAddress): Promise { + public async stopImpersonating(who: EthAddress): Promise { const res = await this.rpcCall('anvil_stopImpersonatingAccount', [who.toString()]); - if (res.error) throw new Error(`Error pranking ${who}: ${res.error.message}`); + if (res.error) throw new Error(`Error when stopping the impersonation of ${who}: ${res.error.message}`); this.logger(`Stopped impersonating ${who}`); } diff --git a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts index 38a9adb19dc..a55db9f0a57 100644 --- a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts +++ b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts @@ -66,6 +66,14 @@ describe('e2e_cheat_codes', () => { expect(await cc.l1.timestamp()).toBe(timestamp + increment); }); + it('setNextBlockTimestamp to a past timestamp throws', async () => { + const timestamp = await cc.l1.timestamp(); + const pastTimestamp = timestamp - 1000; + await expect(async () => await cc.l1.setNextBlockTimestamp(pastTimestamp)).rejects.toThrow( + `Error setting next block timestamp: Timestamp error: ${pastTimestamp} is lower than or equal to previous block's timestamp`, + ); + }); + it('load a value at a particular storage slot', async () => { // check that storage slot 0 is empty as expected const res = await cc.l1.load(EthAddress.ZERO, 0n); @@ -105,7 +113,7 @@ describe('e2e_cheat_codes', () => { const beforeBalance = await publicClient.getBalance({ address: randomAddress }); // impersonate random address - await cc.l1.startPrank(EthAddress.fromString(randomAddress)); + await cc.l1.startImpersonating(EthAddress.fromString(randomAddress)); // send funds from random address const amountToSend = parseEther('0.1'); const txHash = await walletClient.sendTransaction({ @@ -118,7 +126,7 @@ describe('e2e_cheat_codes', () => { expect(await publicClient.getBalance({ address: randomAddress })).toBe(beforeBalance - amountToSend - feePaid); // stop impersonating - await cc.l1.stopPrank(EthAddress.fromString(randomAddress)); + await cc.l1.stopImpersonating(EthAddress.fromString(randomAddress)); // making calls from random address should not be successful try { @@ -134,7 +142,7 @@ describe('e2e_cheat_codes', () => { } }); - it('can modify L1 block time', async () => { + it('can modify L2 block time', async () => { // deploy lending contract const tx = LendingContract.deploy(aztecRpcServer).send(); await tx.isMined({ interval: 0.1 }); @@ -164,5 +172,13 @@ describe('e2e_cheat_codes', () => { expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp); expect; }, 50_000); + + it('should throw if setting L2 block time to a past timestamp', async () => { + const timestamp = await cc.l1.timestamp(); + const pastTimestamp = timestamp - 1000; + await expect(async () => await cc.l2.warp(pastTimestamp)).rejects.toThrow( + `Error setting next block timestamp: Timestamp error: ${pastTimestamp} is lower than or equal to previous block's timestamp`, + ); + }); }); }); From a349f75d5cff770d327303b47fa270b926e038dd Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 10:09:19 +0100 Subject: [PATCH 4/9] use .eth and .aztec instead of .l1 and .l2 (#1611) In case we like the `.eth` and `.aztec` variation over `.l1` and `.l2` in cheatcodes! This would get merged into my docs pr #1585 --- docs/docs/dev_docs/testing/cheat_codes.md | 128 +++++++++--------- .../aztec.js/src/utils/cheat_codes.ts | 46 +++---- .../end-to-end/src/e2e_cheat_codes.test.ts | 58 ++++---- yarn-project/end-to-end/src/fixtures/utils.ts | 6 +- 4 files changed, 119 insertions(+), 119 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index b5b403a549a..3e1d63989e0 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -6,16 +6,16 @@ title: Cheat Codes To help with testing, the sandbox is shipped with a set of cheatcodes. -Cheatcodes allow you to change the time of the L2 block, load certain state or more easily manipulate L1 instead of having to write dedicated RPC calls to anvil. +Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil. :::info Prerequisites -If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recommend reading up on that since Aztec Sandbox uses Anvil as the local L1 instance. +If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recommend reading up on that since Aztec Sandbox uses Anvil as the local Ethereum instance. ::: ### Aims The guide will cover how to manipulate the state of the: -- L1 blockchain; +- Ethereum blockchain; - Aztec network. ### Dependencies @@ -31,53 +31,53 @@ const aztecRpcClient = createAztecRpcClient(aztecRpcUrl); const cc = await CheatCodes.create(aztecRpcUrl, aztecRpcClient); ``` -There are two properties of the CheatCodes class - `l1` and `l2` for cheatcodes relating to the L1 and L2 (Aztec) respectively. +There are two properties of the CheatCodes class - `eth` and `aztec` for cheatcodes relating to the Ethereum blockchain (L1) and the Aztec network (L2) respectively. -## L1 related cheatcodes +## Ethereum related cheatcodes These are cheatcodes exposed from anvil conveniently wrapped for ease of use in the Sandbox. ### Interface ``` -// Fetch current block number of L1 +// Fetch current block number of Ethereum public async blockNumber(): Promise -// Fetch chain ID of L1 +// Fetch chain ID of the local Ethereum instance public async chainId(): Promise -// Fetch current timestamp on L1 +// Fetch current timestamp on Ethereum public async timestamp(): Promise -// Mine a given number of blocks on L1. Mines 1 block by default +// Mine a given number of blocks on Ethereum. Mines 1 block by default public async mine(numberOfBlocks = 1): Promise -// Set the timestamp for the next block on L1. +// Set the timestamp for the next block on Ethereum. public async setNextBlockTimestamp(timestamp: number): Promise -// Dumps the current L1 chain state to a given file. +// Dumps the current Ethereum chain state to a given file. public async dumpChainState(fileName: string): Promise -// Loads the L1 chain state from a file. You may use `dumpChainState()` to save the state of the L1 chain to a file and later load it. +// Loads the Ethereum chain state from a file. You may use `dumpChainState()` to save the state of the Ethereum chain to a file and later load it. public async loadChainState(fileName: string): Promise -// Load the value at a storage slot of a contract address on L1 +// Load the value at a storage slot of a contract address on Ethereum public async load(contract: EthAddress, slot: bigint): Promise -// Set the value at a storage slot of a contract address on L1 (e.g. modify a storage variable on your portal contract or even the rollup contract). +// Set the value at a storage slot of a contract address on Ethereum (e.g. modify a storage variable on your portal contract or even the rollup contract). public async store(contract: EthAddress, slot: bigint, value: bigint): Promise -// Computes the slot value for a given map and key on L1. A convenient wrapper to find the appropriate storage slot to load or overwrite the state. +// Computes the slot value for a given map and key on Ethereum. A convenient wrapper to find the appropriate storage slot to load or overwrite the state. public keccak256(baseSlot: bigint, key: bigint): bigint -// Let you send transactions on L1 impersonating an externally owned or contract, without knowing the private key. +// Let you send transactions on Ethereum impersonating an externally owned or contract, without knowing the private key. public async startImpersonating(who: EthAddress): Promise -// Stop impersonating an account on L1 that you are currently impersonating. +// Stop impersonating an account on Ethereum that you are currently impersonating. public async stopImpersonating(who: EthAddress): Promise -// Set the bytecode for a L1 contract +// Set the bytecode for a Ethereum contract public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise -// Get the bytecode for a L1 contract +// Get the bytecode for a Ethereum contract public async getBytecode(contract: EthAddress): Promise<`0x${string}`> ``` @@ -89,11 +89,11 @@ public async blockNumber(): Promise ``` #### Description -Fetches the current L1 block number. +Fetches the current Ethereum block number. #### Example ```js -const blockNumber = await cc.l1.blockNumber() +const blockNumber = await cc.eth.blockNumber() ``` ### chainId @@ -104,11 +104,11 @@ public async chainId(): Promise ``` #### Description -Fetches the L1 chain ID +Fetches the Ethereum chain ID #### Example ```js -const chainId = await cc.l1.chainId() +const chainId = await cc.eth.chainId() ``` ### timestamp @@ -119,11 +119,11 @@ public async timestamp(): Promise ``` #### Description -Fetches the current L1 timestamp. +Fetches the current Ethereum timestamp. #### Example ```js -const timestamp = await cc.l1.timestamp() +const timestamp = await cc.eth.timestamp() ``` ### mine @@ -134,13 +134,13 @@ public async mine(numberOfBlocks = 1): Promise ``` #### Description -Mines the specified number of blocks on L1 (default 1). +Mines the specified number of blocks on Ethereum (default 1). #### Example ```js -const blockNum = await cc.l1.blockNumber(); -await cc.l1.mine(10) // mines 10 blocks -const newBlockNum = await cc.l1.blockNumber(); // = blockNum + 10. +const blockNum = await cc.eth.blockNumber(); +await cc.eth.mine(10) // mines 10 blocks +const newBlockNum = await cc.eth.blockNumber(); // = blockNum + 10. ``` ### setNextBlockTimestamp @@ -151,13 +151,13 @@ public async setNextBlockTimestamp(timestamp: number): Promise ``` #### Description -Sets the timestamp (unix format in seconds) for the next mined block on L1. +Sets the timestamp (unix format in seconds) for the next mined block on Ethereum. Remember that timestamp can only be set in the future and not in the past. #### Example ```js // // Set next block timestamp to 16 Aug 2023 10:54:30 GMT -await cc.l1.setNextBlockTimestamp(1692183270) +await cc.eth.setNextBlockTimestamp(1692183270) // next transaction you will do will have the timestamp as 1692183270 ``` @@ -169,13 +169,13 @@ public async dumpChainState(fileName: string): Promise ``` #### Description -Dumps the current L1 chain state to a file. +Dumps the current Ethereum chain state to a file. Stores a hex string representing the complete state of the chain in a file with the provided path. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. When combined with `loadChainState()` cheatcode, it can be let you easily import the current state of mainnet into the Anvil instance of the sandbox, to use Uniswap for example. #### Example ```js -await cc.l1.dumpChainState('chain-state.json') +await cc.eth.dumpChainState('chain-state.json') ``` ### loadChainState @@ -186,12 +186,12 @@ public async loadChainState(fileName: string): Promise ``` #### Description -Loads the L1 chain state from a file which contains a hex string representing an L1 state. -When given a file previously written to by `cc.l1.dumpChainState()`, it merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. +Loads the Ethereum chain state from a file which contains a hex string representing an Ethereum state. +When given a file previously written to by `cc.eth.dumpChainState()`, it merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. #### Example ```js -await cc.l1.loadChainState('chain-state.json') +await cc.eth.loadChainState('chain-state.json') ``` ### load @@ -202,7 +202,7 @@ public async load(contract: EthAddress, slot: bigint): Promise ``` #### Description -Loads the value at a storage slot of a L1 contract. +Loads the value at a storage slot of a Ethereum contract. #### Example ``` @@ -211,7 +211,7 @@ Loads the value at a storage slot of a L1 contract. /// } const leetContractAddress = EthAddress.fromString('0x1234...'); -const value = await cc.l1.load(leetContractAddress, BigInt(0)); +const value = await cc.eth.load(leetContractAddress, BigInt(0)); console.log(value); // 1337 ``` @@ -223,7 +223,7 @@ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise ``` #### Description -Start impersonating an L1 account. +Start impersonating an Ethereum account. This allows you to use this address as a sender. #### Example ```js -await cc.l1.startImpersonating(EthAddress.fromString(address)); +await cc.eth.startImpersonating(EthAddress.fromString(address)); ``` ### stopImpersonating @@ -285,12 +285,12 @@ public async stopImpersonating(who: EthAddress): Promise ``` #### Description -Stop impersonating an L1 account. +Stop impersonating an Ethereum account. Stops an active impersonation started by startImpersonating. #### Example ```js -await cc.l1.stopImpersonating(EthAddress.fromString(address)) +await cc.eth.stopImpersonating(EthAddress.fromString(address)) ``` ### getBytecode @@ -301,11 +301,11 @@ public async getBytecode(contract: EthAddress): Promise<`0x${string}`> ``` #### Description -Get the bytecode for an L1 contract. +Get the bytecode for an Ethereum contract. #### Example ```js -const bytecode = await cc.l1.getBytecode(contract) // 0x6080604052348015610010... +const bytecode = await cc.eth.getBytecode(contract) // 0x6080604052348015610010... ``` ### etch @@ -316,24 +316,24 @@ public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise ``` #### Description -Set the bytecode for an L1 contract. +Set the bytecode for an Ethereum contract. #### Example ```js const bytecode = `0x6080604052348015610010...` -await cc.l1.etch(contract, bytecode) -console.log(await cc.l1.getBytecode(contract)) // 0x6080604052348015610010... +await cc.eth.etch(contract, bytecode) +console.log(await cc.eth.getBytecode(contract)) // 0x6080604052348015610010... ``` -## L2 related cheatcodes +## Aztec related cheatcodes These are cheatcodes specific to manipulating the state of Aztec rollup. ### Interface ``` -// Get the current L2 block number +// Get the current aztec block number public async blockNumber(): Promise -// Set time of the next execution on L2. It also modifies time on L1 for next execution and stores this time as the last rollup block on the rollup contract. +// Set time of the next execution on aztec. It also modifies time on Ethereum for next execution and stores this time as the last rollup block on the rollup contract. public async warp(to: number): Promise // Loads the value stored at the given slot in the public storage of the given contract. @@ -351,11 +351,11 @@ public async blockNumber(): Promise ``` #### Description -Get the current L2 block number. +Get the current aztec block number. #### Example ```js -const blockNumber = await cc.l2.blockNumber() +const blockNumber = await cc.aztec.blockNumber() ``` ### warp @@ -366,14 +366,14 @@ public async warp(to: number): Promise ``` #### Description -Sets the time of L1 and the time of the next L2 block. -Like with the corresponding L1 cheatcode, time can only be set in the future, not the past. +Sets the time on Ethereum and the time of the next block on Aztec. +Like with the corresponding Ethereum cheatcode, time can only be set in the future, not the past. #### Example ```js -const timestamp = await cc.l1.timestamp(); +const timestamp = await cc.eth.timestamp(); const newTimestamp = timestamp + 100_000_000; -await cc.l2.warp(newTimestamp); +await cc.aztec.warp(newTimestamp); // any noir contract calls that make use of current timestamp and is executed in the next rollup block will now read `newTimestamp` ``` @@ -409,7 +409,7 @@ The baseSlot is specified in the noir contract. /// ... /// } -const slot = cc.l2.computeSlotInMap(1n, key) +const slot = cc.aztec.computeSlotInMap(1n, key) ``` ### loadPublic @@ -445,8 +445,8 @@ Note: One Field element occupies a storage slot. So structs with multiple field /// } const address = AztecAddress.fromString("0x123...") -const slot = cc.l2.computeSlotInMap(1n, key) -const value = await cc.l2.loadPublic(address, slot); +const slot = cc.aztec.computeSlotInMap(1n, key) +const value = await cc.aztec.loadPublic(address, slot); ``` ## Participate diff --git a/yarn-project/aztec.js/src/utils/cheat_codes.ts b/yarn-project/aztec.js/src/utils/cheat_codes.ts index 47dbee5d1af..41e641eaafe 100644 --- a/yarn-project/aztec.js/src/utils/cheat_codes.ts +++ b/yarn-project/aztec.js/src/utils/cheat_codes.ts @@ -17,35 +17,35 @@ const toFr = (value: Fr | bigint): Fr => { export class CheatCodes { constructor( /** - * The L1 cheat codes. + * The cheat codes for ethereum (L1). */ - public l1: L1CheatCodes, + public eth: EthCheatCodes, /** - * The L2 cheat codes. + * The cheat codes for aztec. */ - public l2: L2CheatCodes, + public aztec: AztecCheatCodes, ) {} static async create(rpcUrl: string, aztecRpc: AztecRPC): Promise { - const l1CheatCodes = new L1CheatCodes(rpcUrl); - const l2CheatCodes = new L2CheatCodes(aztecRpc, await CircuitsWasm.get(), l1CheatCodes); - return new CheatCodes(l1CheatCodes, l2CheatCodes); + const ethCheatCodes = new EthCheatCodes(rpcUrl); + const aztecCheatCodes = new AztecCheatCodes(aztecRpc, await CircuitsWasm.get(), ethCheatCodes); + return new CheatCodes(ethCheatCodes, aztecCheatCodes); } } /** - * A class that provides utility functions for interacting with the L1 chain. + * A class that provides utility functions for interacting with ethereum (L1). */ -export class L1CheatCodes { +export class EthCheatCodes { constructor( /** * The RPC client to use for interacting with the chain */ public rpcUrl: string, /** - * The logger to use for the l1 cheatcodes + * The logger to use for the eth cheatcodes */ - public logger = createDebugLogger('aztec:cheat_codes:l1'), + public logger = createDebugLogger('aztec:cheat_codes:eth'), ) {} async rpcCall(method: string, params: any[]) { @@ -130,7 +130,7 @@ export class L1CheatCodes { } /** - * Load the value at a storage slot of a contract address on L1 + * Load the value at a storage slot of a contract address on eth * @param contract - The contract address * @param slot - The storage slot * @returns - The value at the storage slot @@ -141,7 +141,7 @@ export class L1CheatCodes { } /** - * Set the value at a storage slot of a contract address on L1 + * Set the value at a storage slot of a contract address on eth * @param contract - The contract address * @param slot - The storage slot * @param value - The value to set the storage slot to @@ -208,9 +208,9 @@ export class L1CheatCodes { } /** - * A class that provides utility functions for interacting with the L2 chain. + * A class that provides utility functions for interacting with the aztec chain. */ -export class L2CheatCodes { +export class AztecCheatCodes { constructor( /** * The RPC client to use for interacting with the chain @@ -221,13 +221,13 @@ export class L2CheatCodes { */ public wasm: CircuitsWasm, /** - * The L1 cheat codes. + * The eth cheat codes. */ - public l1: L1CheatCodes, + public eth: EthCheatCodes, /** - * The logger to use for the l2 cheatcodes + * The logger to use for the aztec cheatcodes */ - public logger = createDebugLogger('aztec:cheat_codes:l2'), + public logger = createDebugLogger('aztec:cheat_codes:aztec'), ) {} /** @@ -256,16 +256,16 @@ export class L2CheatCodes { } /** - * Set time of the next execution on L2. - * It also modifies time on L1 for next execution and stores this time as the last rollup block on the rollup contract. + * Set time of the next execution on aztec. + * It also modifies time on eth for next execution and stores this time as the last rollup block on the rollup contract. * @param to - The timestamp to set the next block to (must be greater than current time) */ public async warp(to: number): Promise { const rollupContract = (await this.aztecRpc.getNodeInfo()).rollupAddress; - await this.l1.setNextBlockTimestamp(to); + await this.eth.setNextBlockTimestamp(to); // also store this time on the rollup contract (slot 1 tracks `lastBlockTs`). // This is because when the sequencer executes public functions, it uses the timestamp stored in the rollup contract. - await this.l1.store(rollupContract, 1n, BigInt(to)); + await this.eth.store(rollupContract, 1n, BigInt(to)); } /** diff --git a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts index a55db9f0a57..f68071ab996 100644 --- a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts +++ b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts @@ -41,42 +41,42 @@ describe('e2e_cheat_codes', () => { describe('L1 only', () => { describe('mine', () => { it(`mine block`, async () => { - const blockNumber = await cc.l1.blockNumber(); - await cc.l1.mine(); - expect(await cc.l1.blockNumber()).toBe(blockNumber + 1); + const blockNumber = await cc.eth.blockNumber(); + await cc.eth.mine(); + expect(await cc.eth.blockNumber()).toBe(blockNumber + 1); }); it.each([10, 42, 99])(`mine blocks`, async increment => { - const blockNumber = await cc.l1.blockNumber(); - await cc.l1.mine(increment); - expect(await cc.l1.blockNumber()).toBe(blockNumber + increment); + const blockNumber = await cc.eth.blockNumber(); + await cc.eth.mine(increment); + expect(await cc.eth.blockNumber()).toBe(blockNumber + increment); }); }); it.each([100, 42, 99])('setNextBlockTimestamp', async increment => { - const blockNumber = await cc.l1.blockNumber(); - const timestamp = await cc.l1.timestamp(); - await cc.l1.setNextBlockTimestamp(timestamp + increment); + const blockNumber = await cc.eth.blockNumber(); + const timestamp = await cc.eth.timestamp(); + await cc.eth.setNextBlockTimestamp(timestamp + increment); - expect(await cc.l1.timestamp()).toBe(timestamp); + expect(await cc.eth.timestamp()).toBe(timestamp); - await cc.l1.mine(); + await cc.eth.mine(); - expect(await cc.l1.blockNumber()).toBe(blockNumber + 1); - expect(await cc.l1.timestamp()).toBe(timestamp + increment); + expect(await cc.eth.blockNumber()).toBe(blockNumber + 1); + expect(await cc.eth.timestamp()).toBe(timestamp + increment); }); it('setNextBlockTimestamp to a past timestamp throws', async () => { - const timestamp = await cc.l1.timestamp(); + const timestamp = await cc.eth.timestamp(); const pastTimestamp = timestamp - 1000; - await expect(async () => await cc.l1.setNextBlockTimestamp(pastTimestamp)).rejects.toThrow( + await expect(async () => await cc.eth.setNextBlockTimestamp(pastTimestamp)).rejects.toThrow( `Error setting next block timestamp: Timestamp error: ${pastTimestamp} is lower than or equal to previous block's timestamp`, ); }); it('load a value at a particular storage slot', async () => { // check that storage slot 0 is empty as expected - const res = await cc.l1.load(EthAddress.ZERO, 0n); + const res = await cc.eth.load(EthAddress.ZERO, 0n); expect(res).toBe(0n); }); @@ -86,18 +86,18 @@ describe('e2e_cheat_codes', () => { const storageSlot = BigInt('0x' + storageSlotInHex); const valueToSet = 5n; const contractAddress = EthAddress.fromString('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'); - await cc.l1.store(contractAddress, storageSlot, valueToSet); - expect(await cc.l1.load(contractAddress, storageSlot)).toBe(valueToSet); + await cc.eth.store(contractAddress, storageSlot, valueToSet); + expect(await cc.eth.load(contractAddress, storageSlot)).toBe(valueToSet); // also test with the keccak value of the slot - can be used to compute storage slots of maps - await cc.l1.store(contractAddress, cc.l1.keccak256(0n, storageSlot), valueToSet); - expect(await cc.l1.load(contractAddress, cc.l1.keccak256(0n, storageSlot))).toBe(valueToSet); + await cc.eth.store(contractAddress, cc.eth.keccak256(0n, storageSlot), valueToSet); + expect(await cc.eth.load(contractAddress, cc.eth.keccak256(0n, storageSlot))).toBe(valueToSet); }, ); it('set bytecode correctly', async () => { const contractAddress = EthAddress.fromString('0x70997970C51812dc3A010C7d01b50e0d17dc79C8'); - await cc.l1.etch(contractAddress, '0x1234'); - expect(await cc.l1.getBytecode(contractAddress)).toBe('0x1234'); + await cc.eth.etch(contractAddress, '0x1234'); + expect(await cc.eth.getBytecode(contractAddress)).toBe('0x1234'); }); it('impersonate', async () => { @@ -113,7 +113,7 @@ describe('e2e_cheat_codes', () => { const beforeBalance = await publicClient.getBalance({ address: randomAddress }); // impersonate random address - await cc.l1.startImpersonating(EthAddress.fromString(randomAddress)); + await cc.eth.startImpersonating(EthAddress.fromString(randomAddress)); // send funds from random address const amountToSend = parseEther('0.1'); const txHash = await walletClient.sendTransaction({ @@ -126,7 +126,7 @@ describe('e2e_cheat_codes', () => { expect(await publicClient.getBalance({ address: randomAddress })).toBe(beforeBalance - amountToSend - feePaid); // stop impersonating - await cc.l1.stopImpersonating(EthAddress.fromString(randomAddress)); + await cc.eth.stopImpersonating(EthAddress.fromString(randomAddress)); // making calls from random address should not be successful try { @@ -150,9 +150,9 @@ describe('e2e_cheat_codes', () => { const contract = await LendingContract.at(receipt.contractAddress!, wallet); // now update time: - const timestamp = await cc.l1.timestamp(); + const timestamp = await cc.eth.timestamp(); const newTimestamp = timestamp + 100_000_000; - await cc.l2.warp(newTimestamp); + await cc.aztec.warp(newTimestamp); // ensure rollup contract is correctly updated const rollup = getContract({ address: getAddress(rollupAddress.toString()), abi: RollupAbi, publicClient }); @@ -167,16 +167,16 @@ describe('e2e_cheat_codes', () => { const lastUpdatedTs = Number((await contract.methods.getTot(0).view())['last_updated_ts']); expect(lastUpdatedTs).toEqual(newTimestamp); // ensure anvil is correctly updated - expect(await cc.l1.timestamp()).toEqual(newTimestamp); + expect(await cc.eth.timestamp()).toEqual(newTimestamp); // ensure rollup contract is correctly updated expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp); expect; }, 50_000); it('should throw if setting L2 block time to a past timestamp', async () => { - const timestamp = await cc.l1.timestamp(); + const timestamp = await cc.eth.timestamp(); const pastTimestamp = timestamp - 1000; - await expect(async () => await cc.l2.warp(pastTimestamp)).rejects.toThrow( + 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`, ); }); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 85dff3bf91b..53fa13034ad 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -9,7 +9,7 @@ import { EntrypointCollection, EntrypointWallet, EthAddress, - L1CheatCodes, + EthCheatCodes, Wallet, createAztecRpcClient as createJsonRpcClient, getL1ContractAddresses, @@ -232,8 +232,8 @@ export async function setup( const config = getConfigEnvVars(); if (stateLoad) { - const l1CheatCodes = new L1CheatCodes(config.rpcUrl); - await l1CheatCodes.loadChainState(stateLoad); + const ethCheatCodes = new EthCheatCodes(config.rpcUrl); + await ethCheatCodes.loadChainState(stateLoad); } const logger = getLogger(); From 95c08b1c3e5611e44680de170ca2ba51698612b5 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 10:29:31 +0000 Subject: [PATCH 5/9] use hardhat_* --- docs/docs/dev_docs/testing/cheat_codes.md | 4 ++-- yarn-project/aztec.js/src/utils/cheat_codes.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index 3e1d63989e0..1baa9d18b41 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -6,7 +6,7 @@ title: Cheat Codes To help with testing, the sandbox is shipped with a set of cheatcodes. -Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil. +Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil or hardhat. :::info Prerequisites If you aren't familiar with [Anvil](https://book.getfoundry.sh/anvil/), we recommend reading up on that since Aztec Sandbox uses Anvil as the local Ethereum instance. @@ -34,7 +34,7 @@ const cc = await CheatCodes.create(aztecRpcUrl, aztecRpcClient); There are two properties of the CheatCodes class - `eth` and `aztec` for cheatcodes relating to the Ethereum blockchain (L1) and the Aztec network (L2) respectively. ## Ethereum related cheatcodes -These are cheatcodes exposed from anvil conveniently wrapped for ease of use in the Sandbox. +These are cheatcodes exposed from anvil/hardhat conveniently wrapped for ease of use in the Sandbox. ### Interface ``` diff --git a/yarn-project/aztec.js/src/utils/cheat_codes.ts b/yarn-project/aztec.js/src/utils/cheat_codes.ts index 41e641eaafe..bf296344b90 100644 --- a/yarn-project/aztec.js/src/utils/cheat_codes.ts +++ b/yarn-project/aztec.js/src/utils/cheat_codes.ts @@ -91,7 +91,7 @@ export class EthCheatCodes { * @returns The current chainId */ public async mine(numberOfBlocks = 1): Promise { - const res = await this.rpcCall('anvil_mine', [numberOfBlocks]); + const res = await this.rpcCall('hardhat_mine', [numberOfBlocks]); if (res.error) throw new Error(`Error mining: ${res.error.message}`); this.logger(`Mined ${numberOfBlocks} blocks`); } @@ -101,7 +101,7 @@ export class EthCheatCodes { * @param timestamp - The timestamp to set the next block to */ public async setNextBlockTimestamp(timestamp: number): Promise { - const res = await this.rpcCall('anvil_setNextBlockTimestamp', [timestamp]); + const res = await this.rpcCall('evm_setNextBlockTimestamp', [timestamp]); if (res.error) throw new Error(`Error setting next block timestamp: ${res.error.message}`); this.logger(`Set next block timestamp to ${timestamp}`); } @@ -111,7 +111,7 @@ export class EthCheatCodes { * @param fileName - The file name to dump state into */ public async dumpChainState(fileName: string): Promise { - const res = await this.rpcCall('anvil_dumpState', []); + const res = await this.rpcCall('hardhat_dumpState', []); if (res.error) throw new Error(`Error dumping state: ${res.error.message}`); const jsonContent = JSON.stringify(res.result); fs.writeFileSync(`${fileName}.json`, jsonContent, 'utf8'); @@ -124,7 +124,7 @@ export class EthCheatCodes { */ public async loadChainState(fileName: string): Promise { const data = JSON.parse(fs.readFileSync(`${fileName}.json`, 'utf8')); - const res = await this.rpcCall('anvil_loadState', [data]); + const res = await this.rpcCall('hardhat_loadState', [data]); if (res.error) throw new Error(`Error loading state: ${res.error.message}`); this.logger(`Loaded state from ${fileName}`); } @@ -148,7 +148,7 @@ export class EthCheatCodes { */ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise { // for the rpc call, we need to change value to be a 32 byte hex string. - const res = await this.rpcCall('anvil_setStorageAt', [contract.toString(), toHex(slot), toHex(value, true)]); + const res = await this.rpcCall('hardhat_setStorageAt', [contract.toString(), toHex(slot), toHex(value, true)]); if (res.error) throw new Error(`Error setting storage for contract ${contract} at ${slot}: ${res.error.message}`); this.logger(`Set storage for contract ${contract} at ${slot} to ${value}`); } @@ -170,7 +170,7 @@ export class EthCheatCodes { * @param who - The address to impersonate */ public async startImpersonating(who: EthAddress): Promise { - const res = await this.rpcCall('anvil_impersonateAccount', [who.toString()]); + const res = await this.rpcCall('hardhat_impersonateAccount', [who.toString()]); if (res.error) throw new Error(`Error impersonating ${who}: ${res.error.message}`); this.logger(`Impersonating ${who}`); } @@ -180,7 +180,7 @@ export class EthCheatCodes { * @param who - The address to stop impersonating */ public async stopImpersonating(who: EthAddress): Promise { - const res = await this.rpcCall('anvil_stopImpersonatingAccount', [who.toString()]); + const res = await this.rpcCall('hardhat_stopImpersonatingAccount', [who.toString()]); if (res.error) throw new Error(`Error when stopping the impersonation of ${who}: ${res.error.message}`); this.logger(`Stopped impersonating ${who}`); } @@ -191,7 +191,7 @@ export class EthCheatCodes { * @param bytecode - The bytecode to set */ public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise { - const res = await this.rpcCall('anvil_setCode', [contract.toString(), bytecode]); + const res = await this.rpcCall('hardhat_setCode', [contract.toString(), bytecode]); if (res.error) throw new Error(`Error setting bytecode for ${contract}: ${res.error.message}`); this.logger(`Set bytecode for ${contract} to ${bytecode}`); } From 4402dd670381e265dd705fe3d64b34e238cf7ada Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 11:07:01 +0000 Subject: [PATCH 6/9] use better syntax highlighting --- docs/docs/dev_docs/testing/cheat_codes.md | 176 +++++++++++----------- 1 file changed, 92 insertions(+), 84 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index 1baa9d18b41..4187ffcaf4d 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -24,7 +24,7 @@ For this guide, the following Aztec packages are used: - @aztec/aztec.js ### Initialisation -```js +```ts import { createAztecRpcClient, CheatCodes } from '@aztec/aztec.js'; const aztecRpcUrl = 'http://localhost:8080'; const aztecRpcClient = createAztecRpcClient(aztecRpcUrl); @@ -37,7 +37,7 @@ There are two properties of the CheatCodes class - `eth` and `aztec` for cheatco These are cheatcodes exposed from anvil/hardhat conveniently wrapped for ease of use in the Sandbox. ### Interface -``` +```ts // Fetch current block number of Ethereum public async blockNumber(): Promise @@ -84,7 +84,7 @@ public async getBytecode(contract: EthAddress): Promise<`0x${string}`> ### blockNumber #### Function Signature -```js +```ts public async blockNumber(): Promise ``` @@ -92,14 +92,14 @@ public async blockNumber(): Promise Fetches the current Ethereum block number. #### Example -```js +```ts const blockNumber = await cc.eth.blockNumber() ``` ### chainId #### Function Signature -```js +```ts public async chainId(): Promise ``` @@ -107,14 +107,14 @@ public async chainId(): Promise Fetches the Ethereum chain ID #### Example -```js +```ts const chainId = await cc.eth.chainId() ``` ### timestamp #### Function Signature -```js +```ts public async timestamp(): Promise ``` @@ -122,14 +122,14 @@ public async timestamp(): Promise Fetches the current Ethereum timestamp. #### Example -```js +```ts const timestamp = await cc.eth.timestamp() ``` ### mine #### Function Signature -```js +```ts public async mine(numberOfBlocks = 1): Promise ``` @@ -137,7 +137,7 @@ public async mine(numberOfBlocks = 1): Promise Mines the specified number of blocks on Ethereum (default 1). #### Example -```js +```ts const blockNum = await cc.eth.blockNumber(); await cc.eth.mine(10) // mines 10 blocks const newBlockNum = await cc.eth.blockNumber(); // = blockNum + 10. @@ -146,7 +146,7 @@ const newBlockNum = await cc.eth.blockNumber(); // = blockNum + 10. ### setNextBlockTimestamp #### Function Signature -```js +```ts public async setNextBlockTimestamp(timestamp: number): Promise ``` @@ -155,7 +155,7 @@ Sets the timestamp (unix format in seconds) for the next mined block on Ethereum Remember that timestamp can only be set in the future and not in the past. #### Example -```js +```ts // // Set next block timestamp to 16 Aug 2023 10:54:30 GMT await cc.eth.setNextBlockTimestamp(1692183270) // next transaction you will do will have the timestamp as 1692183270 @@ -164,7 +164,7 @@ await cc.eth.setNextBlockTimestamp(1692183270) ### dumpChainState #### Function Signature -```js +```ts public async dumpChainState(fileName: string): Promise ``` @@ -174,14 +174,14 @@ Stores a hex string representing the complete state of the chain in a file with When combined with `loadChainState()` cheatcode, it can be let you easily import the current state of mainnet into the Anvil instance of the sandbox, to use Uniswap for example. #### Example -```js +```ts await cc.eth.dumpChainState('chain-state.json') ``` ### loadChainState #### Function Signature -```js +```ts public async loadChainState(fileName: string): Promise ``` @@ -190,14 +190,14 @@ Loads the Ethereum chain state from a file which contains a hex string represent When given a file previously written to by `cc.eth.dumpChainState()`, it merges the contents into the current chain state. Will overwrite any colliding accounts/storage slots. #### Example -```js +```ts await cc.eth.loadChainState('chain-state.json') ``` ### load #### Function Signature -```js +```ts public async load(contract: EthAddress, slot: bigint): Promise ``` @@ -205,11 +205,13 @@ public async load(contract: EthAddress, slot: bigint): Promise Loads the value at a storage slot of a Ethereum contract. #### Example +```solidity +contract LeetContract { + uint256 private leet = 1337; // slot 0 +} ``` -/// contract LeetContract { -/// uint256 private leet = 1337; // slot 0 -/// } +```ts const leetContractAddress = EthAddress.fromString('0x1234...'); const value = await cc.eth.load(leetContractAddress, BigInt(0)); console.log(value); // 1337 @@ -218,7 +220,7 @@ console.log(value); // 1337 ### store #### Function Signature -```js +```ts public async store(contract: EthAddress, slot: bigint, value: bigint): Promise ``` @@ -226,11 +228,13 @@ public async store(contract: EthAddress, slot: bigint, value: bigint): Promise uint256) public balances; // base slot 1 +} ``` -/// contract LeetContract { -/// uint256 private leet = 1337; // slot 0 -/// mapping(address => uint256) public balances; // base slot 1 -/// } +```ts // find the storage slot for key `0xdead` in the balance map. const address = BigInt('0x000000000000000000000000000000000000dead'); const slot = cc.eth.keccak256(1n, address); @@ -264,7 +270,7 @@ await cc.eth.store(contractAddress, slot, 100n); ### startImpersonating #### Function Signature -```js +```ts public async startImpersonating(who: EthAddress): Promise ``` @@ -273,14 +279,14 @@ Start impersonating an Ethereum account. This allows you to use this address as a sender. #### Example -```js +```ts await cc.eth.startImpersonating(EthAddress.fromString(address)); ``` ### stopImpersonating #### Function Signature -```js +```ts public async stopImpersonating(who: EthAddress): Promise ``` @@ -289,14 +295,14 @@ Stop impersonating an Ethereum account. Stops an active impersonation started by startImpersonating. #### Example -```js +```ts await cc.eth.stopImpersonating(EthAddress.fromString(address)) ``` ### getBytecode #### Function Signature -```js +```ts public async getBytecode(contract: EthAddress): Promise<`0x${string}`> ``` @@ -304,14 +310,14 @@ public async getBytecode(contract: EthAddress): Promise<`0x${string}`> Get the bytecode for an Ethereum contract. #### Example -```js +```ts const bytecode = await cc.eth.getBytecode(contract) // 0x6080604052348015610010... ``` ### etch #### Function Signature -```js +```ts public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise ``` @@ -319,7 +325,7 @@ public async etch(contract: EthAddress, bytecode: `0x${string}`): Promise Set the bytecode for an Ethereum contract. #### Example -```js +```ts const bytecode = `0x6080604052348015610010...` await cc.eth.etch(contract, bytecode) console.log(await cc.eth.getBytecode(contract)) // 0x6080604052348015610010... @@ -329,7 +335,7 @@ console.log(await cc.eth.getBytecode(contract)) // 0x6080604052348015610010... These are cheatcodes specific to manipulating the state of Aztec rollup. ### Interface -``` +```ts // Get the current aztec block number public async blockNumber(): Promise @@ -346,7 +352,7 @@ public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr ### blockNumber #### Function Signature -```js +```ts public async blockNumber(): Promise ``` @@ -354,14 +360,14 @@ public async blockNumber(): Promise Get the current aztec block number. #### Example -```js +```ts const blockNumber = await cc.aztec.blockNumber() ``` ### warp #### Function Signature -```js +```ts public async warp(to: number): Promise ``` @@ -370,18 +376,18 @@ Sets the time on Ethereum and the time of the next block on Aztec. Like with the corresponding Ethereum cheatcode, time can only be set in the future, not the past. #### Example -```js +```ts const timestamp = await cc.eth.timestamp(); const newTimestamp = timestamp + 100_000_000; await cc.aztec.warp(newTimestamp); - -// any noir contract calls that make use of current timestamp and is executed in the next rollup block will now read `newTimestamp` +// any noir contract calls that make use of current timestamp +// and is executed in the next rollup block will now read `newTimestamp` ``` ### computeSlotInMap #### Function Signature -```js +```ts public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr ``` @@ -390,32 +396,33 @@ Compute storage slot for a map key. The baseSlot is specified in the noir contract. #### Example -``` -/// struct Storage { -/// // highlight-next-line:PublicState -/// balances: Map>, -/// } -/// -/// impl Storage { -/// fn init() -> Self { -/// Storage { -/// balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), -/// } -/// } -/// } -/// -/// -/// contract Token { -/// ... -/// } - +```rust +struct Storage { + // highlight-next-line:PublicState + balances: Map>, +} + +impl Storage { + fn init() -> Self { + Storage { + balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), + } + } +} + +contract Token { + ... +} +``` + +```ts const slot = cc.aztec.computeSlotInMap(1n, key) ``` ### loadPublic #### Function Signature -```js +```ts public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise ``` @@ -425,25 +432,26 @@ Loads the value stored at the given slot in the public storage of the given cont Note: One Field element occupies a storage slot. So structs with multiple field elements won't fit in a single slot. So using loadPublic would only load a part of the struct (depending on the size of the attributes within it). #### Example -``` -/// struct Storage { -/// // highlight-next-line:PublicState -/// balances: Map>, -/// } -/// -/// impl Storage { -/// fn init() -> Self { -/// Storage { -/// balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), -/// } -/// } -/// } -/// -/// -/// contract Token { -/// ... -/// } - +```rust +struct Storage { + // highlight-next-line:PublicState + balances: Map>, +} + +impl Storage { + fn init() -> Self { + Storage { + balances: Map::new(1, |slot| PublicState::new(slot, FieldSerialisationMethods)), + } + } +} + +contract Token { + ... +} +``` + +```ts const address = AztecAddress.fromString("0x123...") const slot = cc.aztec.computeSlotInMap(1n, key) const value = await cc.aztec.loadPublic(address, slot); From 83a09b3202423f856d9e3ecddcac99b3dedfaf77 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 11:09:49 +0000 Subject: [PATCH 7/9] explicit error --- docs/docs/dev_docs/testing/cheat_codes.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index 4187ffcaf4d..943d19edc64 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -151,8 +151,9 @@ public async setNextBlockTimestamp(timestamp: number): Promise ``` #### Description -Sets the timestamp (unix format in seconds) for the next mined block on Ethereum. -Remember that timestamp can only be set in the future and not in the past. +Sets the timestamp (unix format in seconds) for the next mined block on Ethereum. +Time can only be set in the future. +If you set the timestamp to a time in the past, this method will throw an error. #### Example ```ts @@ -374,6 +375,7 @@ public async warp(to: number): Promise #### Description Sets the time on Ethereum and the time of the next block on Aztec. Like with the corresponding Ethereum cheatcode, time can only be set in the future, not the past. +Otherwise, it will throw an error. #### Example ```ts From 298532cc8515d0224c3a97fa1be0d4fb1e1c64c4 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 11:33:06 +0000 Subject: [PATCH 8/9] address sean's nits --- docs/docs/dev_docs/testing/cheat_codes.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index 943d19edc64..fce57546996 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -172,7 +172,7 @@ public async dumpChainState(fileName: string): Promise #### Description Dumps the current Ethereum chain state to a file. Stores a hex string representing the complete state of the chain in a file with the provided path. Can be re-imported into a fresh/restarted instance of Anvil to reattain the same state. -When combined with `loadChainState()` cheatcode, it can be let you easily import the current state of mainnet into the Anvil instance of the sandbox, to use Uniswap for example. +When combined with `loadChainState()` cheatcode, it can be let you easily import the current state of mainnet into the Anvil instance of the sandbox. #### Example ```ts @@ -400,7 +400,6 @@ The baseSlot is specified in the noir contract. #### Example ```rust struct Storage { - // highlight-next-line:PublicState balances: Map>, } @@ -431,12 +430,11 @@ public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise #### Description Loads the value stored at the given slot in the public storage of the given contract. -Note: One Field element occupies a storage slot. So structs with multiple field elements won't fit in a single slot. So using loadPublic would only load a part of the struct (depending on the size of the attributes within it). +Note: One Field element occupies a storage slot. Hence, structs with multiple field elements will be spread over multiple slots, rather they 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 struct Storage { - // highlight-next-line:PublicState balances: Map>, } @@ -462,7 +460,7 @@ const value = await cc.aztec.loadPublic(address, slot); Keep up with the latest discussion and join the conversation in the [Aztec forum](https://discourse.aztec.network). -You can also use the above link to request for more cheatcodes. +You can also use the above link to request more cheatcodes. import Disclaimer from "../../misc/common/\_disclaimer.mdx"; \ No newline at end of file From 89c3d8e3b4453830478b8cd5e81dbae7ee7712ba Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Fri, 18 Aug 2023 11:37:32 +0000 Subject: [PATCH 9/9] improve struct slot wording --- docs/docs/dev_docs/testing/cheat_codes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/dev_docs/testing/cheat_codes.md index fce57546996..4a09ac7f811 100644 --- a/docs/docs/dev_docs/testing/cheat_codes.md +++ b/docs/docs/dev_docs/testing/cheat_codes.md @@ -430,7 +430,7 @@ public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise #### Description Loads the value stored at the given slot in the public storage of the given contract. -Note: One Field element occupies a storage slot. Hence, structs with multiple field elements will be spread over multiple slots, rather they 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). +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