Skip to content

Commit ba28788

Browse files
spalladinoludamad
andauthored
fix: Try fix e2e epochs in CI (#10804)
Attempts two fixes at e2e epochs test. First, it increases the L1 block time, to account for general CI slowness. Second, it adds more retries to the L1 gas utils getTx, since the e2e epochs test works using the tx delayer, which artificially introduces a delay between a tx being sent and it being available in anvil, so it triggered a timeout in the utils. **Update**: Increasing the retries caused the error to change, we were getting a timeout in teardown. This was caused because the sequencer got stuck in waiting for the tx to be mined for way too long (more than 5 minutes, the afterAll hook timeout), and the `node.stop()` waits for the current loops to end before returning. But what's interesting is _why_ the sequencer got stuck in waiting for its tx to be mined. The tx was being delayed by the tx-delayer, which intercepts txs, manually computes their tx hash to return it to the caller immediately, and holds on the tx to submit it to anvil at a later point in time. What came up is that the tx hash we were manually computing over txs with blobs did not match the tx hash returned by anvil. This has been logged as #10824. However, we can sidestep this issue by just choosing a reasonable value for max attempts so teardown doesn't timeout. --------- Co-authored-by: ludamad <adam.domurad@gmail.com>
1 parent b8bdb52 commit ba28788

File tree

4 files changed

+52
-20
lines changed

4 files changed

+52
-20
lines changed

yarn-project/end-to-end/src/e2e_epochs.test.ts

+20-14
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ describe('e2e_epochs', () => {
2424
let l1BlockNumber: number;
2525
let handle: NodeJS.Timeout;
2626

27-
const EPOCH_DURATION = 4;
28-
const L1_BLOCK_TIME = 5;
29-
const L2_SLOT_DURATION_IN_L1_BLOCKS = 2;
27+
const EPOCH_DURATION_IN_L2_SLOTS = 4;
28+
const L2_SLOT_DURATION_IN_L1_SLOTS = 2;
29+
const L1_BLOCK_TIME_IN_S = 8;
3030

3131
beforeAll(async () => {
3232
// Set up system without any account nor protocol contracts
@@ -35,13 +35,16 @@ describe('e2e_epochs', () => {
3535
assumeProvenThrough: undefined,
3636
skipProtocolContracts: true,
3737
salt: 1,
38-
aztecEpochDuration: EPOCH_DURATION,
39-
aztecSlotDuration: L1_BLOCK_TIME * L2_SLOT_DURATION_IN_L1_BLOCKS,
40-
ethereumSlotDuration: L1_BLOCK_TIME,
41-
aztecEpochProofClaimWindowInL2Slots: EPOCH_DURATION / 2,
38+
aztecEpochDuration: EPOCH_DURATION_IN_L2_SLOTS,
39+
aztecSlotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
40+
ethereumSlotDuration: L1_BLOCK_TIME_IN_S,
41+
aztecEpochProofClaimWindowInL2Slots: EPOCH_DURATION_IN_L2_SLOTS / 2,
4242
minTxsPerBlock: 0,
4343
realProofs: false,
4444
startProverNode: true,
45+
// This must be enough so that the tx from the prover is delayed properly,
46+
// but not so much to hang the sequencer and timeout the teardown
47+
txPropagationMaxQueryAttempts: 12,
4548
});
4649

4750
logger = context.logger;
@@ -87,8 +90,8 @@ describe('e2e_epochs', () => {
8790

8891
// Constants used for time calculation
8992
constants = {
90-
epochDuration: EPOCH_DURATION,
91-
slotDuration: L1_BLOCK_TIME * L2_SLOT_DURATION_IN_L1_BLOCKS,
93+
epochDuration: EPOCH_DURATION_IN_L2_SLOTS,
94+
slotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
9295
l1GenesisBlock: await rollup.getL1StartBlock(),
9396
l1GenesisTime: await rollup.getL1GenesisTime(),
9497
};
@@ -105,7 +108,7 @@ describe('e2e_epochs', () => {
105108
const waitUntilEpochStarts = async (epoch: number) => {
106109
const [start] = getTimestampRangeForEpoch(BigInt(epoch), constants);
107110
logger.info(`Waiting until L1 timestamp ${start} is reached as the start of epoch ${epoch}`);
108-
await waitUntilL1Timestamp(l1Client, start - BigInt(L1_BLOCK_TIME));
111+
await waitUntilL1Timestamp(l1Client, start - BigInt(L1_BLOCK_TIME_IN_S));
109112
return start;
110113
};
111114

@@ -124,12 +127,14 @@ describe('e2e_epochs', () => {
124127
proverDelayer.pauseNextTxUntilTimestamp(epoch2Start);
125128
logger.info(`Delayed prover tx until epoch 2 starts at ${epoch2Start}`);
126129

127-
// Wait until the last block of epoch 1 is published and then hold off the sequencer
128-
await waitUntilL2BlockNumber(blockNumberAtEndOfEpoch0 + EPOCH_DURATION);
129-
sequencerDelayer.pauseNextTxUntilTimestamp(epoch2Start + BigInt(L1_BLOCK_TIME));
130+
// Wait until the last block of epoch 1 is published and then hold off the sequencer.
131+
// Note that the tx below will block the sequencer until it times out
132+
// the txPropagationMaxQueryAttempts until #10824 is fixed.
133+
await waitUntilL2BlockNumber(blockNumberAtEndOfEpoch0 + EPOCH_DURATION_IN_L2_SLOTS);
134+
sequencerDelayer.pauseNextTxUntilTimestamp(epoch2Start + BigInt(L1_BLOCK_TIME_IN_S));
130135

131136
// Next sequencer to publish a block should trigger a rollback to block 1
132-
await waitUntilL1Timestamp(l1Client, epoch2Start + BigInt(L1_BLOCK_TIME));
137+
await waitUntilL1Timestamp(l1Client, epoch2Start + BigInt(L1_BLOCK_TIME_IN_S));
133138
expect(await rollup.getBlockNumber()).toEqual(1n);
134139
expect(await rollup.getSlotNumber()).toEqual(8n);
135140

@@ -142,5 +147,6 @@ describe('e2e_epochs', () => {
142147
const lastL2BlockTxReceipt = await l1Client.getTransactionReceipt({ hash: lastL2BlockTxHash! });
143148
expect(lastL2BlockTxReceipt.status).toEqual('success');
144149
expect(lastL2BlockTxReceipt.blockNumber).toBeGreaterThan(lastProverTxReceipt!.blockNumber);
150+
logger.info(`Test succeeded`);
145151
});
146152
});

yarn-project/ethereum/src/l1_tx_utils.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { times } from '@aztec/foundation/collection';
12
import {
23
type ConfigMappingsType,
34
bigintConfigHelper,
@@ -71,6 +72,11 @@ export interface L1TxUtilsConfig {
7172
* How long to wait for a tx to be mined before giving up
7273
*/
7374
txTimeoutMs?: number;
75+
/**
76+
* How many attempts will be done to get a tx after it was sent?
77+
* First attempt is done at 1s, second at 2s, third at 3s, etc.
78+
*/
79+
txPropagationMaxQueryAttempts?: number;
7480
}
7581

7682
export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
@@ -119,6 +125,11 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
119125
env: 'L1_TX_MONITOR_TX_TIMEOUT_MS',
120126
...numberConfigHelper(300_000), // 5 mins
121127
},
128+
txPropagationMaxQueryAttempts: {
129+
description: 'How many attempts will be done to get a tx after it was sent',
130+
env: 'L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS',
131+
...numberConfigHelper(3),
132+
},
122133
};
123134

124135
export const defaultL1TxUtilsConfig = getDefaultConfig<L1TxUtilsConfig>(l1TxUtilsConfigMappings);
@@ -213,12 +224,14 @@ export class L1TxUtils {
213224
const gasConfig = { ...this.config, ..._gasConfig };
214225
const account = this.walletClient.account;
215226
const blobInputs = _blobInputs || {};
227+
const makeGetTransactionBackoff = () =>
228+
makeBackoff(times(gasConfig.txPropagationMaxQueryAttempts ?? 3, i => i + 1));
216229

217230
// Retry a few times, in case the tx is not yet propagated.
218231
const tx = await retry<GetTransactionReturnType>(
219232
() => this.publicClient.getTransaction({ hash: initialTxHash }),
220233
`Getting L1 transaction ${initialTxHash}`,
221-
makeBackoff([1, 2, 3]),
234+
makeGetTransactionBackoff(),
222235
this.logger,
223236
true,
224237
);
@@ -261,7 +274,7 @@ export class L1TxUtils {
261274
const tx = await retry<GetTransactionReturnType>(
262275
() => this.publicClient.getTransaction({ hash: currentTxHash }),
263276
`Getting L1 transaction ${currentTxHash}`,
264-
makeBackoff([1, 2, 3]),
277+
makeGetTransactionBackoff(),
265278
this.logger,
266279
true,
267280
);

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

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { omit } from '@aztec/foundation/collection';
12
import { type Logger, createLogger } from '@aztec/foundation/log';
23
import { retryUntil } from '@aztec/foundation/retry';
34

@@ -8,6 +9,7 @@ import {
89
type PublicClient,
910
type WalletClient,
1011
keccak256,
12+
parseTransaction,
1113
publicActions,
1214
walletActions,
1315
} from 'viem';
@@ -89,6 +91,7 @@ class DelayerImpl implements Delayer {
8991
/**
9092
* Returns a new client (without modifying the one passed in) with an injected tx delayer.
9193
* The delayer can be used to hold off the next tx to be sent until a given block number.
94+
* TODO(#10824): This doesn't play along well with blob txs for some reason.
9295
*/
9396
export function withDelayer<T extends WalletClient>(
9497
client: T,
@@ -116,16 +119,25 @@ export function withDelayer<T extends WalletClient>(
116119
// Compute the tx hash manually so we emulate sendRawTransaction response
117120
const { serializedTransaction } = args[0];
118121
const txHash = keccak256(serializedTransaction);
119-
logger.info(`Delaying tx ${txHash} until ${inspect(waitUntil)}`);
122+
logger.info(`Delaying tx ${txHash} until ${inspect(waitUntil)}`, {
123+
argsLen: args.length,
124+
...omit(parseTransaction(serializedTransaction), 'data', 'sidecars'),
125+
});
120126

121127
// Do not await here so we can return the tx hash immediately as if it had been sent on the spot.
122128
// Instead, delay it so it lands on the desired block number or timestamp, assuming anvil will
123129
// mine it immediately.
124130
void wait
125131
.then(async () => {
126-
const txHash = await client.sendRawTransaction(...args);
127-
logger.info(`Sent previously delayed tx ${txHash} to land on ${inspect(waitUntil)}`);
128-
delayer.txs.push(txHash);
132+
const clientTxHash = await client.sendRawTransaction(...args);
133+
if (clientTxHash !== txHash) {
134+
logger.error(`Tx hash returned by the client does not match computed one`, {
135+
clientTxHash,
136+
computedTxHash: txHash,
137+
});
138+
}
139+
logger.info(`Sent previously delayed tx ${clientTxHash} to land on ${inspect(waitUntil)}`);
140+
delayer.txs.push(clientTxHash);
129141
})
130142
.catch(err => logger.error(`Error sending tx after delay`, err));
131143

yarn-project/foundation/src/config/env_var.ts

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export type EnvVar =
183183
| 'L1_TX_MONITOR_CHECK_INTERVAL_MS'
184184
| 'L1_TX_MONITOR_STALL_TIME_MS'
185185
| 'L1_TX_MONITOR_TX_TIMEOUT_MS'
186+
| 'L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS'
186187
| 'FAUCET_MNEMONIC_ACCOUNT_INDEX'
187188
| 'FAUCET_ETH_AMOUNT'
188189
| 'FAUCET_INTERVAL_MS'

0 commit comments

Comments
 (0)