-
-
Notifications
You must be signed in to change notification settings - Fork 315
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: check gas limit in header received from builder
- Loading branch information
Showing
9 changed files
with
217 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {BLSPubkey, Epoch, bellatrix} from "@lodestar/types"; | ||
import {toPubkeyHex} from "@lodestar/utils"; | ||
|
||
const REGISTRATION_PRESERVE_EPOCHS = 2; | ||
|
||
export type ValidatorRegistration = { | ||
epoch: Epoch; | ||
/** Preferred gas limit of validator */ | ||
gasLimit: number; | ||
}; | ||
|
||
export class ValidatorRegistrationCache { | ||
private readonly registrationByValidatorPubkey: Map<string, ValidatorRegistration>; | ||
constructor() { | ||
this.registrationByValidatorPubkey = new Map(); | ||
} | ||
|
||
add(epoch: Epoch, {pubkey, gasLimit}: bellatrix.ValidatorRegistrationV1): void { | ||
this.registrationByValidatorPubkey.set(toPubkeyHex(pubkey), {epoch, gasLimit}); | ||
} | ||
|
||
prune(epoch: Epoch): void { | ||
for (const [pubkeyHex, registration] of this.registrationByValidatorPubkey.entries()) { | ||
// We only retain an registrations for REGISTRATION_PRESERVE_EPOCHS epochs | ||
if (registration.epoch + REGISTRATION_PRESERVE_EPOCHS < epoch) { | ||
this.registrationByValidatorPubkey.delete(pubkeyHex); | ||
} | ||
} | ||
} | ||
|
||
get(pubkey: BLSPubkey): ValidatorRegistration | undefined { | ||
return this.registrationByValidatorPubkey.get(toPubkeyHex(pubkey)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* Calculates expected gas limit based on parent gas limit and target gas limit | ||
*/ | ||
export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: number): number { | ||
const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / 1024) - 1, 0); | ||
|
||
if (targetGasLimit > parentGasLimit) { | ||
const gasDiff = targetGasLimit - parentGasLimit; | ||
return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference); | ||
} | ||
|
||
const gasDiff = parentGasLimit - targetGasLimit; | ||
return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference); | ||
} |
58 changes: 58 additions & 0 deletions
58
packages/beacon-node/test/unit/execution/builder/cache.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import {ssz} from "@lodestar/types"; | ||
import {beforeEach, describe, expect, it} from "vitest"; | ||
import {ValidatorRegistrationCache} from "../../../../src/execution/builder/cache.js"; | ||
|
||
describe("ValidatorRegistrationCache", () => { | ||
const gasLimit1 = 30000000; | ||
const gasLimit2 = 36000000; | ||
|
||
const validatorPubkey1 = new Uint8Array(48).fill(1); | ||
const validatorPubkey2 = new Uint8Array(48).fill(2); | ||
|
||
const validatorRegistration1 = ssz.bellatrix.ValidatorRegistrationV1.defaultValue(); | ||
validatorRegistration1.pubkey = validatorPubkey1; | ||
validatorRegistration1.gasLimit = gasLimit1; | ||
|
||
const validatorRegistration2 = ssz.bellatrix.ValidatorRegistrationV1.defaultValue(); | ||
validatorRegistration2.pubkey = validatorPubkey2; | ||
validatorRegistration2.gasLimit = gasLimit2; | ||
|
||
let cache: ValidatorRegistrationCache; | ||
|
||
beforeEach(() => { | ||
// max 2 items | ||
cache = new ValidatorRegistrationCache(); | ||
cache.add(1, validatorRegistration1); | ||
cache.add(3, validatorRegistration2); | ||
}); | ||
|
||
it("get for registered validator", () => { | ||
expect(cache.get(validatorPubkey1)?.gasLimit).toBe(gasLimit1); | ||
}); | ||
|
||
it("get for unknown validator", () => { | ||
const unknownValidatorPubkey = new Uint8Array(48).fill(3); | ||
expect(cache.get(unknownValidatorPubkey)).toBe(undefined); | ||
}); | ||
|
||
it("override and get latest", () => { | ||
const newGasLimit = 60000000; | ||
const registration = ssz.bellatrix.ValidatorRegistrationV1.defaultValue(); | ||
registration.pubkey = validatorPubkey1; | ||
registration.gasLimit = newGasLimit; | ||
|
||
cache.add(5, registration); | ||
|
||
expect(cache.get(validatorPubkey1)?.gasLimit).toBe(newGasLimit); | ||
}); | ||
|
||
it("prune", () => { | ||
cache.prune(4); | ||
|
||
// No registration as it has been pruned | ||
expect(cache.get(validatorPubkey1)).toBe(undefined); | ||
|
||
// Registration hasn't been pruned | ||
expect(cache.get(validatorPubkey2)?.gasLimit).toBe(gasLimit2); | ||
}); | ||
}); |
66 changes: 66 additions & 0 deletions
66
packages/beacon-node/test/unit/execution/builder/utils.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {describe, expect, it} from "vitest"; | ||
import {getExpectedGasLimit} from "../../../../src/execution/builder/utils.js"; | ||
|
||
describe("execution / builder / utils", () => { | ||
describe("getExpectedGasLimit", () => { | ||
const testCases: { | ||
name: string; | ||
parentGasLimit: number; | ||
targetGasLimit: number; | ||
expected: number; | ||
}[] = [ | ||
{ | ||
name: "Increase within limit", | ||
parentGasLimit: 30000000, | ||
targetGasLimit: 30000100, | ||
expected: 30000100, | ||
}, | ||
{ | ||
name: "Increase exceeding limit", | ||
parentGasLimit: 30000000, | ||
targetGasLimit: 36000000, | ||
expected: 30029295, // maxGasLimitDifference = (30000000 / 1024) - 1 = 29295 | ||
}, | ||
{ | ||
name: "Decrease within limit", | ||
parentGasLimit: 30000000, | ||
targetGasLimit: 29999990, | ||
expected: 29999990, | ||
}, | ||
{ | ||
name: "Decrease exceeding limit", | ||
parentGasLimit: 36000000, | ||
targetGasLimit: 30000000, | ||
expected: 35964845, // maxGasLimitDifference = (36000000 / 1024) - 1 = 35155 | ||
}, | ||
{ | ||
name: "Target equals parent", | ||
parentGasLimit: 30000000, | ||
targetGasLimit: 30000000, | ||
expected: 30000000, // No change | ||
}, | ||
{ | ||
name: "Very small parent gas limit", | ||
parentGasLimit: 1025, | ||
targetGasLimit: 2000, | ||
expected: 1025, | ||
}, | ||
{ | ||
name: "Target far below parent but limited", | ||
parentGasLimit: 30000000, | ||
targetGasLimit: 10000000, | ||
expected: 29970705, // maxGasLimitDifference = (30000000 / 1024) - 1 = 29295 | ||
}, | ||
{ | ||
name: "Parent gas limit under flows", | ||
parentGasLimit: 1023, | ||
targetGasLimit: 30000000, | ||
expected: 1023, | ||
}, | ||
]; | ||
|
||
it.each(testCases)("$name", ({parentGasLimit, targetGasLimit, expected}) => { | ||
expect(getExpectedGasLimit(parentGasLimit, targetGasLimit)).toBe(expected); | ||
}); | ||
}); | ||
}); |