@aztec/slasher 0.0.1-commit.d431d1c → 0.0.1-commit.d58ff9d0

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.
Files changed (95) hide show
  1. package/README.md +90 -76
  2. package/dest/config.d.ts +1 -1
  3. package/dest/config.d.ts.map +1 -1
  4. package/dest/config.js +41 -29
  5. package/dest/factory/create_facade.d.ts +3 -3
  6. package/dest/factory/create_facade.d.ts.map +1 -1
  7. package/dest/factory/create_facade.js +26 -3
  8. package/dest/factory/create_implementation.d.ts +6 -7
  9. package/dest/factory/create_implementation.d.ts.map +1 -1
  10. package/dest/factory/create_implementation.js +8 -56
  11. package/dest/factory/get_settings.d.ts +4 -4
  12. package/dest/factory/get_settings.d.ts.map +1 -1
  13. package/dest/factory/get_settings.js +3 -3
  14. package/dest/factory/index.d.ts +2 -2
  15. package/dest/factory/index.d.ts.map +1 -1
  16. package/dest/factory/index.js +1 -1
  17. package/dest/generated/slasher-defaults.d.ts +8 -6
  18. package/dest/generated/slasher-defaults.d.ts.map +1 -1
  19. package/dest/generated/slasher-defaults.js +7 -5
  20. package/dest/index.d.ts +6 -4
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +5 -3
  23. package/dest/metrics.d.ts +7 -0
  24. package/dest/metrics.d.ts.map +1 -0
  25. package/dest/metrics.js +11 -0
  26. package/dest/null_slasher_client.d.ts +3 -4
  27. package/dest/null_slasher_client.d.ts.map +1 -1
  28. package/dest/null_slasher_client.js +1 -4
  29. package/dest/slash_offenses_collector.d.ts +10 -9
  30. package/dest/slash_offenses_collector.d.ts.map +1 -1
  31. package/dest/slash_offenses_collector.js +50 -30
  32. package/dest/{tally_slasher_client.d.ts → slasher_client.d.ts} +17 -28
  33. package/dest/slasher_client.d.ts.map +1 -0
  34. package/dest/{tally_slasher_client.js → slasher_client.js} +55 -45
  35. package/dest/slasher_client_facade.d.ts +6 -8
  36. package/dest/slasher_client_facade.d.ts.map +1 -1
  37. package/dest/slasher_client_facade.js +6 -9
  38. package/dest/slasher_client_interface.d.ts +7 -21
  39. package/dest/slasher_client_interface.d.ts.map +1 -1
  40. package/dest/slasher_client_interface.js +1 -4
  41. package/dest/stores/offenses_store.d.ts +12 -12
  42. package/dest/stores/offenses_store.d.ts.map +1 -1
  43. package/dest/stores/offenses_store.js +64 -39
  44. package/dest/watcher.d.ts +8 -1
  45. package/dest/watcher.d.ts.map +1 -1
  46. package/dest/watcher.js +1 -0
  47. package/dest/watchers/attestations_block_watcher.d.ts +26 -13
  48. package/dest/watchers/attestations_block_watcher.d.ts.map +1 -1
  49. package/dest/watchers/attestations_block_watcher.js +76 -61
  50. package/dest/watchers/attested_invalid_proposal_watcher.d.ts +42 -0
  51. package/dest/watchers/attested_invalid_proposal_watcher.d.ts.map +1 -0
  52. package/dest/watchers/attested_invalid_proposal_watcher.js +117 -0
  53. package/dest/watchers/broadcasted_invalid_checkpoint_proposal_watcher.d.ts +38 -0
  54. package/dest/watchers/broadcasted_invalid_checkpoint_proposal_watcher.d.ts.map +1 -0
  55. package/dest/watchers/broadcasted_invalid_checkpoint_proposal_watcher.js +138 -0
  56. package/dest/watchers/checkpoint_equivocation_watcher.d.ts +30 -0
  57. package/dest/watchers/checkpoint_equivocation_watcher.d.ts.map +1 -0
  58. package/dest/watchers/checkpoint_equivocation_watcher.js +69 -0
  59. package/dest/watchers/data_withholding_watcher.d.ts +63 -0
  60. package/dest/watchers/data_withholding_watcher.d.ts.map +1 -0
  61. package/dest/watchers/data_withholding_watcher.js +193 -0
  62. package/package.json +10 -10
  63. package/src/config.ts +48 -29
  64. package/src/factory/create_facade.ts +33 -5
  65. package/src/factory/create_implementation.ts +24 -105
  66. package/src/factory/get_settings.ts +8 -8
  67. package/src/factory/index.ts +1 -1
  68. package/src/generated/slasher-defaults.ts +7 -5
  69. package/src/index.ts +5 -3
  70. package/src/metrics.ts +19 -0
  71. package/src/null_slasher_client.ts +2 -6
  72. package/src/slash_offenses_collector.ts +70 -32
  73. package/src/{tally_slasher_client.ts → slasher_client.ts} +72 -54
  74. package/src/slasher_client_facade.ts +6 -11
  75. package/src/slasher_client_interface.ts +6 -21
  76. package/src/stores/offenses_store.ts +76 -48
  77. package/src/watcher.ts +8 -0
  78. package/src/watchers/attestations_block_watcher.ts +88 -82
  79. package/src/watchers/attested_invalid_proposal_watcher.ts +168 -0
  80. package/src/watchers/broadcasted_invalid_checkpoint_proposal_watcher.ts +192 -0
  81. package/src/watchers/checkpoint_equivocation_watcher.ts +96 -0
  82. package/src/watchers/data_withholding_watcher.ts +225 -0
  83. package/dest/empire_slasher_client.d.ts +0 -190
  84. package/dest/empire_slasher_client.d.ts.map +0 -1
  85. package/dest/empire_slasher_client.js +0 -572
  86. package/dest/stores/payloads_store.d.ts +0 -29
  87. package/dest/stores/payloads_store.d.ts.map +0 -1
  88. package/dest/stores/payloads_store.js +0 -125
  89. package/dest/tally_slasher_client.d.ts.map +0 -1
  90. package/dest/watchers/epoch_prune_watcher.d.ts +0 -38
  91. package/dest/watchers/epoch_prune_watcher.d.ts.map +0 -1
  92. package/dest/watchers/epoch_prune_watcher.js +0 -158
  93. package/src/empire_slasher_client.ts +0 -657
  94. package/src/stores/payloads_store.ts +0 -146
  95. package/src/watchers/epoch_prune_watcher.ts +0 -220
@@ -1,73 +1,25 @@
1
- import { EthAddress } from '@aztec/foundation/eth-address';
2
1
  import { createLogger } from '@aztec/foundation/log';
3
- import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
4
- import { EmpireSlasherClient } from '../empire_slasher_client.js';
5
2
  import { NullSlasherClient } from '../null_slasher_client.js';
3
+ import { SlasherClient } from '../slasher_client.js';
6
4
  import { SlasherOffensesStore } from '../stores/offenses_store.js';
7
- import { SlasherPayloadsStore } from '../stores/payloads_store.js';
8
- import { TallySlasherClient } from '../tally_slasher_client.js';
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')) {
5
+ import { getSlasherSettings } from './get_settings.js';
6
+ /** Creates a slasher client implementation based on the slasher proposer type in the rollup */ export async function createSlasherImplementation(config, rollup, l1Client, watchers, epochCache, dateProvider, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
11
7
  const proposer = await rollup.getSlashingProposer();
12
8
  if (!proposer) {
13
9
  return new NullSlasherClient(config);
14
- } else if (proposer.type === 'tally') {
15
- return createTallySlasher(config, rollup, proposer, watchers, dateProvider, epochCache, kvStore, logger);
16
10
  } else {
17
- if (!slashFactoryAddress || slashFactoryAddress.equals(EthAddress.ZERO)) {
18
- throw new Error('Cannot initialize an empire-based SlasherClient without a SlashFactory address');
19
- }
20
- const slashFactory = new SlashFactoryContract(l1Client, slashFactoryAddress.toString());
21
- return createEmpireSlasher(config, rollup, proposer, slashFactory, watchers, dateProvider, kvStore, logger);
11
+ return createSlasher(config, rollup, proposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger);
22
12
  }
23
13
  }
24
- async function createEmpireSlasher(config, rollup, slashingProposer, slashFactoryContract, watchers, dateProvider, kvStore, logger = createLogger('slasher')) {
25
- if (slashingProposer.type !== 'empire') {
26
- throw new Error('Slashing proposer contract is not of type Empire');
27
- }
28
- const [slashingExecutionDelayInRounds, slashingPayloadLifetimeInRounds, slashingRoundSize, slashingQuorumSize, epochDuration, proofSubmissionEpochs, l1GenesisTime, slotDuration, l1StartBlock, slasher] = await Promise.all([
29
- slashingProposer.getExecutionDelayInRounds(),
30
- slashingProposer.getLifetimeInRounds(),
31
- slashingProposer.getRoundSize(),
32
- slashingProposer.getQuorumSize(),
33
- rollup.getEpochDuration(),
34
- rollup.getProofSubmissionEpochs(),
35
- rollup.getL1GenesisTime(),
36
- rollup.getSlotDuration(),
37
- rollup.getL1StartBlock(),
38
- rollup.getSlasherContract()
39
- ]);
14
+ async function createSlasher(config, rollup, slashingProposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
40
15
  const settings = {
41
- slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
42
- slashingPayloadLifetimeInRounds: Number(slashingPayloadLifetimeInRounds),
43
- slashingRoundSize: Number(slashingRoundSize),
44
- slashingQuorumSize: Number(slashingQuorumSize),
45
- epochDuration: Number(epochDuration),
46
- proofSubmissionEpochs: Number(proofSubmissionEpochs),
47
- l1GenesisTime: l1GenesisTime,
48
- slotDuration: Number(slotDuration),
49
- l1StartBlock,
50
- ethereumSlotDuration: config.ethereumSlotDuration,
51
- slashingAmounts: undefined
16
+ ...await getSlasherSettings(rollup, slashingProposer),
17
+ rollupRegisteredAtL2Slot
52
18
  };
53
- const payloadsStore = new SlasherPayloadsStore(kvStore, {
54
- slashingPayloadLifetimeInRounds: settings.slashingPayloadLifetimeInRounds
55
- });
56
- const offensesStore = new SlasherOffensesStore(kvStore, {
57
- ...settings,
58
- slashOffenseExpirationRounds: config.slashOffenseExpirationRounds
59
- });
60
- return new EmpireSlasherClient(config, settings, slashFactoryContract, slashingProposer, slasher, rollup, watchers, dateProvider, offensesStore, payloadsStore, logger);
61
- }
62
- async function createTallySlasher(config, rollup, slashingProposer, watchers, dateProvider, epochCache, kvStore, logger = createLogger('slasher')) {
63
- if (slashingProposer.type !== 'tally') {
64
- throw new Error('Slashing proposer contract is not of type tally');
65
- }
66
- const settings = await getTallySlasherSettings(rollup, slashingProposer);
67
19
  const slasher = await rollup.getSlasherContract();
68
20
  const offensesStore = new SlasherOffensesStore(kvStore, {
69
21
  ...settings,
70
22
  slashOffenseExpirationRounds: config.slashOffenseExpirationRounds
71
23
  });
72
- return new TallySlasherClient(config, settings, slashingProposer, slasher, rollup, watchers, epochCache, dateProvider, offensesStore, logger);
24
+ return new SlasherClient(config, settings, slashingProposer, slasher, rollup, watchers, epochCache, dateProvider, offensesStore, logger);
73
25
  }
@@ -1,4 +1,4 @@
1
- import type { RollupContract, TallySlashingProposerContract } from '@aztec/ethereum/contracts';
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0X3NldHRpbmdzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFjdG9yeS9nZXRfc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0YsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUV2RSx3QkFBc0IsdUJBQXVCLENBQzNDLE1BQU0sRUFBRSxjQUFjLEVBQ3RCLGdCQUFnQixDQUFDLEVBQUUsNkJBQTZCLEdBQy9DLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQWtEL0IifQ==
1
+ import type { RollupContract, SlashingProposerContract } from '@aztec/ethereum/contracts';
2
+ import type { SlasherSettings } from '../slasher_client.js';
3
+ export declare function getSlasherSettings(rollup: RollupContract, slashingProposer?: SlashingProposerContract): Promise<Omit<SlasherSettings, 'rollupRegisteredAtL2Slot'>>;
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0X3NldHRpbmdzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFjdG9yeS9nZXRfc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFMUYsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFNUQsd0JBQXNCLGtCQUFrQixDQUN0QyxNQUFNLEVBQUUsY0FBYyxFQUN0QixnQkFBZ0IsQ0FBQyxFQUFFLHdCQUF3QixHQUMxQyxPQUFPLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSwwQkFBMEIsQ0FBQyxDQUFDLENBa0Q1RCJ9
@@ -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,CAkD/B"}
1
+ {"version":3,"file":"get_settings.d.ts","sourceRoot":"","sources":["../../src/factory/get_settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,gBAAgB,CAAC,EAAE,wBAAwB,GAC1C,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC,CAkD5D"}
@@ -1,8 +1,8 @@
1
- export async function getTallySlasherSettings(rollup, slashingProposer) {
1
+ export async function getSlasherSettings(rollup, slashingProposer) {
2
2
  if (!slashingProposer) {
3
3
  const rollupSlashingProposer = await rollup.getSlashingProposer();
4
- if (!rollupSlashingProposer || rollupSlashingProposer.type !== 'tally') {
5
- throw new Error('Rollup slashing proposer is not of type tally');
4
+ if (!rollupSlashingProposer) {
5
+ throw new Error('Rollup slashing proposer not found');
6
6
  }
7
7
  slashingProposer = rollupSlashingProposer;
8
8
  }
@@ -1,3 +1,3 @@
1
1
  export { createSlasherFacade as createSlasher } from './create_facade.js';
2
- export { getTallySlasherSettings } from './get_settings.js';
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mYWN0b3J5L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxtQkFBbUIsSUFBSSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQyJ9
2
+ export { getSlasherSettings } from './get_settings.js';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mYWN0b3J5L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxtQkFBbUIsSUFBSSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/factory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/factory/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,2 +1,2 @@
1
1
  export { createSlasherFacade as createSlasher } from './create_facade.js';
2
- export { getTallySlasherSettings } from './get_settings.js';
2
+ export { getSlasherSettings } from './get_settings.js';
@@ -1,19 +1,21 @@
1
1
  /** Default slasher configuration values from network-defaults.yml */
2
2
  export declare const slasherDefaultEnv: {
3
- readonly SLASH_MIN_PENALTY_PERCENTAGE: 0.5;
4
- readonly SLASH_MAX_PENALTY_PERCENTAGE: 2;
5
3
  readonly SLASH_OFFENSE_EXPIRATION_ROUNDS: 4;
6
- readonly SLASH_MAX_PAYLOAD_SIZE: 50;
4
+ readonly SLASH_MAX_PAYLOAD_SIZE: 80;
7
5
  readonly SLASH_EXECUTE_ROUNDS_LOOK_BACK: 4;
8
- readonly SLASH_PRUNE_PENALTY: 10000000000000000000;
9
6
  readonly SLASH_DATA_WITHHOLDING_PENALTY: 10000000000000000000;
7
+ readonly SLASH_DATA_WITHHOLDING_TOLERANCE_SLOTS: 3;
10
8
  readonly SLASH_INACTIVITY_TARGET_PERCENTAGE: 0.9;
11
9
  readonly SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD: 1;
12
10
  readonly SLASH_INACTIVITY_PENALTY: 10000000000000000000;
13
11
  readonly SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000;
14
- readonly SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000;
12
+ readonly SLASH_PROPOSE_DESCENDANT_OF_CHECKPOINT_WITH_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000;
13
+ readonly SLASH_ATTEST_INVALID_CHECKPOINT_PROPOSAL_PENALTY: 10000000000000000000;
14
+ readonly SLASH_DUPLICATE_PROPOSAL_PENALTY: 0;
15
+ readonly SLASH_DUPLICATE_ATTESTATION_PENALTY: 0;
15
16
  readonly SLASH_UNKNOWN_PENALTY: 10000000000000000000;
16
17
  readonly SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000;
18
+ readonly SLASH_INVALID_CHECKPOINT_PROPOSAL_PENALTY: 0;
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"}
@@ -1,19 +1,21 @@
1
1
  // Auto-generated from spartan/environments/network-defaults.yml
2
2
  // Do not edit manually - run yarn generate to regenerate
3
3
  /** Default slasher configuration values from network-defaults.yml */ export const slasherDefaultEnv = {
4
- SLASH_MIN_PENALTY_PERCENTAGE: 0.5,
5
- SLASH_MAX_PENALTY_PERCENTAGE: 2,
6
4
  SLASH_OFFENSE_EXPIRATION_ROUNDS: 4,
7
- SLASH_MAX_PAYLOAD_SIZE: 50,
5
+ SLASH_MAX_PAYLOAD_SIZE: 80,
8
6
  SLASH_EXECUTE_ROUNDS_LOOK_BACK: 4,
9
- SLASH_PRUNE_PENALTY: 10000000000000000000,
10
7
  SLASH_DATA_WITHHOLDING_PENALTY: 10000000000000000000,
8
+ SLASH_DATA_WITHHOLDING_TOLERANCE_SLOTS: 3,
11
9
  SLASH_INACTIVITY_TARGET_PERCENTAGE: 0.9,
12
10
  SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD: 1,
13
11
  SLASH_INACTIVITY_PENALTY: 10000000000000000000,
14
12
  SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
15
- SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000,
13
+ SLASH_PROPOSE_DESCENDANT_OF_CHECKPOINT_WITH_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
14
+ SLASH_ATTEST_INVALID_CHECKPOINT_PROPOSAL_PENALTY: 10000000000000000000,
15
+ SLASH_DUPLICATE_PROPOSAL_PENALTY: 0,
16
+ SLASH_DUPLICATE_ATTESTATION_PENALTY: 0,
16
17
  SLASH_UNKNOWN_PENALTY: 10000000000000000000,
17
18
  SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
19
+ SLASH_INVALID_CHECKPOINT_PROPOSAL_PENALTY: 0,
18
20
  SLASH_GRACE_PERIOD_L2_SLOTS: 0
19
21
  };
package/dest/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  export * from './config.js';
2
- export * from './watchers/epoch_prune_watcher.js';
2
+ export * from './watchers/data_withholding_watcher.js';
3
3
  export * from './watchers/attestations_block_watcher.js';
4
- export * from './empire_slasher_client.js';
5
- export * from './tally_slasher_client.js';
4
+ export * from './watchers/attested_invalid_proposal_watcher.js';
5
+ export * from './watchers/broadcasted_invalid_checkpoint_proposal_watcher.js';
6
+ export * from './watchers/checkpoint_equivocation_watcher.js';
7
+ export * from './slasher_client.js';
6
8
  export * from './slash_offenses_collector.js';
7
9
  export * from './slasher_client_interface.js';
8
10
  export * from './factory/index.js';
9
11
  export * from './watcher.js';
10
12
  export * from '@aztec/stdlib/slashing';
11
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLG1DQUFtQyxDQUFDO0FBQ2xELGNBQWMsMENBQTBDLENBQUM7QUFDekQsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsK0JBQStCLENBQUM7QUFDOUMsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsd0JBQXdCLENBQUMifQ==
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLHdDQUF3QyxDQUFDO0FBQ3ZELGNBQWMsMENBQTBDLENBQUM7QUFDekQsY0FBYyxpREFBaUQsQ0FBQztBQUNoRSxjQUFjLCtEQUErRCxDQUFDO0FBQzlFLGNBQWMsK0NBQStDLENBQUM7QUFDOUQsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLCtCQUErQixDQUFDO0FBQzlDLGNBQWMsK0JBQStCLENBQUM7QUFDOUMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLHdCQUF3QixDQUFDIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mCAAmC,CAAC;AAClD,cAAc,0CAA0C,CAAC;AACzD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,wCAAwC,CAAC;AACvD,cAAc,0CAA0C,CAAC;AACzD,cAAc,iDAAiD,CAAC;AAChE,cAAc,+DAA+D,CAAC;AAC9E,cAAc,+CAA+C,CAAC;AAC9D,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
package/dest/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  export * from './config.js';
2
- export * from './watchers/epoch_prune_watcher.js';
2
+ export * from './watchers/data_withholding_watcher.js';
3
3
  export * from './watchers/attestations_block_watcher.js';
4
- export * from './empire_slasher_client.js';
5
- export * from './tally_slasher_client.js';
4
+ export * from './watchers/attested_invalid_proposal_watcher.js';
5
+ export * from './watchers/broadcasted_invalid_checkpoint_proposal_watcher.js';
6
+ export * from './watchers/checkpoint_equivocation_watcher.js';
7
+ export * from './slasher_client.js';
6
8
  export * from './slash_offenses_collector.js';
7
9
  export * from './slasher_client_interface.js';
8
10
  export * from './factory/index.js';
@@ -0,0 +1,7 @@
1
+ import { type TelemetryClient } from '@aztec/telemetry-client';
2
+ export declare class SlasherMetrics {
3
+ private readonly roundExecuted;
4
+ constructor(client: TelemetryClient, name?: string);
5
+ recordRoundExecuted(): void;
6
+ }
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL21ldHJpY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLEtBQUssZUFBZSxFQUdyQixNQUFNLHlCQUF5QixDQUFDO0FBRWpDLHFCQUFhLGNBQWM7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQWdCO0lBRTlDLFlBQVksTUFBTSxFQUFFLGVBQWUsRUFBRSxJQUFJLFNBQVksRUFHcEQ7SUFFTSxtQkFBbUIsSUFBSSxJQUFJLENBRWpDO0NBQ0YifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C,YAAY,MAAM,EAAE,eAAe,EAAE,IAAI,SAAY,EAGpD;IAEM,mBAAmB,IAAI,IAAI,CAEjC;CACF"}
@@ -0,0 +1,11 @@
1
+ import { Metrics, createUpDownCounterWithDefault } from '@aztec/telemetry-client';
2
+ export class SlasherMetrics {
3
+ roundExecuted;
4
+ constructor(client, name = 'Slasher'){
5
+ const meter = client.getMeter(name);
6
+ this.roundExecuted = createUpDownCounterWithDefault(meter, Metrics.SLASHER_ROUND_EXECUTED_COUNT);
7
+ }
8
+ recordRoundExecuted() {
9
+ this.roundExecuted.add(1);
10
+ }
11
+ }
@@ -1,5 +1,5 @@
1
1
  import type { SlotNumber } from '@aztec/foundation/branded-types';
2
- import type { Offense, ProposerSlashAction, SlashPayloadRound } from '@aztec/stdlib/slashing';
2
+ import type { Offense, ProposerSlashAction } from '@aztec/stdlib/slashing';
3
3
  import type { SlasherConfig } from './config.js';
4
4
  import type { SlasherClientInterface } from './slasher_client_interface.js';
5
5
  export declare class NullSlasherClient implements SlasherClientInterface {
@@ -7,11 +7,10 @@ export declare class NullSlasherClient implements SlasherClientInterface {
7
7
  constructor(config: SlasherConfig);
8
8
  start(): Promise<void>;
9
9
  stop(): Promise<void>;
10
- getSlashPayloads(): Promise<SlashPayloadRound[]>;
11
10
  gatherOffensesForRound(_round?: bigint): Promise<Offense[]>;
12
- getPendingOffenses(): Promise<Offense[]>;
11
+ getOffenses(): Promise<Offense[]>;
13
12
  updateConfig(config: Partial<SlasherConfig>): void;
14
13
  getProposerActions(_slotNumber: SlotNumber): Promise<ProposerSlashAction[]>;
15
14
  getConfig(): SlasherConfig;
16
15
  }
17
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbF9zbGFzaGVyX2NsaWVudC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL251bGxfc2xhc2hlcl9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUYsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFNUUscUJBQWEsaUJBQWtCLFlBQVcsc0JBQXNCO0lBQ2xELE9BQU8sQ0FBQyxNQUFNO0lBQTFCLFlBQW9CLE1BQU0sRUFBRSxhQUFhLEVBQUk7SUFFdEMsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFNUI7SUFFTSxJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUUzQjtJQUVNLGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBRXREO0lBRU0sc0JBQXNCLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUVqRTtJQUVNLGtCQUFrQixJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUU5QztJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FFeEQ7SUFFTSxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsVUFBVSxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBRWpGO0lBRU0sU0FBUyxJQUFJLGFBQWEsQ0FFaEM7Q0FDRiJ9
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbF9zbGFzaGVyX2NsaWVudC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL251bGxfc2xhc2hlcl9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFM0UsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFNUUscUJBQWEsaUJBQWtCLFlBQVcsc0JBQXNCO0lBQ2xELE9BQU8sQ0FBQyxNQUFNO0lBQTFCLFlBQW9CLE1BQU0sRUFBRSxhQUFhLEVBQUk7SUFFdEMsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFNUI7SUFFTSxJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUUzQjtJQUVNLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FFakU7SUFFTSxXQUFXLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRXZDO0lBRU0sWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUV4RDtJQUVNLGtCQUFrQixDQUFDLFdBQVcsRUFBRSxVQUFVLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FFakY7SUFFTSxTQUFTLElBQUksYUFBYSxDQUVoQztDQUNGIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"null_slasher_client.d.ts","sourceRoot":"","sources":["../src/null_slasher_client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE9F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,qBAAa,iBAAkB,YAAW,sBAAsB;IAClD,OAAO,CAAC,MAAM;IAA1B,YAAoB,MAAM,EAAE,aAAa,EAAI;IAEtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5B;IAEM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAEM,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAEtD;IAEM,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEjE;IAEM,kBAAkB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAE9C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAExD;IAEM,kBAAkB,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAEjF;IAEM,SAAS,IAAI,aAAa,CAEhC;CACF"}
1
+ {"version":3,"file":"null_slasher_client.d.ts","sourceRoot":"","sources":["../src/null_slasher_client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,qBAAa,iBAAkB,YAAW,sBAAsB;IAClD,OAAO,CAAC,MAAM;IAA1B,YAAoB,MAAM,EAAE,aAAa,EAAI;IAEtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5B;IAEM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAEM,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEjE;IAEM,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAEvC;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAExD;IAEM,kBAAkB,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAEjF;IAEM,SAAS,IAAI,aAAa,CAEhC;CACF"}
@@ -9,13 +9,10 @@ export class NullSlasherClient {
9
9
  stop() {
10
10
  return Promise.resolve();
11
11
  }
12
- getSlashPayloads() {
13
- return Promise.resolve([]);
14
- }
15
12
  gatherOffensesForRound(_round) {
16
13
  return Promise.resolve([]);
17
14
  }
18
- getPendingOffenses() {
15
+ getOffenses() {
19
16
  return Promise.resolve([]);
20
17
  }
21
18
  updateConfig(config) {
@@ -1,12 +1,14 @@
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';
4
- import { type OffenseIdentifier } from '@aztec/stdlib/slashing';
5
5
  import type { SlasherOffensesStore } from './stores/offenses_store.js';
6
- import { type WantToSlashArgs, type Watcher } from './watcher.js';
6
+ import { type WantToClearSlashArgs, type WantToSlashArgs, type Watcher } from './watcher.js';
7
7
  export type SlashOffensesCollectorConfig = Prettify<Pick<SlasherConfig, 'slashGracePeriodL2Slots'>>;
8
8
  export type SlashOffensesCollectorSettings = Prettify<Pick<L1RollupConstants, 'epochDuration'> & {
9
9
  slashingAmounts: [bigint, bigint, bigint] | undefined;
10
+ /** L2 slot at which the rollup was registered as canonical in the Registry. Used to anchor the slash grace period. */
11
+ rollupRegisteredAtL2Slot: SlotNumber;
10
12
  }>;
11
13
  /**
12
14
  * Collects and manages slashable offenses from watchers.
@@ -20,6 +22,7 @@ export declare class SlashOffensesCollector {
20
22
  private readonly offensesStore;
21
23
  private readonly log;
22
24
  private readonly unwatchCallbacks;
25
+ private readonly storeMutationQueue;
23
26
  constructor(config: SlashOffensesCollectorConfig, settings: SlashOffensesCollectorSettings, watchers: Watcher[], offensesStore: SlasherOffensesStore, log?: import("@aztec/foundation/log").Logger);
24
27
  start(): Promise<void>;
25
28
  stop(): Promise<void>;
@@ -29,17 +32,15 @@ export declare class SlashOffensesCollector {
29
32
  * @param args - the arguments from the watcher, including the validators, amounts, and offenses
30
33
  */
31
34
  handleWantToSlash(args: WantToSlashArgs[]): Promise<void>;
35
+ handleWantToClearSlash(args: WantToClearSlashArgs[]): Promise<void>;
32
36
  /**
33
37
  * Triggered on a time basis when we enter a new slashing round.
34
38
  * Clears expired offenses from stores.
35
39
  */
36
40
  handleNewRound(round: bigint): Promise<void>;
37
- /**
38
- * Marks offenses as slashed (no longer pending)
39
- * @param offenses - The offenses to mark as slashed
40
- */
41
- markAsSlashed(offenses: OffenseIdentifier[]): Promise<void>;
42
- /** Returns whether to skip an offense if it happened during the grace period at the beginning of the chain */
41
+ /** Returns whether to skip an offense if it happened during the grace period after the network upgrade */
43
42
  private shouldSkipOffense;
43
+ private getOffenseLogData;
44
+ private enqueueStoreMutation;
44
45
  }
45
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDckUsT0FBTyxFQUFnQixLQUFLLGlCQUFpQixFQUFxQixNQUFNLHdCQUF3QixDQUFDO0FBRWpHLE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdkUsT0FBTyxFQUF1QixLQUFLLGVBQWUsRUFBRSxLQUFLLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV2RixNQUFNLE1BQU0sNEJBQTRCLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDO0FBQ3BHLE1BQU0sTUFBTSw4QkFBOEIsR0FBRyxRQUFRLENBQ25ELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxlQUFlLENBQUMsR0FBRztJQUFFLGVBQWUsRUFBRSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLEdBQUcsU0FBUyxDQUFBO0NBQUUsQ0FDckcsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCxxQkFBYSxzQkFBc0I7SUFJL0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNO0lBQ3ZCLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUTtJQUN6QixPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVE7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQVB0QixPQUFPLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFzQjtJQUV2RCxZQUNtQixNQUFNLEVBQUUsNEJBQTRCLEVBQ3BDLFFBQVEsRUFBRSw4QkFBOEIsRUFDeEMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUNuQixhQUFhLEVBQUUsb0JBQW9CLEVBQ25DLEdBQUcseUNBQTZDLEVBQy9EO0lBRUcsS0FBSyxrQkFhWDtJQUVNLElBQUksa0JBU1Y7SUFFRDs7OztPQUlHO0lBQ1UsaUJBQWlCLENBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRSxpQkE2QnJEO0lBRUQ7OztPQUdHO0lBQ1UsY0FBYyxDQUFDLEtBQUssRUFBRSxNQUFNLGlCQUt4QztJQUVEOzs7T0FHRztJQUNJLGFBQWEsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsaUJBR2pEO0lBRUQsOEdBQThHO0lBQzlHLE9BQU8sQ0FBQyxpQkFBaUI7Q0FJMUIifQ==
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBR2xFLE9BQU8sS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFHckUsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN2RSxPQUFPLEVBR0wsS0FBSyxvQkFBb0IsRUFDekIsS0FBSyxlQUFlLEVBQ3BCLEtBQUssT0FBTyxFQUNiLE1BQU0sY0FBYyxDQUFDO0FBRXRCLE1BQU0sTUFBTSw0QkFBNEIsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDLENBQUM7QUFDcEcsTUFBTSxNQUFNLDhCQUE4QixHQUFHLFFBQVEsQ0FDbkQsSUFBSSxDQUFDLGlCQUFpQixFQUFFLGVBQWUsQ0FBQyxHQUFHO0lBQ3pDLGVBQWUsRUFBRSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLEdBQUcsU0FBUyxDQUFDO0lBQ3RELHNIQUFzSDtJQUN0SCx3QkFBd0IsRUFBRSxVQUFVLENBQUM7Q0FDdEMsQ0FDRixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILHFCQUFhLHNCQUFzQjtJQUsvQixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU07SUFDdkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRO0lBQ3pCLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUTtJQUN6QixPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWE7SUFDOUIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHO0lBUnRCLE9BQU8sQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQXNCO0lBQ3ZELE9BQU8sQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQXFCO0lBRXhELFlBQ21CLE1BQU0sRUFBRSw0QkFBNEIsRUFDcEMsUUFBUSxFQUFFLDhCQUE4QixFQUN4QyxRQUFRLEVBQUUsT0FBTyxFQUFFLEVBQ25CLGFBQWEsRUFBRSxvQkFBb0IsRUFDbkMsR0FBRyx5Q0FBNkMsRUFDL0Q7SUFFRyxLQUFLLGtCQW1CWDtJQUVZLElBQUksa0JBVWhCO0lBRUQ7Ozs7T0FJRztJQUNVLGlCQUFpQixDQUFDLElBQUksRUFBRSxlQUFlLEVBQUUsaUJBK0JyRDtJQUVZLHNCQUFzQixDQUFDLElBQUksRUFBRSxvQkFBb0IsRUFBRSxpQkFXL0Q7SUFFRDs7O09BR0c7SUFDVSxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0saUJBS3hDO0lBRUQsMEdBQTBHO0lBQzFHLE9BQU8sQ0FBQyxpQkFBaUI7SUFLekIsT0FBTyxDQUFDLGlCQUFpQjtJQVF6QixPQUFPLENBQUMsb0JBQW9CO0NBRzdCIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"slash_offenses_collector.d.ts","sourceRoot":"","sources":["../src/slash_offenses_collector.ts"],"names":[],"mappings":"AACA,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;IAAE,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAAE,CACrG,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,8GAA8G;IAC9G,OAAO,CAAC,iBAAiB;CAI1B"}
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;AAGlE,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;AAGrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,OAAO,EACb,MAAM,cAAc,CAAC;AAEtB,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;IAK/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;IARtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsB;IACvD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IAExD,YACmB,MAAM,EAAE,4BAA4B,EACpC,QAAQ,EAAE,8BAA8B,EACxC,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,EAAE,oBAAoB,EACnC,GAAG,yCAA6C,EAC/D;IAEG,KAAK,kBAmBX;IAEY,IAAI,kBAUhB;IAED;;;;OAIG;IACU,iBAAiB,CAAC,IAAI,EAAE,eAAe,EAAE,iBA+BrD;IAEY,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,EAAE,iBAW/D;IAED;;;OAGG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,iBAKxC;IAED,0GAA0G;IAC1G,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,oBAAoB;CAG7B"}
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
- import { getSlotForOffense } from '@aztec/stdlib/slashing';
3
- import { WANT_TO_SLASH_EVENT } from './watcher.js';
2
+ import { SerialQueue } from '@aztec/foundation/queue';
3
+ import { getOffenseTypeName, getSlotForOffense } from '@aztec/stdlib/slashing';
4
+ import { WANT_TO_CLEAR_SLASH_EVENT, WANT_TO_SLASH_EVENT } from './watcher.js';
4
5
  /**
5
6
  * Collects and manages slashable offenses from watchers.
6
7
  * This class handles the common logic for subscribing to slash watcher events,
@@ -12,6 +13,7 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
12
13
  offensesStore;
13
14
  log;
14
15
  unwatchCallbacks;
16
+ storeMutationQueue;
15
17
  constructor(config, settings, watchers, offensesStore, log = createLogger('slasher:offenses-collector')){
16
18
  this.config = config;
17
19
  this.settings = settings;
@@ -19,25 +21,30 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
19
21
  this.offensesStore = offensesStore;
20
22
  this.log = log;
21
23
  this.unwatchCallbacks = [];
24
+ this.storeMutationQueue = new SerialQueue();
22
25
  }
23
26
  start() {
24
27
  this.log.debug('Starting SlashOffensesCollector...');
25
- // Subscribe to watchers WANT_TO_SLASH_EVENT
28
+ this.storeMutationQueue.start();
29
+ // Subscribe to watcher slashing events.
26
30
  for (const watcher of this.watchers){
27
- const wantToSlashCallback = (args)=>void this.handleWantToSlash(args).catch((err)=>this.log.error('Error handling wantToSlash', err));
31
+ const wantToSlashCallback = (args)=>this.enqueueStoreMutation('wantToSlash', ()=>this.handleWantToSlash(args));
28
32
  watcher.on(WANT_TO_SLASH_EVENT, wantToSlashCallback);
29
33
  this.unwatchCallbacks.push(()=>watcher.removeListener(WANT_TO_SLASH_EVENT, wantToSlashCallback));
34
+ const wantToClearSlashCallback = (args)=>this.enqueueStoreMutation('wantToClearSlash', ()=>this.handleWantToClearSlash(args));
35
+ watcher.on(WANT_TO_CLEAR_SLASH_EVENT, wantToClearSlashCallback);
36
+ this.unwatchCallbacks.push(()=>watcher.removeListener(WANT_TO_CLEAR_SLASH_EVENT, wantToClearSlashCallback));
30
37
  }
31
38
  this.log.info('Started SlashOffensesCollector');
32
39
  return Promise.resolve();
33
40
  }
34
- stop() {
41
+ async stop() {
35
42
  this.log.debug('Stopping SlashOffensesCollector...');
36
43
  for (const unwatchCallback of this.unwatchCallbacks){
37
44
  unwatchCallback();
38
45
  }
46
+ await this.storeMutationQueue.end();
39
47
  this.log.info('SlashOffensesCollector stopped');
40
- return Promise.resolve();
41
48
  }
42
49
  /**
43
50
  * Called when a slash watcher emits WANT_TO_SLASH_EVENT.
@@ -45,28 +52,40 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
45
52
  * @param args - the arguments from the watcher, including the validators, amounts, and offenses
46
53
  */ async handleWantToSlash(args) {
47
54
  for (const arg of args){
48
- const pendingOffense = {
55
+ const offense = {
49
56
  validator: arg.validator,
50
57
  amount: arg.amount,
51
58
  offenseType: arg.offenseType,
52
59
  epochOrSlot: arg.epochOrSlot
53
60
  };
54
- if (this.shouldSkipOffense(pendingOffense)) {
55
- this.log.verbose('Skipping offense during grace period', pendingOffense);
56
- continue;
57
- }
58
- if (await this.offensesStore.hasOffense(pendingOffense)) {
59
- this.log.debug('Skipping repeated offense', pendingOffense);
61
+ if (this.shouldSkipOffense(offense)) {
62
+ this.log.verbose('Skipping offense during grace period', this.getOffenseLogData(offense));
60
63
  continue;
61
64
  }
62
- if (this.settings.slashingAmounts) {
63
- const minSlash = this.settings.slashingAmounts[0];
64
- if (arg.amount < minSlash) {
65
- this.log.warn(`Offense amount ${arg.amount} is below minimum slashing amount ${minSlash}`);
65
+ const added = await this.offensesStore.addOffense(offense);
66
+ if (added) {
67
+ if (this.settings.slashingAmounts) {
68
+ const minSlash = this.settings.slashingAmounts[0];
69
+ if (arg.amount < minSlash) {
70
+ this.log.warn(`Offense amount ${arg.amount} is below minimum slashing amount ${minSlash}`, this.getOffenseLogData(offense));
71
+ }
66
72
  }
73
+ this.log.info(`Adding pending offense for validator ${arg.validator}`, this.getOffenseLogData(offense));
74
+ } else {
75
+ this.log.debug('Skipping repeated offense', this.getOffenseLogData(offense));
76
+ }
77
+ }
78
+ }
79
+ async handleWantToClearSlash(args) {
80
+ for (const arg of args){
81
+ const cleared = await this.offensesStore.clearOffenses(arg);
82
+ if (cleared > 0) {
83
+ this.log.info(`Cleared ${cleared} pending offenses`, {
84
+ offenseType: getOffenseTypeName(arg.offenseType),
85
+ epochOrSlot: arg.epochOrSlot,
86
+ validators: arg.validators?.map((validator)=>validator.toString())
87
+ });
67
88
  }
68
- this.log.info(`Adding pending offense for validator ${arg.validator}`, pendingOffense);
69
- await this.offensesStore.addPendingOffense(pendingOffense);
70
89
  }
71
90
  }
72
91
  /**
@@ -78,17 +97,18 @@ import { WANT_TO_SLASH_EVENT } from './watcher.js';
78
97
  this.log.debug(`Cleared ${cleared} expired offenses for round ${round}`);
79
98
  }
80
99
  }
81
- /**
82
- * Marks offenses as slashed (no longer pending)
83
- * @param offenses - The offenses to mark as slashed
84
- */ markAsSlashed(offenses) {
85
- this.log.verbose(`Marking offenses as slashed`, {
86
- offenses
87
- });
88
- return this.offensesStore.markAsSlashed(offenses);
89
- }
90
- /** Returns whether to skip an offense if it happened during the grace period at the beginning of the chain */ shouldSkipOffense(offense) {
100
+ /** Returns whether to skip an offense if it happened during the grace period after the network upgrade */ shouldSkipOffense(offense) {
91
101
  const offenseSlot = getSlotForOffense(offense, this.settings);
92
- return offenseSlot < this.config.slashGracePeriodL2Slots;
102
+ return offenseSlot < this.settings.rollupRegisteredAtL2Slot + this.config.slashGracePeriodL2Slots;
103
+ }
104
+ getOffenseLogData(offense) {
105
+ return {
106
+ ...offense,
107
+ validator: offense.validator.toString(),
108
+ offenseType: getOffenseTypeName(offense.offenseType)
109
+ };
110
+ }
111
+ enqueueStoreMutation(label, callback) {
112
+ void this.storeMutationQueue.put(callback).catch((err)=>this.log.error(`Error handling ${label}`, err));
93
113
  }
94
114
  }