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

fix: attestations are requested based on their proposal not just slot #8442

Merged
merged 39 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b51e908
feat: cleanup publisher
LHerskind Aug 22, 2024
da2eb7a
refactor: get rid of timetraveler from l1-publisher
LHerskind Aug 28, 2024
3388966
feat: revert if timestamp in future
LHerskind Aug 28, 2024
13a60a3
feat: including txhashes explicitly in the rollup attestations
Maddiaa0 Aug 29, 2024
86026f2
temp
Maddiaa0 Aug 30, 2024
f3eac5b
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Aug 30, 2024
fc7a04a
temp
Maddiaa0 Aug 30, 2024
9eed298
temp
Maddiaa0 Sep 2, 2024
cc09455
temp
Maddiaa0 Sep 2, 2024
06f950f
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 2, 2024
4727cd9
temp: get passing with txhash payloads
Maddiaa0 Sep 3, 2024
b4c2a46
fix: make sure transactions are available in the tx pool
Maddiaa0 Sep 5, 2024
4a8d178
chore: remove logs
Maddiaa0 Sep 5, 2024
b4324fc
fmt
Maddiaa0 Sep 5, 2024
052641a
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 5, 2024
a803a94
🪿
Maddiaa0 Sep 5, 2024
164c117
chore: validator tests
Maddiaa0 Sep 6, 2024
c10260c
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 6, 2024
045af5a
clean
Maddiaa0 Sep 6, 2024
73d26ec
🧹
Maddiaa0 Sep 6, 2024
d358228
chore: fix sequencing tests
Maddiaa0 Sep 7, 2024
4b31953
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 7, 2024
2e3f80b
fmt solidity
Maddiaa0 Sep 7, 2024
5734006
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 7, 2024
1bde1fe
fix: test hash
Maddiaa0 Sep 8, 2024
29fa090
fix: attestations are requested based on their proposal not just slot
Maddiaa0 Sep 8, 2024
7a50a2b
exp: adjust test nodes
Maddiaa0 Sep 8, 2024
1c2b151
fix: use abi.encode vs encodePacked
Maddiaa0 Sep 11, 2024
e6e7f6b
fix
Maddiaa0 Sep 11, 2024
6f417fc
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 11, 2024
cde6283
fix: merge fix
Maddiaa0 Sep 11, 2024
8290c99
fmt
Maddiaa0 Sep 11, 2024
87aeb1f
Merge branch 'md/check-tx-requests-before-signing' into md/address-at…
Maddiaa0 Sep 11, 2024
1452017
Merge branch 'master' into md/check-tx-requests-before-signing
Maddiaa0 Sep 11, 2024
13d4f2b
Merge branch 'md/check-tx-requests-before-signing' into md/address-at…
Maddiaa0 Sep 11, 2024
1e9e6db
Merge branch 'master' into md/address-attestation-pool-by-proposal
Maddiaa0 Sep 11, 2024
7943cf1
Merge branch 'master' into md/address-attestation-pool-by-proposal
Maddiaa0 Sep 19, 2024
b2ee826
fix
Maddiaa0 Sep 19, 2024
92f5d4d
Merge branch 'master' into md/address-attestation-pool-by-proposal
Maddiaa0 Sep 27, 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
3 changes: 2 additions & 1 deletion yarn-project/p2p/src/attestation_pool/attestation_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export interface AttestationPool {
* Retrieve all of the attestations observed pertaining to a given slot
*
* @param slot - The slot to query
* @param proposalId - The proposal to query
* @return BlockAttestations
*/
getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]>;
getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]>;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Fr } from '@aztec/foundation/fields';

import { type PrivateKeyAccount } from 'viem';

import { InMemoryAttestationPool } from './memory_attestation_pool.js';
Expand All @@ -16,19 +18,22 @@ describe('MemoryAttestationPool', () => {

it('should add attestation to pool', async () => {
const slotNumber = 420;
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber)));
const archive = Fr.random();
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));

const proposalId = attestations[0].p2pMessageIdentifier.toString();

await ap.addAttestations(attestations);

const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber));
const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);

expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
expect(retreivedAttestations).toEqual(attestations);

// Delete by slot
await ap.deleteAttestationsForSlot(BigInt(slotNumber));

const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber));
const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestationsAfterDelete.length).toBe(0);
});

Expand All @@ -40,8 +45,9 @@ describe('MemoryAttestationPool', () => {

for (const attestation of attestations) {
const slot = attestation.payload.header.globalVariables.slotNumber;
const proposalId = attestation.p2pMessageIdentifier.toString();

const retreivedAttestations = await ap.getAttestationsForSlot(slot.toBigInt());
const retreivedAttestations = await ap.getAttestationsForSlot(slot.toBigInt(), proposalId);
expect(retreivedAttestations.length).toBe(1);
expect(retreivedAttestations[0]).toEqual(attestation);
expect(retreivedAttestations[0].payload.header.globalVariables.slotNumber).toEqual(slot);
Expand All @@ -50,17 +56,55 @@ describe('MemoryAttestationPool', () => {

it('Should delete attestations', async () => {
const slotNumber = 420;
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber)));
const archive = Fr.random();
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
const proposalId = attestations[0].p2pMessageIdentifier.toString();

await ap.addAttestations(attestations);

const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber));
const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
expect(retreivedAttestations).toEqual(attestations);

await ap.deleteAttestations(attestations);

const gottenAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber));
const gottenAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(gottenAfterDelete.length).toBe(0);
});

it('Should blanket delete attestations per slot', async () => {
const slotNumber = 420;
const archive = Fr.random();
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
const proposalId = attestations[0].p2pMessageIdentifier.toString();

await ap.addAttestations(attestations);

const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
expect(retreivedAttestations).toEqual(attestations);

await ap.deleteAttestationsForSlot(BigInt(slotNumber));

const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestationsAfterDelete.length).toBe(0);
});

it('Should blanket delete attestations per slot and proposal', async () => {
const slotNumber = 420;
const archive = Fr.random();
const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
const proposalId = attestations[0].p2pMessageIdentifier.toString();

await ap.addAttestations(attestations);

const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
expect(retreivedAttestations).toEqual(attestations);

await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);

const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
expect(retreivedAttestationsAfterDelete.length).toBe(0);
});
});
62 changes: 50 additions & 12 deletions yarn-project/p2p/src/attestation_pool/memory_attestation_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,34 @@ import { createDebugLogger } from '@aztec/foundation/log';
import { type AttestationPool } from './attestation_pool.js';

export class InMemoryAttestationPool implements AttestationPool {
private attestations: Map</*slot=*/ bigint, Map</*address=*/ string, BlockAttestation>>;
private attestations: Map</*slot=*/ bigint, Map</*proposalId*/ string, Map</*address=*/ string, BlockAttestation>>>;

constructor(private log = createDebugLogger('aztec:attestation_pool')) {
this.attestations = new Map();
}

public getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]> {
public getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
const slotAttestationMap = this.attestations.get(slot);
if (slotAttestationMap) {
return Promise.resolve(Array.from(slotAttestationMap.values()));
} else {
return Promise.resolve([]);
const proposalAttestationMap = slotAttestationMap.get(proposalId);
if (proposalAttestationMap) {
return Promise.resolve(Array.from(proposalAttestationMap.values()));
}
}
return Promise.resolve([]);
}

public addAttestations(attestations: BlockAttestation[]): Promise<void> {
for (const attestation of attestations) {
// Perf: order and group by slot before insertion
const slotNumber = attestation.payload.header.globalVariables.slotNumber;

const proposalId = attestation.p2pMessageIdentifier.toString();
const address = attestation.getSender();

const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber.toBigInt());
slotAttestationMap.set(address.toString(), attestation);
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
proposalAttestationMap.set(address.toString(), attestation);

this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`);
}
Expand All @@ -41,14 +45,27 @@ export class InMemoryAttestationPool implements AttestationPool {
return Promise.resolve();
}

public deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void> {
LHerskind marked this conversation as resolved.
Show resolved Hide resolved
const slotAttestationMap = this.attestations.get(slot);
if (slotAttestationMap) {
slotAttestationMap.delete(proposalId);
this.log.verbose(`Removed attestation for slot ${slot}`);
}
return Promise.resolve();
}

public deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
LHerskind marked this conversation as resolved.
Show resolved Hide resolved
for (const attestation of attestations) {
const slotNumber = attestation.payload.header.globalVariables.slotNumber;
const slotAttestationMap = this.attestations.get(slotNumber.toBigInt());
if (slotAttestationMap) {
const address = attestation.getSender();
slotAttestationMap.delete(address.toString());
this.log.verbose(`Deleted attestation for slot ${slotNumber} from ${address}`);
const proposalId = attestation.p2pMessageIdentifier.toString();
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
if (proposalAttestationMap) {
const address = attestation.getSender();
proposalAttestationMap.delete(address.toString());
this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
}
}
}
return Promise.resolve();
Expand All @@ -59,13 +76,34 @@ export class InMemoryAttestationPool implements AttestationPool {
* Get Slot or Default
*
* Fetch the slot mapping, if it does not exist, then create a mapping and return it
* @param map - The map to fetch from
* @param slot - The slot to fetch
* @returns The slot mapping
*/
function getSlotOrDefault(
map: Map<bigint, Map<string, BlockAttestation>>,
map: Map<bigint, Map<string, Map<string, BlockAttestation>>>,
slot: bigint,
): Map<string, BlockAttestation> {
): Map<string, Map<string, BlockAttestation>> {
if (!map.has(slot)) {
map.set(slot, new Map<string, BlockAttestation>());
map.set(slot, new Map<string, Map<string, BlockAttestation>>());
}
return map.get(slot)!;
}

/**
* Get Proposal or Default
*
* Fetch the proposal mapping, if it does not exist, then create a mapping and return it
* @param map - The map to fetch from
* @param proposalId - The proposal id to fetch
* @returns The proposal mapping
*/
function getProposalOrDefault(
map: Map<string, Map<string, BlockAttestation>>,
proposalId: string,
): Map<string, BlockAttestation> {
if (!map.has(proposalId)) {
map.set(proposalId, new Map<string, BlockAttestation>());
}
return map.get(proposalId)!;
}
7 changes: 5 additions & 2 deletions yarn-project/p2p/src/attestation_pool/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ export const generateAccount = () => {
* @param slot The slot number the attestation is for
* @returns A Block Attestation
*/
export const mockAttestation = async (signer: PrivateKeyAccount, slot: number = 0): Promise<BlockAttestation> => {
export const mockAttestation = async (
signer: PrivateKeyAccount,
slot: number = 0,
archive: Fr = Fr.random(),
): Promise<BlockAttestation> => {
// Use arbitrary numbers for all other than slot
const header = makeHeader(1, 2, slot);
const archive = Fr.random();
const txs = [0, 1, 2, 3, 4, 5].map(() => TxHash.random());

const payload = new ConsensusPayload(header, archive, txs);
Expand Down
7 changes: 4 additions & 3 deletions yarn-project/p2p/src/client/p2p_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ export interface P2P {
* Queries the Attestation pool for attestations for the given slot
*
* @param slot - the slot to query
* @param proposalId - the proposal id to query
* @returns BlockAttestations
*/
getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]>;
getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]>;

/**
* Registers a callback from the validator client that determines how to behave when
Expand Down Expand Up @@ -281,8 +282,8 @@ export class P2PClient implements P2P {
return this.p2pService.propagate(proposal);
}

public getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]> {
return Promise.resolve(this.attestationPool.getAttestationsForSlot(slot));
public getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
return Promise.resolve(this.attestationPool.getAttestationsForSlot(slot, proposalId));
}

// REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/validator-client/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,13 @@ export class ValidatorClient implements Validator {
const slot = proposal.payload.header.globalVariables.slotNumber.toBigInt();
this.log.info(`Waiting for ${numberOfRequiredAttestations} attestations for slot: ${slot}`);

const proposalId = proposal.p2pMessageIdentifier.toString();
const myAttestation = await this.validationService.attestToProposal(proposal);

const startTime = Date.now();

while (true) {
const attestations = [myAttestation, ...(await this.p2pClient.getAttestationsForSlot(slot))];
const attestations = [myAttestation, ...(await this.p2pClient.getAttestationsForSlot(slot, proposalId))];

if (attestations.length >= numberOfRequiredAttestations) {
this.log.info(`Collected all ${numberOfRequiredAttestations} attestations for slot, ${slot}`);
Expand Down
Loading