@aztec/ethereum 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa
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/account.d.ts +1 -1
- package/dest/chain.d.ts +1 -1
- package/dest/client.d.ts +25 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +60 -4
- package/dest/config.d.ts +48 -73
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +120 -386
- package/dest/constants.d.ts +1 -1
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/empire_base.d.ts +7 -5
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_base.js +1 -1
- package/dest/contracts/errors.d.ts +1 -1
- package/dest/contracts/errors.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +6 -5
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +11 -9
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/fee_juice.d.ts +1 -1
- package/dest/contracts/fee_juice.d.ts.map +1 -1
- package/dest/contracts/governance.d.ts +113 -36
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +207 -16
- package/dest/contracts/governance_proposer.d.ts +38 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +455 -12
- package/dest/contracts/gse.d.ts +4 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +2 -2
- package/dest/contracts/inbox.d.ts +24 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +42 -2
- package/dest/contracts/index.d.ts +6 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +5 -2
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.js +1 -0
- package/dest/contracts/multicall.d.ts +130 -13
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +203 -93
- package/dest/contracts/outbox.d.ts +64 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +113 -0
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5591 -131
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +1125 -232
- package/dest/contracts/slasher_contract.d.ts +1 -1
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +11 -10
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +21 -16
- package/dest/contracts/utils.d.ts +1 -1
- package/dest/deploy_aztec_l1_contracts.d.ts +267 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +417 -0
- package/dest/deploy_l1_contract.d.ts +68 -0
- package/dest/deploy_l1_contract.d.ts.map +1 -0
- package/dest/deploy_l1_contract.js +312 -0
- package/dest/eth-signer/eth-signer.d.ts +1 -1
- package/dest/eth-signer/index.d.ts +1 -1
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/l1_artifacts.d.ts +21007 -16779
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +99 -80
- package/dest/l1_reader.d.ts +7 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +15 -7
- package/dest/l1_tx_utils/config.d.ts +11 -5
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +46 -10
- package/dest/l1_tx_utils/constants.d.ts +8 -2
- package/dest/l1_tx_utils/constants.d.ts.map +1 -1
- package/dest/l1_tx_utils/constants.js +27 -2
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/index.d.ts +10 -0
- package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/index-blobs.js +2 -0
- package/dest/l1_tx_utils/index.d.ts +4 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +3 -0
- package/dest/l1_tx_utils/interfaces.d.ts +2 -2
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +252 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.js +568 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -8
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +202 -92
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -30
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +65 -168
- package/dest/l1_tx_utils/signer.d.ts +1 -1
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +70 -39
- package/dest/l1_tx_utils/types.d.ts +27 -1
- package/dest/l1_tx_utils/types.d.ts.map +1 -1
- package/dest/l1_tx_utils/types.js +10 -0
- package/dest/l1_tx_utils/utils.d.ts +1 -1
- package/dest/l1_types.d.ts +1 -1
- package/dest/publisher_manager.d.ts +34 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +119 -8
- package/dest/queries.d.ts +14 -3
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +84 -9
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +80 -26
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +137 -39
- package/dest/test/eth_cheat_codes.d.ts +47 -8
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +100 -44
- package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -2
- package/dest/test/rollup_cheat_codes.d.ts +75 -14
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +145 -42
- package/dest/test/start_anvil.d.ts +25 -2
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -28
- package/dest/test/upgrade_utils.d.ts +1 -1
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/types.d.ts +57 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/utils.d.ts +24 -4
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +112 -16
- package/dest/zkPassportVerifierAddress.d.ts +1 -1
- package/package.json +34 -17
- package/src/client.ts +66 -2
- package/src/config.ts +162 -470
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +6 -5
- package/src/contracts/fee_asset_handler.ts +10 -7
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +279 -13
- package/src/contracts/governance_proposer.ts +74 -7
- package/src/contracts/gse.ts +7 -2
- package/src/contracts/inbox.ts +64 -4
- package/src/contracts/index.ts +5 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +247 -103
- package/src/contracts/outbox.ts +132 -0
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +830 -194
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +26 -21
- package/src/deploy_aztec_l1_contracts.ts +652 -0
- package/src/deploy_l1_contract.ts +362 -0
- package/src/forwarder_proxy.ts +108 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -92
- package/src/l1_reader.ts +25 -10
- package/src/l1_tx_utils/config.ts +55 -14
- package/src/l1_tx_utils/constants.ts +13 -2
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +163 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +245 -0
- package/src/l1_tx_utils/fee-strategies/types.ts +56 -0
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +108 -0
- package/src/l1_tx_utils/index-blobs.ts +2 -0
- package/src/l1_tx_utils/index.ts +3 -0
- package/src/l1_tx_utils/interfaces.ts +1 -1
- package/src/l1_tx_utils/l1_fee_analyzer.ts +875 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +194 -72
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +79 -214
- package/src/{test → l1_tx_utils}/tx_delayer.ts +97 -58
- package/src/l1_tx_utils/types.ts +32 -0
- package/src/publisher_manager.ts +145 -12
- package/src/queries.ts +93 -10
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +198 -51
- package/src/test/eth_cheat_codes.ts +91 -48
- package/src/test/index.ts +1 -2
- package/src/test/rollup_cheat_codes.ts +174 -45
- package/src/test/start_anvil.ts +179 -27
- package/src/test/upgrade_utils.ts +2 -2
- package/src/types.ts +62 -0
- package/src/utils.ts +128 -19
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -65
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -194
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.d.ts +0 -226
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1473
- package/dest/index.d.ts +0 -18
- package/dest/index.d.ts.map +0 -1
- package/dest/index.js +0 -17
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -259
- package/src/deploy_l1_contracts.ts +0 -1849
- package/src/index.ts +0 -17
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OutboxContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
2
2
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
3
|
+
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
4
|
+
import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
7
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
5
8
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
6
9
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
7
10
|
|
|
@@ -13,8 +16,8 @@ import {
|
|
|
13
16
|
getContract,
|
|
14
17
|
hexToBigInt,
|
|
15
18
|
http,
|
|
19
|
+
keccak256,
|
|
16
20
|
} from 'viem';
|
|
17
|
-
import { foundry } from 'viem/chains';
|
|
18
21
|
|
|
19
22
|
import { EthCheatCodes } from './eth_cheat_codes.js';
|
|
20
23
|
|
|
@@ -30,8 +33,8 @@ export class RollupCheatCodes {
|
|
|
30
33
|
addresses: Pick<L1ContractAddresses, 'rollupAddress'>,
|
|
31
34
|
) {
|
|
32
35
|
this.client = createPublicClient({
|
|
33
|
-
chain:
|
|
34
|
-
transport: fallback(ethCheatCodes.rpcUrls.map(url => http(url))),
|
|
36
|
+
chain: ethCheatCodes.chain,
|
|
37
|
+
transport: fallback(ethCheatCodes.rpcUrls.map(url => http(url, { batch: false }))),
|
|
35
38
|
});
|
|
36
39
|
this.rollup = getContract({
|
|
37
40
|
abi: RollupAbi,
|
|
@@ -50,15 +53,34 @@ export class RollupCheatCodes {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
/** Returns the current slot */
|
|
53
|
-
public async getSlot() {
|
|
56
|
+
public async getSlot(): Promise<SlotNumber> {
|
|
54
57
|
const ts = BigInt((await this.client.getBlock()).timestamp);
|
|
55
|
-
return
|
|
58
|
+
return this.getSlotAt(ts);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Returns the slot number at a given timestamp. */
|
|
62
|
+
public async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
63
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Returns the timestamp for the start of a given slot. */
|
|
67
|
+
public async getTimestampForSlot(slot: SlotNumber): Promise<bigint> {
|
|
68
|
+
return await this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Returns the number of seconds until the start of the given slot based on L1 block timestamp. */
|
|
72
|
+
public async getSecondsUntilSlot(slot: SlotNumber): Promise<number> {
|
|
73
|
+
const [currentTimestamp, targetTimestamp] = await Promise.all([
|
|
74
|
+
this.client.getBlock().then(b => BigInt(b.timestamp)),
|
|
75
|
+
this.rollup.read.getTimestampForSlot([BigInt(slot)]),
|
|
76
|
+
]);
|
|
77
|
+
return Math.max(0, Number(targetTimestamp - currentTimestamp));
|
|
56
78
|
}
|
|
57
79
|
|
|
58
80
|
/** Returns the current epoch */
|
|
59
|
-
public async getEpoch() {
|
|
81
|
+
public async getEpoch(): Promise<EpochNumber> {
|
|
60
82
|
const slotNumber = await this.getSlot();
|
|
61
|
-
return await this.rollup.read.getEpochAtSlot([slotNumber]);
|
|
83
|
+
return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)]));
|
|
62
84
|
}
|
|
63
85
|
|
|
64
86
|
/**
|
|
@@ -66,13 +88,13 @@ export class RollupCheatCodes {
|
|
|
66
88
|
* @returns The pending and proven chain tips
|
|
67
89
|
*/
|
|
68
90
|
public async getTips(): Promise<{
|
|
69
|
-
/** The pending chain tip */ pending:
|
|
70
|
-
/** The proven chain tip */ proven:
|
|
91
|
+
/** The pending chain tip */ pending: CheckpointNumber;
|
|
92
|
+
/** The proven chain tip */ proven: CheckpointNumber;
|
|
71
93
|
}> {
|
|
72
|
-
const
|
|
94
|
+
const { pending, proven } = await this.rollup.read.getTips();
|
|
73
95
|
return {
|
|
74
|
-
pending:
|
|
75
|
-
proven:
|
|
96
|
+
pending: CheckpointNumber.fromBigInt(pending),
|
|
97
|
+
proven: CheckpointNumber.fromBigInt(proven),
|
|
76
98
|
};
|
|
77
99
|
}
|
|
78
100
|
|
|
@@ -81,16 +103,16 @@ export class RollupCheatCodes {
|
|
|
81
103
|
*/
|
|
82
104
|
public async debugRollup() {
|
|
83
105
|
const rollup = new RollupContract(this.client, this.rollup.address);
|
|
84
|
-
const pendingNum = await rollup.
|
|
85
|
-
const provenNum = await rollup.
|
|
106
|
+
const pendingNum = await rollup.getCheckpointNumber();
|
|
107
|
+
const provenNum = await rollup.getProvenCheckpointNumber();
|
|
86
108
|
const validators = await rollup.getAttesters();
|
|
87
109
|
const committee = await rollup.getCurrentEpochCommittee();
|
|
88
110
|
const archive = await rollup.archive();
|
|
89
111
|
const slot = await this.getSlot();
|
|
90
112
|
const epochNum = await rollup.getEpochNumberForSlotNumber(slot);
|
|
91
113
|
|
|
92
|
-
this.logger.info(`Pending
|
|
93
|
-
this.logger.info(`Proven
|
|
114
|
+
this.logger.info(`Pending checkpoint num: ${pendingNum}`);
|
|
115
|
+
this.logger.info(`Proven checkpoint num: ${provenNum}`);
|
|
94
116
|
this.logger.info(`Validators: ${validators.map(v => v.toString()).join(', ')}`);
|
|
95
117
|
this.logger.info(`Committee: ${committee?.map(v => v.toString()).join(', ')}`);
|
|
96
118
|
this.logger.info(`Archive: ${archive}`);
|
|
@@ -101,13 +123,13 @@ export class RollupCheatCodes {
|
|
|
101
123
|
/** Fetches the epoch and slot duration config from the rollup contract */
|
|
102
124
|
public async getConfig(): Promise<{
|
|
103
125
|
/** Epoch duration */ epochDuration: bigint;
|
|
104
|
-
/** Slot duration */ slotDuration:
|
|
126
|
+
/** Slot duration */ slotDuration: number;
|
|
105
127
|
}> {
|
|
106
128
|
const [epochDuration, slotDuration] = await Promise.all([
|
|
107
129
|
this.rollup.read.getEpochDuration(),
|
|
108
130
|
this.rollup.read.getSlotDuration(),
|
|
109
131
|
]);
|
|
110
|
-
return { epochDuration, slotDuration };
|
|
132
|
+
return { epochDuration, slotDuration: Number(slotDuration) };
|
|
111
133
|
}
|
|
112
134
|
|
|
113
135
|
/**
|
|
@@ -116,18 +138,18 @@ export class RollupCheatCodes {
|
|
|
116
138
|
* @param opts - Options
|
|
117
139
|
*/
|
|
118
140
|
public async advanceToEpoch(
|
|
119
|
-
epoch:
|
|
141
|
+
epoch: EpochNumber,
|
|
120
142
|
opts: {
|
|
121
143
|
/** Offset in seconds */
|
|
122
144
|
offset?: number;
|
|
123
145
|
} = {},
|
|
124
146
|
) {
|
|
125
147
|
const { epochDuration: slotsInEpoch } = await this.getConfig();
|
|
126
|
-
const
|
|
127
|
-
|
|
148
|
+
const slotNumber = SlotNumber(Number(epoch) * Number(slotsInEpoch));
|
|
149
|
+
const timestamp = (await this.rollup.read.getTimestampForSlot([BigInt(slotNumber)])) + BigInt(opts.offset ?? 0);
|
|
128
150
|
try {
|
|
129
151
|
await this.ethCheatCodes.warp(Number(timestamp), { ...opts, silent: true, resetBlockInterval: true });
|
|
130
|
-
this.logger.warn(`Warped to epoch ${epoch}
|
|
152
|
+
this.logger.warn(`Warped to epoch ${epoch}`, { offset: opts.offset, timestamp });
|
|
131
153
|
} catch (err) {
|
|
132
154
|
this.logger.warn(`Warp to epoch ${epoch} failed: ${err}`);
|
|
133
155
|
}
|
|
@@ -138,8 +160,8 @@ export class RollupCheatCodes {
|
|
|
138
160
|
public async advanceToNextEpoch() {
|
|
139
161
|
const slot = await this.getSlot();
|
|
140
162
|
const { epochDuration, slotDuration } = await this.getConfig();
|
|
141
|
-
const slotsUntilNextEpoch = epochDuration - (slot % epochDuration) + 1n;
|
|
142
|
-
const timeToNextEpoch = slotsUntilNextEpoch * slotDuration;
|
|
163
|
+
const slotsUntilNextEpoch = epochDuration - (BigInt(slot) % epochDuration) + 1n;
|
|
164
|
+
const timeToNextEpoch = slotsUntilNextEpoch * BigInt(slotDuration);
|
|
143
165
|
const l1Timestamp = BigInt((await this.client.getBlock()).timestamp);
|
|
144
166
|
await this.ethCheatCodes.warp(Number(l1Timestamp + timeToNextEpoch), {
|
|
145
167
|
silent: true,
|
|
@@ -151,10 +173,26 @@ export class RollupCheatCodes {
|
|
|
151
173
|
/** Warps time in L1 until the beginning of the next slot. */
|
|
152
174
|
public async advanceToNextSlot() {
|
|
153
175
|
const currentSlot = await this.getSlot();
|
|
154
|
-
const
|
|
176
|
+
const nextSlot = SlotNumber(currentSlot + 1);
|
|
177
|
+
const timestamp = await this.rollup.read.getTimestampForSlot([BigInt(nextSlot)]);
|
|
155
178
|
await this.ethCheatCodes.warp(Number(timestamp), { silent: true, resetBlockInterval: true });
|
|
156
|
-
this.logger.warn(`Advanced to slot ${
|
|
157
|
-
return [timestamp,
|
|
179
|
+
this.logger.warn(`Advanced to slot ${nextSlot}`);
|
|
180
|
+
return [timestamp, nextSlot];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Warps L1 time to the start of an explicit absolute slot. Unlike `advanceSlots(N)` which is
|
|
185
|
+
* relative to the current L1 timestamp at call time and therefore races with real-time
|
|
186
|
+
* progression between query and warp, this lands at the slot regardless of latency.
|
|
187
|
+
*
|
|
188
|
+
* Throws if the requested slot is in the past relative to current L1 time (anvil cannot
|
|
189
|
+
* rewind).
|
|
190
|
+
*/
|
|
191
|
+
public async advanceToSlot(slot: SlotNumber) {
|
|
192
|
+
const timestamp = await this.rollup.read.getTimestampForSlot([BigInt(slot)]);
|
|
193
|
+
await this.ethCheatCodes.warp(Number(timestamp), { silent: true, resetBlockInterval: true });
|
|
194
|
+
this.logger.warn(`Advanced to slot ${slot}`, { timestamp });
|
|
195
|
+
return timestamp;
|
|
158
196
|
}
|
|
159
197
|
|
|
160
198
|
/**
|
|
@@ -163,42 +201,42 @@ export class RollupCheatCodes {
|
|
|
163
201
|
*/
|
|
164
202
|
public async advanceSlots(howMany: number) {
|
|
165
203
|
const l1Timestamp = (await this.client.getBlock()).timestamp;
|
|
166
|
-
const slotDuration = await this.rollup.read.getSlotDuration();
|
|
167
|
-
const timeToWarp = BigInt(howMany) * slotDuration;
|
|
204
|
+
const slotDuration = Number(await this.rollup.read.getSlotDuration());
|
|
205
|
+
const timeToWarp = BigInt(howMany) * BigInt(slotDuration);
|
|
168
206
|
await this.ethCheatCodes.warp(l1Timestamp + timeToWarp, { silent: true, resetBlockInterval: true });
|
|
169
207
|
const [slot, epoch] = await Promise.all([this.getSlot(), this.getEpoch()]);
|
|
170
208
|
this.logger.warn(`Advanced ${howMany} slots up to slot ${slot} in epoch ${epoch}`);
|
|
171
209
|
}
|
|
172
210
|
|
|
173
211
|
/**
|
|
174
|
-
* Marks the specified
|
|
175
|
-
* @param
|
|
212
|
+
* Marks the specified checkpoint (or latest if none) as proven
|
|
213
|
+
* @param maybeCheckpointNumber - The checkpoint number to mark as proven (defaults to latest pending)
|
|
176
214
|
*/
|
|
177
|
-
public markAsProven(
|
|
215
|
+
public markAsProven(maybeCheckpointNumber?: CheckpointNumber) {
|
|
178
216
|
return this.ethCheatCodes.execWithPausedAnvil(async () => {
|
|
179
217
|
const tipsBefore = await this.getTips();
|
|
180
218
|
const { pending, proven } = tipsBefore;
|
|
181
219
|
|
|
182
|
-
let
|
|
183
|
-
if (
|
|
184
|
-
|
|
220
|
+
let checkpointNumber = maybeCheckpointNumber;
|
|
221
|
+
if (checkpointNumber === undefined || checkpointNumber > pending) {
|
|
222
|
+
checkpointNumber = pending;
|
|
185
223
|
}
|
|
186
|
-
if (
|
|
187
|
-
this.logger.debug(`
|
|
224
|
+
if (checkpointNumber <= proven) {
|
|
225
|
+
this.logger.debug(`Checkpoint ${checkpointNumber} is already proven`);
|
|
188
226
|
return;
|
|
189
227
|
}
|
|
190
228
|
|
|
191
229
|
// @note @LHerskind this is heavily dependent on the storage layout and size of values
|
|
192
230
|
// The rollupStore is a struct and if the size of elements or the struct changes, this can break
|
|
193
|
-
const
|
|
231
|
+
const provenCheckpointNumberSlot = hexToBigInt(RollupContract.stfStorageSlot);
|
|
194
232
|
|
|
195
233
|
// Need to pack it as a single 32 byte word
|
|
196
|
-
const newValue = (BigInt(tipsBefore.pending) << 128n) | BigInt(
|
|
197
|
-
await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address),
|
|
234
|
+
const newValue = (BigInt(tipsBefore.pending) << 128n) | BigInt(checkpointNumber);
|
|
235
|
+
await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address), provenCheckpointNumberSlot, newValue);
|
|
198
236
|
|
|
199
237
|
const tipsAfter = await this.getTips();
|
|
200
238
|
if (tipsAfter.pending < tipsAfter.proven) {
|
|
201
|
-
throw new Error('Overwrote pending tip to a
|
|
239
|
+
throw new Error('Overwrote pending tip to a checkpoint in the past');
|
|
202
240
|
}
|
|
203
241
|
|
|
204
242
|
this.logger.info(
|
|
@@ -207,9 +245,59 @@ export class RollupCheatCodes {
|
|
|
207
245
|
});
|
|
208
246
|
}
|
|
209
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Polls the rollup until its current epoch reaches `epoch`. Unlike {@link advanceToEpoch} this does
|
|
250
|
+
* not warp the L1 clock; it only waits for the chain to reach `epoch` through external activity.
|
|
251
|
+
*/
|
|
252
|
+
public async waitForEpoch(epoch: EpochNumber, opts: { timeout?: number; interval?: number } = {}): Promise<void> {
|
|
253
|
+
await retryUntil(
|
|
254
|
+
async () => (await this.getEpoch()) >= epoch || undefined,
|
|
255
|
+
`rollup epoch >= ${epoch}`,
|
|
256
|
+
opts.timeout ?? 60,
|
|
257
|
+
opts.interval ?? 1,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Polls the rollup until its current slot reaches `slot`. Unlike {@link advanceToSlot} this does not
|
|
263
|
+
* warp the L1 clock; it only waits for the chain to reach `slot` through external activity.
|
|
264
|
+
*/
|
|
265
|
+
public async waitForSlot(slot: SlotNumber, opts: { timeout?: number; interval?: number } = {}): Promise<void> {
|
|
266
|
+
await retryUntil(
|
|
267
|
+
async () => (await this.getSlot()) >= slot || undefined,
|
|
268
|
+
`rollup slot >= ${slot}`,
|
|
269
|
+
opts.timeout ?? 60,
|
|
270
|
+
opts.interval ?? 1,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Polls the rollup until its pending checkpoint settles below `checkpoint` on a freshly mined, non-zero
|
|
276
|
+
* checkpoint, and returns that new pending checkpoint number. Reads the L1 rollup contract directly
|
|
277
|
+
* rather than a node, since a rollback lands on L1 first.
|
|
278
|
+
*
|
|
279
|
+
* A prune can momentarily drop the pending checkpoint to 0 before the post-deadline propose mines its
|
|
280
|
+
* replacement, so a caller detecting a rollback wants the new lower checkpoint, not that transient
|
|
281
|
+
* empty state — hence the non-zero guard.
|
|
282
|
+
*/
|
|
283
|
+
public async waitForCheckpointBelow(
|
|
284
|
+
checkpoint: CheckpointNumber,
|
|
285
|
+
opts: { timeout?: number; interval?: number } = {},
|
|
286
|
+
): Promise<CheckpointNumber> {
|
|
287
|
+
return await retryUntil(
|
|
288
|
+
async () => {
|
|
289
|
+
const { pending } = await this.getTips();
|
|
290
|
+
return pending > 0 && pending < checkpoint ? pending : undefined;
|
|
291
|
+
},
|
|
292
|
+
`rollup checkpoint in (0, ${checkpoint})`,
|
|
293
|
+
opts.timeout ?? 60,
|
|
294
|
+
opts.interval ?? 1,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
210
298
|
/**
|
|
211
299
|
* Overrides the inProgress field of the Inbox contract state
|
|
212
|
-
* @param howMuch - How many
|
|
300
|
+
* @param howMuch - How many checkpoints to move it forward
|
|
213
301
|
*/
|
|
214
302
|
public advanceInboxInProgress(howMuch: number | bigint): Promise<bigint> {
|
|
215
303
|
return this.ethCheatCodes.execWithPausedAnvil(async () => {
|
|
@@ -248,6 +336,17 @@ export class RollupCheatCodes {
|
|
|
248
336
|
});
|
|
249
337
|
}
|
|
250
338
|
|
|
339
|
+
public insertOutbox(epoch: EpochNumber, numCheckpointsInEpoch: number, outHash: bigint) {
|
|
340
|
+
return this.ethCheatCodes.execWithPausedAnvil(async () => {
|
|
341
|
+
const outboxAddress = await this.rollup.read.getOutbox();
|
|
342
|
+
const epochRootSlot = OutboxContract.getEpochRootStorageSlot(epoch, numCheckpointsInEpoch);
|
|
343
|
+
await this.ethCheatCodes.store(EthAddress.fromString(outboxAddress), epochRootSlot, outHash);
|
|
344
|
+
this.logger.warn(
|
|
345
|
+
`Advanced outbox to epoch ${epoch} numCheckpointsInEpoch ${numCheckpointsInEpoch} with out hash ${outHash}`,
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
251
350
|
/**
|
|
252
351
|
* Executes an action impersonated as the owner of the Rollup contract.
|
|
253
352
|
* @param action - The action to execute
|
|
@@ -293,7 +392,8 @@ export class RollupCheatCodes {
|
|
|
293
392
|
}
|
|
294
393
|
|
|
295
394
|
/**
|
|
296
|
-
* Directly updates proving cost per mana.
|
|
395
|
+
* Directly updates proving cost per mana. Throws if the on-chain tx reverts
|
|
396
|
+
* (e.g. rate-limit cooldown, step cap, or floor) instead of silently succeeding.
|
|
297
397
|
* @param ethValue - The new proving cost per mana in ETH
|
|
298
398
|
*/
|
|
299
399
|
public async setProvingCostPerMana(ethValue: bigint) {
|
|
@@ -303,8 +403,37 @@ export class RollupCheatCodes {
|
|
|
303
403
|
chain: this.client.chain,
|
|
304
404
|
gasLimit: 1000000n,
|
|
305
405
|
});
|
|
306
|
-
await this.client.waitForTransactionReceipt({ hash });
|
|
406
|
+
const receipt = await this.client.waitForTransactionReceipt({ hash });
|
|
407
|
+
if (receipt.status !== 'success') {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`setProvingCostPerMana(${ethValue}) reverted on L1 (tx ${hash}). ` +
|
|
410
|
+
`Likely FeeLib rate-limit (30-day cooldown or 1.5x step cap); ` +
|
|
411
|
+
`use clearProvingCostCooldown() between successive updates.`,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
307
414
|
this.logger.warn(`Updated proving cost per mana to ${ethValue}`);
|
|
308
415
|
});
|
|
309
416
|
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Resets the 30-day proving-cost update cooldown enforced by FeeLib.updateProvingCostPerMana
|
|
420
|
+
* by zeroing `FeeStore.provingCostLastUpdate` directly in contract storage. Use between
|
|
421
|
+
* successive setProvingCostPerMana / bumpProvingCostPerMana calls so the later update can
|
|
422
|
+
* land instead of reverting. Does not touch L1 time, so PXE/tx-expiration state stays intact.
|
|
423
|
+
*
|
|
424
|
+
* @note This is tightly coupled to the `FeeStore` layout in
|
|
425
|
+
* l1-contracts/src/core/libraries/rollup/FeeLib.sol:
|
|
426
|
+
* slot + 0: CompressedFeeConfig config (uint256)
|
|
427
|
+
* slot + 1: L1GasOracleValues l1GasOracleValues (14+14+4 bytes, packed)
|
|
428
|
+
* slot + 2: uint64 provingCostLastUpdate (only member — zeroing the slot is safe)
|
|
429
|
+
* If the struct layout changes, update the offset below.
|
|
430
|
+
*/
|
|
431
|
+
public async clearProvingCostCooldown() {
|
|
432
|
+
const feeStoreBaseSlot = hexToBigInt(keccak256(Buffer.from('aztec.fee.storage', 'utf-8')));
|
|
433
|
+
const provingCostLastUpdateSlot = feeStoreBaseSlot + 2n;
|
|
434
|
+
await this.ethCheatCodes.store(EthAddress.fromString(this.rollup.address), provingCostLastUpdateSlot, 0n, {
|
|
435
|
+
silent: true,
|
|
436
|
+
});
|
|
437
|
+
this.logger.warn(`Cleared proving-cost update cooldown`);
|
|
438
|
+
}
|
|
310
439
|
}
|
package/src/test/start_anvil.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
3
|
+
import type { TestDateProvider } from '@aztec/foundation/timer';
|
|
3
4
|
import { fileURLToPath } from '@aztec/foundation/url';
|
|
4
5
|
|
|
5
|
-
import { type
|
|
6
|
+
import { type ChildProcess, spawn } from 'child_process';
|
|
6
7
|
import { dirname, resolve } from 'path';
|
|
7
8
|
|
|
9
|
+
/** Minimal interface matching the @viem/anvil Anvil shape used by callers. */
|
|
10
|
+
export interface Anvil {
|
|
11
|
+
readonly port: number;
|
|
12
|
+
readonly host: string;
|
|
13
|
+
readonly status: 'listening' | 'idle';
|
|
14
|
+
stop(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
/**
|
|
9
18
|
* Ensures there's a running Anvil instance and returns the RPC URL.
|
|
10
19
|
*/
|
|
@@ -15,53 +24,196 @@ export async function startAnvil(
|
|
|
15
24
|
log?: boolean;
|
|
16
25
|
captureMethodCalls?: boolean;
|
|
17
26
|
accounts?: number;
|
|
27
|
+
chainId?: number;
|
|
28
|
+
/** The hardfork to use (e.g. 'cancun', 'latest'). */
|
|
29
|
+
hardfork?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Number of slots per epoch used by anvil to compute the 'finalized' and 'safe' block tags.
|
|
32
|
+
* Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
|
|
33
|
+
* Defaults to 1 so the finalized block advances immediately, making tests that check
|
|
34
|
+
* L1-finality-based logic work without needing hundreds of mined blocks.
|
|
35
|
+
*/
|
|
36
|
+
slotsInAnEpoch?: number;
|
|
37
|
+
/**
|
|
38
|
+
* If provided, the date provider will be synced to anvil's block time on every mined block.
|
|
39
|
+
* This keeps the dateProvider in lockstep with anvil's chain time, avoiding drift between
|
|
40
|
+
* the wall clock and the L1 chain when computing L1 slot timestamps.
|
|
41
|
+
*/
|
|
42
|
+
dateProvider?: TestDateProvider;
|
|
18
43
|
} = {},
|
|
19
44
|
): Promise<{ anvil: Anvil; methodCalls?: string[]; rpcUrl: string; stop: () => Promise<void> }> {
|
|
20
45
|
const anvilBinary = resolve(dirname(fileURLToPath(import.meta.url)), '../../', 'scripts/anvil_kill_wrapper.sh');
|
|
21
46
|
const logger = opts.log ? createLogger('ethereum:anvil') : undefined;
|
|
22
47
|
const methodCalls = opts.captureMethodCalls ? ([] as string[]) : undefined;
|
|
23
48
|
|
|
24
|
-
let
|
|
49
|
+
let detectedPort: number | undefined;
|
|
25
50
|
|
|
26
|
-
// Start anvil.
|
|
27
|
-
// We go via a wrapper script to ensure if the parent dies, anvil dies.
|
|
28
51
|
const anvil = await retry(
|
|
29
52
|
async () => {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
host
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
accounts
|
|
37
|
-
|
|
53
|
+
const port = opts.port ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : 8545);
|
|
54
|
+
const args: string[] = [
|
|
55
|
+
'--host',
|
|
56
|
+
'127.0.0.1',
|
|
57
|
+
'--port',
|
|
58
|
+
String(port),
|
|
59
|
+
'--accounts',
|
|
60
|
+
String(opts.accounts ?? 20),
|
|
61
|
+
'--gas-limit',
|
|
62
|
+
String(45_000_000),
|
|
63
|
+
'--chain-id',
|
|
64
|
+
String(opts.chainId ?? 31337),
|
|
65
|
+
];
|
|
66
|
+
if (opts.l1BlockTime !== undefined) {
|
|
67
|
+
args.push('--block-time', String(opts.l1BlockTime));
|
|
68
|
+
}
|
|
69
|
+
if (opts.hardfork !== undefined) {
|
|
70
|
+
args.push('--hardfork', opts.hardfork);
|
|
71
|
+
}
|
|
72
|
+
args.push('--slots-in-an-epoch', String(opts.slotsInAnEpoch ?? 1));
|
|
73
|
+
|
|
74
|
+
const child = spawn(anvilBinary, args, {
|
|
75
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
76
|
+
env: { ...process.env, RAYON_NUM_THREADS: '1' },
|
|
38
77
|
});
|
|
39
78
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
79
|
+
// Wait for "Listening on" or an early exit.
|
|
80
|
+
await new Promise<void>((resolve, reject) => {
|
|
81
|
+
let stderr = '';
|
|
82
|
+
|
|
83
|
+
const onStdout = (data: Buffer) => {
|
|
84
|
+
const text = data.toString();
|
|
85
|
+
logger?.debug(text.trim());
|
|
86
|
+
methodCalls?.push(...(text.match(/eth_[^\s]+/g) || []));
|
|
87
|
+
|
|
88
|
+
if (detectedPort === undefined && text.includes('Listening on')) {
|
|
89
|
+
const match = text.match(/Listening on ([^:]+):(\d+)/);
|
|
90
|
+
if (match) {
|
|
91
|
+
detectedPort = parseInt(match[2]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (detectedPort !== undefined) {
|
|
95
|
+
child.stdout?.removeListener('data', onStdout);
|
|
96
|
+
child.stderr?.removeListener('data', onStderr);
|
|
97
|
+
child.removeListener('close', onClose);
|
|
98
|
+
resolve();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
43
101
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
102
|
+
const onStderr = (data: Buffer) => {
|
|
103
|
+
stderr += data.toString();
|
|
104
|
+
logger?.debug(data.toString().trim());
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const onClose = (code: number | null) => {
|
|
108
|
+
child.stdout?.removeListener('data', onStdout);
|
|
109
|
+
child.stderr?.removeListener('data', onStderr);
|
|
110
|
+
reject(new Error(`Anvil exited with code ${code} before listening. stderr: ${stderr}`));
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
child.stdout?.on('data', onStdout);
|
|
114
|
+
child.stderr?.on('data', onStderr);
|
|
115
|
+
child.once('close', onClose);
|
|
48
116
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
117
|
+
|
|
118
|
+
// Continue piping for logging, method-call capture, and/or dateProvider sync after startup.
|
|
119
|
+
if (logger || opts.captureMethodCalls || opts.dateProvider) {
|
|
120
|
+
child.stdout?.on('data', (data: Buffer) => {
|
|
121
|
+
const text = data.toString();
|
|
122
|
+
logger?.debug(text.trim());
|
|
123
|
+
methodCalls?.push(...(text.match(/eth_[^\s]+/g) || []));
|
|
124
|
+
if (opts.dateProvider) {
|
|
125
|
+
syncDateProviderFromAnvilOutput(text, opts.dateProvider);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
child.stderr?.on('data', (data: Buffer) => {
|
|
129
|
+
logger?.debug(data.toString().trim());
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
// Consume streams so the child process doesn't block on full pipe buffers.
|
|
133
|
+
child.stdout?.resume();
|
|
134
|
+
child.stderr?.resume();
|
|
52
135
|
}
|
|
53
136
|
|
|
54
|
-
return
|
|
137
|
+
return child;
|
|
55
138
|
},
|
|
56
139
|
'Start anvil',
|
|
57
140
|
makeBackoff([5, 5, 5]),
|
|
58
141
|
);
|
|
59
142
|
|
|
60
|
-
if (!
|
|
143
|
+
if (!detectedPort) {
|
|
61
144
|
throw new Error('Failed to start anvil');
|
|
62
145
|
}
|
|
63
146
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
147
|
+
const port = detectedPort;
|
|
148
|
+
let status: 'listening' | 'idle' = 'listening';
|
|
149
|
+
|
|
150
|
+
anvil.once('close', () => {
|
|
151
|
+
status = 'idle';
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const stop = async () => {
|
|
155
|
+
if (status === 'idle') {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
await killChild(anvil);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const anvilObj: Anvil = {
|
|
162
|
+
port,
|
|
163
|
+
host: '127.0.0.1',
|
|
164
|
+
get status() {
|
|
165
|
+
return status;
|
|
166
|
+
},
|
|
167
|
+
stop,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return { anvil: anvilObj, methodCalls, stop, rpcUrl: `http://127.0.0.1:${port}` };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Extracts block time from anvil stdout and syncs the dateProvider. */
|
|
174
|
+
function syncDateProviderFromAnvilOutput(text: string, dateProvider: TestDateProvider): void {
|
|
175
|
+
// Anvil logs mined blocks as:
|
|
176
|
+
// Block Time: "Fri, 20 Mar 2026 02:10:46 +0000"
|
|
177
|
+
const match = text.match(/Block Time:\s*"([^"]+)"/);
|
|
178
|
+
if (match) {
|
|
179
|
+
const blockTimeMs = new Date(match[1]).getTime();
|
|
180
|
+
if (!isNaN(blockTimeMs)) {
|
|
181
|
+
dateProvider.setTime(blockTimeMs);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Send SIGTERM, wait up to 5 s, then SIGKILL. All timers are always cleared. */
|
|
187
|
+
function killChild(child: ChildProcess): Promise<void> {
|
|
188
|
+
return new Promise<void>(resolve => {
|
|
189
|
+
if (child.exitCode !== null || child.killed) {
|
|
190
|
+
child.stdout?.destroy();
|
|
191
|
+
child.stderr?.destroy();
|
|
192
|
+
resolve();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let killTimer: NodeJS.Timeout | undefined;
|
|
197
|
+
|
|
198
|
+
const onClose = () => {
|
|
199
|
+
if (killTimer !== undefined) {
|
|
200
|
+
clearTimeout(killTimer);
|
|
201
|
+
}
|
|
202
|
+
// Destroy stdio streams so their PipeWrap handles don't keep the event loop alive.
|
|
203
|
+
child.stdout?.destroy();
|
|
204
|
+
child.stderr?.destroy();
|
|
205
|
+
resolve();
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
child.once('close', onClose);
|
|
209
|
+
child.kill('SIGTERM');
|
|
210
|
+
|
|
211
|
+
killTimer = setTimeout(() => {
|
|
212
|
+
killTimer = undefined;
|
|
213
|
+
child.kill('SIGKILL');
|
|
214
|
+
}, 5000);
|
|
215
|
+
|
|
216
|
+
// Ensure the timer does not prevent Node from exiting.
|
|
217
|
+
killTimer.unref();
|
|
218
|
+
});
|
|
67
219
|
}
|
|
@@ -7,7 +7,7 @@ import { type GetContractReturnType, type PrivateKeyAccount, getContract } from
|
|
|
7
7
|
|
|
8
8
|
import { extractProposalIdFromLogs } from '../contracts/governance.js';
|
|
9
9
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
10
|
-
import {
|
|
10
|
+
import { createL1TxUtils } from '../l1_tx_utils/index.js';
|
|
11
11
|
import type { ExtendedViemWalletClient, ViemPublicClient } from '../types.js';
|
|
12
12
|
import { EthCheatCodes } from './eth_cheat_codes.js';
|
|
13
13
|
|
|
@@ -22,7 +22,7 @@ export async function executeGovernanceProposal(
|
|
|
22
22
|
) {
|
|
23
23
|
const proposal = await governance.read.getProposal([proposalId]);
|
|
24
24
|
|
|
25
|
-
const l1TxUtils =
|
|
25
|
+
const l1TxUtils = createL1TxUtils(l1Client);
|
|
26
26
|
|
|
27
27
|
const waitL1Block = async () => {
|
|
28
28
|
await l1TxUtils.sendAndMonitorTransaction({
|