@aztec/slasher 4.0.0-nightly.20260112 → 4.0.0-nightly.20260114

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/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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRbkUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFckUsWUFBWSxFQUFFLGFBQWEsRUFBRSxDQUFDO0FBRTlCLGVBQU8sTUFBTSxvQkFBb0IsRUFBRSxhQW9CbEMsQ0FBQztBQUVGLGVBQU8sTUFBTSxxQkFBcUIsRUFBRSxrQkFBa0IsQ0FBQyxhQUFhLENBeUhuRSxDQUFDIn0=
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRbkUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFJckUsWUFBWSxFQUFFLGFBQWEsRUFBRSxDQUFDO0FBRTlCLGVBQU8sTUFBTSxvQkFBb0IsRUFBRSxhQW9CbEMsQ0FBQztBQUVGLGVBQU8sTUFBTSxxQkFBcUIsRUFBRSxrQkFBa0IsQ0FBQyxhQUFhLENBeUhuRSxDQUFDIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAQnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAErE,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,aAoBlC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,CAAC,aAAa,CAyHnE,CAAC"}
package/dest/config.js CHANGED
@@ -1,25 +1,25 @@
1
- import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
2
1
  import { bigintConfigHelper, booleanConfigHelper, floatConfigHelper, numberConfigHelper } from '@aztec/foundation/config';
3
2
  import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { slasherDefaultEnv } from './generated/slasher-defaults.js';
4
4
  export const DefaultSlasherConfig = {
5
5
  slashOverridePayload: undefined,
6
- slashMinPenaltyPercentage: 0.5,
7
- slashMaxPenaltyPercentage: 2.0,
6
+ slashMinPenaltyPercentage: slasherDefaultEnv.SLASH_MIN_PENALTY_PERCENTAGE,
7
+ slashMaxPenaltyPercentage: slasherDefaultEnv.SLASH_MAX_PENALTY_PERCENTAGE,
8
8
  slashValidatorsAlways: [],
9
9
  slashValidatorsNever: [],
10
- slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
11
- slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
12
- slashInactivityTargetPercentage: 0.9,
13
- slashInactivityConsecutiveEpochThreshold: 1,
14
- slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountSmall,
15
- slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
16
- slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountSmall,
17
- slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountSmall,
18
- slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
19
- slashOffenseExpirationRounds: 4,
20
- slashMaxPayloadSize: 50,
21
- slashGracePeriodL2Slots: 0,
22
- slashExecuteRoundsLookBack: 4,
10
+ slashPrunePenalty: BigInt(slasherDefaultEnv.SLASH_PRUNE_PENALTY),
11
+ slashDataWithholdingPenalty: BigInt(slasherDefaultEnv.SLASH_DATA_WITHHOLDING_PENALTY),
12
+ slashInactivityTargetPercentage: slasherDefaultEnv.SLASH_INACTIVITY_TARGET_PERCENTAGE,
13
+ slashInactivityConsecutiveEpochThreshold: slasherDefaultEnv.SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD,
14
+ slashBroadcastedInvalidBlockPenalty: BigInt(slasherDefaultEnv.SLASH_INVALID_BLOCK_PENALTY),
15
+ slashInactivityPenalty: BigInt(slasherDefaultEnv.SLASH_INACTIVITY_PENALTY),
16
+ slashProposeInvalidAttestationsPenalty: BigInt(slasherDefaultEnv.SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY),
17
+ slashAttestDescendantOfInvalidPenalty: BigInt(slasherDefaultEnv.SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY),
18
+ slashUnknownPenalty: BigInt(slasherDefaultEnv.SLASH_UNKNOWN_PENALTY),
19
+ slashOffenseExpirationRounds: slasherDefaultEnv.SLASH_OFFENSE_EXPIRATION_ROUNDS,
20
+ slashMaxPayloadSize: slasherDefaultEnv.SLASH_MAX_PAYLOAD_SIZE,
21
+ slashGracePeriodL2Slots: slasherDefaultEnv.SLASH_GRACE_PERIOD_L2_SLOTS,
22
+ slashExecuteRoundsLookBack: slasherDefaultEnv.SLASH_EXECUTE_ROUNDS_LOOK_BACK,
23
23
  slashSelfAllowed: false
24
24
  };
25
25
  export const slasherConfigMappings = {
@@ -0,0 +1,19 @@
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: 50;
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_UNKNOWN_PENALTY: 10000000000000000000;
16
+ readonly SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000;
17
+ readonly SLASH_GRACE_PERIOD_L2_SLOTS: 0;
18
+ };
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hlci1kZWZhdWx0cy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dlbmVyYXRlZC9zbGFzaGVyLWRlZmF1bHRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLHFFQUFxRTtBQUNyRSxlQUFPLE1BQU0saUJBQWlCOzs7Ozs7Ozs7Ozs7Ozs7O0NBZ0JwQixDQUFDIn0=
@@ -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;;;;;;;;;;;;;;;;CAgBpB,CAAC"}
@@ -0,0 +1,19 @@
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: 50,
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_UNKNOWN_PENALTY: 10000000000000000000,
17
+ SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
18
+ SLASH_GRACE_PERIOD_L2_SLOTS: 0
19
+ };
@@ -15,19 +15,19 @@ export declare class AttestationsBlockWatcher extends AttestationsBlockWatcher_b
15
15
  private l2BlockSource;
16
16
  private epochCache;
17
17
  private log;
18
- private maxInvalidBlocks;
18
+ private maxInvalidCheckpoints;
19
19
  private invalidArchiveRoots;
20
20
  private config;
21
- private boundHandleInvalidBlock;
21
+ private boundHandleInvalidCheckpoint;
22
22
  constructor(l2BlockSource: L2BlockSourceEventEmitter, epochCache: EpochCache, config: AttestationsBlockWatcherConfig);
23
23
  updateConfig(newConfig: Partial<AttestationsBlockWatcherConfig>): void;
24
24
  start(): Promise<void>;
25
25
  stop(): Promise<void>;
26
- private handleInvalidBlock;
26
+ private handleInvalidCheckpoint;
27
27
  private slashAttestorsOnAncestorInvalid;
28
28
  private slashProposer;
29
29
  private getOffenseFromInvalidationReason;
30
- private addInvalidBlock;
30
+ private addInvalidCheckpoint;
31
31
  }
32
32
  export {};
33
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0ZXN0YXRpb25zX2Jsb2NrX3dhdGNoZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93YXRjaGVycy9hdHRlc3RhdGlvbnNfYmxvY2tfd2F0Y2hlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFJaEQsT0FBTyxFQUdMLEtBQUsseUJBQXlCLEVBRy9CLE1BQU0scUJBQXFCLENBQUM7QUFLN0IsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBNkMsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFN0csUUFBQSxNQUFNLGtDQUFrQyw4RkFHOUIsQ0FBQztBQUVYLEtBQUssOEJBQThCLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLE9BQU8sa0NBQWtDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDOztBQUUvRzs7Ozs7R0FLRztBQUNILHFCQUFhLHdCQUF5QixTQUFRLDZCQUEyQyxZQUFXLE9BQU87SUF1QnZHLE9BQU8sQ0FBQyxhQUFhO0lBQ3JCLE9BQU8sQ0FBQyxVQUFVO0lBdkJwQixPQUFPLENBQUMsR0FBRyxDQUFzRDtJQUdqRSxPQUFPLENBQUMsZ0JBQWdCLENBQU87SUFHL0IsT0FBTyxDQUFDLG1CQUFtQixDQUEwQjtJQUVyRCxPQUFPLENBQUMsTUFBTSxDQUFpQztJQUUvQyxPQUFPLENBQUMsdUJBQXVCLENBUzdCO0lBRUYsWUFDVSxhQUFhLEVBQUUseUJBQXlCLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQzlCLE1BQU0sRUFBRSw4QkFBOEIsRUFLdkM7SUFFTSxZQUFZLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyw4QkFBOEIsQ0FBQyxRQUdyRTtJQUVNLEtBQUssa0JBR1g7SUFFTSxJQUFJLGtCQU1WO0lBRUQsT0FBTyxDQUFDLGtCQUFrQjtJQXlCMUIsT0FBTyxDQUFDLCtCQUErQjtJQXdCdkMsT0FBTyxDQUFDLGFBQWE7SUFpQ3JCLE9BQU8sQ0FBQyxnQ0FBZ0M7SUFheEMsT0FBTyxDQUFDLGVBQWU7Q0FTeEIifQ==
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0ZXN0YXRpb25zX2Jsb2NrX3dhdGNoZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93YXRjaGVycy9hdHRlc3RhdGlvbnNfYmxvY2tfd2F0Y2hlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFJaEQsT0FBTyxFQUVMLEtBQUsseUJBQXlCLEVBRy9CLE1BQU0scUJBQXFCLENBQUM7QUFNN0IsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBNkMsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFN0csUUFBQSxNQUFNLGtDQUFrQyw4RkFHOUIsQ0FBQztBQUVYLEtBQUssOEJBQThCLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDLE9BQU8sa0NBQWtDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDOztBQUUvRzs7Ozs7R0FLRztBQUNILHFCQUFhLHdCQUF5QixTQUFRLDZCQUEyQyxZQUFXLE9BQU87SUF1QnZHLE9BQU8sQ0FBQyxhQUFhO0lBQ3JCLE9BQU8sQ0FBQyxVQUFVO0lBdkJwQixPQUFPLENBQUMsR0FBRyxDQUFzRDtJQUdqRSxPQUFPLENBQUMscUJBQXFCLENBQU87SUFHcEMsT0FBTyxDQUFDLG1CQUFtQixDQUEwQjtJQUVyRCxPQUFPLENBQUMsTUFBTSxDQUFpQztJQUUvQyxPQUFPLENBQUMsNEJBQTRCLENBU2xDO0lBRUYsWUFDVSxhQUFhLEVBQUUseUJBQXlCLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQzlCLE1BQU0sRUFBRSw4QkFBOEIsRUFLdkM7SUFFTSxZQUFZLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyw4QkFBOEIsQ0FBQyxRQUdyRTtJQUVNLEtBQUssa0JBTVg7SUFFTSxJQUFJLGtCQU1WO0lBRUQsT0FBTyxDQUFDLHVCQUF1QjtJQXlCL0IsT0FBTyxDQUFDLCtCQUErQjtJQTJCdkMsT0FBTyxDQUFDLGFBQWE7SUFpQ3JCLE9BQU8sQ0FBQyxnQ0FBZ0M7SUFheEMsT0FBTyxDQUFDLG9CQUFvQjtDQVM3QiJ9
@@ -1 +1 @@
1
- {"version":3,"file":"attestations_block_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/attestations_block_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,OAAO,EAGL,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAK7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,kCAAkC,8FAG9B,CAAC;AAEX,KAAK,8BAA8B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,kCAAkC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE/G;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,6BAA2C,YAAW,OAAO;IAuBvG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,UAAU;IAvBpB,OAAO,CAAC,GAAG,CAAsD;IAGjE,OAAO,CAAC,gBAAgB,CAAO;IAG/B,OAAO,CAAC,mBAAmB,CAA0B;IAErD,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,uBAAuB,CAS7B;IAEF,YACU,aAAa,EAAE,yBAAyB,EACxC,UAAU,EAAE,UAAU,EAC9B,MAAM,EAAE,8BAA8B,EAKvC;IAEM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,8BAA8B,CAAC,QAGrE;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAMV;IAED,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,+BAA+B;IAwBvC,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,gCAAgC;IAaxC,OAAO,CAAC,eAAe;CASxB"}
1
+ {"version":3,"file":"attestations_block_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/attestations_block_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAC;AAM7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,kCAAkC,8FAG9B,CAAC;AAEX,KAAK,8BAA8B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,kCAAkC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE/G;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,6BAA2C,YAAW,OAAO;IAuBvG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,UAAU;IAvBpB,OAAO,CAAC,GAAG,CAAsD;IAGjE,OAAO,CAAC,qBAAqB,CAAO;IAGpC,OAAO,CAAC,mBAAmB,CAA0B;IAErD,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,4BAA4B,CASlC;IAEF,YACU,aAAa,EAAE,yBAAyB,EACxC,UAAU,EAAE,UAAU,EAC9B,MAAM,EAAE,8BAA8B,EAKvC;IAEM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,8BAA8B,CAAC,QAGrE;IAEM,KAAK,kBAMX;IAEM,IAAI,kBAMV;IAED,OAAO,CAAC,uBAAuB;IAyB/B,OAAO,CAAC,+BAA+B;IA2BvC,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,gCAAgC;IAaxC,OAAO,CAAC,oBAAoB;CAS7B"}
@@ -18,18 +18,18 @@ const AttestationsBlockWatcherConfigKeys = [
18
18
  l2BlockSource;
19
19
  epochCache;
20
20
  log;
21
- // Only keep track of the last N invalid blocks
22
- maxInvalidBlocks;
21
+ // Only keep track of the last N invalid checkpoints
22
+ maxInvalidCheckpoints;
23
23
  // All invalid archive roots seen
24
24
  invalidArchiveRoots;
25
25
  config;
26
- boundHandleInvalidBlock;
26
+ boundHandleInvalidCheckpoint;
27
27
  constructor(l2BlockSource, epochCache, config){
28
- super(), this.l2BlockSource = l2BlockSource, this.epochCache = epochCache, this.log = createLogger('attestations-block-watcher'), this.maxInvalidBlocks = 100, this.invalidArchiveRoots = new Set(), this.boundHandleInvalidBlock = (event)=>{
28
+ super(), this.l2BlockSource = l2BlockSource, this.epochCache = epochCache, this.log = createLogger('attestations-block-watcher'), this.maxInvalidCheckpoints = 100, this.invalidArchiveRoots = new Set(), this.boundHandleInvalidCheckpoint = (event)=>{
29
29
  try {
30
- this.handleInvalidBlock(event);
30
+ this.handleInvalidCheckpoint(event);
31
31
  } catch (err) {
32
- this.log.error('Error handling invalid block', err, {
32
+ this.log.error('Error handling invalid checkpoint', err, {
33
33
  ...event.validationResult,
34
34
  reason: event.validationResult.reason
35
35
  });
@@ -43,39 +43,39 @@ const AttestationsBlockWatcherConfigKeys = [
43
43
  this.log.verbose('AttestationsBlockWatcher config updated', this.config);
44
44
  }
45
45
  start() {
46
- this.l2BlockSource.on(L2BlockSourceEvents.InvalidAttestationsBlockDetected, this.boundHandleInvalidBlock);
46
+ this.l2BlockSource.events.on(L2BlockSourceEvents.InvalidAttestationsCheckpointDetected, this.boundHandleInvalidCheckpoint);
47
47
  return Promise.resolve();
48
48
  }
49
49
  stop() {
50
- this.l2BlockSource.removeListener(L2BlockSourceEvents.InvalidAttestationsBlockDetected, this.boundHandleInvalidBlock);
50
+ this.l2BlockSource.events.removeListener(L2BlockSourceEvents.InvalidAttestationsCheckpointDetected, this.boundHandleInvalidCheckpoint);
51
51
  return Promise.resolve();
52
52
  }
53
- handleInvalidBlock(event) {
53
+ handleInvalidCheckpoint(event) {
54
54
  const { validationResult } = event;
55
- const block = validationResult.block;
56
- // Check if we already have processed this block, archiver may emit the same event multiple times
57
- if (this.invalidArchiveRoots.has(block.archive.toString())) {
58
- this.log.trace(`Already processed invalid block ${block.blockNumber}`);
55
+ const checkpoint = validationResult.checkpoint;
56
+ // Check if we already have processed this checkpoint, archiver may emit the same event multiple times
57
+ if (this.invalidArchiveRoots.has(checkpoint.archive.toString())) {
58
+ this.log.trace(`Already processed invalid checkpoint ${checkpoint.checkpointNumber}`);
59
59
  return;
60
60
  }
61
- this.log.verbose(`Detected invalid block ${block.blockNumber}`, {
62
- ...block,
61
+ this.log.verbose(`Detected invalid checkpoint ${checkpoint.checkpointNumber}`, {
62
+ ...checkpoint,
63
63
  reason: validationResult.valid === false ? validationResult.reason : 'unknown'
64
64
  });
65
- // Store the invalid block
66
- this.addInvalidBlock(event.validationResult.block);
67
- // Slash the proposer of the invalid block
65
+ // Store the invalid checkpoint
66
+ this.addInvalidCheckpoint(event.validationResult.checkpoint);
67
+ // Slash the proposer of the invalid checkpoint
68
68
  this.slashProposer(event.validationResult);
69
- // Check if the parent of this block is invalid as well, if so, we will slash its attestors as well
69
+ // Check if the parent of this checkpoint is invalid as well, if so, we will slash its attestors as well
70
70
  this.slashAttestorsOnAncestorInvalid(event.validationResult);
71
71
  }
72
72
  slashAttestorsOnAncestorInvalid(validationResult) {
73
- const block = validationResult.block;
74
- const parentArchive = block.lastArchive.toString();
73
+ const checkpoint = validationResult.checkpoint;
74
+ const parentArchive = checkpoint.lastArchive.toString();
75
75
  if (this.invalidArchiveRoots.has(parentArchive)) {
76
76
  const attestors = validationResult.attestors;
77
- this.log.info(`Want to slash attestors of block ${block.blockNumber} built on invalid block`, {
78
- ...block,
77
+ this.log.info(`Want to slash attestors of checkpoint ${checkpoint.checkpointNumber} built on invalid checkpoint`, {
78
+ ...checkpoint,
79
79
  ...attestors,
80
80
  parentArchive
81
81
  });
@@ -83,14 +83,14 @@ const AttestationsBlockWatcherConfigKeys = [
83
83
  validator: attestor,
84
84
  amount: this.config.slashAttestDescendantOfInvalidPenalty,
85
85
  offenseType: OffenseType.ATTESTED_DESCENDANT_OF_INVALID,
86
- epochOrSlot: BigInt(SlotNumber(block.slotNumber))
86
+ epochOrSlot: BigInt(SlotNumber(checkpoint.slotNumber))
87
87
  })));
88
88
  }
89
89
  }
90
90
  slashProposer(validationResult) {
91
- const { reason, block } = validationResult;
92
- const blockNumber = block.blockNumber;
93
- const slot = block.slotNumber;
91
+ const { reason, checkpoint } = validationResult;
92
+ const checkpointNumber = checkpoint.checkpointNumber;
93
+ const slot = checkpoint.slotNumber;
94
94
  const epochCommitteeInfo = {
95
95
  committee: validationResult.committee,
96
96
  seed: validationResult.seed,
@@ -98,7 +98,7 @@ const AttestationsBlockWatcherConfigKeys = [
98
98
  };
99
99
  const proposer = this.epochCache.getProposerFromEpochCommittee(epochCommitteeInfo, slot);
100
100
  if (!proposer) {
101
- this.log.warn(`No proposer found for block ${blockNumber} at slot ${slot}`);
101
+ this.log.warn(`No proposer found for checkpoint ${checkpointNumber} at slot ${slot}`);
102
102
  return;
103
103
  }
104
104
  const offense = this.getOffenseFromInvalidationReason(reason);
@@ -109,8 +109,8 @@ const AttestationsBlockWatcherConfigKeys = [
109
109
  offenseType: offense,
110
110
  epochOrSlot: BigInt(slot)
111
111
  };
112
- this.log.info(`Want to slash proposer of block ${blockNumber} due to ${reason}`, {
113
- ...block,
112
+ this.log.info(`Want to slash proposer of checkpoint ${checkpointNumber} due to ${reason}`, {
113
+ ...checkpoint,
114
114
  ...args
115
115
  });
116
116
  this.emit(WANT_TO_SLASH_EVENT, [
@@ -130,10 +130,10 @@ const AttestationsBlockWatcherConfigKeys = [
130
130
  }
131
131
  }
132
132
  }
133
- addInvalidBlock(block) {
134
- this.invalidArchiveRoots.add(block.archive.toString());
133
+ addInvalidCheckpoint(checkpoint) {
134
+ this.invalidArchiveRoots.add(checkpoint.archive.toString());
135
135
  // Prune old entries if we exceed the maximum
136
- if (this.invalidArchiveRoots.size > this.maxInvalidBlocks) {
136
+ if (this.invalidArchiveRoots.size > this.maxInvalidCheckpoints) {
137
137
  const oldestKey = this.invalidArchiveRoots.keys().next().value;
138
138
  this.invalidArchiveRoots.delete(oldestKey);
139
139
  }
@@ -1,7 +1,8 @@
1
1
  import { EpochCache } from '@aztec/epoch-cache';
2
- import { L2Block, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
2
+ import type { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { L2BlockNew, type L2BlockSourceEventEmitter } from '@aztec/stdlib/block';
3
4
  import type { IFullNodeBlockBuilder, ITxProvider, MerkleTreeWriteOperations, SlasherConfig } from '@aztec/stdlib/interfaces/server';
4
- import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
5
+ import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
5
6
  import { type Watcher, type WatcherEmitter } from '../watcher.js';
6
7
  declare const EpochPruneWatcherPenaltiesConfigKeys: readonly ["slashPrunePenalty", "slashDataWithholdingPenalty"];
7
8
  type EpochPruneWatcherPenalties = Pick<SlasherConfig, (typeof EpochPruneWatcherPenaltiesConfigKeys)[number]>;
@@ -28,10 +29,10 @@ export declare class EpochPruneWatcher extends EpochPruneWatcher_base implements
28
29
  private handlePruneL2Blocks;
29
30
  private emitSlashForEpoch;
30
31
  private processPruneL2Blocks;
31
- validateBlocks(blocks: L2Block[]): Promise<void>;
32
- validateBlock(blockFromL1: L2Block, fork: MerkleTreeWriteOperations): Promise<void>;
32
+ validateBlocks(blocks: L2BlockNew[]): Promise<void>;
33
+ validateBlock(blockFromL1: L2BlockNew, previousCheckpointOutHashes: Fr[], fork: MerkleTreeWriteOperations): Promise<void>;
33
34
  private getValidatorsForEpoch;
34
35
  private validatorsToSlashingArgs;
35
36
  }
36
37
  export {};
37
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSWhELE9BQU8sRUFFTCxPQUFPLEVBRVAsS0FBSyx5QkFBeUIsRUFFL0IsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEtBQUssRUFDVixxQkFBcUIsRUFDckIsV0FBVyxFQUNYLHlCQUF5QixFQUN6QixhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBV25FLE9BQU8sRUFBNkMsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFN0csUUFBQSxNQUFNLG9DQUFvQywrREFBZ0UsQ0FBQztBQUUzRyxLQUFLLDBCQUEwQixHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxPQUFPLG9DQUFvQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQzs7QUFFN0c7Ozs7O0dBS0c7QUFDSCxxQkFBYSxpQkFBa0IsU0FBUSxzQkFBMkMsWUFBVyxPQUFPO0lBU2hHLE9BQU8sQ0FBQyxhQUFhO0lBQ3JCLE9BQU8sQ0FBQyxtQkFBbUI7SUFDM0IsT0FBTyxDQUFDLFVBQVU7SUFDbEIsT0FBTyxDQUFDLFVBQVU7SUFDbEIsT0FBTyxDQUFDLFlBQVk7SUFadEIsT0FBTyxDQUFDLEdBQUcsQ0FBK0M7SUFHMUQsT0FBTyxDQUFDLHdCQUF3QixDQUF1QztJQUV2RSxPQUFPLENBQUMsU0FBUyxDQUE2QjtJQUU5QyxZQUNVLGFBQWEsRUFBRSx5QkFBeUIsRUFDeEMsbUJBQW1CLEVBQUUsbUJBQW1CLEVBQ3hDLFVBQVUsRUFBRSxVQUFVLEVBQ3RCLFVBQVUsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLGlCQUFpQixDQUFDLEVBQ2hELFlBQVksRUFBRSxxQkFBcUIsRUFDM0MsU0FBUyxFQUFFLDBCQUEwQixFQU90QztJQUVNLEtBQUssa0JBR1g7SUFFTSxJQUFJLGtCQUdWO0lBRU0sWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUd4RDtJQUVELE9BQU8sQ0FBQyxtQkFBbUI7WUFPYixpQkFBaUI7WUFXakIsb0JBQW9CO0lBd0JyQixjQUFjLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FZNUQ7SUFFWSxhQUFhLENBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUseUJBQXlCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQStCL0Y7WUFFYSxxQkFBcUI7SUFTbkMsT0FBTyxDQUFDLHdCQUF3QjtDQWdCakMifQ==
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBvY2hfcHJ1bmVfd2F0Y2hlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhdGNoZXJzL2Vwb2NoX3BydW5lX3dhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBR2hELE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXpELE9BQU8sRUFFTCxVQUFVLEVBRVYsS0FBSyx5QkFBeUIsRUFFL0IsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QixPQUFPLEtBQUssRUFDVixxQkFBcUIsRUFDckIsV0FBVyxFQUNYLHlCQUF5QixFQUN6QixhQUFhLEVBQ2QsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxtQkFBbUIsRUFBNEIsTUFBTSx5QkFBeUIsQ0FBQztBQVc3RixPQUFPLEVBQTZDLEtBQUssT0FBTyxFQUFFLEtBQUssY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdHLFFBQUEsTUFBTSxvQ0FBb0MsK0RBQWdFLENBQUM7QUFFM0csS0FBSywwQkFBMEIsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUMsT0FBTyxvQ0FBb0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7O0FBRTdHOzs7OztHQUtHO0FBQ0gscUJBQWEsaUJBQWtCLFNBQVEsc0JBQTJDLFlBQVcsT0FBTztJQVNoRyxPQUFPLENBQUMsYUFBYTtJQUNyQixPQUFPLENBQUMsbUJBQW1CO0lBQzNCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxVQUFVO0lBQ2xCLE9BQU8sQ0FBQyxZQUFZO0lBWnRCLE9BQU8sQ0FBQyxHQUFHLENBQStDO0lBRzFELE9BQU8sQ0FBQyx3QkFBd0IsQ0FBdUM7SUFFdkUsT0FBTyxDQUFDLFNBQVMsQ0FBNkI7SUFFOUMsWUFDVSxhQUFhLEVBQUUseUJBQXlCLEVBQ3hDLG1CQUFtQixFQUFFLG1CQUFtQixFQUN4QyxVQUFVLEVBQUUsVUFBVSxFQUN0QixVQUFVLEVBQUUsSUFBSSxDQUFDLFdBQVcsRUFBRSxpQkFBaUIsQ0FBQyxFQUNoRCxZQUFZLEVBQUUscUJBQXFCLEVBQzNDLFNBQVMsRUFBRSwwQkFBMEIsRUFPdEM7SUFFTSxLQUFLLGtCQUdYO0lBRU0sSUFBSSxrQkFHVjtJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FHeEQ7SUFFRCxPQUFPLENBQUMsbUJBQW1CO1lBT2IsaUJBQWlCO1lBV2pCLG9CQUFvQjtJQXdCckIsY0FBYyxDQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBa0IvRDtJQUVZLGFBQWEsQ0FDeEIsV0FBVyxFQUFFLFVBQVUsRUFDdkIsMkJBQTJCLEVBQUUsRUFBRSxFQUFFLEVBQ2pDLElBQUksRUFBRSx5QkFBeUIsR0FDOUIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWdDZjtZQUVhLHFCQUFxQjtJQVNuQyxPQUFPLENBQUMsd0JBQXdCO0NBZ0JqQyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,OAAO,EAEL,OAAO,EAEP,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,qBAAqB,EACrB,WAAW,EACX,yBAAyB,EACzB,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAWnE,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,oCAAoC,+DAAgE,CAAC;AAE3G,KAAK,0BAA0B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE7G;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IAZtB,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,wBAAwB,CAAuC;IAEvE,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACU,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,YAAY,EAAE,qBAAqB,EAC3C,SAAS,EAAE,0BAA0B,EAOtC;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAGV;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAGxD;IAED,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAWjB,oBAAoB;IAwBrB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5D;IAEY,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F;YAEa,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
1
+ {"version":3,"file":"epoch_prune_watcher.d.ts","sourceRoot":"","sources":["../../src/watchers/epoch_prune_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEzD,OAAO,EAEL,UAAU,EAEV,KAAK,yBAAyB,EAE/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,qBAAqB,EACrB,WAAW,EACX,yBAAyB,EACzB,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,yBAAyB,CAAC;AAW7F,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE7G,QAAA,MAAM,oCAAoC,+DAAgE,CAAC;AAE3G,KAAK,0BAA0B,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,OAAO,oCAAoC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;;AAE7G;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,sBAA2C,YAAW,OAAO;IAShG,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IAZtB,OAAO,CAAC,GAAG,CAA+C;IAG1D,OAAO,CAAC,wBAAwB,CAAuC;IAEvE,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACU,aAAa,EAAE,yBAAyB,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAChD,YAAY,EAAE,qBAAqB,EAC3C,SAAS,EAAE,0BAA0B,EAOtC;IAEM,KAAK,kBAGX;IAEM,IAAI,kBAGV;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAGxD;IAED,OAAO,CAAC,mBAAmB;YAOb,iBAAiB;YAWjB,oBAAoB;IAwBrB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB/D;IAEY,aAAa,CACxB,WAAW,EAAE,UAAU,EACvB,2BAA2B,EAAE,EAAE,EAAE,EACjC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAgCf;YAEa,qBAAqB;IASnC,OAAO,CAAC,wBAAwB;CAgBjC"}
@@ -3,6 +3,7 @@ import { merge, pick } from '@aztec/foundation/collection';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { L2BlockSourceEvents } from '@aztec/stdlib/block';
5
5
  import { getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
6
+ import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
6
7
  import { OffenseType, getOffenseTypeName } from '@aztec/stdlib/slashing';
7
8
  import { ReExFailedTxsError, ReExStateMismatchError, TransactionsNotAvailableError, ValidatorError } from '@aztec/stdlib/validators';
8
9
  import EventEmitter from 'node:events';
@@ -32,11 +33,11 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
32
33
  this.log.verbose(`EpochPruneWatcher initialized with penalties: valid epoch pruned=${penalties.slashPrunePenalty} data withholding=${penalties.slashDataWithholdingPenalty}`);
33
34
  }
34
35
  start() {
35
- this.l2BlockSource.on(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
36
+ this.l2BlockSource.events.on(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
36
37
  return Promise.resolve();
37
38
  }
38
39
  stop() {
39
- this.l2BlockSource.removeListener(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
40
+ this.l2BlockSource.events.removeListener(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
40
41
  return Promise.resolve();
41
42
  }
42
43
  updateConfig(config) {
@@ -62,7 +63,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
62
63
  async processPruneL2Blocks(blocks, epochNumber) {
63
64
  try {
64
65
  const l1Constants = this.epochCache.getL1Constants();
65
- const epochBlocks = blocks.filter((b)=>getEpochAtSlot(b.slot, l1Constants) === epochNumber);
66
+ const epochBlocks = blocks.filter((b)=>getEpochAtSlot(b.header.getSlot(), l1Constants) === epochNumber);
66
67
  this.log.info(`Detected chain prune. Validating epoch ${epochNumber} with blocks ${epochBlocks[0]?.number} to ${epochBlocks[epochBlocks.length - 1]?.number}.`, {
67
68
  blocks: epochBlocks.map((b)=>b.toBlockInfo())
68
69
  });
@@ -84,16 +85,25 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
84
85
  if (blocks.length === 0) {
85
86
  return;
86
87
  }
88
+ let previousCheckpointOutHashes = [];
87
89
  const fork = await this.blockBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
88
90
  try {
89
91
  for (const block of blocks){
90
- await this.validateBlock(block, fork);
92
+ await this.validateBlock(block, previousCheckpointOutHashes, fork);
93
+ // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
94
+ const checkpointOutHash = computeCheckpointOutHash([
95
+ block.body.txEffects.map((tx)=>tx.l2ToL1Msgs)
96
+ ]);
97
+ previousCheckpointOutHashes = [
98
+ ...previousCheckpointOutHashes,
99
+ checkpointOutHash
100
+ ];
91
101
  }
92
102
  } finally{
93
103
  await fork.close();
94
104
  }
95
105
  }
96
- async validateBlock(blockFromL1, fork) {
106
+ async validateBlock(blockFromL1, previousCheckpointOutHashes, fork) {
97
107
  this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
98
108
  const txHashes = blockFromL1.body.txEffects.map((txEffect)=>txEffect.txHash);
99
109
  // We load txs from the mempool directly, since the TxCollector running in the background has already been
@@ -105,7 +115,7 @@ const EpochPruneWatcherPenaltiesConfigKeys = [
105
115
  }
106
116
  const checkpointNumber = CheckpointNumber.fromBlockNumber(blockFromL1.number);
107
117
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
108
- const { block, failedTxs, numTxs } = await this.blockBuilder.buildBlock(txs, l1ToL2Messages, blockFromL1.header.globalVariables, {}, fork);
118
+ const { block, failedTxs, numTxs } = await this.blockBuilder.buildBlock(txs, l1ToL2Messages, previousCheckpointOutHashes, blockFromL1.header.globalVariables, {}, fork);
109
119
  if (numTxs !== txs.length) {
110
120
  // This should be detected by state mismatch, but this makes it easier to debug.
111
121
  throw new ValidatorError(`Built block with ${numTxs} txs, expected ${txs.length}`);
package/package.json CHANGED
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "name": "@aztec/slasher",
3
- "version": "4.0.0-nightly.20260112",
3
+ "version": "4.0.0-nightly.20260114",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
7
7
  "./config": "./dest/config.js"
8
8
  },
9
9
  "inherits": [
10
- "../package.common.json"
10
+ "../package.common.json",
11
+ "./package.local.json"
11
12
  ],
12
13
  "scripts": {
13
14
  "build": "yarn clean && ../scripts/tsc.sh",
14
15
  "build:dev": "../scripts/tsc.sh --watch",
15
16
  "clean": "rm -rf ./dest .tsbuildinfo",
16
17
  "bb": "node --no-warnings ./dest/bb/index.js",
17
- "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
18
+ "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}",
19
+ "generate": "./scripts/generate.sh"
18
20
  },
19
21
  "jest": {
20
22
  "moduleNameMapper": {
@@ -54,20 +56,20 @@
54
56
  ]
55
57
  },
56
58
  "dependencies": {
57
- "@aztec/epoch-cache": "4.0.0-nightly.20260112",
58
- "@aztec/ethereum": "4.0.0-nightly.20260112",
59
- "@aztec/foundation": "4.0.0-nightly.20260112",
60
- "@aztec/kv-store": "4.0.0-nightly.20260112",
61
- "@aztec/l1-artifacts": "4.0.0-nightly.20260112",
62
- "@aztec/stdlib": "4.0.0-nightly.20260112",
63
- "@aztec/telemetry-client": "4.0.0-nightly.20260112",
59
+ "@aztec/epoch-cache": "4.0.0-nightly.20260114",
60
+ "@aztec/ethereum": "4.0.0-nightly.20260114",
61
+ "@aztec/foundation": "4.0.0-nightly.20260114",
62
+ "@aztec/kv-store": "4.0.0-nightly.20260114",
63
+ "@aztec/l1-artifacts": "4.0.0-nightly.20260114",
64
+ "@aztec/stdlib": "4.0.0-nightly.20260114",
65
+ "@aztec/telemetry-client": "4.0.0-nightly.20260114",
64
66
  "source-map-support": "^0.5.21",
65
67
  "tslib": "^2.4.0",
66
68
  "viem": "npm:@aztec/viem@2.38.2",
67
69
  "zod": "^3.23.8"
68
70
  },
69
71
  "devDependencies": {
70
- "@aztec/aztec.js": "4.0.0-nightly.20260112",
72
+ "@aztec/aztec.js": "4.0.0-nightly.20260114",
71
73
  "@jest/globals": "^30.0.0",
72
74
  "@types/jest": "^30.0.0",
73
75
  "@types/node": "^22.15.17",
package/src/config.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
2
1
  import type { ConfigMappingsType } from '@aztec/foundation/config';
3
2
  import {
4
3
  bigintConfigHelper,
@@ -9,27 +8,29 @@ import {
9
8
  import { EthAddress } from '@aztec/foundation/eth-address';
10
9
  import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
11
10
 
11
+ import { slasherDefaultEnv } from './generated/slasher-defaults.js';
12
+
12
13
  export type { SlasherConfig };
13
14
 
14
15
  export const DefaultSlasherConfig: SlasherConfig = {
15
16
  slashOverridePayload: undefined,
16
- slashMinPenaltyPercentage: 0.5, // 50% of penalty
17
- slashMaxPenaltyPercentage: 2.0, //2x of penalty
17
+ slashMinPenaltyPercentage: slasherDefaultEnv.SLASH_MIN_PENALTY_PERCENTAGE,
18
+ slashMaxPenaltyPercentage: slasherDefaultEnv.SLASH_MAX_PENALTY_PERCENTAGE,
18
19
  slashValidatorsAlways: [], // Empty by default
19
20
  slashValidatorsNever: [], // Empty by default
20
- slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
21
- slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
22
- slashInactivityTargetPercentage: 0.9,
23
- slashInactivityConsecutiveEpochThreshold: 1, // Default to 1 for backward compatibility
24
- slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountSmall,
25
- slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
26
- slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountSmall,
27
- slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountSmall,
28
- slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
29
- slashOffenseExpirationRounds: 4,
30
- slashMaxPayloadSize: 50,
31
- slashGracePeriodL2Slots: 0,
32
- slashExecuteRoundsLookBack: 4,
21
+ slashPrunePenalty: BigInt(slasherDefaultEnv.SLASH_PRUNE_PENALTY),
22
+ slashDataWithholdingPenalty: BigInt(slasherDefaultEnv.SLASH_DATA_WITHHOLDING_PENALTY),
23
+ slashInactivityTargetPercentage: slasherDefaultEnv.SLASH_INACTIVITY_TARGET_PERCENTAGE,
24
+ slashInactivityConsecutiveEpochThreshold: slasherDefaultEnv.SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD,
25
+ slashBroadcastedInvalidBlockPenalty: BigInt(slasherDefaultEnv.SLASH_INVALID_BLOCK_PENALTY),
26
+ slashInactivityPenalty: BigInt(slasherDefaultEnv.SLASH_INACTIVITY_PENALTY),
27
+ slashProposeInvalidAttestationsPenalty: BigInt(slasherDefaultEnv.SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY),
28
+ slashAttestDescendantOfInvalidPenalty: BigInt(slasherDefaultEnv.SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY),
29
+ slashUnknownPenalty: BigInt(slasherDefaultEnv.SLASH_UNKNOWN_PENALTY),
30
+ slashOffenseExpirationRounds: slasherDefaultEnv.SLASH_OFFENSE_EXPIRATION_ROUNDS,
31
+ slashMaxPayloadSize: slasherDefaultEnv.SLASH_MAX_PAYLOAD_SIZE,
32
+ slashGracePeriodL2Slots: slasherDefaultEnv.SLASH_GRACE_PERIOD_L2_SLOTS,
33
+ slashExecuteRoundsLookBack: slasherDefaultEnv.SLASH_EXECUTE_ROUNDS_LOOK_BACK,
33
34
  slashSelfAllowed: false,
34
35
  };
35
36
 
@@ -0,0 +1,21 @@
1
+ // Auto-generated from spartan/environments/network-defaults.yml
2
+ // Do not edit manually - run yarn generate to regenerate
3
+
4
+ /** Default slasher configuration values from network-defaults.yml */
5
+ export const slasherDefaultEnv = {
6
+ SLASH_MIN_PENALTY_PERCENTAGE: 0.5,
7
+ SLASH_MAX_PENALTY_PERCENTAGE: 2,
8
+ SLASH_OFFENSE_EXPIRATION_ROUNDS: 4,
9
+ SLASH_MAX_PAYLOAD_SIZE: 50,
10
+ SLASH_EXECUTE_ROUNDS_LOOK_BACK: 4,
11
+ SLASH_PRUNE_PENALTY: 10000000000000000000,
12
+ SLASH_DATA_WITHHOLDING_PENALTY: 10000000000000000000,
13
+ SLASH_INACTIVITY_TARGET_PERCENTAGE: 0.9,
14
+ SLASH_INACTIVITY_CONSECUTIVE_EPOCH_THRESHOLD: 1,
15
+ SLASH_INACTIVITY_PENALTY: 10000000000000000000,
16
+ SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY: 10000000000000000000,
17
+ SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY: 10000000000000000000,
18
+ SLASH_UNKNOWN_PENALTY: 10000000000000000000,
19
+ SLASH_INVALID_BLOCK_PENALTY: 10000000000000000000,
20
+ SLASH_GRACE_PERIOD_L2_SLOTS: 0,
21
+ } as const;
@@ -3,12 +3,12 @@ import { SlotNumber } from '@aztec/foundation/branded-types';
3
3
  import { merge, pick } from '@aztec/foundation/collection';
4
4
  import { type Logger, createLogger } from '@aztec/foundation/log';
5
5
  import {
6
- type InvalidBlockDetectedEvent,
7
- type L2BlockInfo,
6
+ type InvalidCheckpointDetectedEvent,
8
7
  type L2BlockSourceEventEmitter,
9
8
  L2BlockSourceEvents,
10
- type ValidateBlockNegativeResult,
9
+ type ValidateCheckpointNegativeResult,
11
10
  } from '@aztec/stdlib/block';
11
+ import type { CheckpointInfo } from '@aztec/stdlib/checkpoint';
12
12
  import { OffenseType } from '@aztec/stdlib/slashing';
13
13
 
14
14
  import EventEmitter from 'node:events';
@@ -32,19 +32,19 @@ type AttestationsBlockWatcherConfig = Pick<SlasherConfig, (typeof AttestationsBl
32
32
  export class AttestationsBlockWatcher extends (EventEmitter as new () => WatcherEmitter) implements Watcher {
33
33
  private log: Logger = createLogger('attestations-block-watcher');
34
34
 
35
- // Only keep track of the last N invalid blocks
36
- private maxInvalidBlocks = 100;
35
+ // Only keep track of the last N invalid checkpoints
36
+ private maxInvalidCheckpoints = 100;
37
37
 
38
38
  // All invalid archive roots seen
39
39
  private invalidArchiveRoots: Set<string> = new Set();
40
40
 
41
41
  private config: AttestationsBlockWatcherConfig;
42
42
 
43
- private boundHandleInvalidBlock = (event: InvalidBlockDetectedEvent) => {
43
+ private boundHandleInvalidCheckpoint = (event: InvalidCheckpointDetectedEvent) => {
44
44
  try {
45
- this.handleInvalidBlock(event);
45
+ this.handleInvalidCheckpoint(event);
46
46
  } catch (err) {
47
- this.log.error('Error handling invalid block', err, {
47
+ this.log.error('Error handling invalid checkpoint', err, {
48
48
  ...event.validationResult,
49
49
  reason: event.validationResult.reason,
50
50
  });
@@ -67,54 +67,60 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
67
67
  }
68
68
 
69
69
  public start() {
70
- this.l2BlockSource.on(L2BlockSourceEvents.InvalidAttestationsBlockDetected, this.boundHandleInvalidBlock);
70
+ this.l2BlockSource.events.on(
71
+ L2BlockSourceEvents.InvalidAttestationsCheckpointDetected,
72
+ this.boundHandleInvalidCheckpoint,
73
+ );
71
74
  return Promise.resolve();
72
75
  }
73
76
 
74
77
  public stop() {
75
- this.l2BlockSource.removeListener(
76
- L2BlockSourceEvents.InvalidAttestationsBlockDetected,
77
- this.boundHandleInvalidBlock,
78
+ this.l2BlockSource.events.removeListener(
79
+ L2BlockSourceEvents.InvalidAttestationsCheckpointDetected,
80
+ this.boundHandleInvalidCheckpoint,
78
81
  );
79
82
  return Promise.resolve();
80
83
  }
81
84
 
82
- private handleInvalidBlock(event: InvalidBlockDetectedEvent): void {
85
+ private handleInvalidCheckpoint(event: InvalidCheckpointDetectedEvent): void {
83
86
  const { validationResult } = event;
84
- const block = validationResult.block;
87
+ const checkpoint = validationResult.checkpoint;
85
88
 
86
- // Check if we already have processed this block, archiver may emit the same event multiple times
87
- if (this.invalidArchiveRoots.has(block.archive.toString())) {
88
- this.log.trace(`Already processed invalid block ${block.blockNumber}`);
89
+ // Check if we already have processed this checkpoint, archiver may emit the same event multiple times
90
+ if (this.invalidArchiveRoots.has(checkpoint.archive.toString())) {
91
+ this.log.trace(`Already processed invalid checkpoint ${checkpoint.checkpointNumber}`);
89
92
  return;
90
93
  }
91
94
 
92
- this.log.verbose(`Detected invalid block ${block.blockNumber}`, {
93
- ...block,
95
+ this.log.verbose(`Detected invalid checkpoint ${checkpoint.checkpointNumber}`, {
96
+ ...checkpoint,
94
97
  reason: validationResult.valid === false ? validationResult.reason : 'unknown',
95
98
  });
96
99
 
97
- // Store the invalid block
98
- this.addInvalidBlock(event.validationResult.block);
100
+ // Store the invalid checkpoint
101
+ this.addInvalidCheckpoint(event.validationResult.checkpoint);
99
102
 
100
- // Slash the proposer of the invalid block
103
+ // Slash the proposer of the invalid checkpoint
101
104
  this.slashProposer(event.validationResult);
102
105
 
103
- // Check if the parent of this block is invalid as well, if so, we will slash its attestors as well
106
+ // Check if the parent of this checkpoint is invalid as well, if so, we will slash its attestors as well
104
107
  this.slashAttestorsOnAncestorInvalid(event.validationResult);
105
108
  }
106
109
 
107
- private slashAttestorsOnAncestorInvalid(validationResult: ValidateBlockNegativeResult) {
108
- const block = validationResult.block;
110
+ private slashAttestorsOnAncestorInvalid(validationResult: ValidateCheckpointNegativeResult) {
111
+ const checkpoint = validationResult.checkpoint;
109
112
 
110
- const parentArchive = block.lastArchive.toString();
113
+ const parentArchive = checkpoint.lastArchive.toString();
111
114
  if (this.invalidArchiveRoots.has(parentArchive)) {
112
115
  const attestors = validationResult.attestors;
113
- this.log.info(`Want to slash attestors of block ${block.blockNumber} built on invalid block`, {
114
- ...block,
115
- ...attestors,
116
- parentArchive,
117
- });
116
+ this.log.info(
117
+ `Want to slash attestors of checkpoint ${checkpoint.checkpointNumber} built on invalid checkpoint`,
118
+ {
119
+ ...checkpoint,
120
+ ...attestors,
121
+ parentArchive,
122
+ },
123
+ );
118
124
 
119
125
  this.emit(
120
126
  WANT_TO_SLASH_EVENT,
@@ -122,16 +128,16 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
122
128
  validator: attestor,
123
129
  amount: this.config.slashAttestDescendantOfInvalidPenalty,
124
130
  offenseType: OffenseType.ATTESTED_DESCENDANT_OF_INVALID,
125
- epochOrSlot: BigInt(SlotNumber(block.slotNumber)),
131
+ epochOrSlot: BigInt(SlotNumber(checkpoint.slotNumber)),
126
132
  })),
127
133
  );
128
134
  }
129
135
  }
130
136
 
131
- private slashProposer(validationResult: ValidateBlockNegativeResult) {
132
- const { reason, block } = validationResult;
133
- const blockNumber = block.blockNumber;
134
- const slot = block.slotNumber;
137
+ private slashProposer(validationResult: ValidateCheckpointNegativeResult) {
138
+ const { reason, checkpoint } = validationResult;
139
+ const checkpointNumber = checkpoint.checkpointNumber;
140
+ const slot = checkpoint.slotNumber;
135
141
  const epochCommitteeInfo = {
136
142
  committee: validationResult.committee,
137
143
  seed: validationResult.seed,
@@ -140,7 +146,7 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
140
146
  const proposer = this.epochCache.getProposerFromEpochCommittee(epochCommitteeInfo, slot);
141
147
 
142
148
  if (!proposer) {
143
- this.log.warn(`No proposer found for block ${blockNumber} at slot ${slot}`);
149
+ this.log.warn(`No proposer found for checkpoint ${checkpointNumber} at slot ${slot}`);
144
150
  return;
145
151
  }
146
152
 
@@ -153,15 +159,15 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
153
159
  epochOrSlot: BigInt(slot),
154
160
  };
155
161
 
156
- this.log.info(`Want to slash proposer of block ${blockNumber} due to ${reason}`, {
157
- ...block,
162
+ this.log.info(`Want to slash proposer of checkpoint ${checkpointNumber} due to ${reason}`, {
163
+ ...checkpoint,
158
164
  ...args,
159
165
  });
160
166
 
161
167
  this.emit(WANT_TO_SLASH_EVENT, [args]);
162
168
  }
163
169
 
164
- private getOffenseFromInvalidationReason(reason: ValidateBlockNegativeResult['reason']): OffenseType {
170
+ private getOffenseFromInvalidationReason(reason: ValidateCheckpointNegativeResult['reason']): OffenseType {
165
171
  switch (reason) {
166
172
  case 'invalid-attestation':
167
173
  return OffenseType.PROPOSED_INCORRECT_ATTESTATIONS;
@@ -174,11 +180,11 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher
174
180
  }
175
181
  }
176
182
 
177
- private addInvalidBlock(block: L2BlockInfo) {
178
- this.invalidArchiveRoots.add(block.archive.toString());
183
+ private addInvalidCheckpoint(checkpoint: CheckpointInfo) {
184
+ this.invalidArchiveRoots.add(checkpoint.archive.toString());
179
185
 
180
186
  // Prune old entries if we exceed the maximum
181
- if (this.invalidArchiveRoots.size > this.maxInvalidBlocks) {
187
+ if (this.invalidArchiveRoots.size > this.maxInvalidCheckpoints) {
182
188
  const oldestKey = this.invalidArchiveRoots.keys().next().value!;
183
189
  this.invalidArchiveRoots.delete(oldestKey);
184
190
  }
@@ -1,10 +1,11 @@
1
1
  import { EpochCache } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
3
3
  import { merge, pick } from '@aztec/foundation/collection';
4
+ import type { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { type Logger, createLogger } from '@aztec/foundation/log';
5
6
  import {
6
7
  EthAddress,
7
- L2Block,
8
+ L2BlockNew,
8
9
  type L2BlockPruneEvent,
9
10
  type L2BlockSourceEventEmitter,
10
11
  L2BlockSourceEvents,
@@ -16,7 +17,7 @@ import type {
16
17
  MerkleTreeWriteOperations,
17
18
  SlasherConfig,
18
19
  } from '@aztec/stdlib/interfaces/server';
19
- import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
20
+ import { type L1ToL2MessageSource, computeCheckpointOutHash } from '@aztec/stdlib/messaging';
20
21
  import { OffenseType, getOffenseTypeName } from '@aztec/stdlib/slashing';
21
22
  import {
22
23
  ReExFailedTxsError,
@@ -63,12 +64,12 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
63
64
  }
64
65
 
65
66
  public start() {
66
- this.l2BlockSource.on(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
67
+ this.l2BlockSource.events.on(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
67
68
  return Promise.resolve();
68
69
  }
69
70
 
70
71
  public stop() {
71
- this.l2BlockSource.removeListener(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
72
+ this.l2BlockSource.events.removeListener(L2BlockSourceEvents.L2PruneDetected, this.boundHandlePruneL2Blocks);
72
73
  return Promise.resolve();
73
74
  }
74
75
 
@@ -95,10 +96,10 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
95
96
  this.emit(WANT_TO_SLASH_EVENT, args);
96
97
  }
97
98
 
98
- private async processPruneL2Blocks(blocks: L2Block[], epochNumber: EpochNumber): Promise<void> {
99
+ private async processPruneL2Blocks(blocks: L2BlockNew[], epochNumber: EpochNumber): Promise<void> {
99
100
  try {
100
101
  const l1Constants = this.epochCache.getL1Constants();
101
- const epochBlocks = blocks.filter(b => getEpochAtSlot(b.slot, l1Constants) === epochNumber);
102
+ const epochBlocks = blocks.filter(b => getEpochAtSlot(b.header.getSlot(), l1Constants) === epochNumber);
102
103
  this.log.info(
103
104
  `Detected chain prune. Validating epoch ${epochNumber} with blocks ${epochBlocks[0]?.number} to ${epochBlocks[epochBlocks.length - 1]?.number}.`,
104
105
  { blocks: epochBlocks.map(b => b.toBlockInfo()) },
@@ -119,21 +120,31 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
119
120
  }
120
121
  }
121
122
 
122
- public async validateBlocks(blocks: L2Block[]): Promise<void> {
123
+ public async validateBlocks(blocks: L2BlockNew[]): Promise<void> {
123
124
  if (blocks.length === 0) {
124
125
  return;
125
126
  }
127
+
128
+ let previousCheckpointOutHashes: Fr[] = [];
126
129
  const fork = await this.blockBuilder.getFork(BlockNumber(blocks[0].header.globalVariables.blockNumber - 1));
127
130
  try {
128
131
  for (const block of blocks) {
129
- await this.validateBlock(block, fork);
132
+ await this.validateBlock(block, previousCheckpointOutHashes, fork);
133
+
134
+ // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
135
+ const checkpointOutHash = computeCheckpointOutHash([block.body.txEffects.map(tx => tx.l2ToL1Msgs)]);
136
+ previousCheckpointOutHashes = [...previousCheckpointOutHashes, checkpointOutHash];
130
137
  }
131
138
  } finally {
132
139
  await fork.close();
133
140
  }
134
141
  }
135
142
 
136
- public async validateBlock(blockFromL1: L2Block, fork: MerkleTreeWriteOperations): Promise<void> {
143
+ public async validateBlock(
144
+ blockFromL1: L2BlockNew,
145
+ previousCheckpointOutHashes: Fr[],
146
+ fork: MerkleTreeWriteOperations,
147
+ ): Promise<void> {
137
148
  this.log.debug(`Validating pruned block ${blockFromL1.header.globalVariables.blockNumber}`);
138
149
  const txHashes = blockFromL1.body.txEffects.map(txEffect => txEffect.txHash);
139
150
  // We load txs from the mempool directly, since the TxCollector running in the background has already been
@@ -150,6 +161,7 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
150
161
  const { block, failedTxs, numTxs } = await this.blockBuilder.buildBlock(
151
162
  txs,
152
163
  l1ToL2Messages,
164
+ previousCheckpointOutHashes,
153
165
  blockFromL1.header.globalVariables,
154
166
  {},
155
167
  fork,