@aztec/validator-client 0.0.1-commit.3469e52 → 0.0.1-commit.3895657bc
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/README.md +64 -19
- package/dest/block_proposal_handler.d.ts +7 -9
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +71 -81
- package/dest/checkpoint_builder.d.ts +22 -13
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +107 -39
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +30 -7
- package/dest/duties/validation_service.d.ts +2 -2
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +5 -11
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +2 -1
- package/dest/index.d.ts +1 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +0 -1
- package/dest/key_store/ha_key_store.d.ts +1 -1
- package/dest/key_store/ha_key_store.d.ts.map +1 -1
- package/dest/key_store/ha_key_store.js +2 -2
- package/dest/metrics.d.ts +12 -3
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +46 -5
- package/dest/validator.d.ts +40 -14
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +212 -56
- package/package.json +19 -17
- package/src/block_proposal_handler.ts +87 -109
- package/src/checkpoint_builder.ts +146 -40
- package/src/config.ts +30 -7
- package/src/duties/validation_service.ts +11 -10
- package/src/factory.ts +1 -0
- package/src/index.ts +0 -1
- package/src/key_store/ha_key_store.ts +2 -2
- package/src/metrics.ts +63 -6
- package/src/validator.ts +262 -68
- package/dest/tx_validator/index.d.ts +0 -3
- package/dest/tx_validator/index.d.ts.map +0 -1
- package/dest/tx_validator/index.js +0 -2
- 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 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -54
- package/src/tx_validator/index.ts +0 -2
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -135
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.3895657bc",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,28 +64,30 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
68
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
69
|
-
"@aztec/constants": "0.0.1-commit.
|
|
70
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
71
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
72
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
73
|
-
"@aztec/node-keystore": "0.0.1-commit.
|
|
74
|
-
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.
|
|
75
|
-
"@aztec/p2p": "0.0.1-commit.
|
|
76
|
-
"@aztec/protocol-contracts": "0.0.1-commit.
|
|
77
|
-
"@aztec/prover-client": "0.0.1-commit.
|
|
78
|
-
"@aztec/simulator": "0.0.1-commit.
|
|
79
|
-
"@aztec/slasher": "0.0.1-commit.
|
|
80
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
81
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
82
|
-
"@aztec/validator-ha-signer": "0.0.1-commit.
|
|
67
|
+
"@aztec/blob-client": "0.0.1-commit.3895657bc",
|
|
68
|
+
"@aztec/blob-lib": "0.0.1-commit.3895657bc",
|
|
69
|
+
"@aztec/constants": "0.0.1-commit.3895657bc",
|
|
70
|
+
"@aztec/epoch-cache": "0.0.1-commit.3895657bc",
|
|
71
|
+
"@aztec/ethereum": "0.0.1-commit.3895657bc",
|
|
72
|
+
"@aztec/foundation": "0.0.1-commit.3895657bc",
|
|
73
|
+
"@aztec/node-keystore": "0.0.1-commit.3895657bc",
|
|
74
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.3895657bc",
|
|
75
|
+
"@aztec/p2p": "0.0.1-commit.3895657bc",
|
|
76
|
+
"@aztec/protocol-contracts": "0.0.1-commit.3895657bc",
|
|
77
|
+
"@aztec/prover-client": "0.0.1-commit.3895657bc",
|
|
78
|
+
"@aztec/simulator": "0.0.1-commit.3895657bc",
|
|
79
|
+
"@aztec/slasher": "0.0.1-commit.3895657bc",
|
|
80
|
+
"@aztec/stdlib": "0.0.1-commit.3895657bc",
|
|
81
|
+
"@aztec/telemetry-client": "0.0.1-commit.3895657bc",
|
|
82
|
+
"@aztec/validator-ha-signer": "0.0.1-commit.3895657bc",
|
|
83
83
|
"koa": "^2.16.1",
|
|
84
84
|
"koa-router": "^13.1.1",
|
|
85
85
|
"tslib": "^2.4.0",
|
|
86
86
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
+
"@aztec/archiver": "0.0.1-commit.3895657bc",
|
|
90
|
+
"@aztec/world-state": "0.0.1-commit.3895657bc",
|
|
89
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
90
92
|
"@jest/globals": "^30.0.0",
|
|
91
93
|
"@types/jest": "^30.0.0",
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
2
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
3
3
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { pick } from '@aztec/foundation/collection';
|
|
4
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
6
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
6
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
8
9
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
9
10
|
import type { P2P, PeerId } from '@aztec/p2p';
|
|
10
|
-
import { TxProvider } from '@aztec/p2p';
|
|
11
11
|
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
12
|
-
import type {
|
|
12
|
+
import type { BlockData, L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
13
13
|
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
computeCheckpointOutHash,
|
|
18
|
-
computeInHashFromL1ToL2Messages,
|
|
19
|
-
} from '@aztec/stdlib/messaging';
|
|
14
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
15
|
+
import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
16
|
+
import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
20
17
|
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
21
|
-
import {
|
|
18
|
+
import type { CheckpointGlobalVariables, FailedTx, Tx } from '@aztec/stdlib/tx';
|
|
22
19
|
import {
|
|
23
20
|
ReExFailedTxsError,
|
|
24
21
|
ReExStateMismatchError,
|
|
@@ -44,7 +41,7 @@ export type BlockProposalValidationFailureReason =
|
|
|
44
41
|
| 'unknown_error';
|
|
45
42
|
|
|
46
43
|
type ReexecuteTransactionsResult = {
|
|
47
|
-
block:
|
|
44
|
+
block: L2Block;
|
|
48
45
|
failedTxs: FailedTx[];
|
|
49
46
|
reexecutionTimeMs: number;
|
|
50
47
|
totalManaUsed: number;
|
|
@@ -77,7 +74,7 @@ export class BlockProposalHandler {
|
|
|
77
74
|
private worldState: WorldStateSynchronizer,
|
|
78
75
|
private blockSource: L2BlockSource & L2BlockSink,
|
|
79
76
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
80
|
-
private txProvider:
|
|
77
|
+
private txProvider: ITxProvider,
|
|
81
78
|
private blockProposalValidator: BlockProposalValidator,
|
|
82
79
|
private epochCache: EpochCache,
|
|
83
80
|
private config: ValidatorClientFullConfig,
|
|
@@ -92,25 +89,28 @@ export class BlockProposalHandler {
|
|
|
92
89
|
this.tracer = telemetry.getTracer('BlockProposalHandler');
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
// Non-validator handler that re-executes for monitoring but does not attest.
|
|
92
|
+
register(p2pClient: P2P, shouldReexecute: boolean): BlockProposalHandler {
|
|
93
|
+
// Non-validator handler that processes or re-executes for monitoring but does not attest.
|
|
97
94
|
// Returns boolean indicating whether the proposal was valid.
|
|
98
95
|
const handler = async (proposal: BlockProposal, proposalSender: PeerId): Promise<boolean> => {
|
|
99
96
|
try {
|
|
100
|
-
const
|
|
97
|
+
const { slotNumber, blockNumber } = proposal;
|
|
98
|
+
const result = await this.handleBlockProposal(proposal, proposalSender, shouldReexecute);
|
|
101
99
|
if (result.isValid) {
|
|
102
|
-
this.log.info(`Non-validator
|
|
100
|
+
this.log.info(`Non-validator block proposal ${blockNumber} at slot ${slotNumber} handled`, {
|
|
103
101
|
blockNumber: result.blockNumber,
|
|
102
|
+
slotNumber,
|
|
104
103
|
reexecutionTimeMs: result.reexecutionResult?.reexecutionTimeMs,
|
|
105
104
|
totalManaUsed: result.reexecutionResult?.totalManaUsed,
|
|
106
105
|
numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0,
|
|
106
|
+
reexecuted: shouldReexecute,
|
|
107
107
|
});
|
|
108
108
|
return true;
|
|
109
109
|
} else {
|
|
110
|
-
this.log.warn(
|
|
111
|
-
blockNumber
|
|
112
|
-
reason: result.reason,
|
|
113
|
-
|
|
110
|
+
this.log.warn(
|
|
111
|
+
`Non-validator block proposal ${blockNumber} at slot ${slotNumber} failed processing with ${result.reason}`,
|
|
112
|
+
{ blockNumber: result.blockNumber, slotNumber, reason: result.reason },
|
|
113
|
+
);
|
|
114
114
|
return false;
|
|
115
115
|
}
|
|
116
116
|
} catch (error) {
|
|
@@ -146,23 +146,23 @@ export class BlockProposalHandler {
|
|
|
146
146
|
|
|
147
147
|
// Check that the proposal is from the current proposer, or the next proposer
|
|
148
148
|
// This should have been handled by the p2p layer, but we double check here out of caution
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
149
|
+
const validationResult = await this.blockProposalValidator.validate(proposal);
|
|
150
|
+
if (validationResult.result !== 'accept') {
|
|
151
151
|
this.log.warn(`Proposal is not valid, skipping processing`, proposalInfo);
|
|
152
152
|
return { isValid: false, reason: 'invalid_proposal' };
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// Check that the parent proposal is a block we know, otherwise reexecution would fail
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
156
|
+
const parentBlock = await this.getParentBlock(proposal);
|
|
157
|
+
if (parentBlock === undefined) {
|
|
158
158
|
this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
|
|
159
159
|
return { isValid: false, reason: 'parent_block_not_found' };
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
// Check that the parent block's slot is
|
|
163
|
-
if (
|
|
164
|
-
this.log.warn(`Parent block slot is greater than
|
|
165
|
-
parentBlockSlot:
|
|
162
|
+
// Check that the parent block's slot is not greater than the proposal's slot.
|
|
163
|
+
if (parentBlock !== 'genesis' && parentBlock.header.getSlot() > slotNumber) {
|
|
164
|
+
this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
|
|
165
|
+
parentBlockSlot: parentBlock.header.getSlot().toString(),
|
|
166
166
|
proposalSlot: slotNumber.toString(),
|
|
167
167
|
...proposalInfo,
|
|
168
168
|
});
|
|
@@ -171,9 +171,9 @@ export class BlockProposalHandler {
|
|
|
171
171
|
|
|
172
172
|
// Compute the block number based on the parent block
|
|
173
173
|
const blockNumber =
|
|
174
|
-
|
|
174
|
+
parentBlock === 'genesis'
|
|
175
175
|
? BlockNumber(INITIAL_L2_BLOCK_NUM)
|
|
176
|
-
: BlockNumber(
|
|
176
|
+
: BlockNumber(parentBlock.header.getBlockNumber() + 1);
|
|
177
177
|
|
|
178
178
|
// Check that this block number does not exist already
|
|
179
179
|
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
@@ -189,8 +189,17 @@ export class BlockProposalHandler {
|
|
|
189
189
|
deadline: this.getReexecutionDeadline(slotNumber, config),
|
|
190
190
|
});
|
|
191
191
|
|
|
192
|
+
// If reexecution is disabled, bail. We are just interested in triggering tx collection.
|
|
193
|
+
if (!shouldReexecute) {
|
|
194
|
+
this.log.info(
|
|
195
|
+
`Received valid block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`,
|
|
196
|
+
proposalInfo,
|
|
197
|
+
);
|
|
198
|
+
return { isValid: true, blockNumber };
|
|
199
|
+
}
|
|
200
|
+
|
|
192
201
|
// Compute the checkpoint number for this block and validate checkpoint consistency
|
|
193
|
-
const checkpointResult =
|
|
202
|
+
const checkpointResult = this.computeCheckpointNumber(proposal, parentBlock, proposalInfo);
|
|
194
203
|
if (checkpointResult.reason) {
|
|
195
204
|
return { isValid: false, blockNumber, reason: checkpointResult.reason };
|
|
196
205
|
}
|
|
@@ -215,53 +224,44 @@ export class BlockProposalHandler {
|
|
|
215
224
|
return { isValid: false, blockNumber, reason: 'txs_not_available' };
|
|
216
225
|
}
|
|
217
226
|
|
|
227
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
228
|
+
const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
|
|
229
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch))
|
|
230
|
+
.filter(c => c.checkpointNumber < checkpointNumber)
|
|
231
|
+
.map(c => c.checkpointOutHash);
|
|
232
|
+
|
|
218
233
|
// Try re-executing the transactions in the proposal if needed
|
|
219
234
|
let reexecutionResult;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const previousCheckpointOutHashes = previousBlocks.map(b =>
|
|
230
|
-
computeCheckpointOutHash([b.body.txEffects.map(tx => tx.l2ToL1Msgs)]),
|
|
235
|
+
try {
|
|
236
|
+
this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
|
|
237
|
+
reexecutionResult = await this.reexecuteTransactions(
|
|
238
|
+
proposal,
|
|
239
|
+
blockNumber,
|
|
240
|
+
checkpointNumber,
|
|
241
|
+
txs,
|
|
242
|
+
l1ToL2Messages,
|
|
243
|
+
previousCheckpointOutHashes,
|
|
231
244
|
);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
proposal,
|
|
237
|
-
blockNumber,
|
|
238
|
-
checkpointNumber,
|
|
239
|
-
txs,
|
|
240
|
-
l1ToL2Messages,
|
|
241
|
-
previousCheckpointOutHashes,
|
|
242
|
-
);
|
|
243
|
-
} catch (error) {
|
|
244
|
-
this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
|
|
245
|
-
const reason = this.getReexecuteFailureReason(error);
|
|
246
|
-
return { isValid: false, blockNumber, reason, reexecutionResult };
|
|
247
|
-
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
|
|
247
|
+
const reason = this.getReexecuteFailureReason(error);
|
|
248
|
+
return { isValid: false, blockNumber, reason, reexecutionResult };
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
// If we succeeded, push this block into the archiver (unless disabled)
|
|
251
|
-
// TODO(palla/mbps): Change default to false once block sync is stable.
|
|
252
252
|
if (reexecutionResult?.block && this.config.skipPushProposedBlocksToArchiver === false) {
|
|
253
253
|
await this.blockSource.addBlock(reexecutionResult?.block);
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
this.log.info(
|
|
257
|
-
`Successfully
|
|
258
|
-
proposalInfo,
|
|
257
|
+
`Successfully re-executed block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`,
|
|
258
|
+
{ ...proposalInfo, ...pick(reexecutionResult, 'reexecutionTimeMs', 'totalManaUsed') },
|
|
259
259
|
);
|
|
260
260
|
|
|
261
261
|
return { isValid: true, blockNumber, reexecutionResult };
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
private async getParentBlock(proposal: BlockProposal): Promise<'genesis' |
|
|
264
|
+
private async getParentBlock(proposal: BlockProposal): Promise<'genesis' | BlockData | undefined> {
|
|
265
265
|
const parentArchive = proposal.blockHeader.lastArchive.root;
|
|
266
266
|
const slot = proposal.slotNumber;
|
|
267
267
|
const config = this.checkpointsBuilder.getConfig();
|
|
@@ -277,12 +277,11 @@ export class BlockProposalHandler {
|
|
|
277
277
|
|
|
278
278
|
try {
|
|
279
279
|
return (
|
|
280
|
-
(await this.blockSource.
|
|
280
|
+
(await this.blockSource.getBlockDataByArchive(parentArchive)) ??
|
|
281
281
|
(timeoutDurationMs <= 0
|
|
282
282
|
? undefined
|
|
283
283
|
: await retryUntil(
|
|
284
|
-
() =>
|
|
285
|
-
this.blockSource.syncImmediate().then(() => this.blockSource.getBlockHeaderByArchive(parentArchive)),
|
|
284
|
+
() => this.blockSource.syncImmediate().then(() => this.blockSource.getBlockDataByArchive(parentArchive)),
|
|
286
285
|
'force archiver sync',
|
|
287
286
|
timeoutDurationMs / 1000,
|
|
288
287
|
0.5,
|
|
@@ -298,12 +297,12 @@ export class BlockProposalHandler {
|
|
|
298
297
|
}
|
|
299
298
|
}
|
|
300
299
|
|
|
301
|
-
private
|
|
300
|
+
private computeCheckpointNumber(
|
|
302
301
|
proposal: BlockProposal,
|
|
303
|
-
|
|
302
|
+
parentBlock: 'genesis' | BlockData,
|
|
304
303
|
proposalInfo: object,
|
|
305
|
-
):
|
|
306
|
-
if (
|
|
304
|
+
): CheckpointComputationResult {
|
|
305
|
+
if (parentBlock === 'genesis') {
|
|
307
306
|
// First block is in checkpoint 1
|
|
308
307
|
if (proposal.indexWithinCheckpoint !== 0) {
|
|
309
308
|
this.log.warn(`First block proposal has non-zero indexWithinCheckpoint`, proposalInfo);
|
|
@@ -312,19 +311,9 @@ export class BlockProposalHandler {
|
|
|
312
311
|
return { checkpointNumber: CheckpointNumber.INITIAL };
|
|
313
312
|
}
|
|
314
313
|
|
|
315
|
-
// Get the parent block to find its checkpoint number
|
|
316
|
-
// TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
|
|
317
|
-
// or at least the L2BlockSource should return a different struct that includes it.
|
|
318
|
-
const parentBlockNumber = parentBlockHeader.getBlockNumber();
|
|
319
|
-
const parentBlock = await this.blockSource.getL2BlockNew(parentBlockNumber);
|
|
320
|
-
if (!parentBlock) {
|
|
321
|
-
this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
|
|
322
|
-
return { reason: 'invalid_proposal' };
|
|
323
|
-
}
|
|
324
|
-
|
|
325
314
|
if (proposal.indexWithinCheckpoint === 0) {
|
|
326
315
|
// If this is the first block in a new checkpoint, increment the checkpoint number
|
|
327
|
-
if (!(proposal.blockHeader.getSlot() >
|
|
316
|
+
if (!(proposal.blockHeader.getSlot() > parentBlock.header.getSlot())) {
|
|
328
317
|
this.log.warn(`Slot should be greater than parent block slot for first block in checkpoint`, proposalInfo);
|
|
329
318
|
return { reason: 'invalid_proposal' };
|
|
330
319
|
}
|
|
@@ -336,7 +325,7 @@ export class BlockProposalHandler {
|
|
|
336
325
|
this.log.warn(`Non-sequential indexWithinCheckpoint`, proposalInfo);
|
|
337
326
|
return { reason: 'invalid_proposal' };
|
|
338
327
|
}
|
|
339
|
-
if (proposal.blockHeader.getSlot() !==
|
|
328
|
+
if (proposal.blockHeader.getSlot() !== parentBlock.header.getSlot()) {
|
|
340
329
|
this.log.warn(`Slot should be equal to parent block slot for non-first block in checkpoint`, proposalInfo);
|
|
341
330
|
return { reason: 'invalid_proposal' };
|
|
342
331
|
}
|
|
@@ -357,7 +346,7 @@ export class BlockProposalHandler {
|
|
|
357
346
|
*/
|
|
358
347
|
private validateNonFirstBlockInCheckpoint(
|
|
359
348
|
proposal: BlockProposal,
|
|
360
|
-
parentBlock:
|
|
349
|
+
parentBlock: BlockData,
|
|
361
350
|
proposalInfo: object,
|
|
362
351
|
): CheckpointComputationResult | undefined {
|
|
363
352
|
const proposalGlobals = proposal.blockHeader.globalVariables;
|
|
@@ -436,29 +425,6 @@ export class BlockProposalHandler {
|
|
|
436
425
|
return new Date(nextSlotTimestampSeconds * 1000);
|
|
437
426
|
}
|
|
438
427
|
|
|
439
|
-
/**
|
|
440
|
-
* Gets all prior blocks in the same checkpoint (same slot and checkpoint number) up to but not including upToBlockNumber.
|
|
441
|
-
*/
|
|
442
|
-
private async getBlocksInCheckpoint(
|
|
443
|
-
slot: SlotNumber,
|
|
444
|
-
upToBlockNumber: BlockNumber,
|
|
445
|
-
checkpointNumber: CheckpointNumber,
|
|
446
|
-
): Promise<L2BlockNew[]> {
|
|
447
|
-
const blocks: L2BlockNew[] = [];
|
|
448
|
-
let currentBlockNumber = BlockNumber(upToBlockNumber - 1);
|
|
449
|
-
|
|
450
|
-
while (currentBlockNumber >= INITIAL_L2_BLOCK_NUM) {
|
|
451
|
-
const block = await this.blockSource.getL2BlockNew(currentBlockNumber);
|
|
452
|
-
if (!block || block.header.getSlot() !== slot || block.checkpointNumber !== checkpointNumber) {
|
|
453
|
-
break;
|
|
454
|
-
}
|
|
455
|
-
blocks.unshift(block);
|
|
456
|
-
currentBlockNumber = BlockNumber(currentBlockNumber - 1);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
return blocks;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
428
|
private getReexecuteFailureReason(err: any) {
|
|
463
429
|
if (err instanceof ReExStateMismatchError) {
|
|
464
430
|
return 'state_mismatch';
|
|
@@ -492,18 +458,21 @@ export class BlockProposalHandler {
|
|
|
492
458
|
const slot = proposal.slotNumber;
|
|
493
459
|
const config = this.checkpointsBuilder.getConfig();
|
|
494
460
|
|
|
495
|
-
// Get prior blocks in this checkpoint (same slot
|
|
496
|
-
const
|
|
461
|
+
// Get prior blocks in this checkpoint (same slot before current block)
|
|
462
|
+
const allBlocksInSlot = await this.blockSource.getBlocksForSlot(slot);
|
|
463
|
+
const priorBlocks = allBlocksInSlot.filter(b => b.number < blockNumber && b.header.getSlot() === slot);
|
|
497
464
|
|
|
498
465
|
// Fork before the block to be built
|
|
499
466
|
const parentBlockNumber = BlockNumber(blockNumber - 1);
|
|
500
|
-
|
|
467
|
+
await this.worldState.syncImmediate(parentBlockNumber);
|
|
468
|
+
await using fork = await this.worldState.fork(parentBlockNumber);
|
|
501
469
|
|
|
502
|
-
// Build checkpoint constants from proposal (excludes blockNumber
|
|
470
|
+
// Build checkpoint constants from proposal (excludes blockNumber which is per-block)
|
|
503
471
|
const constants: CheckpointGlobalVariables = {
|
|
504
472
|
chainId: new Fr(config.l1ChainId),
|
|
505
473
|
version: new Fr(config.rollupVersion),
|
|
506
474
|
slotNumber: slot,
|
|
475
|
+
timestamp: blockHeader.globalVariables.timestamp,
|
|
507
476
|
coinbase: blockHeader.globalVariables.coinbase,
|
|
508
477
|
feeRecipient: blockHeader.globalVariables.feeRecipient,
|
|
509
478
|
gasFees: blockHeader.globalVariables.gasFees,
|
|
@@ -513,26 +482,35 @@ export class BlockProposalHandler {
|
|
|
513
482
|
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(
|
|
514
483
|
checkpointNumber,
|
|
515
484
|
constants,
|
|
485
|
+
0n, // only takes effect in the following checkpoint.
|
|
516
486
|
l1ToL2Messages,
|
|
517
487
|
previousCheckpointOutHashes,
|
|
518
488
|
fork,
|
|
519
489
|
priorBlocks,
|
|
490
|
+
this.log.getBindings(),
|
|
520
491
|
);
|
|
521
492
|
|
|
522
493
|
// Build the new block
|
|
523
494
|
const deadline = this.getReexecutionDeadline(slot, config);
|
|
495
|
+
const maxBlockGas =
|
|
496
|
+
this.config.validateMaxL2BlockGas !== undefined || this.config.validateMaxDABlockGas !== undefined
|
|
497
|
+
? new Gas(this.config.validateMaxDABlockGas ?? Infinity, this.config.validateMaxL2BlockGas ?? Infinity)
|
|
498
|
+
: undefined;
|
|
524
499
|
const result = await checkpointBuilder.buildBlock(txs, blockNumber, blockHeader.globalVariables.timestamp, {
|
|
525
500
|
deadline,
|
|
526
501
|
expectedEndState: blockHeader.state,
|
|
502
|
+
maxTransactions: this.config.validateMaxTxsPerBlock,
|
|
503
|
+
maxBlockGas,
|
|
527
504
|
});
|
|
528
505
|
|
|
529
506
|
const { block, failedTxs } = result;
|
|
530
507
|
const numFailedTxs = failedTxs.length;
|
|
531
508
|
|
|
532
|
-
this.log.verbose(`
|
|
509
|
+
this.log.verbose(`Block proposal ${blockNumber} at slot ${slot} transaction re-execution complete`, {
|
|
533
510
|
numFailedTxs,
|
|
534
511
|
numProposalTxs: txHashes.length,
|
|
535
512
|
numProcessedTxs: block.body.txEffects.length,
|
|
513
|
+
blockNumber,
|
|
536
514
|
slot,
|
|
537
515
|
});
|
|
538
516
|
|