@aztec/slasher 4.0.0-nightly.20250907 → 4.0.0-nightly.20260108
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 +60 -11
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +8 -2
- package/dest/empire_slasher_client.d.ts +8 -6
- package/dest/empire_slasher_client.d.ts.map +1 -1
- package/dest/empire_slasher_client.js +11 -5
- package/dest/factory/create_facade.d.ts +3 -2
- package/dest/factory/create_facade.d.ts.map +1 -1
- package/dest/factory/create_implementation.d.ts +3 -3
- package/dest/factory/create_implementation.d.ts.map +1 -1
- package/dest/factory/create_implementation.js +6 -4
- package/dest/factory/get_settings.d.ts +2 -2
- package/dest/factory/get_settings.d.ts.map +1 -1
- package/dest/factory/index.d.ts +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/null_slasher_client.d.ts +3 -2
- package/dest/null_slasher_client.d.ts.map +1 -1
- package/dest/slash_offenses_collector.d.ts +1 -1
- package/dest/slash_offenses_collector.d.ts.map +1 -1
- package/dest/slash_offenses_collector.js +1 -2
- package/dest/slash_round_monitor.d.ts +5 -4
- package/dest/slash_round_monitor.d.ts.map +1 -1
- package/dest/slasher_client_facade.d.ts +4 -3
- package/dest/slasher_client_facade.d.ts.map +1 -1
- package/dest/slasher_client_facade.js +1 -0
- package/dest/slasher_client_interface.d.ts +3 -2
- package/dest/slasher_client_interface.d.ts.map +1 -1
- package/dest/stores/offenses_store.d.ts +1 -1
- package/dest/stores/offenses_store.d.ts.map +1 -1
- package/dest/stores/offenses_store.js +1 -1
- package/dest/stores/payloads_store.d.ts +2 -2
- package/dest/stores/payloads_store.d.ts.map +1 -1
- package/dest/stores/schema_version.d.ts +1 -1
- package/dest/tally_slasher_client.d.ts +14 -8
- package/dest/tally_slasher_client.d.ts.map +1 -1
- package/dest/tally_slasher_client.js +57 -12
- package/dest/test/dummy_watcher.d.ts +11 -0
- package/dest/test/dummy_watcher.d.ts.map +1 -0
- package/dest/test/dummy_watcher.js +14 -0
- package/dest/watcher.d.ts +3 -1
- package/dest/watcher.d.ts.map +1 -1
- package/dest/watchers/attestations_block_watcher.d.ts +6 -3
- package/dest/watchers/attestations_block_watcher.d.ts.map +1 -1
- package/dest/watchers/attestations_block_watcher.js +37 -22
- package/dest/watchers/epoch_prune_watcher.d.ts +8 -7
- package/dest/watchers/epoch_prune_watcher.d.ts.map +1 -1
- package/dest/watchers/epoch_prune_watcher.js +48 -37
- package/package.json +13 -12
- package/src/config.ts +8 -2
- package/src/empire_slasher_client.ts +15 -8
- package/src/factory/create_facade.ts +2 -1
- package/src/factory/create_implementation.ts +6 -1
- package/src/factory/get_settings.ts +1 -1
- package/src/null_slasher_client.ts +2 -1
- package/src/slash_offenses_collector.ts +1 -2
- package/src/slash_round_monitor.ts +3 -2
- package/src/slasher_client_facade.ts +4 -2
- package/src/slasher_client_interface.ts +2 -1
- package/src/stores/offenses_store.ts +1 -1
- package/src/tally_slasher_client.ts +80 -17
- package/src/test/dummy_watcher.ts +21 -0
- package/src/watcher.ts +4 -1
- package/src/watchers/attestations_block_watcher.ts +44 -26
- package/src/watchers/epoch_prune_watcher.ts +67 -55
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
2
|
+
|
|
3
|
+
import EventEmitter from 'node:events';
|
|
4
|
+
|
|
5
|
+
import { WANT_TO_SLASH_EVENT, type WantToSlashArgs, type Watcher, type WatcherEmitter } from '../watcher.js';
|
|
6
|
+
|
|
7
|
+
export class DummyWatcher extends (EventEmitter as new () => WatcherEmitter) implements Watcher {
|
|
8
|
+
public updateConfig(_config: Partial<SlasherConfig>) {}
|
|
9
|
+
|
|
10
|
+
public start() {
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public stop() {
|
|
15
|
+
return Promise.resolve();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public triggerSlash(args: WantToSlashArgs[]) {
|
|
19
|
+
this.emit(WANT_TO_SLASH_EVENT, args);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/watcher.ts
CHANGED
|
@@ -2,13 +2,15 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
2
2
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
3
3
|
import { OffenseType } from '@aztec/stdlib/slashing';
|
|
4
4
|
|
|
5
|
+
import type { SlasherConfig } from './config.js';
|
|
6
|
+
|
|
5
7
|
export const WANT_TO_SLASH_EVENT = 'want-to-slash' as const;
|
|
6
8
|
|
|
7
9
|
export interface WantToSlashArgs {
|
|
8
10
|
validator: EthAddress;
|
|
9
11
|
amount: bigint;
|
|
10
12
|
offenseType: OffenseType;
|
|
11
|
-
epochOrSlot: bigint; // Epoch number for epoch-based offenses,
|
|
13
|
+
epochOrSlot: bigint; // Epoch number for epoch-based offenses, slot number for slot-based
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
// Event map for specific, known events of a watcher
|
|
@@ -21,4 +23,5 @@ export type WatcherEmitter = TypedEventEmitter<WatcherEventMap>;
|
|
|
21
23
|
export type Watcher = WatcherEmitter & {
|
|
22
24
|
start?: () => Promise<void>;
|
|
23
25
|
stop?: () => Promise<void>;
|
|
26
|
+
updateConfig: (config: Partial<SlasherConfig>) => void;
|
|
24
27
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { merge, pick } from '@aztec/foundation/collection';
|
|
2
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
5
|
import {
|
|
4
6
|
type InvalidBlockDetectedEvent,
|
|
7
|
+
type L2BlockInfo,
|
|
5
8
|
type L2BlockSourceEventEmitter,
|
|
6
9
|
L2BlockSourceEvents,
|
|
7
|
-
PublishedL2Block,
|
|
8
10
|
type ValidateBlockNegativeResult,
|
|
9
11
|
} from '@aztec/stdlib/block';
|
|
10
12
|
import { OffenseType } from '@aztec/stdlib/slashing';
|
|
@@ -14,6 +16,13 @@ import EventEmitter from 'node:events';
|
|
|
14
16
|
import type { SlasherConfig } from '../config.js';
|
|
15
17
|
import { WANT_TO_SLASH_EVENT, type WantToSlashArgs, type Watcher, type WatcherEmitter } from '../watcher.js';
|
|
16
18
|
|
|
19
|
+
const AttestationsBlockWatcherConfigKeys = [
|
|
20
|
+
'slashAttestDescendantOfInvalidPenalty',
|
|
21
|
+
'slashProposeInvalidAttestationsPenalty',
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
type AttestationsBlockWatcherConfig = Pick<SlasherConfig, (typeof AttestationsBlockWatcherConfigKeys)[number]>;
|
|
25
|
+
|
|
17
26
|
/**
|
|
18
27
|
* This watcher is responsible for detecting invalid blocks and creating slashing arguments for offenders.
|
|
19
28
|
* An invalid block is one that doesn't have enough attestations or has incorrect attestations.
|
|
@@ -29,13 +38,14 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
29
38
|
// All invalid archive roots seen
|
|
30
39
|
private invalidArchiveRoots: Set<string> = new Set();
|
|
31
40
|
|
|
41
|
+
private config: AttestationsBlockWatcherConfig;
|
|
42
|
+
|
|
32
43
|
private boundHandleInvalidBlock = (event: InvalidBlockDetectedEvent) => {
|
|
33
44
|
try {
|
|
34
45
|
this.handleInvalidBlock(event);
|
|
35
46
|
} catch (err) {
|
|
36
47
|
this.log.error('Error handling invalid block', err, {
|
|
37
|
-
...event.validationResult
|
|
38
|
-
...event.validationResult.block.l1,
|
|
48
|
+
...event.validationResult,
|
|
39
49
|
reason: event.validationResult.reason,
|
|
40
50
|
});
|
|
41
51
|
}
|
|
@@ -44,13 +54,16 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
44
54
|
constructor(
|
|
45
55
|
private l2BlockSource: L2BlockSourceEventEmitter,
|
|
46
56
|
private epochCache: EpochCache,
|
|
47
|
-
|
|
48
|
-
SlasherConfig,
|
|
49
|
-
'slashAttestDescendantOfInvalidPenalty' | 'slashProposeInvalidAttestationsPenalty'
|
|
50
|
-
>,
|
|
57
|
+
config: AttestationsBlockWatcherConfig,
|
|
51
58
|
) {
|
|
52
59
|
super();
|
|
53
|
-
this.
|
|
60
|
+
this.config = pick(config, ...AttestationsBlockWatcherConfigKeys);
|
|
61
|
+
this.log.info('AttestationsBlockWatcher initialized');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public updateConfig(newConfig: Partial<AttestationsBlockWatcherConfig>) {
|
|
65
|
+
this.config = merge(this.config, pick(newConfig, ...AttestationsBlockWatcherConfigKeys));
|
|
66
|
+
this.log.verbose('AttestationsBlockWatcher config updated', this.config);
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
public start() {
|
|
@@ -68,16 +81,16 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
68
81
|
|
|
69
82
|
private handleInvalidBlock(event: InvalidBlockDetectedEvent): void {
|
|
70
83
|
const { validationResult } = event;
|
|
71
|
-
const block = validationResult.block
|
|
84
|
+
const block = validationResult.block;
|
|
72
85
|
|
|
73
86
|
// Check if we already have processed this block, archiver may emit the same event multiple times
|
|
74
|
-
if (this.invalidArchiveRoots.has(block.archive.
|
|
75
|
-
this.log.trace(`Already processed invalid block ${block.
|
|
87
|
+
if (this.invalidArchiveRoots.has(block.archive.toString())) {
|
|
88
|
+
this.log.trace(`Already processed invalid block ${block.blockNumber}`);
|
|
76
89
|
return;
|
|
77
90
|
}
|
|
78
91
|
|
|
79
|
-
this.log.verbose(`Detected invalid block ${block.
|
|
80
|
-
...block
|
|
92
|
+
this.log.verbose(`Detected invalid block ${block.blockNumber}`, {
|
|
93
|
+
...block,
|
|
81
94
|
reason: validationResult.valid === false ? validationResult.reason : 'unknown',
|
|
82
95
|
});
|
|
83
96
|
|
|
@@ -94,11 +107,11 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
94
107
|
private slashAttestorsOnAncestorInvalid(validationResult: ValidateBlockNegativeResult) {
|
|
95
108
|
const block = validationResult.block;
|
|
96
109
|
|
|
97
|
-
const parentArchive = block.
|
|
98
|
-
if (this.invalidArchiveRoots.has(
|
|
99
|
-
const attestors = validationResult.
|
|
100
|
-
this.log.info(`Want to slash attestors of block ${block.
|
|
101
|
-
...block
|
|
110
|
+
const parentArchive = block.lastArchive.toString();
|
|
111
|
+
if (this.invalidArchiveRoots.has(parentArchive)) {
|
|
112
|
+
const attestors = validationResult.attestors;
|
|
113
|
+
this.log.info(`Want to slash attestors of block ${block.blockNumber} built on invalid block`, {
|
|
114
|
+
...block,
|
|
102
115
|
...attestors,
|
|
103
116
|
parentArchive,
|
|
104
117
|
});
|
|
@@ -109,7 +122,7 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
109
122
|
validator: attestor,
|
|
110
123
|
amount: this.config.slashAttestDescendantOfInvalidPenalty,
|
|
111
124
|
offenseType: OffenseType.ATTESTED_DESCENDANT_OF_INVALID,
|
|
112
|
-
epochOrSlot: block.
|
|
125
|
+
epochOrSlot: BigInt(SlotNumber(block.slotNumber)),
|
|
113
126
|
})),
|
|
114
127
|
);
|
|
115
128
|
}
|
|
@@ -117,9 +130,14 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
117
130
|
|
|
118
131
|
private slashProposer(validationResult: ValidateBlockNegativeResult) {
|
|
119
132
|
const { reason, block } = validationResult;
|
|
120
|
-
const blockNumber = block.
|
|
121
|
-
const slot = block.
|
|
122
|
-
const
|
|
133
|
+
const blockNumber = block.blockNumber;
|
|
134
|
+
const slot = block.slotNumber;
|
|
135
|
+
const epochCommitteeInfo = {
|
|
136
|
+
committee: validationResult.committee,
|
|
137
|
+
seed: validationResult.seed,
|
|
138
|
+
epoch: validationResult.epoch,
|
|
139
|
+
};
|
|
140
|
+
const proposer = this.epochCache.getProposerFromEpochCommittee(epochCommitteeInfo, slot);
|
|
123
141
|
|
|
124
142
|
if (!proposer) {
|
|
125
143
|
this.log.warn(`No proposer found for block ${blockNumber} at slot ${slot}`);
|
|
@@ -132,11 +150,11 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
132
150
|
validator: proposer,
|
|
133
151
|
amount,
|
|
134
152
|
offenseType: offense,
|
|
135
|
-
epochOrSlot:
|
|
153
|
+
epochOrSlot: BigInt(slot),
|
|
136
154
|
};
|
|
137
155
|
|
|
138
156
|
this.log.info(`Want to slash proposer of block ${blockNumber} due to ${reason}`, {
|
|
139
|
-
...block
|
|
157
|
+
...block,
|
|
140
158
|
...args,
|
|
141
159
|
});
|
|
142
160
|
|
|
@@ -156,8 +174,8 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
|
|
|
156
174
|
}
|
|
157
175
|
}
|
|
158
176
|
|
|
159
|
-
private addInvalidBlock(block:
|
|
160
|
-
this.invalidArchiveRoots.add(block.
|
|
177
|
+
private addInvalidBlock(block: L2BlockInfo) {
|
|
178
|
+
this.invalidArchiveRoots.add(block.archive.toString());
|
|
161
179
|
|
|
162
180
|
// Prune old entries if we exceed the maximum
|
|
163
181
|
if (this.invalidArchiveRoots.size > this.maxInvalidBlocks) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Tx } from '@aztec/aztec.js';
|
|
2
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
+
import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { merge, pick } from '@aztec/foundation/collection';
|
|
3
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import {
|
|
5
6
|
EthAddress,
|
|
@@ -8,9 +9,15 @@ import {
|
|
|
8
9
|
type L2BlockSourceEventEmitter,
|
|
9
10
|
L2BlockSourceEvents,
|
|
10
11
|
} from '@aztec/stdlib/block';
|
|
11
|
-
import
|
|
12
|
+
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
|
+
import type {
|
|
14
|
+
IFullNodeBlockBuilder,
|
|
15
|
+
ITxProvider,
|
|
16
|
+
MerkleTreeWriteOperations,
|
|
17
|
+
SlasherConfig,
|
|
18
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
12
19
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
13
|
-
import { OffenseType } from '@aztec/stdlib/slashing';
|
|
20
|
+
import { OffenseType, getOffenseTypeName } from '@aztec/stdlib/slashing';
|
|
14
21
|
import {
|
|
15
22
|
ReExFailedTxsError,
|
|
16
23
|
ReExStateMismatchError,
|
|
@@ -22,10 +29,9 @@ import EventEmitter from 'node:events';
|
|
|
22
29
|
|
|
23
30
|
import { WANT_TO_SLASH_EVENT, type WantToSlashArgs, type Watcher, type WatcherEmitter } from '../watcher.js';
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
32
|
+
const EpochPruneWatcherPenaltiesConfigKeys = ['slashPrunePenalty', 'slashDataWithholdingPenalty'] as const;
|
|
33
|
+
|
|
34
|
+
type EpochPruneWatcherPenalties = Pick<SlasherConfig, (typeof EpochPruneWatcherPenaltiesConfigKeys)[number]>;
|
|
29
35
|
|
|
30
36
|
/**
|
|
31
37
|
* This watcher is responsible for detecting chain prunes and creating slashing arguments for the committee.
|
|
@@ -39,15 +45,18 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
39
45
|
// Store bound function reference for proper listener removal
|
|
40
46
|
private boundHandlePruneL2Blocks = this.handlePruneL2Blocks.bind(this);
|
|
41
47
|
|
|
48
|
+
private penalties: EpochPruneWatcherPenalties;
|
|
49
|
+
|
|
42
50
|
constructor(
|
|
43
51
|
private l2BlockSource: L2BlockSourceEventEmitter,
|
|
44
52
|
private l1ToL2MessageSource: L1ToL2MessageSource,
|
|
45
53
|
private epochCache: EpochCache,
|
|
46
54
|
private txProvider: Pick<ITxProvider, 'getAvailableTxs'>,
|
|
47
55
|
private blockBuilder: IFullNodeBlockBuilder,
|
|
48
|
-
|
|
56
|
+
penalties: EpochPruneWatcherPenalties,
|
|
49
57
|
) {
|
|
50
58
|
super();
|
|
59
|
+
this.penalties = pick(penalties, ...EpochPruneWatcherPenaltiesConfigKeys);
|
|
51
60
|
this.log.verbose(
|
|
52
61
|
`EpochPruneWatcher initialized with penalties: valid epoch pruned=${penalties.slashPrunePenalty} data withholding=${penalties.slashDataWithholdingPenalty}`,
|
|
53
62
|
);
|
|
@@ -63,56 +72,58 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
63
72
|
return Promise.resolve();
|
|
64
73
|
}
|
|
65
74
|
|
|
75
|
+
public updateConfig(config: Partial<SlasherConfig>): void {
|
|
76
|
+
this.penalties = merge(this.penalties, pick(config, ...EpochPruneWatcherPenaltiesConfigKeys));
|
|
77
|
+
this.log.verbose('EpochPruneWatcher config updated', this.penalties);
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
private handlePruneL2Blocks(event: L2BlockPruneEvent): void {
|
|
67
81
|
const { blocks, epochNumber } = event;
|
|
68
|
-
this.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// This can happen if we fail to get the validators for the epoch.
|
|
107
|
-
this.log.error('Error while creating slash for epoch', error);
|
|
108
|
-
});
|
|
82
|
+
void this.processPruneL2Blocks(blocks, epochNumber).catch(err =>
|
|
83
|
+
this.log.error('Error processing pruned L2 blocks', err, { epochNumber }),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private async emitSlashForEpoch(offense: OffenseType, epochNumber: EpochNumber): Promise<void> {
|
|
88
|
+
const validators = await this.getValidatorsForEpoch(epochNumber);
|
|
89
|
+
if (validators.length === 0) {
|
|
90
|
+
this.log.warn(`No validators found for epoch ${epochNumber} (cannot slash for ${getOffenseTypeName(offense)})`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const args = this.validatorsToSlashingArgs(validators, offense, epochNumber);
|
|
94
|
+
this.log.verbose(`Created slash for ${getOffenseTypeName(offense)} at epoch ${epochNumber}`, args);
|
|
95
|
+
this.emit(WANT_TO_SLASH_EVENT, args);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private async processPruneL2Blocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void> {
|
|
99
|
+
try {
|
|
100
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
101
|
+
const epochBlocks = blocks.filter(b => getEpochAtSlot(b.slot, l1Constants) === epochNumber);
|
|
102
|
+
this.log.info(
|
|
103
|
+
`Detected chain prune. Validating epoch ${epochNumber} with blocks ${epochBlocks[0]?.number} to ${epochBlocks[epochBlocks.length - 1]?.number}.`,
|
|
104
|
+
{ blocks: epochBlocks.map(b => b.toBlockInfo()) },
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
await this.validateBlocks(epochBlocks);
|
|
108
|
+
this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
|
|
109
|
+
await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof TransactionsNotAvailableError) {
|
|
112
|
+
this.log.info(`Data for pruned epoch ${epochNumber} was not available. Will want to slash.`, {
|
|
113
|
+
message: error.message,
|
|
114
|
+
});
|
|
115
|
+
await this.emitSlashForEpoch(OffenseType.DATA_WITHHOLDING, epochNumber);
|
|
116
|
+
} else {
|
|
117
|
+
this.log.error(`Error while validating pruned epoch ${epochNumber}. Will not want to slash.`, error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
public async validateBlocks(blocks: L2Block[]): Promise<void> {
|
|
112
123
|
if (blocks.length === 0) {
|
|
113
124
|
return;
|
|
114
125
|
}
|
|
115
|
-
const fork = await this.blockBuilder.getFork(blocks[0].header.globalVariables.blockNumber - 1);
|
|
126
|
+
const fork = await this.blockBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
|
|
116
127
|
try {
|
|
117
128
|
for (const block of blocks) {
|
|
118
129
|
await this.validateBlock(block, fork);
|
|
@@ -134,9 +145,10 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
134
145
|
throw new TransactionsNotAvailableError(missingTxs);
|
|
135
146
|
}
|
|
136
147
|
|
|
137
|
-
const
|
|
148
|
+
const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
|
|
149
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
138
150
|
const { block, failedTxs, numTxs } = await this.blockBuilder.buildBlock(
|
|
139
|
-
txs
|
|
151
|
+
txs,
|
|
140
152
|
l1ToL2Messages,
|
|
141
153
|
blockFromL1.header.globalVariables,
|
|
142
154
|
{},
|
|
@@ -154,7 +166,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
154
166
|
}
|
|
155
167
|
}
|
|
156
168
|
|
|
157
|
-
private async getValidatorsForEpoch(epochNumber:
|
|
169
|
+
private async getValidatorsForEpoch(epochNumber: EpochNumber): Promise<EthAddress[]> {
|
|
158
170
|
const { committee } = await this.epochCache.getCommitteeForEpoch(epochNumber);
|
|
159
171
|
if (!committee) {
|
|
160
172
|
this.log.trace(`No committee found for epoch ${epochNumber}`);
|
|
@@ -166,7 +178,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
166
178
|
private validatorsToSlashingArgs(
|
|
167
179
|
validators: EthAddress[],
|
|
168
180
|
offenseType: OffenseType,
|
|
169
|
-
epochOrSlot:
|
|
181
|
+
epochOrSlot: EpochNumber,
|
|
170
182
|
): WantToSlashArgs[] {
|
|
171
183
|
const penalty =
|
|
172
184
|
offenseType === OffenseType.DATA_WITHHOLDING
|
|
@@ -176,7 +188,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
176
188
|
validator: v,
|
|
177
189
|
amount: penalty,
|
|
178
190
|
offenseType,
|
|
179
|
-
epochOrSlot,
|
|
191
|
+
epochOrSlot: BigInt(epochOrSlot),
|
|
180
192
|
}));
|
|
181
193
|
}
|
|
182
194
|
}
|