@aztec/sequencer-client 0.72.1 → 0.74.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.
Files changed (70) hide show
  1. package/dest/client/sequencer-client.d.ts +11 -6
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +46 -10
  4. package/dest/config.d.ts +1 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +3 -4
  7. package/dest/publisher/config.d.ts +5 -0
  8. package/dest/publisher/config.d.ts.map +1 -1
  9. package/dest/publisher/config.js +9 -2
  10. package/dest/publisher/index.d.ts +1 -1
  11. package/dest/publisher/index.d.ts.map +1 -1
  12. package/dest/publisher/index.js +2 -2
  13. package/dest/publisher/{l1-publisher-metrics.d.ts → sequencer-publisher-metrics.d.ts} +6 -2
  14. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -0
  15. package/dest/publisher/sequencer-publisher-metrics.js +111 -0
  16. package/dest/publisher/sequencer-publisher.d.ts +163 -0
  17. package/dest/publisher/sequencer-publisher.d.ts.map +1 -0
  18. package/dest/publisher/sequencer-publisher.js +528 -0
  19. package/dest/sequencer/allowed.d.ts +1 -1
  20. package/dest/sequencer/allowed.d.ts.map +1 -1
  21. package/dest/sequencer/allowed.js +4 -4
  22. package/dest/sequencer/metrics.d.ts +1 -1
  23. package/dest/sequencer/metrics.d.ts.map +1 -1
  24. package/dest/sequencer/metrics.js +3 -4
  25. package/dest/sequencer/sequencer.d.ts +17 -10
  26. package/dest/sequencer/sequencer.d.ts.map +1 -1
  27. package/dest/sequencer/sequencer.js +103 -109
  28. package/dest/sequencer/utils.d.ts +1 -1
  29. package/dest/sequencer/utils.d.ts.map +1 -1
  30. package/dest/sequencer/utils.js +3 -3
  31. package/dest/slasher/factory.d.ts +2 -2
  32. package/dest/slasher/factory.d.ts.map +1 -1
  33. package/dest/slasher/factory.js +2 -2
  34. package/dest/slasher/slasher_client.d.ts +4 -4
  35. package/dest/slasher/slasher_client.d.ts.map +1 -1
  36. package/dest/slasher/slasher_client.js +38 -26
  37. package/dest/test/index.d.ts +3 -3
  38. package/dest/test/index.d.ts.map +1 -1
  39. package/dest/test/index.js +1 -2
  40. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  41. package/dest/tx_validator/gas_validator.js +4 -3
  42. package/dest/tx_validator/test_utils.d.ts +4 -4
  43. package/dest/tx_validator/test_utils.d.ts.map +1 -1
  44. package/dest/tx_validator/test_utils.js +3 -3
  45. package/package.json +21 -20
  46. package/src/client/sequencer-client.ts +81 -14
  47. package/src/config.ts +3 -3
  48. package/src/publisher/config.ts +13 -1
  49. package/src/publisher/index.ts +1 -1
  50. package/src/publisher/{l1-publisher-metrics.ts → sequencer-publisher-metrics.ts} +41 -2
  51. package/src/publisher/sequencer-publisher.ts +710 -0
  52. package/src/sequencer/allowed.ts +3 -3
  53. package/src/sequencer/metrics.ts +2 -3
  54. package/src/sequencer/sequencer.ts +138 -125
  55. package/src/sequencer/utils.ts +5 -2
  56. package/src/slasher/factory.ts +3 -3
  57. package/src/slasher/slasher_client.ts +44 -30
  58. package/src/test/index.ts +2 -4
  59. package/src/tx_validator/gas_validator.ts +5 -4
  60. package/src/tx_validator/test_utils.ts +5 -5
  61. package/dest/publisher/l1-publisher-metrics.d.ts.map +0 -1
  62. package/dest/publisher/l1-publisher-metrics.js +0 -85
  63. package/dest/publisher/l1-publisher.d.ts +0 -195
  64. package/dest/publisher/l1-publisher.d.ts.map +0 -1
  65. package/dest/publisher/l1-publisher.js +0 -930
  66. package/dest/test/test-l1-publisher.d.ts +0 -9
  67. package/dest/test/test-l1-publisher.d.ts.map +0 -1
  68. package/dest/test/test-l1-publisher.js +0 -11
  69. package/src/publisher/l1-publisher.ts +0 -1288
  70. package/src/test/test-l1-publisher.ts +0 -20
@@ -1,8 +1,19 @@
1
1
  import { type BlobSinkClientInterface } from '@aztec/blob-sink/client';
2
2
  import { type L1ToL2MessageSource, type L2BlockSource, type WorldStateSynchronizer } from '@aztec/circuit-types';
3
- import { type ContractDataSource } from '@aztec/circuits.js';
4
- import { isAnvilTestChain } from '@aztec/ethereum';
5
- import { type EthAddress } from '@aztec/foundation/eth-address';
3
+ import { type AztecAddress, type ContractDataSource } from '@aztec/circuits.js';
4
+ import { EpochCache } from '@aztec/epoch-cache';
5
+ import {
6
+ ForwarderContract,
7
+ GovernanceProposerContract,
8
+ L1TxUtilsWithBlobs,
9
+ RollupContract,
10
+ SlashingProposerContract,
11
+ createEthereumChain,
12
+ createL1Clients,
13
+ isAnvilTestChain,
14
+ } from '@aztec/ethereum';
15
+ import { EthAddress } from '@aztec/foundation/eth-address';
16
+ import { createLogger } from '@aztec/foundation/log';
6
17
  import { type DateProvider } from '@aztec/foundation/timer';
7
18
  import { type P2P } from '@aztec/p2p';
8
19
  import { LightweightBlockBuilderFactory } from '@aztec/prover-client/block-builder';
@@ -12,7 +23,7 @@ import { type ValidatorClient } from '@aztec/validator-client';
12
23
 
13
24
  import { type SequencerClientConfig } from '../config.js';
14
25
  import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
15
- import { L1Publisher } from '../publisher/index.js';
26
+ import { SequencerPublisher } from '../publisher/index.js';
16
27
  import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
17
28
  import { type SlasherClient } from '../slasher/index.js';
18
29
 
@@ -46,9 +57,11 @@ export class SequencerClient {
46
57
  l2BlockSource: L2BlockSource;
47
58
  l1ToL2MessageSource: L1ToL2MessageSource;
48
59
  telemetry: TelemetryClient;
49
- publisher?: L1Publisher;
60
+ publisher?: SequencerPublisher;
50
61
  blobSinkClient?: BlobSinkClientInterface;
51
62
  dateProvider: DateProvider;
63
+ epochCache?: EpochCache;
64
+ l1TxUtils?: L1TxUtilsWithBlobs;
52
65
  },
53
66
  ) {
54
67
  const {
@@ -61,18 +74,68 @@ export class SequencerClient {
61
74
  l1ToL2MessageSource,
62
75
  telemetry: telemetryClient,
63
76
  } = deps;
77
+ const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey } = config;
78
+ const chain = createEthereumChain(rpcUrl, chainId);
79
+ const log = createLogger('sequencer-client');
80
+ const { publicClient, walletClient } = createL1Clients(rpcUrl, publisherPrivateKey, chain.chainInfo);
81
+ const l1TxUtils = deps.l1TxUtils ?? new L1TxUtilsWithBlobs(publicClient, walletClient, log, config);
82
+ const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
83
+ const [l1GenesisTime, slotDuration] = await Promise.all([
84
+ rollupContract.getL1GenesisTime(),
85
+ rollupContract.getSlotDuration(),
86
+ ] as const);
87
+ const forwarderContract =
88
+ config.customForwarderContractAddress && config.customForwarderContractAddress !== EthAddress.ZERO
89
+ ? new ForwarderContract(
90
+ publicClient,
91
+ config.customForwarderContractAddress.toString(),
92
+ config.l1Contracts.rollupAddress.toString(),
93
+ )
94
+ : await ForwarderContract.create(
95
+ walletClient.account.address,
96
+ walletClient,
97
+ publicClient,
98
+ log,
99
+ config.l1Contracts.rollupAddress.toString(),
100
+ );
101
+
102
+ const governanceProposerContract = new GovernanceProposerContract(
103
+ publicClient,
104
+ config.l1Contracts.governanceProposerAddress.toString(),
105
+ );
106
+ const slashingProposerAddress = await rollupContract.getSlashingProposerAddress();
107
+ const slashingProposerContract = new SlashingProposerContract(publicClient, slashingProposerAddress.toString());
108
+ const epochCache =
109
+ deps.epochCache ??
110
+ (await EpochCache.create(
111
+ config.l1Contracts.rollupAddress,
112
+ {
113
+ l1RpcUrl: rpcUrl,
114
+ l1ChainId: chainId,
115
+ viemPollingIntervalMS: config.viemPollingIntervalMS,
116
+ aztecSlotDuration: config.aztecSlotDuration,
117
+ ethereumSlotDuration: config.ethereumSlotDuration,
118
+ aztecEpochDuration: config.aztecEpochDuration,
119
+ },
120
+ { dateProvider: deps.dateProvider },
121
+ ));
122
+
64
123
  const publisher =
65
- deps.publisher ?? new L1Publisher(config, { telemetry: telemetryClient, blobSinkClient: deps.blobSinkClient });
124
+ deps.publisher ??
125
+ new SequencerPublisher(config, {
126
+ l1TxUtils,
127
+ telemetry: telemetryClient,
128
+ blobSinkClient: deps.blobSinkClient,
129
+ rollupContract,
130
+ epochCache,
131
+ forwarderContract,
132
+ governanceProposerContract,
133
+ slashingProposerContract,
134
+ });
66
135
  const globalsBuilder = new GlobalVariableBuilder(config);
67
136
 
68
137
  const publicProcessorFactory = new PublicProcessorFactory(contractDataSource, deps.dateProvider, telemetryClient);
69
138
 
70
- const rollup = publisher.getRollupContract();
71
- const [l1GenesisTime, slotDuration] = await Promise.all([
72
- rollup.read.GENESIS_TIME(),
73
- rollup.read.SLOT_DURATION(),
74
- ] as const);
75
-
76
139
  const ethereumSlotDuration = config.ethereumSlotDuration;
77
140
 
78
141
  // When running in anvil, assume we can post a tx up until the very last second of an L1 slot.
@@ -117,7 +180,7 @@ export class SequencerClient {
117
180
  * @param config - New parameters.
118
181
  */
119
182
  public updateSequencerConfig(config: SequencerConfig) {
120
- this.sequencer.updateConfig(config);
183
+ return this.sequencer.updateConfig(config);
121
184
  }
122
185
 
123
186
  /**
@@ -143,7 +206,11 @@ export class SequencerClient {
143
206
  return this.sequencer.coinbase;
144
207
  }
145
208
 
146
- get feeRecipient() {
209
+ get feeRecipient(): AztecAddress {
147
210
  return this.sequencer.feeRecipient;
148
211
  }
212
+
213
+ get forwarderAddress(): EthAddress {
214
+ return this.sequencer.getForwarderAddress();
215
+ }
149
216
  }
package/src/config.ts CHANGED
@@ -11,8 +11,8 @@ import {
11
11
  booleanConfigHelper,
12
12
  getConfigFromMappings,
13
13
  numberConfigHelper,
14
+ pickConfigMappings,
14
15
  } from '@aztec/foundation/config';
15
- import { pickConfigMappings } from '@aztec/foundation/config';
16
16
  import { EthAddress } from '@aztec/foundation/eth-address';
17
17
 
18
18
  import {
@@ -41,7 +41,7 @@ export type SequencerClientConfig = PublisherConfig &
41
41
  SequencerConfig &
42
42
  L1ReaderConfig &
43
43
  ChainConfig &
44
- Pick<L1ContractsConfig, 'ethereumSlotDuration'>;
44
+ Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
45
45
 
46
46
  export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
47
47
  transactionPollingIntervalMS: {
@@ -138,7 +138,7 @@ export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientCo
138
138
  ...getTxSenderConfigMappings('SEQ'),
139
139
  ...getPublisherConfigMappings('SEQ'),
140
140
  ...chainConfigMappings,
141
- ...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration']),
141
+ ...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration', 'aztecSlotDuration', 'aztecEpochDuration']),
142
142
  };
143
143
 
144
144
  /**
@@ -1,5 +1,6 @@
1
1
  import { type L1ReaderConfig, type L1TxUtilsConfig, NULL_KEY, l1TxUtilsConfigMappings } from '@aztec/ethereum';
2
2
  import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
3
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
4
 
4
5
  /**
5
6
  * The configuration of the rollup transaction publisher.
@@ -14,6 +15,11 @@ export type TxSenderConfig = L1ReaderConfig & {
14
15
  * The number of confirmations required.
15
16
  */
16
17
  requiredConfirmations: number;
18
+
19
+ /**
20
+ * The address of the custom forwarder contract.
21
+ */
22
+ customForwarderContractAddress: EthAddress;
17
23
  };
18
24
 
19
25
  /**
@@ -44,6 +50,12 @@ export const getTxSenderConfigMappings: (
44
50
  defaultValue: 31337,
45
51
  description: 'The chain ID of the ethereum host.',
46
52
  },
53
+ customForwarderContractAddress: {
54
+ env: `CUSTOM_FORWARDER_CONTRACT_ADDRESS`,
55
+ parseEnv: (val: string) => EthAddress.fromString(val),
56
+ description: 'The address of the custom forwarder contract.',
57
+ defaultValue: EthAddress.ZERO,
58
+ },
47
59
  publisherPrivateKey: {
48
60
  env: `${scope}_PUBLISHER_PRIVATE_KEY`,
49
61
  description: 'The private key to be used by the publisher.',
@@ -78,7 +90,7 @@ export const getPublisherConfigMappings: (
78
90
  },
79
91
  ...l1TxUtilsConfigMappings,
80
92
  blobSinkUrl: {
81
- env: `${scope}_BLOB_SINK_URL`,
93
+ env: 'BLOB_SINK_URL',
82
94
  description: 'The URL of the blob sink.',
83
95
  parseEnv: (val?: string) => val,
84
96
  },
@@ -1 +1 @@
1
- export { L1Publisher, L1SubmitEpochProofArgs } from './l1-publisher.js';
1
+ export { SequencerPublisher } from './sequencer-publisher.js';
@@ -12,7 +12,7 @@ import { formatEther } from 'viem/utils';
12
12
 
13
13
  export type L1TxType = 'submitProof' | 'process' | 'claimEpochProofRight';
14
14
 
15
- export class L1PublisherMetrics {
15
+ export class SequencerPublisherMetrics {
16
16
  private gasPrice: Histogram;
17
17
 
18
18
  private txCount: UpDownCounter;
@@ -23,7 +23,12 @@ export class L1PublisherMetrics {
23
23
  private txBlobDataGasUsed: Histogram;
24
24
  private txBlobDataGasCost: Histogram;
25
25
 
26
- constructor(client: TelemetryClient, name = 'L1Publisher') {
26
+ private readonly blobCountHistogram: Histogram;
27
+ private readonly blobInclusionBlocksHistogram: Histogram;
28
+ private readonly blobTxSuccessCounter: UpDownCounter;
29
+ private readonly blobTxFailureCounter: UpDownCounter;
30
+
31
+ constructor(client: TelemetryClient, name = 'SequencerPublisher') {
27
32
  const meter = client.getMeter(name);
28
33
 
29
34
  this.gasPrice = meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE, {
@@ -71,6 +76,26 @@ export class L1PublisherMetrics {
71
76
  unit: 'gwei',
72
77
  valueType: ValueType.INT,
73
78
  });
79
+
80
+ this.blobCountHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_COUNT, {
81
+ description: 'Number of blobs in L1 transactions',
82
+ unit: 'blobs',
83
+ valueType: ValueType.INT,
84
+ });
85
+
86
+ this.blobInclusionBlocksHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_INCLUSION_BLOCKS, {
87
+ description: 'Number of L1 blocks between blob tx submission and inclusion',
88
+ unit: 'blocks',
89
+ valueType: ValueType.INT,
90
+ });
91
+
92
+ this.blobTxSuccessCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_SUCCESS, {
93
+ description: 'Number of successful L1 transactions with blobs',
94
+ });
95
+
96
+ this.blobTxFailureCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_FAILURE, {
97
+ description: 'Number of failed L1 transactions with blobs',
98
+ });
74
99
  }
75
100
 
76
101
  recordFailedTx(txType: L1TxType) {
@@ -78,6 +103,10 @@ export class L1PublisherMetrics {
78
103
  [Attributes.L1_TX_TYPE]: txType,
79
104
  [Attributes.OK]: false,
80
105
  });
106
+
107
+ if (txType === 'process') {
108
+ this.blobTxFailureCounter.add(1);
109
+ }
81
110
  }
82
111
 
83
112
  recordSubmitProof(durationMs: number, stats: L1PublishProofStats) {
@@ -86,6 +115,16 @@ export class L1PublisherMetrics {
86
115
 
87
116
  recordProcessBlockTx(durationMs: number, stats: L1PublishBlockStats) {
88
117
  this.recordTx('process', durationMs, stats);
118
+
119
+ if (stats.blobCount && stats.blobCount > 0) {
120
+ this.blobCountHistogram.record(stats.blobCount);
121
+
122
+ if (stats.inclusionBlocks !== undefined) {
123
+ this.blobInclusionBlocksHistogram.record(stats.inclusionBlocks);
124
+ }
125
+
126
+ this.blobTxSuccessCounter.add(1);
127
+ }
89
128
  }
90
129
 
91
130
  recordClaimEpochProofRightTx(durationMs: number, stats: L1PublishStats) {