@aztec/sequencer-client 4.0.0-devnet.2-patch.3 → 4.0.0-devnet.3-patch.0
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 -1
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +38 -19
- package/dest/config.d.ts +24 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +29 -16
- package/dest/global_variable_builder/global_builder.d.ts +13 -7
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +22 -21
- package/dest/global_variable_builder/index.d.ts +2 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.d.ts +15 -8
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +65 -36
- package/dest/sequencer/checkpoint_proposal_job.d.ts +4 -4
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +98 -68
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/sequencer.d.ts +12 -7
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +15 -17
- package/dest/sequencer/timetable.d.ts +4 -3
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +6 -7
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +7 -9
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +41 -30
- package/package.json +28 -28
- package/src/client/sequencer-client.ts +48 -14
- package/src/config.ts +35 -19
- package/src/global_variable_builder/global_builder.ts +22 -23
- package/src/global_variable_builder/index.ts +1 -1
- package/src/publisher/sequencer-publisher.ts +61 -44
- package/src/sequencer/checkpoint_proposal_job.ts +156 -98
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/sequencer.ts +16 -18
- package/src/sequencer/timetable.ts +7 -7
- package/src/sequencer/types.ts +1 -1
- package/src/test/mock_checkpoint_builder.ts +53 -48
package/src/config.ts
CHANGED
|
@@ -35,15 +35,13 @@ export type { SequencerConfig };
|
|
|
35
35
|
* Default values for SequencerConfig.
|
|
36
36
|
* Centralized location for all sequencer configuration defaults.
|
|
37
37
|
*/
|
|
38
|
-
export const DefaultSequencerConfig
|
|
38
|
+
export const DefaultSequencerConfig = {
|
|
39
39
|
sequencerPollingIntervalMS: 500,
|
|
40
|
-
maxTxsPerBlock: 32,
|
|
41
40
|
minTxsPerBlock: 1,
|
|
42
41
|
buildCheckpointIfEmpty: false,
|
|
43
42
|
publishTxsWithProposals: false,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
maxBlockSizeInBytes: 1024 * 1024,
|
|
43
|
+
perBlockAllocationMultiplier: 1.2,
|
|
44
|
+
redistributeCheckpointBudget: true,
|
|
47
45
|
enforceTimeTable: true,
|
|
48
46
|
attestationPropagationTime: DEFAULT_P2P_PROPAGATION_TIME,
|
|
49
47
|
secondsBeforeInvalidatingBlockAsCommitteeMember: 144, // 12 L1 blocks
|
|
@@ -52,11 +50,13 @@ export const DefaultSequencerConfig: ResolvedSequencerConfig = {
|
|
|
52
50
|
skipInvalidateBlockAsProposer: false,
|
|
53
51
|
broadcastInvalidBlockProposal: false,
|
|
54
52
|
injectFakeAttestation: false,
|
|
53
|
+
injectHighSValueAttestation: false,
|
|
54
|
+
injectUnrecoverableSignatureAttestation: false,
|
|
55
55
|
fishermanMode: false,
|
|
56
56
|
shuffleAttestationOrdering: false,
|
|
57
57
|
skipPushProposedBlocksToArchiver: false,
|
|
58
58
|
skipPublishingCheckpointsPercent: 0,
|
|
59
|
-
};
|
|
59
|
+
} satisfies ResolvedSequencerConfig;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Configuration settings for the SequencerClient.
|
|
@@ -68,7 +68,7 @@ export type SequencerClientConfig = SequencerPublisherConfig &
|
|
|
68
68
|
SequencerConfig &
|
|
69
69
|
L1ReaderConfig &
|
|
70
70
|
ChainConfig &
|
|
71
|
-
Pick<P2PConfig, '
|
|
71
|
+
Pick<P2PConfig, 'txPublicSetupAllowListExtend'> &
|
|
72
72
|
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
|
|
73
73
|
|
|
74
74
|
export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
@@ -77,10 +77,10 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
77
77
|
description: 'The number of ms to wait between polling for checking to build on the next slot.',
|
|
78
78
|
...numberConfigHelper(DefaultSequencerConfig.sequencerPollingIntervalMS),
|
|
79
79
|
},
|
|
80
|
-
|
|
81
|
-
env: '
|
|
82
|
-
description: 'The maximum number of txs
|
|
83
|
-
|
|
80
|
+
maxTxsPerCheckpoint: {
|
|
81
|
+
env: 'SEQ_MAX_TX_PER_CHECKPOINT',
|
|
82
|
+
description: 'The maximum number of txs across all blocks in a checkpoint.',
|
|
83
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
84
84
|
},
|
|
85
85
|
minTxsPerBlock: {
|
|
86
86
|
env: 'SEQ_MIN_TX_PER_BLOCK',
|
|
@@ -99,12 +99,25 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
99
99
|
maxL2BlockGas: {
|
|
100
100
|
env: 'SEQ_MAX_L2_BLOCK_GAS',
|
|
101
101
|
description: 'The maximum L2 block gas.',
|
|
102
|
-
|
|
102
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
103
103
|
},
|
|
104
104
|
maxDABlockGas: {
|
|
105
105
|
env: 'SEQ_MAX_DA_BLOCK_GAS',
|
|
106
106
|
description: 'The maximum DA block gas.',
|
|
107
|
-
|
|
107
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
108
|
+
},
|
|
109
|
+
perBlockAllocationMultiplier: {
|
|
110
|
+
env: 'SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER',
|
|
111
|
+
description:
|
|
112
|
+
'Per-block gas budget multiplier for both L2 and DA gas. Budget per block is (checkpointLimit / maxBlocks) * multiplier.' +
|
|
113
|
+
' Values greater than one allow early blocks to use more than their even share, relying on checkpoint-level capping for later blocks.',
|
|
114
|
+
...numberConfigHelper(DefaultSequencerConfig.perBlockAllocationMultiplier),
|
|
115
|
+
},
|
|
116
|
+
redistributeCheckpointBudget: {
|
|
117
|
+
env: 'SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET',
|
|
118
|
+
description:
|
|
119
|
+
'Redistribute remaining checkpoint budget evenly across remaining blocks instead of allowing a single block to consume the entire remaining budget.',
|
|
120
|
+
...booleanConfigHelper(DefaultSequencerConfig.redistributeCheckpointBudget),
|
|
108
121
|
},
|
|
109
122
|
coinbase: {
|
|
110
123
|
env: 'COINBASE',
|
|
@@ -124,11 +137,6 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
124
137
|
env: 'ACVM_BINARY_PATH',
|
|
125
138
|
description: 'The path to the ACVM binary',
|
|
126
139
|
},
|
|
127
|
-
maxBlockSizeInBytes: {
|
|
128
|
-
env: 'SEQ_MAX_BLOCK_SIZE_IN_BYTES',
|
|
129
|
-
description: 'Max block size',
|
|
130
|
-
...numberConfigHelper(DefaultSequencerConfig.maxBlockSizeInBytes),
|
|
131
|
-
},
|
|
132
140
|
enforceTimeTable: {
|
|
133
141
|
env: 'SEQ_ENFORCE_TIME_TABLE',
|
|
134
142
|
description: 'Whether to enforce the time table when building blocks',
|
|
@@ -186,6 +194,14 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
186
194
|
description: 'Inject a fake attestation (for testing only)',
|
|
187
195
|
...booleanConfigHelper(DefaultSequencerConfig.injectFakeAttestation),
|
|
188
196
|
},
|
|
197
|
+
injectHighSValueAttestation: {
|
|
198
|
+
description: 'Inject a malleable attestation with a high-s value (for testing only)',
|
|
199
|
+
...booleanConfigHelper(DefaultSequencerConfig.injectHighSValueAttestation),
|
|
200
|
+
},
|
|
201
|
+
injectUnrecoverableSignatureAttestation: {
|
|
202
|
+
description: 'Inject an attestation with an unrecoverable signature (for testing only)',
|
|
203
|
+
...booleanConfigHelper(DefaultSequencerConfig.injectUnrecoverableSignatureAttestation),
|
|
204
|
+
},
|
|
189
205
|
fishermanMode: {
|
|
190
206
|
env: 'FISHERMAN_MODE',
|
|
191
207
|
description:
|
|
@@ -214,7 +230,7 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
214
230
|
description: 'Percent probability (0 - 100) of sequencer skipping checkpoint publishing (testing only)',
|
|
215
231
|
...numberConfigHelper(DefaultSequencerConfig.skipPublishingCheckpointsPercent),
|
|
216
232
|
},
|
|
217
|
-
...pickConfigMappings(p2pConfigMappings, ['
|
|
233
|
+
...pickConfigMappings(p2pConfigMappings, ['txPublicSetupAllowListExtend']),
|
|
218
234
|
};
|
|
219
235
|
|
|
220
236
|
export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientConfig> = {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
-
import type { L1ContractsConfig } from '@aztec/ethereum/config';
|
|
3
1
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
4
|
-
import type {
|
|
2
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
5
3
|
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
6
4
|
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
7
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
8
6
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
10
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
|
-
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
10
|
+
import { type L1RollupConstants, getNextL1SlotTimestamp, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
12
11
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
13
12
|
import type {
|
|
14
13
|
CheckpointGlobalVariables,
|
|
@@ -16,7 +15,12 @@ import type {
|
|
|
16
15
|
} from '@aztec/stdlib/tx';
|
|
17
16
|
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
/** Configuration for the GlobalVariableBuilder (excludes L1 client config). */
|
|
19
|
+
export type GlobalVariableBuilderConfig = {
|
|
20
|
+
l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
|
|
21
|
+
ethereumSlotDuration: number;
|
|
22
|
+
rollupVersion: bigint;
|
|
23
|
+
} & Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'>;
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
26
|
* Simple global variables builder.
|
|
@@ -27,7 +31,6 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
27
31
|
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
28
32
|
|
|
29
33
|
private readonly rollupContract: RollupContract;
|
|
30
|
-
private readonly publicClient: ViemPublicClient;
|
|
31
34
|
private readonly ethereumSlotDuration: number;
|
|
32
35
|
private readonly aztecSlotDuration: number;
|
|
33
36
|
private readonly l1GenesisTime: bigint;
|
|
@@ -36,28 +39,18 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
36
39
|
private version: Fr;
|
|
37
40
|
|
|
38
41
|
constructor(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
private readonly dateProvider: DateProvider,
|
|
43
|
+
private readonly publicClient: ViemPublicClient,
|
|
44
|
+
config: GlobalVariableBuilderConfig,
|
|
42
45
|
) {
|
|
43
|
-
const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
|
|
44
|
-
|
|
45
|
-
const chain = createEthereumChain(l1RpcUrls, chainId);
|
|
46
|
-
|
|
47
46
|
this.version = new Fr(config.rollupVersion);
|
|
48
|
-
this.chainId = new Fr(
|
|
47
|
+
this.chainId = new Fr(this.publicClient.chain!.id);
|
|
49
48
|
|
|
50
49
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
51
50
|
this.aztecSlotDuration = config.slotDuration;
|
|
52
51
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
53
52
|
|
|
54
|
-
this.
|
|
55
|
-
chain: chain.chainInfo,
|
|
56
|
-
transport: fallback(chain.rpcUrls.map(url => http(url, { batch: false }))),
|
|
57
|
-
pollingInterval: config.viemPollingIntervalMS,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
this.rollupContract = new RollupContract(this.publicClient, l1Contracts.rollupAddress);
|
|
53
|
+
this.rollupContract = new RollupContract(this.publicClient, config.l1Contracts.rollupAddress);
|
|
61
54
|
}
|
|
62
55
|
|
|
63
56
|
/**
|
|
@@ -73,7 +66,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
73
66
|
const earliestTimestamp = await this.rollupContract.getTimestampForSlot(
|
|
74
67
|
SlotNumber.fromBigInt(BigInt(lastCheckpoint.slotNumber) + 1n),
|
|
75
68
|
);
|
|
76
|
-
const nextEthTimestamp =
|
|
69
|
+
const nextEthTimestamp = getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
70
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
71
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
72
|
+
});
|
|
77
73
|
const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
|
|
78
74
|
|
|
79
75
|
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
@@ -108,7 +104,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
108
104
|
const slot: SlotNumber =
|
|
109
105
|
maybeSlot ??
|
|
110
106
|
(await this.rollupContract.getSlotAt(
|
|
111
|
-
|
|
107
|
+
getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
108
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
109
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
110
|
+
}),
|
|
112
111
|
));
|
|
113
112
|
|
|
114
113
|
const checkpointGlobalVariables = await this.buildCheckpointGlobalVariables(coinbase, feeRecipient, slot);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { GlobalVariableBuilder } from './global_builder.js';
|
|
1
|
+
export { GlobalVariableBuilder, type GlobalVariableBuilderConfig } from './global_builder.js';
|
|
@@ -28,6 +28,7 @@ import { FormattedViemError, formatViemError, mergeAbis, tryExtractEvent } from
|
|
|
28
28
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
29
29
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
30
30
|
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
31
|
+
import { trimmedBytesLength } from '@aztec/foundation/buffer';
|
|
31
32
|
import { pick } from '@aztec/foundation/collection';
|
|
32
33
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
33
34
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -40,6 +41,7 @@ import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
|
40
41
|
import { type ProposerSlashAction, encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
41
42
|
import { CommitteeAttestationsAndSigners, type ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
42
43
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
44
|
+
import { getLastL1SlotTimestampForL2Slot, getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
43
45
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
44
46
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
45
47
|
import type { L1PublishCheckpointStats } from '@aztec/stdlib/stats';
|
|
@@ -120,6 +122,8 @@ export class SequencerPublisher {
|
|
|
120
122
|
|
|
121
123
|
protected log: Logger;
|
|
122
124
|
protected ethereumSlotDuration: bigint;
|
|
125
|
+
protected aztecSlotDuration: bigint;
|
|
126
|
+
private dateProvider: DateProvider;
|
|
123
127
|
|
|
124
128
|
private blobClient: BlobClientInterface;
|
|
125
129
|
|
|
@@ -150,7 +154,7 @@ export class SequencerPublisher {
|
|
|
150
154
|
|
|
151
155
|
constructor(
|
|
152
156
|
private config: Pick<SequencerPublisherConfig, 'fishermanMode'> &
|
|
153
|
-
Pick<L1ContractsConfig, 'ethereumSlotDuration'> & { l1ChainId: number },
|
|
157
|
+
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'> & { l1ChainId: number },
|
|
154
158
|
deps: {
|
|
155
159
|
telemetry?: TelemetryClient;
|
|
156
160
|
blobClient: BlobClientInterface;
|
|
@@ -168,6 +172,8 @@ export class SequencerPublisher {
|
|
|
168
172
|
) {
|
|
169
173
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
170
174
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
175
|
+
this.aztecSlotDuration = BigInt(config.aztecSlotDuration);
|
|
176
|
+
this.dateProvider = deps.dateProvider;
|
|
171
177
|
this.epochCache = deps.epochCache;
|
|
172
178
|
this.lastActions = deps.lastActions;
|
|
173
179
|
|
|
@@ -356,8 +362,8 @@ export class SequencerPublisher {
|
|
|
356
362
|
// @note - we can only have one blob config per bundle
|
|
357
363
|
// find requests with gas and blob configs
|
|
358
364
|
// See https://github.com/AztecProtocol/aztec-packages/issues/11513
|
|
359
|
-
const gasConfigs =
|
|
360
|
-
const blobConfigs =
|
|
365
|
+
const gasConfigs = validRequests.filter(request => request.gasConfig).map(request => request.gasConfig);
|
|
366
|
+
const blobConfigs = validRequests.filter(request => request.blobConfig).map(request => request.blobConfig);
|
|
361
367
|
|
|
362
368
|
if (blobConfigs.length > 1) {
|
|
363
369
|
throw new Error('Multiple blob configs found');
|
|
@@ -425,7 +431,16 @@ export class SequencerPublisher {
|
|
|
425
431
|
this.log.error(`Failed to publish bundled transactions (${actionsListStr})`, result);
|
|
426
432
|
return { failedActions: requests.map(r => r.action) };
|
|
427
433
|
} else {
|
|
428
|
-
this.log.verbose(`Published bundled transactions (${actionsListStr})`, {
|
|
434
|
+
this.log.verbose(`Published bundled transactions (${actionsListStr})`, {
|
|
435
|
+
result,
|
|
436
|
+
requests: requests.map(r => ({
|
|
437
|
+
...r,
|
|
438
|
+
// Avoid logging large blob data
|
|
439
|
+
blobConfig: r.blobConfig
|
|
440
|
+
? { ...r.blobConfig, blobs: r.blobConfig.blobs.map(b => ({ size: trimmedBytesLength(b) })) }
|
|
441
|
+
: undefined,
|
|
442
|
+
})),
|
|
443
|
+
});
|
|
429
444
|
const successfulActions: Action[] = [];
|
|
430
445
|
const failedActions: Action[] = [];
|
|
431
446
|
for (const request of requests) {
|
|
@@ -440,20 +455,24 @@ export class SequencerPublisher {
|
|
|
440
455
|
}
|
|
441
456
|
|
|
442
457
|
/**
|
|
443
|
-
* @notice Will call `
|
|
458
|
+
* @notice Will call `canProposeAt` to make sure that it is possible to propose
|
|
444
459
|
* @param tipArchive - The archive to check
|
|
445
460
|
* @returns The slot and block number if it is possible to propose, undefined otherwise
|
|
446
461
|
*/
|
|
447
|
-
public
|
|
462
|
+
public canProposeAt(
|
|
448
463
|
tipArchive: Fr,
|
|
449
464
|
msgSender: EthAddress,
|
|
450
|
-
opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
465
|
+
opts: { forcePendingCheckpointNumber?: CheckpointNumber; pipelined?: boolean } = {},
|
|
451
466
|
) {
|
|
452
467
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
453
468
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
454
469
|
|
|
470
|
+
const pipelined = opts.pipelined ?? false;
|
|
471
|
+
const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
|
|
472
|
+
const nextL1SlotTs = this.getNextL1SlotTimestamp() + slotOffset;
|
|
473
|
+
|
|
455
474
|
return this.rollupContract
|
|
456
|
-
.
|
|
475
|
+
.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), nextL1SlotTs, {
|
|
457
476
|
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber,
|
|
458
477
|
})
|
|
459
478
|
.catch(err => {
|
|
@@ -490,7 +509,7 @@ export class SequencerPublisher {
|
|
|
490
509
|
flags,
|
|
491
510
|
] as const;
|
|
492
511
|
|
|
493
|
-
const ts =
|
|
512
|
+
const ts = this.getSimulationTimestamp(header.slotNumber);
|
|
494
513
|
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(
|
|
495
514
|
opts?.forcePendingCheckpointNumber,
|
|
496
515
|
);
|
|
@@ -513,7 +532,7 @@ export class SequencerPublisher {
|
|
|
513
532
|
data: encodeFunctionData({ abi: RollupAbi, functionName: 'validateHeaderWithAttestations', args }),
|
|
514
533
|
from: MULTI_CALL_3_ADDRESS,
|
|
515
534
|
},
|
|
516
|
-
{ time: ts
|
|
535
|
+
{ time: ts },
|
|
517
536
|
stateOverrides,
|
|
518
537
|
);
|
|
519
538
|
this.log.debug(`Simulated validateHeader`);
|
|
@@ -640,8 +659,7 @@ export class SequencerPublisher {
|
|
|
640
659
|
attestationsAndSigners: CommitteeAttestationsAndSigners,
|
|
641
660
|
attestationsAndSignersSignature: Signature,
|
|
642
661
|
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
643
|
-
): Promise<
|
|
644
|
-
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
662
|
+
): Promise<void> {
|
|
645
663
|
const blobFields = checkpoint.toBlobFields();
|
|
646
664
|
const blobs = await getBlobsPerL1Block(blobFields);
|
|
647
665
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
@@ -660,13 +678,11 @@ export class SequencerPublisher {
|
|
|
660
678
|
blobInput,
|
|
661
679
|
] as const;
|
|
662
680
|
|
|
663
|
-
await this.simulateProposeTx(args,
|
|
664
|
-
return ts;
|
|
681
|
+
await this.simulateProposeTx(args, options);
|
|
665
682
|
}
|
|
666
683
|
|
|
667
684
|
private async enqueueCastSignalHelper(
|
|
668
685
|
slotNumber: SlotNumber,
|
|
669
|
-
timestamp: bigint,
|
|
670
686
|
signalType: GovernanceSignalAction,
|
|
671
687
|
payload: EthAddress,
|
|
672
688
|
base: IEmpireBase,
|
|
@@ -744,11 +760,16 @@ export class SequencerPublisher {
|
|
|
744
760
|
lastValidL2Slot: slotNumber,
|
|
745
761
|
});
|
|
746
762
|
|
|
763
|
+
const timestamp = this.getSimulationTimestamp(slotNumber);
|
|
764
|
+
|
|
747
765
|
try {
|
|
748
766
|
await this.l1TxUtils.simulate(request, { time: timestamp }, [], mergeAbis([request.abi ?? [], ErrorsAbi]));
|
|
749
767
|
this.log.debug(`Simulation for ${action} at slot ${slotNumber} succeeded`, { request });
|
|
750
768
|
} catch (err) {
|
|
751
|
-
|
|
769
|
+
const viemError = formatViemError(err);
|
|
770
|
+
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError, {
|
|
771
|
+
simulationTimestamp: timestamp,
|
|
772
|
+
});
|
|
752
773
|
// Yes, we enqueue the request anyway, in case there was a bug with the simulation itself
|
|
753
774
|
}
|
|
754
775
|
|
|
@@ -799,19 +820,16 @@ export class SequencerPublisher {
|
|
|
799
820
|
/**
|
|
800
821
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
801
822
|
* @param slotNumber - The slot number to cast a signal for.
|
|
802
|
-
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
803
823
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
804
824
|
*/
|
|
805
825
|
public enqueueGovernanceCastSignal(
|
|
806
826
|
governancePayload: EthAddress,
|
|
807
827
|
slotNumber: SlotNumber,
|
|
808
|
-
timestamp: bigint,
|
|
809
828
|
signerAddress: EthAddress,
|
|
810
829
|
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
811
830
|
): Promise<boolean> {
|
|
812
831
|
return this.enqueueCastSignalHelper(
|
|
813
832
|
slotNumber,
|
|
814
|
-
timestamp,
|
|
815
833
|
'governance-signal',
|
|
816
834
|
governancePayload,
|
|
817
835
|
this.govProposerContract,
|
|
@@ -824,7 +842,6 @@ export class SequencerPublisher {
|
|
|
824
842
|
public async enqueueSlashingActions(
|
|
825
843
|
actions: ProposerSlashAction[],
|
|
826
844
|
slotNumber: SlotNumber,
|
|
827
|
-
timestamp: bigint,
|
|
828
845
|
signerAddress: EthAddress,
|
|
829
846
|
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
830
847
|
): Promise<boolean> {
|
|
@@ -845,7 +862,6 @@ export class SequencerPublisher {
|
|
|
845
862
|
});
|
|
846
863
|
await this.enqueueCastSignalHelper(
|
|
847
864
|
slotNumber,
|
|
848
|
-
timestamp,
|
|
849
865
|
'empire-slashing-signal',
|
|
850
866
|
action.payload,
|
|
851
867
|
this.slashingProposerContract,
|
|
@@ -864,7 +880,6 @@ export class SequencerPublisher {
|
|
|
864
880
|
(receipt: TransactionReceipt) =>
|
|
865
881
|
!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs),
|
|
866
882
|
slotNumber,
|
|
867
|
-
timestamp,
|
|
868
883
|
);
|
|
869
884
|
break;
|
|
870
885
|
}
|
|
@@ -882,7 +897,6 @@ export class SequencerPublisher {
|
|
|
882
897
|
request,
|
|
883
898
|
(receipt: TransactionReceipt) => !!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs),
|
|
884
899
|
slotNumber,
|
|
885
|
-
timestamp,
|
|
886
900
|
);
|
|
887
901
|
break;
|
|
888
902
|
}
|
|
@@ -906,7 +920,6 @@ export class SequencerPublisher {
|
|
|
906
920
|
request,
|
|
907
921
|
(receipt: TransactionReceipt) => !!tallySlashingProposer.tryExtractVoteCastEvent(receipt.logs),
|
|
908
922
|
slotNumber,
|
|
909
|
-
timestamp,
|
|
910
923
|
);
|
|
911
924
|
break;
|
|
912
925
|
}
|
|
@@ -928,7 +941,6 @@ export class SequencerPublisher {
|
|
|
928
941
|
request,
|
|
929
942
|
(receipt: TransactionReceipt) => !!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs),
|
|
930
943
|
slotNumber,
|
|
931
|
-
timestamp,
|
|
932
944
|
);
|
|
933
945
|
break;
|
|
934
946
|
}
|
|
@@ -964,15 +976,13 @@ export class SequencerPublisher {
|
|
|
964
976
|
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
965
977
|
};
|
|
966
978
|
|
|
967
|
-
let ts: bigint;
|
|
968
|
-
|
|
969
979
|
try {
|
|
970
980
|
// @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available
|
|
971
981
|
// This means that we can avoid the simulation issues in later checks.
|
|
972
982
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
973
983
|
// make time consistency checks break.
|
|
974
984
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
975
|
-
|
|
985
|
+
await this.validateCheckpointForSubmission(
|
|
976
986
|
checkpoint,
|
|
977
987
|
attestationsAndSigners,
|
|
978
988
|
attestationsAndSignersSignature,
|
|
@@ -988,7 +998,7 @@ export class SequencerPublisher {
|
|
|
988
998
|
}
|
|
989
999
|
|
|
990
1000
|
this.log.verbose(`Enqueuing checkpoint propose transaction`, { ...checkpoint.toCheckpointInfo(), ...opts });
|
|
991
|
-
await this.addProposeTx(checkpoint, proposeTxArgs, opts
|
|
1001
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, opts);
|
|
992
1002
|
}
|
|
993
1003
|
|
|
994
1004
|
public enqueueInvalidateCheckpoint(
|
|
@@ -1031,8 +1041,8 @@ export class SequencerPublisher {
|
|
|
1031
1041
|
request: L1TxRequest,
|
|
1032
1042
|
checkSuccess: (receipt: TransactionReceipt) => boolean | undefined,
|
|
1033
1043
|
slotNumber: SlotNumber,
|
|
1034
|
-
timestamp: bigint,
|
|
1035
1044
|
) {
|
|
1045
|
+
const timestamp = this.getSimulationTimestamp(slotNumber);
|
|
1036
1046
|
const logData = { slotNumber, timestamp, gasLimit: undefined as bigint | undefined };
|
|
1037
1047
|
if (this.lastActions[action] && this.lastActions[action] === slotNumber) {
|
|
1038
1048
|
this.log.debug(`Skipping duplicate action ${action} for slot ${slotNumber}`);
|
|
@@ -1046,8 +1056,9 @@ export class SequencerPublisher {
|
|
|
1046
1056
|
|
|
1047
1057
|
let gasUsed: bigint;
|
|
1048
1058
|
const simulateAbi = mergeAbis([request.abi ?? [], ErrorsAbi]);
|
|
1059
|
+
|
|
1049
1060
|
try {
|
|
1050
|
-
({ gasUsed } = await this.l1TxUtils.simulate(request, { time: timestamp }, [], simulateAbi));
|
|
1061
|
+
({ gasUsed } = await this.l1TxUtils.simulate(request, { time: timestamp }, [], simulateAbi));
|
|
1051
1062
|
this.log.verbose(`Simulation for ${action} succeeded`, { ...logData, request, gasUsed });
|
|
1052
1063
|
} catch (err) {
|
|
1053
1064
|
const viemError = formatViemError(err, simulateAbi);
|
|
@@ -1103,7 +1114,6 @@ export class SequencerPublisher {
|
|
|
1103
1114
|
|
|
1104
1115
|
private async prepareProposeTx(
|
|
1105
1116
|
encodedData: L1ProcessArgs,
|
|
1106
|
-
timestamp: bigint,
|
|
1107
1117
|
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
1108
1118
|
) {
|
|
1109
1119
|
const kzg = Blob.getViemKzgInstance();
|
|
@@ -1158,7 +1168,7 @@ export class SequencerPublisher {
|
|
|
1158
1168
|
blobInput,
|
|
1159
1169
|
] as const;
|
|
1160
1170
|
|
|
1161
|
-
const { rollupData, simulationResult } = await this.simulateProposeTx(args,
|
|
1171
|
+
const { rollupData, simulationResult } = await this.simulateProposeTx(args, options);
|
|
1162
1172
|
|
|
1163
1173
|
return { args, blobEvaluationGas, rollupData, simulationResult };
|
|
1164
1174
|
}
|
|
@@ -1166,7 +1176,6 @@ export class SequencerPublisher {
|
|
|
1166
1176
|
/**
|
|
1167
1177
|
* Simulates the propose tx with eth_simulateV1
|
|
1168
1178
|
* @param args - The propose tx args
|
|
1169
|
-
* @param timestamp - The timestamp to simulate proposal at
|
|
1170
1179
|
* @returns The simulation result
|
|
1171
1180
|
*/
|
|
1172
1181
|
private async simulateProposeTx(
|
|
@@ -1183,7 +1192,6 @@ export class SequencerPublisher {
|
|
|
1183
1192
|
ViemSignature,
|
|
1184
1193
|
`0x${string}`,
|
|
1185
1194
|
],
|
|
1186
|
-
timestamp: bigint,
|
|
1187
1195
|
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
1188
1196
|
) {
|
|
1189
1197
|
const rollupData = encodeFunctionData({
|
|
@@ -1217,6 +1225,8 @@ export class SequencerPublisher {
|
|
|
1217
1225
|
});
|
|
1218
1226
|
}
|
|
1219
1227
|
|
|
1228
|
+
const simTs = this.getSimulationTimestamp(SlotNumber.fromBigInt(args[0].header.slotNumber));
|
|
1229
|
+
|
|
1220
1230
|
const simulationResult = await this.l1TxUtils
|
|
1221
1231
|
.simulate(
|
|
1222
1232
|
{
|
|
@@ -1226,8 +1236,7 @@ export class SequencerPublisher {
|
|
|
1226
1236
|
...(this.proposerAddressForSimulation && { from: this.proposerAddressForSimulation.toString() }),
|
|
1227
1237
|
},
|
|
1228
1238
|
{
|
|
1229
|
-
|
|
1230
|
-
time: timestamp + 1n,
|
|
1239
|
+
time: simTs,
|
|
1231
1240
|
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
1232
1241
|
gasLimit: MAX_L1_TX_LIMIT * 2n,
|
|
1233
1242
|
},
|
|
@@ -1249,7 +1258,7 @@ export class SequencerPublisher {
|
|
|
1249
1258
|
logs: [],
|
|
1250
1259
|
};
|
|
1251
1260
|
}
|
|
1252
|
-
this.log.error(`Failed to simulate propose tx`, viemError);
|
|
1261
|
+
this.log.error(`Failed to simulate propose tx`, viemError, { simulationTimestamp: simTs });
|
|
1253
1262
|
throw err;
|
|
1254
1263
|
});
|
|
1255
1264
|
|
|
@@ -1260,16 +1269,11 @@ export class SequencerPublisher {
|
|
|
1260
1269
|
checkpoint: Checkpoint,
|
|
1261
1270
|
encodedData: L1ProcessArgs,
|
|
1262
1271
|
opts: { txTimeoutAt?: Date; forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
1263
|
-
timestamp: bigint,
|
|
1264
1272
|
): Promise<void> {
|
|
1265
1273
|
const slot = checkpoint.header.slotNumber;
|
|
1266
1274
|
const timer = new Timer();
|
|
1267
1275
|
const kzg = Blob.getViemKzgInstance();
|
|
1268
|
-
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(
|
|
1269
|
-
encodedData,
|
|
1270
|
-
timestamp,
|
|
1271
|
-
opts,
|
|
1272
|
-
);
|
|
1276
|
+
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, opts);
|
|
1273
1277
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
1274
1278
|
const gasLimit = this.l1TxUtils.bumpGasLimit(
|
|
1275
1279
|
BigInt(Math.ceil((Number(simulationResult.gasUsed) * 64) / 63)) +
|
|
@@ -1345,4 +1349,17 @@ export class SequencerPublisher {
|
|
|
1345
1349
|
},
|
|
1346
1350
|
});
|
|
1347
1351
|
}
|
|
1352
|
+
|
|
1353
|
+
/** Returns the timestamp of the last L1 slot within a given L2 slot. Used as the simulation timestamp
|
|
1354
|
+
* for eth_simulateV1 calls, since it's guaranteed to be greater than any L1 block produced during the slot. */
|
|
1355
|
+
private getSimulationTimestamp(slot: SlotNumber): bigint {
|
|
1356
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
1357
|
+
return getLastL1SlotTimestampForL2Slot(slot, l1Constants);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
/** Returns the timestamp of the next L1 slot boundary after now. */
|
|
1361
|
+
private getNextL1SlotTimestamp(): bigint {
|
|
1362
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
1363
|
+
return getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), l1Constants);
|
|
1364
|
+
}
|
|
1348
1365
|
}
|