Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 27 additions & 0 deletions yarn-project/archiver/src/l1/calldata_retriever.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { GasFees } from '@aztec/stdlib/gas';
import { ConsensusPayload, SignatureDomainSeparator } from '@aztec/stdlib/p2p';
import { CheckpointHeader } from '@aztec/stdlib/rollup';

import { jest } from '@jest/globals';
import { type MockProxy, mock } from 'jest-mock-extended';
import {
type Hex,
Expand Down Expand Up @@ -1017,6 +1018,32 @@ describe('CalldataRetriever', () => {
expect(debugClient.request).toHaveBeenCalledTimes(2);
});

it('should log trace+debug failure warn only once per tx hash', async () => {
CalldataRetriever.resetTraceFailureWarnedForTesting();
const warnSpy = jest.spyOn(logger, 'warn');

// First attempt: both trace and debug fail
debugClient.request.mockRejectedValueOnce(new Error('trace_transaction not supported'));
debugClient.request.mockRejectedValueOnce(new Error('debug_traceTransaction not supported'));

await expect(retriever.extractCalldataViaTrace(txHash)).rejects.toThrow(
'Failed to trace transaction ' + txHash + ' to extract propose calldata',
);
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot decode L1 tx'));

// Second attempt: same tx, both fail again - should not log warn again
debugClient.request.mockRejectedValueOnce(new Error('trace_transaction not supported'));
debugClient.request.mockRejectedValueOnce(new Error('debug_traceTransaction not supported'));

await expect(retriever.extractCalldataViaTrace(txHash)).rejects.toThrow(
'Failed to trace transaction ' + txHash + ' to extract propose calldata',
);
expect(warnSpy).toHaveBeenCalledTimes(1);

warnSpy.mockRestore();
});

it('should throw when no propose calls found', async () => {
// Mock debug client to return empty trace
debugClient.request.mockResolvedValueOnce([]);
Expand Down
22 changes: 20 additions & 2 deletions yarn-project/archiver/src/l1/calldata_retriever.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ import type { CallInfo } from './types.js';
* in order to reconstruct an L2 block header.
*/
export class CalldataRetriever {
/** Tx hashes we've already logged for trace+debug failure (log once per tx per process). */
private static readonly traceFailureWarnedTxHashes = new Set<string>();

/** Clears the trace-failure warned set. For testing only. */
static resetTraceFailureWarnedForTesting(): void {
CalldataRetriever.traceFailureWarnedTxHashes.clear();
}

/** Pre-computed valid contract calls for validation */
private readonly validContractCalls: ValidContractCall[];

Expand Down Expand Up @@ -313,7 +321,8 @@ export class CalldataRetriever {
this.logger.debug(`Successfully traced using trace_transaction, found ${calls.length} calls`);
} catch (err) {
const traceError = err instanceof Error ? err : new Error(String(err));
this.logger.verbose(`Failed trace_transaction for ${txHash}`, { traceError });
this.logger.verbose(`Failed trace_transaction for ${txHash}: ${traceError.message}`);
this.logger.debug(`Trace failure details for ${txHash}`, { traceError });

try {
// Fall back to debug_traceTransaction (Geth RPC)
Expand All @@ -322,7 +331,16 @@ export class CalldataRetriever {
this.logger.debug(`Successfully traced using debug_traceTransaction, found ${calls.length} calls`);
} catch (debugErr) {
const debugError = debugErr instanceof Error ? debugErr : new Error(String(debugErr));
this.logger.warn(`All tracing methods failed for tx ${txHash}`, {
// Log once per tx so we don't spam on every sync cycle when sync point doesn't advance
if (!CalldataRetriever.traceFailureWarnedTxHashes.has(txHash)) {
CalldataRetriever.traceFailureWarnedTxHashes.add(txHash);
this.logger.warn(
`Cannot decode L1 tx ${txHash}: trace and debug RPC failed or unavailable. ` +
`trace_transaction: ${traceError.message}; debug_traceTransaction: ${debugError.message}`,
);
}
// Full error objects can be very long; keep at debug only
this.logger.debug(`Trace/debug failure details for tx ${txHash}`, {
traceError,
debugError,
txHash,
Expand Down
Loading