Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(val): reject proposals not for the current or next slot #10450

Merged
merged 36 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e2d7829
feat: delete attestations older than a slot
Maddiaa0 Nov 30, 2024
67ea59c
fmt
Maddiaa0 Nov 30, 2024
b95bcef
test: attestation pool pruning
Maddiaa0 Nov 30, 2024
f6ac466
fmt
Maddiaa0 Nov 30, 2024
e67eaef
feat: epoch cache, do not attest if not in committee or from current …
Maddiaa0 Nov 30, 2024
0265e47
cleanup
Maddiaa0 Nov 30, 2024
6a795ea
test: validator client tests
Maddiaa0 Nov 30, 2024
50eaa4c
fmt
Maddiaa0 Nov 30, 2024
98b118a
fmt + test
Maddiaa0 Dec 2, 2024
6507c02
tmp
Maddiaa0 Dec 3, 2024
97f35c3
fix: next and current slot
Maddiaa0 Dec 5, 2024
7003114
fmt
Maddiaa0 Dec 5, 2024
452e781
Merge branch 'master' into md/epoch-cache--
Maddiaa0 Dec 5, 2024
8c8df0c
post merge fix
Maddiaa0 Dec 5, 2024
e2b43fb
fix: ordering
Maddiaa0 Dec 5, 2024
e0976bb
fix: ordering
Maddiaa0 Dec 5, 2024
cda7e99
temp
Maddiaa0 Dec 5, 2024
da87b55
fix
Maddiaa0 Dec 5, 2024
5fc9900
fix: linter and test
just-mitch Dec 5, 2024
17353cf
Merge branch 'master' into md/epoch-cache--
just-mitch Dec 5, 2024
bcbcccd
fix: merge conflicts
just-mitch Dec 5, 2024
1309414
fix: function ordering and p2p tests
just-mitch Dec 5, 2024
6aba551
fix: reex test - sending same proposal twice in one slot
Maddiaa0 Dec 6, 2024
82da16b
fix: for a slot ci runner, decrease the time jump length
Maddiaa0 Dec 6, 2024
13ec8e4
fix: epoch cache flake
Maddiaa0 Dec 6, 2024
1b71b84
Merge branch 'md/epoch-cache--' into md/reject-not-for-current-slot
Maddiaa0 Dec 6, 2024
c8c5df6
chore: test
Maddiaa0 Dec 6, 2024
b822475
fmt
Maddiaa0 Dec 6, 2024
676b7ed
fix: in native testnet, deploy validators at genesis
Maddiaa0 Dec 6, 2024
ca99658
fix: run interleaved
Maddiaa0 Dec 6, 2024
74627af
Merge branch 'md/epoch-cache--' into md/reject-not-for-current-slot
Maddiaa0 Dec 6, 2024
e955e8d
fix: earthfile
Maddiaa0 Dec 6, 2024
38b57fc
Merge branch 'md/epoch-cache--' into md/reject-not-for-current-slot
Maddiaa0 Dec 6, 2024
6820c2a
Merge branch 'master' into md/reject-not-for-current-slot
Maddiaa0 Dec 6, 2024
54c71a7
fmt
Maddiaa0 Dec 6, 2024
49c917f
Merge branch 'master' into md/reject-not-for-current-slot
Maddiaa0 Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions yarn-project/epoch-cache/src/epoch_cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,18 @@ describe('EpochCache', () => {
// Hence the chosen values for testCommittee below

// Get validator for slot 0
let [currentValidator] = await epochCache.getProposerInCurrentOrNextSlot();
expect(currentValidator).toEqual(testCommittee[1]);
const { currentProposer } = await epochCache.getProposerInCurrentOrNextSlot();
expect(currentProposer).toEqual(testCommittee[1]);

// Move to next slot
jest.setSystemTime(initialTime + Number(SLOT_DURATION) * 1000);
[currentValidator] = await epochCache.getProposerInCurrentOrNextSlot();
expect(currentValidator).toEqual(testCommittee[1]);
const { currentProposer: nextProposer } = await epochCache.getProposerInCurrentOrNextSlot();
expect(nextProposer).toEqual(testCommittee[1]);

// Move to slot that wraps around validator set
jest.setSystemTime(initialTime + Number(SLOT_DURATION) * 3 * 1000);
[currentValidator] = await epochCache.getProposerInCurrentOrNextSlot();
expect(currentValidator).toEqual(testCommittee[0]);
const { currentProposer: nextNextProposer } = await epochCache.getProposerInCurrentOrNextSlot();
expect(nextNextProposer).toEqual(testCommittee[0]);
});

it('Should request to update the validator set when on the epoch boundary', async () => {
Expand Down
13 changes: 9 additions & 4 deletions yarn-project/epoch-cache/src/epoch_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,12 @@ export class EpochCache {
* If we are at an epoch boundary, then we can update the cache for the next epoch, this is the last check
* we do in the validator client, so we can update the cache here.
*/
async getProposerInCurrentOrNextSlot(): Promise<[EthAddress, EthAddress]> {
async getProposerInCurrentOrNextSlot(): Promise<{
currentProposer: EthAddress;
nextProposer: EthAddress;
currentSlot: bigint;
nextSlot: bigint;
}> {
// Validators are sorted by their index in the committee, and getValidatorSet will cache
const committee = await this.getCommittee();
const { slot: currentSlot, epoch: currentEpoch } = this.getEpochAndSlotNow();
Expand All @@ -176,10 +181,10 @@ export class EpochCache {
BigInt(committee.length),
);

const calculatedProposer = committee[Number(proposerIndex)];
const nextCalculatedProposer = committee[Number(nextProposerIndex)];
const currentProposer = committee[Number(proposerIndex)];
const nextProposer = committee[Number(nextProposerIndex)];

return [calculatedProposer, nextCalculatedProposer];
return { currentProposer, nextProposer, currentSlot, nextSlot };
}

/**
Expand Down
39 changes: 36 additions & 3 deletions yarn-project/validator-client/src/validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ describe('ValidationService', () => {
// mock the p2pClient.getTxStatus to return undefined for all transactions
p2pClient.getTxStatus.mockImplementation(() => undefined);
epochCache.getProposerInCurrentOrNextSlot.mockImplementation(() =>
Promise.resolve([proposal.getSender(), proposal.getSender()]),
Promise.resolve({
currentProposer: proposal.getSender(),
nextProposer: proposal.getSender(),
currentSlot: proposal.slotNumber.toBigInt(),
nextSlot: proposal.slotNumber.toBigInt() + 1n,
}),
);
epochCache.isInCommittee.mockImplementation(() => Promise.resolve(true));

Expand All @@ -119,7 +124,12 @@ describe('ValidationService', () => {

// Setup epoch cache mocks
epochCache.getProposerInCurrentOrNextSlot.mockImplementation(() =>
Promise.resolve([proposal.getSender(), proposal.getSender()]),
Promise.resolve({
currentProposer: proposal.getSender(),
nextProposer: proposal.getSender(),
currentSlot: proposal.slotNumber.toBigInt(),
nextSlot: proposal.slotNumber.toBigInt() + 1n,
}),
);
epochCache.isInCommittee.mockImplementation(() => Promise.resolve(false));

Expand All @@ -132,7 +142,30 @@ describe('ValidationService', () => {

// Setup epoch cache mocks
epochCache.getProposerInCurrentOrNextSlot.mockImplementation(() =>
Promise.resolve([EthAddress.random(), EthAddress.random()]),
Promise.resolve({
currentProposer: EthAddress.random(),
nextProposer: EthAddress.random(),
currentSlot: proposal.slotNumber.toBigInt(),
nextSlot: proposal.slotNumber.toBigInt() + 1n,
}),
);
epochCache.isInCommittee.mockImplementation(() => Promise.resolve(true));

const attestation = await validatorClient.attestToProposal(proposal);
expect(attestation).toBeUndefined();
});

it('Should not return an attestation if the proposal is not for the current or next slot', async () => {
const proposal = makeBlockProposal();

// Setup epoch cache mocks
epochCache.getProposerInCurrentOrNextSlot.mockImplementation(() =>
Promise.resolve({
currentProposer: proposal.getSender(),
nextProposer: proposal.getSender(),
currentSlot: proposal.slotNumber.toBigInt() + 20n,
nextSlot: proposal.slotNumber.toBigInt() + 21n,
}),
);
epochCache.isInCommittee.mockImplementation(() => Promise.resolve(true));

Expand Down
13 changes: 11 additions & 2 deletions yarn-project/validator-client/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,21 @@ export class ValidatorClient extends WithTracer implements Validator {
}

// Check that the proposal is from the current proposer, or the next proposer.
const [currentProposer, nextSlotProposer] = await this.epochCache.getProposerInCurrentOrNextSlot();
if (!proposal.getSender().equals(currentProposer) && !proposal.getSender().equals(nextSlotProposer)) {
const proposalSender = proposal.getSender();
const { currentProposer, nextProposer, currentSlot, nextSlot } =
await this.epochCache.getProposerInCurrentOrNextSlot();
if (!proposalSender.equals(currentProposer) && !proposalSender.equals(nextProposer)) {
this.log.verbose(`Not the current or next proposer, skipping attestation`);
return undefined;
}

// Check that the proposal is for the current or next slot
const slotNumberBigInt = proposal.slotNumber.toBigInt();
if (slotNumberBigInt !== currentSlot && slotNumberBigInt !== nextSlot) {
this.log.verbose(`Not the current or next slot, skipping attestation`);
return undefined;
}

// Check that all of the tranasctions in the proposal are available in the tx pool before attesting
this.log.verbose(`request to attest`, {
archive: proposal.payload.archive.toString(),
Expand Down
Loading