-
Notifications
You must be signed in to change notification settings - Fork 283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Initial cheatcode loadPublic
#1353
+281
−82
Merged
Changes from 9 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
85295b2
feat: initial cheatcodes
LHerskind 408e782
chore: use cheatcodes
LHerskind 87d647f
chore: lint 🧹
LHerskind 2ce9445
chore: compartmentalize cheatcodes to l1 and l2
LHerskind 26b7b9d
feat: adding minor l1 tools
LHerskind 8d07eda
chore: formatting & lint 🧹
LHerskind a25707a
test: add separate test
LHerskind 851f32a
chore: boring naming
LHerskind 6995eaf
chore: minor cleanup
LHerskind b70fd60
chore: fix conflict
LHerskind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import { AztecAddress, CircuitsWasm, Fr } from '@aztec/circuits.js'; | ||
import { pedersenPlookupCommitInputs } from '@aztec/circuits.js/barretenberg'; | ||
import { createDebugLogger } from '@aztec/foundation/log'; | ||
import { AztecRPC } from '@aztec/types'; | ||
|
||
const toFr = (value: Fr | bigint): Fr => { | ||
return typeof value === 'bigint' ? new Fr(value) : value; | ||
}; | ||
|
||
/** | ||
* A class that provides utility functions for interacting with the chain. | ||
*/ | ||
export class CheatCodes { | ||
constructor( | ||
/** | ||
* The L1 cheat codes. | ||
*/ | ||
public l1: L1CheatCodes, | ||
/** | ||
* The L2 cheat codes. | ||
*/ | ||
public l2: L2CheatCodes, | ||
) {} | ||
|
||
static async create(rpcUrl: string, aztecRpc: AztecRPC): Promise<CheatCodes> { | ||
const l1CheatCodes = new L1CheatCodes(rpcUrl); | ||
const l2CheatCodes = new L2CheatCodes(aztecRpc, await CircuitsWasm.get(), l1CheatCodes); | ||
return new CheatCodes(l1CheatCodes, l2CheatCodes); | ||
} | ||
} | ||
|
||
/** | ||
* A class that provides utility functions for interacting with the L1 chain. | ||
*/ | ||
class L1CheatCodes { | ||
constructor( | ||
/** | ||
* The RPC client to use for interacting with the chain | ||
*/ | ||
public rpcUrl: string, | ||
/** | ||
* The logger to use for the l1 cheatcodes | ||
*/ | ||
public logger = createDebugLogger('aztec:cheat_codes:l1'), | ||
) {} | ||
|
||
async rpcCall(method: string, params: any[]) { | ||
const paramsString = JSON.stringify(params); | ||
const content = { | ||
body: `{"jsonrpc":"2.0", "method": "${method}", "params": ${paramsString}, "id": 1}`, | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
}; | ||
return await (await fetch(this.rpcUrl, content)).json(); | ||
} | ||
|
||
/** | ||
* Get the current blocknumber | ||
* @returns The current block number | ||
*/ | ||
public async blockNumber(): Promise<number> { | ||
const res = await this.rpcCall('eth_blockNumber', []); | ||
return parseInt(res.result, 16); | ||
} | ||
|
||
/** | ||
* Get the current chainId | ||
* @returns The current chainId | ||
*/ | ||
public async chainId(): Promise<number> { | ||
const res = await this.rpcCall('eth_chainId', []); | ||
return parseInt(res.result, 16); | ||
} | ||
|
||
/** | ||
* Get the current timestamp | ||
* @returns The current timestamp | ||
*/ | ||
public async timestamp(): Promise<number> { | ||
const res = await this.rpcCall('eth_getBlockByNumber', ['latest', true]); | ||
return parseInt(res.result.timestamp, 16); | ||
} | ||
|
||
/** | ||
* Get the current chainId | ||
* @param numberOfBlocks - The number of blocks to mine | ||
* @returns The current chainId | ||
*/ | ||
public async mine(numberOfBlocks = 1): Promise<void> { | ||
const res = await this.rpcCall('anvil_mine', [numberOfBlocks]); | ||
if (res.error) throw new Error(`Error mining: ${res.error.message}`); | ||
this.logger(`Mined ${numberOfBlocks} blocks`); | ||
} | ||
|
||
/** | ||
* Set the next block timestamp | ||
* @param timestamp - The timestamp to set the next block to | ||
*/ | ||
public async setNextBlockTimestamp(timestamp: number): Promise<void> { | ||
const res = await this.rpcCall('anvil_setNextBlockTimestamp', [timestamp]); | ||
if (res.error) throw new Error(`Error setting next block timestamp: ${res.error.message}`); | ||
this.logger(`Set next block timestamp to ${timestamp}`); | ||
} | ||
|
||
// Good basis for the remaining functions: | ||
// https://github.com/foundry-rs/foundry/blob/master/anvil/core/src/eth/mod.rs | ||
} | ||
|
||
/** | ||
* A class that provides utility functions for interacting with the L2 chain. | ||
*/ | ||
class L2CheatCodes { | ||
constructor( | ||
/** | ||
* The RPC client to use for interacting with the chain | ||
*/ | ||
public aztecRpc: AztecRPC, | ||
/** | ||
* The circuits wasm module used for pedersen hashing | ||
*/ | ||
public wasm: CircuitsWasm, | ||
/** | ||
* The L1 cheat codes. | ||
*/ | ||
public l1: L1CheatCodes, | ||
/** | ||
* The logger to use for the l2 cheatcodes | ||
*/ | ||
public logger = createDebugLogger('aztec:cheat_codes:l2'), | ||
) {} | ||
|
||
/** | ||
* Computes the slot value for a given map and key. | ||
* @param baseSlot - The base slot of the map (specified in noir contract) | ||
* @param key - The key to lookup in the map | ||
* @returns The storage slot of the value in the map | ||
*/ | ||
public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint): Fr { | ||
// Based on `at` function in | ||
// aztec3-packages/yarn-project/noir-contracts/src/contracts/noir-aztec/src/state_vars/map.nr | ||
return Fr.fromBuffer( | ||
pedersenPlookupCommitInputs( | ||
this.wasm, | ||
[toFr(baseSlot), toFr(key)].map(f => f.toBuffer()), | ||
), | ||
); | ||
} | ||
|
||
/** | ||
* Get the current blocknumber | ||
* @returns The current block number | ||
*/ | ||
public async blockNumber(): Promise<number> { | ||
return await this.aztecRpc.getBlockNum(); | ||
} | ||
|
||
/** | ||
* Loads the value stored at the given slot in the public storage of the given contract. | ||
* @param who - The address of the contract | ||
* @param slot - The storage slot to lookup | ||
* @returns The value stored at the given slot | ||
*/ | ||
public async loadPublic(who: AztecAddress, slot: Fr | bigint): Promise<Fr> { | ||
const storageValue = await this.aztecRpc.getPublicStorageAt(who, toFr(slot)); | ||
if (storageValue === undefined) { | ||
throw new Error(`Storage slot ${slot} not found`); | ||
} | ||
return Fr.fromBuffer(storageValue); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { AztecNodeService } from '@aztec/aztec-node'; | ||
import { AztecRPCServer } from '@aztec/aztec-rpc'; | ||
import { AztecRPC } from '@aztec/types'; | ||
|
||
import { CheatCodes } from './cheat_codes.js'; | ||
import { setup } from './utils.js'; | ||
|
||
describe('e2e_cheat_codes', () => { | ||
let aztecNode: AztecNodeService | undefined; | ||
let aztecRpcServer: AztecRPC; | ||
|
||
let cc: CheatCodes; | ||
|
||
beforeAll(async () => { | ||
({ aztecNode, aztecRpcServer, cheatCodes: cc } = await setup()); | ||
}, 100_000); | ||
|
||
afterAll(async () => { | ||
await aztecNode?.stop(); | ||
if (aztecRpcServer instanceof AztecRPCServer) { | ||
await aztecRpcServer?.stop(); | ||
} | ||
}); | ||
|
||
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); | ||
}); | ||
|
||
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); | ||
}); | ||
}); | ||
|
||
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); | ||
|
||
expect(await cc.l1.timestamp()).toBe(timestamp); | ||
|
||
await cc.l1.mine(); | ||
|
||
expect(await cc.l1.blockNumber()).toBe(blockNumber + 1); | ||
expect(await cc.l1.timestamp()).toBe(timestamp + increment); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load public is a bit ambiguous as a name, load public slot it more explicit
who could also just be address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were using this naming to make it closer to foundry cheatcodes.