Skip to content

Commit cd6ad49

Browse files
committed
fix: using ABIs for error handling & update L1 TX gas limits
1 parent dbc315a commit cd6ad49

File tree

15 files changed

+203
-64
lines changed

15 files changed

+203
-64
lines changed

yarn-project/ethereum/src/contracts/empire_slashing_proposer.ts

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { EmpireSlashingProposerAbi } from '@aztec/l1-artifacts/EmpireSlashingPro
66

77
import EventEmitter from 'events';
88
import {
9-
type EncodeFunctionDataParameters,
109
type GetContractReturnType,
1110
type Hex,
1211
type Log,
@@ -100,6 +99,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
10099
public createSignalRequest(payload: Hex): L1TxRequest {
101100
return {
102101
to: this.address.toString(),
102+
abi: EmpireSlashingProposerAbi,
103103
data: encodeSignal(payload),
104104
};
105105
}
@@ -121,6 +121,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
121121
);
122122
return {
123123
to: this.address.toString(),
124+
abi: EmpireSlashingProposerAbi,
124125
data: encodeSignalWithSignature(payload, signature),
125126
};
126127
}
@@ -180,6 +181,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
180181
public buildExecuteRoundRequest(round: bigint): L1TxRequest {
181182
return {
182183
to: this.address.toString(),
184+
abi: EmpireSlashingProposerAbi,
183185
data: encodeFunctionData({
184186
abi: EmpireSlashingProposerAbi,
185187
functionName: 'submitRoundWinner',
@@ -222,24 +224,13 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
222224
if (typeof round === 'number') {
223225
round = BigInt(round);
224226
}
225-
const args: EncodeFunctionDataParameters<typeof EmpireSlashingProposerAbi, 'submitRoundWinner'> = {
226-
abi: EmpireSlashingProposerAbi,
227-
functionName: 'submitRoundWinner',
228-
args: [round],
229-
};
230-
const data = encodeFunctionData(args);
227+
const request = this.buildExecuteRoundRequest(round);
231228
const response = await txUtils
232-
.sendAndMonitorTransaction(
233-
{
234-
to: this.address.toString(),
235-
data,
236-
},
237-
{
238-
// Gas estimation is way off for this, likely because we are creating the contract/selector to call
239-
// for the actual slashing dynamically.
240-
gasLimitBufferPercentage: 50, // +50% gas
241-
},
242-
)
229+
.sendAndMonitorTransaction(request, {
230+
// Gas estimation is way off for this, likely because we are creating the contract/selector to call
231+
// for the actual slashing dynamically.
232+
gasLimitBufferPercentage: 50, // +50% gas
233+
})
243234
.catch(err => {
244235
if (err instanceof FormattedViemError && err.message.includes('ProposalAlreadyExecuted')) {
245236
throw new ProposalAlreadyExecutedError(round);
@@ -248,15 +239,13 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
248239
});
249240

250241
if (response.receipt.status === 'reverted') {
251-
const error = await txUtils.tryGetErrorFromRevertedTx(
252-
data,
253-
{
254-
...args,
255-
address: this.address.toString(),
256-
},
257-
undefined,
258-
[],
259-
);
242+
const args = {
243+
abi: EmpireSlashingProposerAbi,
244+
functionName: 'submitRoundWinner' as const,
245+
args: [round] as const,
246+
address: this.address.toString(),
247+
};
248+
const error = await txUtils.tryGetErrorFromRevertedTx(request.data!, args, undefined, []);
260249
if (error?.includes('ProposalAlreadyExecuted')) {
261250
throw new ProposalAlreadyExecutedError(round);
262251
}

yarn-project/ethereum/src/contracts/fee_asset_handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class FeeAssetHandlerContract {
4343
}
4444
return txUtils.sendAndMonitorTransaction({
4545
to: this.address.toString(),
46+
abi: FeeAssetHandlerAbi,
4647
data: encodeFunctionData({
4748
abi: FeeAssetHandlerAbi,
4849
functionName: 'mint',
@@ -54,6 +55,7 @@ export class FeeAssetHandlerContract {
5455
public setMintAmount(txUtils: L1TxUtils, amount: bigint) {
5556
return txUtils.sendAndMonitorTransaction({
5657
to: this.address.toString(),
58+
abi: FeeAssetHandlerAbi,
5759
data: encodeFunctionData({
5860
abi: FeeAssetHandlerAbi,
5961
functionName: 'setMintAmount',

yarn-project/ethereum/src/contracts/governance.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
211211

212212
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
213213
to: this.governanceContract.address,
214+
abi: GovernanceAbi,
214215
data: encodedVoteData,
215216
});
216217

@@ -265,6 +266,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
265266

266267
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
267268
to: this.governanceContract.address,
269+
abi: GovernanceAbi,
268270
data: encodedExecuteData,
269271
});
270272

yarn-project/ethereum/src/contracts/governance_proposer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export class GovernanceProposerContract implements IEmpireBase {
8383
public createSignalRequest(payload: Hex): L1TxRequest {
8484
return {
8585
to: this.address.toString(),
86+
abi: GovernanceProposerAbi,
8687
data: encodeSignal(payload),
8788
};
8889
}
@@ -104,6 +105,7 @@ export class GovernanceProposerContract implements IEmpireBase {
104105
);
105106
return {
106107
to: this.address.toString(),
108+
abi: GovernanceProposerAbi,
107109
data: encodeSignalWithSignature(payload, signature),
108110
};
109111
}
@@ -117,8 +119,9 @@ export class GovernanceProposerContract implements IEmpireBase {
117119
}> {
118120
const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
119121
to: this.address.toString(),
122+
abi: GovernanceProposerAbi,
120123
data: encodeFunctionData({
121-
abi: this.proposer.abi,
124+
abi: GovernanceProposerAbi,
122125
functionName: 'submitRoundWinner',
123126
args: [round],
124127
}),

yarn-project/ethereum/src/contracts/multicall.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ export class Multicall3 {
3434
};
3535

3636
const encodedForwarderData = encodeFunctionData(forwarderFunctionData);
37-
3837
try {
3938
const { receipt, state } = await l1TxUtils.sendAndMonitorTransaction(
40-
{ to: MULTI_CALL_3_ADDRESS, data: encodedForwarderData },
39+
{
40+
to: MULTI_CALL_3_ADDRESS,
41+
data: encodedForwarderData,
42+
abi: multicall3Abi,
43+
},
4144
gasConfig,
4245
blobConfig,
4346
);

yarn-project/ethereum/src/contracts/rollup.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ export class RollupContract {
805805
): L1TxRequest {
806806
return {
807807
to: this.address,
808+
abi: RollupAbi,
808809
data: encodeFunctionData({
809810
abi: RollupAbi,
810811
functionName: 'invalidateBadAttestation',
@@ -826,6 +827,7 @@ export class RollupContract {
826827
): L1TxRequest {
827828
return {
828829
to: this.address,
830+
abi: RollupAbi,
829831
data: encodeFunctionData({
830832
abi: RollupAbi,
831833
functionName: 'invalidateInsufficientAttestations',
@@ -959,6 +961,7 @@ export class RollupContract {
959961
setupEpoch(l1TxUtils: L1TxUtils) {
960962
return l1TxUtils.sendAndMonitorTransaction({
961963
to: this.address,
964+
abi: RollupAbi,
962965
data: encodeFunctionData({
963966
abi: RollupAbi,
964967
functionName: 'setupEpoch',
@@ -970,6 +973,7 @@ export class RollupContract {
970973
vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
971974
return l1TxUtils.sendAndMonitorTransaction({
972975
to: this.address,
976+
abi: RollupAbi,
973977
data: encodeFunctionData({
974978
abi: RollupAbi,
975979
functionName: 'vote',

yarn-project/ethereum/src/contracts/tally_slashing_proposer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import type { L1TxRequest } from '@aztec/ethereum/l1-tx-utils';
22
import type { ViemClient } from '@aztec/ethereum/types';
3-
import { tryExtractEvent } from '@aztec/ethereum/utils';
3+
import { mergeAbis, tryExtractEvent } from '@aztec/ethereum/utils';
44
import { SlotNumber } from '@aztec/foundation/branded-types';
55
import { Buffer32 } from '@aztec/foundation/buffer';
66
import { EthAddress } from '@aztec/foundation/eth-address';
77
import { Signature } from '@aztec/foundation/eth-signature';
88
import { hexToBuffer } from '@aztec/foundation/string';
9+
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
910
import { TallySlashingProposerAbi } from '@aztec/l1-artifacts/TallySlashingProposerAbi';
1011

1112
import {
@@ -160,6 +161,7 @@ export class TallySlashingProposerContract {
160161

161162
return {
162163
to: this.contract.address,
164+
abi: TallySlashingProposerAbi,
163165
data: encodeFunctionData({
164166
abi: TallySlashingProposerAbi,
165167
functionName: 'vote',
@@ -207,6 +209,7 @@ export class TallySlashingProposerContract {
207209
public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
208210
return {
209211
to: this.contract.address,
212+
abi: TallySlashingProposerAbi,
210213
data: encodeFunctionData({
211214
abi: TallySlashingProposerAbi,
212215
functionName: 'vote',
@@ -224,6 +227,7 @@ export class TallySlashingProposerContract {
224227
public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
225228
return {
226229
to: this.contract.address,
230+
abi: mergeAbis([TallySlashingProposerAbi, SlasherAbi]),
227231
data: encodeFunctionData({
228232
abi: TallySlashingProposerAbi,
229233
functionName: 'executeRound',

yarn-project/ethereum/src/l1_tx_utils/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// 1_000_000_000_000_000_000 Wei = 1 ETH
44
export const WEI_CONST = 1_000_000_000n;
55

6-
// @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
7-
export const LARGE_GAS_LIMIT = 12_000_000n;
6+
// EIP-7825: protocol-level cap on tx gas limit (2^24). Clients reject above this.
7+
export const MAX_L1_TX_LIMIT = 16_777_216n;
88

99
// setting a minimum bump percentage to 10% due to geth's implementation
1010
// https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298

yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
type L1TxRequest,
3838
type L1TxState,
3939
type L1TxUtilsConfig,
40+
MAX_L1_TX_LIMIT,
4041
ReadOnlyL1TxUtils,
4142
TxUtilsState,
4243
UnknownMinedTxError,
@@ -1416,7 +1417,7 @@ describe('L1TxUtils', () => {
14161417
expect(newState.receipt!.status).toBe('success');
14171418
}, 10_000);
14181419

1419-
it('ensures block gas limit is set when using LARGE_GAS_LIMIT', async () => {
1420+
it('ensures block gas limit is set when using MAX_L1_TX_LIMIT', async () => {
14201421
let capturedBlockOverrides: any = {};
14211422
const originalSimulate = gasUtils['_simulate'].bind(gasUtils);
14221423

@@ -1430,7 +1431,7 @@ describe('L1TxUtils', () => {
14301431
try {
14311432
// Test with ensureBlockGasLimit: true (default)
14321433
await gasUtils.simulate(request, {}, [], undefined, { ignoreBlockGasLimit: false });
1433-
expect(capturedBlockOverrides.gasLimit).toBe(24_000_000n);
1434+
expect(capturedBlockOverrides.gasLimit).toBe(MAX_L1_TX_LIMIT);
14341435

14351436
// Test with ensureBlockGasLimit: false
14361437
capturedBlockOverrides = {};
@@ -1446,7 +1447,7 @@ describe('L1TxUtils', () => {
14461447
}
14471448
});
14481449

1449-
it('ensures block gas limit is set when using LARGE_GAS_LIMIT with custom block overrides', async () => {
1450+
it('ensures block gas limit is set when using MAX_L1_TX_LIMIT with custom block overrides', async () => {
14501451
let capturedBlockOverrides: any = {};
14511452
const originalSimulate = gasUtils['_simulate'].bind(gasUtils);
14521453

@@ -1463,7 +1464,7 @@ describe('L1TxUtils', () => {
14631464
await gasUtils.simulate(request, myCustomBlockOverrides, [], undefined, { ignoreBlockGasLimit: false });
14641465

14651466
// Verify that block gas limit is set while preserving custom overrides
1466-
expect(capturedBlockOverrides.gasLimit).toBe(24_000_000n); // 12_000_000 * 2
1467+
expect(capturedBlockOverrides.gasLimit).toBe(MAX_L1_TX_LIMIT);
14671468
expect(capturedBlockOverrides.baseFeePerGas).toBe(1000000000n);
14681469
} finally {
14691470
spy.mockRestore();

yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { jsonRpc } from 'viem/nonce';
2727
import type { ViemClient } from '../types.js';
2828
import { formatViemError } from '../utils.js';
2929
import { type L1TxUtilsConfig, l1TxUtilsConfigMappings } from './config.js';
30-
import { LARGE_GAS_LIMIT } from './constants.js';
30+
import { MAX_L1_TX_LIMIT } from './constants.js';
3131
import type { IL1TxMetrics, IL1TxStore } from './interfaces.js';
3232
import { ReadOnlyL1TxUtils } from './readonly_l1_tx_utils.js';
3333
import {
@@ -207,7 +207,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
207207

208208
let gasLimit: bigint;
209209
if (this.debugMaxGasLimit) {
210-
gasLimit = LARGE_GAS_LIMIT;
210+
gasLimit = MAX_L1_TX_LIMIT;
211211
} else if (gasConfig.gasLimit) {
212212
gasLimit = gasConfig.gasLimit;
213213
} else {
@@ -283,7 +283,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
283283
return { txHash, state: l1TxState };
284284
} catch (err: any) {
285285
const viemError = formatViemError(err, request.abi);
286-
this.logger.error(`Failed to send L1 transaction`, viemError, {
286+
this.logger.error(`Failed to send L1 transaction: ${viemError.message}`, viemError, {
287287
request: pick(request, 'to', 'value'),
288288
});
289289
throw viemError;
@@ -631,12 +631,12 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
631631
from: request.from ?? this.getSenderAddress().toString(),
632632
maxFeePerGas: gasPrice.maxFeePerGas,
633633
maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
634-
gas: request.gas ?? LARGE_GAS_LIMIT,
634+
gas: request.gas ?? MAX_L1_TX_LIMIT,
635635
};
636636

637637
if (!request.gas && !gasConfig.ignoreBlockGasLimit) {
638-
// LARGE_GAS_LIMIT is set as call.gas, increase block gasLimit
639-
blockOverrides.gasLimit = LARGE_GAS_LIMIT * 2n;
638+
// MAX_L1_TX_LIMIT is set as call.gas, ensure block gasLimit is sufficient
639+
blockOverrides.gasLimit = MAX_L1_TX_LIMIT;
640640
}
641641

642642
return this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);

0 commit comments

Comments
 (0)