@aztec/p2p 4.0.0-nightly.20260112 → 4.0.0-nightly.20260114
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/reqresp/constants.d.ts +12 -0
- package/dest/services/reqresp/constants.d.ts.map +1 -0
- package/dest/services/reqresp/constants.js +7 -0
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/block_txs/bitvector.js +7 -0
- package/dest/services/reqresp/protocols/status.d.ts +1 -1
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.js +2 -1
- 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/reqresp/constants.ts +14 -0
- package/src/services/reqresp/protocols/block_txs/bitvector.ts +9 -0
- package/src/services/reqresp/protocols/status.ts +5 -3
- 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
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
-
import type {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
ConsensusPayload,
|
|
8
|
-
SignatureDomainSeparator,
|
|
9
|
-
getHashedSignaturePayloadEthSignedMessage,
|
|
10
|
-
} from '@aztec/stdlib/p2p';
|
|
11
|
-
import { makeL2BlockHeader } from '@aztec/stdlib/testing';
|
|
12
|
-
import { TxHash } from '@aztec/stdlib/tx';
|
|
13
|
-
|
|
14
|
-
import { jest } from '@jest/globals';
|
|
15
|
-
import { type MockProxy, mock } from 'jest-mock-extended';
|
|
16
|
-
|
|
17
|
-
import type { PoolInstrumentation } from '../instrumentation.js';
|
|
4
|
+
import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
|
|
5
|
+
import { makeBlockProposal, makeCheckpointProposal, makeL2BlockHeader } from '@aztec/stdlib/testing';
|
|
6
|
+
|
|
18
7
|
import type { AttestationPool } from './attestation_pool.js';
|
|
19
|
-
import {
|
|
8
|
+
import { MAX_PROPOSALS_PER_SLOT } from './kv_attestation_pool.js';
|
|
9
|
+
import { mockCheckpointAttestation } from './mocks.js';
|
|
20
10
|
|
|
21
11
|
const NUMBER_OF_SIGNERS_PER_TEST = 4;
|
|
22
12
|
|
|
@@ -24,273 +14,182 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
24
14
|
let ap: AttestationPool;
|
|
25
15
|
let signers: Secp256k1Signer[];
|
|
26
16
|
|
|
27
|
-
// Check that metrics are recorded correctly
|
|
28
|
-
let metricsMock: MockProxy<PoolInstrumentation<BlockAttestation>>;
|
|
29
|
-
|
|
30
17
|
beforeEach(() => {
|
|
31
18
|
ap = getAttestationPool();
|
|
32
19
|
signers = Array.from({ length: NUMBER_OF_SIGNERS_PER_TEST }, () => Secp256k1Signer.random());
|
|
33
|
-
|
|
34
|
-
metricsMock = mock<PoolInstrumentation<BlockAttestation>>();
|
|
35
|
-
// Can i overwrite this like this??
|
|
36
|
-
(ap as any).metrics = metricsMock;
|
|
37
20
|
});
|
|
38
21
|
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
return signers.map(signer =>
|
|
22
|
+
const createCheckpointAttestationsForSlot = (slotNumber: number, archive?: Fr) => {
|
|
23
|
+
const archiveToUse = archive ?? Fr.random();
|
|
24
|
+
return signers.map(signer => mockCheckpointAttestation(signer, slotNumber, archiveToUse));
|
|
42
25
|
};
|
|
43
26
|
|
|
44
|
-
const
|
|
27
|
+
const mockBlockProposalForPool = (
|
|
28
|
+
signer: Secp256k1Signer,
|
|
29
|
+
slotNumber: number,
|
|
30
|
+
archive: Fr = Fr.random(),
|
|
31
|
+
): Promise<BlockProposal> => {
|
|
45
32
|
const header = makeL2BlockHeader(1, 2, slotNumber);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const txHashes = [TxHash.random(), TxHash.random()]; // Mock tx hashes
|
|
52
|
-
|
|
53
|
-
return new BlockProposalClass(payload, signature, txHashes);
|
|
33
|
+
return makeBlockProposal({
|
|
34
|
+
signer,
|
|
35
|
+
blockHeader: header,
|
|
36
|
+
archiveRoot: archive,
|
|
37
|
+
});
|
|
54
38
|
};
|
|
55
39
|
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
const
|
|
40
|
+
// Compare checkpoint attestations buffers
|
|
41
|
+
// Using array containing as the kv store does not respect insertion order
|
|
42
|
+
const compareCheckpointAttestations = (a1: CheckpointAttestation[], a2: CheckpointAttestation[]) => {
|
|
59
43
|
const a1Buffer = a1.map(attestation => attestation.toBuffer());
|
|
60
44
|
const a2Buffer = a2.map(attestation => attestation.toBuffer());
|
|
61
45
|
expect(a1Buffer.length).toBe(a2Buffer.length);
|
|
62
46
|
expect(a1Buffer).toEqual(expect.arrayContaining(a2Buffer));
|
|
63
47
|
};
|
|
64
48
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await ap.addAttestations(attestations);
|
|
71
|
-
|
|
72
|
-
const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(
|
|
73
|
-
SlotNumber(slotNumber),
|
|
74
|
-
archive.toString(),
|
|
75
|
-
);
|
|
76
|
-
expect(retrievedAttestations.length).toBe(attestations.length);
|
|
77
|
-
compareAttestations(retrievedAttestations, attestations);
|
|
78
|
-
|
|
79
|
-
// Check hasAttestation for added attestations
|
|
80
|
-
for (const attestation of attestations) {
|
|
81
|
-
expect(await ap.hasAttestation(attestation)).toBe(true);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const retrievedAttestationsForSlot = await ap.getAttestationsForSlot(SlotNumber(slotNumber));
|
|
85
|
-
expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
|
|
86
|
-
compareAttestations(retrievedAttestationsForSlot, attestations);
|
|
87
|
-
|
|
88
|
-
// Add another one
|
|
89
|
-
const newAttestation = mockAttestation(signers[NUMBER_OF_SIGNERS_PER_TEST - 1], slotNumber, archive);
|
|
90
|
-
await ap.addAttestations([newAttestation]);
|
|
91
|
-
const retrievedAttestationsAfterAdd = await ap.getAttestationsForSlotAndProposal(
|
|
92
|
-
SlotNumber(slotNumber),
|
|
93
|
-
archive.toString(),
|
|
94
|
-
);
|
|
95
|
-
expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
|
|
96
|
-
compareAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
|
|
97
|
-
expect(await ap.hasAttestation(newAttestation)).toBe(true);
|
|
98
|
-
const retrievedAttestationsForSlotAfterAdd = await ap.getAttestationsForSlot(SlotNumber(slotNumber));
|
|
99
|
-
expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
|
|
100
|
-
compareAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
|
|
101
|
-
|
|
102
|
-
// Delete by slot
|
|
103
|
-
await ap.deleteAttestationsForSlot(SlotNumber(slotNumber));
|
|
104
|
-
|
|
105
|
-
const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
|
|
106
|
-
SlotNumber(slotNumber),
|
|
107
|
-
archive.toString(),
|
|
108
|
-
);
|
|
109
|
-
expect(retreivedAttestationsAfterDelete.length).toBe(0);
|
|
110
|
-
// Check hasAttestation after deletion
|
|
111
|
-
for (const attestation of attestations) {
|
|
112
|
-
expect(await ap.hasAttestation(attestation)).toBe(false);
|
|
113
|
-
}
|
|
114
|
-
expect(await ap.hasAttestation(newAttestation)).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should handle duplicate proposals in a slot', async () => {
|
|
118
|
-
const slotNumber = 420;
|
|
119
|
-
const archive = Fr.random();
|
|
120
|
-
|
|
121
|
-
// Use the same signer for all attestations
|
|
122
|
-
const attestations: BlockAttestation[] = [];
|
|
123
|
-
const signer = signers[0];
|
|
124
|
-
for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
|
|
125
|
-
attestations.push(mockAttestation(signer, slotNumber, archive));
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Add them to store and check we end up with only one
|
|
129
|
-
await ap.addAttestations(attestations);
|
|
130
|
-
|
|
131
|
-
const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(
|
|
132
|
-
SlotNumber(slotNumber),
|
|
133
|
-
archive.toString(),
|
|
134
|
-
);
|
|
135
|
-
expect(retreivedAttestations.length).toBe(1);
|
|
136
|
-
expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
|
|
137
|
-
expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
|
|
138
|
-
|
|
139
|
-
// Try adding them on another operation and check they are still not duplicated
|
|
140
|
-
await ap.addAttestations([attestations[0]]);
|
|
141
|
-
expect(await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), archive.toString())).toHaveLength(1);
|
|
142
|
-
});
|
|
49
|
+
describe('CheckpointAttestation', () => {
|
|
50
|
+
it('should add attestations to pool', async () => {
|
|
51
|
+
const slotNumber = 420;
|
|
52
|
+
const archive = Fr.random();
|
|
53
|
+
const attestations = signers.slice(0, -1).map(signer => mockCheckpointAttestation(signer, slotNumber, archive));
|
|
143
54
|
|
|
144
|
-
|
|
145
|
-
const slotNumbers = [1, 2, 3, 4];
|
|
146
|
-
const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i]));
|
|
55
|
+
await ap.addCheckpointAttestations(attestations);
|
|
147
56
|
|
|
148
|
-
|
|
57
|
+
const retrievedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(
|
|
58
|
+
SlotNumber(slotNumber),
|
|
59
|
+
archive.toString(),
|
|
60
|
+
);
|
|
61
|
+
expect(retrievedAttestations.length).toBe(attestations.length);
|
|
62
|
+
compareCheckpointAttestations(retrievedAttestations, attestations);
|
|
149
63
|
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
64
|
+
// Check hasCheckpointAttestation for added attestations
|
|
65
|
+
for (const attestation of attestations) {
|
|
66
|
+
expect(await ap.hasCheckpointAttestation(attestation)).toBe(true);
|
|
67
|
+
}
|
|
153
68
|
|
|
154
|
-
const
|
|
155
|
-
expect(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
69
|
+
const retrievedAttestationsForSlot = await ap.getCheckpointAttestationsForSlot(SlotNumber(slotNumber));
|
|
70
|
+
expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
|
|
71
|
+
compareCheckpointAttestations(retrievedAttestationsForSlot, attestations);
|
|
72
|
+
|
|
73
|
+
// Add another one
|
|
74
|
+
const newAttestation = mockCheckpointAttestation(signers[NUMBER_OF_SIGNERS_PER_TEST - 1], slotNumber, archive);
|
|
75
|
+
await ap.addCheckpointAttestations([newAttestation]);
|
|
76
|
+
const retrievedAttestationsAfterAdd = await ap.getCheckpointAttestationsForSlotAndProposal(
|
|
77
|
+
SlotNumber(slotNumber),
|
|
78
|
+
archive.toString(),
|
|
79
|
+
);
|
|
80
|
+
expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
|
|
81
|
+
compareCheckpointAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
|
|
82
|
+
expect(await ap.hasCheckpointAttestation(newAttestation)).toBe(true);
|
|
83
|
+
const retrievedAttestationsForSlotAfterAdd = await ap.getCheckpointAttestationsForSlot(SlotNumber(slotNumber));
|
|
84
|
+
expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
|
|
85
|
+
compareCheckpointAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
|
|
86
|
+
|
|
87
|
+
// Delete by slot
|
|
88
|
+
await ap.deleteCheckpointAttestationsOlderThan(SlotNumber(slotNumber + 1));
|
|
89
|
+
|
|
90
|
+
const retreivedAttestationsAfterDelete = await ap.getCheckpointAttestationsForSlotAndProposal(
|
|
91
|
+
SlotNumber(slotNumber),
|
|
92
|
+
archive.toString(),
|
|
93
|
+
);
|
|
94
|
+
expect(retreivedAttestationsAfterDelete.length).toBe(0);
|
|
95
|
+
// Check hasCheckpointAttestation after deletion
|
|
96
|
+
for (const attestation of attestations) {
|
|
97
|
+
expect(await ap.hasCheckpointAttestation(attestation)).toBe(false);
|
|
98
|
+
}
|
|
99
|
+
expect(await ap.hasCheckpointAttestation(newAttestation)).toBe(false);
|
|
100
|
+
});
|
|
160
101
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i], archives[i]));
|
|
102
|
+
it('should handle duplicate proposals in a slot', async () => {
|
|
103
|
+
const slotNumber = 420;
|
|
104
|
+
const archive = Fr.random();
|
|
165
105
|
|
|
166
|
-
|
|
106
|
+
// Use the same signer for all attestations
|
|
107
|
+
const attestations: CheckpointAttestation[] = [];
|
|
108
|
+
const signer = signers[0];
|
|
109
|
+
for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
|
|
110
|
+
attestations.push(mockCheckpointAttestation(signer, slotNumber, archive));
|
|
111
|
+
}
|
|
167
112
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const proposalId = attestation.archive.toString();
|
|
113
|
+
// Add them to store and check we end up with only one
|
|
114
|
+
await ap.addCheckpointAttestations(attestations);
|
|
171
115
|
|
|
172
|
-
const retreivedAttestations = await ap.
|
|
116
|
+
const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(
|
|
117
|
+
SlotNumber(slotNumber),
|
|
118
|
+
archive.toString(),
|
|
119
|
+
);
|
|
173
120
|
expect(retreivedAttestations.length).toBe(1);
|
|
174
|
-
expect(retreivedAttestations[0].toBuffer()).toEqual(
|
|
175
|
-
expect(retreivedAttestations[0].
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const proposalId = attestations[0].archive.toString();
|
|
184
|
-
|
|
185
|
-
await ap.addAttestations(attestations);
|
|
186
|
-
|
|
187
|
-
const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
|
|
188
|
-
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
|
|
189
|
-
compareAttestations(retreivedAttestations, attestations);
|
|
190
|
-
|
|
191
|
-
// Check hasAttestation before deletion
|
|
192
|
-
for (const attestation of attestations) {
|
|
193
|
-
expect(await ap.hasAttestation(attestation)).toBe(true);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
await ap.deleteAttestations(attestations);
|
|
121
|
+
expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
|
|
122
|
+
expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
|
|
123
|
+
|
|
124
|
+
// Try adding them on another operation and check they are still not duplicated
|
|
125
|
+
await ap.addCheckpointAttestations([attestations[0]]);
|
|
126
|
+
expect(
|
|
127
|
+
await ap.getCheckpointAttestationsForSlotAndProposal(SlotNumber(slotNumber), archive.toString()),
|
|
128
|
+
).toHaveLength(1);
|
|
129
|
+
});
|
|
197
130
|
|
|
198
|
-
|
|
199
|
-
|
|
131
|
+
it('should store attestations by differing slot', async () => {
|
|
132
|
+
const slotNumbers = [1, 2, 3, 4];
|
|
133
|
+
const attestations = signers.map((signer, i) => mockCheckpointAttestation(signer, slotNumbers[i]));
|
|
200
134
|
|
|
201
|
-
|
|
202
|
-
for (const attestation of attestations) {
|
|
203
|
-
expect(await ap.hasAttestation(attestation)).toBe(false);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
135
|
+
await ap.addCheckpointAttestations(attestations);
|
|
206
136
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
|
|
211
|
-
const proposalId = attestations[0].archive.toString();
|
|
212
|
-
|
|
213
|
-
await ap.addAttestations(attestations);
|
|
137
|
+
for (const attestation of attestations) {
|
|
138
|
+
const slot = attestation.payload.header.slotNumber;
|
|
139
|
+
const archive = attestation.archive.toString();
|
|
214
140
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
141
|
+
const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(slot, archive);
|
|
142
|
+
expect(retreivedAttestations.length).toBe(1);
|
|
143
|
+
expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
|
|
144
|
+
expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
218
147
|
|
|
219
|
-
|
|
148
|
+
it('should store attestations by differing slot and archive', async () => {
|
|
149
|
+
const slotNumbers = [1, 1, 2, 3];
|
|
150
|
+
const archives = [Fr.random(), Fr.random(), Fr.random(), Fr.random()];
|
|
151
|
+
const attestations = signers.map((signer, i) => mockCheckpointAttestation(signer, slotNumbers[i], archives[i]));
|
|
220
152
|
|
|
221
|
-
|
|
222
|
-
SlotNumber(slotNumber),
|
|
223
|
-
proposalId,
|
|
224
|
-
);
|
|
225
|
-
expect(retreivedAttestationsAfterDelete.length).toBe(0);
|
|
226
|
-
});
|
|
153
|
+
await ap.addCheckpointAttestations(attestations);
|
|
227
154
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
|
|
232
|
-
const proposalId = attestations[0].archive.toString();
|
|
233
|
-
|
|
234
|
-
// Add another set of attestations with a different proposalId, yet the same slot
|
|
235
|
-
const archive2 = Fr.random();
|
|
236
|
-
const attestations2 = signers.map(signer => mockAttestation(signer, slotNumber, archive2));
|
|
237
|
-
const proposalId2 = attestations2[0].archive.toString();
|
|
238
|
-
|
|
239
|
-
await ap.addAttestations(attestations);
|
|
240
|
-
await ap.addAttestations(attestations2);
|
|
241
|
-
|
|
242
|
-
const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
|
|
243
|
-
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
|
|
244
|
-
compareAttestations(retreivedAttestations, attestations);
|
|
245
|
-
|
|
246
|
-
await ap.deleteAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
|
|
247
|
-
|
|
248
|
-
const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
|
|
249
|
-
SlotNumber(slotNumber),
|
|
250
|
-
proposalId,
|
|
251
|
-
);
|
|
252
|
-
expect(retreivedAttestationsAfterDelete.length).toBe(0);
|
|
253
|
-
|
|
254
|
-
const retreivedAttestationsAfterDeleteForOtherProposal = await ap.getAttestationsForSlotAndProposal(
|
|
255
|
-
SlotNumber(slotNumber),
|
|
256
|
-
proposalId2,
|
|
257
|
-
);
|
|
258
|
-
expect(retreivedAttestationsAfterDeleteForOtherProposal.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
|
|
259
|
-
compareAttestations(retreivedAttestationsAfterDeleteForOtherProposal, attestations2);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('should delete attestations older than a given slot', async () => {
|
|
263
|
-
const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
|
|
264
|
-
const attestations = (
|
|
265
|
-
await Promise.all(slotNumbers.map(slotNumber => createAttestationsForSlot(slotNumber)))
|
|
266
|
-
).flat();
|
|
267
|
-
const proposalId = attestations[0].archive.toString();
|
|
155
|
+
for (const attestation of attestations) {
|
|
156
|
+
const slot = attestation.payload.header.slotNumber;
|
|
157
|
+
const proposalId = attestation.archive.toString();
|
|
268
158
|
|
|
269
|
-
|
|
159
|
+
const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(slot, proposalId);
|
|
160
|
+
expect(retreivedAttestations.length).toBe(1);
|
|
161
|
+
expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
|
|
162
|
+
expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
270
165
|
|
|
271
|
-
|
|
272
|
-
|
|
166
|
+
it('should delete attestations older than a given slot', async () => {
|
|
167
|
+
const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
|
|
168
|
+
const attestations = (
|
|
169
|
+
await Promise.all(slotNumbers.map(slotNumber => createCheckpointAttestationsForSlot(slotNumber)))
|
|
170
|
+
).flat();
|
|
171
|
+
const proposalId = attestations[0].archive.toString();
|
|
273
172
|
|
|
274
|
-
|
|
173
|
+
await ap.addCheckpointAttestations(attestations);
|
|
275
174
|
|
|
276
|
-
|
|
175
|
+
const attestationsForSlot1 = await ap.getCheckpointAttestationsForSlotAndProposal(SlotNumber(1), proposalId);
|
|
176
|
+
expect(attestationsForSlot1.length).toBe(signers.length);
|
|
277
177
|
|
|
278
|
-
|
|
279
|
-
expect(attestationsForSlot1AfterDelete.length).toBe(0);
|
|
178
|
+
await ap.deleteCheckpointAttestationsOlderThan(SlotNumber(73));
|
|
280
179
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
180
|
+
const attestationsForSlot1AfterDelete = await ap.getCheckpointAttestationsForSlotAndProposal(
|
|
181
|
+
SlotNumber(1),
|
|
182
|
+
proposalId,
|
|
183
|
+
);
|
|
184
|
+
expect(attestationsForSlot1AfterDelete.length).toBe(0);
|
|
185
|
+
});
|
|
287
186
|
});
|
|
288
187
|
|
|
289
188
|
describe('BlockProposal in attestation pool', () => {
|
|
290
189
|
it('should add and retrieve block proposal', async () => {
|
|
291
190
|
const slotNumber = 420;
|
|
292
191
|
const archive = Fr.random();
|
|
293
|
-
const proposal =
|
|
192
|
+
const proposal = await mockBlockProposalForPool(signers[0], slotNumber, archive);
|
|
294
193
|
const proposalId = proposal.archive.toString();
|
|
295
194
|
|
|
296
195
|
await ap.addBlockProposal(proposal);
|
|
@@ -317,13 +216,13 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
317
216
|
it('should update block proposal if added twice with same id', async () => {
|
|
318
217
|
const slotNumber = 420;
|
|
319
218
|
const archive = Fr.random();
|
|
320
|
-
const proposal1 =
|
|
219
|
+
const proposal1 = await mockBlockProposalForPool(signers[0], slotNumber, archive);
|
|
321
220
|
const proposalId = proposal1.archive.toString();
|
|
322
221
|
|
|
323
222
|
await ap.addBlockProposal(proposal1);
|
|
324
223
|
|
|
325
224
|
// Create a new proposal with same archive but different signer
|
|
326
|
-
const proposal2 =
|
|
225
|
+
const proposal2 = await mockBlockProposalForPool(signers[1], slotNumber, archive);
|
|
327
226
|
|
|
328
227
|
await ap.addBlockProposal(proposal2);
|
|
329
228
|
|
|
@@ -336,8 +235,8 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
336
235
|
|
|
337
236
|
it('should handle block proposals with different slots and same archive', async () => {
|
|
338
237
|
const archive = Fr.random();
|
|
339
|
-
const proposal1 =
|
|
340
|
-
const proposal2 =
|
|
238
|
+
const proposal1 = await mockBlockProposalForPool(signers[0], 100, archive);
|
|
239
|
+
const proposal2 = await mockBlockProposalForPool(signers[1], 200, archive);
|
|
341
240
|
const proposalId = archive.toString();
|
|
342
241
|
|
|
343
242
|
await ap.addBlockProposal(proposal1);
|
|
@@ -349,81 +248,126 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
349
248
|
expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toBuffer());
|
|
350
249
|
expect(retrievedProposal!.slotNumber).toBe(SlotNumber(200));
|
|
351
250
|
});
|
|
251
|
+
});
|
|
352
252
|
|
|
353
|
-
|
|
253
|
+
describe('CheckpointProposal in attestation pool', () => {
|
|
254
|
+
const mockCheckpointProposalForPool = (
|
|
255
|
+
signer: Secp256k1Signer,
|
|
256
|
+
slotNumber: number,
|
|
257
|
+
archive: Fr = Fr.random(),
|
|
258
|
+
): Promise<CheckpointProposal> => {
|
|
259
|
+
const header = makeL2BlockHeader(1, 2, slotNumber);
|
|
260
|
+
return makeCheckpointProposal({
|
|
261
|
+
signer,
|
|
262
|
+
checkpointHeader: header.toCheckpointHeader(),
|
|
263
|
+
archiveRoot: archive,
|
|
264
|
+
lastBlock: { blockHeader: header },
|
|
265
|
+
});
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
it('should add and retrieve checkpoint proposal as core (without lastBlock)', async () => {
|
|
354
269
|
const slotNumber = 420;
|
|
355
270
|
const archive = Fr.random();
|
|
356
|
-
const proposal =
|
|
271
|
+
const proposal = await mockCheckpointProposalForPool(signers[0], slotNumber, archive);
|
|
357
272
|
const proposalId = proposal.archive.toString();
|
|
358
273
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
await ap.addAttestations(attestations);
|
|
274
|
+
await ap.addCheckpointProposal(proposal);
|
|
275
|
+
|
|
276
|
+
const retrievedProposal = await ap.getCheckpointProposal(proposalId);
|
|
363
277
|
|
|
364
|
-
// Verify proposal exists
|
|
365
|
-
let retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
366
278
|
expect(retrievedProposal).toBeDefined();
|
|
367
|
-
|
|
279
|
+
// Should return core version (without lastBlock)
|
|
280
|
+
expect(retrievedProposal!.toBuffer()).toEqual(proposal.toCore().toBuffer());
|
|
368
281
|
|
|
369
|
-
//
|
|
370
|
-
await ap.
|
|
282
|
+
// Check hasCheckpointProposal with both id and object
|
|
283
|
+
expect(await ap.hasCheckpointProposal(proposalId)).toBe(true);
|
|
284
|
+
expect(await ap.hasCheckpointProposal(proposal)).toBe(true);
|
|
285
|
+
});
|
|
371
286
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
287
|
+
it('should extract and store block proposal when adding checkpoint proposal with lastBlock', async () => {
|
|
288
|
+
const slotNumber = 420;
|
|
289
|
+
const archive = Fr.random();
|
|
290
|
+
const proposal = await mockCheckpointProposalForPool(signers[0], slotNumber, archive);
|
|
291
|
+
const proposalId = proposal.archive.toString();
|
|
292
|
+
|
|
293
|
+
// Verify the proposal has a lastBlock
|
|
294
|
+
const expectedBlockProposal = proposal.getBlockProposal();
|
|
295
|
+
expect(expectedBlockProposal).toBeDefined();
|
|
296
|
+
|
|
297
|
+
await ap.addCheckpointProposal(proposal);
|
|
298
|
+
|
|
299
|
+
// The block proposal should be stored separately and retrievable
|
|
300
|
+
const retrievedBlockProposal = await ap.getBlockProposal(proposalId);
|
|
301
|
+
expect(retrievedBlockProposal).toBeDefined();
|
|
302
|
+
expect(retrievedBlockProposal!.archive.toString()).toBe(archive.toString());
|
|
303
|
+
expect(retrievedBlockProposal!.blockHeader.toBuffer()).toEqual(expectedBlockProposal!.blockHeader.toBuffer());
|
|
376
304
|
});
|
|
377
305
|
|
|
378
|
-
it('should
|
|
306
|
+
it('should not store block proposal when checkpoint proposal has no lastBlock', async () => {
|
|
379
307
|
const slotNumber = 420;
|
|
380
308
|
const archive = Fr.random();
|
|
381
|
-
const
|
|
309
|
+
const header = makeL2BlockHeader(1, 2, slotNumber);
|
|
310
|
+
// Create a checkpoint proposal WITHOUT lastBlock
|
|
311
|
+
const proposal = await makeCheckpointProposal({
|
|
312
|
+
signer: signers[0],
|
|
313
|
+
checkpointHeader: header.toCheckpointHeader(),
|
|
314
|
+
archiveRoot: archive,
|
|
315
|
+
// No lastBlock
|
|
316
|
+
});
|
|
382
317
|
const proposalId = proposal.archive.toString();
|
|
383
318
|
|
|
384
|
-
|
|
385
|
-
await ap.addBlockProposal(proposal);
|
|
319
|
+
await ap.addCheckpointProposal(proposal);
|
|
386
320
|
|
|
387
|
-
//
|
|
388
|
-
|
|
389
|
-
expect(
|
|
390
|
-
expect(await ap.hasBlockProposal(proposal)).toBe(true);
|
|
321
|
+
// The checkpoint proposal should be stored
|
|
322
|
+
const retrievedCheckpointProposal = await ap.getCheckpointProposal(proposalId);
|
|
323
|
+
expect(retrievedCheckpointProposal).toBeDefined();
|
|
391
324
|
|
|
392
|
-
//
|
|
393
|
-
await ap.
|
|
325
|
+
// But no block proposal should be stored (archive key won't have a block proposal)
|
|
326
|
+
const retrievedBlockProposal = await ap.getBlockProposal(proposalId);
|
|
327
|
+
expect(retrievedBlockProposal).toBeUndefined();
|
|
328
|
+
});
|
|
394
329
|
|
|
395
|
-
|
|
396
|
-
|
|
330
|
+
it('should return undefined for non-existent checkpoint proposal', async () => {
|
|
331
|
+
const nonExistentId = Fr.random().toString();
|
|
332
|
+
const retrievedProposal = await ap.getCheckpointProposal(nonExistentId);
|
|
397
333
|
expect(retrievedProposal).toBeUndefined();
|
|
398
|
-
|
|
334
|
+
|
|
335
|
+
// Check hasCheckpointProposal returns false for non-existent proposal
|
|
336
|
+
expect(await ap.hasCheckpointProposal(nonExistentId)).toBe(false);
|
|
399
337
|
});
|
|
400
338
|
|
|
401
|
-
it('should
|
|
339
|
+
it('should update checkpoint proposal if added twice with same id', async () => {
|
|
402
340
|
const slotNumber = 420;
|
|
403
341
|
const archive = Fr.random();
|
|
404
|
-
const
|
|
405
|
-
const proposalId =
|
|
342
|
+
const proposal1 = await mockCheckpointProposalForPool(signers[0], slotNumber, archive);
|
|
343
|
+
const proposalId = proposal1.archive.toString();
|
|
406
344
|
|
|
407
|
-
|
|
408
|
-
await ap.addBlockProposal(proposal);
|
|
345
|
+
await ap.addCheckpointProposal(proposal1);
|
|
409
346
|
|
|
410
|
-
//
|
|
411
|
-
const
|
|
412
|
-
await ap.addAttestations(attestations);
|
|
347
|
+
// Create a new proposal with same archive but different signer
|
|
348
|
+
const proposal2 = await mockCheckpointProposalForPool(signers[1], slotNumber, archive);
|
|
413
349
|
|
|
414
|
-
|
|
415
|
-
const retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
416
|
-
const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
|
|
350
|
+
await ap.addCheckpointProposal(proposal2);
|
|
417
351
|
|
|
352
|
+
const retrievedProposal = await ap.getCheckpointProposal(proposalId);
|
|
418
353
|
expect(retrievedProposal).toBeDefined();
|
|
419
|
-
|
|
420
|
-
expect(
|
|
354
|
+
// Should have the second proposal (as core)
|
|
355
|
+
expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toCore().toBuffer());
|
|
356
|
+
expect(retrievedProposal!.getSender()?.toString()).toBe(signers[1].address.toString());
|
|
357
|
+
});
|
|
421
358
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
359
|
+
it('should throw ProposalSlotCapExceededError when exceeding capacity', async () => {
|
|
360
|
+
const slotNumber = 420;
|
|
361
|
+
|
|
362
|
+
// Add MAX_PROPOSALS_PER_SLOT proposals
|
|
363
|
+
for (let i = 0; i < MAX_PROPOSALS_PER_SLOT; i++) {
|
|
364
|
+
const proposal = await mockCheckpointProposalForPool(signers[i % NUMBER_OF_SIGNERS_PER_TEST], slotNumber);
|
|
365
|
+
await ap.addCheckpointProposal(proposal);
|
|
426
366
|
}
|
|
367
|
+
|
|
368
|
+
// The next proposal should throw
|
|
369
|
+
const extraProposal = await mockCheckpointProposalForPool(signers[0], slotNumber);
|
|
370
|
+
await expect(ap.addCheckpointProposal(extraProposal)).rejects.toThrow('Maximum checkpoint proposals per slot');
|
|
427
371
|
});
|
|
428
372
|
});
|
|
429
373
|
}
|