@aztec/sequencer-client 0.87.6 → 1.0.0-nightly.20250604
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 +5 -5
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +8 -8
- package/dest/global_variable_builder/global_builder.d.ts +4 -1
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +14 -2
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/config.js +1 -4
- package/dest/publisher/sequencer-publisher.d.ts +4 -4
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +23 -14
- package/dest/sequencer/block_builder.d.ts +33 -0
- package/dest/sequencer/block_builder.d.ts.map +1 -0
- package/dest/sequencer/block_builder.js +109 -0
- package/dest/sequencer/index.d.ts +1 -0
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +1 -0
- package/dest/sequencer/sequencer.d.ts +17 -64
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +74 -173
- package/dest/sequencer/utils.d.ts +2 -2
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +6 -4
- package/dest/tx_validator/tx_validator_factory.d.ts +2 -6
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/package.json +26 -25
- package/src/client/sequencer-client.ts +12 -20
- package/src/global_variable_builder/global_builder.ts +16 -2
- package/src/index.ts +1 -2
- package/src/publisher/config.ts +1 -1
- package/src/publisher/sequencer-publisher.ts +32 -21
- package/src/sequencer/block_builder.ts +192 -0
- package/src/sequencer/index.ts +1 -0
- package/src/sequencer/sequencer.ts +96 -221
- package/src/sequencer/utils.ts +14 -6
- package/src/tx_validator/tx_validator_factory.ts +2 -4
- package/dest/slasher/factory.d.ts +0 -7
- package/dest/slasher/factory.d.ts.map +0 -1
- package/dest/slasher/factory.js +0 -8
- package/dest/slasher/index.d.ts +0 -3
- package/dest/slasher/index.d.ts.map +0 -1
- package/dest/slasher/index.js +0 -2
- package/dest/slasher/slasher_client.d.ts +0 -75
- package/dest/slasher/slasher_client.d.ts.map +0 -1
- package/dest/slasher/slasher_client.js +0 -135
- package/src/slasher/factory.ts +0 -15
- package/src/slasher/index.ts +0 -2
- package/src/slasher/slasher_client.ts +0 -199
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-nightly.20250604",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -26,36 +26,37 @@
|
|
|
26
26
|
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aztec/aztec.js": "0.
|
|
30
|
-
"@aztec/bb-prover": "0.
|
|
31
|
-
"@aztec/blob-lib": "0.
|
|
32
|
-
"@aztec/blob-sink": "0.
|
|
33
|
-
"@aztec/constants": "0.
|
|
34
|
-
"@aztec/epoch-cache": "0.
|
|
35
|
-
"@aztec/ethereum": "0.
|
|
36
|
-
"@aztec/foundation": "0.
|
|
37
|
-
"@aztec/l1-artifacts": "0.
|
|
38
|
-
"@aztec/merkle-tree": "0.
|
|
39
|
-
"@aztec/noir-acvm_js": "0.
|
|
40
|
-
"@aztec/noir-contracts.js": "0.
|
|
41
|
-
"@aztec/noir-protocol-circuits-types": "0.
|
|
42
|
-
"@aztec/noir-types": "0.
|
|
43
|
-
"@aztec/p2p": "0.
|
|
44
|
-
"@aztec/protocol-contracts": "0.
|
|
45
|
-
"@aztec/prover-client": "0.
|
|
46
|
-
"@aztec/simulator": "0.
|
|
47
|
-
"@aztec/
|
|
48
|
-
"@aztec/
|
|
49
|
-
"@aztec/
|
|
50
|
-
"@aztec/
|
|
29
|
+
"@aztec/aztec.js": "1.0.0-nightly.20250604",
|
|
30
|
+
"@aztec/bb-prover": "1.0.0-nightly.20250604",
|
|
31
|
+
"@aztec/blob-lib": "1.0.0-nightly.20250604",
|
|
32
|
+
"@aztec/blob-sink": "1.0.0-nightly.20250604",
|
|
33
|
+
"@aztec/constants": "1.0.0-nightly.20250604",
|
|
34
|
+
"@aztec/epoch-cache": "1.0.0-nightly.20250604",
|
|
35
|
+
"@aztec/ethereum": "1.0.0-nightly.20250604",
|
|
36
|
+
"@aztec/foundation": "1.0.0-nightly.20250604",
|
|
37
|
+
"@aztec/l1-artifacts": "1.0.0-nightly.20250604",
|
|
38
|
+
"@aztec/merkle-tree": "1.0.0-nightly.20250604",
|
|
39
|
+
"@aztec/noir-acvm_js": "1.0.0-nightly.20250604",
|
|
40
|
+
"@aztec/noir-contracts.js": "1.0.0-nightly.20250604",
|
|
41
|
+
"@aztec/noir-protocol-circuits-types": "1.0.0-nightly.20250604",
|
|
42
|
+
"@aztec/noir-types": "1.0.0-nightly.20250604",
|
|
43
|
+
"@aztec/p2p": "1.0.0-nightly.20250604",
|
|
44
|
+
"@aztec/protocol-contracts": "1.0.0-nightly.20250604",
|
|
45
|
+
"@aztec/prover-client": "1.0.0-nightly.20250604",
|
|
46
|
+
"@aztec/simulator": "1.0.0-nightly.20250604",
|
|
47
|
+
"@aztec/slasher": "1.0.0-nightly.20250604",
|
|
48
|
+
"@aztec/stdlib": "1.0.0-nightly.20250604",
|
|
49
|
+
"@aztec/telemetry-client": "1.0.0-nightly.20250604",
|
|
50
|
+
"@aztec/validator-client": "1.0.0-nightly.20250604",
|
|
51
|
+
"@aztec/world-state": "1.0.0-nightly.20250604",
|
|
51
52
|
"lodash.chunk": "^4.2.0",
|
|
52
53
|
"lodash.pick": "^4.4.0",
|
|
53
54
|
"tslib": "^2.4.0",
|
|
54
55
|
"viem": "2.23.7"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@aztec/archiver": "0.
|
|
58
|
-
"@aztec/kv-store": "0.
|
|
58
|
+
"@aztec/archiver": "1.0.0-nightly.20250604",
|
|
59
|
+
"@aztec/kv-store": "1.0.0-nightly.20250604",
|
|
59
60
|
"@jest/globals": "^29.5.0",
|
|
60
61
|
"@types/jest": "^29.5.0",
|
|
61
62
|
"@types/lodash.chunk": "^4.2.7",
|
|
@@ -14,12 +14,10 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
14
14
|
import { createLogger } from '@aztec/foundation/log';
|
|
15
15
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
16
16
|
import type { P2P } from '@aztec/p2p';
|
|
17
|
-
import {
|
|
18
|
-
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
17
|
+
import type { SlasherClient } from '@aztec/slasher';
|
|
19
18
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
20
19
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
21
|
-
import type {
|
|
22
|
-
import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
20
|
+
import type { IFullNodeBlockBuilder, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
23
21
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
24
22
|
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
25
23
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
@@ -28,7 +26,6 @@ import type { SequencerClientConfig } from '../config.js';
|
|
|
28
26
|
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
29
27
|
import { SequencerPublisher } from '../publisher/index.js';
|
|
30
28
|
import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
31
|
-
import type { SlasherClient } from '../slasher/index.js';
|
|
32
29
|
|
|
33
30
|
/**
|
|
34
31
|
* Encapsulates the full sequencer and publisher.
|
|
@@ -55,7 +52,7 @@ export class SequencerClient {
|
|
|
55
52
|
p2pClient: P2P;
|
|
56
53
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
57
54
|
slasherClient: SlasherClient;
|
|
58
|
-
|
|
55
|
+
blockBuilder: IFullNodeBlockBuilder;
|
|
59
56
|
l2BlockSource: L2BlockSource;
|
|
60
57
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
61
58
|
telemetry: TelemetryClient;
|
|
@@ -71,7 +68,7 @@ export class SequencerClient {
|
|
|
71
68
|
p2pClient,
|
|
72
69
|
worldStateSynchronizer,
|
|
73
70
|
slasherClient,
|
|
74
|
-
|
|
71
|
+
blockBuilder,
|
|
75
72
|
l2BlockSource,
|
|
76
73
|
l1ToL2MessageSource,
|
|
77
74
|
telemetry: telemetryClient,
|
|
@@ -93,12 +90,7 @@ export class SequencerClient {
|
|
|
93
90
|
config.customForwarderContractAddress.toString(),
|
|
94
91
|
config.l1Contracts.rollupAddress.toString(),
|
|
95
92
|
)
|
|
96
|
-
: await ForwarderContract.create(
|
|
97
|
-
l1Client.account.address,
|
|
98
|
-
l1Client,
|
|
99
|
-
log,
|
|
100
|
-
config.l1Contracts.rollupAddress.toString(),
|
|
101
|
-
);
|
|
93
|
+
: await ForwarderContract.create(l1Client, log, config.l1Contracts.rollupAddress.toString());
|
|
102
94
|
|
|
103
95
|
const governanceProposerContract = new GovernanceProposerContract(
|
|
104
96
|
l1Client,
|
|
@@ -136,8 +128,6 @@ export class SequencerClient {
|
|
|
136
128
|
});
|
|
137
129
|
const globalsBuilder = new GlobalVariableBuilder(config);
|
|
138
130
|
|
|
139
|
-
const publicProcessorFactory = new PublicProcessorFactory(contractDataSource, deps.dateProvider, telemetryClient);
|
|
140
|
-
|
|
141
131
|
const ethereumSlotDuration = config.ethereumSlotDuration;
|
|
142
132
|
|
|
143
133
|
const rollupManaLimit = Number(await rollupContract.getManaLimit());
|
|
@@ -171,11 +161,9 @@ export class SequencerClient {
|
|
|
171
161
|
p2pClient,
|
|
172
162
|
worldStateSynchronizer,
|
|
173
163
|
slasherClient,
|
|
174
|
-
new LightweightBlockBuilderFactory(telemetryClient),
|
|
175
164
|
l2BlockSource,
|
|
176
165
|
l1ToL2MessageSource,
|
|
177
|
-
|
|
178
|
-
contractDataSource,
|
|
166
|
+
blockBuilder,
|
|
179
167
|
l1Constants,
|
|
180
168
|
deps.dateProvider,
|
|
181
169
|
{ ...config, maxL1TxInclusionTimeIntoSlot, maxL2BlockGas: sequencerManaLimit },
|
|
@@ -213,6 +201,10 @@ export class SequencerClient {
|
|
|
213
201
|
this.sequencer.restart();
|
|
214
202
|
}
|
|
215
203
|
|
|
204
|
+
public getSequencer(): Sequencer {
|
|
205
|
+
return this.sequencer;
|
|
206
|
+
}
|
|
207
|
+
|
|
216
208
|
get coinbase(): EthAddress {
|
|
217
209
|
return this.sequencer.coinbase;
|
|
218
210
|
}
|
|
@@ -225,8 +217,8 @@ export class SequencerClient {
|
|
|
225
217
|
return this.sequencer.getForwarderAddress();
|
|
226
218
|
}
|
|
227
219
|
|
|
228
|
-
get
|
|
229
|
-
return this.sequencer.
|
|
220
|
+
get validatorAddresses(): EthAddress[] | undefined {
|
|
221
|
+
return this.sequencer.getValidatorAddresses();
|
|
230
222
|
}
|
|
231
223
|
|
|
232
224
|
get maxL2BlockGas(): number | undefined {
|
|
@@ -20,6 +20,8 @@ import { createPublicClient, fallback, http } from 'viem';
|
|
|
20
20
|
*/
|
|
21
21
|
export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
22
22
|
private log = createLogger('sequencer:global_variable_builder');
|
|
23
|
+
private currentBaseFees: Promise<GasFees> = Promise.resolve(new GasFees(Fr.ZERO, Fr.ZERO));
|
|
24
|
+
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
23
25
|
|
|
24
26
|
private readonly rollupContract: RollupContract;
|
|
25
27
|
private readonly publicClient: ViemPublicClient;
|
|
@@ -46,9 +48,9 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Computes the "current" base fees, e.g., the price that you currently should pay to get include in the next block
|
|
49
|
-
* @returns Base fees for the
|
|
51
|
+
* @returns Base fees for the next block
|
|
50
52
|
*/
|
|
51
|
-
|
|
53
|
+
private async computeCurrentBaseFees(): Promise<GasFees> {
|
|
52
54
|
// Since this might be called in the middle of a slot where a block might have been published,
|
|
53
55
|
// we need to fetch the last block written, and estimate the earliest timestamp for the next block.
|
|
54
56
|
// The timestamp of that last block will act as a lower bound for the next block.
|
|
@@ -61,6 +63,18 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
61
63
|
return new GasFees(Fr.ZERO, new Fr(await this.rollupContract.getManaBaseFeeAt(timestamp, true)));
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
public async getCurrentBaseFees(): Promise<GasFees> {
|
|
67
|
+
// Get the current block number
|
|
68
|
+
const blockNumber = await this.publicClient.getBlockNumber();
|
|
69
|
+
|
|
70
|
+
// If the L1 block number has changed then chain a new promise to get the current base fees
|
|
71
|
+
if (this.currentL1BlockNumber === undefined || blockNumber > this.currentL1BlockNumber) {
|
|
72
|
+
this.currentL1BlockNumber = blockNumber;
|
|
73
|
+
this.currentBaseFees = this.currentBaseFees.then(() => this.computeCurrentBaseFees());
|
|
74
|
+
}
|
|
75
|
+
return this.currentBaseFees;
|
|
76
|
+
}
|
|
77
|
+
|
|
64
78
|
public async getGlobalConstantVariables(): Promise<Pick<GlobalVariables, 'chainId' | 'version'>> {
|
|
65
79
|
if (!this.chainId) {
|
|
66
80
|
this.chainId = new Fr(this.publicClient.chain.id);
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export * from './client/index.js';
|
|
2
2
|
export * from './config.js';
|
|
3
3
|
export * from './publisher/index.js';
|
|
4
|
+
export { FullNodeBlockBuilder as BlockBuilder, Sequencer, SequencerState } from './sequencer/index.js';
|
|
4
5
|
export * from './tx_validator/tx_validator_factory.js';
|
|
5
|
-
export * from './slasher/index.js';
|
|
6
|
-
export { Sequencer, SequencerState } from './sequencer/index.js';
|
|
7
6
|
|
|
8
7
|
// Used by the node to simulate public parts of transactions. Should these be moved to a shared library?
|
|
9
8
|
// ISSUE(#9832)
|
package/src/publisher/config.ts
CHANGED
|
@@ -50,7 +50,7 @@ export const getTxSenderConfigMappings: (
|
|
|
50
50
|
description: 'The private key to be used by the publisher.',
|
|
51
51
|
parseEnv: (val: string) => (val ? `0x${val.replace('0x', '')}` : NULL_KEY),
|
|
52
52
|
defaultValue: NULL_KEY,
|
|
53
|
-
fallback: ['VALIDATOR_PRIVATE_KEY'],
|
|
53
|
+
// fallback: ['VALIDATOR_PRIVATE_KEY'],
|
|
54
54
|
},
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
21
21
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
22
22
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
23
|
-
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
24
23
|
import { createLogger } from '@aztec/foundation/log';
|
|
25
24
|
import { Timer } from '@aztec/foundation/timer';
|
|
26
25
|
import { ForwarderAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
26
|
+
import { CommitteeAttestation } from '@aztec/stdlib/block';
|
|
27
27
|
import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/stdlib/p2p';
|
|
28
28
|
import type { L1PublishBlockStats } from '@aztec/stdlib/stats';
|
|
29
29
|
import { type ProposedBlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
@@ -48,7 +48,7 @@ type L1ProcessArgs = {
|
|
|
48
48
|
/** L2 block tx hashes */
|
|
49
49
|
txHashes: TxHash[];
|
|
50
50
|
/** Attestations */
|
|
51
|
-
attestations?:
|
|
51
|
+
attestations?: CommitteeAttestation[];
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
export enum VoteType {
|
|
@@ -74,7 +74,7 @@ interface RequestWithExpiry {
|
|
|
74
74
|
export class SequencerPublisher {
|
|
75
75
|
private interrupted = false;
|
|
76
76
|
private metrics: SequencerPublisherMetrics;
|
|
77
|
-
|
|
77
|
+
public epochCache: EpochCache;
|
|
78
78
|
private forwarderContract: ForwarderContract;
|
|
79
79
|
|
|
80
80
|
protected governanceLog = createLogger('sequencer:publisher:governance');
|
|
@@ -264,7 +264,9 @@ export class SequencerPublisher {
|
|
|
264
264
|
* @returns The slot and block number if it is possible to propose, undefined otherwise
|
|
265
265
|
*/
|
|
266
266
|
public canProposeAtNextEthBlock(tipArchive: Buffer) {
|
|
267
|
+
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
267
268
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
269
|
+
|
|
268
270
|
return this.rollupContract
|
|
269
271
|
.canProposeAtNextEthBlock(tipArchive, this.getForwarderAddress().toString(), this.ethereumSlotDuration)
|
|
270
272
|
.catch(err => {
|
|
@@ -288,19 +290,29 @@ export class SequencerPublisher {
|
|
|
288
290
|
*/
|
|
289
291
|
public async validateBlockForSubmission(
|
|
290
292
|
header: ProposedBlockHeader,
|
|
291
|
-
attestationData: { digest: Buffer;
|
|
293
|
+
attestationData: { digest: Buffer; attestations: CommitteeAttestation[] } = {
|
|
292
294
|
digest: Buffer.alloc(32),
|
|
293
|
-
|
|
295
|
+
attestations: [],
|
|
294
296
|
},
|
|
295
297
|
): Promise<bigint> {
|
|
296
298
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
297
299
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
+
// If we have no attestations, we still need to provide the empty attestations
|
|
301
|
+
// so that the committee is recalculated correctly
|
|
302
|
+
const ignoreSignatures = attestationData.attestations.length === 0;
|
|
303
|
+
if (ignoreSignatures) {
|
|
304
|
+
const committee = await this.epochCache.getCommittee(header.slotNumber.toBigInt());
|
|
305
|
+
attestationData.attestations = committee.committee.map(committeeMember =>
|
|
306
|
+
CommitteeAttestation.fromAddress(committeeMember),
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const formattedAttestations = attestationData.attestations.map(attest => attest.toViem());
|
|
311
|
+
const flags = { ignoreDA: true, ignoreSignatures };
|
|
300
312
|
|
|
301
313
|
const args = [
|
|
302
314
|
toHex(header.toBuffer()),
|
|
303
|
-
|
|
315
|
+
formattedAttestations,
|
|
304
316
|
toHex(attestationData.digest),
|
|
305
317
|
ts,
|
|
306
318
|
toHex(header.contentCommitment.blobsHash),
|
|
@@ -330,14 +342,8 @@ export class SequencerPublisher {
|
|
|
330
342
|
return false;
|
|
331
343
|
}
|
|
332
344
|
const round = await base.computeRound(slotNumber);
|
|
333
|
-
const
|
|
334
|
-
this.rollupContract.getProposerAt(timestamp),
|
|
335
|
-
base.getRoundInfo(this.rollupContract.address, round),
|
|
336
|
-
]);
|
|
345
|
+
const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
|
|
337
346
|
|
|
338
|
-
if (proposer.toLowerCase() !== this.getForwarderAddress().toString().toLowerCase()) {
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
347
|
if (roundInfo.lastVote >= slotNumber) {
|
|
342
348
|
return false;
|
|
343
349
|
}
|
|
@@ -347,9 +353,15 @@ export class SequencerPublisher {
|
|
|
347
353
|
|
|
348
354
|
const action = voteType === VoteType.GOVERNANCE ? 'governance-vote' : 'slashing-vote';
|
|
349
355
|
|
|
356
|
+
const request = await base.createVoteRequestWithSignature(payload.toString(), this.l1TxUtils.client);
|
|
357
|
+
this.log.debug(`Created ${action} request with signature`, {
|
|
358
|
+
request,
|
|
359
|
+
signer: this.l1TxUtils.client.account?.address,
|
|
360
|
+
});
|
|
361
|
+
|
|
350
362
|
this.addRequest({
|
|
351
363
|
action,
|
|
352
|
-
request
|
|
364
|
+
request,
|
|
353
365
|
lastValidL2Slot: slotNumber,
|
|
354
366
|
onResult: (_request, result) => {
|
|
355
367
|
if (!result || result.receipt.status !== 'success') {
|
|
@@ -376,6 +388,7 @@ export class SequencerPublisher {
|
|
|
376
388
|
if (!slashPayload) {
|
|
377
389
|
return undefined;
|
|
378
390
|
}
|
|
391
|
+
this.log.info(`Slash payload: ${slashPayload}`);
|
|
379
392
|
return { payload: slashPayload, base: this.slashingProposerContract };
|
|
380
393
|
}
|
|
381
394
|
throw new Error('Unreachable: Invalid vote type');
|
|
@@ -405,7 +418,7 @@ export class SequencerPublisher {
|
|
|
405
418
|
*/
|
|
406
419
|
public async enqueueProposeL2Block(
|
|
407
420
|
block: L2Block,
|
|
408
|
-
attestations?:
|
|
421
|
+
attestations?: CommitteeAttestation[],
|
|
409
422
|
txHashes?: TxHash[],
|
|
410
423
|
opts: { txTimeoutAt?: Date } = {},
|
|
411
424
|
): Promise<boolean> {
|
|
@@ -431,7 +444,7 @@ export class SequencerPublisher {
|
|
|
431
444
|
// make time consistency checks break.
|
|
432
445
|
const ts = await this.validateBlockForSubmission(proposedBlockHeader, {
|
|
433
446
|
digest: digest.toBuffer(),
|
|
434
|
-
|
|
447
|
+
attestations: attestations ?? [],
|
|
435
448
|
});
|
|
436
449
|
|
|
437
450
|
this.log.debug(`Submitting propose transaction`);
|
|
@@ -486,9 +499,7 @@ export class SequencerPublisher {
|
|
|
486
499
|
throw new Error('Failed to validate blobs');
|
|
487
500
|
});
|
|
488
501
|
|
|
489
|
-
const attestations = encodedData.attestations
|
|
490
|
-
? encodedData.attestations.map(attest => attest.toViemSignature())
|
|
491
|
-
: [];
|
|
502
|
+
const attestations = encodedData.attestations ? encodedData.attestations.map(attest => attest.toViem()) : [];
|
|
492
503
|
const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.toString()) : [];
|
|
493
504
|
const args = [
|
|
494
505
|
{
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { elapsed } from '@aztec/aztec.js';
|
|
2
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
4
|
+
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
5
|
+
import { LightweightBlockFactory } from '@aztec/prover-client/block-factory';
|
|
6
|
+
import {
|
|
7
|
+
GuardedMerkleTreeOperations,
|
|
8
|
+
PublicContractsDB,
|
|
9
|
+
PublicProcessor,
|
|
10
|
+
TelemetryPublicTxSimulator,
|
|
11
|
+
} from '@aztec/simulator/server';
|
|
12
|
+
import type { ChainConfig } from '@aztec/stdlib/config';
|
|
13
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
14
|
+
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
15
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
16
|
+
import type {
|
|
17
|
+
BuildBlockOptions,
|
|
18
|
+
BuildBlockResult,
|
|
19
|
+
IFullNodeBlockBuilder,
|
|
20
|
+
MerkleTreeWriteOperations,
|
|
21
|
+
PublicProcessorValidator,
|
|
22
|
+
WorldStateSynchronizer,
|
|
23
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
24
|
+
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
25
|
+
import { GlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
26
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
27
|
+
|
|
28
|
+
import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
|
|
29
|
+
|
|
30
|
+
const log = createLogger('sequencer:block-builder');
|
|
31
|
+
|
|
32
|
+
export async function buildBlock(
|
|
33
|
+
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
34
|
+
newGlobalVariables: GlobalVariables,
|
|
35
|
+
opts: BuildBlockOptions = {},
|
|
36
|
+
l1ToL2MessageSource: L1ToL2MessageSource,
|
|
37
|
+
worldStateFork: MerkleTreeWriteOperations,
|
|
38
|
+
processor: PublicProcessor,
|
|
39
|
+
validator: PublicProcessorValidator,
|
|
40
|
+
l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>,
|
|
41
|
+
dateProvider: DateProvider,
|
|
42
|
+
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
43
|
+
): Promise<BuildBlockResult> {
|
|
44
|
+
const blockBuildingTimer = new Timer();
|
|
45
|
+
const blockNumber = newGlobalVariables.blockNumber.toNumber();
|
|
46
|
+
const slot = newGlobalVariables.slotNumber.toBigInt();
|
|
47
|
+
log.debug(`Requesting L1 to L2 messages from contract for block ${blockNumber}`);
|
|
48
|
+
const l1ToL2Messages = await l1ToL2MessageSource.getL1ToL2Messages(BigInt(blockNumber));
|
|
49
|
+
const msgCount = l1ToL2Messages.length;
|
|
50
|
+
|
|
51
|
+
log.verbose(`Building block ${blockNumber} for slot ${slot}`, {
|
|
52
|
+
slot,
|
|
53
|
+
slotStart: new Date(Number(getTimestampForSlot(slot, l1Constants)) * 1000),
|
|
54
|
+
now: new Date(dateProvider.now()),
|
|
55
|
+
blockNumber,
|
|
56
|
+
msgCount,
|
|
57
|
+
opts,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const blockFactory = new LightweightBlockFactory(worldStateFork, telemetryClient);
|
|
62
|
+
await blockFactory.startNewBlock(newGlobalVariables, l1ToL2Messages);
|
|
63
|
+
|
|
64
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
|
|
65
|
+
processor.process(pendingTxs, opts, validator),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// All real transactions have been added, set the block as full and pad if needed
|
|
69
|
+
await blockFactory.addTxs(processedTxs);
|
|
70
|
+
const block = await blockFactory.setBlockCompleted();
|
|
71
|
+
|
|
72
|
+
// How much public gas was processed
|
|
73
|
+
const publicGas = processedTxs.reduce((acc, tx) => acc.add(tx.gasUsed.publicGas), Gas.empty());
|
|
74
|
+
|
|
75
|
+
const res = {
|
|
76
|
+
block,
|
|
77
|
+
publicGas,
|
|
78
|
+
publicProcessorDuration,
|
|
79
|
+
numMsgs: l1ToL2Messages.length,
|
|
80
|
+
numTxs: processedTxs.length,
|
|
81
|
+
failedTxs: failedTxs,
|
|
82
|
+
blockBuildingTimer,
|
|
83
|
+
usedTxs,
|
|
84
|
+
};
|
|
85
|
+
log.trace('Built block', res.block.header);
|
|
86
|
+
return res;
|
|
87
|
+
} finally {
|
|
88
|
+
// We wait a bit to close the forks since the processor may still be working on a dangling tx
|
|
89
|
+
// which was interrupted due to the processingDeadline being hit.
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
91
|
+
setTimeout(async () => {
|
|
92
|
+
try {
|
|
93
|
+
await worldStateFork.close();
|
|
94
|
+
} catch (err) {
|
|
95
|
+
// This can happen if the sequencer is stopped before we hit this timeout.
|
|
96
|
+
log.warn(`Error closing forks for block processing`, err);
|
|
97
|
+
}
|
|
98
|
+
}, 5000);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
|
|
103
|
+
constructor(
|
|
104
|
+
private config: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'> &
|
|
105
|
+
Pick<ChainConfig, 'l1ChainId' | 'rollupVersion'>,
|
|
106
|
+
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
107
|
+
private worldState: WorldStateSynchronizer,
|
|
108
|
+
private contractDataSource: ContractDataSource,
|
|
109
|
+
private dateProvider: DateProvider,
|
|
110
|
+
private telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
111
|
+
) {}
|
|
112
|
+
|
|
113
|
+
public getConfig() {
|
|
114
|
+
return {
|
|
115
|
+
l1GenesisTime: this.config.l1GenesisTime,
|
|
116
|
+
slotDuration: this.config.slotDuration,
|
|
117
|
+
l1ChainId: this.config.l1ChainId,
|
|
118
|
+
rollupVersion: this.config.rollupVersion,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async makeBlockBuilderDeps(globalVariables: GlobalVariables, opts: BuildBlockOptions) {
|
|
123
|
+
const publicProcessorDBFork = await this.worldState.fork();
|
|
124
|
+
const contractsDB = new PublicContractsDB(this.contractDataSource);
|
|
125
|
+
const guardedFork = new GuardedMerkleTreeOperations(publicProcessorDBFork);
|
|
126
|
+
|
|
127
|
+
const publicTxSimulator = new TelemetryPublicTxSimulator(
|
|
128
|
+
guardedFork,
|
|
129
|
+
contractsDB,
|
|
130
|
+
globalVariables,
|
|
131
|
+
/*doMerkleOperations=*/ true,
|
|
132
|
+
/*skipFeeEnforcement=*/ true,
|
|
133
|
+
/*clientInitiatedSimulation=*/ false,
|
|
134
|
+
this.telemetryClient,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const processor = new PublicProcessor(
|
|
138
|
+
globalVariables,
|
|
139
|
+
guardedFork,
|
|
140
|
+
contractsDB,
|
|
141
|
+
publicTxSimulator,
|
|
142
|
+
this.dateProvider,
|
|
143
|
+
this.telemetryClient,
|
|
144
|
+
);
|
|
145
|
+
const validator = createValidatorForBlockBuilding(
|
|
146
|
+
publicProcessorDBFork,
|
|
147
|
+
this.contractDataSource,
|
|
148
|
+
globalVariables,
|
|
149
|
+
opts.txPublicSetupAllowList ?? [],
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
publicProcessorDBFork,
|
|
154
|
+
processor,
|
|
155
|
+
validator,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private async syncToPreviousBlock(parentBlockNumber: number, timeout: number | undefined) {
|
|
160
|
+
await retryUntil(
|
|
161
|
+
() => this.worldState.syncImmediate(parentBlockNumber, true).then(syncedTo => syncedTo >= parentBlockNumber),
|
|
162
|
+
'sync to previous block',
|
|
163
|
+
timeout,
|
|
164
|
+
0.1,
|
|
165
|
+
);
|
|
166
|
+
log.debug(`Synced to previous block ${parentBlockNumber}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async buildBlock(
|
|
170
|
+
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
171
|
+
globalVariables: GlobalVariables,
|
|
172
|
+
opts: BuildBlockOptions,
|
|
173
|
+
): Promise<BuildBlockResult> {
|
|
174
|
+
const parentBlockNumber = globalVariables.blockNumber.toNumber() - 1;
|
|
175
|
+
const syncTimeout = opts.deadline ? (opts.deadline.getTime() - this.dateProvider.now()) / 1000 : undefined;
|
|
176
|
+
await this.syncToPreviousBlock(parentBlockNumber, syncTimeout);
|
|
177
|
+
const { publicProcessorDBFork, processor, validator } = await this.makeBlockBuilderDeps(globalVariables, opts);
|
|
178
|
+
|
|
179
|
+
return buildBlock(
|
|
180
|
+
pendingTxs,
|
|
181
|
+
globalVariables,
|
|
182
|
+
opts,
|
|
183
|
+
this.l1ToL2MessageSource,
|
|
184
|
+
publicProcessorDBFork,
|
|
185
|
+
processor,
|
|
186
|
+
validator,
|
|
187
|
+
this.config,
|
|
188
|
+
this.dateProvider,
|
|
189
|
+
this.telemetryClient,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
package/src/sequencer/index.ts
CHANGED