@aztec/sequencer-client 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c
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 +21 -16
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +45 -27
- package/dest/config.d.ts +14 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +83 -35
- package/dest/global_variable_builder/global_builder.d.ts +20 -13
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +51 -41
- package/dest/index.d.ts +2 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/config.d.ts +37 -20
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +104 -39
- package/dest/publisher/sequencer-publisher-factory.d.ts +15 -6
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +14 -3
- package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +23 -86
- package/dest/publisher/sequencer-publisher.d.ts +63 -47
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +630 -137
- package/dest/sequencer/checkpoint_proposal_job.d.ts +102 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job.js +1213 -0
- package/dest/sequencer/checkpoint_voter.d.ts +35 -0
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_voter.js +109 -0
- package/dest/sequencer/config.d.ts +3 -2
- package/dest/sequencer/config.d.ts.map +1 -1
- package/dest/sequencer/events.d.ts +46 -0
- package/dest/sequencer/events.d.ts.map +1 -0
- package/dest/sequencer/events.js +1 -0
- package/dest/sequencer/index.d.ts +4 -2
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +3 -1
- package/dest/sequencer/metrics.d.ts +38 -6
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +216 -72
- package/dest/sequencer/sequencer.d.ts +119 -133
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +717 -625
- package/dest/sequencer/timetable.d.ts +51 -14
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +145 -59
- package/dest/sequencer/types.d.ts +3 -0
- package/dest/sequencer/types.d.ts.map +1 -0
- package/dest/sequencer/types.js +1 -0
- package/dest/sequencer/utils.d.ts +14 -8
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +7 -4
- package/dest/test/index.d.ts +6 -7
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +97 -0
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
- package/dest/test/mock_checkpoint_builder.js +222 -0
- package/dest/test/utils.d.ts +53 -0
- package/dest/test/utils.d.ts.map +1 -0
- package/dest/test/utils.js +104 -0
- package/package.json +32 -30
- package/src/client/sequencer-client.ts +54 -47
- package/src/config.ts +95 -44
- package/src/global_variable_builder/global_builder.ts +65 -61
- package/src/index.ts +1 -7
- package/src/publisher/config.ts +122 -50
- package/src/publisher/sequencer-publisher-factory.ts +28 -10
- package/src/publisher/sequencer-publisher-metrics.ts +19 -71
- package/src/publisher/sequencer-publisher.ts +350 -176
- package/src/sequencer/README.md +531 -0
- package/src/sequencer/checkpoint_proposal_job.ts +914 -0
- package/src/sequencer/checkpoint_voter.ts +130 -0
- package/src/sequencer/config.ts +2 -1
- package/src/sequencer/events.ts +27 -0
- package/src/sequencer/index.ts +3 -1
- package/src/sequencer/metrics.ts +268 -82
- package/src/sequencer/sequencer.ts +464 -831
- package/src/sequencer/timetable.ts +175 -80
- package/src/sequencer/types.ts +6 -0
- package/src/sequencer/utils.ts +18 -9
- package/src/test/index.ts +5 -6
- package/src/test/mock_checkpoint_builder.ts +320 -0
- package/src/test/utils.ts +167 -0
- package/dest/sequencer/block_builder.d.ts +0 -27
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -134
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -17
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -53
- package/src/sequencer/block_builder.ts +0 -222
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -132
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
2
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
isAnvilTestChain,
|
|
9
|
-
} from '@aztec/ethereum';
|
|
10
|
-
import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
3
|
+
import { isAnvilTestChain } from '@aztec/ethereum/chain';
|
|
4
|
+
import { getPublicClient } from '@aztec/ethereum/client';
|
|
5
|
+
import { GovernanceProposerContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
6
|
+
import { type Delayer, L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
7
|
+
import { PublisherManager } from '@aztec/ethereum/publisher-manager';
|
|
11
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
12
9
|
import { createLogger } from '@aztec/foundation/log';
|
|
13
10
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
14
11
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
15
12
|
import type { P2P } from '@aztec/p2p';
|
|
16
13
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
17
|
-
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
18
|
-
import type {
|
|
19
|
-
IFullNodeBlockBuilder,
|
|
20
|
-
ValidatorClientFullConfig,
|
|
21
|
-
WorldStateSynchronizer,
|
|
22
|
-
} from '@aztec/stdlib/interfaces/server';
|
|
14
|
+
import type { L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
15
|
+
import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
23
16
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
24
17
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
25
18
|
import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
26
|
-
import { NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
19
|
+
import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
27
20
|
|
|
28
|
-
import type
|
|
21
|
+
import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
|
|
29
22
|
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
30
23
|
import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
31
24
|
import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
@@ -35,11 +28,12 @@ import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
|
35
28
|
*/
|
|
36
29
|
export class SequencerClient {
|
|
37
30
|
constructor(
|
|
38
|
-
protected publisherManager: PublisherManager<
|
|
31
|
+
protected publisherManager: PublisherManager<L1TxUtils>,
|
|
39
32
|
protected sequencer: Sequencer,
|
|
40
|
-
protected
|
|
33
|
+
protected checkpointsBuilder: FullNodeCheckpointsBuilder,
|
|
41
34
|
protected validatorClient?: ValidatorClient,
|
|
42
35
|
private l1Metrics?: L1Metrics,
|
|
36
|
+
private delayer_?: Delayer,
|
|
43
37
|
) {}
|
|
44
38
|
|
|
45
39
|
/**
|
|
@@ -57,19 +51,19 @@ export class SequencerClient {
|
|
|
57
51
|
public static async new(
|
|
58
52
|
config: SequencerClientConfig,
|
|
59
53
|
deps: {
|
|
60
|
-
validatorClient: ValidatorClient
|
|
54
|
+
validatorClient: ValidatorClient;
|
|
61
55
|
p2pClient: P2P;
|
|
62
56
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
63
57
|
slasherClient: SlasherClientInterface | undefined;
|
|
64
|
-
|
|
65
|
-
l2BlockSource: L2BlockSource;
|
|
58
|
+
checkpointsBuilder: FullNodeCheckpointsBuilder;
|
|
59
|
+
l2BlockSource: L2BlockSource & L2BlockSink;
|
|
66
60
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
67
61
|
telemetry: TelemetryClient;
|
|
68
62
|
publisherFactory?: SequencerPublisherFactory;
|
|
69
|
-
|
|
63
|
+
blobClient: BlobClientInterface;
|
|
70
64
|
dateProvider: DateProvider;
|
|
71
65
|
epochCache?: EpochCache;
|
|
72
|
-
l1TxUtils:
|
|
66
|
+
l1TxUtils: L1TxUtils[];
|
|
73
67
|
nodeKeyStore: KeystoreManager;
|
|
74
68
|
},
|
|
75
69
|
) {
|
|
@@ -78,7 +72,7 @@ export class SequencerClient {
|
|
|
78
72
|
p2pClient,
|
|
79
73
|
worldStateSynchronizer,
|
|
80
74
|
slasherClient,
|
|
81
|
-
|
|
75
|
+
checkpointsBuilder,
|
|
82
76
|
l2BlockSource,
|
|
83
77
|
l1ToL2MessageSource,
|
|
84
78
|
telemetry: telemetryClient,
|
|
@@ -92,11 +86,17 @@ export class SequencerClient {
|
|
|
92
86
|
publicClient,
|
|
93
87
|
l1TxUtils.map(x => x.getSenderAddress()),
|
|
94
88
|
);
|
|
95
|
-
const publisherManager = new PublisherManager(
|
|
89
|
+
const publisherManager = new PublisherManager(
|
|
90
|
+
l1TxUtils,
|
|
91
|
+
getPublisherConfigFromSequencerConfig(config),
|
|
92
|
+
log.getBindings(),
|
|
93
|
+
);
|
|
96
94
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
97
|
-
const [l1GenesisTime, slotDuration] = await Promise.all([
|
|
95
|
+
const [l1GenesisTime, slotDuration, rollupVersion, rollupManaLimit] = await Promise.all([
|
|
98
96
|
rollupContract.getL1GenesisTime(),
|
|
99
97
|
rollupContract.getSlotDuration(),
|
|
98
|
+
rollupContract.getVersion(),
|
|
99
|
+
rollupContract.getManaLimit().then(Number),
|
|
100
100
|
] as const);
|
|
101
101
|
|
|
102
102
|
const governanceProposerContract = new GovernanceProposerContract(
|
|
@@ -125,7 +125,7 @@ export class SequencerClient {
|
|
|
125
125
|
deps.publisherFactory ??
|
|
126
126
|
new SequencerPublisherFactory(config, {
|
|
127
127
|
telemetry: telemetryClient,
|
|
128
|
-
|
|
128
|
+
blobClient: deps.blobClient,
|
|
129
129
|
epochCache,
|
|
130
130
|
governanceProposerContract,
|
|
131
131
|
slashFactoryContract,
|
|
@@ -135,33 +135,27 @@ export class SequencerClient {
|
|
|
135
135
|
nodeKeyStore: NodeKeystoreAdapter.fromKeyStoreManager(deps.nodeKeyStore),
|
|
136
136
|
logger: log,
|
|
137
137
|
});
|
|
138
|
-
const globalsBuilder = new GlobalVariableBuilder(config);
|
|
139
138
|
|
|
140
139
|
const ethereumSlotDuration = config.ethereumSlotDuration;
|
|
140
|
+
const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration };
|
|
141
|
+
|
|
142
|
+
const globalsBuilder = new GlobalVariableBuilder({ ...config, ...l1Constants, rollupVersion });
|
|
141
143
|
|
|
142
|
-
const rollupManaLimit = Number(await rollupContract.getManaLimit());
|
|
143
144
|
let sequencerManaLimit = config.maxL2BlockGas ?? rollupManaLimit;
|
|
144
145
|
if (sequencerManaLimit > rollupManaLimit) {
|
|
145
146
|
log.warn(
|
|
146
|
-
`Provided maxL2BlockGas
|
|
147
|
+
`Provided maxL2BlockGas ${sequencerManaLimit} is greater than the max allowed by L1. Setting limit to ${rollupManaLimit}.`,
|
|
147
148
|
);
|
|
148
149
|
sequencerManaLimit = rollupManaLimit;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
// When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
|
|
152
|
-
// Otherwise,
|
|
153
|
-
// maxL1TxInclusionTimeIntoSlot of zero) to get the tx into that L1 slot.
|
|
153
|
+
// Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
|
|
154
154
|
// In theory, the L1 slot has an initial 4s phase where the block is propagated, so we could
|
|
155
|
-
//
|
|
155
|
+
// reduce the publishing time allowance. However, we prefer being conservative.
|
|
156
156
|
// See https://www.blocknative.com/blog/anatomy-of-a-slot#7 for more info.
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
const l1Constants = {
|
|
161
|
-
l1GenesisTime,
|
|
162
|
-
slotDuration: Number(slotDuration),
|
|
163
|
-
ethereumSlotDuration,
|
|
164
|
-
};
|
|
157
|
+
const l1PublishingTimeBasedOnChain = isAnvilTestChain(config.l1ChainId) ? 1 : ethereumSlotDuration;
|
|
158
|
+
const l1PublishingTime = config.l1PublishingTime ?? l1PublishingTimeBasedOnChain;
|
|
165
159
|
|
|
166
160
|
const sequencer = new Sequencer(
|
|
167
161
|
publisherFactory,
|
|
@@ -172,19 +166,22 @@ export class SequencerClient {
|
|
|
172
166
|
slasherClient,
|
|
173
167
|
l2BlockSource,
|
|
174
168
|
l1ToL2MessageSource,
|
|
175
|
-
|
|
169
|
+
checkpointsBuilder,
|
|
176
170
|
l1Constants,
|
|
177
171
|
deps.dateProvider,
|
|
178
172
|
epochCache,
|
|
179
173
|
rollupContract,
|
|
180
|
-
{ ...config,
|
|
174
|
+
{ ...config, l1PublishingTime, maxL2BlockGas: sequencerManaLimit },
|
|
181
175
|
telemetryClient,
|
|
182
176
|
log,
|
|
183
177
|
);
|
|
184
178
|
|
|
185
|
-
|
|
179
|
+
sequencer.init();
|
|
180
|
+
|
|
181
|
+
// Extract the shared delayer from the first L1TxUtils instance (all instances share the same delayer)
|
|
182
|
+
const delayer = l1TxUtils[0]?.delayer;
|
|
186
183
|
|
|
187
|
-
return new SequencerClient(publisherManager, sequencer,
|
|
184
|
+
return new SequencerClient(publisherManager, sequencer, checkpointsBuilder, validatorClient, l1Metrics, delayer);
|
|
188
185
|
}
|
|
189
186
|
|
|
190
187
|
/**
|
|
@@ -193,7 +190,7 @@ export class SequencerClient {
|
|
|
193
190
|
*/
|
|
194
191
|
public updateConfig(config: SequencerConfig & Partial<ValidatorClientFullConfig>) {
|
|
195
192
|
this.sequencer.updateConfig(config);
|
|
196
|
-
this.
|
|
193
|
+
this.checkpointsBuilder.updateConfig(config);
|
|
197
194
|
this.validatorClient?.updateConfig(config);
|
|
198
195
|
}
|
|
199
196
|
|
|
@@ -219,6 +216,16 @@ export class SequencerClient {
|
|
|
219
216
|
return this.sequencer;
|
|
220
217
|
}
|
|
221
218
|
|
|
219
|
+
/** Updates the publisher factory's node keystore adapter after a keystore reload. */
|
|
220
|
+
public updatePublisherNodeKeyStore(adapter: NodeKeystoreAdapter): void {
|
|
221
|
+
this.sequencer.updatePublisherNodeKeyStore(adapter);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Returns the shared tx delayer for sequencer L1 txs, if enabled. Test-only. */
|
|
225
|
+
getDelayer(): Delayer | undefined {
|
|
226
|
+
return this.delayer_;
|
|
227
|
+
}
|
|
228
|
+
|
|
222
229
|
get validatorAddresses(): EthAddress[] | undefined {
|
|
223
230
|
return this.sequencer.getValidatorAddresses();
|
|
224
231
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type L1ReaderConfig,
|
|
4
|
-
l1ContractsConfigMappings,
|
|
5
|
-
l1ReaderConfigMappings,
|
|
6
|
-
} from '@aztec/ethereum';
|
|
1
|
+
import { type L1ContractsConfig, l1ContractsConfigMappings } from '@aztec/ethereum/config';
|
|
2
|
+
import { type L1ReaderConfig, l1ReaderConfigMappings } from '@aztec/ethereum/l1-reader';
|
|
7
3
|
import {
|
|
8
4
|
type ConfigMappingsType,
|
|
9
5
|
booleanConfigHelper,
|
|
@@ -12,31 +8,63 @@ import {
|
|
|
12
8
|
pickConfigMappings,
|
|
13
9
|
} from '@aztec/foundation/config';
|
|
14
10
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
15
|
-
import { type KeyStoreConfig, keyStoreConfigMappings } from '@aztec/node-keystore';
|
|
16
|
-
import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p';
|
|
11
|
+
import { type KeyStoreConfig, keyStoreConfigMappings } from '@aztec/node-keystore/config';
|
|
12
|
+
import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
|
|
17
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
18
|
-
import {
|
|
19
|
-
|
|
14
|
+
import {
|
|
15
|
+
type ChainConfig,
|
|
16
|
+
type SequencerConfig,
|
|
17
|
+
chainConfigMappings,
|
|
18
|
+
sharedSequencerConfigMappings,
|
|
19
|
+
} from '@aztec/stdlib/config';
|
|
20
|
+
import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
|
|
21
|
+
import { DEFAULT_P2P_PROPAGATION_TIME } from '@aztec/stdlib/timetable';
|
|
22
|
+
import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client/config';
|
|
20
23
|
|
|
21
24
|
import {
|
|
22
|
-
type
|
|
23
|
-
type
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
type SequencerPublisherConfig,
|
|
26
|
+
type SequencerTxSenderConfig,
|
|
27
|
+
sequencerPublisherConfigMappings,
|
|
28
|
+
sequencerTxSenderConfigMappings,
|
|
26
29
|
} from './publisher/config.js';
|
|
27
30
|
|
|
28
31
|
export * from './publisher/config.js';
|
|
29
32
|
export type { SequencerConfig };
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Default values for SequencerConfig.
|
|
36
|
+
* Centralized location for all sequencer configuration defaults.
|
|
37
|
+
*/
|
|
38
|
+
export const DefaultSequencerConfig: ResolvedSequencerConfig = {
|
|
39
|
+
sequencerPollingIntervalMS: 500,
|
|
40
|
+
maxTxsPerBlock: 32,
|
|
41
|
+
minTxsPerBlock: 1,
|
|
42
|
+
buildCheckpointIfEmpty: false,
|
|
43
|
+
publishTxsWithProposals: false,
|
|
44
|
+
maxL2BlockGas: 10e9,
|
|
45
|
+
maxDABlockGas: 10e9,
|
|
46
|
+
maxBlockSizeInBytes: 1024 * 1024,
|
|
47
|
+
enforceTimeTable: true,
|
|
48
|
+
attestationPropagationTime: DEFAULT_P2P_PROPAGATION_TIME,
|
|
49
|
+
secondsBeforeInvalidatingBlockAsCommitteeMember: 144, // 12 L1 blocks
|
|
50
|
+
secondsBeforeInvalidatingBlockAsNonCommitteeMember: 432, // 36 L1 blocks
|
|
51
|
+
skipCollectingAttestations: false,
|
|
52
|
+
skipInvalidateBlockAsProposer: false,
|
|
53
|
+
broadcastInvalidBlockProposal: false,
|
|
54
|
+
injectFakeAttestation: false,
|
|
55
|
+
fishermanMode: false,
|
|
56
|
+
shuffleAttestationOrdering: false,
|
|
57
|
+
skipPushProposedBlocksToArchiver: false,
|
|
58
|
+
skipPublishingCheckpointsPercent: 0,
|
|
59
|
+
};
|
|
32
60
|
|
|
33
61
|
/**
|
|
34
62
|
* Configuration settings for the SequencerClient.
|
|
35
63
|
*/
|
|
36
|
-
export type SequencerClientConfig =
|
|
64
|
+
export type SequencerClientConfig = SequencerPublisherConfig &
|
|
37
65
|
KeyStoreConfig &
|
|
38
66
|
ValidatorClientConfig &
|
|
39
|
-
|
|
67
|
+
SequencerTxSenderConfig &
|
|
40
68
|
SequencerConfig &
|
|
41
69
|
L1ReaderConfig &
|
|
42
70
|
ChainConfig &
|
|
@@ -44,35 +72,39 @@ export type SequencerClientConfig = PublisherConfig &
|
|
|
44
72
|
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
|
|
45
73
|
|
|
46
74
|
export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
47
|
-
|
|
48
|
-
env: '
|
|
49
|
-
description: 'The number of ms to wait between polling for
|
|
50
|
-
...numberConfigHelper(
|
|
75
|
+
sequencerPollingIntervalMS: {
|
|
76
|
+
env: 'SEQ_POLLING_INTERVAL_MS',
|
|
77
|
+
description: 'The number of ms to wait between polling for checking to build on the next slot.',
|
|
78
|
+
...numberConfigHelper(DefaultSequencerConfig.sequencerPollingIntervalMS),
|
|
51
79
|
},
|
|
52
80
|
maxTxsPerBlock: {
|
|
53
81
|
env: 'SEQ_MAX_TX_PER_BLOCK',
|
|
54
82
|
description: 'The maximum number of txs to include in a block.',
|
|
55
|
-
...numberConfigHelper(
|
|
83
|
+
...numberConfigHelper(DefaultSequencerConfig.maxTxsPerBlock),
|
|
56
84
|
},
|
|
57
85
|
minTxsPerBlock: {
|
|
58
86
|
env: 'SEQ_MIN_TX_PER_BLOCK',
|
|
59
87
|
description: 'The minimum number of txs to include in a block.',
|
|
60
|
-
...numberConfigHelper(
|
|
88
|
+
...numberConfigHelper(DefaultSequencerConfig.minTxsPerBlock),
|
|
89
|
+
},
|
|
90
|
+
minValidTxsPerBlock: {
|
|
91
|
+
description:
|
|
92
|
+
'The minimum number of valid txs (after execution) to include in a block. If not set, falls back to minTxsPerBlock.',
|
|
61
93
|
},
|
|
62
94
|
publishTxsWithProposals: {
|
|
63
95
|
env: 'SEQ_PUBLISH_TXS_WITH_PROPOSALS',
|
|
64
96
|
description: 'Whether to publish txs with proposals.',
|
|
65
|
-
...booleanConfigHelper(
|
|
97
|
+
...booleanConfigHelper(DefaultSequencerConfig.publishTxsWithProposals),
|
|
66
98
|
},
|
|
67
99
|
maxL2BlockGas: {
|
|
68
100
|
env: 'SEQ_MAX_L2_BLOCK_GAS',
|
|
69
101
|
description: 'The maximum L2 block gas.',
|
|
70
|
-
...numberConfigHelper(
|
|
102
|
+
...numberConfigHelper(DefaultSequencerConfig.maxL2BlockGas),
|
|
71
103
|
},
|
|
72
104
|
maxDABlockGas: {
|
|
73
105
|
env: 'SEQ_MAX_DA_BLOCK_GAS',
|
|
74
106
|
description: 'The maximum DA block gas.',
|
|
75
|
-
...numberConfigHelper(
|
|
107
|
+
...numberConfigHelper(DefaultSequencerConfig.maxDABlockGas),
|
|
76
108
|
},
|
|
77
109
|
coinbase: {
|
|
78
110
|
env: 'COINBASE',
|
|
@@ -95,73 +127,92 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
95
127
|
maxBlockSizeInBytes: {
|
|
96
128
|
env: 'SEQ_MAX_BLOCK_SIZE_IN_BYTES',
|
|
97
129
|
description: 'Max block size',
|
|
98
|
-
...numberConfigHelper(
|
|
130
|
+
...numberConfigHelper(DefaultSequencerConfig.maxBlockSizeInBytes),
|
|
99
131
|
},
|
|
100
132
|
enforceTimeTable: {
|
|
101
133
|
env: 'SEQ_ENFORCE_TIME_TABLE',
|
|
102
134
|
description: 'Whether to enforce the time table when building blocks',
|
|
103
|
-
...booleanConfigHelper(),
|
|
104
|
-
defaultValue: true,
|
|
135
|
+
...booleanConfigHelper(DefaultSequencerConfig.enforceTimeTable),
|
|
105
136
|
},
|
|
106
137
|
governanceProposerPayload: {
|
|
107
138
|
env: 'GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS',
|
|
108
139
|
description: 'The address of the payload for the governanceProposer',
|
|
109
140
|
parseEnv: (val: string) => EthAddress.fromString(val),
|
|
110
|
-
defaultValue: EthAddress.ZERO,
|
|
111
141
|
},
|
|
112
|
-
|
|
113
|
-
env: '
|
|
114
|
-
description: 'How
|
|
142
|
+
l1PublishingTime: {
|
|
143
|
+
env: 'SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT',
|
|
144
|
+
description: 'How much time (in seconds) we allow in the slot for publishing the L1 tx (defaults to 1 L1 slot).',
|
|
115
145
|
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
116
146
|
},
|
|
117
147
|
attestationPropagationTime: {
|
|
118
148
|
env: 'SEQ_ATTESTATION_PROPAGATION_TIME',
|
|
119
149
|
description: 'How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way)',
|
|
120
|
-
...numberConfigHelper(
|
|
150
|
+
...numberConfigHelper(DefaultSequencerConfig.attestationPropagationTime),
|
|
121
151
|
},
|
|
122
152
|
fakeProcessingDelayPerTxMs: {
|
|
123
153
|
description: 'Used for testing to introduce a fake delay after processing each tx',
|
|
124
154
|
},
|
|
155
|
+
fakeThrowAfterProcessingTxCount: {
|
|
156
|
+
description: 'Used for testing to throw an error after processing N txs',
|
|
157
|
+
},
|
|
125
158
|
secondsBeforeInvalidatingBlockAsCommitteeMember: {
|
|
126
159
|
env: 'SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_COMMITTEE_MEMBER',
|
|
127
160
|
description:
|
|
128
161
|
'How many seconds to wait before trying to invalidate a block from the pending chain as a committee member (zero to never invalidate).' +
|
|
129
162
|
' The next proposer is expected to invalidate, so the committee acts as a fallback.',
|
|
130
|
-
...numberConfigHelper(
|
|
163
|
+
...numberConfigHelper(DefaultSequencerConfig.secondsBeforeInvalidatingBlockAsCommitteeMember),
|
|
131
164
|
},
|
|
132
165
|
secondsBeforeInvalidatingBlockAsNonCommitteeMember: {
|
|
133
166
|
env: 'SEQ_SECONDS_BEFORE_INVALIDATING_BLOCK_AS_NON_COMMITTEE_MEMBER',
|
|
134
167
|
description:
|
|
135
168
|
'How many seconds to wait before trying to invalidate a block from the pending chain as a non-committee member (zero to never invalidate).' +
|
|
136
169
|
' The next proposer is expected to invalidate, then the committee, so other sequencers act as a fallback.',
|
|
137
|
-
...numberConfigHelper(
|
|
170
|
+
...numberConfigHelper(DefaultSequencerConfig.secondsBeforeInvalidatingBlockAsNonCommitteeMember),
|
|
138
171
|
},
|
|
139
172
|
skipCollectingAttestations: {
|
|
140
173
|
description:
|
|
141
174
|
'Whether to skip collecting attestations from validators and only use self-attestations (for testing only)',
|
|
142
|
-
...booleanConfigHelper(
|
|
175
|
+
...booleanConfigHelper(DefaultSequencerConfig.skipCollectingAttestations),
|
|
143
176
|
},
|
|
144
177
|
skipInvalidateBlockAsProposer: {
|
|
145
178
|
description: 'Do not invalidate the previous block if invalid when we are the proposer (for testing only)',
|
|
146
|
-
...booleanConfigHelper(
|
|
179
|
+
...booleanConfigHelper(DefaultSequencerConfig.skipInvalidateBlockAsProposer),
|
|
147
180
|
},
|
|
148
181
|
broadcastInvalidBlockProposal: {
|
|
149
182
|
description: 'Broadcast invalid block proposals with corrupted state (for testing only)',
|
|
150
|
-
...booleanConfigHelper(
|
|
183
|
+
...booleanConfigHelper(DefaultSequencerConfig.broadcastInvalidBlockProposal),
|
|
151
184
|
},
|
|
152
185
|
injectFakeAttestation: {
|
|
153
186
|
description: 'Inject a fake attestation (for testing only)',
|
|
154
|
-
...booleanConfigHelper(
|
|
187
|
+
...booleanConfigHelper(DefaultSequencerConfig.injectFakeAttestation),
|
|
155
188
|
},
|
|
156
189
|
fishermanMode: {
|
|
157
190
|
env: 'FISHERMAN_MODE',
|
|
158
191
|
description:
|
|
159
192
|
'Whether to run in fisherman mode: builds blocks on every slot for validation without publishing to L1',
|
|
160
|
-
...booleanConfigHelper(
|
|
193
|
+
...booleanConfigHelper(DefaultSequencerConfig.fishermanMode),
|
|
161
194
|
},
|
|
162
195
|
shuffleAttestationOrdering: {
|
|
163
196
|
description: 'Shuffle attestation ordering to create invalid ordering (for testing only)',
|
|
164
|
-
...booleanConfigHelper(
|
|
197
|
+
...booleanConfigHelper(DefaultSequencerConfig.shuffleAttestationOrdering),
|
|
198
|
+
},
|
|
199
|
+
...sharedSequencerConfigMappings,
|
|
200
|
+
buildCheckpointIfEmpty: {
|
|
201
|
+
env: 'SEQ_BUILD_CHECKPOINT_IF_EMPTY',
|
|
202
|
+
description: 'Have sequencer build and publish an empty checkpoint if there are no txs',
|
|
203
|
+
...booleanConfigHelper(DefaultSequencerConfig.buildCheckpointIfEmpty),
|
|
204
|
+
},
|
|
205
|
+
skipPushProposedBlocksToArchiver: {
|
|
206
|
+
description: 'Skip pushing proposed blocks to archiver (default: true)',
|
|
207
|
+
...booleanConfigHelper(DefaultSequencerConfig.skipPushProposedBlocksToArchiver),
|
|
208
|
+
},
|
|
209
|
+
minBlocksForCheckpoint: {
|
|
210
|
+
description: 'Minimum number of blocks required for a checkpoint proposal (test only)',
|
|
211
|
+
},
|
|
212
|
+
skipPublishingCheckpointsPercent: {
|
|
213
|
+
env: 'SEQ_SKIP_CHECKPOINT_PUBLISH_PERCENT',
|
|
214
|
+
description: 'Percent probability (0 - 100) of sequencer skipping checkpoint publishing (testing only)',
|
|
215
|
+
...numberConfigHelper(DefaultSequencerConfig.skipPublishingCheckpointsPercent),
|
|
165
216
|
},
|
|
166
217
|
...pickConfigMappings(p2pConfigMappings, ['txPublicSetupAllowList']),
|
|
167
218
|
};
|
|
@@ -171,8 +222,8 @@ export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientCo
|
|
|
171
222
|
...sequencerConfigMappings,
|
|
172
223
|
...keyStoreConfigMappings,
|
|
173
224
|
...l1ReaderConfigMappings,
|
|
174
|
-
...
|
|
175
|
-
...
|
|
225
|
+
...sequencerTxSenderConfigMappings,
|
|
226
|
+
...sequencerPublisherConfigMappings,
|
|
176
227
|
...chainConfigMappings,
|
|
177
228
|
...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration', 'aztecSlotDuration', 'aztecEpochDuration']),
|
|
178
229
|
};
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from '@aztec/
|
|
8
|
-
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
+
import type { L1ContractsConfig } from '@aztec/ethereum/config';
|
|
3
|
+
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
4
|
+
import type { L1ReaderConfig } from '@aztec/ethereum/l1-reader';
|
|
5
|
+
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
6
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
7
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
9
8
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
10
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
11
9
|
import { createLogger } from '@aztec/foundation/log';
|
|
12
10
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
|
+
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
12
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
14
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
CheckpointGlobalVariables,
|
|
15
|
+
GlobalVariableBuilder as GlobalVariableBuilderInterface,
|
|
16
|
+
} from '@aztec/stdlib/tx';
|
|
15
17
|
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
16
18
|
|
|
17
19
|
import { createPublicClient, fallback, http } from 'viem';
|
|
@@ -21,26 +23,37 @@ import { createPublicClient, fallback, http } from 'viem';
|
|
|
21
23
|
*/
|
|
22
24
|
export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
23
25
|
private log = createLogger('sequencer:global_variable_builder');
|
|
24
|
-
private
|
|
26
|
+
private currentMinFees: Promise<GasFees> = Promise.resolve(new GasFees(0, 0));
|
|
25
27
|
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
26
28
|
|
|
27
29
|
private readonly rollupContract: RollupContract;
|
|
28
30
|
private readonly publicClient: ViemPublicClient;
|
|
29
31
|
private readonly ethereumSlotDuration: number;
|
|
32
|
+
private readonly aztecSlotDuration: number;
|
|
33
|
+
private readonly l1GenesisTime: bigint;
|
|
30
34
|
|
|
31
|
-
private chainId
|
|
32
|
-
private version
|
|
35
|
+
private chainId: Fr;
|
|
36
|
+
private version: Fr;
|
|
33
37
|
|
|
34
|
-
constructor(
|
|
38
|
+
constructor(
|
|
39
|
+
config: L1ReaderConfig &
|
|
40
|
+
Pick<L1ContractsConfig, 'ethereumSlotDuration'> &
|
|
41
|
+
Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'> & { rollupVersion: bigint },
|
|
42
|
+
) {
|
|
35
43
|
const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
|
|
36
44
|
|
|
37
45
|
const chain = createEthereumChain(l1RpcUrls, chainId);
|
|
38
46
|
|
|
47
|
+
this.version = new Fr(config.rollupVersion);
|
|
48
|
+
this.chainId = new Fr(chainId);
|
|
49
|
+
|
|
39
50
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
51
|
+
this.aztecSlotDuration = config.slotDuration;
|
|
52
|
+
this.l1GenesisTime = config.l1GenesisTime;
|
|
40
53
|
|
|
41
54
|
this.publicClient = createPublicClient({
|
|
42
55
|
chain: chain.chainInfo,
|
|
43
|
-
transport: fallback(chain.rpcUrls.map(url => http(url))),
|
|
56
|
+
transport: fallback(chain.rpcUrls.map(url => http(url, { batch: false }))),
|
|
44
57
|
pollingInterval: config.viemPollingIntervalMS,
|
|
45
58
|
});
|
|
46
59
|
|
|
@@ -48,48 +61,38 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
/**
|
|
51
|
-
* Computes the "current"
|
|
52
|
-
* @returns
|
|
64
|
+
* Computes the "current" min fees, e.g., the price that you currently should pay to get include in the next block
|
|
65
|
+
* @returns Min fees for the next block
|
|
53
66
|
*/
|
|
54
|
-
private async
|
|
67
|
+
private async computeCurrentMinFees(): Promise<GasFees> {
|
|
55
68
|
// Since this might be called in the middle of a slot where a block might have been published,
|
|
56
69
|
// we need to fetch the last block written, and estimate the earliest timestamp for the next block.
|
|
57
70
|
// The timestamp of that last block will act as a lower bound for the next block.
|
|
58
71
|
|
|
59
|
-
const
|
|
72
|
+
const lastCheckpoint = await this.rollupContract.getPendingCheckpoint();
|
|
60
73
|
const earliestTimestamp = await this.rollupContract.getTimestampForSlot(
|
|
61
|
-
SlotNumber.fromBigInt(
|
|
74
|
+
SlotNumber.fromBigInt(BigInt(lastCheckpoint.slotNumber) + 1n),
|
|
62
75
|
);
|
|
63
76
|
const nextEthTimestamp = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration));
|
|
64
77
|
const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
|
|
65
78
|
|
|
66
|
-
return new GasFees(0, await this.rollupContract.
|
|
79
|
+
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
67
80
|
}
|
|
68
81
|
|
|
69
|
-
public async
|
|
82
|
+
public async getCurrentMinFees(): Promise<GasFees> {
|
|
70
83
|
// Get the current block number
|
|
71
84
|
const blockNumber = await this.publicClient.getBlockNumber();
|
|
72
85
|
|
|
73
|
-
// If the L1 block number has changed then chain a new promise to get the current
|
|
86
|
+
// If the L1 block number has changed then chain a new promise to get the current min fees
|
|
74
87
|
if (this.currentL1BlockNumber === undefined || blockNumber > this.currentL1BlockNumber) {
|
|
75
88
|
this.currentL1BlockNumber = blockNumber;
|
|
76
|
-
this.
|
|
77
|
-
}
|
|
78
|
-
return this.currentBaseFees;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
public async getGlobalConstantVariables(): Promise<Pick<GlobalVariables, 'chainId' | 'version'>> {
|
|
82
|
-
if (!this.chainId) {
|
|
83
|
-
this.chainId = new Fr(this.publicClient.chain.id);
|
|
84
|
-
}
|
|
85
|
-
if (!this.version) {
|
|
86
|
-
this.version = new Fr(await this.rollupContract.getVersion());
|
|
89
|
+
this.currentMinFees = this.currentMinFees.then(() => this.computeCurrentMinFees());
|
|
87
90
|
}
|
|
88
|
-
return
|
|
91
|
+
return this.currentMinFees;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/**
|
|
92
|
-
* Simple builder of global variables
|
|
95
|
+
* Simple builder of global variables.
|
|
93
96
|
* @param blockNumber - The block number to build global variables for.
|
|
94
97
|
* @param coinbase - The address to receive block reward.
|
|
95
98
|
* @param feeRecipient - The address to receive fees.
|
|
@@ -97,37 +100,38 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
97
100
|
* @returns The global variables for the given block number.
|
|
98
101
|
*/
|
|
99
102
|
public async buildGlobalVariables(
|
|
100
|
-
blockNumber:
|
|
103
|
+
blockNumber: BlockNumber,
|
|
101
104
|
coinbase: EthAddress,
|
|
102
105
|
feeRecipient: AztecAddress,
|
|
103
|
-
|
|
106
|
+
maybeSlot?: SlotNumber,
|
|
104
107
|
): Promise<GlobalVariables> {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
const slot: SlotNumber =
|
|
109
|
+
maybeSlot ??
|
|
110
|
+
(await this.rollupContract.getSlotAt(
|
|
111
|
+
BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration)),
|
|
112
|
+
));
|
|
113
|
+
|
|
114
|
+
const checkpointGlobalVariables = await this.buildCheckpointGlobalVariables(coinbase, feeRecipient, slot);
|
|
115
|
+
return GlobalVariables.from({ blockNumber, ...checkpointGlobalVariables });
|
|
116
|
+
}
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
/** Builds global variables that are constant throughout a checkpoint. */
|
|
119
|
+
public async buildCheckpointGlobalVariables(
|
|
120
|
+
coinbase: EthAddress,
|
|
121
|
+
feeRecipient: AztecAddress,
|
|
122
|
+
slotNumber: SlotNumber,
|
|
123
|
+
): Promise<CheckpointGlobalVariables> {
|
|
124
|
+
const { chainId, version } = this;
|
|
116
125
|
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
const timestamp = getTimestampForSlot(slotNumber, {
|
|
127
|
+
slotDuration: this.aztecSlotDuration,
|
|
128
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
129
|
+
});
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
blockNumber,
|
|
124
|
-
slot,
|
|
125
|
-
timestamp,
|
|
126
|
-
coinbase,
|
|
127
|
-
feeRecipient,
|
|
128
|
-
gasFees,
|
|
129
|
-
);
|
|
131
|
+
// We can skip much of the logic in getCurrentMinFees since it we already check that we are not within a slot elsewhere.
|
|
132
|
+
// TODO(palla/mbps): Can we use a cached value here?
|
|
133
|
+
const gasFees = new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
130
134
|
|
|
131
|
-
return
|
|
135
|
+
return { chainId, version, slotNumber, timestamp, coinbase, feeRecipient, gasFees };
|
|
132
136
|
}
|
|
133
137
|
}
|