@aztec/sequencer-client 0.0.1-commit.9ef841308 → 0.0.1-commit.a89ec08
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/client/sequencer-client.d.ts +3 -2
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +7 -8
- package/dest/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +1 -2
- package/dest/publisher/config.d.ts +1 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +3 -23
- package/dest/publisher/index.d.ts +1 -2
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +2 -16
- package/dest/publisher/sequencer-publisher.d.ts +2 -12
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +11 -260
- package/dest/sequencer/checkpoint_proposal_job.d.ts +4 -10
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +75 -117
- package/dest/sequencer/events.d.ts +1 -2
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +1 -5
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +0 -11
- package/dest/sequencer/sequencer.d.ts +5 -4
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +49 -58
- package/dest/test/mock_checkpoint_builder.d.ts +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +2 -0
- package/package.json +28 -27
- package/src/client/sequencer-client.ts +12 -8
- package/src/config.ts +0 -4
- package/src/publisher/config.ts +0 -41
- package/src/publisher/index.ts +0 -3
- package/src/publisher/sequencer-publisher-factory.ts +3 -18
- package/src/publisher/sequencer-publisher.ts +16 -237
- package/src/sequencer/checkpoint_proposal_job.ts +66 -139
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/metrics.ts +0 -14
- package/src/sequencer/sequencer.ts +57 -83
- package/src/test/mock_checkpoint_builder.ts +2 -0
- package/dest/publisher/l1_tx_failed_store/factory.d.ts +0 -11
- package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +0 -1
- package/dest/publisher/l1_tx_failed_store/factory.js +0 -22
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +0 -59
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +0 -1
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +0 -1
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +0 -15
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +0 -1
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +0 -34
- package/dest/publisher/l1_tx_failed_store/index.d.ts +0 -4
- package/dest/publisher/l1_tx_failed_store/index.d.ts.map +0 -1
- package/dest/publisher/l1_tx_failed_store/index.js +0 -2
- package/src/publisher/l1_tx_failed_store/factory.ts +0 -32
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +0 -55
- package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +0 -46
- package/src/publisher/l1_tx_failed_store/index.ts +0 -3
package/src/publisher/config.ts
CHANGED
|
@@ -4,8 +4,6 @@ import { type L1TxUtilsConfig, l1TxUtilsConfigMappings } from '@aztec/ethereum/l
|
|
|
4
4
|
import { type ConfigMappingsType, SecretValue, booleanConfigHelper } from '@aztec/foundation/config';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
|
|
7
|
-
import { parseEther } from 'viem';
|
|
8
|
-
|
|
9
7
|
/** Configuration of the transaction publisher. */
|
|
10
8
|
export type TxSenderConfig = L1ReaderConfig & {
|
|
11
9
|
/** The private key to be used by the publisher. */
|
|
@@ -50,39 +48,13 @@ export type PublisherConfig = L1TxUtilsConfig &
|
|
|
50
48
|
fishermanMode?: boolean;
|
|
51
49
|
/** Address of the forwarder contract to wrap all L1 transactions through (for testing purposes only) */
|
|
52
50
|
publisherForwarderAddress?: EthAddress;
|
|
53
|
-
/** Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path */
|
|
54
|
-
l1TxFailedStore?: string;
|
|
55
|
-
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
56
|
-
publisherFundingThreshold?: bigint;
|
|
57
|
-
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
58
|
-
publisherFundingAmount?: bigint;
|
|
59
51
|
};
|
|
60
52
|
|
|
61
|
-
/** Shared config mappings for publisher funding, used by both sequencer and prover publisher configs. */
|
|
62
|
-
const publisherFundingConfigMappings = {
|
|
63
|
-
publisherFundingThreshold: {
|
|
64
|
-
env: 'PUBLISHER_FUNDING_THRESHOLD' as const,
|
|
65
|
-
description:
|
|
66
|
-
'Min ETH balance below which a publisher gets funded. Specified in ether (e.g. 0.1). Unset = funding disabled.',
|
|
67
|
-
parseEnv: (val: string) => parseEther(val),
|
|
68
|
-
},
|
|
69
|
-
publisherFundingAmount: {
|
|
70
|
-
env: 'PUBLISHER_FUNDING_AMOUNT' as const,
|
|
71
|
-
description:
|
|
72
|
-
'Amount of ETH to send when funding a publisher. Specified in ether (e.g. 0.5). Unset = funding disabled.',
|
|
73
|
-
parseEnv: (val: string) => parseEther(val),
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
|
|
77
53
|
export type ProverPublisherConfig = L1TxUtilsConfig &
|
|
78
54
|
BlobClientConfig & {
|
|
79
55
|
fishermanMode?: boolean;
|
|
80
56
|
proverPublisherAllowInvalidStates?: boolean;
|
|
81
57
|
proverPublisherForwarderAddress?: EthAddress;
|
|
82
|
-
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
83
|
-
publisherFundingThreshold?: bigint;
|
|
84
|
-
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
85
|
-
publisherFundingAmount?: bigint;
|
|
86
58
|
};
|
|
87
59
|
|
|
88
60
|
export type SequencerPublisherConfig = L1TxUtilsConfig &
|
|
@@ -90,12 +62,6 @@ export type SequencerPublisherConfig = L1TxUtilsConfig &
|
|
|
90
62
|
fishermanMode?: boolean;
|
|
91
63
|
sequencerPublisherAllowInvalidStates?: boolean;
|
|
92
64
|
sequencerPublisherForwarderAddress?: EthAddress;
|
|
93
|
-
/** Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path */
|
|
94
|
-
l1TxFailedStore?: string;
|
|
95
|
-
/** Min ETH balance below which a publisher gets funded. Undefined = funding disabled. */
|
|
96
|
-
publisherFundingThreshold?: bigint;
|
|
97
|
-
/** Amount of ETH to send when funding a publisher. Undefined = funding disabled. */
|
|
98
|
-
publisherFundingAmount?: bigint;
|
|
99
65
|
};
|
|
100
66
|
|
|
101
67
|
export function getPublisherConfigFromProverConfig(config: ProverPublisherConfig): PublisherConfig {
|
|
@@ -111,7 +77,6 @@ export function getPublisherConfigFromSequencerConfig(config: SequencerPublisher
|
|
|
111
77
|
...config,
|
|
112
78
|
publisherAllowInvalidStates: config.sequencerPublisherAllowInvalidStates,
|
|
113
79
|
publisherForwarderAddress: config.sequencerPublisherForwarderAddress,
|
|
114
|
-
l1TxFailedStore: config.l1TxFailedStore,
|
|
115
80
|
};
|
|
116
81
|
}
|
|
117
82
|
|
|
@@ -168,11 +133,6 @@ export const sequencerPublisherConfigMappings: ConfigMappingsType<SequencerPubli
|
|
|
168
133
|
description: 'Address of the forwarder contract to wrap all L1 transactions through (for testing purposes only)',
|
|
169
134
|
parseEnv: (val: string) => (val ? EthAddress.fromString(val) : undefined),
|
|
170
135
|
},
|
|
171
|
-
l1TxFailedStore: {
|
|
172
|
-
env: 'L1_TX_FAILED_STORE',
|
|
173
|
-
description: 'Store for failed L1 transaction inputs (test networks only). Format: gs://bucket/path',
|
|
174
|
-
},
|
|
175
|
-
...publisherFundingConfigMappings,
|
|
176
136
|
};
|
|
177
137
|
|
|
178
138
|
export const proverPublisherConfigMappings: ConfigMappingsType<ProverPublisherConfig & L1TxUtilsConfig> = {
|
|
@@ -194,5 +154,4 @@ export const proverPublisherConfigMappings: ConfigMappingsType<ProverPublisherCo
|
|
|
194
154
|
description: 'Address of the forwarder contract to wrap all L1 transactions through (for testing purposes only)',
|
|
195
155
|
parseEnv: (val: string) => (val ? EthAddress.fromString(val) : undefined),
|
|
196
156
|
},
|
|
197
|
-
...publisherFundingConfigMappings,
|
|
198
157
|
};
|
package/src/publisher/index.ts
CHANGED
|
@@ -3,6 +3,3 @@ export { SequencerPublisherFactory } from './sequencer-publisher-factory.js';
|
|
|
3
3
|
|
|
4
4
|
// Used for tests
|
|
5
5
|
export { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
6
|
-
|
|
7
|
-
// Failed L1 tx store (optional, for test networks)
|
|
8
|
-
export { type FailedL1Tx, type FailedL1TxUri, type L1TxFailedStore } from './l1_tx_failed_store/index.js';
|
|
@@ -81,23 +81,8 @@ export class SequencerPublisherFactory {
|
|
|
81
81
|
const rollup = this.deps.rollupContract;
|
|
82
82
|
const slashingProposerContract = await rollup.getSlashingProposer();
|
|
83
83
|
|
|
84
|
-
const getNextPublisher = async (excludeAddresses: EthAddress[]): Promise<L1TxUtils | undefined> => {
|
|
85
|
-
const exclusionFilter: PublisherFilter<L1TxUtils> = (utils: L1TxUtils) => {
|
|
86
|
-
if (excludeAddresses.some(addr => addr.equals(utils.getSenderAddress()))) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
return filter(utils);
|
|
90
|
-
};
|
|
91
|
-
try {
|
|
92
|
-
return await this.deps.publisherManager.getAvailablePublisher(exclusionFilter);
|
|
93
|
-
} catch {
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
84
|
const publisher = new SequencerPublisher(this.sequencerConfig, {
|
|
99
85
|
l1TxUtils: l1Publisher,
|
|
100
|
-
getNextPublisher,
|
|
101
86
|
telemetry: this.deps.telemetry,
|
|
102
87
|
blobClient: this.deps.blobClient,
|
|
103
88
|
rollupContract: this.deps.rollupContract,
|
|
@@ -117,8 +102,8 @@ export class SequencerPublisherFactory {
|
|
|
117
102
|
};
|
|
118
103
|
}
|
|
119
104
|
|
|
120
|
-
/**
|
|
121
|
-
public
|
|
122
|
-
|
|
105
|
+
/** Interrupts all publishers managed by this factory. Used during sequencer shutdown. */
|
|
106
|
+
public interruptAll(): void {
|
|
107
|
+
this.deps.publisherManager.interrupt();
|
|
123
108
|
}
|
|
124
109
|
}
|
|
@@ -31,7 +31,6 @@ import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
|
31
31
|
import { trimmedBytesLength } from '@aztec/foundation/buffer';
|
|
32
32
|
import { pick } from '@aztec/foundation/collection';
|
|
33
33
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
34
|
-
import { TimeoutError } from '@aztec/foundation/error';
|
|
35
34
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
36
35
|
import { Signature, type ViemSignature } from '@aztec/foundation/eth-signature';
|
|
37
36
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
@@ -48,19 +47,9 @@ import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
|
48
47
|
import type { L1PublishCheckpointStats } from '@aztec/stdlib/stats';
|
|
49
48
|
import { type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
50
49
|
|
|
51
|
-
import {
|
|
52
|
-
type Hex,
|
|
53
|
-
type StateOverride,
|
|
54
|
-
type TransactionReceipt,
|
|
55
|
-
type TypedDataDefinition,
|
|
56
|
-
encodeFunctionData,
|
|
57
|
-
keccak256,
|
|
58
|
-
multicall3Abi,
|
|
59
|
-
toHex,
|
|
60
|
-
} from 'viem';
|
|
50
|
+
import { type StateOverride, type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
|
|
61
51
|
|
|
62
52
|
import type { SequencerPublisherConfig } from './config.js';
|
|
63
|
-
import { type FailedL1Tx, type L1TxFailedStore, createL1TxFailedStore } from './l1_tx_failed_store/index.js';
|
|
64
53
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
65
54
|
|
|
66
55
|
/** Arguments to the process method of the rollup contract */
|
|
@@ -122,7 +111,6 @@ export class SequencerPublisher {
|
|
|
122
111
|
private interrupted = false;
|
|
123
112
|
private metrics: SequencerPublisherMetrics;
|
|
124
113
|
public epochCache: EpochCache;
|
|
125
|
-
private failedTxStore?: Promise<L1TxFailedStore | undefined>;
|
|
126
114
|
|
|
127
115
|
protected governanceLog = createLogger('sequencer:publisher:governance');
|
|
128
116
|
protected slashingLog = createLogger('sequencer:publisher:slashing');
|
|
@@ -142,9 +130,6 @@ export class SequencerPublisher {
|
|
|
142
130
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */
|
|
143
131
|
private proposerAddressForSimulation?: EthAddress;
|
|
144
132
|
|
|
145
|
-
/** Optional callback to obtain a replacement publisher when the current one fails to send. */
|
|
146
|
-
private getNextPublisher?: (excludeAddresses: EthAddress[]) => Promise<L1TxUtils | undefined>;
|
|
147
|
-
|
|
148
133
|
/** L1 fee analyzer for fisherman mode */
|
|
149
134
|
private l1FeeAnalyzer?: L1FeeAnalyzer;
|
|
150
135
|
|
|
@@ -168,7 +153,7 @@ export class SequencerPublisher {
|
|
|
168
153
|
protected requests: RequestWithExpiry[] = [];
|
|
169
154
|
|
|
170
155
|
constructor(
|
|
171
|
-
private config: Pick<SequencerPublisherConfig, 'fishermanMode'
|
|
156
|
+
private config: Pick<SequencerPublisherConfig, 'fishermanMode'> &
|
|
172
157
|
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'> & { l1ChainId: number },
|
|
173
158
|
deps: {
|
|
174
159
|
telemetry?: TelemetryClient;
|
|
@@ -183,7 +168,6 @@ export class SequencerPublisher {
|
|
|
183
168
|
metrics: SequencerPublisherMetrics;
|
|
184
169
|
lastActions: Partial<Record<Action, SlotNumber>>;
|
|
185
170
|
log?: Logger;
|
|
186
|
-
getNextPublisher?: (excludeAddresses: EthAddress[]) => Promise<L1TxUtils | undefined>;
|
|
187
171
|
},
|
|
188
172
|
) {
|
|
189
173
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
@@ -199,7 +183,6 @@ export class SequencerPublisher {
|
|
|
199
183
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
200
184
|
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
201
185
|
this.l1TxUtils = deps.l1TxUtils;
|
|
202
|
-
this.getNextPublisher = deps.getNextPublisher;
|
|
203
186
|
|
|
204
187
|
this.rollupContract = deps.rollupContract;
|
|
205
188
|
|
|
@@ -228,31 +211,6 @@ export class SequencerPublisher {
|
|
|
228
211
|
this.rollupContract,
|
|
229
212
|
createLogger('sequencer:publisher:price-oracle'),
|
|
230
213
|
);
|
|
231
|
-
|
|
232
|
-
// Initialize failed L1 tx store (optional, for test networks)
|
|
233
|
-
this.failedTxStore = createL1TxFailedStore(config.l1TxFailedStore, this.log);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Backs up a failed L1 transaction to the configured store for debugging.
|
|
238
|
-
* Does nothing if no store is configured.
|
|
239
|
-
*/
|
|
240
|
-
private backupFailedTx(failedTx: Omit<FailedL1Tx, 'timestamp'>): void {
|
|
241
|
-
if (!this.failedTxStore) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const tx: FailedL1Tx = {
|
|
246
|
-
...failedTx,
|
|
247
|
-
timestamp: Date.now(),
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
// Fire and forget - don't block on backup
|
|
251
|
-
void this.failedTxStore
|
|
252
|
-
.then(store => store?.saveFailedTx(tx))
|
|
253
|
-
.catch(err => {
|
|
254
|
-
this.log.warn(`Failed to backup failed L1 tx to store`, err);
|
|
255
|
-
});
|
|
256
214
|
}
|
|
257
215
|
|
|
258
216
|
public getRollupContract(): RollupContract {
|
|
@@ -291,7 +249,7 @@ export class SequencerPublisher {
|
|
|
291
249
|
}
|
|
292
250
|
|
|
293
251
|
public getCurrentL2Slot(): SlotNumber {
|
|
294
|
-
return this.epochCache.
|
|
252
|
+
return this.epochCache.getEpochAndSlotNow().slot;
|
|
295
253
|
}
|
|
296
254
|
|
|
297
255
|
/**
|
|
@@ -434,36 +392,19 @@ export class SequencerPublisher {
|
|
|
434
392
|
validRequests.sort((a, b) => compareActions(a.action, b.action));
|
|
435
393
|
|
|
436
394
|
try {
|
|
437
|
-
// Capture context for failed tx backup before sending
|
|
438
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
439
|
-
const multicallData = encodeFunctionData({
|
|
440
|
-
abi: multicall3Abi,
|
|
441
|
-
functionName: 'aggregate3',
|
|
442
|
-
args: [
|
|
443
|
-
validRequests.map(r => ({
|
|
444
|
-
target: r.request.to!,
|
|
445
|
-
callData: r.request.data!,
|
|
446
|
-
allowFailure: true,
|
|
447
|
-
})),
|
|
448
|
-
],
|
|
449
|
-
});
|
|
450
|
-
const blobDataHex = blobConfig?.blobs?.map(b => toHex(b)) as Hex[] | undefined;
|
|
451
|
-
|
|
452
|
-
const txContext = { multicallData, blobData: blobDataHex, l1BlockNumber };
|
|
453
|
-
|
|
454
395
|
this.log.debug('Forwarding transactions', {
|
|
455
396
|
validRequests: validRequests.map(request => request.action),
|
|
456
397
|
txConfig,
|
|
457
398
|
});
|
|
458
|
-
const result = await
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
txContext,
|
|
399
|
+
const result = await Multicall3.forward(
|
|
400
|
+
validRequests.map(request => request.request),
|
|
401
|
+
this.l1TxUtils,
|
|
402
|
+
txConfig,
|
|
403
|
+
blobConfig,
|
|
404
|
+
this.rollupContract.address,
|
|
405
|
+
this.log,
|
|
466
406
|
);
|
|
407
|
+
const { successfulActions = [], failedActions = [] } = this.callbackBundledTransactions(validRequests, result);
|
|
467
408
|
return { result, expiredActions, sentActions: validActions, successfulActions, failedActions };
|
|
468
409
|
} catch (err) {
|
|
469
410
|
const viemError = formatViemError(err);
|
|
@@ -481,76 +422,13 @@ export class SequencerPublisher {
|
|
|
481
422
|
}
|
|
482
423
|
}
|
|
483
424
|
|
|
484
|
-
/**
|
|
485
|
-
* Forwards transactions via Multicall3, rotating to the next available publisher if a send
|
|
486
|
-
* failure occurs (i.e. the tx never reached the chain).
|
|
487
|
-
* On-chain reverts and simulation errors are returned as-is without rotation.
|
|
488
|
-
*/
|
|
489
|
-
private async forwardWithPublisherRotation(
|
|
490
|
-
validRequests: RequestWithExpiry[],
|
|
491
|
-
txConfig: RequestWithExpiry['gasConfig'],
|
|
492
|
-
blobConfig: L1BlobInputs | undefined,
|
|
493
|
-
) {
|
|
494
|
-
const triedAddresses: EthAddress[] = [];
|
|
495
|
-
let currentPublisher = this.l1TxUtils;
|
|
496
|
-
|
|
497
|
-
while (true) {
|
|
498
|
-
triedAddresses.push(currentPublisher.getSenderAddress());
|
|
499
|
-
try {
|
|
500
|
-
const result = await Multicall3.forward(
|
|
501
|
-
validRequests.map(r => r.request),
|
|
502
|
-
currentPublisher,
|
|
503
|
-
txConfig,
|
|
504
|
-
blobConfig,
|
|
505
|
-
this.rollupContract.address,
|
|
506
|
-
this.log,
|
|
507
|
-
);
|
|
508
|
-
this.l1TxUtils = currentPublisher;
|
|
509
|
-
return result;
|
|
510
|
-
} catch (err) {
|
|
511
|
-
if (err instanceof TimeoutError) {
|
|
512
|
-
throw err;
|
|
513
|
-
}
|
|
514
|
-
const viemError = formatViemError(err);
|
|
515
|
-
if (!this.getNextPublisher) {
|
|
516
|
-
this.log.error('Failed to publish bundled transactions', viemError);
|
|
517
|
-
return undefined;
|
|
518
|
-
}
|
|
519
|
-
this.log.warn(
|
|
520
|
-
`Publisher ${currentPublisher.getSenderAddress()} failed to send, rotating to next publisher`,
|
|
521
|
-
viemError,
|
|
522
|
-
);
|
|
523
|
-
const nextPublisher = await this.getNextPublisher([...triedAddresses]);
|
|
524
|
-
if (!nextPublisher) {
|
|
525
|
-
this.log.error('All available publishers exhausted, failed to publish bundled transactions');
|
|
526
|
-
return undefined;
|
|
527
|
-
}
|
|
528
|
-
currentPublisher = nextPublisher;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
425
|
private callbackBundledTransactions(
|
|
534
426
|
requests: RequestWithExpiry[],
|
|
535
|
-
result
|
|
536
|
-
txContext: { multicallData: Hex; blobData?: Hex[]; l1BlockNumber: bigint },
|
|
427
|
+
result?: { receipt: TransactionReceipt } | FormattedViemError,
|
|
537
428
|
) {
|
|
538
429
|
const actionsListStr = requests.map(r => r.action).join(', ');
|
|
539
430
|
if (result instanceof FormattedViemError) {
|
|
540
431
|
this.log.error(`Failed to publish bundled transactions (${actionsListStr})`, result);
|
|
541
|
-
this.backupFailedTx({
|
|
542
|
-
id: keccak256(txContext.multicallData),
|
|
543
|
-
failureType: 'send-error',
|
|
544
|
-
request: { to: MULTI_CALL_3_ADDRESS, data: txContext.multicallData },
|
|
545
|
-
blobData: txContext.blobData,
|
|
546
|
-
l1BlockNumber: txContext.l1BlockNumber.toString(),
|
|
547
|
-
error: { message: result.message, name: result.name },
|
|
548
|
-
context: {
|
|
549
|
-
actions: requests.map(r => r.action),
|
|
550
|
-
requests: requests.map(r => ({ action: r.action, to: r.request.to! as Hex, data: r.request.data! })),
|
|
551
|
-
sender: this.getSenderAddress().toString(),
|
|
552
|
-
},
|
|
553
|
-
});
|
|
554
432
|
return { failedActions: requests.map(r => r.action) };
|
|
555
433
|
} else {
|
|
556
434
|
this.log.verbose(`Published bundled transactions (${actionsListStr})`, {
|
|
@@ -572,30 +450,6 @@ export class SequencerPublisher {
|
|
|
572
450
|
failedActions.push(request.action);
|
|
573
451
|
}
|
|
574
452
|
}
|
|
575
|
-
// Single backup for the whole reverted tx
|
|
576
|
-
if (failedActions.length > 0 && result?.receipt?.status === 'reverted') {
|
|
577
|
-
this.backupFailedTx({
|
|
578
|
-
id: result.receipt.transactionHash,
|
|
579
|
-
failureType: 'revert',
|
|
580
|
-
request: { to: MULTI_CALL_3_ADDRESS, data: txContext.multicallData },
|
|
581
|
-
blobData: txContext.blobData,
|
|
582
|
-
l1BlockNumber: result.receipt.blockNumber.toString(),
|
|
583
|
-
receipt: {
|
|
584
|
-
transactionHash: result.receipt.transactionHash,
|
|
585
|
-
blockNumber: result.receipt.blockNumber.toString(),
|
|
586
|
-
gasUsed: (result.receipt.gasUsed ?? 0n).toString(),
|
|
587
|
-
status: 'reverted',
|
|
588
|
-
},
|
|
589
|
-
error: { message: result.errorMsg ?? 'Transaction reverted' },
|
|
590
|
-
context: {
|
|
591
|
-
actions: failedActions,
|
|
592
|
-
requests: requests
|
|
593
|
-
.filter(r => failedActions.includes(r.action))
|
|
594
|
-
.map(r => ({ action: r.action, to: r.request.to! as Hex, data: r.request.data! })),
|
|
595
|
-
sender: this.getSenderAddress().toString(),
|
|
596
|
-
},
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
453
|
return { successfulActions, failedActions };
|
|
600
454
|
}
|
|
601
455
|
}
|
|
@@ -613,7 +467,7 @@ export class SequencerPublisher {
|
|
|
613
467
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
614
468
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
615
469
|
|
|
616
|
-
const pipelined = opts.pipelined ??
|
|
470
|
+
const pipelined = opts.pipelined ?? false;
|
|
617
471
|
const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
|
|
618
472
|
const nextL1SlotTs = this.getNextL1SlotTimestamp() + slotOffset;
|
|
619
473
|
|
|
@@ -632,7 +486,6 @@ export class SequencerPublisher {
|
|
|
632
486
|
return undefined;
|
|
633
487
|
});
|
|
634
488
|
}
|
|
635
|
-
|
|
636
489
|
/**
|
|
637
490
|
* @notice Will simulate `validateHeader` to make sure that the block header is valid
|
|
638
491
|
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header.
|
|
@@ -712,8 +565,6 @@ export class SequencerPublisher {
|
|
|
712
565
|
const request = this.buildInvalidateCheckpointRequest(validationResult);
|
|
713
566
|
this.log.debug(`Simulating invalidate checkpoint ${checkpointNumber}`, { ...logData, request });
|
|
714
567
|
|
|
715
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
716
|
-
|
|
717
568
|
try {
|
|
718
569
|
const { gasUsed } = await this.l1TxUtils.simulate(
|
|
719
570
|
request,
|
|
@@ -765,18 +616,6 @@ export class SequencerPublisher {
|
|
|
765
616
|
|
|
766
617
|
// Otherwise, throw. We cannot build the next checkpoint if we cannot invalidate the previous one.
|
|
767
618
|
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed`, viemError, logData);
|
|
768
|
-
this.backupFailedTx({
|
|
769
|
-
id: keccak256(request.data!),
|
|
770
|
-
failureType: 'simulation',
|
|
771
|
-
request: { to: request.to!, data: request.data!, value: request.value?.toString() },
|
|
772
|
-
l1BlockNumber: l1BlockNumber.toString(),
|
|
773
|
-
error: { message: viemError.message, name: viemError.name },
|
|
774
|
-
context: {
|
|
775
|
-
actions: [`invalidate-${reason}`],
|
|
776
|
-
checkpointNumber,
|
|
777
|
-
sender: this.getSenderAddress().toString(),
|
|
778
|
-
},
|
|
779
|
-
});
|
|
780
619
|
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber}`, { cause: viemError });
|
|
781
620
|
}
|
|
782
621
|
}
|
|
@@ -921,7 +760,6 @@ export class SequencerPublisher {
|
|
|
921
760
|
lastValidL2Slot: slotNumber,
|
|
922
761
|
});
|
|
923
762
|
|
|
924
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
925
763
|
const timestamp = this.getSimulationTimestamp(slotNumber);
|
|
926
764
|
|
|
927
765
|
try {
|
|
@@ -931,19 +769,6 @@ export class SequencerPublisher {
|
|
|
931
769
|
const viemError = formatViemError(err);
|
|
932
770
|
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError, {
|
|
933
771
|
simulationTimestamp: timestamp,
|
|
934
|
-
l1BlockNumber,
|
|
935
|
-
});
|
|
936
|
-
this.backupFailedTx({
|
|
937
|
-
id: keccak256(request.data!),
|
|
938
|
-
failureType: 'simulation',
|
|
939
|
-
request: { to: request.to!, data: request.data!, value: request.value?.toString() },
|
|
940
|
-
l1BlockNumber: l1BlockNumber.toString(),
|
|
941
|
-
error: { message: viemError.message, name: viemError.name },
|
|
942
|
-
context: {
|
|
943
|
-
actions: [action],
|
|
944
|
-
slot: slotNumber,
|
|
945
|
-
sender: this.getSenderAddress().toString(),
|
|
946
|
-
},
|
|
947
772
|
});
|
|
948
773
|
// Yes, we enqueue the request anyway, in case there was a bug with the simulation itself
|
|
949
774
|
}
|
|
@@ -1229,8 +1054,6 @@ export class SequencerPublisher {
|
|
|
1229
1054
|
|
|
1230
1055
|
this.log.debug(`Simulating ${action} for slot ${slotNumber}`, logData);
|
|
1231
1056
|
|
|
1232
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1233
|
-
|
|
1234
1057
|
let gasUsed: bigint;
|
|
1235
1058
|
const simulateAbi = mergeAbis([request.abi ?? [], ErrorsAbi]);
|
|
1236
1059
|
|
|
@@ -1241,19 +1064,6 @@ export class SequencerPublisher {
|
|
|
1241
1064
|
const viemError = formatViemError(err, simulateAbi);
|
|
1242
1065
|
this.log.error(`Simulation for ${action} at ${slotNumber} failed`, viemError, logData);
|
|
1243
1066
|
|
|
1244
|
-
this.backupFailedTx({
|
|
1245
|
-
id: keccak256(request.data!),
|
|
1246
|
-
failureType: 'simulation',
|
|
1247
|
-
request: { to: request.to!, data: request.data!, value: request.value?.toString() },
|
|
1248
|
-
l1BlockNumber: l1BlockNumber.toString(),
|
|
1249
|
-
error: { message: viemError.message, name: viemError.name },
|
|
1250
|
-
context: {
|
|
1251
|
-
actions: [action],
|
|
1252
|
-
slot: slotNumber,
|
|
1253
|
-
sender: this.getSenderAddress().toString(),
|
|
1254
|
-
},
|
|
1255
|
-
});
|
|
1256
|
-
|
|
1257
1067
|
return false;
|
|
1258
1068
|
}
|
|
1259
1069
|
|
|
@@ -1336,27 +1146,9 @@ export class SequencerPublisher {
|
|
|
1336
1146
|
kzg,
|
|
1337
1147
|
},
|
|
1338
1148
|
)
|
|
1339
|
-
.catch(
|
|
1340
|
-
const
|
|
1341
|
-
this.log.error(`Failed to validate blobs`,
|
|
1342
|
-
const validateBlobsData = encodeFunctionData({
|
|
1343
|
-
abi: RollupAbi,
|
|
1344
|
-
functionName: 'validateBlobs',
|
|
1345
|
-
args: [blobInput],
|
|
1346
|
-
});
|
|
1347
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1348
|
-
this.backupFailedTx({
|
|
1349
|
-
id: keccak256(validateBlobsData),
|
|
1350
|
-
failureType: 'simulation',
|
|
1351
|
-
request: { to: this.rollupContract.address as Hex, data: validateBlobsData },
|
|
1352
|
-
blobData: encodedData.blobs.map(b => toHex(b.data)) as Hex[],
|
|
1353
|
-
l1BlockNumber: l1BlockNumber.toString(),
|
|
1354
|
-
error: { message: viemError.message, name: viemError.name },
|
|
1355
|
-
context: {
|
|
1356
|
-
actions: ['validate-blobs'],
|
|
1357
|
-
sender: this.getSenderAddress().toString(),
|
|
1358
|
-
},
|
|
1359
|
-
});
|
|
1149
|
+
.catch(err => {
|
|
1150
|
+
const { message, metaMessages } = formatViemError(err);
|
|
1151
|
+
this.log.error(`Failed to validate blobs`, message, { metaMessages });
|
|
1360
1152
|
throw new Error('Failed to validate blobs');
|
|
1361
1153
|
});
|
|
1362
1154
|
}
|
|
@@ -1433,7 +1225,6 @@ export class SequencerPublisher {
|
|
|
1433
1225
|
});
|
|
1434
1226
|
}
|
|
1435
1227
|
|
|
1436
|
-
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1437
1228
|
const simTs = this.getSimulationTimestamp(SlotNumber.fromBigInt(args[0].header.slotNumber));
|
|
1438
1229
|
|
|
1439
1230
|
const simulationResult = await this.l1TxUtils
|
|
@@ -1468,18 +1259,6 @@ export class SequencerPublisher {
|
|
|
1468
1259
|
};
|
|
1469
1260
|
}
|
|
1470
1261
|
this.log.error(`Failed to simulate propose tx`, viemError, { simulationTimestamp: simTs });
|
|
1471
|
-
this.backupFailedTx({
|
|
1472
|
-
id: keccak256(rollupData),
|
|
1473
|
-
failureType: 'simulation',
|
|
1474
|
-
request: { to: this.rollupContract.address, data: rollupData },
|
|
1475
|
-
l1BlockNumber: l1BlockNumber.toString(),
|
|
1476
|
-
error: { message: viemError.message, name: viemError.name },
|
|
1477
|
-
context: {
|
|
1478
|
-
actions: ['propose'],
|
|
1479
|
-
slot: Number(args[0].header.slotNumber),
|
|
1480
|
-
sender: this.getSenderAddress().toString(),
|
|
1481
|
-
},
|
|
1482
|
-
});
|
|
1483
1262
|
throw err;
|
|
1484
1263
|
});
|
|
1485
1264
|
|