@aztec/slasher 0.0.1-commit.6d63667d → 0.0.1-commit.86469d5
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import {
|
|
2
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { L2Block, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
|
|
4
|
-
import type { ICheckpointsBuilder, ITxProvider, SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
4
|
+
import type { ICheckpointsBuilder, ITxProvider, MerkleTreeWriteOperations, SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
5
5
|
import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
6
6
|
import { type Watcher, type WatcherEmitter } from '../watcher.js';
|
|
7
7
|
declare const EpochPruneWatcherPenaltiesConfigKeys: readonly ["slashPrunePenalty", "slashDataWithholdingPenalty"];
|
|
@@ -29,11 +29,10 @@ export declare class EpochPruneWatcher extends EpochPruneWatcher_base implements
|
|
|
29
29
|
private handlePruneL2Blocks;
|
|
30
30
|
private emitSlashForEpoch;
|
|
31
31
|
private processPruneL2Blocks;
|
|
32
|
-
validateBlocks(blocks: L2Block[]
|
|
33
|
-
|
|
34
|
-
private validateBlockInCheckpoint;
|
|
32
|
+
validateBlocks(blocks: L2Block[]): Promise<void>;
|
|
33
|
+
validateBlock(blockFromL1: L2Block, previousCheckpointOutHashes: Fr[], fork: MerkleTreeWriteOperations): Promise<void>;
|
|
35
34
|
private getValidatorsForEpoch;
|
|
36
35
|
private validatorsToSlashingArgs;
|
|
37
36
|
}
|
|
38
37
|
export {};
|
|
39
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBR2hELE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXpELE9BQU8sRUFFTCxPQUFPLEVBQ1AsS0FBSyx5QkFBeUIsRUFHL0IsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEtBQUssRUFDVixtQkFBbUIsRUFDbkIsV0FBVyxFQUNYLHlCQUF5QixFQUN6QixhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxtQkFBbUIsRUFBNEIsTUFBTSx5QkFBeUIsQ0FBQztBQVk3RixPQUFPLEVBQTZDLEtBQUssT0FBTyxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdHLFFBQUEsTUFBTSxvQ0FBb0MsK0RBQWdFLENBQUM7QUFFM0csS0FBSywwQkFBMEIsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsT0FBTyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7O0FBRTdHOzs7OztHQUtHO0FBQ0gscUJBQWEsaUJBQWtCLFNBQVEsc0JBQTJDLFlBQVcsT0FBTztJQVNoRyxPQUFPLENBQUMsYUFBYTtJQUNyQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxrQkFBa0I7SUFaNUIsT0FBTyxDQUFDLEdBQUcsQ0FBK0M7SUFHMUQsT0FBTyxDQUFDLHdCQUF3QixDQUF1QztJQUV2RSxPQUFPLENBQUMsU0FBUyxDQUE2QjtJQUU5QyxZQUNVLGFBQWEsRUFBRSx5QkFBeUIsRUFDeEMsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLGlCQUFpQixDQUFDLEVBQ2hELGtCQUFrQixFQUFFLG1CQUFtQixFQUMvQyxTQUFTLEVBQUUsMEJBQTBCLEVBT3RDO0lBRU0sS0FBSyxrQkFHWDtJQUVNLElBQUksa0JBR1Y7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBR3hEO0lBRUQsT0FBTyxDQUFDLG1CQUFtQjtZQU9iLGlCQUFpQjtZQVdqQixvQkFBb0I7SUF3QnJCLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWtCNUQ7SUFFWSxhQUFhLENBQ3hCLFdBQVcsRUFBRSxPQUFPLEVBQ3BCLDJCQUEyQixFQUFFLEVBQUUsRUFBRSxFQUNqQyxJQUFJLEVBQUUseUJBQXlCLEdBQzlCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0E4Q2Y7WUFFYSxxQkFBcUI7SUFTbkMsT0FBTyxDQUFDLHdCQUF3QjtDQWdCakMifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEzD,OAAO,EAEL,OAAO,EACP,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,yBAAyB,CAAC;AAY7F,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,oCAAoC,+DAAgE,CAAC;AAE3G,KAAK,0BAA0B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE7G;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAZ5B,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,wBAAwB,CAAuC;IAEvE,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACU,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,kBAAkB,EAAE,mBAAmB,EAC/C,SAAS,EAAE,0BAA0B,EAOtC;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAGV;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAGxD;IAED,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAWjB,oBAAoB;IAwBrB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB5D;IAEY,aAAa,CACxB,WAAW,EAAE,OAAO,EACpB,2BAA2B,EAAE,EAAE,EAAE,EACjC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA8Cf;YAEa,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import {
|
|
1
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { merge, pick } from '@aztec/foundation/collection';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { L2BlockSourceEvents } from '@aztec/stdlib/block';
|
|
5
5
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -67,7 +67,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
67
67
|
this.log.info(`Detected chain prune. Validating epoch ${epochNumber} with blocks ${epochBlocks[0]?.number} to ${epochBlocks[epochBlocks.length - 1]?.number}.`, {
|
|
68
68
|
blocks: epochBlocks.map((b)=>b.toBlockInfo())
|
|
69
69
|
});
|
|
70
|
-
await this.validateBlocks(epochBlocks
|
|
70
|
+
await this.validateBlocks(epochBlocks);
|
|
71
71
|
this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
|
|
72
72
|
await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
|
|
73
73
|
} catch (error) {
|
|
@@ -81,26 +81,19 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
async validateBlocks(blocks
|
|
84
|
+
async validateBlocks(blocks) {
|
|
85
85
|
if (blocks.length === 0) {
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
...blocks
|
|
91
|
-
].sort((a, b)=>a.number - b.number);
|
|
92
|
-
const blocksByCheckpoint = chunkBy(sortedBlocks, (b)=>b.checkpointNumber);
|
|
93
|
-
// Get prior checkpoints in the epoch (in case this was a partial prune) to extract the out hashes
|
|
94
|
-
const priorCheckpointOutHashes = (await this.l2BlockSource.getCheckpointsForEpoch(epochNumber)).filter((c)=>c.number < sortedBlocks[0].checkpointNumber).map((c)=>c.getCheckpointOutHash());
|
|
95
|
-
let previousCheckpointOutHashes = [
|
|
96
|
-
...priorCheckpointOutHashes
|
|
97
|
-
];
|
|
98
|
-
const fork = await this.checkpointsBuilder.getFork(BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1));
|
|
88
|
+
let previousCheckpointOutHashes = [];
|
|
89
|
+
const fork = await this.checkpointsBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
|
|
99
90
|
try {
|
|
100
|
-
for (const
|
|
101
|
-
await this.
|
|
102
|
-
//
|
|
103
|
-
const checkpointOutHash = computeCheckpointOutHash(
|
|
91
|
+
for (const block of blocks){
|
|
92
|
+
await this.validateBlock(block, previousCheckpointOutHashes, fork);
|
|
93
|
+
// TODO(mbps): This assumes one block per checkpoint, which is only true for now.
|
|
94
|
+
const checkpointOutHash = computeCheckpointOutHash([
|
|
95
|
+
block.body.txEffects.map((tx)=>tx.l2ToL1Msgs)
|
|
96
|
+
]);
|
|
104
97
|
previousCheckpointOutHashes = [
|
|
105
98
|
...previousCheckpointOutHashes,
|
|
106
99
|
checkpointOutHash
|
|
@@ -110,29 +103,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
110
103
|
await fork.close();
|
|
111
104
|
}
|
|
112
105
|
}
|
|
113
|
-
async
|
|
114
|
-
const checkpointNumber = checkpointBlocks[0].checkpointNumber;
|
|
115
|
-
this.log.debug(`Validating pruned checkpoint ${checkpointNumber} with ${checkpointBlocks.length} blocks`);
|
|
116
|
-
// Get L1ToL2Messages once for the entire checkpoint
|
|
117
|
-
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
118
|
-
// Build checkpoint constants from first block's global variables
|
|
119
|
-
const gv = checkpointBlocks[0].header.globalVariables;
|
|
120
|
-
const constants = {
|
|
121
|
-
chainId: gv.chainId,
|
|
122
|
-
version: gv.version,
|
|
123
|
-
slotNumber: gv.slotNumber,
|
|
124
|
-
coinbase: gv.coinbase,
|
|
125
|
-
feeRecipient: gv.feeRecipient,
|
|
126
|
-
gasFees: gv.gasFees
|
|
127
|
-
};
|
|
128
|
-
// Start checkpoint builder once for all blocks in this checkpoint
|
|
129
|
-
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
|
|
130
|
-
// Validate all blocks in the checkpoint sequentially
|
|
131
|
-
for (const block of checkpointBlocks){
|
|
132
|
-
await this.validateBlockInCheckpoint(block, checkpointBuilder);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
async validateBlockInCheckpoint(blockFromL1, checkpointBuilder) {
|
|
106
|
+
async validateBlock(blockFromL1, previousCheckpointOutHashes, fork) {
|
|
136
107
|
this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
|
|
137
108
|
const txHashes = blockFromL1.body.txEffects.map((txEffect)=>txEffect.txHash);
|
|
138
109
|
// We load txs from the mempool directly, since the TxCollector running in the background has already been
|
|
@@ -142,7 +113,19 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
142
113
|
if (missingTxs && missingTxs.length > 0) {
|
|
143
114
|
throw new TransactionsNotAvailableError(missingTxs);
|
|
144
115
|
}
|
|
116
|
+
const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
|
|
117
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
145
118
|
const gv = blockFromL1.header.globalVariables;
|
|
119
|
+
const constants = {
|
|
120
|
+
chainId: gv.chainId,
|
|
121
|
+
version: gv.version,
|
|
122
|
+
slotNumber: gv.slotNumber,
|
|
123
|
+
coinbase: gv.coinbase,
|
|
124
|
+
feeRecipient: gv.feeRecipient,
|
|
125
|
+
gasFees: gv.gasFees
|
|
126
|
+
};
|
|
127
|
+
// Use checkpoint builder to validate the block
|
|
128
|
+
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
|
|
146
129
|
const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {});
|
|
147
130
|
if (numTxs !== txs.length) {
|
|
148
131
|
// This should be detected by state mismatch, but this makes it easier to debug.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/slasher",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.86469d5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -56,20 +56,20 @@
|
|
|
56
56
|
]
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
60
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
61
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
62
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
63
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
64
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
65
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
59
|
+
"@aztec/epoch-cache": "0.0.1-commit.86469d5",
|
|
60
|
+
"@aztec/ethereum": "0.0.1-commit.86469d5",
|
|
61
|
+
"@aztec/foundation": "0.0.1-commit.86469d5",
|
|
62
|
+
"@aztec/kv-store": "0.0.1-commit.86469d5",
|
|
63
|
+
"@aztec/l1-artifacts": "0.0.1-commit.86469d5",
|
|
64
|
+
"@aztec/stdlib": "0.0.1-commit.86469d5",
|
|
65
|
+
"@aztec/telemetry-client": "0.0.1-commit.86469d5",
|
|
66
66
|
"source-map-support": "^0.5.21",
|
|
67
67
|
"tslib": "^2.4.0",
|
|
68
68
|
"viem": "npm:@aztec/viem@2.38.2",
|
|
69
69
|
"zod": "^3.23.8"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@aztec/aztec.js": "0.0.1-commit.
|
|
72
|
+
"@aztec/aztec.js": "0.0.1-commit.86469d5",
|
|
73
73
|
"@jest/globals": "^30.0.0",
|
|
74
74
|
"@types/jest": "^30.0.0",
|
|
75
75
|
"@types/node": "^22.15.17",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import {
|
|
2
|
+
import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { merge, pick } from '@aztec/foundation/collection';
|
|
4
4
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import {
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
} from '@aztec/stdlib/block';
|
|
13
13
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
14
14
|
import type {
|
|
15
|
-
ICheckpointBlockBuilder,
|
|
16
15
|
ICheckpointsBuilder,
|
|
17
16
|
ITxProvider,
|
|
18
17
|
MerkleTreeWriteOperations,
|
|
@@ -107,7 +106,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
107
106
|
{ blocks: epochBlocks.map(b => b.toBlockInfo()) },
|
|
108
107
|
);
|
|
109
108
|
|
|
110
|
-
await this.validateBlocks(epochBlocks
|
|
109
|
+
await this.validateBlocks(epochBlocks);
|
|
111
110
|
this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
|
|
112
111
|
await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
|
|
113
112
|
} catch (error) {
|
|
@@ -122,32 +121,19 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
public async validateBlocks(blocks: L2Block[]
|
|
124
|
+
public async validateBlocks(blocks: L2Block[]): Promise<void> {
|
|
126
125
|
if (blocks.length === 0) {
|
|
127
126
|
return;
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
const blocksByCheckpoint = chunkBy(sortedBlocks, b => b.checkpointNumber);
|
|
133
|
-
|
|
134
|
-
// Get prior checkpoints in the epoch (in case this was a partial prune) to extract the out hashes
|
|
135
|
-
const priorCheckpointOutHashes = (await this.l2BlockSource.getCheckpointsForEpoch(epochNumber))
|
|
136
|
-
.filter(c => c.number < sortedBlocks[0].checkpointNumber)
|
|
137
|
-
.map(c => c.getCheckpointOutHash());
|
|
138
|
-
let previousCheckpointOutHashes: Fr[] = [...priorCheckpointOutHashes];
|
|
139
|
-
|
|
140
|
-
const fork = await this.checkpointsBuilder.getFork(
|
|
141
|
-
BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1),
|
|
142
|
-
);
|
|
129
|
+
let previousCheckpointOutHashes: Fr[] = [];
|
|
130
|
+
const fork = await this.checkpointsBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
|
|
143
131
|
try {
|
|
144
|
-
for (const
|
|
145
|
-
await this.
|
|
132
|
+
for (const block of blocks) {
|
|
133
|
+
await this.validateBlock(block, previousCheckpointOutHashes, fork);
|
|
146
134
|
|
|
147
|
-
//
|
|
148
|
-
const checkpointOutHash = computeCheckpointOutHash(
|
|
149
|
-
checkpointBlocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
150
|
-
);
|
|
135
|
+
// TODO(mbps): This assumes one block per checkpoint, which is only true for now.
|
|
136
|
+
const checkpointOutHash = computeCheckpointOutHash([block.body.txEffects.map(tx => tx.l2ToL1Msgs)]);
|
|
151
137
|
previousCheckpointOutHashes = [...previousCheckpointOutHashes, checkpointOutHash];
|
|
152
138
|
}
|
|
153
139
|
} finally {
|
|
@@ -155,19 +141,25 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
155
141
|
}
|
|
156
142
|
}
|
|
157
143
|
|
|
158
|
-
|
|
159
|
-
|
|
144
|
+
public async validateBlock(
|
|
145
|
+
blockFromL1: L2Block,
|
|
160
146
|
previousCheckpointOutHashes: Fr[],
|
|
161
147
|
fork: MerkleTreeWriteOperations,
|
|
162
148
|
): Promise<void> {
|
|
163
|
-
|
|
164
|
-
|
|
149
|
+
this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
|
|
150
|
+
const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
|
|
151
|
+
// We load txs from the mempool directly, since the TxCollector running in the background has already been
|
|
152
|
+
// trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
|
|
153
|
+
// it's likely that they are not available in the network at all.
|
|
154
|
+
const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
156
|
+
if (missingTxs && missingTxs.length > 0) {
|
|
157
|
+
throw new TransactionsNotAvailableError(missingTxs);
|
|
158
|
+
}
|
|
168
159
|
|
|
169
|
-
|
|
170
|
-
const
|
|
160
|
+
const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
|
|
161
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
162
|
+
const gv = blockFromL1.header.globalVariables;
|
|
171
163
|
const constants: CheckpointGlobalVariables = {
|
|
172
164
|
chainId: gv.chainId,
|
|
173
165
|
version: gv.version,
|
|
@@ -177,7 +169,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
177
169
|
gasFees: gv.gasFees,
|
|
178
170
|
};
|
|
179
171
|
|
|
180
|
-
//
|
|
172
|
+
// Use checkpoint builder to validate the block
|
|
181
173
|
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(
|
|
182
174
|
checkpointNumber,
|
|
183
175
|
constants,
|
|
@@ -187,28 +179,6 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
187
179
|
this.log.getBindings(),
|
|
188
180
|
);
|
|
189
181
|
|
|
190
|
-
// Validate all blocks in the checkpoint sequentially
|
|
191
|
-
for (const block of checkpointBlocks) {
|
|
192
|
-
await this.validateBlockInCheckpoint(block, checkpointBuilder);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private async validateBlockInCheckpoint(
|
|
197
|
-
blockFromL1: L2Block,
|
|
198
|
-
checkpointBuilder: ICheckpointBlockBuilder,
|
|
199
|
-
): Promise<void> {
|
|
200
|
-
this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
|
|
201
|
-
const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
|
|
202
|
-
// We load txs from the mempool directly, since the TxCollector running in the background has already been
|
|
203
|
-
// trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
|
|
204
|
-
// it's likely that they are not available in the network at all.
|
|
205
|
-
const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
|
|
206
|
-
|
|
207
|
-
if (missingTxs && missingTxs.length > 0) {
|
|
208
|
-
throw new TransactionsNotAvailableError(missingTxs);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const gv = blockFromL1.header.globalVariables;
|
|
212
182
|
const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {});
|
|
213
183
|
|
|
214
184
|
if (numTxs !== txs.length) {
|