@aztec/slasher 0.0.1-commit.a072138 → 0.0.1-commit.a89ec08
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 +24 -14
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +13 -1
- package/dest/factory/create_facade.d.ts +2 -2
- package/dest/factory/create_facade.d.ts.map +1 -1
- package/dest/factory/create_facade.js +25 -2
- package/dest/factory/create_implementation.d.ts +3 -2
- package/dest/factory/create_implementation.d.ts.map +1 -1
- package/dest/factory/create_implementation.js +11 -7
- package/dest/factory/get_settings.d.ts +2 -2
- package/dest/factory/get_settings.d.ts.map +1 -1
- package/dest/generated/slasher-defaults.d.ts +3 -1
- package/dest/generated/slasher-defaults.d.ts.map +1 -1
- package/dest/generated/slasher-defaults.js +2 -0
- package/dest/slash_offenses_collector.d.ts +5 -2
- package/dest/slash_offenses_collector.d.ts.map +1 -1
- package/dest/slash_offenses_collector.js +3 -7
- package/dest/slasher_client_facade.d.ts +3 -2
- package/dest/slasher_client_facade.d.ts.map +1 -1
- package/dest/slasher_client_facade.js +4 -2
- package/dest/tally_slasher_client.d.ts +2 -2
- package/dest/tally_slasher_client.d.ts.map +1 -1
- package/dest/tally_slasher_client.js +6 -6
- package/dest/watchers/epoch_prune_watcher.d.ts +6 -5
- package/dest/watchers/epoch_prune_watcher.d.ts.map +1 -1
- package/dest/watchers/epoch_prune_watcher.js +47 -26
- package/package.json +9 -9
- package/src/config.ts +15 -1
- package/src/factory/create_facade.ts +31 -2
- package/src/factory/create_implementation.ts +28 -3
- package/src/factory/get_settings.ts +2 -2
- package/src/generated/slasher-defaults.ts +2 -0
- package/src/slash_offenses_collector.ts +9 -8
- package/src/slasher_client_facade.ts +2 -0
- package/src/tally_slasher_client.ts +8 -7
- package/src/watchers/epoch_prune_watcher.ts +61 -26
package/README.md
CHANGED
|
@@ -137,9 +137,15 @@ List of all slashable offenses in the system:
|
|
|
137
137
|
**Time Unit**: Slot-based offense.
|
|
138
138
|
|
|
139
139
|
### ATTESTED_DESCENDANT_OF_INVALID
|
|
140
|
-
**Description**: A committee member attested to a block built on top of an invalid ancestor.
|
|
141
|
-
**Detection**: AttestationsBlockWatcher tracks invalid blocks and their descendants.
|
|
142
|
-
**Target**: Committee members who attested to the descendant block.
|
|
140
|
+
**Description**: A committee member attested to a block built on top of an invalid ancestor.
|
|
141
|
+
**Detection**: AttestationsBlockWatcher tracks invalid blocks and their descendants.
|
|
142
|
+
**Target**: Committee members who attested to the descendant block.
|
|
143
|
+
**Time Unit**: Slot-based offense.
|
|
144
|
+
|
|
145
|
+
### DUPLICATE_PROPOSAL
|
|
146
|
+
**Description**: A proposer sent multiple block or checkpoint proposals for the same position (slot and indexWithinCheckpoint for blocks, or slot for checkpoints) with different content. Since each slot has exactly one designated proposer, sending conflicting proposals is equivocation.
|
|
147
|
+
**Detection**: Detected in the P2P layer when proposals are received. The AttestationPool tracks proposals by position; when a second proposal arrives for the same position with a different archive, it flags the duplicate. The first duplicate is propagated (Accept) so other validators can witness the offense.
|
|
148
|
+
**Target**: Proposer who broadcast the duplicate proposal.
|
|
143
149
|
**Time Unit**: Slot-based offense.
|
|
144
150
|
|
|
145
151
|
## Configuration
|
|
@@ -175,10 +181,11 @@ These settings are configured locally on each validator node:
|
|
|
175
181
|
- `slashDataWithholdingPenalty`: Penalty for DATA_WITHHOLDING
|
|
176
182
|
- `slashInactivityPenalty`: Penalty for INACTIVITY
|
|
177
183
|
- `slashBroadcastedInvalidBlockPenalty`: Penalty for BROADCASTED_INVALID_BLOCK_PROPOSAL
|
|
184
|
+
- `slashDuplicateProposalPenalty`: Penalty for DUPLICATE_PROPOSAL
|
|
178
185
|
- `slashProposeInvalidAttestationsPenalty`: Penalty for PROPOSED_INSUFFICIENT_ATTESTATIONS and PROPOSED_INCORRECT_ATTESTATIONS
|
|
179
186
|
- `slashAttestDescendantOfInvalidPenalty`: Penalty for ATTESTED_DESCENDANT_OF_INVALID
|
|
180
187
|
- `slashUnknownPenalty`: Default penalty for unknown offense types
|
|
181
|
-
- `slashMaxPayloadSize`: Maximum size of slash payloads
|
|
188
|
+
- `slashMaxPayloadSize`: Maximum size of slash payloads. In the empire model this limits offenses per payload. In the tally model it limits the number of **unique validators** (across all committees and epochs in a round) that receive non-zero votes. When this cap is hit, the lowest-severity validator-epoch pairs are zeroed out first, so the most severe slashes are always preserved. Note that multiple offenses for the same validator in the same epoch are summed and counted as a single validator entry against this limit.
|
|
182
189
|
- `slashMinPenaltyPercentage`: Agree to slashes if they are at least this percentage of the configured penalty (empire model)
|
|
183
190
|
- `slashMaxPenaltyPercentage`: Agree to slashes if they are at most this percentage of the configured penalty (empire model)
|
|
184
191
|
|
|
@@ -195,21 +202,24 @@ Details about specific offenses in the system:
|
|
|
195
202
|
|
|
196
203
|
Inactivity slashing is one of the most critical, since it allows purging validators that are not fulfilling their duties, which could potentially bring the chain to a halt. This slashing must be aggressive enough to balance out the rate of the entry queue, in case the queue is filled with inactive validators. Furthermore, if enough inactive validators join the system, it may become impossible to gather enough quorum to pass any governance proposal.
|
|
197
204
|
|
|
198
|
-
Inactivity slashing is handled by the `Sentinel` which monitors performance of all validators slot-by-slot. After each slot, the sentinel assigns one of the following to the
|
|
199
|
-
- `
|
|
200
|
-
- `
|
|
201
|
-
- `
|
|
205
|
+
Inactivity slashing is handled by the `Sentinel` which monitors performance of all validators slot-by-slot. With the multiple-blocks-per-slot model, block proposals and checkpoints are distinct concepts: proposers build multiple blocks per slot, but attestations are only for checkpoints. After each slot, the sentinel assigns one of the following to the proposer for the slot:
|
|
206
|
+
- `checkpoint-mined` if the checkpoint was added to L1
|
|
207
|
+
- `checkpoint-proposed` if the checkpoint received at least one attestation, but didn't make it to L1
|
|
208
|
+
- `checkpoint-missed` if blocks were proposed but the checkpoint received no attestations
|
|
209
|
+
- `blocks-missed` if no block proposals were sent for this slot at all
|
|
210
|
+
|
|
211
|
+
And assigns one of the following to each validator (these refer to checkpoint attestations):
|
|
212
|
+
- `attestation-sent` if there was a `checkpoint-proposed` or `checkpoint-mined` and a checkpoint attestation from this validator was seen on either on L1 or on the P2P network
|
|
213
|
+
- `attestation-missed` if there was a `checkpoint-proposed` or `checkpoint-mined` but no checkpoint attestation was seen
|
|
214
|
+
- none if the slot was a `blocks-missed`
|
|
202
215
|
|
|
203
|
-
|
|
204
|
-
- `attestation-sent` if there was a `block-proposed` or `block-mined` and an attestation from this validator was seen on either on L1 or on the P2P network
|
|
205
|
-
- `attestation-missed` if there was a `block-proposed` or `block-mined` but no attestation was seen
|
|
206
|
-
- none if the slot was a `block-missed`
|
|
216
|
+
Both `blocks-missed` and `checkpoint-missed` count as proposer inactivity.
|
|
207
217
|
|
|
208
218
|
Once an epoch is proven, the sentinel computes the _proven performance_ for the epoch for each validator. Note that we wait until the epoch is proven so we know that the data for all blocks in the epoch was available, and validators who did not attest were effectively inactive. Then, for each validator such that:
|
|
209
219
|
|
|
210
220
|
```
|
|
211
|
-
total_failures = count(
|
|
212
|
-
total = count(
|
|
221
|
+
total_failures = count(blocks-missed) + count(checkpoint-missed) + count(attestation-missed)
|
|
222
|
+
total = count(checkpoint-*) + count(blocks-*) + count(attestation-*)
|
|
213
223
|
total_failures / total >= slash_inactivity_target_percentage
|
|
214
224
|
```
|
|
215
225
|
|
package/dest/config.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
|
3
3
|
export type { SlasherConfig };
|
|
4
4
|
export declare const DefaultSlasherConfig: SlasherConfig;
|
|
5
5
|
export declare const slasherConfigMappings: ConfigMappingsType<SlasherConfig>;
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRbkUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFJckUsWUFBWSxFQUFFLGFBQWEsRUFBRSxDQUFDO0FBRTlCLGVBQU8sTUFBTSxvQkFBb0IsRUFBRSxhQXNCbEMsQ0FBQztBQUVGLGVBQU8sTUFBTSxxQkFBcUIsRUFBRSxrQkFBa0IsQ0FBQyxhQUFhLENBcUluRSxDQUFDIn0=
|
package/dest/config.d.ts.map
CHANGED
|
@@ -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;AAQnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAIrE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,eAAO,MAAM,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAQnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAIrE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,eAAO,MAAM,oBAAoB,EAAE,aAsBlC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,CAAC,aAAa,CAqInE,CAAC"}
|
package/dest/config.js
CHANGED
|
@@ -12,6 +12,8 @@ export const DefaultSlasherConfig = {
|
|
|
12
12
|
slashInactivityTargetPercentage: slasherDefaultEnv.SLASH_INACTIVITY_TARGET_PERCENTAGE,
|
|
13
13
|
slashInactivityConsecutiveEpochThreshold: slasherDefaultEnv.SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD,
|
|
14
14
|
slashBroadcastedInvalidBlockPenalty: BigInt(slasherDefaultEnv.SLASH_INVALID_BLOCK_PENALTY),
|
|
15
|
+
slashDuplicateProposalPenalty: BigInt(slasherDefaultEnv.SLASH_DUPLICATE_PROPOSAL_PENALTY),
|
|
16
|
+
slashDuplicateAttestationPenalty: BigInt(slasherDefaultEnv.SLASH_DUPLICATE_ATTESTATION_PENALTY),
|
|
15
17
|
slashInactivityPenalty: BigInt(slasherDefaultEnv.SLASH_INACTIVITY_PENALTY),
|
|
16
18
|
slashProposeInvalidAttestationsPenalty: BigInt(slasherDefaultEnv.SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY),
|
|
17
19
|
slashAttestDescendantOfInvalidPenalty: BigInt(slasherDefaultEnv.SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY),
|
|
@@ -66,6 +68,16 @@ export const slasherConfigMappings = {
|
|
|
66
68
|
description: 'Penalty amount for slashing a validator for an invalid block proposed via p2p.',
|
|
67
69
|
...bigintConfigHelper(DefaultSlasherConfig.slashBroadcastedInvalidBlockPenalty)
|
|
68
70
|
},
|
|
71
|
+
slashDuplicateProposalPenalty: {
|
|
72
|
+
env: 'SLASH_DUPLICATE_PROPOSAL_PENALTY',
|
|
73
|
+
description: 'Penalty amount for slashing a validator for sending duplicate proposals.',
|
|
74
|
+
...bigintConfigHelper(DefaultSlasherConfig.slashDuplicateProposalPenalty)
|
|
75
|
+
},
|
|
76
|
+
slashDuplicateAttestationPenalty: {
|
|
77
|
+
env: 'SLASH_DUPLICATE_ATTESTATION_PENALTY',
|
|
78
|
+
description: 'Penalty amount for slashing a validator for signing attestations for different proposals at the same slot.',
|
|
79
|
+
...bigintConfigHelper(DefaultSlasherConfig.slashDuplicateAttestationPenalty)
|
|
80
|
+
},
|
|
69
81
|
slashInactivityTargetPercentage: {
|
|
70
82
|
env: 'SLASH_INACTIVITY_TARGET_PERCENTAGE',
|
|
71
83
|
description: 'Missed attestation percentage to trigger creation of inactivity slash payload (0, 1]. Must be greater than 0',
|
|
@@ -118,7 +130,7 @@ export const slasherConfigMappings = {
|
|
|
118
130
|
...numberConfigHelper(DefaultSlasherConfig.slashMaxPayloadSize)
|
|
119
131
|
},
|
|
120
132
|
slashGracePeriodL2Slots: {
|
|
121
|
-
description: 'Number of L2 slots
|
|
133
|
+
description: 'Number of L2 slots after the network upgrade during which slashing offenses are ignored. The upgrade time is determined from the CanonicalRollupUpdated event.',
|
|
122
134
|
env: 'SLASH_GRACE_PERIOD_L2_SLOTS',
|
|
123
135
|
...numberConfigHelper(DefaultSlasherConfig.slashGracePeriodL2Slots)
|
|
124
136
|
},
|
|
@@ -10,7 +10,7 @@ import type { Watcher } from '../watcher.js';
|
|
|
10
10
|
/** Creates a slasher client facade that updates itself whenever the rollup slasher changes */
|
|
11
11
|
export declare function createSlasherFacade(config: SlasherConfig & DataStoreConfig & {
|
|
12
12
|
ethereumSlotDuration: number;
|
|
13
|
-
}, l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress'>, l1Client: ViemClient, watchers: Watcher[], dateProvider: DateProvider, epochCache: EpochCache,
|
|
13
|
+
}, l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress' | 'registryAddress'>, l1Client: ViemClient, watchers: Watcher[], dateProvider: DateProvider, epochCache: EpochCache,
|
|
14
14
|
/** List of own validator addresses to add to the slashValidatorNever list unless slashSelfAllowed is true */
|
|
15
15
|
validatorAddresses?: EthAddress[], logger?: import("@aztec/foundation/log").Logger): Promise<SlasherClientInterface>;
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2ZhY2FkZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZhY3RvcnkvY3JlYXRlX2ZhY2FkZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFaEQsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDaEUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUc5RCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUdyRSxPQUFPLEtBQUssRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRTdFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU3Qyw4RkFBOEY7QUFDOUYsd0JBQXNCLG1CQUFtQixDQUN2QyxNQUFNLEVBQUUsYUFBYSxHQUFHLGVBQWUsR0FBRztJQUFFLG9CQUFvQixFQUFFLE1BQU0sQ0FBQTtDQUFFLEVBQzFFLFdBQVcsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsQ0FBQyxFQUFFLGVBQWUsR0FBRyxxQkFBcUIsR0FBRyxpQkFBaUIsQ0FBQyxFQUM3RyxRQUFRLEVBQUUsVUFBVSxFQUNwQixRQUFRLEVBQUUsT0FBTyxFQUFFLEVBQ25CLFlBQVksRUFBRSxZQUFZLEVBQzFCLFVBQVUsRUFBRSxVQUFVO0FBQ3RCLDZHQUE2RztBQUM3RyxrQkFBa0IsR0FBRSxVQUFVLEVBQU8sRUFDckMsTUFBTSx5Q0FBMEIsR0FDL0IsT0FBTyxDQUFDLHNCQUFzQixDQUFDLENBbURqQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_facade.d.ts","sourceRoot":"","sources":["../../src/factory/create_facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"create_facade.d.ts","sourceRoot":"","sources":["../../src/factory/create_facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,8FAA8F;AAC9F,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,EAC1E,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB,CAAC,EAC7G,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,OAAO,EAAE,EACnB,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,UAAU;AACtB,6GAA6G;AAC7G,kBAAkB,GAAE,UAAU,EAAO,EACrC,MAAM,yCAA0B,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CAmDjC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
1
|
+
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
2
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { unique } from '@aztec/foundation/collection';
|
|
3
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
7
|
+
import { getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
6
8
|
import { SlasherClientFacade } from '../slasher_client_facade.js';
|
|
7
9
|
import { SCHEMA_VERSION } from '../stores/schema_version.js';
|
|
8
10
|
/** Creates a slasher client facade that updates itself whenever the rollup slasher changes */ export async function createSlasherFacade(config, l1Contracts, l1Client, watchers, dateProvider, epochCache, /** List of own validator addresses to add to the slashValidatorNever list unless slashSelfAllowed is true */ validatorAddresses = [], logger = createLogger('slasher')) {
|
|
@@ -11,6 +13,27 @@ import { SCHEMA_VERSION } from '../stores/schema_version.js';
|
|
|
11
13
|
}
|
|
12
14
|
const kvStore = await createStore('slasher', SCHEMA_VERSION, config, logger.getBindings());
|
|
13
15
|
const rollup = new RollupContract(l1Client, l1Contracts.rollupAddress);
|
|
16
|
+
// Compute and cache the L2 slot at which the rollup was registered as canonical
|
|
17
|
+
const settingsMap = kvStore.openMap('slasher-settings');
|
|
18
|
+
const cacheKey = `registeredSlot:${l1Contracts.rollupAddress}`;
|
|
19
|
+
let rollupRegisteredAtL2Slot = await settingsMap.getAsync(cacheKey);
|
|
20
|
+
if (rollupRegisteredAtL2Slot === undefined) {
|
|
21
|
+
const registry = new RegistryContract(l1Client, l1Contracts.registryAddress);
|
|
22
|
+
const l1StartBlock = await rollup.getL1StartBlock();
|
|
23
|
+
const registrationTimestamp = await registry.getCanonicalRollupRegistrationTimestamp(l1Contracts.rollupAddress, l1StartBlock);
|
|
24
|
+
if (registrationTimestamp !== undefined) {
|
|
25
|
+
const l1GenesisTime = await rollup.getL1GenesisTime();
|
|
26
|
+
const slotDuration = await rollup.getSlotDuration();
|
|
27
|
+
rollupRegisteredAtL2Slot = getSlotAtTimestamp(registrationTimestamp, {
|
|
28
|
+
l1GenesisTime,
|
|
29
|
+
slotDuration: Number(slotDuration)
|
|
30
|
+
});
|
|
31
|
+
} else {
|
|
32
|
+
rollupRegisteredAtL2Slot = SlotNumber(0);
|
|
33
|
+
}
|
|
34
|
+
await settingsMap.set(cacheKey, rollupRegisteredAtL2Slot);
|
|
35
|
+
logger.info(`Canonical rollup registered at L2 slot ${rollupRegisteredAtL2Slot}`);
|
|
36
|
+
}
|
|
14
37
|
const slashValidatorsNever = config.slashSelfAllowed ? config.slashValidatorsNever : unique([
|
|
15
38
|
...config.slashValidatorsNever,
|
|
16
39
|
...validatorAddresses
|
|
@@ -19,5 +42,5 @@ import { SCHEMA_VERSION } from '../stores/schema_version.js';
|
|
|
19
42
|
...config,
|
|
20
43
|
slashValidatorsNever
|
|
21
44
|
};
|
|
22
|
-
return new SlasherClientFacade(updatedConfig, rollup, l1Client, l1Contracts.slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, logger);
|
|
45
|
+
return new SlasherClientFacade(updatedConfig, rollup, l1Client, l1Contracts.slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger);
|
|
23
46
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
2
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
3
3
|
import type { ViemClient } from '@aztec/ethereum/types';
|
|
4
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
6
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
6
7
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
@@ -13,5 +14,5 @@ import type { Watcher } from '../watcher.js';
|
|
|
13
14
|
/** Creates a slasher client implementation (either tally or empire) based on the slasher proposer type in the rollup */
|
|
14
15
|
export declare function createSlasherImplementation(config: SlasherConfig & DataStoreConfig & {
|
|
15
16
|
ethereumSlotDuration: number;
|
|
16
|
-
}, rollup: RollupContract, l1Client: ViemClient, slashFactoryAddress: EthAddress | undefined, watchers: Watcher[], epochCache: EpochCache, dateProvider: DateProvider, kvStore: AztecLMDBStoreV2, logger?: import("@aztec/foundation/log").Logger): Promise<EmpireSlasherClient | NullSlasherClient | TallySlasherClient>;
|
|
17
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
17
|
+
}, rollup: RollupContract, l1Client: ViemClient, slashFactoryAddress: EthAddress | undefined, watchers: Watcher[], epochCache: EpochCache, dateProvider: DateProvider, kvStore: AztecLMDBStoreV2, rollupRegisteredAtL2Slot: SlotNumber, logger?: import("@aztec/foundation/log").Logger): Promise<EmpireSlasherClient | NullSlasherClient | TallySlasherClient>;
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2ltcGxlbWVudGF0aW9uLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFjdG9yeS9jcmVhdGVfaW1wbGVtZW50YXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFFTCxjQUFjLEVBRWYsTUFBTSwyQkFBMkIsQ0FBQztBQUNuQyxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN4RCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFM0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzNELE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBR3JFLE9BQU8sRUFBRSxtQkFBbUIsRUFBOEIsTUFBTSw2QkFBNkIsQ0FBQztBQUM5RixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUc5RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHN0Msd0hBQXdIO0FBQ3hILHdCQUFzQiwyQkFBMkIsQ0FDL0MsTUFBTSxFQUFFLGFBQWEsR0FBRyxlQUFlLEdBQUc7SUFBRSxvQkFBb0IsRUFBRSxNQUFNLENBQUE7Q0FBRSxFQUMxRSxNQUFNLEVBQUUsY0FBYyxFQUN0QixRQUFRLEVBQUUsVUFBVSxFQUNwQixtQkFBbUIsRUFBRSxVQUFVLEdBQUcsU0FBUyxFQUMzQyxRQUFRLEVBQUUsT0FBTyxFQUFFLEVBQ25CLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFlBQVksRUFBRSxZQUFZLEVBQzFCLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsd0JBQXdCLEVBQUUsVUFBVSxFQUNwQyxNQUFNLHlDQUEwQix5RUFrQ2pDIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create_implementation.d.ts","sourceRoot":"","sources":["../../src/factory/create_implementation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAEL,cAAc,EAEf,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAA8B,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,wHAAwH;AACxH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,EAC1E,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,UAAU,EACpB,mBAAmB,EAAE,UAAU,GAAG,SAAS,EAC3C,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,gBAAgB,EACzB,MAAM,yCAA0B,
|
|
1
|
+
{"version":3,"file":"create_implementation.d.ts","sourceRoot":"","sources":["../../src/factory/create_implementation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAEL,cAAc,EAEf,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAA8B,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,wHAAwH;AACxH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,EAC1E,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,UAAU,EACpB,mBAAmB,EAAE,UAAU,GAAG,SAAS,EAC3C,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,gBAAgB,EACzB,wBAAwB,EAAE,UAAU,EACpC,MAAM,yCAA0B,yEAkCjC"}
|
|
@@ -7,21 +7,21 @@ import { SlasherOffensesStore } from '../stores/offenses_store.js';
|
|
|
7
7
|
import { SlasherPayloadsStore } from '../stores/payloads_store.js';
|
|
8
8
|
import { TallySlasherClient } from '../tally_slasher_client.js';
|
|
9
9
|
import { getTallySlasherSettings } from './get_settings.js';
|
|
10
|
-
/** Creates a slasher client implementation (either tally or empire) based on the slasher proposer type in the rollup */ export async function createSlasherImplementation(config, rollup, l1Client, slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, logger = createLogger('slasher')) {
|
|
10
|
+
/** Creates a slasher client implementation (either tally or empire) based on the slasher proposer type in the rollup */ export async function createSlasherImplementation(config, rollup, l1Client, slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
|
|
11
11
|
const proposer = await rollup.getSlashingProposer();
|
|
12
12
|
if (!proposer) {
|
|
13
13
|
return new NullSlasherClient(config);
|
|
14
14
|
} else if (proposer.type === 'tally') {
|
|
15
|
-
return createTallySlasher(config, rollup, proposer, watchers, dateProvider, epochCache, kvStore, logger);
|
|
15
|
+
return createTallySlasher(config, rollup, proposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger);
|
|
16
16
|
} else {
|
|
17
17
|
if (!slashFactoryAddress || slashFactoryAddress.equals(EthAddress.ZERO)) {
|
|
18
18
|
throw new Error('Cannot initialize an empire-based SlasherClient without a SlashFactory address');
|
|
19
19
|
}
|
|
20
20
|
const slashFactory = new SlashFactoryContract(l1Client, slashFactoryAddress.toString());
|
|
21
|
-
return createEmpireSlasher(config, rollup, proposer, slashFactory, watchers, dateProvider, kvStore, logger);
|
|
21
|
+
return createEmpireSlasher(config, rollup, proposer, slashFactory, watchers, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
async function createEmpireSlasher(config, rollup, slashingProposer, slashFactoryContract, watchers, dateProvider, kvStore, logger = createLogger('slasher')) {
|
|
24
|
+
async function createEmpireSlasher(config, rollup, slashingProposer, slashFactoryContract, watchers, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
|
|
25
25
|
if (slashingProposer.type !== 'empire') {
|
|
26
26
|
throw new Error('Slashing proposer contract is not of type Empire');
|
|
27
27
|
}
|
|
@@ -48,7 +48,8 @@ async function createEmpireSlasher(config, rollup, slashingProposer, slashFactor
|
|
|
48
48
|
slotDuration: Number(slotDuration),
|
|
49
49
|
l1StartBlock,
|
|
50
50
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
51
|
-
slashingAmounts: undefined
|
|
51
|
+
slashingAmounts: undefined,
|
|
52
|
+
rollupRegisteredAtL2Slot
|
|
52
53
|
};
|
|
53
54
|
const payloadsStore = new SlasherPayloadsStore(kvStore, {
|
|
54
55
|
slashingPayloadLifetimeInRounds: settings.slashingPayloadLifetimeInRounds
|
|
@@ -59,11 +60,14 @@ async function createEmpireSlasher(config, rollup, slashingProposer, slashFactor
|
|
|
59
60
|
});
|
|
60
61
|
return new EmpireSlasherClient(config, settings, slashFactoryContract, slashingProposer, slasher, rollup, watchers, dateProvider, offensesStore, payloadsStore, logger);
|
|
61
62
|
}
|
|
62
|
-
async function createTallySlasher(config, rollup, slashingProposer, watchers, dateProvider, epochCache, kvStore, logger = createLogger('slasher')) {
|
|
63
|
+
async function createTallySlasher(config, rollup, slashingProposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
|
|
63
64
|
if (slashingProposer.type !== 'tally') {
|
|
64
65
|
throw new Error('Slashing proposer contract is not of type tally');
|
|
65
66
|
}
|
|
66
|
-
const settings =
|
|
67
|
+
const settings = {
|
|
68
|
+
...await getTallySlasherSettings(rollup, slashingProposer),
|
|
69
|
+
rollupRegisteredAtL2Slot
|
|
70
|
+
};
|
|
67
71
|
const slasher = await rollup.getSlasherContract();
|
|
68
72
|
const offensesStore = new SlasherOffensesStore(kvStore, {
|
|
69
73
|
...settings,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { RollupContract, TallySlashingProposerContract } from '@aztec/ethereum/contracts';
|
|
2
2
|
import type { TallySlasherSettings } from '../tally_slasher_client.js';
|
|
3
|
-
export declare function getTallySlasherSettings(rollup: RollupContract, slashingProposer?: TallySlashingProposerContract): Promise<TallySlasherSettings
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
3
|
+
export declare function getTallySlasherSettings(rollup: RollupContract, slashingProposer?: TallySlashingProposerContract): Promise<Omit<TallySlasherSettings, 'rollupRegisteredAtL2Slot'>>;
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0X3NldHRpbmdzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFjdG9yeS9nZXRfc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0YsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUV2RSx3QkFBc0IsdUJBQXVCLENBQzNDLE1BQU0sRUFBRSxjQUFjLEVBQ3RCLGdCQUFnQixDQUFDLEVBQUUsNkJBQTZCLEdBQy9DLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQWtEakUifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_settings.d.ts","sourceRoot":"","sources":["../../src/factory/get_settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAE/F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,cAAc,EACtB,gBAAgB,CAAC,EAAE,6BAA6B,GAC/C,OAAO,CAAC,oBAAoB,CAAC,
|
|
1
|
+
{"version":3,"file":"get_settings.d.ts","sourceRoot":"","sources":["../../src/factory/get_settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAE/F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,cAAc,EACtB,gBAAgB,CAAC,EAAE,6BAA6B,GAC/C,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,0BAA0B,CAAC,CAAC,CAkDjE"}
|
|
@@ -12,8 +12,10 @@ export declare const slasherDefaultEnv: {
|
|
|
12
12
|
readonly SLASH_INACTIVITY_PENALTY: 10000000000000000000;
|
|
13
13
|
readonly SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000;
|
|
14
14
|
readonly SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000;
|
|
15
|
+
readonly SLASH_DUPLICATE_PROPOSAL_PENALTY: 0;
|
|
16
|
+
readonly SLASH_DUPLICATE_ATTESTATION_PENALTY: 0;
|
|
15
17
|
readonly SLASH_UNKNOWN_PENALTY: 10000000000000000000;
|
|
16
18
|
readonly SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000;
|
|
17
19
|
readonly SLASH_GRACE_PERIOD_L2_SLOTS: 0;
|
|
18
20
|
};
|
|
19
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlci1kZWZhdWx0cy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dlbmVyYXRlZC9zbGFzaGVyLWRlZmF1bHRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLHFFQUFxRTtBQUNyRSxlQUFPLE1BQU0saUJBQWlCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FrQnBCLENBQUMifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slasher-defaults.d.ts","sourceRoot":"","sources":["../../src/generated/slasher-defaults.ts"],"names":[],"mappings":"AAGA,qEAAqE;AACrE,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"slasher-defaults.d.ts","sourceRoot":"","sources":["../../src/generated/slasher-defaults.ts"],"names":[],"mappings":"AAGA,qEAAqE;AACrE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;CAkBpB,CAAC"}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
SLASH_INACTIVITY_PENALTY: 10000000000000000000,
|
|
14
14
|
SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
|
|
15
15
|
SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000,
|
|
16
|
+
SLASH_DUPLICATE_PROPOSAL_PENALTY: 0,
|
|
17
|
+
SLASH_DUPLICATE_ATTESTATION_PENALTY: 0,
|
|
16
18
|
SLASH_UNKNOWN_PENALTY: 10000000000000000000,
|
|
17
19
|
SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
|
|
18
20
|
SLASH_GRACE_PERIOD_L2_SLOTS: 0
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import type { Prettify } from '@aztec/foundation/types';
|
|
2
3
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
3
4
|
import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
@@ -7,6 +8,8 @@ import { type WantToSlashArgs, type Watcher } from './watcher.js';
|
|
|
7
8
|
export type SlashOffensesCollectorConfig = Prettify<Pick<SlasherConfig, 'slashGracePeriodL2Slots'>>;
|
|
8
9
|
export type SlashOffensesCollectorSettings = Prettify<Pick<L1RollupConstants, 'epochDuration'> & {
|
|
9
10
|
slashingAmounts: [bigint, bigint, bigint] | undefined;
|
|
11
|
+
/** L2 slot at which the rollup was registered as canonical in the Registry. Used to anchor the slash grace period. */
|
|
12
|
+
rollupRegisteredAtL2Slot: SlotNumber;
|
|
10
13
|
}>;
|
|
11
14
|
/**
|
|
12
15
|
* Collects and manages slashable offenses from watchers.
|
|
@@ -39,7 +42,7 @@ export declare class SlashOffensesCollector {
|
|
|
39
42
|
* @param offenses - The offenses to mark as slashed
|
|
40
43
|
*/
|
|
41
44
|
markAsSlashed(offenses: OffenseIdentifier[]): Promise<void>;
|
|
42
|
-
/** Returns whether to skip an offense if it happened during the grace period
|
|
45
|
+
/** Returns whether to skip an offense if it happened during the grace period after the network upgrade */
|
|
43
46
|
private shouldSkipOffense;
|
|
44
47
|
}
|
|
45
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWxFLE9BQU8sS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDckUsT0FBTyxFQUFnQixLQUFLLGlCQUFpQixFQUFxQixNQUFNLHdCQUF3QixDQUFDO0FBRWpHLE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdkUsT0FBTyxFQUF1QixLQUFLLGVBQWUsRUFBRSxLQUFLLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV2RixNQUFNLE1BQU0sNEJBQTRCLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDO0FBQ3BHLE1BQU0sTUFBTSw4QkFBOEIsR0FBRyxRQUFRLENBQ25ELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxlQUFlLENBQUMsR0FBRztJQUN6QyxlQUFlLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLFNBQVMsQ0FBQztJQUN0RCxzSEFBc0g7SUFDdEgsd0JBQXdCLEVBQUUsVUFBVSxDQUFDO0NBQ3RDLENBQ0YsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCxxQkFBYSxzQkFBc0I7SUFJL0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNO0lBQ3ZCLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUTtJQUN6QixPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVE7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQVB0QixPQUFPLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFzQjtJQUV2RCxZQUNtQixNQUFNLEVBQUUsNEJBQTRCLEVBQ3BDLFFBQVEsRUFBRSw4QkFBOEIsRUFDeEMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUNuQixhQUFhLEVBQUUsb0JBQW9CLEVBQ25DLEdBQUcseUNBQTZDLEVBQy9EO0lBRUcsS0FBSyxrQkFhWDtJQUVNLElBQUksa0JBU1Y7SUFFRDs7OztPQUlHO0lBQ1UsaUJBQWlCLENBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRSxpQkE2QnJEO0lBRUQ7OztPQUdHO0lBQ1UsY0FBYyxDQUFDLEtBQUssRUFBRSxNQUFNLGlCQUt4QztJQUVEOzs7T0FHRztJQUNJLGFBQWEsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsaUJBR2pEO0lBRUQsMEdBQTBHO0lBQzFHLE9BQU8sQ0FBQyxpQkFBaUI7Q0FJMUIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slash_offenses_collector.d.ts","sourceRoot":"","sources":["../src/slash_offenses_collector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"slash_offenses_collector.d.ts","sourceRoot":"","sources":["../src/slash_offenses_collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAgB,KAAK,iBAAiB,EAAqB,MAAM,wBAAwB,CAAC;AAEjG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAuB,KAAK,eAAe,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvF,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC,CAAC;AACpG,MAAM,MAAM,8BAA8B,GAAG,QAAQ,CACnD,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,GAAG;IACzC,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACtD,sHAAsH;IACtH,wBAAwB,EAAE,UAAU,CAAC;CACtC,CACF,CAAC;AAEF;;;;GAIG;AACH,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsB;IAEvD,YACmB,MAAM,EAAE,4BAA4B,EACpC,QAAQ,EAAE,8BAA8B,EACxC,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,EAAE,oBAAoB,EACnC,GAAG,yCAA6C,EAC/D;IAEG,KAAK,kBAaX;IAEM,IAAI,kBASV;IAED;;;;OAIG;IACU,iBAAiB,CAAC,IAAI,EAAE,eAAe,EAAE,iBA6BrD;IAED;;;OAGG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,iBAKxC;IAED;;;OAGG;IACI,aAAa,CAAC,QAAQ,EAAE,iBAAiB,EAAE,iBAGjD;IAED,0GAA0G;IAC1G,OAAO,CAAC,iBAAiB;CAI1B"}
|
|
@@ -65,11 +65,7 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
|
|
|
65
65
|
this.log.warn(`Offense amount ${arg.amount} is below minimum slashing amount ${minSlash}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
this.log.info(`Adding pending offense for validator ${arg.validator}`,
|
|
69
|
-
...pendingOffense,
|
|
70
|
-
epochOrSlot: pendingOffense.epochOrSlot.toString(),
|
|
71
|
-
amount: pendingOffense.amount.toString()
|
|
72
|
-
});
|
|
68
|
+
this.log.info(`Adding pending offense for validator ${arg.validator}`, pendingOffense);
|
|
73
69
|
await this.offensesStore.addPendingOffense(pendingOffense);
|
|
74
70
|
}
|
|
75
71
|
}
|
|
@@ -91,8 +87,8 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
|
|
|
91
87
|
});
|
|
92
88
|
return this.offensesStore.markAsSlashed(offenses);
|
|
93
89
|
}
|
|
94
|
-
/** Returns whether to skip an offense if it happened during the grace period
|
|
90
|
+
/** Returns whether to skip an offense if it happened during the grace period after the network upgrade */ shouldSkipOffense(offense) {
|
|
95
91
|
const offenseSlot = getSlotForOffense(offense, this.settings);
|
|
96
|
-
return offenseSlot < this.config.slashGracePeriodL2Slots;
|
|
92
|
+
return offenseSlot < this.settings.rollupRegisteredAtL2Slot + this.config.slashGracePeriodL2Slots;
|
|
97
93
|
}
|
|
98
94
|
}
|
|
@@ -24,12 +24,13 @@ export declare class SlasherClientFacade implements SlasherClientInterface {
|
|
|
24
24
|
private epochCache;
|
|
25
25
|
private dateProvider;
|
|
26
26
|
private kvStore;
|
|
27
|
+
private rollupRegisteredAtL2Slot;
|
|
27
28
|
private logger;
|
|
28
29
|
private client;
|
|
29
30
|
private unwatch;
|
|
30
31
|
constructor(config: SlasherConfig & DataStoreConfig & {
|
|
31
32
|
ethereumSlotDuration: number;
|
|
32
|
-
}, rollup: RollupContract, l1Client: ViemClient, slashFactoryAddress: EthAddress | undefined, watchers: Watcher[], epochCache: EpochCache, dateProvider: DateProvider, kvStore: AztecLMDBStoreV2, logger?: import("@aztec/foundation/log").Logger);
|
|
33
|
+
}, rollup: RollupContract, l1Client: ViemClient, slashFactoryAddress: EthAddress | undefined, watchers: Watcher[], epochCache: EpochCache, dateProvider: DateProvider, kvStore: AztecLMDBStoreV2, rollupRegisteredAtL2Slot: SlotNumber, logger?: import("@aztec/foundation/log").Logger);
|
|
33
34
|
start(): Promise<void>;
|
|
34
35
|
stop(): Promise<void>;
|
|
35
36
|
getConfig(): SlasherConfig;
|
|
@@ -41,4 +42,4 @@ export declare class SlasherClientFacade implements SlasherClientInterface {
|
|
|
41
42
|
private createSlasherClient;
|
|
42
43
|
private handleSlasherChange;
|
|
43
44
|
}
|
|
44
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlcl9jbGllbnRfZmFjYWRlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hlcl9jbGllbnRfZmFjYWRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNyRSxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUc5RixPQUFPLEtBQUssRUFBRSxzQkFBc0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzVFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU1Qzs7OztHQUlHO0FBQ0gscUJBQWEsbUJBQW9CLFlBQVcsc0JBQXNCO0lBSzlELE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsUUFBUTtJQUNoQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxRQUFRO0lBQ2hCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxPQUFPO0lBQ2YsT0FBTyxDQUFDLHdCQUF3QjtJQUNoQyxPQUFPLENBQUMsTUFBTTtJQWJoQixPQUFPLENBQUMsTUFBTSxDQUFxQztJQUNuRCxPQUFPLENBQUMsT0FBTyxDQUEyQjtJQUUxQyxZQUNVLE1BQU0sRUFBRSxhQUFhLEdBQUcsZUFBZSxHQUFHO1FBQUUsb0JBQW9CLEVBQUUsTUFBTSxDQUFBO0tBQUUsRUFDMUUsTUFBTSxFQUFFLGNBQWMsRUFDdEIsUUFBUSxFQUFFLFVBQVUsRUFDcEIsbUJBQW1CLEVBQUUsVUFBVSxHQUFHLFNBQVMsRUFDM0MsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUNuQixVQUFVLEVBQUUsVUFBVSxFQUN0QixZQUFZLEVBQUUsWUFBWSxFQUMxQixPQUFPLEVBQUUsZ0JBQWdCLEVBQ3pCLHdCQUF3QixFQUFFLFVBQVUsRUFDcEMsTUFBTSx5Q0FBMEIsRUFDdEM7SUFFUyxLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQVNsQztJQUVZLElBQUksSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWpDO0lBRU0sU0FBUyxJQUFJLGFBQWEsQ0FFaEM7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBSXhEO0lBRU0sZ0JBQWdCLElBQUksT0FBTyxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FFdEQ7SUFFTSxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRWhFO0lBRU0sa0JBQWtCLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRTlDO0lBRU0sa0JBQWtCLENBQUMsVUFBVSxFQUFFLFVBQVUsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUVoRjtJQUVELE9BQU8sQ0FBQyxtQkFBbUI7WUFlYixtQkFBbUI7Q0FNbEMifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slasher_client_facade.d.ts","sourceRoot":"","sources":["../src/slasher_client_facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG9F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,sBAAsB;IAK9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"slasher_client_facade.d.ts","sourceRoot":"","sources":["../src/slasher_client_facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG9F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,sBAAsB;IAK9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,wBAAwB;IAChC,OAAO,CAAC,MAAM;IAbhB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,OAAO,CAA2B;IAE1C,YACU,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG;QAAE,oBAAoB,EAAE,MAAM,CAAA;KAAE,EAC1E,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,UAAU,EACpB,mBAAmB,EAAE,UAAU,GAAG,SAAS,EAC3C,QAAQ,EAAE,OAAO,EAAE,EACnB,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,gBAAgB,EACzB,wBAAwB,EAAE,UAAU,EACpC,MAAM,yCAA0B,EACtC;IAES,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CASlC;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjC;IAEM,SAAS,IAAI,aAAa,CAEhC;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAIxD;IAEM,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAEtD;IAEM,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEhE;IAEM,kBAAkB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAE9C;IAEM,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAEhF;IAED,OAAO,CAAC,mBAAmB;YAeb,mBAAmB;CAMlC"}
|
|
@@ -13,10 +13,11 @@ import { createSlasherImplementation } from './factory/create_implementation.js'
|
|
|
13
13
|
epochCache;
|
|
14
14
|
dateProvider;
|
|
15
15
|
kvStore;
|
|
16
|
+
rollupRegisteredAtL2Slot;
|
|
16
17
|
logger;
|
|
17
18
|
client;
|
|
18
19
|
unwatch;
|
|
19
|
-
constructor(config, rollup, l1Client, slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, logger = createLogger('slasher')){
|
|
20
|
+
constructor(config, rollup, l1Client, slashFactoryAddress, watchers, epochCache, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')){
|
|
20
21
|
this.config = config;
|
|
21
22
|
this.rollup = rollup;
|
|
22
23
|
this.l1Client = l1Client;
|
|
@@ -25,6 +26,7 @@ import { createSlasherImplementation } from './factory/create_implementation.js'
|
|
|
25
26
|
this.epochCache = epochCache;
|
|
26
27
|
this.dateProvider = dateProvider;
|
|
27
28
|
this.kvStore = kvStore;
|
|
29
|
+
this.rollupRegisteredAtL2Slot = rollupRegisteredAtL2Slot;
|
|
28
30
|
this.logger = logger;
|
|
29
31
|
}
|
|
30
32
|
async start() {
|
|
@@ -65,7 +67,7 @@ import { createSlasherImplementation } from './factory/create_implementation.js'
|
|
|
65
67
|
return this.client?.getProposerActions(slotNumber) ?? Promise.reject(new Error('Slasher client not initialized'));
|
|
66
68
|
}
|
|
67
69
|
createSlasherClient() {
|
|
68
|
-
return createSlasherImplementation(this.config, this.rollup, this.l1Client, this.slashFactoryAddress, this.watchers, this.epochCache, this.dateProvider, this.kvStore, this.logger);
|
|
70
|
+
return createSlasherImplementation(this.config, this.rollup, this.l1Client, this.slashFactoryAddress, this.watchers, this.epochCache, this.dateProvider, this.kvStore, this.rollupRegisteredAtL2Slot, this.logger);
|
|
69
71
|
}
|
|
70
72
|
async handleSlasherChange() {
|
|
71
73
|
this.logger.warn('Slasher contract changed, recreating slasher client');
|
|
@@ -22,7 +22,7 @@ export type TallySlasherSettings = Prettify<SlashRoundMonitorSettings & SlashOff
|
|
|
22
22
|
/** Committee size for block proposal */
|
|
23
23
|
targetCommitteeSize: number;
|
|
24
24
|
}>;
|
|
25
|
-
export type TallySlasherClientConfig = SlashOffensesCollectorConfig & Pick<SlasherConfig, 'slashValidatorsAlways' | 'slashValidatorsNever' | 'slashExecuteRoundsLookBack'>;
|
|
25
|
+
export type TallySlasherClientConfig = SlashOffensesCollectorConfig & Pick<SlasherConfig, 'slashValidatorsAlways' | 'slashValidatorsNever' | 'slashExecuteRoundsLookBack' | 'slashMaxPayloadSize'>;
|
|
26
26
|
/**
|
|
27
27
|
* The Tally Slasher client is responsible for managing slashable offenses using
|
|
28
28
|
* the consensus-based slashing model where proposers vote on individual validator offenses.
|
|
@@ -122,4 +122,4 @@ export declare class TallySlasherClient implements ProposerSlashActionProvider,
|
|
|
122
122
|
*/
|
|
123
123
|
private getSlashedRound;
|
|
124
124
|
}
|
|
125
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
125
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFsbHlfc2xhc2hlcl9jbGllbnQuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90YWxseV9zbGFzaGVyX2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLGVBQWUsRUFBRSw2QkFBNkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTNHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUc3RCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNyRSxPQUFPLEVBQ0wsS0FBSyxPQUFPLEVBRVosS0FBSyxtQkFBbUIsRUFDeEIsS0FBSywyQkFBMkIsRUFDaEMsS0FBSyxpQkFBaUIsRUFHdkIsTUFBTSx3QkFBd0IsQ0FBQztBQUVoQyxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFaEMsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixLQUFLLDRCQUE0QixFQUNqQyxLQUFLLDhCQUE4QixFQUNwQyxNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxLQUFLLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDN0YsT0FBTyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUM1RSxPQUFPLEtBQUssRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3ZFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU1QyxvR0FBb0c7QUFDcEcsTUFBTSxNQUFNLG9C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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tally_slasher_client.d.ts","sourceRoot":"","sources":["../src/tally_slasher_client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAE3G,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAG7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EAGvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,EACL,sBAAsB,EACtB,KAAK,4BAA4B,EACjC,KAAK,8BAA8B,EACpC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,oGAAoG;AACpG,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,yBAAyB,GACvB,8BAA8B,GAAG;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,8BAA8B,EAAE,MAAM,CAAC;IACvC,yBAAyB,EAAE,MAAM,CAAC;IAClC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,wCAAwC;IACxC,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CACJ,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GACjE,IAAI,
|
|
1
|
+
{"version":3,"file":"tally_slasher_client.d.ts","sourceRoot":"","sources":["../src/tally_slasher_client.ts"],"names":[],"mappings":"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"}
|
|
@@ -277,19 +277,19 @@ import { SlashRoundMonitor } from './slash_round_monitor.js';
|
|
|
277
277
|
});
|
|
278
278
|
return undefined;
|
|
279
279
|
}
|
|
280
|
-
const offensesToSlashLog = offensesToSlash.map((offense)=>({
|
|
281
|
-
...offense,
|
|
282
|
-
amount: offense.amount.toString()
|
|
283
|
-
}));
|
|
284
280
|
this.log.info(`Voting to slash ${offensesToSlash.length} offenses`, {
|
|
285
281
|
slotNumber,
|
|
286
282
|
currentRound,
|
|
287
283
|
slashedRound,
|
|
288
|
-
offensesToSlash
|
|
284
|
+
offensesToSlash
|
|
289
285
|
});
|
|
290
286
|
const committees = await this.collectCommitteesActiveDuringRound(slashedRound);
|
|
291
287
|
const epochsForCommittees = getEpochsForRound(slashedRound, this.settings);
|
|
292
|
-
const
|
|
288
|
+
const { slashMaxPayloadSize } = this.config;
|
|
289
|
+
const votes = getSlashConsensusVotesFromOffenses(offensesToSlash, committees, epochsForCommittees.map((e)=>BigInt(e)), {
|
|
290
|
+
...this.settings,
|
|
291
|
+
maxSlashedValidators: slashMaxPayloadSize
|
|
292
|
+
}, this.log);
|
|
293
293
|
if (votes.every((v)=>v === 0)) {
|
|
294
294
|
this.log.warn(`Computed votes for offenses are all zero. Skipping vote.`, {
|
|
295
295
|
slotNumber,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import
|
|
2
|
+
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { L2Block, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
|
|
4
|
-
import type { ICheckpointsBuilder, ITxProvider,
|
|
4
|
+
import type { ICheckpointsBuilder, ITxProvider, 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,10 +29,11 @@ export declare class EpochPruneWatcher extends EpochPruneWatcher_base implements
|
|
|
29
29
|
private handlePruneL2Blocks;
|
|
30
30
|
private emitSlashForEpoch;
|
|
31
31
|
private processPruneL2Blocks;
|
|
32
|
-
validateBlocks(blocks: L2Block[]): Promise<void>;
|
|
33
|
-
|
|
32
|
+
validateBlocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void>;
|
|
33
|
+
private validateCheckpoint;
|
|
34
|
+
private validateBlockInCheckpoint;
|
|
34
35
|
private getValidatorsForEpoch;
|
|
35
36
|
private validatorsToSlashingArgs;
|
|
36
37
|
}
|
|
37
38
|
export {};
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
39
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBZSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUkzRSxPQUFPLEVBRUwsT0FBTyxFQUNQLEtBQUsseUJBQXlCLEVBRy9CLE1BQU0scUJBQXFCLENBQUM7QUFFN0IsT0FBTyxLQUFLLEVBRVYsbUJBQW1CLEVBQ25CLFdBQVcsRUFFWCxhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxtQkFBbUIsRUFBNEIsTUFBTSx5QkFBeUIsQ0FBQztBQVk3RixPQUFPLEVBQTZDLEtBQUssT0FBTyxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdHLFFBQUEsTUFBTSxvQ0FBb0MsK0RBQWdFLENBQUM7QUFFM0csS0FBSywwQkFBMEIsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsT0FBTyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7O0FBRTdHOzs7OztHQUtHO0FBQ0gscUJBQWEsaUJBQWtCLFNBQVEsc0JBQTJDLFlBQVcsT0FBTztJQVNoRyxPQUFPLENBQUMsYUFBYTtJQUNyQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxrQkFBa0I7SUFaNUIsT0FBTyxDQUFDLEdBQUcsQ0FBK0M7SUFHMUQsT0FBTyxDQUFDLHdCQUF3QixDQUF1QztJQUV2RSxPQUFPLENBQUMsU0FBUyxDQUE2QjtJQUU5QyxZQUNVLGFBQWEsRUFBRSx5QkFBeUIsRUFDeEMsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLGlCQUFpQixDQUFDLEVBQ2hELGtCQUFrQixFQUFFLG1CQUFtQixFQUMvQyxTQUFTLEVBQUUsMEJBQTBCLEVBT3RDO0lBRU0sS0FBSyxrQkFHWDtJQUVNLElBQUksa0JBR1Y7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBR3hEO0lBRUQsT0FBTyxDQUFDLG1CQUFtQjtZQU9iLGlCQUFpQjtZQVdqQixvQkFBb0I7SUF3QnJCLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEVBQUUsV0FBVyxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBK0J0RjtZQUVhLGtCQUFrQjtZQXdDbEIseUJBQXlCO1lBaUN6QixxQkFBcUI7SUFTbkMsT0FBTyxDQUFDLHdCQUF3QjtDQWdCakMifQ==
|
|
@@ -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;AAChD,OAAO,EAAe,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAI3E,OAAO,EAEL,OAAO,EACP,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAEV,mBAAmB,EACnB,WAAW,EAEX,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,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BtF;YAEa,kBAAkB;YAwClB,yBAAyB;YAiCzB,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BlockNumber
|
|
2
|
-
import { merge, pick } from '@aztec/foundation/collection';
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { chunkBy, 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, epochNumber);
|
|
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,19 +81,26 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
async validateBlocks(blocks) {
|
|
84
|
+
async validateBlocks(blocks, epochNumber) {
|
|
85
85
|
if (blocks.length === 0) {
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
const
|
|
88
|
+
// Sort blocks by block number and group by checkpoint
|
|
89
|
+
const sortedBlocks = [
|
|
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.getCheckpointsDataForEpoch(epochNumber)).filter((c)=>c.checkpointNumber < sortedBlocks[0].checkpointNumber).map((c)=>c.checkpointOutHash);
|
|
95
|
+
let previousCheckpointOutHashes = [
|
|
96
|
+
...priorCheckpointOutHashes
|
|
97
|
+
];
|
|
98
|
+
const fork = await this.checkpointsBuilder.getFork(BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1));
|
|
90
99
|
try {
|
|
91
|
-
for (const
|
|
92
|
-
await this.
|
|
93
|
-
//
|
|
94
|
-
const checkpointOutHash = computeCheckpointOutHash(
|
|
95
|
-
block.body.txEffects.map((tx)=>tx.l2ToL1Msgs)
|
|
96
|
-
]);
|
|
100
|
+
for (const checkpointBlocks of blocksByCheckpoint){
|
|
101
|
+
await this.validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork);
|
|
102
|
+
// Compute checkpoint out hash from all blocks in this checkpoint
|
|
103
|
+
const checkpointOutHash = computeCheckpointOutHash(checkpointBlocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs)));
|
|
97
104
|
previousCheckpointOutHashes = [
|
|
98
105
|
...previousCheckpointOutHashes,
|
|
99
106
|
checkpointOutHash
|
|
@@ -103,7 +110,30 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
103
110
|
await fork.close();
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
|
-
async
|
|
113
|
+
async validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork) {
|
|
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
|
+
timestamp: gv.timestamp,
|
|
125
|
+
coinbase: gv.coinbase,
|
|
126
|
+
feeRecipient: gv.feeRecipient,
|
|
127
|
+
gasFees: gv.gasFees
|
|
128
|
+
};
|
|
129
|
+
// Start checkpoint builder once for all blocks in this checkpoint
|
|
130
|
+
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(checkpointNumber, constants, 0n, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
|
|
131
|
+
// Validate all blocks in the checkpoint sequentially
|
|
132
|
+
for (const block of checkpointBlocks){
|
|
133
|
+
await this.validateBlockInCheckpoint(block, checkpointBuilder);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async validateBlockInCheckpoint(blockFromL1, checkpointBuilder) {
|
|
107
137
|
this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
|
|
108
138
|
const txHashes = blockFromL1.body.txEffects.map((txEffect)=>txEffect.txHash);
|
|
109
139
|
// We load txs from the mempool directly, since the TxCollector running in the background has already been
|
|
@@ -113,20 +143,11 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
|
|
|
113
143
|
if (missingTxs && missingTxs.length > 0) {
|
|
114
144
|
throw new TransactionsNotAvailableError(missingTxs);
|
|
115
145
|
}
|
|
116
|
-
const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
|
|
117
|
-
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
118
146
|
const gv = blockFromL1.header.globalVariables;
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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());
|
|
129
|
-
const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {});
|
|
147
|
+
const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {
|
|
148
|
+
isBuildingProposal: false,
|
|
149
|
+
minValidTxs: 0
|
|
150
|
+
});
|
|
130
151
|
if (numTxs !== txs.length) {
|
|
131
152
|
// This should be detected by state mismatch, but this makes it easier to debug.
|
|
132
153
|
throw new ValidatorError(`Built block with ${numTxs} txs, expected ${txs.length}`);
|
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.a89ec08",
|
|
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.a89ec08",
|
|
60
|
+
"@aztec/ethereum": "0.0.1-commit.a89ec08",
|
|
61
|
+
"@aztec/foundation": "0.0.1-commit.a89ec08",
|
|
62
|
+
"@aztec/kv-store": "0.0.1-commit.a89ec08",
|
|
63
|
+
"@aztec/l1-artifacts": "0.0.1-commit.a89ec08",
|
|
64
|
+
"@aztec/stdlib": "0.0.1-commit.a89ec08",
|
|
65
|
+
"@aztec/telemetry-client": "0.0.1-commit.a89ec08",
|
|
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.a89ec08",
|
|
73
73
|
"@jest/globals": "^30.0.0",
|
|
74
74
|
"@types/jest": "^30.0.0",
|
|
75
75
|
"@types/node": "^22.15.17",
|
package/src/config.ts
CHANGED
|
@@ -23,6 +23,8 @@ export const DefaultSlasherConfig: SlasherConfig = {
|
|
|
23
23
|
slashInactivityTargetPercentage: slasherDefaultEnv.SLASH_INACTIVITY_TARGET_PERCENTAGE,
|
|
24
24
|
slashInactivityConsecutiveEpochThreshold: slasherDefaultEnv.SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD,
|
|
25
25
|
slashBroadcastedInvalidBlockPenalty: BigInt(slasherDefaultEnv.SLASH_INVALID_BLOCK_PENALTY),
|
|
26
|
+
slashDuplicateProposalPenalty: BigInt(slasherDefaultEnv.SLASH_DUPLICATE_PROPOSAL_PENALTY),
|
|
27
|
+
slashDuplicateAttestationPenalty: BigInt(slasherDefaultEnv.SLASH_DUPLICATE_ATTESTATION_PENALTY),
|
|
26
28
|
slashInactivityPenalty: BigInt(slasherDefaultEnv.SLASH_INACTIVITY_PENALTY),
|
|
27
29
|
slashProposeInvalidAttestationsPenalty: BigInt(slasherDefaultEnv.SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY),
|
|
28
30
|
slashAttestDescendantOfInvalidPenalty: BigInt(slasherDefaultEnv.SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY),
|
|
@@ -88,6 +90,17 @@ export const slasherConfigMappings: ConfigMappingsType<SlasherConfig> = {
|
|
|
88
90
|
description: 'Penalty amount for slashing a validator for an invalid block proposed via p2p.',
|
|
89
91
|
...bigintConfigHelper(DefaultSlasherConfig.slashBroadcastedInvalidBlockPenalty),
|
|
90
92
|
},
|
|
93
|
+
slashDuplicateProposalPenalty: {
|
|
94
|
+
env: 'SLASH_DUPLICATE_PROPOSAL_PENALTY',
|
|
95
|
+
description: 'Penalty amount for slashing a validator for sending duplicate proposals.',
|
|
96
|
+
...bigintConfigHelper(DefaultSlasherConfig.slashDuplicateProposalPenalty),
|
|
97
|
+
},
|
|
98
|
+
slashDuplicateAttestationPenalty: {
|
|
99
|
+
env: 'SLASH_DUPLICATE_ATTESTATION_PENALTY',
|
|
100
|
+
description:
|
|
101
|
+
'Penalty amount for slashing a validator for signing attestations for different proposals at the same slot.',
|
|
102
|
+
...bigintConfigHelper(DefaultSlasherConfig.slashDuplicateAttestationPenalty),
|
|
103
|
+
},
|
|
91
104
|
slashInactivityTargetPercentage: {
|
|
92
105
|
env: 'SLASH_INACTIVITY_TARGET_PERCENTAGE',
|
|
93
106
|
description:
|
|
@@ -142,7 +155,8 @@ export const slasherConfigMappings: ConfigMappingsType<SlasherConfig> = {
|
|
|
142
155
|
...numberConfigHelper(DefaultSlasherConfig.slashMaxPayloadSize),
|
|
143
156
|
},
|
|
144
157
|
slashGracePeriodL2Slots: {
|
|
145
|
-
description:
|
|
158
|
+
description:
|
|
159
|
+
'Number of L2 slots after the network upgrade during which slashing offenses are ignored. The upgrade time is determined from the CanonicalRollupUpdated event.',
|
|
146
160
|
env: 'SLASH_GRACE_PERIOD_L2_SLOTS',
|
|
147
161
|
...numberConfigHelper(DefaultSlasherConfig.slashGracePeriodL2Slots),
|
|
148
162
|
},
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
2
|
+
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
3
3
|
import type { L1ReaderConfig } from '@aztec/ethereum/l1-reader';
|
|
4
4
|
import type { ViemClient } from '@aztec/ethereum/types';
|
|
5
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
5
6
|
import { unique } from '@aztec/foundation/collection';
|
|
6
7
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
8
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
10
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
10
11
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
12
|
+
import { getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
11
13
|
import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
12
14
|
|
|
13
15
|
import { SlasherClientFacade } from '../slasher_client_facade.js';
|
|
@@ -18,7 +20,7 @@ import type { Watcher } from '../watcher.js';
|
|
|
18
20
|
/** Creates a slasher client facade that updates itself whenever the rollup slasher changes */
|
|
19
21
|
export async function createSlasherFacade(
|
|
20
22
|
config: SlasherConfig & DataStoreConfig & { ethereumSlotDuration: number },
|
|
21
|
-
l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress'>,
|
|
23
|
+
l1Contracts: Pick<L1ReaderConfig['l1Contracts'], 'rollupAddress' | 'slashFactoryAddress' | 'registryAddress'>,
|
|
22
24
|
l1Client: ViemClient,
|
|
23
25
|
watchers: Watcher[],
|
|
24
26
|
dateProvider: DateProvider,
|
|
@@ -34,6 +36,32 @@ export async function createSlasherFacade(
|
|
|
34
36
|
const kvStore = await createStore('slasher', SCHEMA_VERSION, config, logger.getBindings());
|
|
35
37
|
const rollup = new RollupContract(l1Client, l1Contracts.rollupAddress);
|
|
36
38
|
|
|
39
|
+
// Compute and cache the L2 slot at which the rollup was registered as canonical
|
|
40
|
+
const settingsMap = kvStore.openMap<string, number>('slasher-settings');
|
|
41
|
+
const cacheKey = `registeredSlot:${l1Contracts.rollupAddress}`;
|
|
42
|
+
let rollupRegisteredAtL2Slot = (await settingsMap.getAsync(cacheKey)) as SlotNumber | undefined;
|
|
43
|
+
|
|
44
|
+
if (rollupRegisteredAtL2Slot === undefined) {
|
|
45
|
+
const registry = new RegistryContract(l1Client, l1Contracts.registryAddress);
|
|
46
|
+
const l1StartBlock = await rollup.getL1StartBlock();
|
|
47
|
+
const registrationTimestamp = await registry.getCanonicalRollupRegistrationTimestamp(
|
|
48
|
+
l1Contracts.rollupAddress,
|
|
49
|
+
l1StartBlock,
|
|
50
|
+
);
|
|
51
|
+
if (registrationTimestamp !== undefined) {
|
|
52
|
+
const l1GenesisTime = await rollup.getL1GenesisTime();
|
|
53
|
+
const slotDuration = await rollup.getSlotDuration();
|
|
54
|
+
rollupRegisteredAtL2Slot = getSlotAtTimestamp(registrationTimestamp, {
|
|
55
|
+
l1GenesisTime,
|
|
56
|
+
slotDuration: Number(slotDuration),
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
rollupRegisteredAtL2Slot = SlotNumber(0);
|
|
60
|
+
}
|
|
61
|
+
await settingsMap.set(cacheKey, rollupRegisteredAtL2Slot);
|
|
62
|
+
logger.info(`Canonical rollup registered at L2 slot ${rollupRegisteredAtL2Slot}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
37
65
|
const slashValidatorsNever = config.slashSelfAllowed
|
|
38
66
|
? config.slashValidatorsNever
|
|
39
67
|
: unique([...config.slashValidatorsNever, ...validatorAddresses].map(a => a.toString())).map(EthAddress.fromString);
|
|
@@ -48,6 +76,7 @@ export async function createSlasherFacade(
|
|
|
48
76
|
epochCache,
|
|
49
77
|
dateProvider,
|
|
50
78
|
kvStore,
|
|
79
|
+
rollupRegisteredAtL2Slot,
|
|
51
80
|
logger,
|
|
52
81
|
);
|
|
53
82
|
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
TallySlashingProposerContract,
|
|
6
6
|
} from '@aztec/ethereum/contracts';
|
|
7
7
|
import type { ViemClient } from '@aztec/ethereum/types';
|
|
8
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
8
9
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
10
|
import { createLogger } from '@aztec/foundation/log';
|
|
10
11
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
@@ -31,19 +32,40 @@ export async function createSlasherImplementation(
|
|
|
31
32
|
epochCache: EpochCache,
|
|
32
33
|
dateProvider: DateProvider,
|
|
33
34
|
kvStore: AztecLMDBStoreV2,
|
|
35
|
+
rollupRegisteredAtL2Slot: SlotNumber,
|
|
34
36
|
logger = createLogger('slasher'),
|
|
35
37
|
) {
|
|
36
38
|
const proposer = await rollup.getSlashingProposer();
|
|
37
39
|
if (!proposer) {
|
|
38
40
|
return new NullSlasherClient(config);
|
|
39
41
|
} else if (proposer.type === 'tally') {
|
|
40
|
-
return createTallySlasher(
|
|
42
|
+
return createTallySlasher(
|
|
43
|
+
config,
|
|
44
|
+
rollup,
|
|
45
|
+
proposer,
|
|
46
|
+
watchers,
|
|
47
|
+
dateProvider,
|
|
48
|
+
epochCache,
|
|
49
|
+
kvStore,
|
|
50
|
+
rollupRegisteredAtL2Slot,
|
|
51
|
+
logger,
|
|
52
|
+
);
|
|
41
53
|
} else {
|
|
42
54
|
if (!slashFactoryAddress || slashFactoryAddress.equals(EthAddress.ZERO)) {
|
|
43
55
|
throw new Error('Cannot initialize an empire-based SlasherClient without a SlashFactory address');
|
|
44
56
|
}
|
|
45
57
|
const slashFactory = new SlashFactoryContract(l1Client, slashFactoryAddress.toString());
|
|
46
|
-
return createEmpireSlasher(
|
|
58
|
+
return createEmpireSlasher(
|
|
59
|
+
config,
|
|
60
|
+
rollup,
|
|
61
|
+
proposer,
|
|
62
|
+
slashFactory,
|
|
63
|
+
watchers,
|
|
64
|
+
dateProvider,
|
|
65
|
+
kvStore,
|
|
66
|
+
rollupRegisteredAtL2Slot,
|
|
67
|
+
logger,
|
|
68
|
+
);
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
71
|
|
|
@@ -55,6 +77,7 @@ async function createEmpireSlasher(
|
|
|
55
77
|
watchers: Watcher[],
|
|
56
78
|
dateProvider: DateProvider,
|
|
57
79
|
kvStore: AztecLMDBStoreV2,
|
|
80
|
+
rollupRegisteredAtL2Slot: SlotNumber,
|
|
58
81
|
logger = createLogger('slasher'),
|
|
59
82
|
): Promise<EmpireSlasherClient> {
|
|
60
83
|
if (slashingProposer.type !== 'empire') {
|
|
@@ -97,6 +120,7 @@ async function createEmpireSlasher(
|
|
|
97
120
|
l1StartBlock,
|
|
98
121
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
99
122
|
slashingAmounts: undefined,
|
|
123
|
+
rollupRegisteredAtL2Slot,
|
|
100
124
|
};
|
|
101
125
|
|
|
102
126
|
const payloadsStore = new SlasherPayloadsStore(kvStore, {
|
|
@@ -130,13 +154,14 @@ async function createTallySlasher(
|
|
|
130
154
|
dateProvider: DateProvider,
|
|
131
155
|
epochCache: EpochCache,
|
|
132
156
|
kvStore: AztecLMDBStoreV2,
|
|
157
|
+
rollupRegisteredAtL2Slot: SlotNumber,
|
|
133
158
|
logger = createLogger('slasher'),
|
|
134
159
|
): Promise<TallySlasherClient> {
|
|
135
160
|
if (slashingProposer.type !== 'tally') {
|
|
136
161
|
throw new Error('Slashing proposer contract is not of type tally');
|
|
137
162
|
}
|
|
138
163
|
|
|
139
|
-
const settings = await getTallySlasherSettings(rollup, slashingProposer);
|
|
164
|
+
const settings = { ...(await getTallySlasherSettings(rollup, slashingProposer)), rollupRegisteredAtL2Slot };
|
|
140
165
|
const slasher = await rollup.getSlasherContract();
|
|
141
166
|
|
|
142
167
|
const offensesStore = new SlasherOffensesStore(kvStore, {
|
|
@@ -5,7 +5,7 @@ import type { TallySlasherSettings } from '../tally_slasher_client.js';
|
|
|
5
5
|
export async function getTallySlasherSettings(
|
|
6
6
|
rollup: RollupContract,
|
|
7
7
|
slashingProposer?: TallySlashingProposerContract,
|
|
8
|
-
): Promise<TallySlasherSettings
|
|
8
|
+
): Promise<Omit<TallySlasherSettings, 'rollupRegisteredAtL2Slot'>> {
|
|
9
9
|
if (!slashingProposer) {
|
|
10
10
|
const rollupSlashingProposer = await rollup.getSlashingProposer();
|
|
11
11
|
if (!rollupSlashingProposer || rollupSlashingProposer.type !== 'tally') {
|
|
@@ -40,7 +40,7 @@ export async function getTallySlasherSettings(
|
|
|
40
40
|
rollup.getTargetCommitteeSize(),
|
|
41
41
|
]);
|
|
42
42
|
|
|
43
|
-
const settings: TallySlasherSettings = {
|
|
43
|
+
const settings: Omit<TallySlasherSettings, 'rollupRegisteredAtL2Slot'> = {
|
|
44
44
|
slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
|
|
45
45
|
slashingRoundSize: Number(slashingRoundSize),
|
|
46
46
|
slashingRoundSizeInEpochs: Number(slashingRoundSizeInEpochs),
|
|
@@ -15,6 +15,8 @@ export const slasherDefaultEnv = {
|
|
|
15
15
|
SLASH_INACTIVITY_PENALTY: 10000000000000000000,
|
|
16
16
|
SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
|
|
17
17
|
SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000,
|
|
18
|
+
SLASH_DUPLICATE_PROPOSAL_PENALTY: 0,
|
|
19
|
+
SLASH_DUPLICATE_ATTESTATION_PENALTY: 0,
|
|
18
20
|
SLASH_UNKNOWN_PENALTY: 10000000000000000000,
|
|
19
21
|
SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
|
|
20
22
|
SLASH_GRACE_PERIOD_L2_SLOTS: 0,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import type { Prettify } from '@aztec/foundation/types';
|
|
3
4
|
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -9,7 +10,11 @@ import { WANT_TO_SLASH_EVENT, type WantToSlashArgs, type Watcher } from './watch
|
|
|
9
10
|
|
|
10
11
|
export type SlashOffensesCollectorConfig = Prettify<Pick<SlasherConfig, 'slashGracePeriodL2Slots'>>;
|
|
11
12
|
export type SlashOffensesCollectorSettings = Prettify<
|
|
12
|
-
Pick<L1RollupConstants, 'epochDuration'> & {
|
|
13
|
+
Pick<L1RollupConstants, 'epochDuration'> & {
|
|
14
|
+
slashingAmounts: [bigint, bigint, bigint] | undefined;
|
|
15
|
+
/** L2 slot at which the rollup was registered as canonical in the Registry. Used to anchor the slash grace period. */
|
|
16
|
+
rollupRegisteredAtL2Slot: SlotNumber;
|
|
17
|
+
}
|
|
13
18
|
>;
|
|
14
19
|
|
|
15
20
|
/**
|
|
@@ -85,11 +90,7 @@ export class SlashOffensesCollector {
|
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
this.log.info(`Adding pending offense for validator ${arg.validator}`,
|
|
89
|
-
...pendingOffense,
|
|
90
|
-
epochOrSlot: pendingOffense.epochOrSlot.toString(),
|
|
91
|
-
amount: pendingOffense.amount.toString(),
|
|
92
|
-
});
|
|
93
|
+
this.log.info(`Adding pending offense for validator ${arg.validator}`, pendingOffense);
|
|
93
94
|
await this.offensesStore.addPendingOffense(pendingOffense);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
@@ -114,9 +115,9 @@ export class SlashOffensesCollector {
|
|
|
114
115
|
return this.offensesStore.markAsSlashed(offenses);
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
/** Returns whether to skip an offense if it happened during the grace period
|
|
118
|
+
/** Returns whether to skip an offense if it happened during the grace period after the network upgrade */
|
|
118
119
|
private shouldSkipOffense(offense: Offense): boolean {
|
|
119
120
|
const offenseSlot = getSlotForOffense(offense, this.settings);
|
|
120
|
-
return offenseSlot < this.config.slashGracePeriodL2Slots;
|
|
121
|
+
return offenseSlot < this.settings.rollupRegisteredAtL2Slot + this.config.slashGracePeriodL2Slots;
|
|
121
122
|
}
|
|
122
123
|
}
|
|
@@ -32,6 +32,7 @@ export class SlasherClientFacade implements SlasherClientInterface {
|
|
|
32
32
|
private epochCache: EpochCache,
|
|
33
33
|
private dateProvider: DateProvider,
|
|
34
34
|
private kvStore: AztecLMDBStoreV2,
|
|
35
|
+
private rollupRegisteredAtL2Slot: SlotNumber,
|
|
35
36
|
private logger = createLogger('slasher'),
|
|
36
37
|
) {}
|
|
37
38
|
|
|
@@ -88,6 +89,7 @@ export class SlasherClientFacade implements SlasherClientInterface {
|
|
|
88
89
|
this.epochCache,
|
|
89
90
|
this.dateProvider,
|
|
90
91
|
this.kvStore,
|
|
92
|
+
this.rollupRegisteredAtL2Slot,
|
|
91
93
|
this.logger,
|
|
92
94
|
);
|
|
93
95
|
}
|
|
@@ -46,7 +46,10 @@ export type TallySlasherSettings = Prettify<
|
|
|
46
46
|
>;
|
|
47
47
|
|
|
48
48
|
export type TallySlasherClientConfig = SlashOffensesCollectorConfig &
|
|
49
|
-
Pick<
|
|
49
|
+
Pick<
|
|
50
|
+
SlasherConfig,
|
|
51
|
+
'slashValidatorsAlways' | 'slashValidatorsNever' | 'slashExecuteRoundsLookBack' | 'slashMaxPayloadSize'
|
|
52
|
+
>;
|
|
50
53
|
|
|
51
54
|
/**
|
|
52
55
|
* The Tally Slasher client is responsible for managing slashable offenses using
|
|
@@ -349,24 +352,22 @@ export class TallySlasherClient implements ProposerSlashActionProvider, SlasherC
|
|
|
349
352
|
return undefined;
|
|
350
353
|
}
|
|
351
354
|
|
|
352
|
-
const offensesToSlashLog = offensesToSlash.map(offense => ({
|
|
353
|
-
...offense,
|
|
354
|
-
amount: offense.amount.toString(),
|
|
355
|
-
}));
|
|
356
355
|
this.log.info(`Voting to slash ${offensesToSlash.length} offenses`, {
|
|
357
356
|
slotNumber,
|
|
358
357
|
currentRound,
|
|
359
358
|
slashedRound,
|
|
360
|
-
offensesToSlash
|
|
359
|
+
offensesToSlash,
|
|
361
360
|
});
|
|
362
361
|
|
|
363
362
|
const committees = await this.collectCommitteesActiveDuringRound(slashedRound);
|
|
364
363
|
const epochsForCommittees = getEpochsForRound(slashedRound, this.settings);
|
|
364
|
+
const { slashMaxPayloadSize } = this.config;
|
|
365
365
|
const votes = getSlashConsensusVotesFromOffenses(
|
|
366
366
|
offensesToSlash,
|
|
367
367
|
committees,
|
|
368
368
|
epochsForCommittees.map(e => BigInt(e)),
|
|
369
|
-
this.settings,
|
|
369
|
+
{ ...this.settings, maxSlashedValidators: slashMaxPayloadSize },
|
|
370
|
+
this.log,
|
|
370
371
|
);
|
|
371
372
|
if (votes.every(v => v === 0)) {
|
|
372
373
|
this.log.warn(`Computed votes for offenses are all zero. Skipping vote.`, {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import { BlockNumber,
|
|
3
|
-
import { merge, pick } from '@aztec/foundation/collection';
|
|
2
|
+
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { chunkBy, 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,6 +12,7 @@ import {
|
|
|
12
12
|
} from '@aztec/stdlib/block';
|
|
13
13
|
import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
14
14
|
import type {
|
|
15
|
+
ICheckpointBlockBuilder,
|
|
15
16
|
ICheckpointsBuilder,
|
|
16
17
|
ITxProvider,
|
|
17
18
|
MerkleTreeWriteOperations,
|
|
@@ -106,7 +107,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
106
107
|
{ blocks: epochBlocks.map(b => b.toBlockInfo()) },
|
|
107
108
|
);
|
|
108
109
|
|
|
109
|
-
await this.validateBlocks(epochBlocks);
|
|
110
|
+
await this.validateBlocks(epochBlocks, epochNumber);
|
|
110
111
|
this.log.info(`Pruned epoch ${epochNumber} was valid. Want to slash committee for not having it proven.`);
|
|
111
112
|
await this.emitSlashForEpoch(OffenseType.VALID_EPOCH_PRUNED, epochNumber);
|
|
112
113
|
} catch (error) {
|
|
@@ -121,19 +122,32 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
public async validateBlocks(blocks: L2Block[]): Promise<void> {
|
|
125
|
+
public async validateBlocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void> {
|
|
125
126
|
if (blocks.length === 0) {
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
const
|
|
130
|
+
// Sort blocks by block number and group by checkpoint
|
|
131
|
+
const sortedBlocks = [...blocks].sort((a, b) => a.number - b.number);
|
|
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.getCheckpointsDataForEpoch(epochNumber))
|
|
136
|
+
.filter(c => c.checkpointNumber < sortedBlocks[0].checkpointNumber)
|
|
137
|
+
.map(c => c.checkpointOutHash);
|
|
138
|
+
let previousCheckpointOutHashes: Fr[] = [...priorCheckpointOutHashes];
|
|
139
|
+
|
|
140
|
+
const fork = await this.checkpointsBuilder.getFork(
|
|
141
|
+
BlockNumber(sortedBlocks[0].header.globalVariables.blockNumber - 1),
|
|
142
|
+
);
|
|
131
143
|
try {
|
|
132
|
-
for (const
|
|
133
|
-
await this.
|
|
144
|
+
for (const checkpointBlocks of blocksByCheckpoint) {
|
|
145
|
+
await this.validateCheckpoint(checkpointBlocks, previousCheckpointOutHashes, fork);
|
|
134
146
|
|
|
135
|
-
//
|
|
136
|
-
const checkpointOutHash = computeCheckpointOutHash(
|
|
147
|
+
// Compute checkpoint out hash from all blocks in this checkpoint
|
|
148
|
+
const checkpointOutHash = computeCheckpointOutHash(
|
|
149
|
+
checkpointBlocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
150
|
+
);
|
|
137
151
|
previousCheckpointOutHashes = [...previousCheckpointOutHashes, checkpointOutHash];
|
|
138
152
|
}
|
|
139
153
|
} finally {
|
|
@@ -141,45 +155,66 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
|
|
|
141
155
|
}
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
private async validateCheckpoint(
|
|
159
|
+
checkpointBlocks: L2Block[],
|
|
146
160
|
previousCheckpointOutHashes: Fr[],
|
|
147
161
|
fork: MerkleTreeWriteOperations,
|
|
148
162
|
): Promise<void> {
|
|
149
|
-
|
|
150
|
-
|
|
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);
|
|
155
|
-
|
|
156
|
-
if (missingTxs && missingTxs.length > 0) {
|
|
157
|
-
throw new TransactionsNotAvailableError(missingTxs);
|
|
158
|
-
}
|
|
163
|
+
const checkpointNumber = checkpointBlocks[0].checkpointNumber;
|
|
164
|
+
this.log.debug(`Validating pruned checkpoint ${checkpointNumber} with ${checkpointBlocks.length} blocks`);
|
|
159
165
|
|
|
160
|
-
|
|
166
|
+
// Get L1ToL2Messages once for the entire checkpoint
|
|
161
167
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
162
|
-
|
|
168
|
+
|
|
169
|
+
// Build checkpoint constants from first block's global variables
|
|
170
|
+
const gv = checkpointBlocks[0].header.globalVariables;
|
|
163
171
|
const constants: CheckpointGlobalVariables = {
|
|
164
172
|
chainId: gv.chainId,
|
|
165
173
|
version: gv.version,
|
|
166
174
|
slotNumber: gv.slotNumber,
|
|
175
|
+
timestamp: gv.timestamp,
|
|
167
176
|
coinbase: gv.coinbase,
|
|
168
177
|
feeRecipient: gv.feeRecipient,
|
|
169
178
|
gasFees: gv.gasFees,
|
|
170
179
|
};
|
|
171
180
|
|
|
172
|
-
//
|
|
181
|
+
// Start checkpoint builder once for all blocks in this checkpoint
|
|
173
182
|
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(
|
|
174
183
|
checkpointNumber,
|
|
175
184
|
constants,
|
|
185
|
+
0n, // feeAssetPriceModifier is not used for validation of the checkpoint content
|
|
176
186
|
l1ToL2Messages,
|
|
177
187
|
previousCheckpointOutHashes,
|
|
178
188
|
fork,
|
|
179
189
|
this.log.getBindings(),
|
|
180
190
|
);
|
|
181
191
|
|
|
182
|
-
|
|
192
|
+
// Validate all blocks in the checkpoint sequentially
|
|
193
|
+
for (const block of checkpointBlocks) {
|
|
194
|
+
await this.validateBlockInCheckpoint(block, checkpointBuilder);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private async validateBlockInCheckpoint(
|
|
199
|
+
blockFromL1: L2Block,
|
|
200
|
+
checkpointBuilder: ICheckpointBlockBuilder,
|
|
201
|
+
): Promise<void> {
|
|
202
|
+
this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
|
|
203
|
+
const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
|
|
204
|
+
// We load txs from the mempool directly, since the TxCollector running in the background has already been
|
|
205
|
+
// trying to fetch them from nodes or via reqresp. If we haven't managed to collect them by now,
|
|
206
|
+
// it's likely that they are not available in the network at all.
|
|
207
|
+
const { txs, missingTxs } = await this.txProvider.getAvailableTxs(txHashes);
|
|
208
|
+
|
|
209
|
+
if (missingTxs && missingTxs.length > 0) {
|
|
210
|
+
throw new TransactionsNotAvailableError(missingTxs);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const gv = blockFromL1.header.globalVariables;
|
|
214
|
+
const { block, failedTxs, numTxs } = await checkpointBuilder.buildBlock(txs, gv.blockNumber, gv.timestamp, {
|
|
215
|
+
isBuildingProposal: false,
|
|
216
|
+
minValidTxs: 0,
|
|
217
|
+
});
|
|
183
218
|
|
|
184
219
|
if (numTxs !== txs.length) {
|
|
185
220
|
// This should be detected by state mismatch, but this makes it easier to debug.
|