@aztec/slasher 0.0.1-commit.6d63667d → 0.0.1-commit.7cf39cb55

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 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,6 +181,7 @@ 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
@@ -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 block proposer for the slot:
199
- - `block-mined` if the block was added to L1
200
- - `block-proposed` if the block received at least one attestation, but didn't make it to L1
201
- - `block-missed` if the block received no attestations (note that we cannot rely on the P2P proposal alone since it may be invalid, unless we reexecute it)
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
- And assigns one of the following to each validator:
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(block-missed) + count(attestation-missed)
212
- total = count(block-*) + count(attestation-*)
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRbkUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFJckUsWUFBWSxFQUFFLGFBQWEsRUFBRSxDQUFDO0FBRTlCLGVBQU8sTUFBTSxvQkFBb0IsRUFBRSxhQW9CbEMsQ0FBQztBQUVGLGVBQU8sTUFBTSxxQkFBcUIsRUFBRSxrQkFBa0IsQ0FBQyxhQUFhLENBeUhuRSxDQUFDIn0=
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRbkUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFJckUsWUFBWSxFQUFFLGFBQWEsRUFBRSxDQUFDO0FBRTlCLGVBQU8sTUFBTSxvQkFBb0IsRUFBRSxhQXNCbEMsQ0FBQztBQUVGLGVBQU8sTUFBTSxxQkFBcUIsRUFBRSxrQkFBa0IsQ0FBQyxhQUFhLENBb0luRSxDQUFDIn0=
@@ -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,aAoBlC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,CAAC,aAAa,CAyHnE,CAAC"}
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,CAoInE,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',
@@ -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: 10000000000000000000;
16
+ readonly SLASH_DUPLICATE_ATTESTATION_PENALTY: 10000000000000000000;
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlci1kZWZhdWx0cy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dlbmVyYXRlZC9zbGFzaGVyLWRlZmF1bHRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLHFFQUFxRTtBQUNyRSxlQUFPLE1BQU0saUJBQWlCOzs7Ozs7Ozs7Ozs7Ozs7O0NBZ0JwQixDQUFDIn0=
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;;;;;;;;;;;;;;;;CAgBpB,CAAC"}
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: 10000000000000000000,
17
+ SLASH_DUPLICATE_ATTESTATION_PENALTY: 10000000000000000000,
16
18
  SLASH_UNKNOWN_PENALTY: 10000000000000000000,
17
19
  SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
18
20
  SLASH_GRACE_PERIOD_L2_SLOTS: 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/slasher",
3
- "version": "0.0.1-commit.6d63667d",
3
+ "version": "0.0.1-commit.7cf39cb55",
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.6d63667d",
60
- "@aztec/ethereum": "0.0.1-commit.6d63667d",
61
- "@aztec/foundation": "0.0.1-commit.6d63667d",
62
- "@aztec/kv-store": "0.0.1-commit.6d63667d",
63
- "@aztec/l1-artifacts": "0.0.1-commit.6d63667d",
64
- "@aztec/stdlib": "0.0.1-commit.6d63667d",
65
- "@aztec/telemetry-client": "0.0.1-commit.6d63667d",
59
+ "@aztec/epoch-cache": "0.0.1-commit.7cf39cb55",
60
+ "@aztec/ethereum": "0.0.1-commit.7cf39cb55",
61
+ "@aztec/foundation": "0.0.1-commit.7cf39cb55",
62
+ "@aztec/kv-store": "0.0.1-commit.7cf39cb55",
63
+ "@aztec/l1-artifacts": "0.0.1-commit.7cf39cb55",
64
+ "@aztec/stdlib": "0.0.1-commit.7cf39cb55",
65
+ "@aztec/telemetry-client": "0.0.1-commit.7cf39cb55",
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.6d63667d",
72
+ "@aztec/aztec.js": "0.0.1-commit.7cf39cb55",
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:
@@ -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: 10000000000000000000,
19
+ SLASH_DUPLICATE_ATTESTATION_PENALTY: 10000000000000000000,
18
20
  SLASH_UNKNOWN_PENALTY: 10000000000000000000,
19
21
  SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
20
22
  SLASH_GRACE_PERIOD_L2_SLOTS: 0,