@aztec/cli 3.0.0-nightly.20250908 → 3.0.0-nightly.20250911
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/dest/cmds/devnet/bootstrap_network.d.ts.map +1 -1
- package/dest/cmds/devnet/bootstrap_network.js +11 -10
- package/dest/cmds/infrastructure/index.d.ts.map +1 -1
- package/dest/cmds/infrastructure/index.js +2 -2
- package/dest/cmds/infrastructure/setup_l2_contract.d.ts +1 -1
- package/dest/cmds/infrastructure/setup_l2_contract.d.ts.map +1 -1
- package/dest/cmds/infrastructure/setup_l2_contract.js +10 -14
- package/dest/cmds/l1/deploy_l1_contracts.js +2 -2
- package/dest/cmds/l1/deploy_new_rollup.js +2 -2
- package/dest/cmds/l1/index.d.ts.map +1 -1
- package/dest/cmds/l1/index.js +9 -7
- package/dest/cmds/l1/update_l1_validators.d.ts +5 -0
- package/dest/cmds/l1/update_l1_validators.d.ts.map +1 -1
- package/dest/cmds/l1/update_l1_validators.js +52 -0
- package/dest/config/chain_l2_config.d.ts +32 -0
- package/dest/config/chain_l2_config.d.ts.map +1 -0
- package/dest/config/chain_l2_config.js +291 -0
- package/dest/config/get_l1_config.d.ts +8 -0
- package/dest/config/get_l1_config.d.ts.map +1 -0
- package/dest/config/get_l1_config.js +22 -0
- package/dest/config/index.d.ts +3 -0
- package/dest/config/index.d.ts.map +1 -0
- package/dest/config/index.js +2 -0
- package/dest/utils/setup_contracts.d.ts +3 -3
- package/dest/utils/setup_contracts.d.ts.map +1 -1
- package/dest/utils/setup_contracts.js +9 -19
- package/package.json +26 -23
- package/src/cmds/devnet/bootstrap_network.ts +15 -10
- package/src/cmds/infrastructure/index.ts +1 -9
- package/src/cmds/infrastructure/setup_l2_contract.ts +10 -17
- package/src/cmds/l1/deploy_l1_contracts.ts +2 -2
- package/src/cmds/l1/deploy_new_rollup.ts +2 -2
- package/src/cmds/l1/index.ts +16 -16
- package/src/cmds/l1/update_l1_validators.ts +74 -0
- package/src/config/chain_l2_config.ts +382 -0
- package/src/config/get_l1_config.ts +28 -0
- package/src/config/index.ts +2 -0
- package/src/utils/setup_contracts.ts +6 -36
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
2
2
|
import { type Operator, getL1ContractsConfigEnvVars } from '@aztec/ethereum';
|
|
3
3
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
import type { LogFn, Logger } from '@aztec/foundation/log';
|
|
@@ -25,7 +25,7 @@ export async function deployNewRollup(
|
|
|
25
25
|
) {
|
|
26
26
|
const config = getL1ContractsConfigEnvVars();
|
|
27
27
|
|
|
28
|
-
const initialAccounts = testAccounts ? await
|
|
28
|
+
const initialAccounts = testAccounts ? await getInitialTestAccountsData() : [];
|
|
29
29
|
const sponsoredFPCAddress = sponsoredFPC ? await getSponsoredFPCAddress() : [];
|
|
30
30
|
const initialFundedAccounts = initialAccounts.map(a => a.address).concat(sponsoredFPCAddress);
|
|
31
31
|
const { genesisArchiveRoot, fundingNeeded } = await getGenesisValues(initialFundedAccounts);
|
package/src/cmds/l1/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
2
|
import type { LogFn, Logger } from '@aztec/foundation/log';
|
|
3
|
-
import { withoutHexPrefix } from '@aztec/foundation/string';
|
|
4
3
|
|
|
5
4
|
import { type Command, Option } from 'commander';
|
|
6
5
|
|
|
6
|
+
import { getL1RollupAddressFromEnv } from '../../config/get_l1_config.js';
|
|
7
7
|
import {
|
|
8
8
|
ETHEREUM_HOSTS,
|
|
9
9
|
MNEMONIC,
|
|
@@ -26,6 +26,8 @@ const l1RpcUrlsOption = new Option(
|
|
|
26
26
|
.makeOptionMandatory(true)
|
|
27
27
|
.argParser((arg: string) => arg.split(',').map(url => url.trim()));
|
|
28
28
|
|
|
29
|
+
const networkOption = new Option('--network <string>', 'Network to execute against').env('NETWORK');
|
|
30
|
+
|
|
29
31
|
export function injectCommands(program: Command, log: LogFn, debugLogger: Logger) {
|
|
30
32
|
program
|
|
31
33
|
.command('deploy-l1-contracts')
|
|
@@ -285,8 +287,9 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
|
|
|
285
287
|
|
|
286
288
|
program
|
|
287
289
|
.command('add-l1-validator')
|
|
288
|
-
.description('Adds a validator to the L1 rollup contract.')
|
|
290
|
+
.description('Adds a validator to the L1 rollup contract via a direct deposit.')
|
|
289
291
|
.addOption(l1RpcUrlsOption)
|
|
292
|
+
.addOption(networkOption)
|
|
290
293
|
.option('-pk, --private-key <string>', 'The private key to use sending the transaction', PRIVATE_KEY)
|
|
291
294
|
.option(
|
|
292
295
|
'-m, --mnemonic <string>',
|
|
@@ -295,32 +298,29 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: Logger
|
|
|
295
298
|
)
|
|
296
299
|
.addOption(l1ChainIdOption)
|
|
297
300
|
.option('--attester <address>', 'ethereum address of the attester', parseEthereumAddress)
|
|
301
|
+
.option('--withdrawer <address>', 'ethereum address of the withdrawer', parseEthereumAddress)
|
|
298
302
|
.option(
|
|
299
303
|
'--bls-secret-key <string>',
|
|
300
304
|
'The BN254 scalar field element used as a secret key for BLS signatures. Will be associated with the attester address.',
|
|
301
305
|
parseBigint,
|
|
302
306
|
)
|
|
303
|
-
.option('--
|
|
304
|
-
.option('--
|
|
305
|
-
Buffer.from(withoutHexPrefix(arg), 'hex'),
|
|
306
|
-
)
|
|
307
|
-
.option(
|
|
308
|
-
'--merkle-proof <string>',
|
|
309
|
-
'The merkle proof to use for the attestation (comma separated list of 32 byte buffers)',
|
|
310
|
-
arg => arg.split(','),
|
|
311
|
-
)
|
|
307
|
+
.option('--move-with-latest-rollup', 'Whether to move with the latest rollup', true)
|
|
308
|
+
.option('--rollup <string>', 'Rollup contract address', parseEthereumAddress)
|
|
312
309
|
.action(async options => {
|
|
313
|
-
const {
|
|
314
|
-
|
|
310
|
+
const { addL1ValidatorViaRollup } = await import('./update_l1_validators.js');
|
|
311
|
+
|
|
312
|
+
const rollupAddress = options.rollup ?? (await getL1RollupAddressFromEnv(options.l1RpcUrls, options.l1ChainId));
|
|
313
|
+
|
|
314
|
+
await addL1ValidatorViaRollup({
|
|
315
315
|
rpcUrls: options.l1RpcUrls,
|
|
316
316
|
chainId: options.l1ChainId,
|
|
317
317
|
privateKey: options.privateKey,
|
|
318
318
|
mnemonic: options.mnemonic,
|
|
319
319
|
attesterAddress: options.attester,
|
|
320
|
-
stakingAssetHandlerAddress: options.stakingAssetHandler,
|
|
321
|
-
merkleProof: options.merkleProof,
|
|
322
|
-
proofParams: options.proof,
|
|
323
320
|
blsSecretKey: options.blsSecretKey,
|
|
321
|
+
withdrawerAddress: options.withdrawer,
|
|
322
|
+
rollupAddress,
|
|
323
|
+
moveWithLatestRollup: options.moveWithLatestRollup,
|
|
324
324
|
log,
|
|
325
325
|
debugLogger,
|
|
326
326
|
});
|
|
@@ -131,6 +131,80 @@ export async function addL1Validator({
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
export async function addL1ValidatorViaRollup({
|
|
135
|
+
rpcUrls,
|
|
136
|
+
chainId,
|
|
137
|
+
privateKey,
|
|
138
|
+
mnemonic,
|
|
139
|
+
attesterAddress,
|
|
140
|
+
withdrawerAddress,
|
|
141
|
+
blsSecretKey,
|
|
142
|
+
moveWithLatestRollup,
|
|
143
|
+
rollupAddress,
|
|
144
|
+
log,
|
|
145
|
+
debugLogger,
|
|
146
|
+
}: RollupCommandArgs &
|
|
147
|
+
LoggerArgs & {
|
|
148
|
+
blsSecretKey: bigint; // scalar field element of BN254
|
|
149
|
+
attesterAddress: EthAddress;
|
|
150
|
+
moveWithLatestRollup: boolean;
|
|
151
|
+
}) {
|
|
152
|
+
const dualLog = makeDualLog(log, debugLogger);
|
|
153
|
+
const account = getAccount(privateKey, mnemonic);
|
|
154
|
+
const chain = createEthereumChain(rpcUrls, chainId);
|
|
155
|
+
const l1Client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
|
|
156
|
+
|
|
157
|
+
dualLog(`Adding validator ${attesterAddress} to rollup ${rollupAddress.toString()} via direct deposit`);
|
|
158
|
+
|
|
159
|
+
if (!withdrawerAddress) {
|
|
160
|
+
throw new Error(`Withdrawer address required`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const rollup = getContract({
|
|
164
|
+
address: rollupAddress.toString(),
|
|
165
|
+
abi: RollupAbi,
|
|
166
|
+
client: l1Client,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const gseAddress = await rollup.read.getGSE();
|
|
170
|
+
|
|
171
|
+
const gse = new GSEContract(l1Client, gseAddress);
|
|
172
|
+
|
|
173
|
+
const registrationTuple = await gse.makeRegistrationTuple(blsSecretKey);
|
|
174
|
+
|
|
175
|
+
const l1TxUtils = createL1TxUtilsFromViemWallet(l1Client, debugLogger);
|
|
176
|
+
|
|
177
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
|
|
178
|
+
to: rollupAddress.toString(),
|
|
179
|
+
data: encodeFunctionData({
|
|
180
|
+
abi: RollupAbi,
|
|
181
|
+
functionName: 'deposit',
|
|
182
|
+
args: [
|
|
183
|
+
attesterAddress.toString(),
|
|
184
|
+
withdrawerAddress.toString(),
|
|
185
|
+
registrationTuple.publicKeyInG1,
|
|
186
|
+
registrationTuple.publicKeyInG2,
|
|
187
|
+
registrationTuple.proofOfPossession,
|
|
188
|
+
moveWithLatestRollup,
|
|
189
|
+
],
|
|
190
|
+
}),
|
|
191
|
+
abi: StakingAssetHandlerAbi,
|
|
192
|
+
});
|
|
193
|
+
dualLog(`Transaction hash: ${receipt.transactionHash}`);
|
|
194
|
+
await l1Client.waitForTransactionReceipt({ hash: receipt.transactionHash });
|
|
195
|
+
if (isAnvilTestChain(chainId)) {
|
|
196
|
+
dualLog(`Funding validator on L1`);
|
|
197
|
+
const cheatCodes = new EthCheatCodes(rpcUrls, debugLogger);
|
|
198
|
+
await cheatCodes.setBalance(attesterAddress, 10n ** 20n);
|
|
199
|
+
} else {
|
|
200
|
+
const balance = await l1Client.getBalance({ address: attesterAddress.toString() });
|
|
201
|
+
dualLog(`Validator balance: ${formatEther(balance)} ETH`);
|
|
202
|
+
if (balance === 0n) {
|
|
203
|
+
dualLog(`WARNING: Proposer has no balance. Remember to fund it!`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
134
208
|
export async function removeL1Validator({
|
|
135
209
|
rpcUrls,
|
|
136
210
|
chainId,
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { DefaultL1ContractsConfig, type L1ContractsConfig } from '@aztec/ethereum';
|
|
2
|
+
import type { EnvVar, NetworkNames } from '@aztec/foundation/config';
|
|
3
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
+
import type { SharedNodeConfig } from '@aztec/node-lib/config';
|
|
5
|
+
import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
6
|
+
|
|
7
|
+
import { mkdir, readFile, stat, writeFile } from 'fs/promises';
|
|
8
|
+
import path, { dirname, join } from 'path';
|
|
9
|
+
|
|
10
|
+
import publicIncludeMetrics from '../../public_include_metric_prefixes.json' with { type: 'json' };
|
|
11
|
+
|
|
12
|
+
export type L2ChainConfig = L1ContractsConfig &
|
|
13
|
+
Omit<SlasherConfig, 'slashValidatorsNever' | 'slashValidatorsAlways'> & {
|
|
14
|
+
l1ChainId: number;
|
|
15
|
+
testAccounts: boolean;
|
|
16
|
+
sponsoredFPC: boolean;
|
|
17
|
+
p2pEnabled: boolean;
|
|
18
|
+
p2pBootstrapNodes: string[];
|
|
19
|
+
registryAddress: string;
|
|
20
|
+
slashFactoryAddress: string;
|
|
21
|
+
feeAssetHandlerAddress: string;
|
|
22
|
+
seqMinTxsPerBlock: number;
|
|
23
|
+
seqMaxTxsPerBlock: number;
|
|
24
|
+
realProofs: boolean;
|
|
25
|
+
snapshotsUrl: string;
|
|
26
|
+
autoUpdate: SharedNodeConfig['autoUpdate'];
|
|
27
|
+
autoUpdateUrl?: string;
|
|
28
|
+
maxTxPoolSize: number;
|
|
29
|
+
publicIncludeMetrics?: string[];
|
|
30
|
+
publicMetricsCollectorUrl?: string;
|
|
31
|
+
publicMetricsCollectFrom?: string[];
|
|
32
|
+
|
|
33
|
+
// Control whether sentinel is enabled or not. Needed for slashing
|
|
34
|
+
sentinelEnabled: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const DefaultSlashConfig = {
|
|
38
|
+
/** Tally-style slashing */
|
|
39
|
+
slasherFlavor: 'tally',
|
|
40
|
+
/** Allow one round for vetoing */
|
|
41
|
+
slashingExecutionDelayInRounds: 1,
|
|
42
|
+
/** How long for a slash payload to be executed */
|
|
43
|
+
slashingLifetimeInRounds: 5,
|
|
44
|
+
/** Allow 2 rounds to discover faults */
|
|
45
|
+
slashingOffsetInRounds: 2,
|
|
46
|
+
/** No slash vetoer */
|
|
47
|
+
slashingVetoer: EthAddress.ZERO,
|
|
48
|
+
/** Use default slash amounts */
|
|
49
|
+
slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
|
|
50
|
+
slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
|
|
51
|
+
slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
|
|
52
|
+
|
|
53
|
+
// Slashing stuff
|
|
54
|
+
slashMinPenaltyPercentage: 0.5,
|
|
55
|
+
slashMaxPenaltyPercentage: 2.0,
|
|
56
|
+
slashInactivityTargetPercentage: 0.7,
|
|
57
|
+
slashInactivityConsecutiveEpochThreshold: 1,
|
|
58
|
+
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
|
|
59
|
+
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
|
|
60
|
+
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
|
|
61
|
+
slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
|
|
62
|
+
slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
|
|
63
|
+
slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
|
|
64
|
+
slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
|
|
65
|
+
slashMaxPayloadSize: 50,
|
|
66
|
+
slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
|
|
67
|
+
slashOffenseExpirationRounds: 8,
|
|
68
|
+
sentinelEnabled: true,
|
|
69
|
+
} satisfies Partial<L2ChainConfig>;
|
|
70
|
+
|
|
71
|
+
export const stagingIgnitionL2ChainConfig: L2ChainConfig = {
|
|
72
|
+
l1ChainId: 11155111,
|
|
73
|
+
testAccounts: true,
|
|
74
|
+
sponsoredFPC: false,
|
|
75
|
+
p2pEnabled: true,
|
|
76
|
+
p2pBootstrapNodes: [],
|
|
77
|
+
registryAddress: '0xf299347e765cfb27f913bde8e4983fd0f195676f',
|
|
78
|
+
slashFactoryAddress: '',
|
|
79
|
+
feeAssetHandlerAddress: '',
|
|
80
|
+
seqMinTxsPerBlock: 0,
|
|
81
|
+
seqMaxTxsPerBlock: 0,
|
|
82
|
+
realProofs: true,
|
|
83
|
+
snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-ignition/',
|
|
84
|
+
autoUpdate: 'config-and-version',
|
|
85
|
+
autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-ignition.json',
|
|
86
|
+
maxTxPoolSize: 100_000_000, // 100MB
|
|
87
|
+
publicIncludeMetrics,
|
|
88
|
+
publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
|
|
89
|
+
publicMetricsCollectFrom: ['sequencer'],
|
|
90
|
+
|
|
91
|
+
...DefaultL1ContractsConfig,
|
|
92
|
+
...DefaultSlashConfig,
|
|
93
|
+
|
|
94
|
+
/** How many seconds an L1 slot lasts. */
|
|
95
|
+
ethereumSlotDuration: 12,
|
|
96
|
+
/** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
|
|
97
|
+
aztecSlotDuration: 36,
|
|
98
|
+
/** How many L2 slots an epoch lasts. */
|
|
99
|
+
aztecEpochDuration: 32,
|
|
100
|
+
/** The target validator committee size. */
|
|
101
|
+
aztecTargetCommitteeSize: 48,
|
|
102
|
+
/** The number of epochs after an epoch ends that proofs are still accepted. */
|
|
103
|
+
aztecProofSubmissionEpochs: 1,
|
|
104
|
+
/** The mana target for the rollup */
|
|
105
|
+
manaTarget: 0n,
|
|
106
|
+
/** The proving cost per mana */
|
|
107
|
+
provingCostPerMana: 0n,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const stagingPublicL2ChainConfig: L2ChainConfig = {
|
|
111
|
+
l1ChainId: 11155111,
|
|
112
|
+
testAccounts: false,
|
|
113
|
+
sponsoredFPC: true,
|
|
114
|
+
p2pEnabled: true,
|
|
115
|
+
p2pBootstrapNodes: [],
|
|
116
|
+
registryAddress: '0x2e48addca360da61e4d6c21ff2b1961af56eb83b',
|
|
117
|
+
slashFactoryAddress: '0xe19410632fd00695bc5a08dd82044b7b26317742',
|
|
118
|
+
feeAssetHandlerAddress: '0xb46dc3d91f849999330b6dd93473fa29fc45b076',
|
|
119
|
+
seqMinTxsPerBlock: 0,
|
|
120
|
+
seqMaxTxsPerBlock: 20,
|
|
121
|
+
realProofs: true,
|
|
122
|
+
snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/staging-public/',
|
|
123
|
+
autoUpdate: 'config-and-version',
|
|
124
|
+
autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/staging-public.json',
|
|
125
|
+
publicIncludeMetrics,
|
|
126
|
+
publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
|
|
127
|
+
publicMetricsCollectFrom: ['sequencer'],
|
|
128
|
+
maxTxPoolSize: 100_000_000, // 100MB
|
|
129
|
+
|
|
130
|
+
// Deployment stuff
|
|
131
|
+
/** How many seconds an L1 slot lasts. */
|
|
132
|
+
ethereumSlotDuration: 12,
|
|
133
|
+
/** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
|
|
134
|
+
aztecSlotDuration: 36,
|
|
135
|
+
/** How many L2 slots an epoch lasts. */
|
|
136
|
+
aztecEpochDuration: 32,
|
|
137
|
+
/** The target validator committee size. */
|
|
138
|
+
aztecTargetCommitteeSize: 48,
|
|
139
|
+
/** The local ejection threshold for a validator. Stricter than ejectionThreshold but local to a specific rollup */
|
|
140
|
+
localEjectionThreshold: DefaultL1ContractsConfig.localEjectionThreshold,
|
|
141
|
+
/** The number of epochs after an epoch ends that proofs are still accepted. */
|
|
142
|
+
aztecProofSubmissionEpochs: 1,
|
|
143
|
+
/** The deposit amount for a validator */
|
|
144
|
+
activationThreshold: DefaultL1ContractsConfig.activationThreshold,
|
|
145
|
+
/** The minimum stake for a validator. */
|
|
146
|
+
ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
|
|
147
|
+
/** The slashing round size */
|
|
148
|
+
slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
|
|
149
|
+
/** Governance proposing round size */
|
|
150
|
+
governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
|
|
151
|
+
/** The mana target for the rollup */
|
|
152
|
+
manaTarget: DefaultL1ContractsConfig.manaTarget,
|
|
153
|
+
/** The proving cost per mana */
|
|
154
|
+
provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
|
|
155
|
+
/** Exit delay for stakers */
|
|
156
|
+
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
|
|
157
|
+
|
|
158
|
+
...DefaultSlashConfig,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const testnetL2ChainConfig: L2ChainConfig = {
|
|
162
|
+
l1ChainId: 11155111,
|
|
163
|
+
testAccounts: false,
|
|
164
|
+
sponsoredFPC: true,
|
|
165
|
+
p2pEnabled: true,
|
|
166
|
+
p2pBootstrapNodes: [],
|
|
167
|
+
registryAddress: '0xcfe61b2574984326679cd15c6566fbd4a724f3b4',
|
|
168
|
+
slashFactoryAddress: '0x58dc5b14f9d3085c9106f5b8208a1026f94614f0',
|
|
169
|
+
feeAssetHandlerAddress: '0x7abdec6e68ae27c37feb6a77371382a109ec4763',
|
|
170
|
+
seqMinTxsPerBlock: 0,
|
|
171
|
+
seqMaxTxsPerBlock: 20,
|
|
172
|
+
realProofs: true,
|
|
173
|
+
snapshotsUrl: 'https://storage.googleapis.com/aztec-testnet/snapshots/testnet/',
|
|
174
|
+
autoUpdate: 'config-and-version',
|
|
175
|
+
autoUpdateUrl: 'https://storage.googleapis.com/aztec-testnet/auto-update/testnet.json',
|
|
176
|
+
maxTxPoolSize: 100_000_000, // 100MB
|
|
177
|
+
publicIncludeMetrics,
|
|
178
|
+
publicMetricsCollectorUrl: 'https://telemetry.alpha-testnet.aztec-labs.com/v1/metrics',
|
|
179
|
+
publicMetricsCollectFrom: ['sequencer'],
|
|
180
|
+
|
|
181
|
+
// Deployment stuff
|
|
182
|
+
/** How many seconds an L1 slot lasts. */
|
|
183
|
+
ethereumSlotDuration: 12,
|
|
184
|
+
/** How many seconds an L2 slots lasts (must be multiple of ethereum slot duration). */
|
|
185
|
+
aztecSlotDuration: 36,
|
|
186
|
+
/** How many L2 slots an epoch lasts. */
|
|
187
|
+
aztecEpochDuration: 32,
|
|
188
|
+
/** The target validator committee size. */
|
|
189
|
+
aztecTargetCommitteeSize: 48,
|
|
190
|
+
/** The number of epochs after an epoch ends that proofs are still accepted. */
|
|
191
|
+
aztecProofSubmissionEpochs: 1,
|
|
192
|
+
/** The deposit amount for a validator */
|
|
193
|
+
activationThreshold: DefaultL1ContractsConfig.activationThreshold,
|
|
194
|
+
/** The minimum stake for a validator. */
|
|
195
|
+
ejectionThreshold: DefaultL1ContractsConfig.ejectionThreshold,
|
|
196
|
+
/** The local ejection threshold for a validator. Stricter than ejectionThreshold but local to a specific rollup */
|
|
197
|
+
localEjectionThreshold: DefaultL1ContractsConfig.localEjectionThreshold,
|
|
198
|
+
/** The slashing round size */
|
|
199
|
+
slashingRoundSizeInEpochs: DefaultL1ContractsConfig.slashingRoundSizeInEpochs,
|
|
200
|
+
/** Governance proposing round size */
|
|
201
|
+
governanceProposerRoundSize: DefaultL1ContractsConfig.governanceProposerRoundSize,
|
|
202
|
+
/** The mana target for the rollup */
|
|
203
|
+
manaTarget: DefaultL1ContractsConfig.manaTarget,
|
|
204
|
+
/** The proving cost per mana */
|
|
205
|
+
provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
|
|
206
|
+
/** Exit delay for stakers */
|
|
207
|
+
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
|
|
208
|
+
|
|
209
|
+
...DefaultSlashConfig,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const BOOTNODE_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour;
|
|
213
|
+
|
|
214
|
+
export async function getBootnodes(networkName: NetworkNames, cacheDir?: string) {
|
|
215
|
+
const cacheFile = cacheDir ? join(cacheDir, networkName, 'bootnodes.json') : undefined;
|
|
216
|
+
try {
|
|
217
|
+
if (cacheFile) {
|
|
218
|
+
const info = await stat(cacheFile);
|
|
219
|
+
if (info.mtimeMs + BOOTNODE_CACHE_DURATION_MS > Date.now()) {
|
|
220
|
+
return JSON.parse(await readFile(cacheFile, 'utf-8'))['bootnodes'];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch {
|
|
224
|
+
// no-op. Get the remote-file
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const url = `http://static.aztec.network/${networkName}/bootnodes.json`;
|
|
228
|
+
const response = await fetch(url);
|
|
229
|
+
if (!response.ok) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`Failed to fetch basic contract addresses from ${url}. Check you are using a correct network name.`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
const json = await response.json();
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
if (cacheFile) {
|
|
238
|
+
await mkdir(dirname(cacheFile), { recursive: true });
|
|
239
|
+
await writeFile(cacheFile, JSON.stringify(json), 'utf-8');
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
// no-op
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return json['bootnodes'];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export async function getL2ChainConfig(
|
|
249
|
+
networkName: NetworkNames,
|
|
250
|
+
cacheDir?: string,
|
|
251
|
+
): Promise<L2ChainConfig | undefined> {
|
|
252
|
+
let config: L2ChainConfig | undefined;
|
|
253
|
+
if (networkName === 'staging-public') {
|
|
254
|
+
config = { ...stagingPublicL2ChainConfig };
|
|
255
|
+
} else if (networkName === 'testnet') {
|
|
256
|
+
config = { ...testnetL2ChainConfig };
|
|
257
|
+
} else if (networkName === 'staging-ignition') {
|
|
258
|
+
config = { ...stagingIgnitionL2ChainConfig };
|
|
259
|
+
}
|
|
260
|
+
if (!config) {
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
// If the bootnodes are not set, get them from the network
|
|
264
|
+
const bootnodeKey: EnvVar = 'BOOTSTRAP_NODES';
|
|
265
|
+
if (!process.env[bootnodeKey]) {
|
|
266
|
+
config.p2pBootstrapNodes = await getBootnodes(networkName, cacheDir);
|
|
267
|
+
}
|
|
268
|
+
return config;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function enrichVar(envVar: EnvVar, value: string | undefined) {
|
|
272
|
+
// Don't override
|
|
273
|
+
if (process.env[envVar] || value === undefined) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
process.env[envVar] = value;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function enrichEthAddressVar(envVar: EnvVar, value: string) {
|
|
280
|
+
// EthAddress doesn't like being given empty strings
|
|
281
|
+
if (value === '') {
|
|
282
|
+
enrichVar(envVar, EthAddress.ZERO.toString());
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
enrichVar(envVar, value);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function getDefaultDataDir(networkName: NetworkNames): string {
|
|
289
|
+
return path.join(process.env.HOME || '~', '.aztec', networkName, 'data');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export async function enrichEnvironmentWithChainConfig(networkName: NetworkNames) {
|
|
293
|
+
if (networkName === 'local') {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
enrichVar('DATA_DIRECTORY', getDefaultDataDir(networkName));
|
|
298
|
+
const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
|
|
299
|
+
const config = await getL2ChainConfig(networkName, cacheDir);
|
|
300
|
+
|
|
301
|
+
if (!config) {
|
|
302
|
+
throw new Error(`Unknown network name: ${networkName}`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
enrichVar('BOOTSTRAP_NODES', config.p2pBootstrapNodes.join(','));
|
|
306
|
+
enrichVar('TEST_ACCOUNTS', config.testAccounts.toString());
|
|
307
|
+
enrichVar('SPONSORED_FPC', config.sponsoredFPC.toString());
|
|
308
|
+
enrichVar('P2P_ENABLED', config.p2pEnabled.toString());
|
|
309
|
+
enrichVar('L1_CHAIN_ID', config.l1ChainId.toString());
|
|
310
|
+
enrichVar('SEQ_MIN_TX_PER_BLOCK', config.seqMinTxsPerBlock.toString());
|
|
311
|
+
enrichVar('SEQ_MAX_TX_PER_BLOCK', config.seqMaxTxsPerBlock.toString());
|
|
312
|
+
enrichVar('PROVER_REAL_PROOFS', config.realProofs.toString());
|
|
313
|
+
enrichVar('PXE_PROVER_ENABLED', config.realProofs.toString());
|
|
314
|
+
enrichVar('SYNC_SNAPSHOTS_URL', config.snapshotsUrl);
|
|
315
|
+
enrichVar('P2P_MAX_TX_POOL_SIZE', config.maxTxPoolSize.toString());
|
|
316
|
+
|
|
317
|
+
if (config.autoUpdate) {
|
|
318
|
+
enrichVar('AUTO_UPDATE', config.autoUpdate?.toString());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (config.autoUpdateUrl) {
|
|
322
|
+
enrichVar('AUTO_UPDATE_URL', config.autoUpdateUrl);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (config.publicIncludeMetrics) {
|
|
326
|
+
enrichVar('PUBLIC_OTEL_INCLUDE_METRICS', config.publicIncludeMetrics.join(','));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (config.publicMetricsCollectorUrl) {
|
|
330
|
+
enrichVar('PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', config.publicMetricsCollectorUrl);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (config.publicMetricsCollectFrom) {
|
|
334
|
+
enrichVar('PUBLIC_OTEL_COLLECT_FROM', config.publicMetricsCollectFrom.join(','));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
enrichEthAddressVar('REGISTRY_CONTRACT_ADDRESS', config.registryAddress);
|
|
338
|
+
enrichEthAddressVar('SLASH_FACTORY_CONTRACT_ADDRESS', config.slashFactoryAddress);
|
|
339
|
+
enrichEthAddressVar('FEE_ASSET_HANDLER_CONTRACT_ADDRESS', config.feeAssetHandlerAddress);
|
|
340
|
+
|
|
341
|
+
// Deployment stuff
|
|
342
|
+
enrichVar('ETHEREUM_SLOT_DURATION', config.ethereumSlotDuration.toString());
|
|
343
|
+
enrichVar('AZTEC_SLOT_DURATION', config.aztecSlotDuration.toString());
|
|
344
|
+
enrichVar('AZTEC_EPOCH_DURATION', config.aztecEpochDuration.toString());
|
|
345
|
+
enrichVar('AZTEC_TARGET_COMMITTEE_SIZE', config.aztecTargetCommitteeSize.toString());
|
|
346
|
+
enrichVar('AZTEC_PROOF_SUBMISSION_EPOCHS', config.aztecProofSubmissionEpochs.toString());
|
|
347
|
+
enrichVar('AZTEC_ACTIVATION_THRESHOLD', config.activationThreshold.toString());
|
|
348
|
+
enrichVar('AZTEC_EJECTION_THRESHOLD', config.ejectionThreshold.toString());
|
|
349
|
+
enrichVar('AZTEC_LOCAL_EJECTION_THRESHOLD', config.localEjectionThreshold.toString());
|
|
350
|
+
enrichVar('AZTEC_SLASHING_QUORUM', config.slashingQuorum?.toString());
|
|
351
|
+
enrichVar('AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS', config.slashingRoundSizeInEpochs.toString());
|
|
352
|
+
enrichVar('AZTEC_GOVERNANCE_PROPOSER_QUORUM', config.governanceProposerQuorum?.toString());
|
|
353
|
+
enrichVar('AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE', config.governanceProposerRoundSize.toString());
|
|
354
|
+
enrichVar('AZTEC_MANA_TARGET', config.manaTarget.toString());
|
|
355
|
+
enrichVar('AZTEC_PROVING_COST_PER_MANA', config.provingCostPerMana.toString());
|
|
356
|
+
enrichVar('AZTEC_SLASH_AMOUNT_SMALL', config.slashAmountSmall.toString());
|
|
357
|
+
enrichVar('AZTEC_SLASH_AMOUNT_MEDIUM', config.slashAmountMedium.toString());
|
|
358
|
+
enrichVar('AZTEC_SLASH_AMOUNT_LARGE', config.slashAmountLarge.toString());
|
|
359
|
+
enrichVar('AZTEC_SLASHING_LIFETIME_IN_ROUNDS', config.slashingLifetimeInRounds.toString());
|
|
360
|
+
enrichVar('AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS', config.slashingExecutionDelayInRounds.toString());
|
|
361
|
+
enrichVar('AZTEC_SLASHING_OFFSET_IN_ROUNDS', config.slashingOffsetInRounds.toString());
|
|
362
|
+
enrichVar('AZTEC_SLASHER_FLAVOR', config.slasherFlavor);
|
|
363
|
+
enrichVar('AZTEC_EXIT_DELAY_SECONDS', config.exitDelaySeconds.toString());
|
|
364
|
+
enrichEthAddressVar('AZTEC_SLASHING_VETOER', config.slashingVetoer.toString());
|
|
365
|
+
|
|
366
|
+
// Slashing
|
|
367
|
+
enrichVar('SLASH_MIN_PENALTY_PERCENTAGE', config.slashMinPenaltyPercentage.toString());
|
|
368
|
+
enrichVar('SLASH_MAX_PENALTY_PERCENTAGE', config.slashMaxPenaltyPercentage.toString());
|
|
369
|
+
enrichVar('SLASH_PRUNE_PENALTY', config.slashPrunePenalty.toString());
|
|
370
|
+
enrichVar('SLASH_DATA_WITHHOLDING_PENALTY', config.slashDataWithholdingPenalty.toString());
|
|
371
|
+
enrichVar('SLASH_INACTIVITY_TARGET_PERCENTAGE', config.slashInactivityTargetPercentage.toString());
|
|
372
|
+
enrichVar('SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD', config.slashInactivityConsecutiveEpochThreshold.toString());
|
|
373
|
+
enrichVar('SLASH_INACTIVITY_PENALTY', config.slashInactivityPenalty.toString());
|
|
374
|
+
enrichVar('SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY', config.slashProposeInvalidAttestationsPenalty.toString());
|
|
375
|
+
enrichVar('SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY', config.slashAttestDescendantOfInvalidPenalty.toString());
|
|
376
|
+
enrichVar('SLASH_UNKNOWN_PENALTY', config.slashUnknownPenalty.toString());
|
|
377
|
+
enrichVar('SLASH_INVALID_BLOCK_PENALTY', config.slashBroadcastedInvalidBlockPenalty.toString());
|
|
378
|
+
enrichVar('SLASH_OFFENSE_EXPIRATION_ROUNDS', config.slashOffenseExpirationRounds.toString());
|
|
379
|
+
enrichVar('SLASH_MAX_PAYLOAD_SIZE', config.slashMaxPayloadSize.toString());
|
|
380
|
+
|
|
381
|
+
enrichVar('SENTINEL_ENABLED', config.sentinelEnabled.toString());
|
|
382
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type L1ContractAddresses, RegistryContract, getL1ContractsConfig, getPublicClient } from '@aztec/ethereum';
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
|
+
|
|
4
|
+
export async function getL1Config(
|
|
5
|
+
registryAddress: EthAddress,
|
|
6
|
+
l1RpcUrls: string[],
|
|
7
|
+
l1ChainId: number,
|
|
8
|
+
rollupVersion: number | 'canonical' = 'canonical',
|
|
9
|
+
): Promise<{ addresses: L1ContractAddresses; config: Awaited<ReturnType<typeof getL1ContractsConfig>> }> {
|
|
10
|
+
const publicClient = getPublicClient({ l1RpcUrls, l1ChainId });
|
|
11
|
+
const addresses = await RegistryContract.collectAddresses(publicClient, registryAddress, rollupVersion);
|
|
12
|
+
|
|
13
|
+
const config = await getL1ContractsConfig(publicClient, addresses);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
addresses,
|
|
17
|
+
config,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function getL1RollupAddressFromEnv(l1RpcUrls: string[], l1ChainId: number) {
|
|
22
|
+
const registryAddress = process.env.REGISTRY_CONTRACT_ADDRESS;
|
|
23
|
+
if (!registryAddress || !EthAddress.isAddress(registryAddress)) {
|
|
24
|
+
throw new Error(`Failed to extract registry address`);
|
|
25
|
+
}
|
|
26
|
+
const { addresses } = await getL1Config(EthAddress.fromString(registryAddress), l1RpcUrls, l1ChainId);
|
|
27
|
+
return addresses.rollupAddress;
|
|
28
|
+
}
|
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AztecAddress,
|
|
3
|
-
DefaultWaitOpts,
|
|
4
|
-
Fr,
|
|
5
|
-
type PXE,
|
|
6
|
-
SignerlessWallet,
|
|
7
|
-
SponsoredFeePaymentMethod,
|
|
8
|
-
type WaitForProvenOpts,
|
|
9
|
-
getContractInstanceFromInstantiationParams,
|
|
10
|
-
waitForProven,
|
|
11
|
-
} from '@aztec/aztec.js';
|
|
1
|
+
import { Fr, type PXE, getContractInstanceFromInstantiationParams } from '@aztec/aztec.js';
|
|
12
2
|
import { SPONSORED_FPC_SALT } from '@aztec/constants';
|
|
13
|
-
import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multicall';
|
|
14
3
|
import type { LogFn } from '@aztec/foundation/log';
|
|
15
4
|
|
|
16
5
|
async function getSponsoredFPCContract() {
|
|
@@ -28,31 +17,12 @@ export async function getSponsoredFPCAddress() {
|
|
|
28
17
|
return sponsoredFPCInstance.address;
|
|
29
18
|
}
|
|
30
19
|
|
|
31
|
-
export async function setupSponsoredFPC(
|
|
32
|
-
pxe: PXE,
|
|
33
|
-
log: LogFn,
|
|
34
|
-
waitOpts = DefaultWaitOpts,
|
|
35
|
-
waitForProvenOptions?: WaitForProvenOpts,
|
|
36
|
-
) {
|
|
20
|
+
export async function setupSponsoredFPC(pxe: PXE, log: LogFn) {
|
|
37
21
|
const SponsoredFPCContract = await getSponsoredFPCContract();
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const { l1ChainId: chainId, rollupVersion } = await pxe.getNodeInfo();
|
|
41
|
-
|
|
42
|
-
const deployer = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(chainId, rollupVersion));
|
|
43
|
-
|
|
44
|
-
const deployTx = SponsoredFPCContract.deploy(deployer).send({
|
|
45
|
-
from: AztecAddress.ZERO,
|
|
46
|
-
contractAddressSalt: new Fr(SPONSORED_FPC_SALT),
|
|
47
|
-
universalDeploy: true,
|
|
48
|
-
fee: { paymentMethod },
|
|
22
|
+
const sponsoredFPCInstance = await getContractInstanceFromInstantiationParams(SponsoredFPCContract.artifact, {
|
|
23
|
+
salt: new Fr(SPONSORED_FPC_SALT),
|
|
49
24
|
});
|
|
25
|
+
await pxe.registerContract({ instance: sponsoredFPCInstance, artifact: SponsoredFPCContract.artifact });
|
|
50
26
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (waitForProvenOptions !== undefined) {
|
|
54
|
-
await waitForProven(pxe, await deployTx.getReceipt(), waitForProvenOptions);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
log(`SponsoredFPC: ${deployed.address}`);
|
|
27
|
+
log(`SponsoredFPC: ${sponsoredFPCInstance.address}`);
|
|
58
28
|
}
|