@aztec/sequencer-client 0.86.0 → 0.87.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/config.d.ts.map +1 -1
- package/dest/config.js +5 -0
- package/dest/global_variable_builder/global_builder.d.ts +6 -3
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +15 -2
- package/dest/publisher/sequencer-publisher-metrics.js +2 -2
- package/dest/publisher/sequencer-publisher.d.ts +4 -6
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +15 -12
- package/dest/sequencer/metrics.d.ts +1 -0
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +3 -0
- package/dest/sequencer/sequencer.d.ts +23 -7
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +47 -22
- package/dest/sequencer/timetable.d.ts +4 -4
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +14 -4
- package/dest/slasher/factory.d.ts.map +1 -1
- package/dest/tx_validator/nullifier_cache.d.ts +0 -2
- package/dest/tx_validator/nullifier_cache.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +16 -3
- package/package.json +30 -30
- package/src/client/sequencer-client.ts +1 -1
- package/src/config.ts +5 -0
- package/src/global_variable_builder/global_builder.ts +17 -5
- package/src/publisher/sequencer-publisher-metrics.ts +2 -2
- package/src/publisher/sequencer-publisher.ts +19 -14
- package/src/sequencer/metrics.ts +4 -0
- package/src/sequencer/sequencer.ts +60 -35
- package/src/sequencer/timetable.ts +16 -4
- package/src/slasher/slasher_client.ts +1 -1
- package/src/test/index.ts +4 -4
- package/src/tx_validator/tx_validator_factory.ts +16 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tx_validator_factory.d.ts","sourceRoot":"","sources":["../../src/tx_validator/tx_validator_factory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tx_validator_factory.d.ts","sourceRoot":"","sources":["../../src/tx_validator/tx_validator_factory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EACV,cAAc,EACd,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,wBAAwB,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,QAAQ,EAAE,6BAA6B,GAAG,SAAS,EACnD,EACE,WAAW,EACX,SAAS,EACT,aAAa,EACb,cAAc,EACd,OAAO,EACP,kBAAkB,GACnB,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GACA,WAAW,CAAC,EAAE,CAAC,CAwBjB;AAED,wBAAgB,+BAA+B,CAC7C,EAAE,EAAE,wBAAwB,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,cAAc,EAAE,GAC/B;IACD,mBAAmB,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IACrC,cAAc,EAAE,cAAc,CAAC;CAChC,CAgBA"}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
2
3
|
import { AggregateTxValidator, ArchiveCache, BlockHeaderTxValidator, DataTxValidator, DoubleSpendTxValidator, GasTxValidator, MetadataTxValidator, PhasesTxValidator, TxProofValidator } from '@aztec/p2p';
|
|
3
|
-
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
4
|
+
import { ProtocolContractAddress, protocolContractTreeRoot } from '@aztec/protocol-contracts';
|
|
4
5
|
import { DatabasePublicStateSource } from '@aztec/stdlib/trees';
|
|
5
6
|
import { NullifierCache } from './nullifier_cache.js';
|
|
6
7
|
export function createValidatorForAcceptingTxs(db, contractDataSource, verifier, { blockNumber, l1ChainId, rollupVersion, setupAllowList, gasFees, skipFeeEnforcement }) {
|
|
7
8
|
const validators = [
|
|
8
9
|
new DataTxValidator(),
|
|
9
|
-
new MetadataTxValidator(
|
|
10
|
+
new MetadataTxValidator({
|
|
11
|
+
l1ChainId: new Fr(l1ChainId),
|
|
12
|
+
rollupVersion: new Fr(rollupVersion),
|
|
13
|
+
blockNumber: new Fr(blockNumber),
|
|
14
|
+
protocolContractTreeRoot,
|
|
15
|
+
vkTreeRoot: getVKTreeRoot()
|
|
16
|
+
}),
|
|
10
17
|
new DoubleSpendTxValidator(new NullifierCache(db)),
|
|
11
18
|
new PhasesTxValidator(contractDataSource, setupAllowList, blockNumber),
|
|
12
19
|
new BlockHeaderTxValidator(new ArchiveCache(db))
|
|
@@ -30,5 +37,11 @@ export function createValidatorForBlockBuilding(db, contractDataSource, globalVa
|
|
|
30
37
|
}
|
|
31
38
|
function preprocessValidator(nullifierCache, archiveCache, publicStateSource, contractDataSource, globalVariables, setupAllowList) {
|
|
32
39
|
// We don't include the TxProofValidator nor the DataTxValidator here because they are already checked by the time we get to block building.
|
|
33
|
-
return new AggregateTxValidator(new MetadataTxValidator(
|
|
40
|
+
return new AggregateTxValidator(new MetadataTxValidator({
|
|
41
|
+
l1ChainId: globalVariables.chainId,
|
|
42
|
+
rollupVersion: globalVariables.version,
|
|
43
|
+
blockNumber: globalVariables.blockNumber,
|
|
44
|
+
protocolContractTreeRoot,
|
|
45
|
+
vkTreeRoot: getVKTreeRoot()
|
|
46
|
+
}), new DoubleSpendTxValidator(nullifierCache), new PhasesTxValidator(contractDataSource, setupAllowList, globalVariables.blockNumber.toNumber()), new GasTxValidator(publicStateSource, ProtocolContractAddress.FeeJuice, globalVariables.gasFees), new BlockHeaderTxValidator(archiveCache));
|
|
34
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -26,49 +26,49 @@
|
|
|
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/stdlib": "0.
|
|
48
|
-
"@aztec/telemetry-client": "0.
|
|
49
|
-
"@aztec/validator-client": "0.
|
|
50
|
-
"@aztec/world-state": "0.
|
|
29
|
+
"@aztec/aztec.js": "0.87.0",
|
|
30
|
+
"@aztec/bb-prover": "0.87.0",
|
|
31
|
+
"@aztec/blob-lib": "0.87.0",
|
|
32
|
+
"@aztec/blob-sink": "0.87.0",
|
|
33
|
+
"@aztec/constants": "0.87.0",
|
|
34
|
+
"@aztec/epoch-cache": "0.87.0",
|
|
35
|
+
"@aztec/ethereum": "0.87.0",
|
|
36
|
+
"@aztec/foundation": "0.87.0",
|
|
37
|
+
"@aztec/l1-artifacts": "0.87.0",
|
|
38
|
+
"@aztec/merkle-tree": "0.87.0",
|
|
39
|
+
"@aztec/noir-acvm_js": "0.87.0",
|
|
40
|
+
"@aztec/noir-contracts.js": "0.87.0",
|
|
41
|
+
"@aztec/noir-protocol-circuits-types": "0.87.0",
|
|
42
|
+
"@aztec/noir-types": "0.87.0",
|
|
43
|
+
"@aztec/p2p": "0.87.0",
|
|
44
|
+
"@aztec/protocol-contracts": "0.87.0",
|
|
45
|
+
"@aztec/prover-client": "0.87.0",
|
|
46
|
+
"@aztec/simulator": "0.87.0",
|
|
47
|
+
"@aztec/stdlib": "0.87.0",
|
|
48
|
+
"@aztec/telemetry-client": "0.87.0",
|
|
49
|
+
"@aztec/validator-client": "0.87.0",
|
|
50
|
+
"@aztec/world-state": "0.87.0",
|
|
51
51
|
"lodash.chunk": "^4.2.0",
|
|
52
52
|
"lodash.pick": "^4.4.0",
|
|
53
53
|
"tslib": "^2.4.0",
|
|
54
54
|
"viem": "2.23.7"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@aztec/archiver": "0.
|
|
58
|
-
"@aztec/kv-store": "0.
|
|
57
|
+
"@aztec/archiver": "0.87.0",
|
|
58
|
+
"@aztec/kv-store": "0.87.0",
|
|
59
59
|
"@jest/globals": "^29.5.0",
|
|
60
60
|
"@types/jest": "^29.5.0",
|
|
61
61
|
"@types/lodash.chunk": "^4.2.7",
|
|
62
62
|
"@types/lodash.pick": "^4.4.7",
|
|
63
|
-
"@types/node": "^
|
|
63
|
+
"@types/node": "^22.15.17",
|
|
64
64
|
"concurrently": "^7.6.0",
|
|
65
|
-
"eslint": "^
|
|
65
|
+
"eslint": "^9.26.0",
|
|
66
66
|
"express": "^4.21.1",
|
|
67
67
|
"jest": "^29.5.0",
|
|
68
68
|
"jest-mock-extended": "^3.0.3",
|
|
69
|
-
"prettier": "^
|
|
69
|
+
"prettier": "^3.5.3",
|
|
70
70
|
"ts-node": "^10.9.1",
|
|
71
|
-
"typescript": "^5.
|
|
71
|
+
"typescript": "^5.3.3"
|
|
72
72
|
},
|
|
73
73
|
"files": [
|
|
74
74
|
"dest",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
],
|
|
78
78
|
"types": "./dest/index.d.ts",
|
|
79
79
|
"engines": {
|
|
80
|
-
"node": ">=
|
|
80
|
+
"node": ">=20.10"
|
|
81
81
|
},
|
|
82
82
|
"jest": {
|
|
83
83
|
"extensionsToTreatAsEsm": [
|
|
@@ -157,7 +157,7 @@ export class SequencerClient {
|
|
|
157
157
|
// make it with a propagation time into slot equal to 4s. However, we prefer being conservative.
|
|
158
158
|
// See https://www.blocknative.com/blog/anatomy-of-a-slot#7 for more info.
|
|
159
159
|
const maxL1TxInclusionTimeIntoSlot =
|
|
160
|
-
config.maxL1TxInclusionTimeIntoSlot ?? isAnvilTestChain(config.l1ChainId) ? ethereumSlotDuration : 0;
|
|
160
|
+
(config.maxL1TxInclusionTimeIntoSlot ?? isAnvilTestChain(config.l1ChainId)) ? ethereumSlotDuration : 0;
|
|
161
161
|
|
|
162
162
|
const l1Constants = {
|
|
163
163
|
l1GenesisTime,
|
package/src/config.ts
CHANGED
|
@@ -58,6 +58,11 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
58
58
|
description: 'The minimum number of txs to include in a block.',
|
|
59
59
|
...numberConfigHelper(1),
|
|
60
60
|
},
|
|
61
|
+
publishTxsWithProposals: {
|
|
62
|
+
env: 'SEQ_PUBLISH_TXS_WITH_PROPOSALS',
|
|
63
|
+
description: 'Whether to publish txs with proposals.',
|
|
64
|
+
...booleanConfigHelper(false),
|
|
65
|
+
},
|
|
61
66
|
maxL2BlockGas: {
|
|
62
67
|
env: 'SEQ_MAX_L2_BLOCK_GAS',
|
|
63
68
|
description: 'The maximum L2 block gas.',
|
|
@@ -21,9 +21,12 @@ import { createPublicClient, fallback, http } from 'viem';
|
|
|
21
21
|
export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
22
22
|
private log = createLogger('sequencer:global_variable_builder');
|
|
23
23
|
|
|
24
|
-
private rollupContract: RollupContract;
|
|
25
|
-
private publicClient: ViemPublicClient;
|
|
26
|
-
private ethereumSlotDuration: number;
|
|
24
|
+
private readonly rollupContract: RollupContract;
|
|
25
|
+
private readonly publicClient: ViemPublicClient;
|
|
26
|
+
private readonly ethereumSlotDuration: number;
|
|
27
|
+
|
|
28
|
+
private chainId?: Fr;
|
|
29
|
+
private version?: Fr;
|
|
27
30
|
|
|
28
31
|
constructor(config: L1ReaderConfig & Pick<L1ContractsConfig, 'ethereumSlotDuration'>) {
|
|
29
32
|
const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
|
|
@@ -58,6 +61,16 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
58
61
|
return new GasFees(Fr.ZERO, new Fr(await this.rollupContract.getManaBaseFeeAt(timestamp, true)));
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
public async getGlobalConstantVariables(): Promise<Pick<GlobalVariables, 'chainId' | 'version'>> {
|
|
65
|
+
if (!this.chainId) {
|
|
66
|
+
this.chainId = new Fr(this.publicClient.chain.id);
|
|
67
|
+
}
|
|
68
|
+
if (!this.version) {
|
|
69
|
+
this.version = new Fr(await this.rollupContract.getVersion());
|
|
70
|
+
}
|
|
71
|
+
return { chainId: this.chainId, version: this.version };
|
|
72
|
+
}
|
|
73
|
+
|
|
61
74
|
/**
|
|
62
75
|
* Simple builder of global variables that use the minimum time possible.
|
|
63
76
|
* @param blockNumber - The block number to build global variables for.
|
|
@@ -72,8 +85,7 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
72
85
|
feeRecipient: AztecAddress,
|
|
73
86
|
slotNumber?: bigint,
|
|
74
87
|
): Promise<GlobalVariables> {
|
|
75
|
-
const version =
|
|
76
|
-
const chainId = new Fr(this.publicClient.chain.id);
|
|
88
|
+
const { chainId, version } = await this.getGlobalConstantVariables();
|
|
77
89
|
|
|
78
90
|
if (slotNumber === undefined) {
|
|
79
91
|
const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration));
|
|
@@ -181,7 +181,7 @@ export class SequencerPublisherMetrics {
|
|
|
181
181
|
|
|
182
182
|
try {
|
|
183
183
|
this.gasPrice.record(parseInt(formatEther(stats.gasPrice, 'gwei'), 10));
|
|
184
|
-
} catch
|
|
184
|
+
} catch {
|
|
185
185
|
// ignore
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -191,7 +191,7 @@ export class SequencerPublisherMetrics {
|
|
|
191
191
|
|
|
192
192
|
try {
|
|
193
193
|
this.txTotalFee.record(parseFloat(formatEther(totalFee)));
|
|
194
|
-
} catch
|
|
194
|
+
} catch {
|
|
195
195
|
// ignore
|
|
196
196
|
}
|
|
197
197
|
}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
formatViemError,
|
|
19
19
|
} from '@aztec/ethereum';
|
|
20
20
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
21
|
-
import { toHex } from '@aztec/foundation/bigint-buffer';
|
|
21
|
+
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
22
22
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
23
23
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
24
24
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -26,11 +26,11 @@ import { Timer } from '@aztec/foundation/timer';
|
|
|
26
26
|
import { ForwarderAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
27
27
|
import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/stdlib/p2p';
|
|
28
28
|
import type { L1PublishBlockStats } from '@aztec/stdlib/stats';
|
|
29
|
-
import { type
|
|
29
|
+
import { type ProposedBlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
30
30
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
31
31
|
|
|
32
32
|
import pick from 'lodash.pick';
|
|
33
|
-
import { type TransactionReceipt, encodeFunctionData } from 'viem';
|
|
33
|
+
import { type TransactionReceipt, encodeFunctionData, toHex } from 'viem';
|
|
34
34
|
|
|
35
35
|
import type { PublisherConfig, TxSenderConfig } from './config.js';
|
|
36
36
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
@@ -41,6 +41,8 @@ type L1ProcessArgs = {
|
|
|
41
41
|
header: Buffer;
|
|
42
42
|
/** A root of the archive tree after the L2 block is applied. */
|
|
43
43
|
archive: Buffer;
|
|
44
|
+
/** State reference after the L2 block is applied. */
|
|
45
|
+
stateReference: Buffer;
|
|
44
46
|
/** L2 block blobs containing all tx effects. */
|
|
45
47
|
blobs: Blob[];
|
|
46
48
|
/** L2 block tx hashes */
|
|
@@ -285,7 +287,7 @@ export class SequencerPublisher {
|
|
|
285
287
|
*
|
|
286
288
|
*/
|
|
287
289
|
public async validateBlockForSubmission(
|
|
288
|
-
header:
|
|
290
|
+
header: ProposedBlockHeader,
|
|
289
291
|
attestationData: { digest: Buffer; signatures: Signature[] } = {
|
|
290
292
|
digest: Buffer.alloc(32),
|
|
291
293
|
signatures: [],
|
|
@@ -297,11 +299,11 @@ export class SequencerPublisher {
|
|
|
297
299
|
const flags = { ignoreDA: true, ignoreSignatures: formattedSignatures.length == 0 };
|
|
298
300
|
|
|
299
301
|
const args = [
|
|
300
|
-
|
|
302
|
+
toHex(header.toBuffer()),
|
|
301
303
|
formattedSignatures,
|
|
302
|
-
|
|
304
|
+
toHex(attestationData.digest),
|
|
303
305
|
ts,
|
|
304
|
-
|
|
306
|
+
toHex(header.contentCommitment.blobsHash),
|
|
305
307
|
flags,
|
|
306
308
|
] as const;
|
|
307
309
|
|
|
@@ -407,14 +409,16 @@ export class SequencerPublisher {
|
|
|
407
409
|
txHashes?: TxHash[],
|
|
408
410
|
opts: { txTimeoutAt?: Date } = {},
|
|
409
411
|
): Promise<boolean> {
|
|
410
|
-
const
|
|
412
|
+
const proposedBlockHeader = block.header.toPropose();
|
|
411
413
|
|
|
414
|
+
const consensusPayload = ConsensusPayload.fromBlock(block);
|
|
412
415
|
const digest = getHashedSignaturePayload(consensusPayload, SignatureDomainSeparator.blockAttestation);
|
|
413
416
|
|
|
414
417
|
const blobs = await Blob.getBlobs(block.body.toBlobFields());
|
|
415
418
|
const proposeTxArgs = {
|
|
416
|
-
header:
|
|
419
|
+
header: proposedBlockHeader.toBuffer(),
|
|
417
420
|
archive: block.archive.root.toBuffer(),
|
|
421
|
+
stateReference: block.header.state.toBuffer(),
|
|
418
422
|
body: block.body.toBuffer(),
|
|
419
423
|
blobs,
|
|
420
424
|
attestations,
|
|
@@ -425,7 +429,7 @@ export class SequencerPublisher {
|
|
|
425
429
|
// This means that we can avoid the simulation issues in later checks.
|
|
426
430
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
427
431
|
// make time consistency checks break.
|
|
428
|
-
const ts = await this.validateBlockForSubmission(
|
|
432
|
+
const ts = await this.validateBlockForSubmission(proposedBlockHeader, {
|
|
429
433
|
digest: digest.toBuffer(),
|
|
430
434
|
signatures: attestations ?? [],
|
|
431
435
|
});
|
|
@@ -488,8 +492,9 @@ export class SequencerPublisher {
|
|
|
488
492
|
const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.toString()) : [];
|
|
489
493
|
const args = [
|
|
490
494
|
{
|
|
491
|
-
header:
|
|
492
|
-
archive:
|
|
495
|
+
header: toHex(encodedData.header),
|
|
496
|
+
archive: toHex(encodedData.archive),
|
|
497
|
+
stateReference: toHex(encodedData.stateReference),
|
|
493
498
|
oracleInput: {
|
|
494
499
|
// We are currently not modifying these. See #9963
|
|
495
500
|
feeAssetPriceModifier: 0n,
|
|
@@ -531,8 +536,8 @@ export class SequencerPublisher {
|
|
|
531
536
|
// @note we override checkBlob to false since blobs are not part simulate()
|
|
532
537
|
stateDiff: [
|
|
533
538
|
{
|
|
534
|
-
slot:
|
|
535
|
-
value:
|
|
539
|
+
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
540
|
+
value: toPaddedHex(0n, true),
|
|
536
541
|
},
|
|
537
542
|
],
|
|
538
543
|
},
|
package/src/sequencer/metrics.ts
CHANGED
|
@@ -23,17 +23,11 @@ import {
|
|
|
23
23
|
type WorldStateSynchronizer,
|
|
24
24
|
} from '@aztec/stdlib/interfaces/server';
|
|
25
25
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
26
|
+
import type { BlockProposalOptions } from '@aztec/stdlib/p2p';
|
|
26
27
|
import { pickFromSchema } from '@aztec/stdlib/schemas';
|
|
27
28
|
import type { L2BlockBuiltStats } from '@aztec/stdlib/stats';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
BlockHeader,
|
|
31
|
-
ContentCommitment,
|
|
32
|
-
type GlobalVariables,
|
|
33
|
-
StateReference,
|
|
34
|
-
Tx,
|
|
35
|
-
type TxHash,
|
|
36
|
-
} from '@aztec/stdlib/tx';
|
|
29
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
30
|
+
import { ContentCommitment, GlobalVariables, ProposedBlockHeader, Tx, type TxHash } from '@aztec/stdlib/tx';
|
|
37
31
|
import {
|
|
38
32
|
Attributes,
|
|
39
33
|
L1Metrics,
|
|
@@ -109,7 +103,7 @@ export class Sequencer {
|
|
|
109
103
|
this.metrics = new SequencerMetrics(
|
|
110
104
|
telemetry,
|
|
111
105
|
() => this.state,
|
|
112
|
-
this.
|
|
106
|
+
this.config.coinbase ?? this.publisher.getSenderAddress(),
|
|
113
107
|
this.publisher.getRollupContract(),
|
|
114
108
|
'Sequencer',
|
|
115
109
|
);
|
|
@@ -120,7 +114,7 @@ export class Sequencer {
|
|
|
120
114
|
);
|
|
121
115
|
|
|
122
116
|
// Register the block builder with the validator client for re-execution
|
|
123
|
-
this.validatorClient?.registerBlockBuilder(this.
|
|
117
|
+
this.validatorClient?.registerBlockBuilder(this.buildBlockFromProposal.bind(this));
|
|
124
118
|
|
|
125
119
|
// Register the slasher on the publisher to fetch slashing payloads
|
|
126
120
|
this.publisher.registerSlashPayloadGetter(this.slasherClient.getSlashPayload.bind(this.slasherClient));
|
|
@@ -161,6 +155,7 @@ export class Sequencer {
|
|
|
161
155
|
}
|
|
162
156
|
if (config.coinbase) {
|
|
163
157
|
this._coinbase = config.coinbase;
|
|
158
|
+
this.metrics.setCoinbase(this._coinbase);
|
|
164
159
|
}
|
|
165
160
|
if (config.feeRecipient) {
|
|
166
161
|
this._feeRecipient = config.feeRecipient;
|
|
@@ -311,14 +306,13 @@ export class Sequencer {
|
|
|
311
306
|
});
|
|
312
307
|
|
|
313
308
|
// If I created a "partial" header here that should make our job much easier.
|
|
314
|
-
const proposalHeader =
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
Fr.ZERO,
|
|
320
|
-
|
|
321
|
-
);
|
|
309
|
+
const proposalHeader = ProposedBlockHeader.from({
|
|
310
|
+
...newGlobalVariables,
|
|
311
|
+
timestamp: newGlobalVariables.timestamp.toBigInt(),
|
|
312
|
+
lastArchiveRoot: chainTipArchive,
|
|
313
|
+
contentCommitment: ContentCommitment.empty(),
|
|
314
|
+
totalManaUsed: Fr.ZERO,
|
|
315
|
+
});
|
|
322
316
|
|
|
323
317
|
let finishedFlushing = false;
|
|
324
318
|
const pendingTxCount = await this.p2pClient.getPendingTxCount();
|
|
@@ -327,7 +321,7 @@ export class Sequencer {
|
|
|
327
321
|
// and also we may need to fetch more if we don't have enough valid txs.
|
|
328
322
|
const pendingTxs = this.p2pClient.iteratePendingTxs();
|
|
329
323
|
|
|
330
|
-
await this.buildBlockAndEnqueuePublish(pendingTxs, proposalHeader).catch(err => {
|
|
324
|
+
await this.buildBlockAndEnqueuePublish(pendingTxs, proposalHeader, newGlobalVariables).catch(err => {
|
|
331
325
|
this.log.error(`Error building/enqueuing block`, err, { blockNumber: newBlockNumber, slot });
|
|
332
326
|
});
|
|
333
327
|
finishedFlushing = true;
|
|
@@ -426,11 +420,8 @@ export class Sequencer {
|
|
|
426
420
|
/**
|
|
427
421
|
* Build a block
|
|
428
422
|
*
|
|
429
|
-
* Shared between the sequencer and the validator for re-execution
|
|
430
|
-
*
|
|
431
423
|
* @param pendingTxs - The pending transactions to construct the block from
|
|
432
424
|
* @param newGlobalVariables - The global variables for the new block
|
|
433
|
-
* @param historicalHeader - The historical header of the parent
|
|
434
425
|
* @param opts - Whether to just validate the block as a validator, as opposed to building it as a proposal
|
|
435
426
|
*/
|
|
436
427
|
protected async buildBlock(
|
|
@@ -509,7 +500,7 @@ export class Sequencer {
|
|
|
509
500
|
maxBlockGas: this.maxBlockGas,
|
|
510
501
|
};
|
|
511
502
|
const limits = opts.validateOnly ? { deadline } : { deadline, ...proposerLimits };
|
|
512
|
-
const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() =>
|
|
503
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
|
|
513
504
|
processor.process(pendingTxs, limits, validator),
|
|
514
505
|
);
|
|
515
506
|
|
|
@@ -553,6 +544,7 @@ export class Sequencer {
|
|
|
553
544
|
numTxs: processedTxs.length,
|
|
554
545
|
numFailedTxs: failedTxs.length,
|
|
555
546
|
blockBuildingTimer,
|
|
547
|
+
usedTxs,
|
|
556
548
|
};
|
|
557
549
|
} finally {
|
|
558
550
|
// We create a fresh processor each time to reset any cached state (eg storage writes)
|
|
@@ -571,6 +563,31 @@ export class Sequencer {
|
|
|
571
563
|
}
|
|
572
564
|
}
|
|
573
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Build a block from a proposal. Used by the validator to re-execute transactions.
|
|
568
|
+
*
|
|
569
|
+
* @param blockNumber - The block number of the proposal.
|
|
570
|
+
* @param header - The header of the proposal.
|
|
571
|
+
* @param pendingTxs - The pending transactions to construct the block from.
|
|
572
|
+
* @param opts - Whether to just validate the block as a validator, as opposed to building it as a proposal.
|
|
573
|
+
*/
|
|
574
|
+
async buildBlockFromProposal(
|
|
575
|
+
blockNumber: Fr,
|
|
576
|
+
header: ProposedBlockHeader,
|
|
577
|
+
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
578
|
+
opts: { validateOnly?: boolean } = {},
|
|
579
|
+
) {
|
|
580
|
+
const { chainId, version } = await this.globalsBuilder.getGlobalConstantVariables();
|
|
581
|
+
const globalVariables = GlobalVariables.from({
|
|
582
|
+
...header,
|
|
583
|
+
blockNumber,
|
|
584
|
+
timestamp: new Fr(header.timestamp),
|
|
585
|
+
chainId,
|
|
586
|
+
version,
|
|
587
|
+
});
|
|
588
|
+
return await this.buildBlock(pendingTxs, globalVariables, opts);
|
|
589
|
+
}
|
|
590
|
+
|
|
574
591
|
/**
|
|
575
592
|
* @notice Build and propose a block to the chain
|
|
576
593
|
*
|
|
@@ -580,18 +597,18 @@ export class Sequencer {
|
|
|
580
597
|
* @param pendingTxs - Iterable of pending transactions to construct the block from
|
|
581
598
|
* @param proposalHeader - The partial header constructed for the proposal
|
|
582
599
|
*/
|
|
583
|
-
@trackSpan('Sequencer.buildBlockAndEnqueuePublish', (_validTxs,
|
|
584
|
-
[Attributes.BLOCK_NUMBER]:
|
|
600
|
+
@trackSpan('Sequencer.buildBlockAndEnqueuePublish', (_validTxs, _proposalHeader, newGlobalVariables) => ({
|
|
601
|
+
[Attributes.BLOCK_NUMBER]: newGlobalVariables.blockNumber.toNumber(),
|
|
585
602
|
}))
|
|
586
603
|
private async buildBlockAndEnqueuePublish(
|
|
587
604
|
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
588
|
-
proposalHeader:
|
|
605
|
+
proposalHeader: ProposedBlockHeader,
|
|
606
|
+
newGlobalVariables: GlobalVariables,
|
|
589
607
|
): Promise<void> {
|
|
590
608
|
await this.publisher.validateBlockForSubmission(proposalHeader);
|
|
591
609
|
|
|
592
|
-
const newGlobalVariables = proposalHeader.globalVariables;
|
|
593
610
|
const blockNumber = newGlobalVariables.blockNumber.toNumber();
|
|
594
|
-
const slot =
|
|
611
|
+
const slot = proposalHeader.slotNumber.toBigInt();
|
|
595
612
|
|
|
596
613
|
// this.metrics.recordNewBlock(blockNumber, validTxs.length);
|
|
597
614
|
const workTimer = new Timer();
|
|
@@ -599,12 +616,12 @@ export class Sequencer {
|
|
|
599
616
|
|
|
600
617
|
try {
|
|
601
618
|
const buildBlockRes = await this.buildBlock(pendingTxs, newGlobalVariables);
|
|
602
|
-
const { publicGas, block, publicProcessorDuration, numTxs, numMsgs, blockBuildingTimer } = buildBlockRes;
|
|
619
|
+
const { publicGas, block, publicProcessorDuration, numTxs, numMsgs, blockBuildingTimer, usedTxs } = buildBlockRes;
|
|
603
620
|
this.metrics.recordBuiltBlock(workTimer.ms(), publicGas.l2Gas);
|
|
604
621
|
|
|
605
622
|
// TODO(@PhilWindle) We should probably periodically check for things like another
|
|
606
623
|
// block being published before ours instead of just waiting on our block
|
|
607
|
-
await this.publisher.validateBlockForSubmission(block.header);
|
|
624
|
+
await this.publisher.validateBlockForSubmission(block.header.toPropose());
|
|
608
625
|
|
|
609
626
|
const blockStats: L2BlockBuiltStats = {
|
|
610
627
|
eventName: 'l2-block-built',
|
|
@@ -631,7 +648,7 @@ export class Sequencer {
|
|
|
631
648
|
|
|
632
649
|
this.log.debug('Collecting attestations');
|
|
633
650
|
const stopCollectingAttestationsTimer = this.metrics.startCollectingAttestationsTimer();
|
|
634
|
-
const attestations = await this.collectAttestations(block,
|
|
651
|
+
const attestations = await this.collectAttestations(block, usedTxs);
|
|
635
652
|
if (attestations !== undefined) {
|
|
636
653
|
this.log.verbose(`Collected ${attestations.length} attestations`, { blockHash, blockNumber });
|
|
637
654
|
}
|
|
@@ -649,7 +666,7 @@ export class Sequencer {
|
|
|
649
666
|
[Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
|
|
650
667
|
[Attributes.BLOCK_TXS_COUNT]: txHashes.length,
|
|
651
668
|
}))
|
|
652
|
-
protected async collectAttestations(block: L2Block,
|
|
669
|
+
protected async collectAttestations(block: L2Block, txs: Tx[]): Promise<Signature[] | undefined> {
|
|
653
670
|
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/7962): inefficient to have a round trip in here - this should be cached
|
|
654
671
|
const committee = await this.publisher.getCurrentEpochCommittee();
|
|
655
672
|
|
|
@@ -671,14 +688,22 @@ export class Sequencer {
|
|
|
671
688
|
this.setState(SequencerState.COLLECTING_ATTESTATIONS, slotNumber);
|
|
672
689
|
|
|
673
690
|
this.log.debug('Creating block proposal for validators');
|
|
674
|
-
const
|
|
691
|
+
const blockProposalOptions: BlockProposalOptions = { publishFullTxs: !!this.config.publishTxsWithProposals };
|
|
692
|
+
const proposal = await this.validatorClient.createBlockProposal(
|
|
693
|
+
block.header.globalVariables.blockNumber,
|
|
694
|
+
block.header.toPropose(),
|
|
695
|
+
block.archive.root,
|
|
696
|
+
block.header.state,
|
|
697
|
+
txs,
|
|
698
|
+
blockProposalOptions,
|
|
699
|
+
);
|
|
675
700
|
if (!proposal) {
|
|
676
701
|
const msg = `Failed to create block proposal`;
|
|
677
702
|
throw new Error(msg);
|
|
678
703
|
}
|
|
679
704
|
|
|
680
705
|
this.log.debug('Broadcasting block proposal to validators');
|
|
681
|
-
this.validatorClient.broadcastBlockProposal(proposal);
|
|
706
|
+
await this.validatorClient.broadcastBlockProposal(proposal);
|
|
682
707
|
|
|
683
708
|
const attestationTimeAllowed = this.enforceTimeTable
|
|
684
709
|
? this.timetable.getMaxAllowedTime(SequencerState.PUBLISHING_BLOCK)!
|
|
@@ -3,6 +3,11 @@ import { createLogger } from '@aztec/aztec.js';
|
|
|
3
3
|
import type { SequencerMetrics } from './metrics.js';
|
|
4
4
|
import { SequencerState } from './utils.js';
|
|
5
5
|
|
|
6
|
+
const MIN_EXECUTION_TIME = 1;
|
|
7
|
+
const BLOCK_PREPARE_TIME = 1;
|
|
8
|
+
const BLOCK_VALIDATION_TIME = 1;
|
|
9
|
+
const ATTESTATION_PROPAGATION_TIME = 2;
|
|
10
|
+
|
|
6
11
|
export class SequencerTimetable {
|
|
7
12
|
/**
|
|
8
13
|
* How late into the slot can we be to start working. Computed as the total time needed for assembling and publishing a block,
|
|
@@ -19,16 +24,16 @@ export class SequencerTimetable {
|
|
|
19
24
|
public readonly l1PublishingTime;
|
|
20
25
|
|
|
21
26
|
/** What's the minimum time we want to leave available for execution and reexecution (used to derive init deadline) */
|
|
22
|
-
public readonly minExecutionTime =
|
|
27
|
+
public readonly minExecutionTime: number = MIN_EXECUTION_TIME;
|
|
23
28
|
|
|
24
29
|
/** How long it takes to get ready to start building */
|
|
25
|
-
public readonly blockPrepareTime =
|
|
30
|
+
public readonly blockPrepareTime: number = BLOCK_PREPARE_TIME;
|
|
26
31
|
|
|
27
32
|
/** How long it takes to for proposals and attestations to travel across the p2p layer (one-way) */
|
|
28
|
-
public readonly attestationPropagationTime =
|
|
33
|
+
public readonly attestationPropagationTime: number = ATTESTATION_PROPAGATION_TIME;
|
|
29
34
|
|
|
30
35
|
/** How much time we spend validating and processing a block after building it, and assembling the proposal to send to attestors */
|
|
31
|
-
public readonly blockValidationTime =
|
|
36
|
+
public readonly blockValidationTime: number = BLOCK_VALIDATION_TIME;
|
|
32
37
|
|
|
33
38
|
constructor(
|
|
34
39
|
private readonly ethereumSlotDuration: number,
|
|
@@ -40,6 +45,13 @@ export class SequencerTimetable {
|
|
|
40
45
|
) {
|
|
41
46
|
this.l1PublishingTime = this.ethereumSlotDuration - this.maxL1TxInclusionTimeIntoSlot;
|
|
42
47
|
|
|
48
|
+
// Assume zero-cost propagation time and faster runs in test environments where L1 slot duration is shortened
|
|
49
|
+
if (this.ethereumSlotDuration < 8) {
|
|
50
|
+
this.attestationPropagationTime = 0;
|
|
51
|
+
this.blockValidationTime = 0.5;
|
|
52
|
+
this.blockPrepareTime = 0.5;
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
const allWorkToDo =
|
|
44
56
|
this.blockPrepareTime +
|
|
45
57
|
this.minExecutionTime * 2 +
|
|
@@ -154,7 +154,7 @@ export class SlasherClient extends WithTracer {
|
|
|
154
154
|
|
|
155
155
|
public handleBlockStreamEvent(event: L2BlockSourceEvent): Promise<void> {
|
|
156
156
|
this.log.debug(`Handling block stream event ${event.type}`);
|
|
157
|
-
switch (event.type) {
|
|
157
|
+
switch (event.type as L2BlockSourceEvents) {
|
|
158
158
|
case L2BlockSourceEvents.L2PruneDetected:
|
|
159
159
|
this.handlePruneL2Blocks(event);
|
|
160
160
|
break;
|
package/src/test/index.ts
CHANGED
|
@@ -6,15 +6,15 @@ import { Sequencer } from '../sequencer/sequencer.js';
|
|
|
6
6
|
import type { SequencerTimetable } from '../sequencer/timetable.js';
|
|
7
7
|
|
|
8
8
|
class TestSequencer_ extends Sequencer {
|
|
9
|
-
public
|
|
10
|
-
public
|
|
11
|
-
public
|
|
9
|
+
declare public publicProcessorFactory: PublicProcessorFactory;
|
|
10
|
+
declare public timetable: SequencerTimetable;
|
|
11
|
+
declare public publisher: SequencerPublisher;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export type TestSequencer = TestSequencer_;
|
|
15
15
|
|
|
16
16
|
class TestSequencerClient_ extends SequencerClient {
|
|
17
|
-
public
|
|
17
|
+
declare public sequencer: TestSequencer;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export type TestSequencerClient = TestSequencerClient_;
|