@lodestar/validator 1.48.0-dev.dd957b093d → 1.48.0-dev.df6a2aa429
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/lib/slashingProtection/attestation/attestationByTargetRepository.d.ts +2 -0
- package/lib/slashingProtection/attestation/attestationByTargetRepository.d.ts.map +1 -1
- package/lib/slashingProtection/attestation/attestationByTargetRepository.js +11 -0
- package/lib/slashingProtection/attestation/attestationByTargetRepository.js.map +1 -1
- package/lib/slashingProtection/attestation/errors.d.ts +10 -1
- package/lib/slashingProtection/attestation/errors.d.ts.map +1 -1
- package/lib/slashingProtection/attestation/errors.js +5 -0
- package/lib/slashingProtection/attestation/errors.js.map +1 -1
- package/lib/slashingProtection/attestation/index.d.ts.map +1 -1
- package/lib/slashingProtection/attestation/index.js +41 -2
- package/lib/slashingProtection/attestation/index.js.map +1 -1
- package/lib/slashingProtection/minMaxSurround/minMaxSurround.d.ts +3 -1
- package/lib/slashingProtection/minMaxSurround/minMaxSurround.d.ts.map +1 -1
- package/lib/slashingProtection/minMaxSurround/minMaxSurround.js +7 -2
- package/lib/slashingProtection/minMaxSurround/minMaxSurround.js.map +1 -1
- package/package.json +12 -12
- package/src/slashingProtection/attestation/attestationByTargetRepository.ts +12 -0
- package/src/slashingProtection/attestation/errors.ts +10 -0
- package/src/slashingProtection/attestation/index.ts +43 -2
- package/src/slashingProtection/minMaxSurround/minMaxSurround.ts +9 -3
|
@@ -18,6 +18,8 @@ export declare class AttestationByTargetRepository {
|
|
|
18
18
|
private readonly maxKey;
|
|
19
19
|
constructor(db: LodestarValidatorDatabaseController);
|
|
20
20
|
getAll(pubkey: BLSPubkey, limit?: number): Promise<SlashingProtectionAttestation[]>;
|
|
21
|
+
/** Attestation with the highest target epoch recorded for `pubkey`, or null if none */
|
|
22
|
+
getLatest(pubkey: BLSPubkey): Promise<SlashingProtectionAttestation | null>;
|
|
21
23
|
get(pubkey: BLSPubkey, targetEpoch: Epoch): Promise<SlashingProtectionAttestation | null>;
|
|
22
24
|
set(pubkey: BLSPubkey, atts: SlashingProtectionAttestation[]): Promise<void>;
|
|
23
25
|
listPubkeys(): Promise<BLSPubkey[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attestationByTargetRepository.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/attestationByTargetRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAC,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAC,SAAS,EAAE,KAAK,EAAM,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAC,MAAM,EAAuB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAC,mCAAmC,EAAC,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAG1D;;;;GAIG;AACH,qBAAa,6BAA6B;IAS5B,SAAS,CAAC,EAAE,EAAE,mCAAmC;IAR7D,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACpD,SAAS,CAAC,MAAM,SAAgD;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,YAAsB,EAAE,EAAE,mCAAmC,EAQ5D;IAEK,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAQxF;IAEK,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,GAAG,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAG9F;IAEK,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF;IAEK,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAGxC;IAED,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;CASlB"}
|
|
1
|
+
{"version":3,"file":"attestationByTargetRepository.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/attestationByTargetRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAC,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAC,SAAS,EAAE,KAAK,EAAM,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAC,MAAM,EAAuB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAC,mCAAmC,EAAC,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAG1D;;;;GAIG;AACH,qBAAa,6BAA6B;IAS5B,SAAS,CAAC,EAAE,EAAE,mCAAmC;IAR7D,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACpD,SAAS,CAAC,MAAM,SAAgD;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,YAAsB,EAAE,EAAE,mCAAmC,EAQ5D;IAEK,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAQxF;IAED,uFAAuF;IACjF,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAShF;IAEK,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,GAAG,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAG9F;IAEK,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF;IAEK,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAGxC;IAED,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;CASlB"}
|
|
@@ -36,6 +36,17 @@ export class AttestationByTargetRepository {
|
|
|
36
36
|
});
|
|
37
37
|
return attestations.map((attestation) => this.type.deserialize(attestation));
|
|
38
38
|
}
|
|
39
|
+
/** Attestation with the highest target epoch recorded for `pubkey`, or null if none */
|
|
40
|
+
async getLatest(pubkey) {
|
|
41
|
+
const [att] = await this.db.values({
|
|
42
|
+
gte: this.encodeKey(pubkey, 0),
|
|
43
|
+
lt: this.encodeKey(pubkey, Number.MAX_SAFE_INTEGER),
|
|
44
|
+
reverse: true,
|
|
45
|
+
limit: 1,
|
|
46
|
+
bucketId: this.bucketId,
|
|
47
|
+
});
|
|
48
|
+
return att ? this.type.deserialize(att) : null;
|
|
49
|
+
}
|
|
39
50
|
async get(pubkey, targetEpoch) {
|
|
40
51
|
const att = await this.db.get(this.encodeKey(pubkey, targetEpoch), this.dbReqOpts);
|
|
41
52
|
return att && this.type.deserialize(att);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attestationByTargetRepository.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/attestationByTargetRepository.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attestationByTargetRepository.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/attestationByTargetRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAO,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAC,gBAAgB,EAAa,SAAS,EAAE,OAAO,EAAC,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAmB,GAAG,EAAC,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAC,MAAM,EAAE,oBAAoB,EAAC,MAAM,kBAAkB,CAAC;AAG9D,OAAO,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,aAAa,CAAC;AAE1D;;;;GAIG;AACH,MAAM,OAAO,6BAA6B;IASlB,EAAE;IARd,IAAI,CAAsC;IAC1C,MAAM,GAAG,MAAM,CAAC,qCAAqC,CAAC;IAE/C,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,SAAS,GAAc,EAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAC,CAAC;IACjD,MAAM,CAAa;IACnB,MAAM,CAAa;IAEpC,YAAsB,EAAuC;kBAAvC,EAAE;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC;YAC5B,WAAW,EAAE,GAAG,CAAC,KAAK;YACtB,WAAW,EAAE,GAAG,CAAC,KAAK;YACtB,WAAW,EAAE,GAAG,CAAC,IAAI;SACtB,CAAC,CAAC,CAAC,wBAAwB;QAC5B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAiB,EAAE,KAAc;QAC5C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;YACxC,KAAK;YACL,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9B,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,gBAAgB,CAAC;YACnD,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,uFAAuF;IACvF,KAAK,CAAC,SAAS,CAAC,MAAiB;QAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;YACjC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9B,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,gBAAgB,CAAC;YACnD,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,CAAC;YACR,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAiB,EAAE,WAAkB;QAC7C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACnF,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAiB,EAAE,IAAqC;QAChE,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CACpB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACjB,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC;YAC5C,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;SAChC,CAAC,CAAC,EACH,IAAI,CAAC,SAAS,CACf,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAC,CAAC,CAAC;QAC9F,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,CAAC;IAEO,SAAS,CAAC,MAAiB,EAAE,WAAkB;QACrD,OAAO,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzG,CAAC;IAEO,SAAS,CAAC,GAAe;QAC/B,OAAO;YACL,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,YAAY,CAAC;YACpE,WAAW,EAAE,UAAU,CACrB,GAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,YAAY,EAAE,gBAAgB,GAAG,YAAY,GAAG,OAAO,CAAC,EACrF,IAAI,CACL;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -27,7 +27,12 @@ export declare enum InvalidAttestationErrorCode {
|
|
|
27
27
|
* The attestation is invalid because its target epoch is less than or equal to the lower
|
|
28
28
|
* bound on target epochs for this validator.
|
|
29
29
|
*/
|
|
30
|
-
TARGET_LESS_THAN_OR_EQ_LOWER_BOUND = "ERR_INVALID_ATTESTATION_TARGET_LESS_THAN_OR_EQ_LOWER_BOUND"
|
|
30
|
+
TARGET_LESS_THAN_OR_EQ_LOWER_BOUND = "ERR_INVALID_ATTESTATION_TARGET_LESS_THAN_OR_EQ_LOWER_BOUND",
|
|
31
|
+
/**
|
|
32
|
+
* The attestation is invalid because its source epoch is below the min-max span lookback window of the
|
|
33
|
+
* latest attestation of this validator, where a surround vote could not be detected.
|
|
34
|
+
*/
|
|
35
|
+
SOURCE_BELOW_MIN_SPAN_LOOKBACK = "ERR_INVALID_ATTESTATION_SOURCE_BELOW_MIN_SPAN_LOOKBACK"
|
|
31
36
|
}
|
|
32
37
|
type InvalidAttestationErrorType = {
|
|
33
38
|
code: InvalidAttestationErrorCode.DOUBLE_VOTE;
|
|
@@ -51,6 +56,10 @@ type InvalidAttestationErrorType = {
|
|
|
51
56
|
code: InvalidAttestationErrorCode.TARGET_LESS_THAN_OR_EQ_LOWER_BOUND;
|
|
52
57
|
targetEpoch: Epoch;
|
|
53
58
|
minTargetEpoch: Epoch;
|
|
59
|
+
} | {
|
|
60
|
+
code: InvalidAttestationErrorCode.SOURCE_BELOW_MIN_SPAN_LOOKBACK;
|
|
61
|
+
sourceEpoch: Epoch;
|
|
62
|
+
minSourceEpoch: Epoch;
|
|
54
63
|
};
|
|
55
64
|
export declare class InvalidAttestationError extends LodestarError<InvalidAttestationErrorType> {
|
|
56
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAE1D,oBAAY,2BAA2B;IACrC;;OAEG;IACH,WAAW,wCAAwC;IACnD;;OAEG;IACH,kBAAkB,+CAA+C;IACjE;;OAEG;IACH,kBAAkB,+CAA+C;IACjE;;OAEG;IACH,qBAAqB,kDAAkD;IACvE;;;OAGG;IACH,4BAA4B,yDAAyD;IACrF;;;OAGG;IACH,kCAAkC,+DAA+D;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAE1D,oBAAY,2BAA2B;IACrC;;OAEG;IACH,WAAW,wCAAwC;IACnD;;OAEG;IACH,kBAAkB,+CAA+C;IACjE;;OAEG;IACH,kBAAkB,+CAA+C;IACjE;;OAEG;IACH,qBAAqB,kDAAkD;IACvE;;;OAGG;IACH,4BAA4B,yDAAyD;IACrF;;;OAGG;IACH,kCAAkC,+DAA+D;IACjG;;;OAGG;IACH,8BAA8B,2DAA2D;CAC1F;AAED,KAAK,2BAA2B,GAC5B;IACE,IAAI,EAAE,2BAA2B,CAAC,WAAW,CAAC;IAC9C,WAAW,EAAE,6BAA6B,CAAC;IAC3C,IAAI,EAAE,6BAA6B,CAAC;CACrC,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC;IACrD,WAAW,EAAE,6BAA6B,CAAC;IAE3C,IAAI,EAAE,6BAA6B,GAAG,IAAI,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC;IACrD,WAAW,EAAE,6BAA6B,CAAC;IAE3C,IAAI,EAAE,6BAA6B,GAAG,IAAI,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,qBAAqB,CAAC;CACzD,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,4BAA4B,CAAC;IAC/D,WAAW,EAAE,KAAK,CAAC;IACnB,cAAc,EAAE,KAAK,CAAC;CACvB,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,kCAAkC,CAAC;IACrE,WAAW,EAAE,KAAK,CAAC;IACnB,cAAc,EAAE,KAAK,CAAC;CACvB,GACD;IACE,IAAI,EAAE,2BAA2B,CAAC,8BAA8B,CAAC;IACjE,WAAW,EAAE,KAAK,CAAC;IACnB,cAAc,EAAE,KAAK,CAAC;CACvB,CAAC;AAEN,qBAAa,uBAAwB,SAAQ,aAAa,CAAC,2BAA2B,CAAC;CAAG"}
|
|
@@ -27,6 +27,11 @@ export var InvalidAttestationErrorCode;
|
|
|
27
27
|
* bound on target epochs for this validator.
|
|
28
28
|
*/
|
|
29
29
|
InvalidAttestationErrorCode["TARGET_LESS_THAN_OR_EQ_LOWER_BOUND"] = "ERR_INVALID_ATTESTATION_TARGET_LESS_THAN_OR_EQ_LOWER_BOUND";
|
|
30
|
+
/**
|
|
31
|
+
* The attestation is invalid because its source epoch is below the min-max span lookback window of the
|
|
32
|
+
* latest attestation of this validator, where a surround vote could not be detected.
|
|
33
|
+
*/
|
|
34
|
+
InvalidAttestationErrorCode["SOURCE_BELOW_MIN_SPAN_LOOKBACK"] = "ERR_INVALID_ATTESTATION_SOURCE_BELOW_MIN_SPAN_LOOKBACK";
|
|
30
35
|
})(InvalidAttestationErrorCode || (InvalidAttestationErrorCode = {}));
|
|
31
36
|
export class InvalidAttestationError extends LodestarError {
|
|
32
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAG9C,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAG9C,MAAM,CAAN,IAAY,2BAgCX;AAhCD,WAAY,2BAA2B;IACrC;;OAEG;IACH,kFAAmD,CAAA;IACnD;;OAEG;IACH,gGAAiE,CAAA;IACjE;;OAEG;IACH,gGAAiE,CAAA;IACjE;;OAEG;IACH,sGAAuE,CAAA;IACvE;;;OAGG;IACH,oHAAqF,CAAA;IACrF;;;OAGG;IACH,gIAAiG,CAAA;IACjG;;;OAGG;IACH,wHAAyF,CAAA;AAC3F,CAAC,EAhCW,2BAA2B,KAA3B,2BAA2B,QAgCtC;AAuCD,MAAM,OAAO,uBAAwB,SAAQ,aAA0C;CAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,KAAK,EAAC,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAC,cAAc,EAAyD,MAAM,4BAA4B,CAAC;AAClH,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAC,6BAA6B,EAAC,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAC,+BAA+B,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAC,uBAAuB,EAAE,2BAA2B,EAAC,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,GAC5B,CAAC;AAEF,aAAK,UAAU;IACb,SAAS,0BAA0B;IACnC,EAAE,mBAAmB;CACtB;AAED,qBAAa,oCAAoC;IAC/C,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,cAAc,CAAiB;IAEvC,YACE,mBAAmB,EAAE,6BAA6B,EAClD,qBAAqB,EAAE,+BAA+B,EACtD,cAAc,EAAE,cAAc,EAK/B;IAED;;;OAGG;IACG,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5G;IAED;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,KAAK,EAAC,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAC,cAAc,EAAyD,MAAM,4BAA4B,CAAC;AAClH,OAAO,EAAC,6BAA6B,EAAC,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAC,6BAA6B,EAAC,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAC,+BAA+B,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAC,uBAAuB,EAAE,2BAA2B,EAAC,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,GAC5B,CAAC;AAEF,aAAK,UAAU;IACb,SAAS,0BAA0B;IACnC,EAAE,mBAAmB;CACtB;AAED,qBAAa,oCAAoC;IAC/C,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,cAAc,CAAiB;IAEvC,YACE,mBAAmB,EAAE,6BAA6B,EAClD,qBAAqB,EAAE,+BAA+B,EACtD,cAAc,EAAE,cAAc,EAK/B;IAED;;;OAGG;IACG,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5G;IAED;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,GAAG,OAAO,CAAC,UAAU,CAAC,CA4FzG;IAED;;;;OAIG;IACG,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpG;IAED;;OAEG;IACG,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAE3G;IAED;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCxG;IAED;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAEpF;IAEK,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAExC;CACF"}
|
|
@@ -38,9 +38,16 @@ export class SlashingProtectionAttestationService {
|
|
|
38
38
|
if (attestation.sourceEpoch > attestation.targetEpoch) {
|
|
39
39
|
throw new InvalidAttestationError({ code: InvalidAttestationErrorCode.SOURCE_EXCEEDS_TARGET });
|
|
40
40
|
}
|
|
41
|
+
const latestAtt = await this.attestationByTarget.getLatest(pubKey);
|
|
41
42
|
// Check for a double vote. Namely, an existing attestation with the same target epoch,
|
|
42
|
-
// and a different signing root.
|
|
43
|
-
|
|
43
|
+
// and a different signing root. No db read needed if the latest attestation has a lower target epoch.
|
|
44
|
+
let sameTargetAtt = null;
|
|
45
|
+
if (latestAtt && latestAtt.targetEpoch === attestation.targetEpoch) {
|
|
46
|
+
sameTargetAtt = latestAtt;
|
|
47
|
+
}
|
|
48
|
+
else if (latestAtt && latestAtt.targetEpoch > attestation.targetEpoch) {
|
|
49
|
+
sameTargetAtt = await this.attestationByTarget.get(pubKey, attestation.targetEpoch);
|
|
50
|
+
}
|
|
44
51
|
if (sameTargetAtt) {
|
|
45
52
|
// Interchange format allows for attestations without signing_root, then assume root is equal
|
|
46
53
|
if (isEqualNonZeroRoot(sameTargetAtt.signingRoot, attestation.signingRoot)) {
|
|
@@ -52,6 +59,19 @@ export class SlashingProtectionAttestationService {
|
|
|
52
59
|
prev: sameTargetAtt,
|
|
53
60
|
});
|
|
54
61
|
}
|
|
62
|
+
// Min-span entries only exist within the lookback window below each recorded source epoch, a surround vote
|
|
63
|
+
// with an older source epoch is undetectable by min-max surround and must be rejected outright. Recorded
|
|
64
|
+
// attestations are surround-free, so the latest one has the highest source epoch and the widest window.
|
|
65
|
+
if (latestAtt) {
|
|
66
|
+
const minSourceEpoch = this.minMaxSurround.minSpanCoverageStart(latestAtt.sourceEpoch);
|
|
67
|
+
if (attestation.sourceEpoch < minSourceEpoch) {
|
|
68
|
+
throw new InvalidAttestationError({
|
|
69
|
+
code: InvalidAttestationErrorCode.SOURCE_BELOW_MIN_SPAN_LOOKBACK,
|
|
70
|
+
sourceEpoch: attestation.sourceEpoch,
|
|
71
|
+
minSourceEpoch,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
55
75
|
// Check for a surround vote
|
|
56
76
|
try {
|
|
57
77
|
await this.minMaxSurround.assertNoSurround(pubKey, attestation);
|
|
@@ -119,6 +139,25 @@ export class SlashingProtectionAttestationService {
|
|
|
119
139
|
* Interchange import / export functionality
|
|
120
140
|
*/
|
|
121
141
|
async importAttestations(pubkey, attestations) {
|
|
142
|
+
// Min-max surround misses a surround vote beyond its lookback, require the highest target attestation to
|
|
143
|
+
// have the highest source epoch as `checkAttestation` relies on it
|
|
144
|
+
let latestAtt = await this.attestationByTarget.getLatest(pubkey);
|
|
145
|
+
let maxSourceAtt = latestAtt;
|
|
146
|
+
for (const attestation of attestations) {
|
|
147
|
+
if (latestAtt === null || attestation.targetEpoch >= latestAtt.targetEpoch) {
|
|
148
|
+
latestAtt = attestation;
|
|
149
|
+
}
|
|
150
|
+
if (maxSourceAtt === null || attestation.sourceEpoch > maxSourceAtt.sourceEpoch) {
|
|
151
|
+
maxSourceAtt = attestation;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (latestAtt && maxSourceAtt && latestAtt.sourceEpoch < maxSourceAtt.sourceEpoch) {
|
|
155
|
+
throw new InvalidAttestationError({
|
|
156
|
+
code: InvalidAttestationErrorCode.NEW_SURROUNDS_PREV,
|
|
157
|
+
attestation: latestAtt,
|
|
158
|
+
prev: maxSourceAtt,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
122
161
|
await this.attestationByTarget.set(pubkey, attestations);
|
|
123
162
|
// Pre-compute spans for all attestations
|
|
124
163
|
for (const attestation of attestations) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,wBAAwB,EAAE,4BAA4B,EAAC,MAAM,4BAA4B,CAAC;AAElH,OAAO,EAAC,kBAAkB,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AACzD,OAAO,EAAC,6BAA6B,EAAC,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAC,+BAA+B,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAC,uBAAuB,EAAE,2BAA2B,EAAC,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,2BAA2B,GAC5B,CAAC;AAEF,IAAK,UAGJ;AAHD,WAAK,UAAU;IACb,iDAAmC,CAAA;IACnC,mCAAqB,CAAA;AACvB,CAAC,EAHI,UAAU,KAAV,UAAU,QAGd;AAED,MAAM,OAAO,oCAAoC;IACvC,mBAAmB,CAAgC;IACnD,qBAAqB,CAAkC;IACvD,cAAc,CAAiB;IAEvC,YACE,mBAAkD,EAClD,qBAAsD,EACtD,cAA8B;QAE9B,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;QAC/C,IAAI,CAAC,qBAAqB,GAAG,qBAAqB,CAAC;QACnD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,yBAAyB,CAAC,MAAiB,EAAE,WAA0C;QAC3F,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAEpE,IAAI,UAAU,KAAK,UAAU,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACpD,CAAC;QAED,uDAAuD;IACzD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,MAAiB,EAAE,WAA0C;QAClF,yEAAyE;QACzE,sFAAsF;QACtF,IAAI,WAAW,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;YACtD,MAAM,IAAI,uBAAuB,CAAC,EAAC,IAAI,EAAE,2BAA2B,CAAC,qBAAqB,EAAC,CAAC,CAAC;QAC/F,CAAC;QAED,uFAAuF;QACvF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/slashingProtection/attestation/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BLSPubkey } from "@lodestar/types";
|
|
1
|
+
import { BLSPubkey, Epoch } from "@lodestar/types";
|
|
2
2
|
import { IDistanceStore, IMinMaxSurround, MinMaxSurroundAttestation } from "./interface.js";
|
|
3
3
|
export declare class MinMaxSurround implements IMinMaxSurround {
|
|
4
4
|
private store;
|
|
@@ -6,6 +6,8 @@ export declare class MinMaxSurround implements IMinMaxSurround {
|
|
|
6
6
|
constructor(store: IDistanceStore, options?: {
|
|
7
7
|
maxEpochLookback?: number;
|
|
8
8
|
});
|
|
9
|
+
/** Lowest epoch with a min-span entry after inserting an attestation with `sourceEpoch` */
|
|
10
|
+
minSpanCoverageStart(sourceEpoch: Epoch): Epoch;
|
|
9
11
|
assertNoSurround(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void>;
|
|
10
12
|
insertAttestation(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void>;
|
|
11
13
|
private updateMinSpan;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minMaxSurround.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/minMaxSurround/minMaxSurround.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"minMaxSurround.d.ts","sourceRoot":"","sources":["../../../src/slashingProtection/minMaxSurround/minMaxSurround.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAgB,cAAc,EAAE,eAAe,EAAE,yBAAyB,EAAC,MAAM,gBAAgB,CAAC;AAsBzG,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,gBAAgB,CAAS;IAEjC,YAAY,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAC,EAGvE;IAED,2FAA2F;IAC3F,oBAAoB,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,CAE9C;IAEK,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/F;IAEK,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;YAIa,aAAa;YAkBb,oBAAoB;YAcpB,aAAa;YAgBb,mBAAmB;CAWlC"}
|
|
@@ -5,7 +5,8 @@ import { SurroundAttestationError, SurroundAttestationErrorCode } from "./errors
|
|
|
5
5
|
* Number of epochs in the past to check for surrounding attestations.
|
|
6
6
|
*
|
|
7
7
|
* This value can be limited to a reasonable high amount as Lodestar does not solely rely on this strategy but also
|
|
8
|
-
*
|
|
8
|
+
* rejects any source epoch below `minSpanCoverageStart` of the latest recorded attestation, which is the minimal
|
|
9
|
+
* strategy (formally proven safe, https://github.com/michaelsproul/slashing-proofs) relaxed by this lookback.
|
|
9
10
|
*
|
|
10
11
|
* Limiting this value is required due to practical reasons as otherwise there would be a min-span DB read and write
|
|
11
12
|
* for each validator from current epoch until genesis which massively increases DB size and causes I/O lag, resulting in
|
|
@@ -23,6 +24,10 @@ export class MinMaxSurround {
|
|
|
23
24
|
this.store = store;
|
|
24
25
|
this.maxEpochLookback = options?.maxEpochLookback ?? DEFAULT_MAX_EPOCH_LOOKBACK;
|
|
25
26
|
}
|
|
27
|
+
/** Lowest epoch with a min-span entry after inserting an attestation with `sourceEpoch` */
|
|
28
|
+
minSpanCoverageStart(sourceEpoch) {
|
|
29
|
+
return Math.max(0, sourceEpoch - 1 - this.maxEpochLookback);
|
|
30
|
+
}
|
|
26
31
|
async assertNoSurround(pubKey, attestation) {
|
|
27
32
|
await this.assertNotSurrounding(pubKey, attestation);
|
|
28
33
|
await this.assertNotSurrounded(pubKey, attestation);
|
|
@@ -34,7 +39,7 @@ export class MinMaxSurround {
|
|
|
34
39
|
// min span
|
|
35
40
|
async updateMinSpan(pubKey, attestation) {
|
|
36
41
|
await this.assertNotSurrounding(pubKey, attestation);
|
|
37
|
-
const untilEpoch =
|
|
42
|
+
const untilEpoch = this.minSpanCoverageStart(attestation.sourceEpoch);
|
|
38
43
|
const values = [];
|
|
39
44
|
for (let epoch = attestation.sourceEpoch - 1; epoch >= untilEpoch; epoch--) {
|
|
40
45
|
const minSpan = await this.store.minSpan.get(pubKey, epoch);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minMaxSurround.js","sourceRoot":"","sources":["../../../src/slashingProtection/minMaxSurround/minMaxSurround.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,wBAAwB,EAAE,4BAA4B,EAAC,MAAM,aAAa,CAAC;AAGnF,+CAA+C;AAC/C,gEAAgE;AAEhE
|
|
1
|
+
{"version":3,"file":"minMaxSurround.js","sourceRoot":"","sources":["../../../src/slashingProtection/minMaxSurround/minMaxSurround.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodestar/validator",
|
|
3
|
-
"version": "1.48.0-dev.
|
|
3
|
+
"version": "1.48.0-dev.df6a2aa429",
|
|
4
4
|
"description": "A Typescript implementation of the validator client",
|
|
5
5
|
"author": "ChainSafe Systems",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,21 +50,21 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@chainsafe/lodestar-z": "catalog:",
|
|
52
52
|
"@chainsafe/ssz": "^1.6.3",
|
|
53
|
-
"@lodestar/api": "^1.48.0-dev.
|
|
54
|
-
"@lodestar/config": "^1.48.0-dev.
|
|
55
|
-
"@lodestar/db": "^1.48.0-dev.
|
|
56
|
-
"@lodestar/params": "^1.48.0-dev.
|
|
57
|
-
"@lodestar/state-transition": "^1.48.0-dev.
|
|
58
|
-
"@lodestar/types": "^1.48.0-dev.
|
|
59
|
-
"@lodestar/utils": "^1.48.0-dev.
|
|
53
|
+
"@lodestar/api": "^1.48.0-dev.df6a2aa429",
|
|
54
|
+
"@lodestar/config": "^1.48.0-dev.df6a2aa429",
|
|
55
|
+
"@lodestar/db": "^1.48.0-dev.df6a2aa429",
|
|
56
|
+
"@lodestar/params": "^1.48.0-dev.df6a2aa429",
|
|
57
|
+
"@lodestar/state-transition": "^1.48.0-dev.df6a2aa429",
|
|
58
|
+
"@lodestar/types": "^1.48.0-dev.df6a2aa429",
|
|
59
|
+
"@lodestar/utils": "^1.48.0-dev.df6a2aa429",
|
|
60
60
|
"strict-event-emitter-types": "^2.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@lodestar/logger": "^1.48.0-dev.
|
|
64
|
-
"@lodestar/spec-test-util": "^1.48.0-dev.
|
|
65
|
-
"@lodestar/test-utils": "^1.48.0-dev.
|
|
63
|
+
"@lodestar/logger": "^1.48.0-dev.df6a2aa429",
|
|
64
|
+
"@lodestar/spec-test-util": "^1.48.0-dev.df6a2aa429",
|
|
65
|
+
"@lodestar/test-utils": "^1.48.0-dev.df6a2aa429",
|
|
66
66
|
"@vekexasia/bigint-buffer2": "^1.1.1",
|
|
67
67
|
"rimraf": "^4.4.1"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "ce162bda2d465c3ad2b2bc889ebeb0a6beb76d41"
|
|
70
70
|
}
|
|
@@ -41,6 +41,18 @@ export class AttestationByTargetRepository {
|
|
|
41
41
|
return attestations.map((attestation) => this.type.deserialize(attestation));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/** Attestation with the highest target epoch recorded for `pubkey`, or null if none */
|
|
45
|
+
async getLatest(pubkey: BLSPubkey): Promise<SlashingProtectionAttestation | null> {
|
|
46
|
+
const [att] = await this.db.values({
|
|
47
|
+
gte: this.encodeKey(pubkey, 0),
|
|
48
|
+
lt: this.encodeKey(pubkey, Number.MAX_SAFE_INTEGER),
|
|
49
|
+
reverse: true,
|
|
50
|
+
limit: 1,
|
|
51
|
+
bucketId: this.bucketId,
|
|
52
|
+
});
|
|
53
|
+
return att ? this.type.deserialize(att) : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
async get(pubkey: BLSPubkey, targetEpoch: Epoch): Promise<SlashingProtectionAttestation | null> {
|
|
45
57
|
const att = await this.db.get(this.encodeKey(pubkey, targetEpoch), this.dbReqOpts);
|
|
46
58
|
return att && this.type.deserialize(att);
|
|
@@ -29,6 +29,11 @@ export enum InvalidAttestationErrorCode {
|
|
|
29
29
|
* bound on target epochs for this validator.
|
|
30
30
|
*/
|
|
31
31
|
TARGET_LESS_THAN_OR_EQ_LOWER_BOUND = "ERR_INVALID_ATTESTATION_TARGET_LESS_THAN_OR_EQ_LOWER_BOUND",
|
|
32
|
+
/**
|
|
33
|
+
* The attestation is invalid because its source epoch is below the min-max span lookback window of the
|
|
34
|
+
* latest attestation of this validator, where a surround vote could not be detected.
|
|
35
|
+
*/
|
|
36
|
+
SOURCE_BELOW_MIN_SPAN_LOOKBACK = "ERR_INVALID_ATTESTATION_SOURCE_BELOW_MIN_SPAN_LOOKBACK",
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
type InvalidAttestationErrorType =
|
|
@@ -61,6 +66,11 @@ type InvalidAttestationErrorType =
|
|
|
61
66
|
code: InvalidAttestationErrorCode.TARGET_LESS_THAN_OR_EQ_LOWER_BOUND;
|
|
62
67
|
targetEpoch: Epoch;
|
|
63
68
|
minTargetEpoch: Epoch;
|
|
69
|
+
}
|
|
70
|
+
| {
|
|
71
|
+
code: InvalidAttestationErrorCode.SOURCE_BELOW_MIN_SPAN_LOOKBACK;
|
|
72
|
+
sourceEpoch: Epoch;
|
|
73
|
+
minSourceEpoch: Epoch;
|
|
64
74
|
};
|
|
65
75
|
|
|
66
76
|
export class InvalidAttestationError extends LodestarError<InvalidAttestationErrorType> {}
|
|
@@ -56,9 +56,16 @@ export class SlashingProtectionAttestationService {
|
|
|
56
56
|
throw new InvalidAttestationError({code: InvalidAttestationErrorCode.SOURCE_EXCEEDS_TARGET});
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
const latestAtt = await this.attestationByTarget.getLatest(pubKey);
|
|
60
|
+
|
|
59
61
|
// Check for a double vote. Namely, an existing attestation with the same target epoch,
|
|
60
|
-
// and a different signing root.
|
|
61
|
-
|
|
62
|
+
// and a different signing root. No db read needed if the latest attestation has a lower target epoch.
|
|
63
|
+
let sameTargetAtt: SlashingProtectionAttestation | null = null;
|
|
64
|
+
if (latestAtt && latestAtt.targetEpoch === attestation.targetEpoch) {
|
|
65
|
+
sameTargetAtt = latestAtt;
|
|
66
|
+
} else if (latestAtt && latestAtt.targetEpoch > attestation.targetEpoch) {
|
|
67
|
+
sameTargetAtt = await this.attestationByTarget.get(pubKey, attestation.targetEpoch);
|
|
68
|
+
}
|
|
62
69
|
if (sameTargetAtt) {
|
|
63
70
|
// Interchange format allows for attestations without signing_root, then assume root is equal
|
|
64
71
|
if (isEqualNonZeroRoot(sameTargetAtt.signingRoot, attestation.signingRoot)) {
|
|
@@ -71,6 +78,20 @@ export class SlashingProtectionAttestationService {
|
|
|
71
78
|
});
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
// Min-span entries only exist within the lookback window below each recorded source epoch, a surround vote
|
|
82
|
+
// with an older source epoch is undetectable by min-max surround and must be rejected outright. Recorded
|
|
83
|
+
// attestations are surround-free, so the latest one has the highest source epoch and the widest window.
|
|
84
|
+
if (latestAtt) {
|
|
85
|
+
const minSourceEpoch = this.minMaxSurround.minSpanCoverageStart(latestAtt.sourceEpoch);
|
|
86
|
+
if (attestation.sourceEpoch < minSourceEpoch) {
|
|
87
|
+
throw new InvalidAttestationError({
|
|
88
|
+
code: InvalidAttestationErrorCode.SOURCE_BELOW_MIN_SPAN_LOOKBACK,
|
|
89
|
+
sourceEpoch: attestation.sourceEpoch,
|
|
90
|
+
minSourceEpoch,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
74
95
|
// Check for a surround vote
|
|
75
96
|
try {
|
|
76
97
|
await this.minMaxSurround.assertNoSurround(pubKey, attestation);
|
|
@@ -143,6 +164,26 @@ export class SlashingProtectionAttestationService {
|
|
|
143
164
|
* Interchange import / export functionality
|
|
144
165
|
*/
|
|
145
166
|
async importAttestations(pubkey: BLSPubkey, attestations: SlashingProtectionAttestation[]): Promise<void> {
|
|
167
|
+
// Min-max surround misses a surround vote beyond its lookback, require the highest target attestation to
|
|
168
|
+
// have the highest source epoch as `checkAttestation` relies on it
|
|
169
|
+
let latestAtt = await this.attestationByTarget.getLatest(pubkey);
|
|
170
|
+
let maxSourceAtt = latestAtt;
|
|
171
|
+
for (const attestation of attestations) {
|
|
172
|
+
if (latestAtt === null || attestation.targetEpoch >= latestAtt.targetEpoch) {
|
|
173
|
+
latestAtt = attestation;
|
|
174
|
+
}
|
|
175
|
+
if (maxSourceAtt === null || attestation.sourceEpoch > maxSourceAtt.sourceEpoch) {
|
|
176
|
+
maxSourceAtt = attestation;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (latestAtt && maxSourceAtt && latestAtt.sourceEpoch < maxSourceAtt.sourceEpoch) {
|
|
180
|
+
throw new InvalidAttestationError({
|
|
181
|
+
code: InvalidAttestationErrorCode.NEW_SURROUNDS_PREV,
|
|
182
|
+
attestation: latestAtt,
|
|
183
|
+
prev: maxSourceAtt,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
146
187
|
await this.attestationByTarget.set(pubkey, attestations);
|
|
147
188
|
|
|
148
189
|
// Pre-compute spans for all attestations
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {BLSPubkey} from "@lodestar/types";
|
|
1
|
+
import {BLSPubkey, Epoch} from "@lodestar/types";
|
|
2
2
|
import {SurroundAttestationError, SurroundAttestationErrorCode} from "./errors.js";
|
|
3
3
|
import {DistanceEntry, IDistanceStore, IMinMaxSurround, MinMaxSurroundAttestation} from "./interface.js";
|
|
4
4
|
|
|
@@ -9,7 +9,8 @@ import {DistanceEntry, IDistanceStore, IMinMaxSurround, MinMaxSurroundAttestatio
|
|
|
9
9
|
* Number of epochs in the past to check for surrounding attestations.
|
|
10
10
|
*
|
|
11
11
|
* This value can be limited to a reasonable high amount as Lodestar does not solely rely on this strategy but also
|
|
12
|
-
*
|
|
12
|
+
* rejects any source epoch below `minSpanCoverageStart` of the latest recorded attestation, which is the minimal
|
|
13
|
+
* strategy (formally proven safe, https://github.com/michaelsproul/slashing-proofs) relaxed by this lookback.
|
|
13
14
|
*
|
|
14
15
|
* Limiting this value is required due to practical reasons as otherwise there would be a min-span DB read and write
|
|
15
16
|
* for each validator from current epoch until genesis which massively increases DB size and causes I/O lag, resulting in
|
|
@@ -30,6 +31,11 @@ export class MinMaxSurround implements IMinMaxSurround {
|
|
|
30
31
|
this.maxEpochLookback = options?.maxEpochLookback ?? DEFAULT_MAX_EPOCH_LOOKBACK;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/** Lowest epoch with a min-span entry after inserting an attestation with `sourceEpoch` */
|
|
35
|
+
minSpanCoverageStart(sourceEpoch: Epoch): Epoch {
|
|
36
|
+
return Math.max(0, sourceEpoch - 1 - this.maxEpochLookback);
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
async assertNoSurround(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
|
|
34
40
|
await this.assertNotSurrounding(pubKey, attestation);
|
|
35
41
|
await this.assertNotSurrounded(pubKey, attestation);
|
|
@@ -45,7 +51,7 @@ export class MinMaxSurround implements IMinMaxSurround {
|
|
|
45
51
|
private async updateMinSpan(pubKey: BLSPubkey, attestation: MinMaxSurroundAttestation): Promise<void> {
|
|
46
52
|
await this.assertNotSurrounding(pubKey, attestation);
|
|
47
53
|
|
|
48
|
-
const untilEpoch =
|
|
54
|
+
const untilEpoch = this.minSpanCoverageStart(attestation.sourceEpoch);
|
|
49
55
|
|
|
50
56
|
const values: DistanceEntry[] = [];
|
|
51
57
|
for (let epoch = attestation.sourceEpoch - 1; epoch >= untilEpoch; epoch--) {
|