@aztec/p2p 4.0.0-nightly.20260112 → 4.0.0-nightly.20260113
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/client/interface.d.ts +18 -5
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +9 -12
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +59 -103
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +61 -42
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +225 -262
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +21 -18
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +113 -108
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +17 -16
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +89 -128
- package/dest/mem_pools/attestation_pool/mocks.d.ts +7 -6
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +9 -8
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -4
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +12 -10
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +5 -5
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +5 -5
- package/dest/msg_validators/index.d.ts +2 -2
- package/dest/msg_validators/index.d.ts.map +1 -1
- package/dest/msg_validators/index.js +1 -1
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/block_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +9 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +6 -0
- package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
- package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/index.js +3 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -0
- package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
- package/dest/msg_validators/{block_proposal_validator/block_proposal_validator.js → proposal_validator/proposal_validator.js} +19 -21
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +23 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -0
- package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +183 -0
- package/dest/services/dummy_service.d.ts +6 -2
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +3 -0
- package/dest/services/encoding.d.ts +1 -1
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +4 -2
- package/dest/services/libp2p/libp2p_service.d.ts +26 -10
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +218 -88
- package/dest/services/service.d.ts +16 -3
- package/dest/services/service.d.ts.map +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +25 -11
- package/dest/testbench/worker_client_manager.d.ts +1 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +6 -1
- package/package.json +14 -14
- package/src/client/interface.ts +19 -4
- package/src/client/p2p_client.ts +69 -110
- package/src/mem_pools/attestation_pool/attestation_pool.ts +68 -41
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +231 -287
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +162 -140
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +141 -164
- package/src/mem_pools/attestation_pool/mocks.ts +13 -9
- package/src/msg_validators/attestation_validator/attestation_validator.ts +16 -13
- package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +7 -7
- package/src/msg_validators/index.ts +1 -1
- package/src/msg_validators/proposal_validator/block_proposal_validator.ts +10 -0
- package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +13 -0
- package/src/msg_validators/proposal_validator/index.ts +3 -0
- package/src/msg_validators/{block_proposal_validator/block_proposal_validator.ts → proposal_validator/proposal_validator.ts} +23 -28
- package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +206 -0
- package/src/services/dummy_service.ts +6 -0
- package/src/services/encoding.ts +3 -1
- package/src/services/libp2p/libp2p_service.ts +258 -94
- package/src/services/service.ts +19 -4
- package/src/testbench/p2p_client_testbench_worker.ts +34 -11
- package/src/testbench/worker_client_manager.ts +6 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
- package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
- package/dest/msg_validators/block_proposal_validator/index.js +0 -1
- package/src/msg_validators/block_proposal_validator/index.ts +0 -1
|
@@ -3,7 +3,12 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
3
3
|
import { toArray } from '@aztec/foundation/iterable';
|
|
4
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
BlockProposal,
|
|
8
|
+
CheckpointAttestation,
|
|
9
|
+
CheckpointProposal,
|
|
10
|
+
type CheckpointProposalCore,
|
|
11
|
+
} from '@aztec/stdlib/p2p';
|
|
7
12
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
8
13
|
|
|
9
14
|
import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
|
|
@@ -14,37 +19,46 @@ export const MAX_PROPOSALS_PER_SLOT = 5;
|
|
|
14
19
|
export const ATTESTATION_CAP_BUFFER = 10;
|
|
15
20
|
|
|
16
21
|
export class KvAttestationPool implements AttestationPool {
|
|
17
|
-
private metrics: PoolInstrumentation<
|
|
22
|
+
private metrics: PoolInstrumentation<CheckpointAttestation>;
|
|
18
23
|
|
|
19
|
-
private attestations: AztecAsyncMap<string, Buffer>;
|
|
20
24
|
private proposals: AztecAsyncMap<
|
|
21
25
|
/* proposal.payload.archive */ string,
|
|
22
26
|
/* buffer representation of proposal */ Buffer
|
|
23
27
|
>;
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
|
|
29
|
+
// Checkpoint attestation storage
|
|
30
|
+
private checkpointAttestations: AztecAsyncMap<string, Buffer>;
|
|
31
|
+
private checkpointProposals: AztecAsyncMap<string, Buffer>;
|
|
32
|
+
private checkpointProposalsForSlot: AztecAsyncMultiMap<number, string>;
|
|
33
|
+
private checkpointAttestationsForProposal: AztecAsyncMultiMap<string, string>;
|
|
26
34
|
|
|
27
35
|
constructor(
|
|
28
36
|
private store: AztecAsyncKVStore,
|
|
29
37
|
telemetry: TelemetryClient = getTelemetryClient(),
|
|
30
38
|
private log = createLogger('aztec:attestation_pool'),
|
|
31
39
|
) {
|
|
32
|
-
this.attestations = store.openMap('attestations');
|
|
33
40
|
this.proposals = store.openMap('proposals');
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
// Initialize checkpoint attestation storage
|
|
43
|
+
this.checkpointAttestations = store.openMap('checkpoint_attestations');
|
|
44
|
+
this.checkpointProposals = store.openMap('checkpoint_proposals');
|
|
45
|
+
this.checkpointProposalsForSlot = store.openMultiMap('checkpoint_proposals_for_slot');
|
|
46
|
+
this.checkpointAttestationsForProposal = store.openMultiMap('checkpoint_attestations_for_proposal');
|
|
36
47
|
|
|
37
48
|
this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL, this.poolStats);
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
private poolStats: PoolStatsCallback = async () => {
|
|
41
52
|
return {
|
|
42
|
-
itemCount: await this.
|
|
53
|
+
itemCount: await this.checkpointAttestations.sizeAsync(),
|
|
43
54
|
};
|
|
44
55
|
};
|
|
45
56
|
|
|
46
57
|
public async isEmpty(): Promise<boolean> {
|
|
47
|
-
for await (const _ of this.
|
|
58
|
+
for await (const _ of this.checkpointAttestations.entriesAsync()) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
for await (const _ of this.proposals.entriesAsync()) {
|
|
48
62
|
return false;
|
|
49
63
|
}
|
|
50
64
|
return true;
|
|
@@ -66,7 +80,81 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
66
80
|
return `${this.getProposalKey(slot, proposalId)}-${address}`;
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
public async
|
|
83
|
+
public async addBlockProposal(blockProposal: BlockProposal): Promise<void> {
|
|
84
|
+
await this.store.transactionAsync(async () => {
|
|
85
|
+
const proposalId = blockProposal.archive.toString();
|
|
86
|
+
// Strip signedTxs before storing to avoid persisting full tx data
|
|
87
|
+
await this.proposals.set(proposalId, blockProposal.withoutSignedTxs().toBuffer());
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public async getBlockProposal(id: string): Promise<BlockProposal | undefined> {
|
|
92
|
+
const buffer = await this.proposals.getAsync(id);
|
|
93
|
+
try {
|
|
94
|
+
if (buffer && buffer.length > 0) {
|
|
95
|
+
return BlockProposal.fromBuffer(buffer);
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
return Promise.resolve(undefined);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return Promise.resolve(undefined);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
|
|
105
|
+
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.archive.toString();
|
|
106
|
+
return await this.proposals.hasAsync(id);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public async addCheckpointProposal(proposal: CheckpointProposal): Promise<void> {
|
|
110
|
+
if (!(await this.canAddCheckpointProposal(proposal))) {
|
|
111
|
+
throw new ProposalSlotCapExceededError(
|
|
112
|
+
`Maximum checkpoint proposals per slot reached: slot=${proposal.slotNumber} cap=${MAX_PROPOSALS_PER_SLOT} proposal=${proposal.archive.toString()}`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Extract and validate the block proposal if present
|
|
117
|
+
const blockProposal = proposal.getBlockProposal();
|
|
118
|
+
if (blockProposal && !(await this.canAddProposal(blockProposal))) {
|
|
119
|
+
throw new ProposalSlotCapExceededError(
|
|
120
|
+
`Maximum block proposals per slot reached when extracting from checkpoint: slot=${proposal.slotNumber} proposal=${blockProposal.archive.toString()}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await this.store.transactionAsync(async () => {
|
|
125
|
+
const slotKey = proposal.slotNumber;
|
|
126
|
+
const proposalId = proposal.archive.toString();
|
|
127
|
+
|
|
128
|
+
await this.checkpointProposalsForSlot.set(slotKey, proposalId);
|
|
129
|
+
// Store the checkpoint proposal as core (without lastBlock) to avoid duplication
|
|
130
|
+
await this.checkpointProposals.set(proposalId, proposal.toCore().toBuffer());
|
|
131
|
+
|
|
132
|
+
// Store the extracted block proposal separately
|
|
133
|
+
if (blockProposal) {
|
|
134
|
+
await this.proposals.set(blockProposal.archive.toString(), blockProposal.withoutSignedTxs().toBuffer());
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public async getCheckpointProposal(id: string): Promise<CheckpointProposalCore | undefined> {
|
|
140
|
+
const buffer = await this.checkpointProposals.getAsync(id);
|
|
141
|
+
try {
|
|
142
|
+
if (buffer && buffer.length > 0) {
|
|
143
|
+
return CheckpointProposal.fromBuffer(buffer);
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
return Promise.resolve(undefined);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return Promise.resolve(undefined);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async hasCheckpointProposal(idOrProposal: string | CheckpointProposal): Promise<boolean> {
|
|
153
|
+
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.archive.toString();
|
|
154
|
+
return await this.checkpointProposals.hasAsync(id);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public async addCheckpointAttestations(attestations: CheckpointAttestation[]): Promise<void> {
|
|
70
158
|
await this.store.transactionAsync(async () => {
|
|
71
159
|
for (const attestation of attestations) {
|
|
72
160
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
@@ -75,7 +163,7 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
75
163
|
|
|
76
164
|
// Skip attestations with invalid signatures
|
|
77
165
|
if (!sender) {
|
|
78
|
-
this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber}`, {
|
|
166
|
+
this.log.warn(`Skipping checkpoint attestation with invalid signature for slot ${slotNumber}`, {
|
|
79
167
|
signature: attestation.signature.toString(),
|
|
80
168
|
slotNumber,
|
|
81
169
|
proposalId,
|
|
@@ -85,15 +173,18 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
85
173
|
|
|
86
174
|
const address = sender.toString();
|
|
87
175
|
|
|
88
|
-
await this.
|
|
176
|
+
await this.checkpointAttestations.set(
|
|
177
|
+
this.getAttestationKey(slotNumber, proposalId, address),
|
|
178
|
+
attestation.toBuffer(),
|
|
179
|
+
);
|
|
89
180
|
|
|
90
|
-
await this.
|
|
91
|
-
await this.
|
|
181
|
+
await this.checkpointProposalsForSlot.set(slotNumber, proposalId.toString());
|
|
182
|
+
await this.checkpointAttestationsForProposal.set(
|
|
92
183
|
this.getProposalKey(slotNumber, proposalId),
|
|
93
184
|
this.getAttestationKey(slotNumber, proposalId, address),
|
|
94
185
|
);
|
|
95
186
|
|
|
96
|
-
this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`, {
|
|
187
|
+
this.log.verbose(`Added checkpoint attestation for slot ${slotNumber} from ${address}`, {
|
|
97
188
|
signature: attestation.signature.toString(),
|
|
98
189
|
slotNumber,
|
|
99
190
|
address,
|
|
@@ -103,122 +194,72 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
103
194
|
});
|
|
104
195
|
}
|
|
105
196
|
|
|
106
|
-
public async
|
|
107
|
-
const proposalIds = await toArray(this.
|
|
108
|
-
const attestations:
|
|
197
|
+
public async getCheckpointAttestationsForSlot(slot: SlotNumber): Promise<CheckpointAttestation[]> {
|
|
198
|
+
const proposalIds = await toArray(this.checkpointProposalsForSlot.getValuesAsync(slot));
|
|
199
|
+
const attestations: CheckpointAttestation[] = [];
|
|
109
200
|
|
|
110
201
|
for (const proposalId of proposalIds) {
|
|
111
|
-
attestations.push(...(await this.
|
|
202
|
+
attestations.push(...(await this.getCheckpointAttestationsForSlotAndProposal(slot, proposalId)));
|
|
112
203
|
}
|
|
113
204
|
|
|
114
205
|
return attestations;
|
|
115
206
|
}
|
|
116
207
|
|
|
117
|
-
public async
|
|
208
|
+
public async getCheckpointAttestationsForSlotAndProposal(
|
|
209
|
+
slot: SlotNumber,
|
|
210
|
+
proposalId: string,
|
|
211
|
+
): Promise<CheckpointAttestation[]> {
|
|
118
212
|
const attestationIds = await toArray(
|
|
119
|
-
this.
|
|
213
|
+
this.checkpointAttestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
|
|
120
214
|
);
|
|
121
|
-
const attestations:
|
|
215
|
+
const attestations: CheckpointAttestation[] = [];
|
|
122
216
|
|
|
123
|
-
// alternatively iterate this.attestaions starting from slot-proposal-EthAddress.zero
|
|
124
217
|
for (const id of attestationIds) {
|
|
125
|
-
const buf = await this.
|
|
218
|
+
const buf = await this.checkpointAttestations.getAsync(id);
|
|
126
219
|
|
|
127
220
|
if (!buf) {
|
|
128
|
-
|
|
129
|
-
throw new Error('Attestation not found ' + id);
|
|
221
|
+
throw new Error('Checkpoint attestation not found ' + id);
|
|
130
222
|
}
|
|
131
223
|
|
|
132
|
-
const attestation =
|
|
224
|
+
const attestation = CheckpointAttestation.fromBuffer(buf);
|
|
133
225
|
attestations.push(attestation);
|
|
134
226
|
}
|
|
135
227
|
|
|
136
228
|
return attestations;
|
|
137
229
|
}
|
|
138
230
|
|
|
139
|
-
public async
|
|
140
|
-
const olderThan = await toArray(this.
|
|
231
|
+
public async deleteCheckpointAttestationsOlderThan(oldestSlot: SlotNumber): Promise<void> {
|
|
232
|
+
const olderThan = await toArray(this.checkpointProposalsForSlot.keysAsync({ end: oldestSlot }));
|
|
141
233
|
for (const oldSlot of olderThan) {
|
|
142
|
-
await this.
|
|
234
|
+
await this.deleteCheckpointAttestationsForSlot(SlotNumber(oldSlot));
|
|
143
235
|
}
|
|
144
236
|
}
|
|
145
237
|
|
|
146
|
-
|
|
238
|
+
private async deleteCheckpointAttestationsForSlot(slot: SlotNumber): Promise<void> {
|
|
147
239
|
let numberOfAttestations = 0;
|
|
148
240
|
await this.store.transactionAsync(async () => {
|
|
149
|
-
const proposalIds = await toArray(this.
|
|
241
|
+
const proposalIds = await toArray(this.checkpointProposalsForSlot.getValuesAsync(slot));
|
|
150
242
|
for (const proposalId of proposalIds) {
|
|
151
243
|
const attestations = await toArray(
|
|
152
|
-
this.
|
|
244
|
+
this.checkpointAttestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
|
|
153
245
|
);
|
|
154
246
|
|
|
155
247
|
numberOfAttestations += attestations.length;
|
|
156
248
|
for (const attestation of attestations) {
|
|
157
|
-
await this.
|
|
249
|
+
await this.checkpointAttestations.delete(attestation);
|
|
158
250
|
}
|
|
159
251
|
|
|
160
|
-
await this.
|
|
161
|
-
await this.
|
|
252
|
+
await this.checkpointProposals.delete(proposalId);
|
|
253
|
+
await this.checkpointAttestationsForProposal.delete(this.getProposalKey(slot, proposalId));
|
|
162
254
|
}
|
|
163
255
|
|
|
164
|
-
|
|
165
|
-
await this.proposalsForSlot.delete(slot);
|
|
256
|
+
await this.checkpointProposalsForSlot.delete(slot);
|
|
166
257
|
|
|
167
|
-
this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
|
|
258
|
+
this.log.verbose(`Removed ${numberOfAttestations} checkpoint attestations for slot ${slot}`);
|
|
168
259
|
});
|
|
169
260
|
}
|
|
170
261
|
|
|
171
|
-
public async
|
|
172
|
-
let numberOfAttestations = 0;
|
|
173
|
-
await this.store.transactionAsync(async () => {
|
|
174
|
-
const attestations = await toArray(
|
|
175
|
-
this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
numberOfAttestations += attestations.length;
|
|
179
|
-
for (const attestation of attestations) {
|
|
180
|
-
await this.attestations.delete(attestation);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
await this.proposals.delete(proposalId);
|
|
184
|
-
await this.proposalsForSlot.deleteValue(slot, proposalId);
|
|
185
|
-
await this.attestationsForProposal.delete(this.getProposalKey(slot, proposalId));
|
|
186
|
-
|
|
187
|
-
this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
|
|
192
|
-
await this.store.transactionAsync(async () => {
|
|
193
|
-
for (const attestation of attestations) {
|
|
194
|
-
const slotNumber = attestation.payload.header.slotNumber;
|
|
195
|
-
const proposalId = attestation.archive;
|
|
196
|
-
const sender = attestation.getSender();
|
|
197
|
-
|
|
198
|
-
// Skip attestations with invalid signatures
|
|
199
|
-
if (!sender) {
|
|
200
|
-
this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber}`);
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const address = sender.toString();
|
|
205
|
-
const key = this.getAttestationKey(slotNumber, proposalId, address);
|
|
206
|
-
|
|
207
|
-
if (await this.attestations.hasAsync(key)) {
|
|
208
|
-
await this.attestations.delete(key);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
await this.attestationsForProposal.deleteValue(
|
|
212
|
-
this.getProposalKey(slotNumber, proposalId),
|
|
213
|
-
this.getAttestationKey(slotNumber, proposalId, address),
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
public async hasAttestation(attestation: BlockAttestation): Promise<boolean> {
|
|
262
|
+
public async hasCheckpointAttestation(attestation: CheckpointAttestation): Promise<boolean> {
|
|
222
263
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
223
264
|
const proposalId = attestation.archive;
|
|
224
265
|
const sender = attestation.getSender();
|
|
@@ -231,68 +272,49 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
231
272
|
const address = sender.toString();
|
|
232
273
|
const key = this.getAttestationKey(slotNumber, proposalId, address);
|
|
233
274
|
|
|
234
|
-
return await this.
|
|
275
|
+
return await this.checkpointAttestations.hasAsync(key);
|
|
235
276
|
}
|
|
236
277
|
|
|
237
|
-
public
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (buffer && buffer.length > 0) {
|
|
241
|
-
return BlockProposal.fromBuffer(buffer);
|
|
242
|
-
}
|
|
243
|
-
} catch {
|
|
244
|
-
return Promise.resolve(undefined);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return Promise.resolve(undefined);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
public async hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
|
|
251
|
-
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.payload.archive.toString();
|
|
252
|
-
return await this.proposals.hasAsync(id);
|
|
278
|
+
public canAddProposal(_block: BlockProposal): Promise<boolean> {
|
|
279
|
+
// TODO(palla/mbps): implement proposal cap logic
|
|
280
|
+
return Promise.resolve(true);
|
|
253
281
|
}
|
|
254
282
|
|
|
255
|
-
public async
|
|
256
|
-
|
|
257
|
-
const slotKey = blockProposal.slotNumber;
|
|
258
|
-
const proposalId = blockProposal.archive.toString();
|
|
259
|
-
|
|
260
|
-
if (!(await this.canAddProposal(blockProposal))) {
|
|
261
|
-
throw new ProposalSlotCapExceededError(
|
|
262
|
-
`Maximum proposals per slot reached: slot=${slotKey} cap=${MAX_PROPOSALS_PER_SLOT} proposal=${proposalId}`,
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
await this.proposalsForSlot.set(slotKey, proposalId);
|
|
267
|
-
// Always update the stored proposal buffer so re-adds overwrite with latest data
|
|
268
|
-
await this.proposals.set(proposalId, blockProposal.toBuffer());
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
public async hasReachedProposalCap(slot: SlotNumber): Promise<boolean> {
|
|
273
|
-
const uniqueProposalCount = await this.proposalsForSlot.getValueCountAsync(slot);
|
|
274
|
-
return uniqueProposalCount >= MAX_PROPOSALS_PER_SLOT;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
public async hasReachedAttestationCap(slot: SlotNumber, proposalId: string, committeeSize: number): Promise<boolean> {
|
|
278
|
-
const limit = committeeSize + ATTESTATION_CAP_BUFFER;
|
|
279
|
-
return (await this.attestationsForProposal.getValueCountAsync(this.getProposalKey(slot, proposalId))) >= limit;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
public async canAddProposal(block: BlockProposal): Promise<boolean> {
|
|
283
|
+
public async canAddCheckpointProposal(proposal: CheckpointProposal): Promise<boolean> {
|
|
284
|
+
// TODO(palla/mbps): Adjust checkpoint proposal limit to 1. Also connect to slashing condition in the caller.
|
|
283
285
|
return (
|
|
284
|
-
(await this.
|
|
286
|
+
(await this.checkpointProposals.hasAsync(proposal.archive.toString())) ||
|
|
287
|
+
!(await this.hasReachedCheckpointProposalCap(proposal.slotNumber))
|
|
285
288
|
);
|
|
286
289
|
}
|
|
287
290
|
|
|
288
|
-
public async
|
|
291
|
+
public async canAddCheckpointAttestation(
|
|
292
|
+
attestation: CheckpointAttestation,
|
|
293
|
+
committeeSize: number,
|
|
294
|
+
): Promise<boolean> {
|
|
289
295
|
return (
|
|
290
|
-
(await this.
|
|
291
|
-
!(await this.
|
|
296
|
+
(await this.hasCheckpointAttestation(attestation)) ||
|
|
297
|
+
!(await this.hasReachedCheckpointAttestationCap(
|
|
292
298
|
attestation.payload.header.slotNumber,
|
|
293
299
|
attestation.archive.toString(),
|
|
294
300
|
committeeSize,
|
|
295
301
|
))
|
|
296
302
|
);
|
|
297
303
|
}
|
|
304
|
+
|
|
305
|
+
public async hasReachedCheckpointProposalCap(slot: SlotNumber): Promise<boolean> {
|
|
306
|
+
const uniqueProposalCount = await this.checkpointProposalsForSlot.getValueCountAsync(slot);
|
|
307
|
+
return uniqueProposalCount >= MAX_PROPOSALS_PER_SLOT;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public async hasReachedCheckpointAttestationCap(
|
|
311
|
+
slot: SlotNumber,
|
|
312
|
+
proposalId: string,
|
|
313
|
+
committeeSize: number,
|
|
314
|
+
): Promise<boolean> {
|
|
315
|
+
const limit = committeeSize + ATTESTATION_CAP_BUFFER;
|
|
316
|
+
return (
|
|
317
|
+
(await this.checkpointAttestationsForProposal.getValueCountAsync(this.getProposalKey(slot, proposalId))) >= limit
|
|
318
|
+
);
|
|
319
|
+
}
|
|
298
320
|
}
|