@aztec/ethereum 3.0.0-nightly.20250910 → 3.0.0-nightly.20250912
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/config.d.ts +6 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +12 -30
- package/dest/contracts/empire_slashing_proposer.d.ts +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +1 -1
- package/dest/contracts/rollup.d.ts +13 -6
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +49 -23
- package/dest/deploy_l1_contracts.d.ts +4 -4
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +51 -25
- package/dest/l1_artifacts.d.ts +689 -62
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_tx_utils.d.ts +4 -2
- package/dest/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils.js +21 -13
- package/dest/l1_tx_utils_with_blobs.d.ts +2 -1
- package/dest/l1_tx_utils_with_blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils_with_blobs.js +7 -5
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +8 -11
- package/dest/test/chain_monitor.d.ts +4 -0
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +57 -11
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +10 -161
- package/package.json +5 -5
- package/src/config.ts +17 -35
- package/src/contracts/empire_slashing_proposer.ts +6 -2
- package/src/contracts/rollup.ts +58 -22
- package/src/deploy_l1_contracts.ts +65 -22
- package/src/l1_tx_utils.ts +28 -9
- package/src/l1_tx_utils_with_blobs.ts +8 -2
- package/src/queries.ts +9 -7
- package/src/test/chain_monitor.ts +64 -8
- package/src/utils.ts +13 -185
package/src/contracts/rollup.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
4
4
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
5
5
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
6
|
-
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
7
6
|
|
|
8
7
|
import chunk from 'lodash.chunk';
|
|
9
8
|
import {
|
|
@@ -11,8 +10,8 @@ import {
|
|
|
11
10
|
type GetContractReturnType,
|
|
12
11
|
type Hex,
|
|
13
12
|
type StateOverride,
|
|
13
|
+
type WatchContractEventReturnType,
|
|
14
14
|
encodeFunctionData,
|
|
15
|
-
getAddress,
|
|
16
15
|
getContract,
|
|
17
16
|
hexToBigInt,
|
|
18
17
|
keccak256,
|
|
@@ -160,13 +159,12 @@ export class RollupContract {
|
|
|
160
159
|
public async getSlashingProposer(): Promise<
|
|
161
160
|
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
162
161
|
> {
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
162
|
+
const slasher = await this.getSlasherContract();
|
|
163
|
+
if (!slasher) {
|
|
165
164
|
return undefined;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
const
|
|
169
|
-
const proposerAddress = await slasher.read.PROPOSER();
|
|
167
|
+
const proposerAddress = await slasher.getProposer();
|
|
170
168
|
const proposerAbi = [
|
|
171
169
|
{
|
|
172
170
|
type: 'function',
|
|
@@ -177,7 +175,7 @@ export class RollupContract {
|
|
|
177
175
|
},
|
|
178
176
|
] as const;
|
|
179
177
|
|
|
180
|
-
const proposer = getContract({ address: proposerAddress, abi: proposerAbi, client: this.client });
|
|
178
|
+
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
181
179
|
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
182
180
|
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
183
181
|
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
@@ -223,6 +221,16 @@ export class RollupContract {
|
|
|
223
221
|
return this.rollup.read.getEjectionThreshold();
|
|
224
222
|
}
|
|
225
223
|
|
|
224
|
+
@memoize
|
|
225
|
+
getLocalEjectionThreshold() {
|
|
226
|
+
return this.rollup.read.getLocalEjectionThreshold();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@memoize
|
|
230
|
+
getLagInEpochs() {
|
|
231
|
+
return this.rollup.read.getLagInEpochs();
|
|
232
|
+
}
|
|
233
|
+
|
|
226
234
|
@memoize
|
|
227
235
|
getActivationThreshold() {
|
|
228
236
|
return this.rollup.read.getActivationThreshold();
|
|
@@ -293,16 +301,19 @@ export class RollupContract {
|
|
|
293
301
|
};
|
|
294
302
|
}
|
|
295
303
|
|
|
296
|
-
|
|
304
|
+
getSlasherAddress() {
|
|
297
305
|
return this.rollup.read.getSlasher();
|
|
298
306
|
}
|
|
299
307
|
|
|
300
308
|
/**
|
|
301
309
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
302
310
|
*/
|
|
303
|
-
async getSlasherContract(): Promise<SlasherContract> {
|
|
304
|
-
const slasherAddress = await this.
|
|
305
|
-
|
|
311
|
+
async getSlasherContract(): Promise<SlasherContract | undefined> {
|
|
312
|
+
const slasherAddress = EthAddress.fromString(await this.getSlasherAddress());
|
|
313
|
+
if (slasherAddress.isZero()) {
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
return new SlasherContract(this.client, slasherAddress);
|
|
306
317
|
}
|
|
307
318
|
|
|
308
319
|
getOwner() {
|
|
@@ -314,13 +325,11 @@ export class RollupContract {
|
|
|
314
325
|
}
|
|
315
326
|
|
|
316
327
|
public async getSlashingProposerAddress() {
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
});
|
|
323
|
-
return EthAddress.fromString(await slasher.read.PROPOSER());
|
|
328
|
+
const slasher = await this.getSlasherContract();
|
|
329
|
+
if (!slasher) {
|
|
330
|
+
return EthAddress.ZERO;
|
|
331
|
+
}
|
|
332
|
+
return await slasher.getProposer();
|
|
324
333
|
}
|
|
325
334
|
|
|
326
335
|
getBlockReward() {
|
|
@@ -433,8 +442,15 @@ export class RollupContract {
|
|
|
433
442
|
return this.rollup.read.getEntryQueueLength();
|
|
434
443
|
}
|
|
435
444
|
|
|
436
|
-
|
|
437
|
-
|
|
445
|
+
getNextFlushableEpoch() {
|
|
446
|
+
return this.rollup.read.getNextFlushableEpoch();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
getCurrentEpochNumber(): Promise<bigint> {
|
|
450
|
+
return this.rollup.read.getCurrentEpoch();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
getEpochNumberForBlock(blockNumber: bigint) {
|
|
438
454
|
return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
|
|
439
455
|
}
|
|
440
456
|
|
|
@@ -719,7 +735,9 @@ export class RollupContract {
|
|
|
719
735
|
});
|
|
720
736
|
}
|
|
721
737
|
|
|
722
|
-
public listenToSlasherChanged(
|
|
738
|
+
public listenToSlasherChanged(
|
|
739
|
+
callback: (args: { oldSlasher: `0x${string}`; newSlasher: `0x${string}` }) => unknown,
|
|
740
|
+
): WatchContractEventReturnType {
|
|
723
741
|
return this.rollup.watchEvent.SlasherUpdated(
|
|
724
742
|
{},
|
|
725
743
|
{
|
|
@@ -735,6 +753,22 @@ export class RollupContract {
|
|
|
735
753
|
);
|
|
736
754
|
}
|
|
737
755
|
|
|
756
|
+
public listenToBlockInvalidated(callback: (args: { blockNumber: bigint }) => unknown): WatchContractEventReturnType {
|
|
757
|
+
return this.rollup.watchEvent.BlockInvalidated(
|
|
758
|
+
{},
|
|
759
|
+
{
|
|
760
|
+
onLogs: logs => {
|
|
761
|
+
for (const log of logs) {
|
|
762
|
+
const args = log.args;
|
|
763
|
+
if (args.blockNumber !== undefined) {
|
|
764
|
+
callback({ blockNumber: args.blockNumber });
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
738
772
|
public async getSlashEvents(l1BlockHash: Hex): Promise<{ amount: bigint; attester: EthAddress }[]> {
|
|
739
773
|
const events = await this.rollup.getEvents.Slashed({}, { blockHash: l1BlockHash, strict: true });
|
|
740
774
|
return events.map(event => ({
|
|
@@ -743,7 +777,9 @@ export class RollupContract {
|
|
|
743
777
|
}));
|
|
744
778
|
}
|
|
745
779
|
|
|
746
|
-
public listenToSlash(
|
|
780
|
+
public listenToSlash(
|
|
781
|
+
callback: (args: { amount: bigint; attester: EthAddress }) => unknown,
|
|
782
|
+
): WatchContractEventReturnType {
|
|
747
783
|
return this.rollup.watchEvent.Slashed(
|
|
748
784
|
{},
|
|
749
785
|
{
|
|
@@ -5,6 +5,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
5
5
|
import type { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
7
7
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
8
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
10
|
import type { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
11
|
|
|
@@ -33,7 +34,6 @@ import { createExtendedL1Client } from './client.js';
|
|
|
33
34
|
import {
|
|
34
35
|
type L1ContractsConfig,
|
|
35
36
|
getEntryQueueConfig,
|
|
36
|
-
getGSEConfiguration,
|
|
37
37
|
getGovernanceConfiguration,
|
|
38
38
|
getRewardBoostConfig,
|
|
39
39
|
getRewardConfig,
|
|
@@ -193,13 +193,11 @@ export const deploySharedContracts = async (
|
|
|
193
193
|
const stakingAssetAddress = await deployer.deploy(StakingAssetArtifact, ['Staking', 'STK', l1Client.account.address]);
|
|
194
194
|
logger.verbose(`Deployed Staking Asset at ${stakingAssetAddress}`);
|
|
195
195
|
|
|
196
|
-
const gseConfiguration = getGSEConfiguration(networkName);
|
|
197
|
-
|
|
198
196
|
const gseAddress = await deployer.deploy(GSEArtifact, [
|
|
199
197
|
l1Client.account.address,
|
|
200
198
|
stakingAssetAddress.toString(),
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
args.activationThreshold,
|
|
200
|
+
args.ejectionThreshold,
|
|
203
201
|
]);
|
|
204
202
|
logger.verbose(`Deployed GSE at ${gseAddress}`);
|
|
205
203
|
|
|
@@ -433,6 +431,7 @@ export const deployRollupForUpgrade = async (
|
|
|
433
431
|
registryAddress: EthAddress,
|
|
434
432
|
logger: Logger,
|
|
435
433
|
txUtilsConfig: L1TxUtilsConfig,
|
|
434
|
+
flushEntryQueue: boolean = true,
|
|
436
435
|
) => {
|
|
437
436
|
const deployer = new L1Deployer(
|
|
438
437
|
extendedClient,
|
|
@@ -445,7 +444,14 @@ export const deployRollupForUpgrade = async (
|
|
|
445
444
|
|
|
446
445
|
const addresses = await RegistryContract.collectAddresses(extendedClient, registryAddress, 'canonical');
|
|
447
446
|
|
|
448
|
-
const { rollup, slashFactoryAddress } = await deployRollup(
|
|
447
|
+
const { rollup, slashFactoryAddress } = await deployRollup(
|
|
448
|
+
extendedClient,
|
|
449
|
+
deployer,
|
|
450
|
+
args,
|
|
451
|
+
addresses,
|
|
452
|
+
flushEntryQueue,
|
|
453
|
+
logger,
|
|
454
|
+
);
|
|
449
455
|
|
|
450
456
|
await deployer.waitForDeployments();
|
|
451
457
|
|
|
@@ -504,6 +510,7 @@ export const deployRollup = async (
|
|
|
504
510
|
| 'gseAddress'
|
|
505
511
|
| 'governanceAddress'
|
|
506
512
|
>,
|
|
513
|
+
flushEntryQueue: boolean,
|
|
507
514
|
logger: Logger,
|
|
508
515
|
) => {
|
|
509
516
|
if (!addresses.gseAddress) {
|
|
@@ -533,6 +540,7 @@ export const deployRollup = async (
|
|
|
533
540
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
534
541
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
535
542
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
543
|
+
lagInEpochs: BigInt(args.lagInEpochs),
|
|
536
544
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
537
545
|
slashingQuorum: BigInt(args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1),
|
|
538
546
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -549,6 +557,7 @@ export const deployRollup = async (
|
|
|
549
557
|
slasherFlavor: slasherFlavorToSolidityEnum(args.slasherFlavor),
|
|
550
558
|
slashingOffsetInRounds: BigInt(args.slashingOffsetInRounds),
|
|
551
559
|
slashAmounts: [args.slashAmountSmall, args.slashAmountMedium, args.slashAmountLarge],
|
|
560
|
+
localEjectionThreshold: args.localEjectionThreshold,
|
|
552
561
|
};
|
|
553
562
|
|
|
554
563
|
const genesisStateArgs = {
|
|
@@ -676,6 +685,7 @@ export const deployRollup = async (
|
|
|
676
685
|
addresses.stakingAssetAddress.toString(),
|
|
677
686
|
args.initialValidators,
|
|
678
687
|
args.acceleratedTestDeployments,
|
|
688
|
+
flushEntryQueue,
|
|
679
689
|
logger,
|
|
680
690
|
);
|
|
681
691
|
}
|
|
@@ -852,6 +862,7 @@ export const addMultipleValidators = async (
|
|
|
852
862
|
stakingAssetAddress: Hex,
|
|
853
863
|
validators: Operator[],
|
|
854
864
|
acceleratedTestDeployments: boolean | undefined,
|
|
865
|
+
flushEntryQueue: boolean,
|
|
855
866
|
logger: Logger,
|
|
856
867
|
) => {
|
|
857
868
|
const rollup = new RollupContract(extendedClient, rollupAddress);
|
|
@@ -918,7 +929,7 @@ export const addMultipleValidators = async (
|
|
|
918
929
|
data: encodeFunctionData({
|
|
919
930
|
abi: MultiAdderArtifact.contractAbi,
|
|
920
931
|
functionName: 'addValidators',
|
|
921
|
-
args: [validatorsTuples, true],
|
|
932
|
+
args: [validatorsTuples, /* skip flushing */ true],
|
|
922
933
|
}),
|
|
923
934
|
},
|
|
924
935
|
{
|
|
@@ -926,19 +937,49 @@ export const addMultipleValidators = async (
|
|
|
926
937
|
},
|
|
927
938
|
);
|
|
928
939
|
|
|
929
|
-
await
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
940
|
+
let queueLength = await rollup.getEntryQueueLength();
|
|
941
|
+
while (flushEntryQueue && queueLength > 0n) {
|
|
942
|
+
logger.info(`Flushing entry queue with ${queueLength} entries`);
|
|
943
|
+
|
|
944
|
+
try {
|
|
945
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
946
|
+
{
|
|
947
|
+
to: rollupAddress,
|
|
948
|
+
data: encodeFunctionData({
|
|
949
|
+
abi: RollupArtifact.contractAbi,
|
|
950
|
+
functionName: 'flushEntryQueue',
|
|
951
|
+
args: [],
|
|
952
|
+
}),
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
gasLimit: 20_000_000n,
|
|
956
|
+
},
|
|
957
|
+
);
|
|
958
|
+
} catch (err) {
|
|
959
|
+
logger.warn('Failed to flush queue', { err });
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
queueLength = await rollup.getEntryQueueLength();
|
|
963
|
+
// check if we drained the queue enough here so we can avoid sleep
|
|
964
|
+
if (queueLength === 0n) {
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
logger.info(`Waiting for next flushable epoch to flush remaining ${queueLength} entries`);
|
|
969
|
+
await retryUntil(
|
|
970
|
+
async () => {
|
|
971
|
+
const [currentEpoch, flushableEpoch] = await Promise.all([
|
|
972
|
+
rollup.getCurrentEpochNumber(),
|
|
973
|
+
rollup.getNextFlushableEpoch(),
|
|
974
|
+
]);
|
|
975
|
+
logger.debug(`Next flushable epoch is ${flushableEpoch} (current epoch is ${currentEpoch})`);
|
|
976
|
+
return currentEpoch >= flushableEpoch;
|
|
977
|
+
},
|
|
978
|
+
'wait for next flushable epoch',
|
|
979
|
+
3600,
|
|
980
|
+
12,
|
|
981
|
+
);
|
|
982
|
+
}
|
|
942
983
|
} else {
|
|
943
984
|
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
944
985
|
{
|
|
@@ -946,7 +987,7 @@ export const addMultipleValidators = async (
|
|
|
946
987
|
data: encodeFunctionData({
|
|
947
988
|
abi: MultiAdderArtifact.contractAbi,
|
|
948
989
|
functionName: 'addValidators',
|
|
949
|
-
args: [validatorsTuples,
|
|
990
|
+
args: [validatorsTuples, /* skip flushing */ !flushEntryQueue],
|
|
950
991
|
}),
|
|
951
992
|
},
|
|
952
993
|
{
|
|
@@ -1029,6 +1070,7 @@ export const deployL1Contracts = async (
|
|
|
1029
1070
|
args: DeployL1ContractsArgs,
|
|
1030
1071
|
txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(),
|
|
1031
1072
|
createVerificationJson: string | false = false,
|
|
1073
|
+
flushEntryQueue: boolean = true,
|
|
1032
1074
|
): Promise<DeployL1ContractsReturnType> => {
|
|
1033
1075
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1034
1076
|
validateConfig(args);
|
|
@@ -1095,6 +1137,7 @@ export const deployL1Contracts = async (
|
|
|
1095
1137
|
stakingAssetAddress,
|
|
1096
1138
|
governanceAddress,
|
|
1097
1139
|
},
|
|
1140
|
+
flushEntryQueue,
|
|
1098
1141
|
logger,
|
|
1099
1142
|
);
|
|
1100
1143
|
|
|
@@ -1145,7 +1188,7 @@ export const deployL1Contracts = async (
|
|
|
1145
1188
|
|
|
1146
1189
|
// Include Slasher and SlashingProposer (if deployed) in verification data
|
|
1147
1190
|
try {
|
|
1148
|
-
const slasherAddrHex = await rollup.
|
|
1191
|
+
const slasherAddrHex = await rollup.getSlasherAddress();
|
|
1149
1192
|
const slasherAddr = EthAddress.fromString(slasherAddrHex);
|
|
1150
1193
|
if (!slasherAddr.isZero()) {
|
|
1151
1194
|
// Slasher constructor: (address _vetoer, address _governance)
|
package/src/l1_tx_utils.ts
CHANGED
|
@@ -279,7 +279,13 @@ export class ReadOnlyL1TxUtils {
|
|
|
279
279
|
let blobBaseFee = 0n;
|
|
280
280
|
if (isBlobTx) {
|
|
281
281
|
try {
|
|
282
|
-
blobBaseFee = await
|
|
282
|
+
blobBaseFee = await retry<bigint>(
|
|
283
|
+
() => this.client.getBlobBaseFee(),
|
|
284
|
+
'Getting L1 blob base fee',
|
|
285
|
+
makeBackoff(times(2, () => 1)),
|
|
286
|
+
this.logger,
|
|
287
|
+
true,
|
|
288
|
+
);
|
|
283
289
|
this.logger?.debug('L1 Blob base fee:', { blobBaseFee: formatGwei(blobBaseFee) });
|
|
284
290
|
} catch {
|
|
285
291
|
this.logger?.warn('Failed to get L1 blob base fee', attempt);
|
|
@@ -706,12 +712,14 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
706
712
|
* Monitors a transaction until completion, handling speed-ups if needed
|
|
707
713
|
* @param request - Original transaction request (needed for speed-ups)
|
|
708
714
|
* @param initialTxHash - Hash of the initial transaction
|
|
715
|
+
* @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
|
|
709
716
|
* @param params - Parameters used in the initial transaction
|
|
710
717
|
* @param gasConfig - Optional gas configuration
|
|
711
718
|
*/
|
|
712
719
|
public async monitorTransaction(
|
|
713
720
|
request: L1TxRequest,
|
|
714
721
|
initialTxHash: Hex,
|
|
722
|
+
allVersions: Set<Hex>,
|
|
715
723
|
params: { gasLimit: bigint },
|
|
716
724
|
_gasConfig?: Partial<L1TxUtilsConfig> & { txTimeoutAt?: Date },
|
|
717
725
|
_blobInputs?: L1BlobInputs,
|
|
@@ -743,7 +751,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
743
751
|
}
|
|
744
752
|
const nonce = tx.nonce;
|
|
745
753
|
|
|
746
|
-
|
|
754
|
+
allVersions.add(initialTxHash);
|
|
747
755
|
let currentTxHash = initialTxHash;
|
|
748
756
|
let attempts = 0;
|
|
749
757
|
let lastAttemptSent = this.dateProvider.now();
|
|
@@ -776,8 +784,9 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
776
784
|
}));
|
|
777
785
|
|
|
778
786
|
const currentNonce = await this.client.getTransactionCount({ address: account });
|
|
787
|
+
// If the current nonce on our account is greater than our transaction's nonce then a tx with the same nonce has been mined.
|
|
779
788
|
if (currentNonce > nonce) {
|
|
780
|
-
for (const hash of
|
|
789
|
+
for (const hash of allVersions) {
|
|
781
790
|
try {
|
|
782
791
|
const receipt = await this.client.getTransactionReceipt({ hash });
|
|
783
792
|
if (receipt) {
|
|
@@ -796,6 +805,10 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
796
805
|
}
|
|
797
806
|
}
|
|
798
807
|
}
|
|
808
|
+
// If we get here then we have checked all of our tx versions and not found anything.
|
|
809
|
+
// We should consider the nonce as MINED
|
|
810
|
+
this.state = TxUtilsState.MINED;
|
|
811
|
+
throw new Error(`Nonce ${nonce} is MINED but not by one of our expected transactions`);
|
|
799
812
|
}
|
|
800
813
|
|
|
801
814
|
this.logger?.trace(`Tx timeout check for ${currentTxHash}: ${isTimedOut()}`, {
|
|
@@ -857,7 +870,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
857
870
|
},
|
|
858
871
|
);
|
|
859
872
|
|
|
860
|
-
const txData = {
|
|
873
|
+
const txData: PrepareTransactionRequestRequest = {
|
|
861
874
|
...request,
|
|
862
875
|
...blobInputs,
|
|
863
876
|
nonce,
|
|
@@ -865,6 +878,9 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
865
878
|
maxFeePerGas: newGasPrice.maxFeePerGas,
|
|
866
879
|
maxPriorityFeePerGas: newGasPrice.maxPriorityFeePerGas,
|
|
867
880
|
};
|
|
881
|
+
if (isBlobTx && newGasPrice.maxFeePerBlobGas) {
|
|
882
|
+
(txData as any).maxFeePerBlobGas = newGasPrice.maxFeePerBlobGas;
|
|
883
|
+
}
|
|
868
884
|
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
869
885
|
const newHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
870
886
|
if (!isCancelTx) {
|
|
@@ -882,7 +898,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
882
898
|
|
|
883
899
|
currentTxHash = newHash;
|
|
884
900
|
|
|
885
|
-
|
|
901
|
+
allVersions.add(currentTxHash);
|
|
886
902
|
lastAttemptSent = this.dateProvider.now();
|
|
887
903
|
}
|
|
888
904
|
await sleep(gasConfig.checkIntervalMs!);
|
|
@@ -904,7 +920,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
904
920
|
this.state = TxUtilsState.NOT_MINED;
|
|
905
921
|
} else if (gasConfig.cancelTxOnTimeout) {
|
|
906
922
|
// Fire cancellation without awaiting to avoid blocking the main thread
|
|
907
|
-
this.attemptTxCancellation(currentTxHash, nonce, isBlobTx, lastGasPrice, attempts).catch(err => {
|
|
923
|
+
this.attemptTxCancellation(currentTxHash, nonce, allVersions, isBlobTx, lastGasPrice, attempts).catch(err => {
|
|
908
924
|
const viemError = formatViemError(err);
|
|
909
925
|
this.logger?.error(`Failed to send cancellation for timed out tx ${currentTxHash}:`, viemError.message, {
|
|
910
926
|
metaMessages: viemError.metaMessages,
|
|
@@ -938,7 +954,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
938
954
|
blobInputs?: L1BlobInputs,
|
|
939
955
|
): Promise<{ receipt: TransactionReceipt; gasPrice: GasPrice }> {
|
|
940
956
|
const { txHash, gasLimit, gasPrice } = await this.sendTransaction(request, gasConfig, blobInputs);
|
|
941
|
-
const receipt = await this.monitorTransaction(request, txHash, { gasLimit }, gasConfig, blobInputs);
|
|
957
|
+
const receipt = await this.monitorTransaction(request, txHash, new Set(), { gasLimit }, gasConfig, blobInputs);
|
|
942
958
|
return { receipt, gasPrice };
|
|
943
959
|
}
|
|
944
960
|
|
|
@@ -973,6 +989,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
973
989
|
/**
|
|
974
990
|
* Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
|
|
975
991
|
* @param nonce - The nonce of the transaction to cancel
|
|
992
|
+
* @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
|
|
976
993
|
* @param previousGasPrice - The gas price of the previous transaction
|
|
977
994
|
* @param attempts - The number of attempts to cancel the transaction
|
|
978
995
|
* @returns The hash of the cancellation transaction
|
|
@@ -980,6 +997,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
980
997
|
protected async attemptTxCancellation(
|
|
981
998
|
currentTxHash: Hex,
|
|
982
999
|
nonce: number,
|
|
1000
|
+
allVersions: Set<Hex>,
|
|
983
1001
|
isBlobTx = false,
|
|
984
1002
|
previousGasPrice?: GasPrice,
|
|
985
1003
|
attempts = 0,
|
|
@@ -1000,7 +1018,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
1000
1018
|
previousGasPrice,
|
|
1001
1019
|
);
|
|
1002
1020
|
|
|
1003
|
-
this.logger?.
|
|
1021
|
+
this.logger?.info(`Attempting to cancel L1 transaction ${currentTxHash} with nonce ${nonce}`, {
|
|
1004
1022
|
maxFeePerGas: formatGwei(cancelGasPrice.maxFeePerGas),
|
|
1005
1023
|
maxPriorityFeePerGas: formatGwei(cancelGasPrice.maxPriorityFeePerGas),
|
|
1006
1024
|
});
|
|
@@ -1022,11 +1040,12 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
1022
1040
|
|
|
1023
1041
|
this.state = TxUtilsState.CANCELLED;
|
|
1024
1042
|
|
|
1025
|
-
this.logger?.
|
|
1043
|
+
this.logger?.info(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`, { nonce });
|
|
1026
1044
|
|
|
1027
1045
|
const receipt = await this.monitorTransaction(
|
|
1028
1046
|
request,
|
|
1029
1047
|
cancelTxHash,
|
|
1048
|
+
allVersions,
|
|
1030
1049
|
{ gasLimit: 21_000n },
|
|
1031
1050
|
undefined,
|
|
1032
1051
|
undefined,
|
|
@@ -19,6 +19,7 @@ export class L1TxUtilsWithBlobs extends L1TxUtils {
|
|
|
19
19
|
/**
|
|
20
20
|
* Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
|
|
21
21
|
* @param nonce - The nonce of the transaction to cancel
|
|
22
|
+
* @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
|
|
22
23
|
* @param previousGasPrice - The gas price of the previous transaction
|
|
23
24
|
* @param attempts - The number of attempts to cancel the transaction
|
|
24
25
|
* @returns The hash of the cancellation transaction
|
|
@@ -26,6 +27,7 @@ export class L1TxUtilsWithBlobs extends L1TxUtils {
|
|
|
26
27
|
override async attemptTxCancellation(
|
|
27
28
|
currentTxHash: Hex,
|
|
28
29
|
nonce: number,
|
|
30
|
+
allVersions: Set<Hex>,
|
|
29
31
|
isBlobTx = false,
|
|
30
32
|
previousGasPrice?: GasPrice,
|
|
31
33
|
attempts = 0,
|
|
@@ -42,7 +44,7 @@ export class L1TxUtilsWithBlobs extends L1TxUtils {
|
|
|
42
44
|
previousGasPrice,
|
|
43
45
|
);
|
|
44
46
|
|
|
45
|
-
this.logger?.
|
|
47
|
+
this.logger?.info(`Attempting to cancel blob L1 transaction ${currentTxHash} with nonce ${nonce}`, {
|
|
46
48
|
maxFeePerGas: formatGwei(cancelGasPrice.maxFeePerGas),
|
|
47
49
|
maxPriorityFeePerGas: formatGwei(cancelGasPrice.maxPriorityFeePerGas),
|
|
48
50
|
maxFeePerBlobGas:
|
|
@@ -65,9 +67,12 @@ export class L1TxUtilsWithBlobs extends L1TxUtils {
|
|
|
65
67
|
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
66
68
|
const cancelTxHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
67
69
|
|
|
70
|
+
this.logger?.info(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`);
|
|
71
|
+
|
|
68
72
|
const receipt = await this.monitorTransaction(
|
|
69
73
|
request,
|
|
70
74
|
cancelTxHash,
|
|
75
|
+
allVersions,
|
|
71
76
|
{ gasLimit: 21_000n },
|
|
72
77
|
undefined,
|
|
73
78
|
undefined,
|
|
@@ -94,11 +99,12 @@ export class L1TxUtilsWithBlobs extends L1TxUtils {
|
|
|
94
99
|
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
95
100
|
const cancelTxHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
96
101
|
|
|
97
|
-
this.logger?.
|
|
102
|
+
this.logger?.info(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`);
|
|
98
103
|
|
|
99
104
|
const receipt = await this.monitorTransaction(
|
|
100
105
|
request,
|
|
101
106
|
cancelTxHash,
|
|
107
|
+
allVersions,
|
|
102
108
|
{ gasLimit: 21_000n },
|
|
103
109
|
undefined,
|
|
104
110
|
blobInputs,
|
package/src/queries.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
-
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
3
|
-
|
|
4
|
-
import { getContract } from 'viem';
|
|
5
2
|
|
|
6
3
|
import type { L1ContractsConfig } from './config.js';
|
|
7
4
|
import { ReadOnlyGovernanceContract } from './contracts/governance.js';
|
|
@@ -27,8 +24,7 @@ export async function getL1ContractsConfig(
|
|
|
27
24
|
const rollupAddress = addresses.rollupAddress ?? (await governanceProposer.getRollupAddress());
|
|
28
25
|
const rollup = new RollupContract(publicClient, rollupAddress.toString());
|
|
29
26
|
const slasherProposer = await rollup.getSlashingProposer();
|
|
30
|
-
const
|
|
31
|
-
const slasher = getContract({ address: slasherAddress, abi: SlasherAbi, client: publicClient });
|
|
27
|
+
const slasher = await rollup.getSlasherContract();
|
|
32
28
|
|
|
33
29
|
const [
|
|
34
30
|
l1StartBlock,
|
|
@@ -37,8 +33,10 @@ export async function getL1ContractsConfig(
|
|
|
37
33
|
aztecSlotDuration,
|
|
38
34
|
aztecProofSubmissionEpochs,
|
|
39
35
|
aztecTargetCommitteeSize,
|
|
36
|
+
lagInEpochs,
|
|
40
37
|
activationThreshold,
|
|
41
38
|
ejectionThreshold,
|
|
39
|
+
localEjectionThreshold,
|
|
42
40
|
governanceProposerQuorum,
|
|
43
41
|
governanceProposerRoundSize,
|
|
44
42
|
slashingQuorum,
|
|
@@ -60,8 +58,10 @@ export async function getL1ContractsConfig(
|
|
|
60
58
|
rollup.getSlotDuration(),
|
|
61
59
|
rollup.getProofSubmissionEpochs(),
|
|
62
60
|
rollup.getTargetCommitteeSize(),
|
|
61
|
+
rollup.getLagInEpochs(),
|
|
63
62
|
rollup.getActivationThreshold(),
|
|
64
63
|
rollup.getEjectionThreshold(),
|
|
64
|
+
rollup.getLocalEjectionThreshold(),
|
|
65
65
|
governanceProposer.getQuorumSize(),
|
|
66
66
|
governanceProposer.getRoundSize(),
|
|
67
67
|
slasherProposer?.getQuorumSize() ?? 0n,
|
|
@@ -70,7 +70,7 @@ export async function getL1ContractsConfig(
|
|
|
70
70
|
slasherProposer?.getExecutionDelayInRounds() ?? 0n,
|
|
71
71
|
slasherProposer?.type === 'tally' ? slasherProposer.getSlashOffsetInRounds() : 0n,
|
|
72
72
|
slasherProposer?.type === 'tally' ? slasherProposer.getSlashingAmounts() : [0n, 0n, 0n],
|
|
73
|
-
slasher
|
|
73
|
+
slasher?.getVetoer() ?? EthAddress.ZERO,
|
|
74
74
|
rollup.getManaTarget(),
|
|
75
75
|
rollup.getProvingCostPerMana(),
|
|
76
76
|
rollup.getVersion(),
|
|
@@ -85,15 +85,17 @@ export async function getL1ContractsConfig(
|
|
|
85
85
|
aztecSlotDuration: Number(aztecSlotDuration),
|
|
86
86
|
aztecProofSubmissionEpochs: Number(aztecProofSubmissionEpochs),
|
|
87
87
|
aztecTargetCommitteeSize: Number(aztecTargetCommitteeSize),
|
|
88
|
+
lagInEpochs: Number(lagInEpochs),
|
|
88
89
|
governanceProposerQuorum: Number(governanceProposerQuorum),
|
|
89
90
|
governanceProposerRoundSize: Number(governanceProposerRoundSize),
|
|
90
91
|
activationThreshold,
|
|
91
92
|
ejectionThreshold,
|
|
93
|
+
localEjectionThreshold,
|
|
92
94
|
slashingQuorum: Number(slashingQuorum),
|
|
93
95
|
slashingRoundSizeInEpochs: Number(slashingRoundSize / aztecEpochDuration),
|
|
94
96
|
slashingLifetimeInRounds: Number(slashingLifetimeInRounds),
|
|
95
97
|
slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
|
|
96
|
-
slashingVetoer
|
|
98
|
+
slashingVetoer,
|
|
97
99
|
manaTarget: manaTarget,
|
|
98
100
|
provingCostPerMana: provingCostPerMana,
|
|
99
101
|
rollupVersion: Number(rollupVersion),
|