Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Sequencer times out L1 tx at end of L2 slot #11112

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions yarn-project/ethereum/src/l1_tx_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,22 @@ describe('GasUtils', () => {
const expectedEstimate = baseEstimate + (baseEstimate * 20n) / 100n;
expect(bufferedEstimate).toBe(expectedEstimate);
});

it('stops trying after timeout', async () => {
await cheatCodes.setAutomine(false);
await cheatCodes.setIntervalMining(0);

const now = Date.now();
await expect(
gasUtils.sendAndMonitorTransaction(
{
to: '0x1234567890123456789012345678901234567890',
data: '0x',
value: 0n,
},
{ txTimeoutAt: new Date(now + 1000) },
),
).rejects.toThrow(/timed out/);
expect(Date.now() - now).toBeGreaterThanOrEqual(990);
}, 60_000);
});
27 changes: 16 additions & 11 deletions yarn-project/ethereum/src/l1_tx_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export class L1TxUtils {
*/
public async sendTransaction(
request: L1TxRequest,
_gasConfig?: Partial<L1TxUtilsConfig> & { fixedGas?: bigint },
_gasConfig?: Partial<L1TxUtilsConfig> & { fixedGas?: bigint; txTimeoutAt?: Date },
_blobInputs?: L1BlobInputs,
): Promise<{ txHash: Hex; gasLimit: bigint; gasPrice: GasPrice }> {
const gasConfig = { ...this.config, ..._gasConfig };
Expand All @@ -189,6 +189,10 @@ export class L1TxUtils {

const gasPrice = await this.getGasPrice(gasConfig);

if (gasConfig.txTimeoutAt && Date.now() > gasConfig.txTimeoutAt.getTime()) {
throw new Error('Transaction timed out before sending');
}

const blobInputs = _blobInputs || {};
const txHash = await this.walletClient.sendTransaction({
...request,
Expand Down Expand Up @@ -218,7 +222,7 @@ export class L1TxUtils {
request: L1TxRequest,
initialTxHash: Hex,
params: { gasLimit: bigint },
_gasConfig?: Partial<L1TxUtilsConfig>,
_gasConfig?: Partial<L1TxUtilsConfig> & { txTimeoutAt?: Date },
_blobInputs?: L1BlobInputs,
): Promise<TransactionReceipt> {
const gasConfig = { ...this.config, ..._gasConfig };
Expand Down Expand Up @@ -246,7 +250,12 @@ export class L1TxUtils {
let attempts = 0;
let lastAttemptSent = Date.now();
const initialTxTime = lastAttemptSent;

let txTimedOut = false;
const isTimedOut = () =>
(gasConfig.txTimeoutAt && Date.now() > gasConfig.txTimeoutAt.getTime()) ||
(gasConfig.txTimeoutMs !== undefined && Date.now() - initialTxTime > gasConfig.txTimeoutMs) ||
false;

while (!txTimedOut) {
try {
Expand Down Expand Up @@ -284,11 +293,9 @@ export class L1TxUtils {
this.logger?.debug(`L1 transaction ${currentTxHash} pending. Time passed: ${timePassed}ms.`);

// Check timeout before continuing
if (gasConfig.txTimeoutMs) {
txTimedOut = Date.now() - initialTxTime > gasConfig.txTimeoutMs;
if (txTimedOut) {
break;
}
txTimedOut = isTimedOut();
if (txTimedOut) {
break;
}

await sleep(gasConfig.checkIntervalMs!);
Expand Down Expand Up @@ -331,9 +338,7 @@ export class L1TxUtils {
await sleep(gasConfig.checkIntervalMs!);
}
// Check if tx has timed out.
if (gasConfig.txTimeoutMs) {
txTimedOut = Date.now() - initialTxTime > gasConfig.txTimeoutMs!;
}
txTimedOut = isTimedOut();
}
throw new Error(`L1 transaction ${currentTxHash} timed out`);
}
Expand All @@ -346,7 +351,7 @@ export class L1TxUtils {
*/
public async sendAndMonitorTransaction(
request: L1TxRequest,
gasConfig?: Partial<L1TxUtilsConfig> & { fixedGas?: bigint },
gasConfig?: Partial<L1TxUtilsConfig> & { fixedGas?: bigint; txTimeoutAt?: Date },
blobInputs?: L1BlobInputs,
): Promise<TransactionReceipt> {
const { txHash, gasLimit } = await this.sendTransaction(request, gasConfig, blobInputs);
Expand Down
13 changes: 10 additions & 3 deletions yarn-project/sequencer-client/src/publisher/l1-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ export class L1Publisher {
attestations?: Signature[],
txHashes?: TxHash[],
proofQuote?: EpochProofQuote,
opts: { txTimeoutAt?: Date } = {},
): Promise<boolean> {
const ctx = {
blockNumber: block.number,
Expand Down Expand Up @@ -598,8 +599,8 @@ export class L1Publisher {

this.log.debug(`Submitting propose transaction`);
const result = proofQuote
? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote)
: await this.sendProposeTx(proposeTxArgs);
? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote, opts)
: await this.sendProposeTx(proposeTxArgs, opts);

if (!result?.receipt) {
this.log.info(`Failed to publish block ${block.number} to L1`, ctx);
Expand Down Expand Up @@ -1016,6 +1017,7 @@ export class L1Publisher {

private async sendProposeTx(
encodedData: L1ProcessArgs,
opts: { txTimeoutAt?: Date } = {},
): Promise<{ receipt: TransactionReceipt | undefined; args: any; functionName: string; data: Hex } | undefined> {
if (this.interrupted) {
return undefined;
Expand All @@ -1035,6 +1037,7 @@ export class L1Publisher {
},
{
fixedGas: gas,
...opts,
},
{
blobs: encodedData.blobs.map(b => b.dataWithZeros),
Expand All @@ -1057,6 +1060,7 @@ export class L1Publisher {
private async sendProposeAndClaimTx(
encodedData: L1ProcessArgs,
quote: EpochProofQuote,
opts: { txTimeoutAt?: Date } = {},
): Promise<{ receipt: TransactionReceipt | undefined; args: any; functionName: string; data: Hex } | undefined> {
if (this.interrupted) {
return undefined;
Expand All @@ -1074,7 +1078,10 @@ export class L1Publisher {
to: this.rollupContract.address,
data,
},
{ fixedGas: gas },
{
fixedGas: gas,
...opts,
},
{
blobs: encodedData.blobs.map(b => b.dataWithZeros),
kzg,
Expand Down
8 changes: 7 additions & 1 deletion yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,13 @@ export class Sequencer {
// Publishes new block to the network and awaits the tx to be mined
this.setState(SequencerState.PUBLISHING_BLOCK, block.header.globalVariables.slotNumber.toBigInt());

const publishedL2Block = await this.publisher.proposeL2Block(block, attestations, txHashes, proofQuote);
// Time out tx at the end of the slot
const slot = block.header.globalVariables.slotNumber.toNumber();
const txTimeoutAt = new Date((this.getSlotStartTimestamp(slot) + this.aztecSlotDuration) * 1000);

const publishedL2Block = await this.publisher.proposeL2Block(block, attestations, txHashes, proofQuote, {
txTimeoutAt,
});
if (!publishedL2Block) {
throw new Error(`Failed to publish block ${block.number}`);
}
Expand Down
Loading