@aztec/slasher 0.0.1-commit.001888fc

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 (86) hide show
  1. package/README.md +228 -0
  2. package/dest/config.d.ts +6 -0
  3. package/dest/config.d.ts.map +1 -0
  4. package/dest/config.js +146 -0
  5. package/dest/empire_slasher_client.d.ts +190 -0
  6. package/dest/empire_slasher_client.d.ts.map +1 -0
  7. package/dest/empire_slasher_client.js +564 -0
  8. package/dest/factory/create_facade.d.ts +16 -0
  9. package/dest/factory/create_facade.d.ts.map +1 -0
  10. package/dest/factory/create_facade.js +46 -0
  11. package/dest/factory/create_implementation.d.ts +18 -0
  12. package/dest/factory/create_implementation.d.ts.map +1 -0
  13. package/dest/factory/create_implementation.js +77 -0
  14. package/dest/factory/get_settings.d.ts +4 -0
  15. package/dest/factory/get_settings.d.ts.map +1 -0
  16. package/dest/factory/get_settings.js +36 -0
  17. package/dest/factory/index.d.ts +3 -0
  18. package/dest/factory/index.d.ts.map +1 -0
  19. package/dest/factory/index.js +2 -0
  20. package/dest/generated/slasher-defaults.d.ts +21 -0
  21. package/dest/generated/slasher-defaults.d.ts.map +1 -0
  22. package/dest/generated/slasher-defaults.js +21 -0
  23. package/dest/index.d.ts +11 -0
  24. package/dest/index.d.ts.map +1 -0
  25. package/dest/index.js +10 -0
  26. package/dest/null_slasher_client.d.ts +17 -0
  27. package/dest/null_slasher_client.d.ts.map +1 -0
  28. package/dest/null_slasher_client.js +33 -0
  29. package/dest/slash_offenses_collector.d.ts +48 -0
  30. package/dest/slash_offenses_collector.d.ts.map +1 -0
  31. package/dest/slash_offenses_collector.js +94 -0
  32. package/dest/slash_round_monitor.d.ts +30 -0
  33. package/dest/slash_round_monitor.d.ts.map +1 -0
  34. package/dest/slash_round_monitor.js +52 -0
  35. package/dest/slasher_client_facade.d.ts +45 -0
  36. package/dest/slasher_client_facade.d.ts.map +1 -0
  37. package/dest/slasher_client_facade.js +78 -0
  38. package/dest/slasher_client_interface.d.ts +39 -0
  39. package/dest/slasher_client_interface.d.ts.map +1 -0
  40. package/dest/slasher_client_interface.js +4 -0
  41. package/dest/stores/offenses_store.d.ts +37 -0
  42. package/dest/stores/offenses_store.d.ts.map +1 -0
  43. package/dest/stores/offenses_store.js +107 -0
  44. package/dest/stores/payloads_store.d.ts +29 -0
  45. package/dest/stores/payloads_store.d.ts.map +1 -0
  46. package/dest/stores/payloads_store.js +128 -0
  47. package/dest/stores/schema_version.d.ts +2 -0
  48. package/dest/stores/schema_version.d.ts.map +1 -0
  49. package/dest/stores/schema_version.js +1 -0
  50. package/dest/tally_slasher_client.d.ts +125 -0
  51. package/dest/tally_slasher_client.d.ts.map +1 -0
  52. package/dest/tally_slasher_client.js +354 -0
  53. package/dest/test/dummy_watcher.d.ts +11 -0
  54. package/dest/test/dummy_watcher.d.ts.map +1 -0
  55. package/dest/test/dummy_watcher.js +14 -0
  56. package/dest/watcher.d.ts +21 -0
  57. package/dest/watcher.d.ts.map +1 -0
  58. package/dest/watcher.js +1 -0
  59. package/dest/watchers/attestations_block_watcher.d.ts +34 -0
  60. package/dest/watchers/attestations_block_watcher.d.ts.map +1 -0
  61. package/dest/watchers/attestations_block_watcher.js +142 -0
  62. package/dest/watchers/epoch_prune_watcher.d.ts +39 -0
  63. package/dest/watchers/epoch_prune_watcher.d.ts.map +1 -0
  64. package/dest/watchers/epoch_prune_watcher.js +176 -0
  65. package/package.json +92 -0
  66. package/src/config.ts +172 -0
  67. package/src/empire_slasher_client.ts +649 -0
  68. package/src/factory/create_facade.ts +82 -0
  69. package/src/factory/create_implementation.ts +184 -0
  70. package/src/factory/get_settings.ts +58 -0
  71. package/src/factory/index.ts +2 -0
  72. package/src/generated/slasher-defaults.ts +23 -0
  73. package/src/index.ts +10 -0
  74. package/src/null_slasher_client.ts +41 -0
  75. package/src/slash_offenses_collector.ts +123 -0
  76. package/src/slash_round_monitor.ts +62 -0
  77. package/src/slasher_client_facade.ts +103 -0
  78. package/src/slasher_client_interface.ts +46 -0
  79. package/src/stores/offenses_store.ts +147 -0
  80. package/src/stores/payloads_store.ts +149 -0
  81. package/src/stores/schema_version.ts +1 -0
  82. package/src/tally_slasher_client.ts +448 -0
  83. package/src/test/dummy_watcher.ts +21 -0
  84. package/src/watcher.ts +27 -0
  85. package/src/watchers/attestations_block_watcher.ts +194 -0
  86. package/src/watchers/epoch_prune_watcher.ts +253 -0
@@ -0,0 +1,77 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { createLogger } from '@aztec/foundation/log';
3
+ import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
4
+ import { EmpireSlasherClient } from '../empire_slasher_client.js';
5
+ import { NullSlasherClient } from '../null_slasher_client.js';
6
+ 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, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
11
+ const proposer = await rollup.getSlashingProposer();
12
+ if (!proposer) {
13
+ return new NullSlasherClient(config);
14
+ } else if (proposer.type === 'tally') {
15
+ return createTallySlasher(config, rollup, proposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger);
16
+ } 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, rollupRegisteredAtL2Slot, logger);
22
+ }
23
+ }
24
+ async function createEmpireSlasher(config, rollup, slashingProposer, slashFactoryContract, watchers, dateProvider, kvStore, rollupRegisteredAtL2Slot, 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
+ ]);
40
+ 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,
52
+ rollupRegisteredAtL2Slot
53
+ };
54
+ const payloadsStore = new SlasherPayloadsStore(kvStore, {
55
+ slashingPayloadLifetimeInRounds: settings.slashingPayloadLifetimeInRounds
56
+ });
57
+ const offensesStore = new SlasherOffensesStore(kvStore, {
58
+ ...settings,
59
+ slashOffenseExpirationRounds: config.slashOffenseExpirationRounds
60
+ });
61
+ return new EmpireSlasherClient(config, settings, slashFactoryContract, slashingProposer, slasher, rollup, watchers, dateProvider, offensesStore, payloadsStore, logger);
62
+ }
63
+ async function createTallySlasher(config, rollup, slashingProposer, watchers, dateProvider, epochCache, kvStore, rollupRegisteredAtL2Slot, logger = createLogger('slasher')) {
64
+ if (slashingProposer.type !== 'tally') {
65
+ throw new Error('Slashing proposer contract is not of type tally');
66
+ }
67
+ const settings = {
68
+ ...await getTallySlasherSettings(rollup, slashingProposer),
69
+ rollupRegisteredAtL2Slot
70
+ };
71
+ const slasher = await rollup.getSlasherContract();
72
+ const offensesStore = new SlasherOffensesStore(kvStore, {
73
+ ...settings,
74
+ slashOffenseExpirationRounds: config.slashOffenseExpirationRounds
75
+ });
76
+ return new TallySlasherClient(config, settings, slashingProposer, slasher, rollup, watchers, epochCache, dateProvider, offensesStore, logger);
77
+ }
@@ -0,0 +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<Omit<TallySlasherSettings, 'rollupRegisteredAtL2Slot'>>;
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0X3NldHRpbmdzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFjdG9yeS9nZXRfc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLDZCQUE2QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0YsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUV2RSx3QkFBc0IsdUJBQXVCLENBQzNDLE1BQU0sRUFBRSxjQUFjLEVBQ3RCLGdCQUFnQixDQUFDLEVBQUUsNkJBQTZCLEdBQy9DLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQWtEakUifQ==
@@ -0,0 +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,IAAI,CAAC,oBAAoB,EAAE,0BAA0B,CAAC,CAAC,CAkDjE"}
@@ -0,0 +1,36 @@
1
+ export async function getTallySlasherSettings(rollup, slashingProposer) {
2
+ if (!slashingProposer) {
3
+ const rollupSlashingProposer = await rollup.getSlashingProposer();
4
+ if (!rollupSlashingProposer || rollupSlashingProposer.type !== 'tally') {
5
+ throw new Error('Rollup slashing proposer is not of type tally');
6
+ }
7
+ slashingProposer = rollupSlashingProposer;
8
+ }
9
+ const [slashingExecutionDelayInRounds, slashingRoundSize, slashingRoundSizeInEpochs, slashingLifetimeInRounds, slashingOffsetInRounds, slashingAmounts, slashingQuorumSize, epochDuration, l1GenesisTime, slotDuration, targetCommitteeSize] = await Promise.all([
10
+ slashingProposer.getExecutionDelayInRounds(),
11
+ slashingProposer.getRoundSize(),
12
+ slashingProposer.getRoundSizeInEpochs(),
13
+ slashingProposer.getLifetimeInRounds(),
14
+ slashingProposer.getSlashOffsetInRounds(),
15
+ slashingProposer.getSlashingAmounts(),
16
+ slashingProposer.getQuorumSize(),
17
+ rollup.getEpochDuration(),
18
+ rollup.getL1GenesisTime(),
19
+ rollup.getSlotDuration(),
20
+ rollup.getTargetCommitteeSize()
21
+ ]);
22
+ const settings = {
23
+ slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
24
+ slashingRoundSize: Number(slashingRoundSize),
25
+ slashingRoundSizeInEpochs: Number(slashingRoundSizeInEpochs),
26
+ slashingLifetimeInRounds: Number(slashingLifetimeInRounds),
27
+ slashingQuorumSize: Number(slashingQuorumSize),
28
+ epochDuration: Number(epochDuration),
29
+ l1GenesisTime: l1GenesisTime,
30
+ slotDuration: Number(slotDuration),
31
+ slashingOffsetInRounds: Number(slashingOffsetInRounds),
32
+ slashingAmounts,
33
+ targetCommitteeSize: Number(targetCommitteeSize)
34
+ };
35
+ return settings;
36
+ }
@@ -0,0 +1,3 @@
1
+ export { createSlasherFacade as createSlasher } from './create_facade.js';
2
+ export { getTallySlasherSettings } from './get_settings.js';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mYWN0b3J5L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxtQkFBbUIsSUFBSSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQyJ9
@@ -0,0 +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"}
@@ -0,0 +1,2 @@
1
+ export { createSlasherFacade as createSlasher } from './create_facade.js';
2
+ export { getTallySlasherSettings } from './get_settings.js';
@@ -0,0 +1,21 @@
1
+ /** Default slasher configuration values from network-defaults.yml */
2
+ export declare const slasherDefaultEnv: {
3
+ readonly SLASH_MIN_PENALTY_PERCENTAGE: 0.5;
4
+ readonly SLASH_MAX_PENALTY_PERCENTAGE: 2;
5
+ readonly SLASH_OFFENSE_EXPIRATION_ROUNDS: 4;
6
+ readonly SLASH_MAX_PAYLOAD_SIZE: 80;
7
+ readonly SLASH_EXECUTE_ROUNDS_LOOK_BACK: 4;
8
+ readonly SLASH_PRUNE_PENALTY: 10000000000000000000;
9
+ readonly SLASH_DATA_WITHHOLDING_PENALTY: 10000000000000000000;
10
+ readonly SLASH_INACTIVITY_TARGET_PERCENTAGE: 0.9;
11
+ readonly SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD: 1;
12
+ readonly SLASH_INACTIVITY_PENALTY: 10000000000000000000;
13
+ readonly SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000;
14
+ readonly SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000;
15
+ readonly SLASH_DUPLICATE_PROPOSAL_PENALTY: 0;
16
+ readonly SLASH_DUPLICATE_ATTESTATION_PENALTY: 0;
17
+ readonly SLASH_UNKNOWN_PENALTY: 10000000000000000000;
18
+ readonly SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000;
19
+ readonly SLASH_GRACE_PERIOD_L2_SLOTS: 0;
20
+ };
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlci1kZWZhdWx0cy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dlbmVyYXRlZC9zbGFzaGVyLWRlZmF1bHRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLHFFQUFxRTtBQUNyRSxlQUFPLE1BQU0saUJBQWlCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FrQnBCLENBQUMifQ==
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,21 @@
1
+ // Auto-generated from spartan/environments/network-defaults.yml
2
+ // Do not edit manually - run yarn generate to regenerate
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
+ SLASH_OFFENSE_EXPIRATION_ROUNDS: 4,
7
+ SLASH_MAX_PAYLOAD_SIZE: 80,
8
+ SLASH_EXECUTE_ROUNDS_LOOK_BACK: 4,
9
+ SLASH_PRUNE_PENALTY: 10000000000000000000,
10
+ SLASH_DATA_WITHHOLDING_PENALTY: 10000000000000000000,
11
+ SLASH_INACTIVITY_TARGET_PERCENTAGE: 0.9,
12
+ SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD: 1,
13
+ SLASH_INACTIVITY_PENALTY: 10000000000000000000,
14
+ SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
15
+ SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000,
16
+ SLASH_DUPLICATE_PROPOSAL_PENALTY: 0,
17
+ SLASH_DUPLICATE_ATTESTATION_PENALTY: 0,
18
+ SLASH_UNKNOWN_PENALTY: 10000000000000000000,
19
+ SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
20
+ SLASH_GRACE_PERIOD_L2_SLOTS: 0
21
+ };
@@ -0,0 +1,11 @@
1
+ export * from './config.js';
2
+ export * from './watchers/epoch_prune_watcher.js';
3
+ export * from './watchers/attestations_block_watcher.js';
4
+ export * from './empire_slasher_client.js';
5
+ export * from './tally_slasher_client.js';
6
+ export * from './slash_offenses_collector.js';
7
+ export * from './slasher_client_interface.js';
8
+ export * from './factory/index.js';
9
+ export * from './watcher.js';
10
+ export * from '@aztec/stdlib/slashing';
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLG1DQUFtQyxDQUFDO0FBQ2xELGNBQWMsMENBQTBDLENBQUM7QUFDekQsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsK0JBQStCLENBQUM7QUFDOUMsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsd0JBQXdCLENBQUMifQ==
@@ -0,0 +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"}
package/dest/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from './config.js';
2
+ export * from './watchers/epoch_prune_watcher.js';
3
+ export * from './watchers/attestations_block_watcher.js';
4
+ export * from './empire_slasher_client.js';
5
+ export * from './tally_slasher_client.js';
6
+ export * from './slash_offenses_collector.js';
7
+ export * from './slasher_client_interface.js';
8
+ export * from './factory/index.js';
9
+ export * from './watcher.js';
10
+ export * from '@aztec/stdlib/slashing';
@@ -0,0 +1,17 @@
1
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import type { Offense, ProposerSlashAction, SlashPayloadRound } from '@aztec/stdlib/slashing';
3
+ import type { SlasherConfig } from './config.js';
4
+ import type { SlasherClientInterface } from './slasher_client_interface.js';
5
+ export declare class NullSlasherClient implements SlasherClientInterface {
6
+ private config;
7
+ constructor(config: SlasherConfig);
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ getSlashPayloads(): Promise<SlashPayloadRound[]>;
11
+ gatherOffensesForRound(_round?: bigint): Promise<Offense[]>;
12
+ getPendingOffenses(): Promise<Offense[]>;
13
+ updateConfig(config: Partial<SlasherConfig>): void;
14
+ getProposerActions(_slotNumber: SlotNumber): Promise<ProposerSlashAction[]>;
15
+ getConfig(): SlasherConfig;
16
+ }
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbF9zbGFzaGVyX2NsaWVudC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL251bGxfc2xhc2hlcl9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUYsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2pELE9BQU8sS0FBSyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFFNUUscUJBQWEsaUJBQWtCLFlBQVcsc0JBQXNCO0lBQ2xELE9BQU8sQ0FBQyxNQUFNO0lBQTFCLFlBQW9CLE1BQU0sRUFBRSxhQUFhLEVBQUk7SUFFdEMsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFNUI7SUFFTSxJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUUzQjtJQUVNLGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBRXREO0lBRU0sc0JBQXNCLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUVqRTtJQUVNLGtCQUFrQixJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUU5QztJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FFeEQ7SUFFTSxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsVUFBVSxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBRWpGO0lBRU0sU0FBUyxJQUFJLGFBQWEsQ0FFaEM7Q0FDRiJ9
@@ -0,0 +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"}
@@ -0,0 +1,33 @@
1
+ export class NullSlasherClient {
2
+ config;
3
+ constructor(config){
4
+ this.config = config;
5
+ }
6
+ start() {
7
+ return Promise.resolve();
8
+ }
9
+ stop() {
10
+ return Promise.resolve();
11
+ }
12
+ getSlashPayloads() {
13
+ return Promise.resolve([]);
14
+ }
15
+ gatherOffensesForRound(_round) {
16
+ return Promise.resolve([]);
17
+ }
18
+ getPendingOffenses() {
19
+ return Promise.resolve([]);
20
+ }
21
+ updateConfig(config) {
22
+ this.config = {
23
+ ...this.config,
24
+ ...config
25
+ };
26
+ }
27
+ getProposerActions(_slotNumber) {
28
+ return Promise.resolve([]);
29
+ }
30
+ getConfig() {
31
+ return this.config;
32
+ }
33
+ }
@@ -0,0 +1,48 @@
1
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import type { Prettify } from '@aztec/foundation/types';
3
+ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
4
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
5
+ import { type OffenseIdentifier } from '@aztec/stdlib/slashing';
6
+ import type { SlasherOffensesStore } from './stores/offenses_store.js';
7
+ import { type WantToSlashArgs, type Watcher } from './watcher.js';
8
+ export type SlashOffensesCollectorConfig = Prettify<Pick<SlasherConfig, 'slashGracePeriodL2Slots'>>;
9
+ export type SlashOffensesCollectorSettings = Prettify<Pick<L1RollupConstants, 'epochDuration'> & {
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;
13
+ }>;
14
+ /**
15
+ * Collects and manages slashable offenses from watchers.
16
+ * This class handles the common logic for subscribing to slash watcher events,
17
+ * storing offenses, and retrieving pending offenses for slashing.
18
+ */
19
+ export declare class SlashOffensesCollector {
20
+ private readonly config;
21
+ private readonly settings;
22
+ private readonly watchers;
23
+ private readonly offensesStore;
24
+ private readonly log;
25
+ private readonly unwatchCallbacks;
26
+ constructor(config: SlashOffensesCollectorConfig, settings: SlashOffensesCollectorSettings, watchers: Watcher[], offensesStore: SlasherOffensesStore, log?: import("@aztec/foundation/log").Logger);
27
+ start(): Promise<void>;
28
+ stop(): Promise<void>;
29
+ /**
30
+ * Called when a slash watcher emits WANT_TO_SLASH_EVENT.
31
+ * Stores pending offenses instead of creating payloads immediately.
32
+ * @param args - the arguments from the watcher, including the validators, amounts, and offenses
33
+ */
34
+ handleWantToSlash(args: WantToSlashArgs[]): Promise<void>;
35
+ /**
36
+ * Triggered on a time basis when we enter a new slashing round.
37
+ * Clears expired offenses from stores.
38
+ */
39
+ handleNewRound(round: bigint): Promise<void>;
40
+ /**
41
+ * Marks offenses as slashed (no longer pending)
42
+ * @param offenses - The offenses to mark as slashed
43
+ */
44
+ markAsSlashed(offenses: OffenseIdentifier[]): Promise<void>;
45
+ /** Returns whether to skip an offense if it happened during the grace period after the network upgrade */
46
+ private shouldSkipOffense;
47
+ }
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hfb2ZmZW5zZXNfY29sbGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWxFLE9BQU8sS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDckUsT0FBTyxFQUFnQixLQUFLLGlCQUFpQixFQUFxQixNQUFNLHdCQUF3QixDQUFDO0FBRWpHLE9BQU8sS0FBSyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdkUsT0FBTyxFQUF1QixLQUFLLGVBQWUsRUFBRSxLQUFLLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV2RixNQUFNLE1BQU0sNEJBQTRCLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDO0FBQ3BHLE1BQU0sTUFBTSw4QkFBOEIsR0FBRyxRQUFRLENBQ25ELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxlQUFlLENBQUMsR0FBRztJQUN6QyxlQUFlLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLFNBQVMsQ0FBQztJQUN0RCxzSEFBc0g7SUFDdEgsd0JBQXdCLEVBQUUsVUFBVSxDQUFDO0NBQ3RDLENBQ0YsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCxxQkFBYSxzQkFBc0I7SUFJL0IsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNO0lBQ3ZCLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUTtJQUN6QixPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVE7SUFDekIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhO0lBQzlCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQVB0QixPQUFPLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFzQjtJQUV2RCxZQUNtQixNQUFNLEVBQUUsNEJBQTRCLEVBQ3BDLFFBQVEsRUFBRSw4QkFBOEIsRUFDeEMsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUNuQixhQUFhLEVBQUUsb0JBQW9CLEVBQ25DLEdBQUcseUNBQTZDLEVBQy9EO0lBRUcsS0FBSyxrQkFhWDtJQUVNLElBQUksa0JBU1Y7SUFFRDs7OztPQUlHO0lBQ1UsaUJBQWlCLENBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRSxpQkE2QnJEO0lBRUQ7OztPQUdHO0lBQ1UsY0FBYyxDQUFDLEtBQUssRUFBRSxNQUFNLGlCQUt4QztJQUVEOzs7T0FHRztJQUNJLGFBQWEsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsaUJBR2pEO0lBRUQsMEdBQTBHO0lBQzFHLE9BQU8sQ0FBQyxpQkFBaUI7Q0FJMUIifQ==
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,94 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { getSlotForOffense } from '@aztec/stdlib/slashing';
3
+ import { WANT_TO_SLASH_EVENT } from './watcher.js';
4
+ /**
5
+ * Collects and manages slashable offenses from watchers.
6
+ * This class handles the common logic for subscribing to slash watcher events,
7
+ * storing offenses, and retrieving pending offenses for slashing.
8
+ */ export class SlashOffensesCollector {
9
+ config;
10
+ settings;
11
+ watchers;
12
+ offensesStore;
13
+ log;
14
+ unwatchCallbacks;
15
+ constructor(config, settings, watchers, offensesStore, log = createLogger('slasher:offenses-collector')){
16
+ this.config = config;
17
+ this.settings = settings;
18
+ this.watchers = watchers;
19
+ this.offensesStore = offensesStore;
20
+ this.log = log;
21
+ this.unwatchCallbacks = [];
22
+ }
23
+ start() {
24
+ this.log.debug('Starting SlashOffensesCollector...');
25
+ // Subscribe to watchers WANT_TO_SLASH_EVENT
26
+ for (const watcher of this.watchers){
27
+ const wantToSlashCallback = (args)=>void this.handleWantToSlash(args).catch((err)=>this.log.error('Error handling wantToSlash', err));
28
+ watcher.on(WANT_TO_SLASH_EVENT, wantToSlashCallback);
29
+ this.unwatchCallbacks.push(()=>watcher.removeListener(WANT_TO_SLASH_EVENT, wantToSlashCallback));
30
+ }
31
+ this.log.info('Started SlashOffensesCollector');
32
+ return Promise.resolve();
33
+ }
34
+ stop() {
35
+ this.log.debug('Stopping SlashOffensesCollector...');
36
+ for (const unwatchCallback of this.unwatchCallbacks){
37
+ unwatchCallback();
38
+ }
39
+ this.log.info('SlashOffensesCollector stopped');
40
+ return Promise.resolve();
41
+ }
42
+ /**
43
+ * Called when a slash watcher emits WANT_TO_SLASH_EVENT.
44
+ * Stores pending offenses instead of creating payloads immediately.
45
+ * @param args - the arguments from the watcher, including the validators, amounts, and offenses
46
+ */ async handleWantToSlash(args) {
47
+ for (const arg of args){
48
+ const pendingOffense = {
49
+ validator: arg.validator,
50
+ amount: arg.amount,
51
+ offenseType: arg.offenseType,
52
+ epochOrSlot: arg.epochOrSlot
53
+ };
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);
60
+ continue;
61
+ }
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}`);
66
+ }
67
+ }
68
+ this.log.info(`Adding pending offense for validator ${arg.validator}`, pendingOffense);
69
+ await this.offensesStore.addPendingOffense(pendingOffense);
70
+ }
71
+ }
72
+ /**
73
+ * Triggered on a time basis when we enter a new slashing round.
74
+ * Clears expired offenses from stores.
75
+ */ async handleNewRound(round) {
76
+ const cleared = await this.offensesStore.clearExpiredOffenses(round);
77
+ if (cleared && cleared > 0) {
78
+ this.log.debug(`Cleared ${cleared} expired offenses for round ${round}`);
79
+ }
80
+ }
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 after the network upgrade */ shouldSkipOffense(offense) {
91
+ const offenseSlot = getSlotForOffense(offense, this.settings);
92
+ return offenseSlot < this.settings.rollupRegisteredAtL2Slot + this.config.slashGracePeriodL2Slots;
93
+ }
94
+ }
@@ -0,0 +1,30 @@
1
+ import { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import type { DateProvider } from '@aztec/foundation/timer';
3
+ import type { Prettify } from '@aztec/foundation/types';
4
+ import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
5
+ export type SlashRoundMonitorSettings = Prettify<Pick<L1RollupConstants, 'epochDuration' | 'l1GenesisTime' | 'slotDuration'> & {
6
+ slashingRoundSize: number;
7
+ }>;
8
+ export declare class SlashRoundMonitor {
9
+ private settings;
10
+ private dateProvider;
11
+ private log;
12
+ private currentRound;
13
+ private intervalId;
14
+ private handler;
15
+ constructor(settings: SlashRoundMonitorSettings, dateProvider: DateProvider, log?: import("@aztec/foundation/log").Logger);
16
+ start(): void;
17
+ stop(): void;
18
+ listenToNewRound(handler: (round: bigint) => Promise<void>): () => void;
19
+ /** Returns the slashing round number and the voting slot within the round based on the L2 chain slot */
20
+ getRoundForSlot(slotNumber: SlotNumber): {
21
+ round: bigint;
22
+ votingSlot: SlotNumber;
23
+ };
24
+ /** Returns the current slashing round and voting slot within the round */
25
+ getCurrentRound(): {
26
+ round: bigint;
27
+ votingSlot: SlotNumber;
28
+ };
29
+ }
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hfcm91bmRfbW9uaXRvci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NsYXNoX3JvdW5kX21vbml0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRTdELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxLQUFLLGlCQUFpQixFQUFzQixNQUFNLDZCQUE2QixDQUFDO0FBR3pGLE1BQU0sTUFBTSx5QkFBeUIsR0FBRyxRQUFRLENBQzlDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxlQUFlLEdBQUcsZUFBZSxHQUFHLGNBQWMsQ0FBQyxHQUFHO0lBQUUsaUJBQWlCLEVBQUUsTUFBTSxDQUFBO0NBQUUsQ0FDNUcsQ0FBQztBQUVGLHFCQUFhLGlCQUFpQjtJQU0xQixPQUFPLENBQUMsUUFBUTtJQUNoQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsR0FBRztJQVBiLE9BQU8sQ0FBQyxZQUFZLENBQWM7SUFDbEMsT0FBTyxDQUFDLFVBQVUsQ0FBeUM7SUFDM0QsT0FBTyxDQUFDLE9BQU8sQ0FBNkQ7SUFFNUUsWUFDVSxRQUFRLEVBQUUseUJBQXlCLEVBQ25DLFlBQVksRUFBRSxZQUFZLEVBQzFCLEdBQUcseUNBQXdDLEVBQ2pEO0lBRUcsS0FBSyxTQVlYO0lBRU0sSUFBSSxTQUtWO0lBRU0sZ0JBQWdCLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLE1BQU0sS0FBSyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsTUFBTSxJQUFJLENBSzdFO0lBRUQsd0dBQXdHO0lBQ2pHLGVBQWUsQ0FBQyxVQUFVLEVBQUUsVUFBVSxHQUFHO1FBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQztRQUFDLFVBQVUsRUFBRSxVQUFVLENBQUE7S0FBRSxDQUV4RjtJQUVELDBFQUEwRTtJQUNuRSxlQUFlLElBQUk7UUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDO1FBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQTtLQUFFLENBSWxFO0NBQ0YifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slash_round_monitor.d.ts","sourceRoot":"","sources":["../src/slash_round_monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,KAAK,iBAAiB,EAAsB,MAAM,6BAA6B,CAAC;AAGzF,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAC9C,IAAI,CAAC,iBAAiB,EAAE,eAAe,GAAG,eAAe,GAAG,cAAc,CAAC,GAAG;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAC5G,CAAC;AAEF,qBAAa,iBAAiB;IAM1B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,GAAG;IAPb,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,UAAU,CAAyC;IAC3D,OAAO,CAAC,OAAO,CAA6D;IAE5E,YACU,QAAQ,EAAE,yBAAyB,EACnC,YAAY,EAAE,YAAY,EAC1B,GAAG,yCAAwC,EACjD;IAEG,KAAK,SAYX;IAEM,IAAI,SAKV;IAEM,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAK7E;IAED,wGAAwG;IACjG,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,CAExF;IAED,0EAA0E;IACnE,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,CAIlE;CACF"}
@@ -0,0 +1,52 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
3
+ import { getRoundForSlot } from '@aztec/stdlib/slashing';
4
+ export class SlashRoundMonitor {
5
+ settings;
6
+ dateProvider;
7
+ log;
8
+ currentRound;
9
+ intervalId;
10
+ handler;
11
+ constructor(settings, dateProvider, log = createLogger('slasher:round-monitor')){
12
+ this.settings = settings;
13
+ this.dateProvider = dateProvider;
14
+ this.log = log;
15
+ this.currentRound = 0n;
16
+ this.intervalId = undefined;
17
+ this.handler = undefined;
18
+ }
19
+ start() {
20
+ // Check for round changes
21
+ this.currentRound = this.getCurrentRound().round;
22
+ this.intervalId = setInterval(()=>{
23
+ const round = this.getCurrentRound().round;
24
+ if (round !== this.currentRound) {
25
+ this.currentRound = round;
26
+ if (this.handler) {
27
+ void this.handler(round).catch((err)=>this.log.error('Error handling new round', err));
28
+ }
29
+ }
30
+ }, 500);
31
+ }
32
+ stop() {
33
+ if (this.intervalId) {
34
+ clearInterval(this.intervalId);
35
+ this.intervalId = undefined;
36
+ }
37
+ }
38
+ listenToNewRound(handler) {
39
+ this.handler = handler;
40
+ return ()=>{
41
+ this.handler = undefined;
42
+ };
43
+ }
44
+ /** Returns the slashing round number and the voting slot within the round based on the L2 chain slot */ getRoundForSlot(slotNumber) {
45
+ return getRoundForSlot(slotNumber, this.settings);
46
+ }
47
+ /** Returns the current slashing round and voting slot within the round */ getCurrentRound() {
48
+ const now = this.dateProvider.nowInSeconds();
49
+ const currentSlot = getSlotAtTimestamp(BigInt(now), this.settings);
50
+ return this.getRoundForSlot(currentSlot);
51
+ }
52
+ }
@@ -0,0 +1,45 @@
1
+ import { EpochCache } from '@aztec/epoch-cache';
2
+ import { RollupContract } from '@aztec/ethereum/contracts';
3
+ import type { ViemClient } from '@aztec/ethereum/types';
4
+ import type { SlotNumber } from '@aztec/foundation/branded-types';
5
+ import { EthAddress } from '@aztec/foundation/eth-address';
6
+ import { DateProvider } from '@aztec/foundation/timer';
7
+ import { AztecLMDBStoreV2 } from '@aztec/kv-store/lmdb-v2';
8
+ import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
9
+ import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
10
+ import type { Offense, ProposerSlashAction, SlashPayloadRound } from '@aztec/stdlib/slashing';
11
+ import type { SlasherClientInterface } from './slasher_client_interface.js';
12
+ import type { Watcher } from './watcher.js';
13
+ /**
14
+ * Facade for the Slasher client. This class forwards all requests to the actual Slasher client implementation.
15
+ * This class also monitors via the rollup contract when the underlying slasher proposer contract changes, and when it
16
+ * does, it stops the current slasher client, recreates a new one with the new contract address, and starts it again.
17
+ */
18
+ export declare class SlasherClientFacade implements SlasherClientInterface {
19
+ private config;
20
+ private rollup;
21
+ private l1Client;
22
+ private slashFactoryAddress;
23
+ private watchers;
24
+ private epochCache;
25
+ private dateProvider;
26
+ private kvStore;
27
+ private rollupRegisteredAtL2Slot;
28
+ private logger;
29
+ private client;
30
+ private unwatch;
31
+ constructor(config: SlasherConfig & DataStoreConfig & {
32
+ ethereumSlotDuration: number;
33
+ }, rollup: RollupContract, l1Client: ViemClient, slashFactoryAddress: EthAddress | undefined, watchers: Watcher[], epochCache: EpochCache, dateProvider: DateProvider, kvStore: AztecLMDBStoreV2, rollupRegisteredAtL2Slot: SlotNumber, logger?: import("@aztec/foundation/log").Logger);
34
+ start(): Promise<void>;
35
+ stop(): Promise<void>;
36
+ getConfig(): SlasherConfig;
37
+ updateConfig(config: Partial<SlasherConfig>): void;
38
+ getSlashPayloads(): Promise<SlashPayloadRound[]>;
39
+ gatherOffensesForRound(round?: bigint): Promise<Offense[]>;
40
+ getPendingOffenses(): Promise<Offense[]>;
41
+ getProposerActions(slotNumber: SlotNumber): Promise<ProposerSlashAction[]>;
42
+ private createSlasherClient;
43
+ private handleSlasherChange;
44
+ }
45
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlcl9jbGllbnRfZmFjYWRlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hlcl9jbGllbnRfZmFjYWRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTNELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNyRSxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEtBQUssRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUc5RixPQUFPLEtBQUssRUFBRSxzQkFBc0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzVFLE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU1Qzs7OztHQUlHO0FBQ0gscUJBQWEsbUJBQW9CLFlBQVcsc0JBQXNCO0lBSzlELE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsUUFBUTtJQUNoQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxRQUFRO0lBQ2hCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxPQUFPO0lBQ2YsT0FBTyxDQUFDLHdCQUF3QjtJQUNoQyxPQUFPLENBQUMsTUFBTTtJQWJoQixPQUFPLENBQUMsTUFBTSxDQUFxQztJQUNuRCxPQUFPLENBQUMsT0FBTyxDQUEyQjtJQUUxQyxZQUNVLE1BQU0sRUFBRSxhQUFhLEdBQUcsZUFBZSxHQUFHO1FBQUUsb0JBQW9CLEVBQUUsTUFBTSxDQUFBO0tBQUUsRUFDMUUsTUFBTSxFQUFFLGNBQWMsRUFDdEIsUUFBUSxFQUFFLFVBQVUsRUFDcEIsbUJBQW1CLEVBQUUsVUFBVSxHQUFHLFNBQVMsRUFDM0MsUUFBUSxFQUFFLE9BQU8sRUFBRSxFQUNuQixVQUFVLEVBQUUsVUFBVSxFQUN0QixZQUFZLEVBQUUsWUFBWSxFQUMxQixPQUFPLEVBQUUsZ0JBQWdCLEVBQ3pCLHdCQUF3QixFQUFFLFVBQVUsRUFDcEMsTUFBTSx5Q0FBMEIsRUFDdEM7SUFFUyxLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQVNsQztJQUVZLElBQUksSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWpDO0lBRU0sU0FBUyxJQUFJLGFBQWEsQ0FFaEM7SUFFTSxZQUFZLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxJQUFJLENBSXhEO0lBRU0sZ0JBQWdCLElBQUksT0FBTyxDQUFDLGlCQUFpQixFQUFFLENBQUMsQ0FFdEQ7SUFFTSxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRWhFO0lBRU0sa0JBQWtCLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRTlDO0lBRU0sa0JBQWtCLENBQUMsVUFBVSxFQUFFLFVBQVUsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUVoRjtJQUVELE9BQU8sQ0FBQyxtQkFBbUI7WUFlYixtQkFBbUI7Q0FNbEMifQ==
@@ -0,0 +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,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,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"}