@aztec/cli 0.17.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -15
- package/dest/cmds/contracts/index.js +12 -0
- package/dest/cmds/contracts/inspect_contract.js +37 -0
- package/dest/cmds/contracts/parse_parameter_struct.js +13 -0
- package/dest/cmds/devnet/bootstrap_network.js +193 -0
- package/dest/cmds/devnet/faucet.js +26 -0
- package/dest/cmds/devnet/index.js +12 -0
- package/dest/cmds/infrastructure/index.js +22 -0
- package/dest/cmds/infrastructure/sequencers.js +93 -0
- package/dest/cmds/infrastructure/setup_protocol_contract.js +31 -0
- package/dest/cmds/l1/advance_epoch.js +10 -0
- package/dest/cmds/l1/assume_proven_through.js +12 -0
- package/dest/cmds/l1/bridge_erc20.js +31 -0
- package/dest/cmds/l1/create_l1_account.js +15 -0
- package/dest/cmds/l1/deploy_l1_contracts.js +25 -0
- package/dest/cmds/l1/deploy_l1_verifier.js +54 -0
- package/dest/cmds/l1/get_l1_balance.js +33 -0
- package/dest/cmds/l1/index.js +127 -0
- package/dest/cmds/l1/prover_stats.js +145 -0
- package/dest/cmds/l1/update_l1_validators.js +186 -0
- package/dest/cmds/misc/compute_selector.js +5 -0
- package/dest/cmds/misc/example_contracts.js +6 -0
- package/dest/cmds/misc/generate_p2p_private_key.js +7 -0
- package/dest/cmds/misc/generate_secret_and_hash.js +11 -0
- package/dest/cmds/misc/generate_secret_key.js +6 -0
- package/dest/cmds/misc/index.js +36 -0
- package/dest/cmds/misc/setup_contracts.js +25 -0
- package/dest/cmds/misc/update/common.js +3 -0
- package/dest/cmds/misc/update/github.js +3 -0
- package/dest/cmds/misc/update/noir.js +45 -0
- package/dest/cmds/misc/update/npm.js +127 -0
- package/dest/cmds/misc/update/utils.js +38 -0
- package/dest/cmds/misc/update.js +52 -0
- package/dest/cmds/pxe/add_contract.js +27 -0
- package/dest/cmds/pxe/block_number.js +10 -0
- package/dest/cmds/pxe/get_account.js +10 -0
- package/dest/cmds/pxe/get_accounts.js +25 -0
- package/dest/cmds/pxe/get_block.js +9 -0
- package/dest/cmds/pxe/get_contract_data.js +31 -0
- package/dest/cmds/pxe/get_current_base_fee.js +7 -0
- package/dest/cmds/pxe/get_l1_to_l2_message_witness.js +11 -0
- package/dest/cmds/pxe/get_logs.js +51 -0
- package/dest/cmds/pxe/get_node_info.js +61 -0
- package/dest/cmds/pxe/get_pxe_info.js +11 -0
- package/dest/cmds/pxe/index.js +55 -0
- package/dest/utils/aztec.js +162 -0
- package/dest/utils/commands.js +303 -0
- package/dest/utils/encoding.js +110 -0
- package/dest/utils/github.js +3 -0
- package/dest/utils/index.js +4 -0
- package/dest/utils/inspect.js +177 -0
- package/package.json +67 -22
- package/src/cmds/contracts/index.ts +34 -0
- package/src/cmds/contracts/inspect_contract.ts +51 -0
- package/src/cmds/contracts/parse_parameter_struct.ts +27 -0
- package/src/cmds/devnet/bootstrap_network.ts +306 -0
- package/src/cmds/devnet/faucet.ts +33 -0
- package/src/cmds/devnet/index.ts +52 -0
- package/src/cmds/infrastructure/index.ts +54 -0
- package/src/cmds/infrastructure/sequencers.ts +100 -0
- package/src/cmds/infrastructure/setup_protocol_contract.ts +36 -0
- package/src/cmds/l1/advance_epoch.ts +12 -0
- package/src/cmds/l1/assume_proven_through.ts +25 -0
- package/src/cmds/l1/bridge_erc20.ts +53 -0
- package/src/cmds/l1/create_l1_account.ts +17 -0
- package/src/cmds/l1/deploy_l1_contracts.ts +55 -0
- package/src/cmds/l1/deploy_l1_verifier.ts +105 -0
- package/src/cmds/l1/get_l1_balance.ts +41 -0
- package/src/cmds/l1/index.ts +415 -0
- package/src/cmds/l1/prover_stats.ts +192 -0
- package/src/cmds/l1/update_l1_validators.ts +238 -0
- package/src/cmds/misc/compute_selector.ts +7 -0
- package/src/cmds/misc/example_contracts.ts +12 -0
- package/src/cmds/misc/generate_p2p_private_key.ts +10 -0
- package/src/cmds/misc/generate_secret_and_hash.ts +15 -0
- package/src/cmds/misc/generate_secret_key.ts +5 -0
- package/src/cmds/misc/index.ts +70 -0
- package/src/cmds/misc/setup_contracts.ts +38 -0
- package/src/cmds/misc/update/common.ts +16 -0
- package/src/cmds/misc/update/github.ts +3 -0
- package/src/cmds/misc/update/noir.ts +57 -0
- package/src/cmds/misc/update/npm.ts +154 -0
- package/src/cmds/misc/update/utils.ts +50 -0
- package/src/cmds/misc/update.ts +78 -0
- package/src/cmds/pxe/add_contract.ts +39 -0
- package/src/cmds/pxe/block_number.ts +9 -0
- package/src/cmds/pxe/get_account.ts +16 -0
- package/src/cmds/pxe/get_accounts.ts +35 -0
- package/src/cmds/pxe/get_block.ts +10 -0
- package/src/cmds/pxe/get_contract_data.ts +49 -0
- package/src/cmds/pxe/get_current_base_fee.ts +9 -0
- package/src/cmds/pxe/get_l1_to_l2_message_witness.ts +25 -0
- package/src/cmds/pxe/get_logs.ts +66 -0
- package/src/cmds/pxe/get_node_info.ts +71 -0
- package/src/cmds/pxe/get_pxe_info.ts +13 -0
- package/src/cmds/pxe/index.ts +170 -0
- package/src/utils/aztec.ts +218 -0
- package/src/utils/commands.ts +384 -0
- package/src/utils/encoding.ts +123 -0
- package/src/utils/github.ts +3 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/inspect.ts +207 -0
- package/dest/bin/index.d.ts +0 -3
- package/dest/bin/index.d.ts.map +0 -1
- package/dest/bin/index.js +0 -19
- package/dest/client.d.ts +0 -17
- package/dest/client.d.ts.map +0 -1
- package/dest/client.js +0 -60
- package/dest/cmds/add_contract.d.ts +0 -7
- package/dest/cmds/add_contract.d.ts.map +0 -1
- package/dest/cmds/add_contract.js +0 -15
- package/dest/cmds/add_note.d.ts +0 -8
- package/dest/cmds/add_note.d.ts.map +0 -1
- package/dest/cmds/add_note.js +0 -13
- package/dest/cmds/block_number.d.ts +0 -6
- package/dest/cmds/block_number.d.ts.map +0 -1
- package/dest/cmds/block_number.js +0 -10
- package/dest/cmds/call.d.ts +0 -7
- package/dest/cmds/call.d.ts.map +0 -1
- package/dest/cmds/call.js +0 -18
- package/dest/cmds/check_deploy.d.ts +0 -7
- package/dest/cmds/check_deploy.d.ts.map +0 -1
- package/dest/cmds/check_deploy.js +0 -16
- package/dest/cmds/compute_selector.d.ts +0 -6
- package/dest/cmds/compute_selector.d.ts.map +0 -1
- package/dest/cmds/compute_selector.js +0 -9
- package/dest/cmds/create_account.d.ts +0 -7
- package/dest/cmds/create_account.d.ts.map +0 -1
- package/dest/cmds/create_account.js +0 -31
- package/dest/cmds/deploy.d.ts +0 -7
- package/dest/cmds/deploy.d.ts.map +0 -1
- package/dest/cmds/deploy.js +0 -58
- package/dest/cmds/deploy_l1_contracts.d.ts +0 -6
- package/dest/cmds/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/cmds/deploy_l1_contracts.js +0 -15
- package/dest/cmds/example_contracts.d.ts +0 -6
- package/dest/cmds/example_contracts.d.ts.map +0 -1
- package/dest/cmds/example_contracts.js +0 -10
- package/dest/cmds/generate_p2p_private_key.d.ts +0 -6
- package/dest/cmds/generate_p2p_private_key.d.ts.map +0 -1
- package/dest/cmds/generate_p2p_private_key.js +0 -11
- package/dest/cmds/generate_private_key.d.ts +0 -6
- package/dest/cmds/generate_private_key.d.ts.map +0 -1
- package/dest/cmds/generate_private_key.js +0 -22
- package/dest/cmds/get_account.d.ts +0 -7
- package/dest/cmds/get_account.d.ts.map +0 -1
- package/dest/cmds/get_account.js +0 -15
- package/dest/cmds/get_accounts.d.ts +0 -6
- package/dest/cmds/get_accounts.d.ts.map +0 -1
- package/dest/cmds/get_accounts.js +0 -18
- package/dest/cmds/get_contract_data.d.ts +0 -7
- package/dest/cmds/get_contract_data.d.ts.map +0 -1
- package/dest/cmds/get_contract_data.js +0 -28
- package/dest/cmds/get_logs.d.ts +0 -7
- package/dest/cmds/get_logs.d.ts.map +0 -1
- package/dest/cmds/get_logs.js +0 -54
- package/dest/cmds/get_node_info.d.ts +0 -6
- package/dest/cmds/get_node_info.d.ts.map +0 -1
- package/dest/cmds/get_node_info.js +0 -15
- package/dest/cmds/get_recipient.d.ts +0 -7
- package/dest/cmds/get_recipient.d.ts.map +0 -1
- package/dest/cmds/get_recipient.js +0 -15
- package/dest/cmds/get_recipients.d.ts +0 -6
- package/dest/cmds/get_recipients.d.ts.map +0 -1
- package/dest/cmds/get_recipients.js +0 -18
- package/dest/cmds/get_tx_receipt.d.ts +0 -7
- package/dest/cmds/get_tx_receipt.d.ts.map +0 -1
- package/dest/cmds/get_tx_receipt.js +0 -16
- package/dest/cmds/inspect_contract.d.ts +0 -6
- package/dest/cmds/inspect_contract.d.ts.map +0 -1
- package/dest/cmds/inspect_contract.js +0 -19
- package/dest/cmds/parse_parameter_struct.d.ts +0 -6
- package/dest/cmds/parse_parameter_struct.d.ts.map +0 -1
- package/dest/cmds/parse_parameter_struct.js +0 -20
- package/dest/cmds/register_account.d.ts +0 -7
- package/dest/cmds/register_account.d.ts.map +0 -1
- package/dest/cmds/register_account.js +0 -13
- package/dest/cmds/register_recipient.d.ts +0 -7
- package/dest/cmds/register_recipient.d.ts.map +0 -1
- package/dest/cmds/register_recipient.js +0 -11
- package/dest/cmds/send.d.ts +0 -7
- package/dest/cmds/send.d.ts.map +0 -1
- package/dest/cmds/send.js +0 -27
- package/dest/cmds/unbox.d.ts +0 -7
- package/dest/cmds/unbox.d.ts.map +0 -1
- package/dest/cmds/unbox.js +0 -133
- package/dest/encoding.d.ts +0 -15
- package/dest/encoding.d.ts.map +0 -1
- package/dest/encoding.js +0 -114
- package/dest/github.d.ts +0 -4
- package/dest/github.d.ts.map +0 -1
- package/dest/github.js +0 -4
- package/dest/index.d.ts +0 -10
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -321
- package/dest/parse_args.d.ts +0 -105
- package/dest/parse_args.d.ts.map +0 -1
- package/dest/parse_args.js +0 -233
- package/dest/test/mocks.d.ts +0 -3
- package/dest/test/mocks.d.ts.map +0 -1
- package/dest/test/mocks.js +0 -65
- package/dest/update/common.d.ts +0 -17
- package/dest/update/common.d.ts.map +0 -1
- package/dest/update/common.js +0 -2
- package/dest/update/noir.d.ts +0 -10
- package/dest/update/noir.d.ts.map +0 -1
- package/dest/update/noir.js +0 -63
- package/dest/update/npm.d.ts +0 -34
- package/dest/update/npm.d.ts.map +0 -1
- package/dest/update/npm.js +0 -125
- package/dest/update/update.d.ts +0 -3
- package/dest/update/update.d.ts.map +0 -1
- package/dest/update/update.js +0 -58
- package/dest/utils.d.ts +0 -70
- package/dest/utils.d.ts.map +0 -1
- package/dest/utils.js +0 -168
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createCompatibleClient } from '@aztec/aztec.js';
|
|
2
|
+
import { createEthereumChain, createL1Clients, deployL1Contract } from '@aztec/ethereum';
|
|
3
|
+
import { HonkVerifierAbi, HonkVerifierBytecode } from '@aztec/l1-artifacts';
|
|
4
|
+
import { InvalidOptionArgumentError } from 'commander';
|
|
5
|
+
import { getContract } from 'viem';
|
|
6
|
+
export async function deployUltraHonkVerifier(rollupAddress, ethRpcUrl, l1ChainId, privateKey, mnemonic, pxeRpcUrl, bbBinaryPath, bbWorkingDirectory, log, debugLogger) {
|
|
7
|
+
if (!bbBinaryPath || !bbWorkingDirectory) {
|
|
8
|
+
throw new InvalidOptionArgumentError('Missing path to bb binary and working directory');
|
|
9
|
+
}
|
|
10
|
+
const { publicClient, walletClient } = createL1Clients(ethRpcUrl, privateKey ?? mnemonic, createEthereumChain(ethRpcUrl, l1ChainId).chainInfo);
|
|
11
|
+
if (!rollupAddress && pxeRpcUrl) {
|
|
12
|
+
const pxe = await createCompatibleClient(pxeRpcUrl, debugLogger);
|
|
13
|
+
const { l1ContractAddresses } = await pxe.getNodeInfo();
|
|
14
|
+
rollupAddress = l1ContractAddresses.rollupAddress.toString();
|
|
15
|
+
}
|
|
16
|
+
if (!rollupAddress) {
|
|
17
|
+
throw new InvalidOptionArgumentError('Missing rollup address');
|
|
18
|
+
}
|
|
19
|
+
const { RollupAbi } = await import('@aztec/l1-artifacts');
|
|
20
|
+
const rollup = getContract({
|
|
21
|
+
abi: RollupAbi,
|
|
22
|
+
address: rollupAddress,
|
|
23
|
+
client: walletClient
|
|
24
|
+
});
|
|
25
|
+
const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, HonkVerifierAbi, HonkVerifierBytecode);
|
|
26
|
+
log(`Deployed honk verifier at ${verifierAddress}`);
|
|
27
|
+
await rollup.write.setEpochVerifier([
|
|
28
|
+
verifierAddress.toString()
|
|
29
|
+
]);
|
|
30
|
+
log(`Rollup accepts only real proofs now`);
|
|
31
|
+
}
|
|
32
|
+
export async function deployMockVerifier(rollupAddress, ethRpcUrl, l1ChainId, privateKey, mnemonic, pxeRpcUrl, log, debugLogger) {
|
|
33
|
+
const { publicClient, walletClient } = createL1Clients(ethRpcUrl, privateKey ?? mnemonic, createEthereumChain(ethRpcUrl, l1ChainId).chainInfo);
|
|
34
|
+
const { MockVerifierAbi, MockVerifierBytecode, RollupAbi } = await import('@aztec/l1-artifacts');
|
|
35
|
+
const { address: mockVerifierAddress } = await deployL1Contract(walletClient, publicClient, MockVerifierAbi, MockVerifierBytecode);
|
|
36
|
+
log(`Deployed MockVerifier at ${mockVerifierAddress.toString()}`);
|
|
37
|
+
if (!rollupAddress && pxeRpcUrl) {
|
|
38
|
+
const pxe = await createCompatibleClient(pxeRpcUrl, debugLogger);
|
|
39
|
+
const { l1ContractAddresses } = await pxe.getNodeInfo();
|
|
40
|
+
rollupAddress = l1ContractAddresses.rollupAddress.toString();
|
|
41
|
+
}
|
|
42
|
+
if (!rollupAddress) {
|
|
43
|
+
throw new InvalidOptionArgumentError('Missing rollup address');
|
|
44
|
+
}
|
|
45
|
+
const rollup = getContract({
|
|
46
|
+
abi: RollupAbi,
|
|
47
|
+
address: rollupAddress,
|
|
48
|
+
client: walletClient
|
|
49
|
+
});
|
|
50
|
+
await rollup.write.setEpochVerifier([
|
|
51
|
+
mockVerifierAddress.toString()
|
|
52
|
+
]);
|
|
53
|
+
log(`Rollup accepts only fake proofs now`);
|
|
54
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createEthereumChain } from '@aztec/ethereum';
|
|
2
|
+
import { TestERC20Abi } from '@aztec/l1-artifacts';
|
|
3
|
+
import { createPublicClient, getContract, http } from 'viem';
|
|
4
|
+
import { prettyPrintJSON } from '../../utils/commands.js';
|
|
5
|
+
export async function getL1Balance(who, token, l1RpcUrl, chainId, json, log) {
|
|
6
|
+
const chain = createEthereumChain(l1RpcUrl, chainId);
|
|
7
|
+
const publicClient = createPublicClient({
|
|
8
|
+
chain: chain.chainInfo,
|
|
9
|
+
transport: http(chain.rpcUrl)
|
|
10
|
+
});
|
|
11
|
+
let balance = 0n;
|
|
12
|
+
if (token) {
|
|
13
|
+
const gasL1 = getContract({
|
|
14
|
+
address: token.toString(),
|
|
15
|
+
abi: TestERC20Abi,
|
|
16
|
+
client: publicClient
|
|
17
|
+
});
|
|
18
|
+
balance = await gasL1.read.balanceOf([
|
|
19
|
+
who.toString()
|
|
20
|
+
]);
|
|
21
|
+
} else {
|
|
22
|
+
balance = await publicClient.getBalance({
|
|
23
|
+
address: who.toString()
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (json) {
|
|
27
|
+
log(prettyPrintJSON({
|
|
28
|
+
balance
|
|
29
|
+
}));
|
|
30
|
+
} else {
|
|
31
|
+
log(`L1 balance of ${who.toString()} is ${balance.toString()}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { Option } from 'commander';
|
|
3
|
+
import { ETHEREUM_HOST, PRIVATE_KEY, l1ChainIdOption, makePxeOption, parseAztecAddress, parseBigint, parseEthereumAddress, pxeOption } from '../../utils/commands.js';
|
|
4
|
+
export function injectCommands(program, log, debugLogger) {
|
|
5
|
+
const { BB_BINARY_PATH, BB_WORKING_DIRECTORY } = process.env;
|
|
6
|
+
program.command('deploy-l1-contracts').description('Deploys all necessary Ethereum contracts for Aztec.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('--validators <string>', 'Comma separated list of validators').option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').option('-i, --mnemonic-index <number>', 'The index of the mnemonic to use in deployment', (arg)=>parseInt(arg), 0).addOption(l1ChainIdOption).option('--salt <number>', 'The optional salt to use in deployment', (arg)=>parseInt(arg)).option('--json', 'Output the contract addresses in JSON format').action(async (options)=>{
|
|
7
|
+
const { deployL1Contracts } = await import('./deploy_l1_contracts.js');
|
|
8
|
+
const initialValidators = options.validators?.split(',').map((validator)=>EthAddress.fromString(validator)) || [];
|
|
9
|
+
await deployL1Contracts(options.rpcUrl, options.l1ChainId, options.privateKey, options.mnemonic, options.mnemonicIndex, options.salt, options.json, initialValidators, log, debugLogger);
|
|
10
|
+
});
|
|
11
|
+
program.command('generate-l1-account').description('Generates a new private key for an account on L1.').option('--json', 'Output the private key in JSON format').action(async ()=>{
|
|
12
|
+
const { generateL1Account } = await import('./update_l1_validators.js');
|
|
13
|
+
const account = generateL1Account();
|
|
14
|
+
log(JSON.stringify(account, null, 2));
|
|
15
|
+
});
|
|
16
|
+
program.command('add-l1-validator').description('Adds a validator to the L1 rollup contract.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--validator <address>', 'ethereum address of the validator', parseEthereumAddress).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).option('--withdrawer <address>', 'ethereum address of the withdrawer', parseEthereumAddress).action(async (options)=>{
|
|
17
|
+
const { addL1Validator } = await import('./update_l1_validators.js');
|
|
18
|
+
await addL1Validator({
|
|
19
|
+
rpcUrl: options.rpcUrl,
|
|
20
|
+
chainId: options.l1ChainId,
|
|
21
|
+
privateKey: options.privateKey,
|
|
22
|
+
mnemonic: options.mnemonic,
|
|
23
|
+
validatorAddress: options.validator,
|
|
24
|
+
rollupAddress: options.rollup,
|
|
25
|
+
withdrawerAddress: options.withdrawer,
|
|
26
|
+
log,
|
|
27
|
+
debugLogger
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
program.command('remove-l1-validator').description('Removes a validator to the L1 rollup contract.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--validator <address>', 'ethereum address of the validator', parseEthereumAddress).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).action(async (options)=>{
|
|
31
|
+
const { removeL1Validator } = await import('./update_l1_validators.js');
|
|
32
|
+
await removeL1Validator({
|
|
33
|
+
rpcUrl: options.rpcUrl,
|
|
34
|
+
chainId: options.l1ChainId,
|
|
35
|
+
privateKey: options.privateKey,
|
|
36
|
+
mnemonic: options.mnemonic,
|
|
37
|
+
validatorAddress: options.validator,
|
|
38
|
+
rollupAddress: options.rollup,
|
|
39
|
+
log,
|
|
40
|
+
debugLogger
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
program.command('fast-forward-epochs').description('Fast forwards the epoch of the L1 rollup contract.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(l1ChainIdOption).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).option('--count <number>', 'The number of epochs to fast forward', (arg)=>BigInt(parseInt(arg)), 1n).action(async (options)=>{
|
|
44
|
+
const { fastForwardEpochs } = await import('./update_l1_validators.js');
|
|
45
|
+
await fastForwardEpochs({
|
|
46
|
+
rpcUrl: options.rpcUrl,
|
|
47
|
+
chainId: options.l1ChainId,
|
|
48
|
+
rollupAddress: options.rollup,
|
|
49
|
+
numEpochs: options.count,
|
|
50
|
+
log,
|
|
51
|
+
debugLogger
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
program.command('debug-rollup').description('Debugs the rollup contract.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(l1ChainIdOption).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).action(async (options)=>{
|
|
55
|
+
const { debugRollup } = await import('./update_l1_validators.js');
|
|
56
|
+
await debugRollup({
|
|
57
|
+
rpcUrl: options.rpcUrl,
|
|
58
|
+
chainId: options.l1ChainId,
|
|
59
|
+
privateKey: options.privateKey,
|
|
60
|
+
mnemonic: options.mnemonic,
|
|
61
|
+
rollupAddress: options.rollup,
|
|
62
|
+
log,
|
|
63
|
+
debugLogger
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
program.command('prune-rollup').description('Prunes the pending chain on the rollup contract.').requiredOption('-u, --rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-pk, --private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--rollup <address>', 'ethereum address of the rollup contract', parseEthereumAddress).action(async (options)=>{
|
|
67
|
+
const { pruneRollup } = await import('./update_l1_validators.js');
|
|
68
|
+
await pruneRollup({
|
|
69
|
+
rpcUrl: options.rpcUrl,
|
|
70
|
+
chainId: options.l1ChainId,
|
|
71
|
+
privateKey: options.privateKey,
|
|
72
|
+
mnemonic: options.mnemonic,
|
|
73
|
+
rollupAddress: options.rollup,
|
|
74
|
+
log,
|
|
75
|
+
debugLogger
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
program.command('deploy-l1-verifier').description('Deploys the rollup verifier contract').requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(new Option('--l1-chain-id <string>', 'The chain id of the L1 network').env('L1_CHAIN_ID').default('31337').makeOptionMandatory(true)).addOption(makePxeOption(false).conflicts('rollup-address')).addOption(new Option('--rollup-address <string>', 'The address of the rollup contract').env('ROLLUP_CONTRACT_ADDRESS').argParser(parseEthereumAddress).conflicts('rpc-url')).option('--l1-private-key <string>', 'The L1 private key to use for deployment', PRIVATE_KEY).option('-m, --mnemonic <string>', 'The mnemonic to use in deployment', 'test test test test test test test test test test test junk').requiredOption('--verifier <verifier>', 'Either mock or real', 'real').option('--bb <path>', 'Path to bb binary', BB_BINARY_PATH).option('--bb-working-dir <path>', 'Path to bb working directory', BB_WORKING_DIRECTORY).action(async (options)=>{
|
|
79
|
+
const { deployMockVerifier, deployUltraHonkVerifier } = await import('./deploy_l1_verifier.js');
|
|
80
|
+
if (options.verifier === 'mock') {
|
|
81
|
+
await deployMockVerifier(options.rollupAddress?.toString(), options.l1RpcUrl, options.l1ChainId, options.l1PrivateKey, options.mnemonic, options.rpcUrl, log, debugLogger);
|
|
82
|
+
} else {
|
|
83
|
+
await deployUltraHonkVerifier(options.rollupAddress?.toString(), options.l1RpcUrl, options.l1ChainId, options.l1PrivateKey, options.mnemonic, options.rpcUrl, options.bb, options.bbWorkingDir, log, debugLogger);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
program.command('bridge-erc20').description('Bridges ERC20 tokens to L2.').argument('<amount>', 'The amount of Fee Juice to mint and bridge.', parseBigint).argument('<recipient>', 'Aztec address of the recipient.', parseAztecAddress).requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-m, --mnemonic <string>', 'The mnemonic to use for deriving the Ethereum address that will mint and bridge', 'test test test test test test test test test test test junk').option('--mint', 'Mint the tokens on L1', false).option('--private', 'If the bridge should use the private flow', false).addOption(l1ChainIdOption).requiredOption('-t, --token <string>', 'The address of the token to bridge', parseEthereumAddress).requiredOption('-p, --portal <string>', 'The address of the portal contract', parseEthereumAddress).option('--l1-private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).option('--json', 'Output the claim in JSON format').action(async (amount, recipient, options)=>{
|
|
87
|
+
const { bridgeERC20 } = await import('./bridge_erc20.js');
|
|
88
|
+
await bridgeERC20(amount, recipient, options.l1RpcUrl, options.l1ChainId, options.l1PrivateKey, options.mnemonic, options.token, options.portal, options.private, options.mint, options.json, log, debugLogger);
|
|
89
|
+
});
|
|
90
|
+
program.command('create-l1-account').option('--json', 'Output the account in JSON format').action(async (options)=>{
|
|
91
|
+
const { createL1Account } = await import('./create_l1_account.js');
|
|
92
|
+
createL1Account(options.json, log);
|
|
93
|
+
});
|
|
94
|
+
program.command('get-l1-balance').description('Gets the balance of an ERC token in L1 for the given Ethereum address.').argument('<who>', 'Ethereum address to check.', parseEthereumAddress).requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).option('-t, --token <string>', 'The address of the token to check the balance of', parseEthereumAddress).addOption(l1ChainIdOption).option('--json', 'Output the balance in JSON format').action(async (who, options)=>{
|
|
95
|
+
const { getL1Balance } = await import('./get_l1_balance.js');
|
|
96
|
+
await getL1Balance(who, options.token, options.l1RpcUrl, options.l1ChainId, options.json, log);
|
|
97
|
+
});
|
|
98
|
+
program.command('set-proven-through', {
|
|
99
|
+
hidden: true
|
|
100
|
+
}).description('Instructs the L1 rollup contract to assume all blocks until the given number are automatically proven.').argument('[blockNumber]', 'The target block number, defaults to the latest pending block number.', parseBigint).requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(pxeOption).option('-m, --mnemonic <string>', 'The mnemonic to use for deriving the Ethereum address that will mint and bridge', 'test test test test test test test test test test test junk').addOption(l1ChainIdOption).option('--l1-private-key <string>', 'The private key to use for deployment', PRIVATE_KEY).action(async (blockNumber, options)=>{
|
|
101
|
+
const { assumeProvenThrough } = await import('./assume_proven_through.js');
|
|
102
|
+
await assumeProvenThrough(blockNumber, options.l1RpcUrl, options.rpcUrl, options.l1ChainId, options.l1PrivateKey, options.mnemonic, log);
|
|
103
|
+
});
|
|
104
|
+
program.command('advance-epoch').description('Use L1 cheat codes to warp time until the next epoch.').requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(pxeOption).action(async (options)=>{
|
|
105
|
+
const { advanceEpoch } = await import('./advance_epoch.js');
|
|
106
|
+
await advanceEpoch(options.l1RpcUrl, options.rpcUrl, log);
|
|
107
|
+
});
|
|
108
|
+
program.command('prover-stats', {
|
|
109
|
+
hidden: true
|
|
110
|
+
}).requiredOption('--l1-rpc-url <string>', 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', ETHEREUM_HOST).addOption(l1ChainIdOption).option('--start-block <number>', 'The L1 block number to start from', parseBigint, 1n).option('--end-block <number>', 'The last L1 block number to query', parseBigint).option('--batch-size <number>', 'The number of blocks to query in each batch', parseBigint, 100n).option('--proving-timeout <number>', 'Cutoff for proving time to consider a block', parseBigint).option('--l1-rollup-address <string>', 'Address of the rollup contract (required if node URL is not set)').option('--node-url <string>', 'JSON RPC URL of an Aztec node to retrieve the rollup contract address (required if L1 rollup address is not set)').option('--raw-logs', 'Output raw logs instead of aggregated stats').action(async (options)=>{
|
|
111
|
+
const { proverStats } = await import('./prover_stats.js');
|
|
112
|
+
const { l1RpcUrl, chainId, l1RollupAddress, startBlock, endBlock, batchSize, nodeUrl, provingTimeout, rawLogs } = options;
|
|
113
|
+
await proverStats({
|
|
114
|
+
l1RpcUrl,
|
|
115
|
+
chainId,
|
|
116
|
+
l1RollupAddress,
|
|
117
|
+
startBlock,
|
|
118
|
+
endBlock,
|
|
119
|
+
batchSize,
|
|
120
|
+
nodeUrl,
|
|
121
|
+
provingTimeout,
|
|
122
|
+
rawLogs,
|
|
123
|
+
log
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
return program;
|
|
127
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { retrieveL2ProofVerifiedEvents } from '@aztec/archiver';
|
|
2
|
+
import { createAztecNodeClient } from '@aztec/circuit-types';
|
|
3
|
+
import { EthAddress } from '@aztec/circuits.js';
|
|
4
|
+
import { createEthereumChain } from '@aztec/ethereum';
|
|
5
|
+
import { compactArray, mapValues, unique } from '@aztec/foundation/collection';
|
|
6
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
|
+
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
8
|
+
import chunk from 'lodash.chunk';
|
|
9
|
+
import groupBy from 'lodash.groupby';
|
|
10
|
+
import { createPublicClient, getAbiItem, getAddress, http } from 'viem';
|
|
11
|
+
export async function proverStats(opts) {
|
|
12
|
+
const debugLog = createLogger('cli:prover_stats');
|
|
13
|
+
const { startBlock, chainId, l1RpcUrl, l1RollupAddress, batchSize, nodeUrl, provingTimeout, endBlock, rawLogs, log } = opts;
|
|
14
|
+
if (!l1RollupAddress && !nodeUrl) {
|
|
15
|
+
throw new Error('Either L1 rollup address or node URL must be set');
|
|
16
|
+
}
|
|
17
|
+
const rollup = l1RollupAddress ? EthAddress.fromString(l1RollupAddress) : await createAztecNodeClient(nodeUrl).getL1ContractAddresses().then((a)=>a.rollupAddress);
|
|
18
|
+
const chain = createEthereumChain(l1RpcUrl, chainId).chainInfo;
|
|
19
|
+
const publicClient = createPublicClient({
|
|
20
|
+
chain,
|
|
21
|
+
transport: http(l1RpcUrl)
|
|
22
|
+
});
|
|
23
|
+
const lastBlockNum = endBlock ?? await publicClient.getBlockNumber();
|
|
24
|
+
debugLog.verbose(`Querying events on rollup at ${rollup.toString()} from ${startBlock} up to ${lastBlockNum}`);
|
|
25
|
+
// Get all events for L2 proof submissions
|
|
26
|
+
const events = await getL2ProofVerifiedEvents(startBlock, lastBlockNum, batchSize, debugLog, publicClient, rollup);
|
|
27
|
+
// If we only care for raw logs, output them
|
|
28
|
+
if (rawLogs && !provingTimeout) {
|
|
29
|
+
log(`l1_block_number, l2_block_number, prover_id, tx_hash`);
|
|
30
|
+
for (const event of events){
|
|
31
|
+
const { l1BlockNumber, l2BlockNumber, proverId, txHash } = event;
|
|
32
|
+
log(`${l1BlockNumber}, ${l2BlockNumber}, ${proverId}, ${txHash}`);
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// If we don't have a proving timeout, we can just count the number of unique blocks per prover
|
|
37
|
+
if (!provingTimeout) {
|
|
38
|
+
const stats = groupBy(events, 'proverId');
|
|
39
|
+
log(`prover_id, total_blocks_proven`);
|
|
40
|
+
for(const proverId in stats){
|
|
41
|
+
const uniqueBlocks = new Set(stats[proverId].map((e)=>e.l2BlockNumber));
|
|
42
|
+
log(`${proverId}, ${uniqueBlocks.size}`);
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// But if we do, fetch the events for each block submitted, so we can look up their timestamp
|
|
47
|
+
const blockEvents = await getL2BlockEvents(startBlock, lastBlockNum, batchSize, debugLog, publicClient, rollup);
|
|
48
|
+
debugLog.verbose(`First L2 block within range is ${blockEvents[0]?.args.blockNumber} at L1 block ${blockEvents[0]?.blockNumber}`);
|
|
49
|
+
// Get the timestamps for every block on every log, both for proof and block submissions
|
|
50
|
+
const l1BlockNumbers = unique([
|
|
51
|
+
...events.map((e)=>e.l1BlockNumber),
|
|
52
|
+
...blockEvents.map((e)=>e.blockNumber)
|
|
53
|
+
]);
|
|
54
|
+
const l1BlockTimestamps = {};
|
|
55
|
+
for (const l1Batch of chunk(l1BlockNumbers, Number(batchSize))){
|
|
56
|
+
const blocks = await Promise.all(l1Batch.map((blockNumber)=>publicClient.getBlock({
|
|
57
|
+
includeTransactions: false,
|
|
58
|
+
blockNumber
|
|
59
|
+
})));
|
|
60
|
+
debugLog.verbose(`Queried ${blocks.length} L1 blocks between ${l1Batch[0]} and ${l1Batch[l1Batch.length - 1]}`);
|
|
61
|
+
for (const block of blocks){
|
|
62
|
+
l1BlockTimestamps[block.number.toString()] = block.timestamp;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Map from l2 block number to the l1 block in which it was submitted
|
|
66
|
+
const l2BlockSubmissions = {};
|
|
67
|
+
for (const blockEvent of blockEvents){
|
|
68
|
+
l2BlockSubmissions[blockEvent.args.blockNumber.toString()] = blockEvent.blockNumber;
|
|
69
|
+
}
|
|
70
|
+
// If we want raw logs, output them
|
|
71
|
+
if (rawLogs) {
|
|
72
|
+
log(`l1_block_number, l2_block_number, l2_block_submission_timestamp, proof_timestamp, prover_id, tx_hash`);
|
|
73
|
+
for (const event of events){
|
|
74
|
+
const { l1BlockNumber, l2BlockNumber, proverId, txHash } = event;
|
|
75
|
+
const uploadedBlockNumber = l2BlockSubmissions[l2BlockNumber.toString()];
|
|
76
|
+
if (!uploadedBlockNumber) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const uploadedTimestamp = l1BlockTimestamps[uploadedBlockNumber.toString()];
|
|
80
|
+
const provenTimestamp = l1BlockTimestamps[l1BlockNumber.toString()];
|
|
81
|
+
log(`${l1BlockNumber}, ${l2BlockNumber}, ${uploadedTimestamp}, ${provenTimestamp}, ${proverId}, ${txHash}`);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Or calculate stats per prover
|
|
86
|
+
const stats = mapValues(groupBy(events, 'proverId'), (blocks, proverId)=>compactArray(blocks.map((e)=>{
|
|
87
|
+
const provenTimestamp = l1BlockTimestamps[e.l1BlockNumber.toString()];
|
|
88
|
+
const uploadedBlockNumber = l2BlockSubmissions[e.l2BlockNumber.toString()];
|
|
89
|
+
if (!uploadedBlockNumber) {
|
|
90
|
+
debugLog.verbose(`Skipping ${proverId}'s proof for L2 block ${e.l2BlockNumber} as it was before the start block`);
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const uploadedTimestamp = l1BlockTimestamps[uploadedBlockNumber.toString()];
|
|
94
|
+
const provingTime = provenTimestamp - uploadedTimestamp;
|
|
95
|
+
debugLog.debug(`prover=${e.proverId} blockNumber=${e.l2BlockNumber} uploaded=${uploadedTimestamp} proven=${provenTimestamp} time=${provingTime}`);
|
|
96
|
+
return {
|
|
97
|
+
provenTimestamp,
|
|
98
|
+
uploadedTimestamp,
|
|
99
|
+
provingTime,
|
|
100
|
+
...e
|
|
101
|
+
};
|
|
102
|
+
})));
|
|
103
|
+
log(`prover_id, blocks_proven_within_timeout, total_blocks_proven, avg_proving_time`);
|
|
104
|
+
for(const proverId in stats){
|
|
105
|
+
const blocks = stats[proverId];
|
|
106
|
+
const withinTimeout = blocks.filter((b)=>b.provingTime <= provingTimeout);
|
|
107
|
+
const uniqueBlocksWithinTimeout = new Set(withinTimeout.map((e)=>e.l2BlockNumber));
|
|
108
|
+
const uniqueBlocks = new Set(blocks.map((e)=>e.l2BlockNumber));
|
|
109
|
+
const avgProvingTime = blocks.length === 0 ? 0 : Math.ceil(Number(blocks.reduce((acc, b)=>acc + b.provingTime, 0n)) / blocks.length);
|
|
110
|
+
log(`${proverId}, ${uniqueBlocksWithinTimeout.size}, ${uniqueBlocks.size}, ${avgProvingTime}`);
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
async function getL2ProofVerifiedEvents(startBlock, lastBlockNum, batchSize, debugLog, publicClient, rollup) {
|
|
115
|
+
let blockNum = startBlock;
|
|
116
|
+
const events = [];
|
|
117
|
+
while(blockNum <= lastBlockNum){
|
|
118
|
+
const end = blockNum + batchSize > lastBlockNum + 1n ? lastBlockNum + 1n : blockNum + batchSize;
|
|
119
|
+
const newEvents = await retrieveL2ProofVerifiedEvents(publicClient, rollup, blockNum, end);
|
|
120
|
+
events.push(...newEvents);
|
|
121
|
+
debugLog.verbose(`Got ${newEvents.length} events querying l2 proof verified from block ${blockNum} to ${end}`);
|
|
122
|
+
blockNum += batchSize;
|
|
123
|
+
}
|
|
124
|
+
return events;
|
|
125
|
+
}
|
|
126
|
+
async function getL2BlockEvents(startBlock, lastBlockNum, batchSize, debugLog, publicClient, rollup) {
|
|
127
|
+
let blockNum = startBlock;
|
|
128
|
+
const events = [];
|
|
129
|
+
while(blockNum <= lastBlockNum){
|
|
130
|
+
const end = blockNum + batchSize > lastBlockNum + 1n ? lastBlockNum + 1n : blockNum + batchSize;
|
|
131
|
+
const newEvents = await publicClient.getLogs({
|
|
132
|
+
address: getAddress(rollup.toString()),
|
|
133
|
+
event: getAbiItem({
|
|
134
|
+
abi: RollupAbi,
|
|
135
|
+
name: 'L2BlockProposed'
|
|
136
|
+
}),
|
|
137
|
+
fromBlock: blockNum,
|
|
138
|
+
toBlock: end
|
|
139
|
+
});
|
|
140
|
+
events.push(...newEvents);
|
|
141
|
+
debugLog.verbose(`Got ${newEvents.length} events querying l2 block submitted from block ${blockNum} to ${end}`);
|
|
142
|
+
blockNum += batchSize;
|
|
143
|
+
}
|
|
144
|
+
return events;
|
|
145
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { EthCheatCodes, createEthereumChain, getExpectedAddress, getL1ContractsConfigEnvVars, isAnvilTestChain } from '@aztec/ethereum';
|
|
2
|
+
import { ForwarderAbi, ForwarderBytecode, RollupAbi, TestERC20Abi } from '@aztec/l1-artifacts';
|
|
3
|
+
import { createPublicClient, createWalletClient, getContract, http } from 'viem';
|
|
4
|
+
import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
|
|
5
|
+
export function generateL1Account() {
|
|
6
|
+
const privateKey = generatePrivateKey();
|
|
7
|
+
const account = privateKeyToAccount(privateKey);
|
|
8
|
+
account.address;
|
|
9
|
+
return {
|
|
10
|
+
privateKey,
|
|
11
|
+
address: account.address
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function addL1Validator({ rpcUrl, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, withdrawerAddress, log, debugLogger }) {
|
|
15
|
+
const config = getL1ContractsConfigEnvVars();
|
|
16
|
+
const dualLog = makeDualLog(log, debugLogger);
|
|
17
|
+
const publicClient = getPublicClient(rpcUrl, chainId);
|
|
18
|
+
const walletClient = getWalletClient(rpcUrl, chainId, privateKey, mnemonic);
|
|
19
|
+
const rollup = getContract({
|
|
20
|
+
address: rollupAddress.toString(),
|
|
21
|
+
abi: RollupAbi,
|
|
22
|
+
client: walletClient
|
|
23
|
+
});
|
|
24
|
+
const stakingAsset = getContract({
|
|
25
|
+
address: await rollup.read.getStakingAsset(),
|
|
26
|
+
abi: TestERC20Abi,
|
|
27
|
+
client: walletClient
|
|
28
|
+
});
|
|
29
|
+
await Promise.all([
|
|
30
|
+
await stakingAsset.write.mint([
|
|
31
|
+
walletClient.account.address,
|
|
32
|
+
config.minimumStake
|
|
33
|
+
], {}),
|
|
34
|
+
await stakingAsset.write.approve([
|
|
35
|
+
rollupAddress.toString(),
|
|
36
|
+
config.minimumStake
|
|
37
|
+
], {})
|
|
38
|
+
].map((txHash)=>publicClient.waitForTransactionReceipt({
|
|
39
|
+
hash: txHash
|
|
40
|
+
})));
|
|
41
|
+
dualLog(`Adding validator ${validatorAddress.toString()} to rollup ${rollupAddress.toString()}`);
|
|
42
|
+
const txHash = await rollup.write.deposit([
|
|
43
|
+
validatorAddress.toString(),
|
|
44
|
+
// TODO(#11451): custom forwarders
|
|
45
|
+
getExpectedAddress(ForwarderAbi, ForwarderBytecode, [
|
|
46
|
+
validatorAddress.toString()
|
|
47
|
+
], validatorAddress.toString()).address,
|
|
48
|
+
withdrawerAddress?.toString() ?? validatorAddress.toString(),
|
|
49
|
+
config.minimumStake
|
|
50
|
+
]);
|
|
51
|
+
dualLog(`Transaction hash: ${txHash}`);
|
|
52
|
+
await publicClient.waitForTransactionReceipt({
|
|
53
|
+
hash: txHash
|
|
54
|
+
});
|
|
55
|
+
if (isAnvilTestChain(chainId)) {
|
|
56
|
+
dualLog(`Funding validator on L1`);
|
|
57
|
+
const cheatCodes = new EthCheatCodes(rpcUrl, debugLogger);
|
|
58
|
+
await cheatCodes.setBalance(validatorAddress, 10n ** 20n);
|
|
59
|
+
} else {
|
|
60
|
+
const balance = await publicClient.getBalance({
|
|
61
|
+
address: validatorAddress.toString()
|
|
62
|
+
});
|
|
63
|
+
const balanceInEth = Number(balance) / 10 ** 18;
|
|
64
|
+
dualLog(`Validator balance: ${balanceInEth.toFixed(6)} ETH`);
|
|
65
|
+
if (balanceInEth === 0) {
|
|
66
|
+
dualLog(`WARNING: Validator has no balance. Remember to fund it!`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export async function removeL1Validator({ rpcUrl, chainId, privateKey, mnemonic, validatorAddress, rollupAddress, log, debugLogger }) {
|
|
71
|
+
const dualLog = makeDualLog(log, debugLogger);
|
|
72
|
+
const publicClient = getPublicClient(rpcUrl, chainId);
|
|
73
|
+
const walletClient = getWalletClient(rpcUrl, chainId, privateKey, mnemonic);
|
|
74
|
+
const rollup = getContract({
|
|
75
|
+
address: rollupAddress.toString(),
|
|
76
|
+
abi: RollupAbi,
|
|
77
|
+
client: walletClient
|
|
78
|
+
});
|
|
79
|
+
dualLog(`Removing validator ${validatorAddress.toString()} from rollup ${rollupAddress.toString()}`);
|
|
80
|
+
const txHash = await rollup.write.initiateWithdraw([
|
|
81
|
+
validatorAddress.toString(),
|
|
82
|
+
validatorAddress.toString()
|
|
83
|
+
]);
|
|
84
|
+
dualLog(`Transaction hash: ${txHash}`);
|
|
85
|
+
await publicClient.waitForTransactionReceipt({
|
|
86
|
+
hash: txHash
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export async function pruneRollup({ rpcUrl, chainId, privateKey, mnemonic, rollupAddress, log, debugLogger }) {
|
|
90
|
+
const dualLog = makeDualLog(log, debugLogger);
|
|
91
|
+
const publicClient = getPublicClient(rpcUrl, chainId);
|
|
92
|
+
const walletClient = getWalletClient(rpcUrl, chainId, privateKey, mnemonic);
|
|
93
|
+
const rollup = getContract({
|
|
94
|
+
address: rollupAddress.toString(),
|
|
95
|
+
abi: RollupAbi,
|
|
96
|
+
client: walletClient
|
|
97
|
+
});
|
|
98
|
+
dualLog(`Trying prune`);
|
|
99
|
+
const txHash = await rollup.write.prune();
|
|
100
|
+
dualLog(`Transaction hash: ${txHash}`);
|
|
101
|
+
await publicClient.waitForTransactionReceipt({
|
|
102
|
+
hash: txHash
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export async function fastForwardEpochs({ rpcUrl, chainId, rollupAddress, numEpochs, log, debugLogger }) {
|
|
106
|
+
const dualLog = makeDualLog(log, debugLogger);
|
|
107
|
+
const publicClient = getPublicClient(rpcUrl, chainId);
|
|
108
|
+
const rollup = getContract({
|
|
109
|
+
address: rollupAddress.toString(),
|
|
110
|
+
abi: RollupAbi,
|
|
111
|
+
client: publicClient
|
|
112
|
+
});
|
|
113
|
+
const cheatCodes = new EthCheatCodes(rpcUrl, debugLogger);
|
|
114
|
+
const currentSlot = await rollup.read.getCurrentSlot();
|
|
115
|
+
const l2SlotsInEpoch = await rollup.read.getEpochDuration();
|
|
116
|
+
const timestamp = await rollup.read.getTimestampForSlot([
|
|
117
|
+
currentSlot + l2SlotsInEpoch * numEpochs
|
|
118
|
+
]);
|
|
119
|
+
dualLog(`Fast forwarding ${numEpochs} epochs to ${timestamp}`);
|
|
120
|
+
try {
|
|
121
|
+
await cheatCodes.warp(Number(timestamp));
|
|
122
|
+
dualLog(`Fast forwarded ${numEpochs} epochs to ${timestamp}`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof Error && error.message.includes("is lower than or equal to previous block's timestamp")) {
|
|
125
|
+
dualLog(`Someone else fast forwarded the chain to a point after/equal to the target time`);
|
|
126
|
+
} else {
|
|
127
|
+
// Re-throw other errors
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export async function debugRollup({ rpcUrl, chainId, rollupAddress, log }) {
|
|
133
|
+
const config = getL1ContractsConfigEnvVars();
|
|
134
|
+
const publicClient = getPublicClient(rpcUrl, chainId);
|
|
135
|
+
const rollup = getContract({
|
|
136
|
+
address: rollupAddress.toString(),
|
|
137
|
+
abi: RollupAbi,
|
|
138
|
+
client: publicClient
|
|
139
|
+
});
|
|
140
|
+
const pendingNum = await rollup.read.getPendingBlockNumber();
|
|
141
|
+
log(`Pending block num: ${pendingNum}`);
|
|
142
|
+
const provenNum = await rollup.read.getProvenBlockNumber();
|
|
143
|
+
log(`Proven block num: ${provenNum}`);
|
|
144
|
+
const validators = await rollup.read.getAttesters();
|
|
145
|
+
log(`Validators: ${validators.map((v)=>v.toString()).join(', ')}`);
|
|
146
|
+
const committee = await rollup.read.getCurrentEpochCommittee();
|
|
147
|
+
log(`Committee: ${committee.map((v)=>v.toString()).join(', ')}`);
|
|
148
|
+
const archive = await rollup.read.archive();
|
|
149
|
+
log(`Archive: ${archive}`);
|
|
150
|
+
const epochNum = await rollup.read.getCurrentEpoch();
|
|
151
|
+
log(`Current epoch: ${epochNum}`);
|
|
152
|
+
const slot = await rollup.read.getCurrentSlot();
|
|
153
|
+
log(`Current slot: ${slot}`);
|
|
154
|
+
const proposerDuringPrevL1Block = await rollup.read.getCurrentProposer();
|
|
155
|
+
log(`Proposer during previous L1 block: ${proposerDuringPrevL1Block}`);
|
|
156
|
+
const nextBlockTS = BigInt((await publicClient.getBlock()).timestamp + BigInt(config.ethereumSlotDuration));
|
|
157
|
+
const proposer = await rollup.read.getProposerAt([
|
|
158
|
+
nextBlockTS
|
|
159
|
+
]);
|
|
160
|
+
log(`Proposer NOW: ${proposer.toString()}`);
|
|
161
|
+
}
|
|
162
|
+
function makeDualLog(log, debugLogger) {
|
|
163
|
+
return (msg)=>{
|
|
164
|
+
log(msg);
|
|
165
|
+
debugLogger.info(msg);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function getPublicClient(rpcUrl, chainId) {
|
|
169
|
+
const chain = createEthereumChain(rpcUrl, chainId);
|
|
170
|
+
return createPublicClient({
|
|
171
|
+
chain: chain.chainInfo,
|
|
172
|
+
transport: http(rpcUrl)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function getWalletClient(rpcUrl, chainId, privateKey, mnemonic) {
|
|
176
|
+
if (!privateKey && !mnemonic) {
|
|
177
|
+
throw new Error('Either privateKey or mnemonic must be provided to create a wallet client');
|
|
178
|
+
}
|
|
179
|
+
const chain = createEthereumChain(rpcUrl, chainId);
|
|
180
|
+
const account = !privateKey ? mnemonicToAccount(mnemonic) : privateKeyToAccount(`${privateKey.startsWith('0x') ? '' : '0x'}${privateKey}`);
|
|
181
|
+
return createWalletClient({
|
|
182
|
+
account,
|
|
183
|
+
chain: chain.chainInfo,
|
|
184
|
+
transport: http(rpcUrl)
|
|
185
|
+
});
|
|
186
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getExampleContractNames } from '../../utils/aztec.js';
|
|
2
|
+
export async function exampleContracts(log) {
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4
|
+
// @ts-ignore - Importing noir-contracts.js even in devDeps results in a circular dependency error. Need to ignore because this line doesn't cause an error in a dev environment
|
|
5
|
+
return (await getExampleContractNames()).filter((name)=>name !== 'AvmTest').sort().forEach((name)=>log(name));
|
|
6
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createSecp256k1PeerId } from '@libp2p/peer-id-factory';
|
|
2
|
+
export async function generateP2PPrivateKey(log) {
|
|
3
|
+
const peerId = await createSecp256k1PeerId();
|
|
4
|
+
const exportedPeerId = Buffer.from(peerId.privateKey).toString('hex');
|
|
5
|
+
log(`Private key: ${exportedPeerId}`);
|
|
6
|
+
log(`Peer Id: ${peerId}`);
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { computeSecretHash } from '@aztec/aztec.js';
|
|
2
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
export function generateSecretAndHash(log) {
|
|
4
|
+
const secret = Fr.random();
|
|
5
|
+
// We hash this the same way that aztec nr hash does.
|
|
6
|
+
const secretHash = computeSecretHash(secret);
|
|
7
|
+
log(`
|
|
8
|
+
Secret: ${secret}
|
|
9
|
+
Secret hash: ${secretHash}
|
|
10
|
+
`);
|
|
11
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { prettyPrintJSON } from '../../utils/commands.js';
|
|
2
|
+
export function injectCommands(program, log) {
|
|
3
|
+
program.command('generate-keys').summary('Generates encryption and signing private keys.').description('Generates and encryption and signing private key pair.').option('--json', 'Output the keys in JSON format').action(async ({ json })=>{
|
|
4
|
+
const { generateSecretKey } = await import('./generate_secret_key.js');
|
|
5
|
+
const { secretKey } = generateSecretKey();
|
|
6
|
+
if (json) {
|
|
7
|
+
log(prettyPrintJSON({
|
|
8
|
+
secretKey: secretKey.toString()
|
|
9
|
+
}));
|
|
10
|
+
} else {
|
|
11
|
+
log(`Secret Key: ${secretKey}`);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
program.command('generate-p2p-private-key').summary('Generates a LibP2P peer private key.').description('Generates a private key that can be used for running a node on a LibP2P network.').action(async ()=>{
|
|
15
|
+
const { generateP2PPrivateKey } = await import('./generate_p2p_private_key.js');
|
|
16
|
+
await generateP2PPrivateKey(log);
|
|
17
|
+
});
|
|
18
|
+
program.command('example-contracts').description('Lists the example contracts available to deploy from @aztec/noir-contracts.js').action(async ()=>{
|
|
19
|
+
const { exampleContracts } = await import('./example_contracts.js');
|
|
20
|
+
await exampleContracts(log);
|
|
21
|
+
});
|
|
22
|
+
program.command('compute-selector').description('Given a function signature, it computes a selector').argument('<functionSignature>', 'Function signature to compute selector for e.g. foo(Field)').action(async (functionSignature)=>{
|
|
23
|
+
const { computeSelector } = await import('./compute_selector.js');
|
|
24
|
+
await computeSelector(functionSignature, log);
|
|
25
|
+
});
|
|
26
|
+
program.command('generate-secret-and-hash').description('Generates an arbitrary secret (Fr), and its hash (using aztec-nr defaults)').action(async ()=>{
|
|
27
|
+
const { generateSecretAndHash } = await import('./generate_secret_and_hash.js');
|
|
28
|
+
generateSecretAndHash(log);
|
|
29
|
+
});
|
|
30
|
+
program.command('update').description('Updates Nodejs and Noir dependencies').argument('[projectPath]', 'Path to the project directory', process.cwd()).option('--contract [paths...]', 'Paths to contracts to update dependencies', []).option('--aztec-version <semver>', 'The version to update Aztec packages to. Defaults to latest', 'latest').action(async (projectPath, options)=>{
|
|
31
|
+
const { updateProject } = await import('./update.js');
|
|
32
|
+
const { contract, aztecVersion } = options;
|
|
33
|
+
await updateProject(projectPath, contract, aztecVersion, log);
|
|
34
|
+
});
|
|
35
|
+
return program;
|
|
36
|
+
}
|