@aztec/slasher 1.2.0 → 2.0.0-nightly.20250813

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.
@@ -0,0 +1,34 @@
1
+ import { EpochCache } from '@aztec/epoch-cache';
2
+ import { type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
3
+ import { type SlasherConfig, type WantToSlashArgs, type Watcher, type WatcherEmitter } from './config.js';
4
+ declare const AttestationsBlockWatcher_base: new () => WatcherEmitter;
5
+ /**
6
+ * This watcher is responsible for detecting invalid blocks and creating slashing arguments for offenders.
7
+ * An invalid block is one that doesn't have enough attestations or has incorrect attestations.
8
+ * The proposer of an invalid block should be slashed.
9
+ * If there's another block consecutive to the invalid one, its proposer and attestors should also be slashed.
10
+ */
11
+ export declare class AttestationsBlockWatcher extends AttestationsBlockWatcher_base implements Watcher {
12
+ private l2BlockSource;
13
+ private epochCache;
14
+ private config;
15
+ private log;
16
+ private maxInvalidBlocks;
17
+ private invalidArchiveRoots;
18
+ private badAttestors;
19
+ private badProposers;
20
+ private boundHandleInvalidBlock;
21
+ constructor(l2BlockSource: L2BlockSourceEventEmitter, epochCache: EpochCache, config: Pick<SlasherConfig, 'slashAttestDescendantOfInvalidPenalty' | 'slashAttestDescendantOfInvalidMaxPenalty' | 'slashProposeInvalidAttestationsPenalty' | 'slashProposeInvalidAttestationsMaxPenalty'>);
22
+ start(): Promise<void>;
23
+ stop(): Promise<void>;
24
+ shouldSlash({ amount, offense, validator }: WantToSlashArgs): Promise<boolean>;
25
+ private handleInvalidBlock;
26
+ private slashAttestorsOnAncestorInvalid;
27
+ private slashProposer;
28
+ private getOffenseFromInvalidationReason;
29
+ private getMaxPenalty;
30
+ private hasOffended;
31
+ private addInvalidBlock;
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=attestations_block_watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestations_block_watcher.d.ts","sourceRoot":"","sources":["../src/attestations_block_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAGL,KAAK,yBAAyB,EAI/B,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;6CAQ0C,UAAU,cAAc;AANvF;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,6BAA2C,YAAW,OAAO;IA0BvG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM;IA3BhB,OAAO,CAAC,GAAG,CAAsD;IAGjE,OAAO,CAAC,gBAAgB,CAAO;IAG/B,OAAO,CAAC,mBAAmB,CAA0B;IAGrD,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,YAAY,CAA0B;IAE9C,OAAO,CAAC,uBAAuB,CAU7B;gBAGQ,aAAa,EAAE,yBAAyB,EACxC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,IAAI,CAClB,aAAa,EACX,uCAAuC,GACvC,0CAA0C,GAC1C,wCAAwC,GACxC,2CAA2C,CAC9C;IAMI,KAAK;IAKL,IAAI;IAQJ,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBrF,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,+BAA+B;IAyBvC,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,gCAAgC;IAaxC,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,eAAe;CASxB"}
@@ -0,0 +1,170 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { L2BlockSourceEvents } from '@aztec/stdlib/block';
3
+ import { Offense } from '@aztec/stdlib/slashing';
4
+ import EventEmitter from 'node:events';
5
+ import { WANT_TO_SLASH_EVENT } from './config.js';
6
+ /**
7
+ * This watcher is responsible for detecting invalid blocks and creating slashing arguments for offenders.
8
+ * An invalid block is one that doesn't have enough attestations or has incorrect attestations.
9
+ * The proposer of an invalid block should be slashed.
10
+ * If there's another block consecutive to the invalid one, its proposer and attestors should also be slashed.
11
+ */ export class AttestationsBlockWatcher extends EventEmitter {
12
+ l2BlockSource;
13
+ epochCache;
14
+ config;
15
+ log;
16
+ // Only keep track of the last N invalid blocks
17
+ maxInvalidBlocks;
18
+ // All invalid archive roots seen
19
+ invalidArchiveRoots;
20
+ // TODO(#16140): Bad validators are never cleared even after slashing
21
+ badAttestors;
22
+ badProposers;
23
+ boundHandleInvalidBlock;
24
+ constructor(l2BlockSource, epochCache, config){
25
+ super(), this.l2BlockSource = l2BlockSource, this.epochCache = epochCache, this.config = config, this.log = createLogger('attestations-block-watcher'), this.maxInvalidBlocks = 100, this.invalidArchiveRoots = new Set(), this.badAttestors = new Set(), this.badProposers = new Set(), this.boundHandleInvalidBlock = (event)=>{
26
+ try {
27
+ this.handleInvalidBlock(event);
28
+ } catch (err) {
29
+ this.log.error('Error handling invalid block', err, {
30
+ ...event.validationResult.block.block.toBlockInfo(),
31
+ ...event.validationResult.block.l1,
32
+ reason: event.validationResult.reason
33
+ });
34
+ }
35
+ };
36
+ this.log.info('InvalidBlockWatcher initialized');
37
+ }
38
+ start() {
39
+ this.l2BlockSource.on(L2BlockSourceEvents.InvalidAttestationsBlockDetected, this.boundHandleInvalidBlock);
40
+ return Promise.resolve();
41
+ }
42
+ stop() {
43
+ this.l2BlockSource.removeListener(L2BlockSourceEvents.InvalidAttestationsBlockDetected, this.boundHandleInvalidBlock);
44
+ return Promise.resolve();
45
+ }
46
+ shouldSlash({ amount, offense, validator }) {
47
+ const maxPenalty = this.getMaxPenalty(offense);
48
+ const logData = {
49
+ validator,
50
+ amount,
51
+ offense,
52
+ maxPenalty
53
+ };
54
+ if (amount > maxPenalty) {
55
+ this.log.warn(`Slash amount ${amount} exceeds maximum penalty ${maxPenalty} for offense ${offense}`, logData);
56
+ return Promise.resolve(false);
57
+ }
58
+ if (this.hasOffended(offense, validator)) {
59
+ this.log.verbose(`Agreeing to slash validator ${validator} for offense ${offense}`, logData);
60
+ return Promise.resolve(true);
61
+ }
62
+ this.log.debug(`Refusing to slash validator ${validator} for offense ${offense}`, logData);
63
+ return Promise.resolve(false);
64
+ }
65
+ handleInvalidBlock(event) {
66
+ const { validationResult } = event;
67
+ const block = validationResult.block.block;
68
+ // Check if we already have processed this block, archiver may emit the same event multiple times
69
+ if (this.invalidArchiveRoots.has(block.archive.root.toString())) {
70
+ this.log.trace(`Already processed invalid block ${block.number}`);
71
+ return;
72
+ }
73
+ this.log.verbose(`Detected invalid block ${block.number}`, {
74
+ ...block.toBlockInfo(),
75
+ reason: validationResult.valid === false ? validationResult.reason : 'unknown'
76
+ });
77
+ // Store the invalid block
78
+ this.addInvalidBlock(event.validationResult.block);
79
+ // Slash the proposer of the invalid block
80
+ this.slashProposer(event.validationResult);
81
+ // Check if the parent of this block is invalid as well, if so, we will slash its attestors as well
82
+ this.slashAttestorsOnAncestorInvalid(event.validationResult);
83
+ }
84
+ slashAttestorsOnAncestorInvalid(validationResult) {
85
+ const block = validationResult.block;
86
+ const parentArchive = block.block.header.lastArchive.root.toString();
87
+ if (this.invalidArchiveRoots.has(block.block.header.lastArchive.root.toString())) {
88
+ const attestors = validationResult.attestations.map((a)=>a.getSender());
89
+ this.log.info(`Want to slash attestors of block ${block.block.number} built on invalid block`, {
90
+ ...block.block.toBlockInfo(),
91
+ ...attestors,
92
+ parentArchive
93
+ });
94
+ attestors.forEach((attestor)=>this.badAttestors.add(attestor.toString()));
95
+ this.emit(WANT_TO_SLASH_EVENT, attestors.map((attestor)=>({
96
+ validator: attestor,
97
+ amount: this.config.slashAttestDescendantOfInvalidPenalty,
98
+ offense: Offense.ATTESTED_DESCENDANT_OF_INVALID
99
+ })));
100
+ }
101
+ }
102
+ slashProposer(validationResult) {
103
+ const { reason, block } = validationResult;
104
+ const blockNumber = block.block.number;
105
+ const slot = block.block.header.getSlot();
106
+ const proposer = this.epochCache.getProposerFromEpochCommittee(validationResult, slot);
107
+ if (!proposer) {
108
+ this.log.warn(`No proposer found for block ${blockNumber} at slot ${slot}`);
109
+ return;
110
+ }
111
+ const offense = this.getOffenseFromInvalidationReason(reason);
112
+ const amount = this.config.slashProposeInvalidAttestationsPenalty;
113
+ const args = {
114
+ validator: proposer,
115
+ amount,
116
+ offense
117
+ };
118
+ this.log.info(`Want to slash proposer of block ${blockNumber} due to ${reason}`, {
119
+ ...block.block.toBlockInfo(),
120
+ ...args
121
+ });
122
+ this.badProposers.add(proposer.toString());
123
+ this.emit(WANT_TO_SLASH_EVENT, [
124
+ args
125
+ ]);
126
+ }
127
+ getOffenseFromInvalidationReason(reason) {
128
+ switch(reason){
129
+ case 'invalid-attestation':
130
+ return Offense.PROPOSED_INCORRECT_ATTESTATIONS;
131
+ case 'insufficient-attestations':
132
+ return Offense.PROPOSED_INSUFFICIENT_ATTESTATIONS;
133
+ default:
134
+ {
135
+ const _ = reason;
136
+ return Offense.UNKNOWN;
137
+ }
138
+ }
139
+ }
140
+ getMaxPenalty(offense) {
141
+ switch(offense){
142
+ case Offense.PROPOSED_INCORRECT_ATTESTATIONS:
143
+ case Offense.PROPOSED_INSUFFICIENT_ATTESTATIONS:
144
+ return this.config.slashProposeInvalidAttestationsMaxPenalty;
145
+ case Offense.ATTESTED_DESCENDANT_OF_INVALID:
146
+ return this.config.slashProposeInvalidAttestationsMaxPenalty;
147
+ default:
148
+ return 0n;
149
+ }
150
+ }
151
+ hasOffended(offense, validator) {
152
+ switch(offense){
153
+ case Offense.PROPOSED_INCORRECT_ATTESTATIONS:
154
+ case Offense.PROPOSED_INSUFFICIENT_ATTESTATIONS:
155
+ return this.badProposers.has(validator.toString());
156
+ case Offense.ATTESTED_DESCENDANT_OF_INVALID:
157
+ return this.badAttestors.has(validator.toString());
158
+ default:
159
+ return false;
160
+ }
161
+ }
162
+ addInvalidBlock(block) {
163
+ this.invalidArchiveRoots.add(block.block.archive.root.toString());
164
+ // Prune old entries if we exceed the maximum
165
+ if (this.invalidArchiveRoots.size > this.maxInvalidBlocks) {
166
+ const oldestKey = this.invalidArchiveRoots.keys().next().value;
167
+ this.invalidArchiveRoots.delete(oldestKey);
168
+ }
169
+ }
170
+ }
package/dest/config.d.ts CHANGED
@@ -1,15 +1,9 @@
1
1
  import type { ConfigMappingsType } from '@aztec/foundation/config';
2
2
  import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { TypedEventEmitter } from '@aztec/foundation/types';
4
- export declare enum Offense {
5
- UNKNOWN = 0,
6
- DATA_WITHHOLDING = 1,
7
- VALID_EPOCH_PRUNED = 2,
8
- INACTIVITY = 3,
9
- INVALID_BLOCK = 4
10
- }
11
- export declare const OffenseToBigInt: Record<Offense, bigint>;
12
- export declare function bigIntToOffense(offense: bigint): Offense;
4
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
5
+ import { Offense } from '@aztec/stdlib/slashing';
6
+ export type { SlasherConfig };
13
7
  export declare const WANT_TO_SLASH_EVENT: "wantToSlash";
14
8
  export interface WantToSlashArgs {
15
9
  validator: EthAddress;
@@ -26,22 +20,6 @@ export type Watcher = WatcherEmitter & {
26
20
  start?: () => Promise<void>;
27
21
  stop?: () => Promise<void>;
28
22
  };
29
- export interface SlasherConfig {
30
- slashOverridePayload?: EthAddress;
31
- slashPayloadTtlSeconds: number;
32
- slashPruneEnabled: boolean;
33
- slashPrunePenalty: bigint;
34
- slashPruneMaxPenalty: bigint;
35
- slashInvalidBlockEnabled: boolean;
36
- slashInvalidBlockPenalty: bigint;
37
- slashInvalidBlockMaxPenalty: bigint;
38
- slashInactivityEnabled: boolean;
39
- slashInactivityCreateTargetPercentage: number;
40
- slashInactivitySignalTargetPercentage: number;
41
- slashInactivityCreatePenalty: bigint;
42
- slashInactivityMaxPenalty: bigint;
43
- slashProposerRoundPollingIntervalSeconds: number;
44
- }
45
23
  export declare const DefaultSlasherConfig: SlasherConfig;
46
24
  export declare const slasherConfigMappings: ConfigMappingsType<SlasherConfig>;
47
25
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,oBAAY,OAAO;IACjB,OAAO,IAAI;IACX,gBAAgB,IAAI;IACpB,kBAAkB,IAAI;IACtB,UAAU,IAAI;IACd,aAAa,IAAI;CAClB;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAMnD,CAAC;AAEF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAexD;AAED,eAAO,MAAM,mBAAmB,EAAG,aAAsB,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,UAAU,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAGD,MAAM,WAAW,eAAe;IAC9B,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvE,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG;IACrC,WAAW,EAAE,YAAY,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,aAAa;IAE5B,oBAAoB,CAAC,EAAE,UAAU,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wBAAwB,EAAE,OAAO,CAAC;IAClC,wBAAwB,EAAE,MAAM,CAAC;IACjC,2BAA2B,EAAE,MAAM,CAAC;IACpC,sBAAsB,EAAE,OAAO,CAAC;IAChC,qCAAqC,EAAE,MAAM,CAAC;IAC9C,qCAAqC,EAAE,MAAM,CAAC;IAC9C,4BAA4B,EAAE,MAAM,CAAC;IACrC,yBAAyB,EAAE,MAAM,CAAC;IAClC,wCAAwC,EAAE,MAAM,CAAC;CAElD;AAED,eAAO,MAAM,oBAAoB,EAAE,aAelC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,CAAC,aAAa,CAiFnE,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AASnE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,eAAO,MAAM,mBAAmB,EAAG,aAAsB,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,UAAU,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAGD,MAAM,WAAW,eAAe;IAC9B,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvE,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG;IACrC,WAAW,EAAE,YAAY,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,aAoBlC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,CAAC,aAAa,CAyGnE,CAAC"}
package/dest/config.js CHANGED
@@ -1,36 +1,6 @@
1
- import { bigintConfigHelper, booleanConfigHelper, floatConfigHelper, numberConfigHelper } from '@aztec/foundation/config';
1
+ import { NULL_KEY } from '@aztec/ethereum';
2
+ import { SecretValue, bigintConfigHelper, booleanConfigHelper, floatConfigHelper, numberConfigHelper, secretValueConfigHelper } from '@aztec/foundation/config';
2
3
  import { EthAddress } from '@aztec/foundation/eth-address';
3
- export var Offense = /*#__PURE__*/ function(Offense) {
4
- Offense[Offense["UNKNOWN"] = 0] = "UNKNOWN";
5
- Offense[Offense["DATA_WITHHOLDING"] = 1] = "DATA_WITHHOLDING";
6
- Offense[Offense["VALID_EPOCH_PRUNED"] = 2] = "VALID_EPOCH_PRUNED";
7
- Offense[Offense["INACTIVITY"] = 3] = "INACTIVITY";
8
- Offense[Offense["INVALID_BLOCK"] = 4] = "INVALID_BLOCK";
9
- return Offense;
10
- }({});
11
- export const OffenseToBigInt = {
12
- [0]: 0n,
13
- [1]: 1n,
14
- [2]: 2n,
15
- [3]: 3n,
16
- [4]: 4n
17
- };
18
- export function bigIntToOffense(offense) {
19
- switch(offense){
20
- case 0n:
21
- return 0;
22
- case 1n:
23
- return 1;
24
- case 2n:
25
- return 2;
26
- case 3n:
27
- return 3;
28
- case 4n:
29
- return 4;
30
- default:
31
- throw new Error(`Unknown offense: ${offense}`);
32
- }
33
- }
34
4
  export const WANT_TO_SLASH_EVENT = 'wantToSlash';
35
5
  export const DefaultSlasherConfig = {
36
6
  slashPayloadTtlSeconds: 60 * 60 * 24,
@@ -46,7 +16,12 @@ export const DefaultSlasherConfig = {
46
16
  slashInactivitySignalTargetPercentage: 0.6,
47
17
  slashInactivityCreatePenalty: 1n,
48
18
  slashInactivityMaxPenalty: 100n,
49
- slashProposerRoundPollingIntervalSeconds: 12
19
+ slashProposeInvalidAttestationsPenalty: 1n,
20
+ slashProposeInvalidAttestationsMaxPenalty: 100n,
21
+ slashAttestDescendantOfInvalidPenalty: 1n,
22
+ slashAttestDescendantOfInvalidMaxPenalty: 100n,
23
+ slashProposerRoundPollingIntervalSeconds: 12,
24
+ slasherPrivateKey: new SecretValue(undefined)
50
25
  };
51
26
  export const slasherConfigMappings = {
52
27
  slashPayloadTtlSeconds: {
@@ -123,8 +98,32 @@ export const slasherConfigMappings = {
123
98
  description: 'Maximum penalty amount for slashing an inactive validator.',
124
99
  ...bigintConfigHelper(DefaultSlasherConfig.slashInactivityMaxPenalty)
125
100
  },
101
+ slashProposeInvalidAttestationsPenalty: {
102
+ env: 'SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY',
103
+ description: 'Penalty amount for slashing a proposer that proposed invalid attestations.',
104
+ ...bigintConfigHelper(DefaultSlasherConfig.slashProposeInvalidAttestationsPenalty)
105
+ },
106
+ slashProposeInvalidAttestationsMaxPenalty: {
107
+ env: 'SLASH_PROPOSE_INVALID_ATTESTATIONS_MAX_PENALTY',
108
+ description: 'Maximum penalty amount for slashing a proposer that proposed invalid attestations.',
109
+ ...bigintConfigHelper(DefaultSlasherConfig.slashProposeInvalidAttestationsMaxPenalty)
110
+ },
111
+ slashAttestDescendantOfInvalidPenalty: {
112
+ env: 'SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY',
113
+ description: 'Penalty amount for slashing a validator that attested to a descendant of an invalid block.',
114
+ ...bigintConfigHelper(DefaultSlasherConfig.slashAttestDescendantOfInvalidPenalty)
115
+ },
116
+ slashAttestDescendantOfInvalidMaxPenalty: {
117
+ env: 'SLASH_ATTEST_DESCENDANT_OF_INVALID_MAX_PENALTY',
118
+ description: 'Maximum penalty amount for slashing a validator that attested to a descendant of an invalid block.',
119
+ ...bigintConfigHelper(DefaultSlasherConfig.slashAttestDescendantOfInvalidMaxPenalty)
120
+ },
126
121
  slashProposerRoundPollingIntervalSeconds: {
127
122
  description: 'Polling interval for slashing proposer round in seconds.',
128
123
  ...numberConfigHelper(DefaultSlasherConfig.slashProposerRoundPollingIntervalSeconds)
124
+ },
125
+ slasherPrivateKey: {
126
+ description: 'Private key used for creating slash payloads.',
127
+ ...secretValueConfigHelper((val)=>val ? `0x${val.replace('0x', '')}` : NULL_KEY)
129
128
  }
130
129
  };
@@ -1,6 +1,6 @@
1
1
  import { EpochCache } from '@aztec/epoch-cache';
2
2
  import { L2Block, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
3
- import type { IFullNodeBlockBuilder, ITxCollector, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
3
+ import type { IFullNodeBlockBuilder, ITxProvider, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
4
4
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
5
5
  import { type WantToSlashArgs, type Watcher, type WatcherEmitter } from './config.js';
6
6
  declare const EpochPruneWatcher_base: new () => WatcherEmitter;
@@ -14,14 +14,15 @@ export declare class EpochPruneWatcher extends EpochPruneWatcher_base implements
14
14
  private l2BlockSource;
15
15
  private l1ToL2MessageSource;
16
16
  private epochCache;
17
- private txCollector;
17
+ private txProvider;
18
18
  private blockBuilder;
19
19
  private penalty;
20
20
  private maxPenalty;
21
21
  private log;
22
22
  private slashableCommittees;
23
23
  private maxSlashableEpochs;
24
- constructor(l2BlockSource: L2BlockSourceEventEmitter, l1ToL2MessageSource: L1ToL2MessageSource, epochCache: EpochCache, txCollector: ITxCollector, blockBuilder: IFullNodeBlockBuilder, penalty: bigint, maxPenalty: bigint);
24
+ private boundHandlePruneL2Blocks;
25
+ constructor(l2BlockSource: L2BlockSourceEventEmitter, l1ToL2MessageSource: L1ToL2MessageSource, epochCache: EpochCache, txProvider: Pick<ITxProvider, 'getAvailableTxs'>, blockBuilder: IFullNodeBlockBuilder, penalty: bigint, maxPenalty: bigint);
25
26
  start(): Promise<void>;
26
27
  stop(): Promise<void>;
27
28
  private handlePruneL2Blocks;
@@ -1 +1 @@
1
- {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../src/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAEL,OAAO,EAEP,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACtH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAUnE,OAAO,EAAgC,KAAK,eAAe,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;sCAQ5D,UAAU,cAAc;AANhF;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IAdpB,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,kBAAkB,CAAO;gBAGvB,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM;IAMrB,KAAK;IAKL,IAAI;IAKX,OAAO,CAAC,mBAAmB;IA8Cd,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BhG,OAAO,CAAC,oBAAoB;YAUd,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,mBAAmB;IAIpB,WAAW,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;CAS7E"}
1
+ {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../src/epoch_prune_watcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAEL,OAAO,EAEP,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACrH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAWnE,OAAO,EAAuB,KAAK,eAAe,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;sCAQnD,UAAU,cAAc;AANhF;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAYhG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IAjBpB,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,kBAAkB,CAAO;IAGjC,OAAO,CAAC,wBAAwB,CAAuC;gBAG7D,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,YAAY,EAAE,qBAAqB,EACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM;IAMrB,KAAK;IAKL,IAAI;IAKX,OAAO,CAAC,mBAAmB;IA8Cd,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgChG,OAAO,CAAC,oBAAoB;YAUd,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,mBAAmB;IAIpB,WAAW,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;CAS7E"}
@@ -1,8 +1,9 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
2
  import { L2BlockSourceEvents } from '@aztec/stdlib/block';
3
+ import { Offense } from '@aztec/stdlib/slashing';
3
4
  import { ReExFailedTxsError, ReExStateMismatchError, TransactionsNotAvailableError, ValidatorError } from '@aztec/stdlib/validators';
4
5
  import EventEmitter from 'node:events';
5
- import { Offense, WANT_TO_SLASH_EVENT } from './config.js';
6
+ import { WANT_TO_SLASH_EVENT } from './config.js';
6
7
  /**
7
8
  * This watcher is responsible for detecting chain prunes and creating slashing arguments for the committee.
8
9
  * It only wants to slash if:
@@ -12,7 +13,7 @@ import { Offense, WANT_TO_SLASH_EVENT } from './config.js';
12
13
  l2BlockSource;
13
14
  l1ToL2MessageSource;
14
15
  epochCache;
15
- txCollector;
16
+ txProvider;
16
17
  blockBuilder;
17
18
  penalty;
18
19
  maxPenalty;
@@ -21,16 +22,18 @@ import { Offense, WANT_TO_SLASH_EVENT } from './config.js';
21
22
  slashableCommittees;
22
23
  // Only keep track of the last N slashable epochs
23
24
  maxSlashableEpochs;
24
- constructor(l2BlockSource, l1ToL2MessageSource, epochCache, txCollector, blockBuilder, penalty, maxPenalty){
25
- super(), this.l2BlockSource = l2BlockSource, this.l1ToL2MessageSource = l1ToL2MessageSource, this.epochCache = epochCache, this.txCollector = txCollector, this.blockBuilder = blockBuilder, this.penalty = penalty, this.maxPenalty = maxPenalty, this.log = createLogger('epoch-prune-watcher'), this.slashableCommittees = new Map(), this.maxSlashableEpochs = 100;
25
+ // Store bound function reference for proper listener removal
26
+ boundHandlePruneL2Blocks;
27
+ constructor(l2BlockSource, l1ToL2MessageSource, epochCache, txProvider, blockBuilder, penalty, maxPenalty){
28
+ super(), this.l2BlockSource = l2BlockSource, this.l1ToL2MessageSource = l1ToL2MessageSource, this.epochCache = epochCache, this.txProvider = txProvider, this.blockBuilder = blockBuilder, this.penalty = penalty, this.maxPenalty = maxPenalty, this.log = createLogger('epoch-prune-watcher'), this.slashableCommittees = new Map(), this.maxSlashableEpochs = 100, this.boundHandlePruneL2Blocks = this.handlePruneL2Blocks.bind(this);
26
29
  this.log.info('EpochPruneWatcher initialized');
27
30
  }
28
31
  start() {
29
- this.l2BlockSource.on(L2BlockSourceEvents.L2PruneDetected, this.handlePruneL2Blocks.bind(this));
32
+ this.l2BlockSource.on(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
30
33
  return Promise.resolve();
31
34
  }
32
35
  stop() {
33
- this.l2BlockSource.removeListener(L2BlockSourceEvents.L2PruneDetected, this.handlePruneL2Blocks.bind(this));
36
+ this.l2BlockSource.removeListener(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
34
37
  return Promise.resolve();
35
38
  }
36
39
  handlePruneL2Blocks(event) {
@@ -89,9 +92,12 @@ import { Offense, WANT_TO_SLASH_EVENT } from './config.js';
89
92
  async validateBlock(blockFromL1, fork) {
90
93
  this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
91
94
  const txHashes = blockFromL1.body.txEffects.map((txEffect)=>txEffect.txHash);
92
- const { txs, missing } = await this.txCollector.collectTransactions(txHashes, undefined);
93
- if (missing && missing.length > 0) {
94
- throw new TransactionsNotAvailableError(missing);
95
+ // We load txs from the mempool directly, since the TxCollector running in the background has already been
96
+ // trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
97
+ // it's likely that they are not available in the network at all.
98
+ const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
99
+ if (missingTxs && missingTxs.length > 0) {
100
+ throw new TransactionsNotAvailableError(missingTxs);
95
101
  }
96
102
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockFromL1.number);
97
103
  const { block, failedTxs, numTxs } = await this.blockBuilder.buildBlock(txs, l1ToL2Messages, blockFromL1.header.globalVariables, {}, fork);
package/dest/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './config.js';
2
2
  export * from './epoch_prune_watcher.js';
3
3
  export * from './slasher_client.js';
4
+ export * from './attestations_block_watcher.js';
5
+ export * from '@aztec/stdlib/slashing';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC"}
package/dest/index.js CHANGED
@@ -1,3 +1,5 @@
1
1
  export * from './config.js';
2
2
  export * from './epoch_prune_watcher.js';
3
3
  export * from './slasher_client.js';
4
+ export * from './attestations_block_watcher.js';
5
+ export * from '@aztec/stdlib/slashing';
@@ -1,9 +1,11 @@
1
- import { type ExtendedViemWalletClient, type L1ReaderConfig, L1TxUtils, SlashingProposerContract } from '@aztec/ethereum';
1
+ import { type L1ReaderConfig, L1TxUtils, SlashingProposerContract, type ViemClient } from '@aztec/ethereum';
2
2
  import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { DateProvider } from '@aztec/foundation/timer';
4
4
  import { SlashFactoryAbi } from '@aztec/l1-artifacts';
5
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
6
+ import { type Offense } from '@aztec/stdlib/slashing';
5
7
  import { type GetContractReturnType } from 'viem';
6
- import { Offense, type SlasherConfig, type Watcher } from './config.js';
8
+ import { type Watcher } from './config.js';
7
9
  type MonitoredSlashPayload = {
8
10
  payloadAddress: EthAddress;
9
11
  validators: readonly EthAddress[];
@@ -37,8 +39,8 @@ type MonitoredSlashPayload = {
37
39
  * - TODO(#14421): Only vote on the proposal if it is possible to reach quorum, e.g., if 6 votes are needed and only 4 slots are left don't vote.
38
40
  */
39
41
  export declare class SlasherClient {
40
- config: SlasherConfig;
41
- protected slashFactoryContract: GetContractReturnType<typeof SlashFactoryAbi, ExtendedViemWalletClient>;
42
+ config: Omit<SlasherConfig, 'slasherPrivateKey'>;
43
+ protected slashFactoryContract: GetContractReturnType<typeof SlashFactoryAbi, ViemClient>;
42
44
  private slashingProposer;
43
45
  private l1TxUtils;
44
46
  private watchers;
@@ -47,22 +49,21 @@ export declare class SlasherClient {
47
49
  private monitoredPayloads;
48
50
  private unwatchCallbacks;
49
51
  private overridePayloadActive;
50
- static new(config: SlasherConfig, l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress'>, l1TxUtils: L1TxUtils, watchers: Watcher[], dateProvider: DateProvider): Promise<SlasherClient>;
51
- constructor(config: SlasherConfig, slashFactoryContract: GetContractReturnType<typeof SlashFactoryAbi, ExtendedViemWalletClient>, slashingProposer: SlashingProposerContract, l1TxUtils: L1TxUtils, watchers: Watcher[], dateProvider: DateProvider, log?: import("@aztec/foundation/log").Logger);
52
- start(): void;
52
+ private slashingExecutionDelayInRounds;
53
+ static new(config: Omit<SlasherConfig, 'slasherPrivateKey'>, l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress'>, l1TxUtils: L1TxUtils | undefined, l1Client: ViemClient, watchers: Watcher[], dateProvider: DateProvider): Promise<SlasherClient>;
54
+ constructor(config: Omit<SlasherConfig, 'slasherPrivateKey'>, slashFactoryContract: GetContractReturnType<typeof SlashFactoryAbi, ViemClient>, slashingProposer: SlashingProposerContract, l1TxUtils: L1TxUtils | undefined, watchers: Watcher[], dateProvider: DateProvider, log?: import("@aztec/foundation/log").Logger);
55
+ start(): Promise<void>;
53
56
  /**
54
57
  * Allows consumers to stop the instance of the slasher client.
55
58
  * 'ready' will now return 'false' and the running promise that keeps the client synced is interrupted.
56
59
  */
57
60
  stop(): Promise<void>;
58
61
  clearMonitoredPayloads(): void;
62
+ setSlashingProposer(slashingProposer: SlashingProposerContract): Promise<void>;
59
63
  /**
60
64
  * Update the config of the slasher client
61
65
  *
62
- * @param config - the new config. Can only update the following fields:
63
- * - slashOverridePayload
64
- * - slashPayloadTtlSeconds
65
- * - slashProposerRoundPollingIntervalSeconds
66
+ * @param config - the new config. Cannot update the slasher private key.
66
67
  */
67
68
  updateConfig(config: Partial<SlasherConfig>): void;
68
69
  /**
@@ -89,9 +90,9 @@ export declare class SlasherClient {
89
90
  *
90
91
  * @param {round: bigint; proposal: `0x${string}`} param0
91
92
  */
92
- protected proposalExecuted({ round, proposal }: {
93
+ protected payloadSubmitted({ round, payload }: {
93
94
  round: bigint;
94
- proposal: `0x${string}`;
95
+ payload: `0x${string}`;
95
96
  }): void;
96
97
  /**
97
98
  * This is called when a watcher emits WANT_TO_SLASH_EVENT.
@@ -144,13 +145,13 @@ export declare class SlasherClient {
144
145
  */
145
146
  private filterExpiredPayloads;
146
147
  /**
147
- * Execute a round if we agree with the proposal.
148
+ * Submit a round to the Slasher if we agree with the payload.
148
149
  *
149
- * Bound to the slashing proposer contract's listenToExecutableProposals method in the constructor.
150
+ * Bound to the slashing proposer contract's listenToSubmittablePayloads method in the constructor.
150
151
  *
151
152
  * @param {proposal: `0x${string}`; round: bigint} param0
152
153
  */
153
- private executeRoundIfAgree;
154
+ private submitRoundIfAgree;
154
155
  private getAddressAndIsDeployed;
155
156
  }
156
157
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"slasher_client.d.ts","sourceRoot":"","sources":["../src/slasher_client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,SAAS,EAGT,wBAAwB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAG3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAEL,KAAK,qBAAqB,EAK3B,MAAM,MAAM,CAAC;AAEd,OAAO,EACL,OAAO,EACP,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEb,MAAM,aAAa,CAAC;AAErB,KAAK,qBAAqB,GAAG;IAC3B,cAAc,EAAE,UAAU,CAAC;IAC3B,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC;IAClC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,aAAa;IA+Bf,MAAM,EAAE,aAAa;IAC5B,SAAS,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,OAAO,eAAe,EAAE,wBAAwB,CAAC;IACvG,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,GAAG;IApCb,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,qBAAqB,CAAS;WAEzB,GAAG,CACd,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,eAAe,GAAG,qBAAqB,CAAC,EACzF,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,EAAE,YAAY;gBAqBnB,MAAM,EAAE,aAAa,EAClB,oBAAoB,EAAE,qBAAqB,CAAC,OAAO,eAAe,EAAE,wBAAwB,CAAC,EAC/F,gBAAgB,EAAE,wBAAwB,EAC1C,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,EAAE,YAAY,EAC1B,GAAG,yCAA0B;IAOhC,KAAK;IAoBZ;;;OAGG;IACU,IAAI;IAeV,sBAAsB;IAK7B;;;;;;;OAOG;IACI,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC;IAYlD;;;;;OAKG;IACI,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAoB5E;;;;;;OAMG;IACI,oBAAoB,IAAI,qBAAqB,EAAE;IAMtD;;;;;;;;OAQG;IACH,SAAS,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE;IAiB1F;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA4DnB;;;;;;;;OAQG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;;;;OAKG;IACH,OAAO,CAAE,gCAAgC;IAezC,OAAO,CAAC,8BAA8B;IAgBtC;;;;OAIG;YACW,mBAAmB;IAgBjC;;;;;;;OAOG;YACW,mBAAmB;IAqBjC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;;OAMG;YACW,mBAAmB;YAkCnB,uBAAuB;CAUtC"}
1
+ {"version":3,"file":"slasher_client.d.ts","sourceRoot":"","sources":["../src/slasher_client.ts"],"names":[],"mappings":"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"}