@aztec/p2p 0.87.6 → 0.87.8
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 +1 -1
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +2 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +3 -3
- 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 +0 -9
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +13 -8
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -0
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +7 -6
- package/dest/mem_pools/instrumentation.d.ts +7 -11
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +25 -37
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +2 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +22 -38
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +1 -0
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +13 -21
- package/dest/services/encoding.d.ts +2 -0
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +9 -1
- package/dest/services/libp2p/instrumentation.d.ts +11 -0
- package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
- package/dest/services/libp2p/instrumentation.js +29 -0
- package/dest/services/libp2p/libp2p_service.d.ts +3 -2
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +30 -17
- package/dest/services/reqresp/reqresp.d.ts +1 -1
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +9 -5
- package/dest/services/tx_collect_instrumentation.d.ts +13 -0
- package/dest/services/tx_collect_instrumentation.d.ts.map +1 -0
- package/dest/services/tx_collect_instrumentation.js +34 -0
- package/dest/services/tx_collector.d.ts +6 -2
- package/dest/services/tx_collector.d.ts.map +1 -1
- package/dest/services/tx_collector.js +65 -50
- package/dest/test-helpers/reqresp-nodes.d.ts +2 -0
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +6 -0
- package/package.json +12 -12
- package/src/client/interface.ts +1 -1
- package/src/client/p2p_client.ts +3 -3
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +0 -14
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +17 -12
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +8 -7
- package/src/mem_pools/instrumentation.ts +32 -46
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +23 -58
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +14 -26
- package/src/services/encoding.ts +9 -1
- package/src/services/libp2p/instrumentation.ts +39 -0
- package/src/services/libp2p/libp2p_service.ts +41 -15
- package/src/services/reqresp/reqresp.ts +6 -6
- package/src/services/tx_collect_instrumentation.ts +44 -0
- package/src/services/tx_collector.ts +93 -67
- package/src/test-helpers/reqresp-nodes.ts +6 -0
|
@@ -2,97 +2,123 @@ import { compactArray } from '@aztec/foundation/collection';
|
|
|
2
2
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
4
4
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
5
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
6
|
+
|
|
7
|
+
import type { PeerId } from '@libp2p/interface';
|
|
5
8
|
|
|
6
9
|
import type { P2PClient } from '../client/p2p_client.js';
|
|
10
|
+
import { TxCollectorInstrumentation } from './tx_collect_instrumentation.js';
|
|
7
11
|
|
|
8
12
|
export class TxCollector {
|
|
13
|
+
private instrumentation: TxCollectorInstrumentation;
|
|
14
|
+
|
|
9
15
|
constructor(
|
|
10
16
|
private p2pClient: Pick<
|
|
11
17
|
P2PClient,
|
|
12
|
-
'getTxsByHashFromPool' | 'hasTxsInPool' | 'getTxsByHash' | 'validate' | 'requestTxsByHash'
|
|
18
|
+
'getTxsByHashFromPool' | 'hasTxsInPool' | 'getTxsByHash' | 'validate' | 'requestTxsByHash' | 'addTxsToPool'
|
|
13
19
|
>,
|
|
14
20
|
private log: Logger = createLogger('p2p:tx-collector'),
|
|
15
|
-
|
|
21
|
+
client: TelemetryClient = getTelemetryClient(),
|
|
22
|
+
) {
|
|
23
|
+
this.instrumentation = new TxCollectorInstrumentation(client, 'TxCollector');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Checks the proposal for transactions we don't already have, validates them and adds them to our pool
|
|
27
|
+
private async collectFromProposal(proposal: BlockProposal): Promise<number> {
|
|
28
|
+
// Does this proposal have any transactions?
|
|
29
|
+
if (!proposal.txs || proposal.txs.length === 0) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const proposalHashes = new Set<string>((proposal.payload.txHashes ?? []).map(txHash => txHash.toString()));
|
|
34
|
+
|
|
35
|
+
// Get the transactions from the proposal and their hashes
|
|
36
|
+
// also, we are only interested in txs that are part of the proposal
|
|
37
|
+
const txsFromProposal = compactArray(
|
|
38
|
+
await Promise.all(
|
|
39
|
+
proposal.txs.map(tx =>
|
|
40
|
+
tx === undefined
|
|
41
|
+
? Promise.resolve(undefined)
|
|
42
|
+
: tx.getTxHash().then(hash => ({
|
|
43
|
+
txHash: hash,
|
|
44
|
+
tx,
|
|
45
|
+
})),
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
).filter(tx => proposalHashes.has(tx.txHash.toString()));
|
|
49
|
+
|
|
50
|
+
// Of the transactions from the proposal, retrieve those that we have in the pool already
|
|
51
|
+
const txsToValidate = [];
|
|
52
|
+
const txsWeAlreadyHave = await this.p2pClient.getTxsByHashFromPool(txsFromProposal.map(tx => tx.txHash));
|
|
53
|
+
|
|
54
|
+
// Txs we already have will have holes where we did not find them
|
|
55
|
+
// Where that is the case we need to validate the tx in the proposal
|
|
56
|
+
for (let i = 0; i < txsWeAlreadyHave.length; i++) {
|
|
57
|
+
if (txsWeAlreadyHave[i] === undefined) {
|
|
58
|
+
txsToValidate.push(txsFromProposal[i].tx);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Now validate all the transactions from the proposal that we don't have
|
|
63
|
+
// This will throw if any of the transactions are invalid, this is probably correct, if someone sends us a proposal with invalid
|
|
64
|
+
// transactions we probably shouldn't spend any more effort on it
|
|
65
|
+
try {
|
|
66
|
+
await this.p2pClient.validate(txsToValidate);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
this.log.error(`Received proposal with invalid transactions, skipping`);
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Now store these transactions in our pool, provided these are the txs in proposal.payload.txHashes they will be pinned already
|
|
73
|
+
await this.p2pClient.addTxsToPool(txsToValidate);
|
|
74
|
+
|
|
75
|
+
return txsToValidate.length;
|
|
76
|
+
}
|
|
16
77
|
|
|
17
78
|
async collectForBlockProposal(
|
|
18
79
|
proposal: BlockProposal,
|
|
19
|
-
peerWhoSentTheProposal:
|
|
80
|
+
peerWhoSentTheProposal: PeerId | undefined,
|
|
20
81
|
): Promise<{ txs: Tx[]; missing?: TxHash[] }> {
|
|
21
82
|
if (proposal.payload.txHashes.length === 0) {
|
|
22
83
|
this.log.verbose(`Received block proposal with no transactions, skipping transaction availability check`);
|
|
23
84
|
return { txs: [] };
|
|
24
85
|
}
|
|
25
|
-
// Is this a new style proposal?
|
|
26
|
-
if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
|
|
27
|
-
// Yes, any txs that we already have we should use
|
|
28
|
-
this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
|
|
29
|
-
|
|
30
|
-
// Request from the pool based on the signed hashes in the payload
|
|
31
|
-
const hashesFromPayload = proposal.payload.txHashes;
|
|
32
|
-
const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
|
|
33
|
-
|
|
34
|
-
const missingTxs = txsToUse.filter(tx => tx === undefined).length;
|
|
35
|
-
if (missingTxs > 0) {
|
|
36
|
-
this.log.verbose(
|
|
37
|
-
`Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
86
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
|
|
44
|
-
for (let i = 0; i < txsToUse.length; i++) {
|
|
45
|
-
if (txsToUse[i] === undefined) {
|
|
46
|
-
// We don't have the transaction, take from the proposal, provided the hash is the same
|
|
47
|
-
const hashOfTxInProposal = await proposal.txs[i].getTxHash();
|
|
48
|
-
if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
|
|
49
|
-
// Hash is equal, we can use the tx from the proposal
|
|
50
|
-
txsToUse[i] = proposal.txs[i];
|
|
51
|
-
usedFromProposal++;
|
|
52
|
-
} else {
|
|
53
|
-
this.log.warn(
|
|
54
|
-
`Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[
|
|
55
|
-
i
|
|
56
|
-
].toString()}`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
87
|
+
const txsInMempool = (await this.p2pClient.hasTxsInPool(proposal.payload.txHashes)).filter(Boolean).length;
|
|
88
|
+
this.instrumentation.incTxsFromMempool(txsInMempool);
|
|
61
89
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} else {
|
|
66
|
-
this.log.info(
|
|
67
|
-
`Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`,
|
|
68
|
-
);
|
|
90
|
+
// Take txs from the proposal if there are any
|
|
91
|
+
const txTakenFromProposal = await this.collectFromProposal(proposal);
|
|
92
|
+
this.instrumentation.incTxsFromProposals(txTakenFromProposal);
|
|
69
93
|
|
|
70
|
-
|
|
71
|
-
return { txs: txsToUse as Tx[] };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
|
|
76
|
-
|
|
77
|
-
// Old style proposal, we will perform a request by hash from pool
|
|
78
|
-
// This will request from network any txs that are missing
|
|
94
|
+
// Now get the txs we need, either from the pool or the p2p network
|
|
79
95
|
const txHashes: TxHash[] = proposal.payload.txHashes;
|
|
80
96
|
|
|
81
|
-
// This part is just for logging that we are requesting from the network
|
|
82
|
-
const availability = await this.p2pClient.hasTxsInPool(txHashes);
|
|
83
|
-
const notAvailable = availability.filter(availability => availability === false);
|
|
84
|
-
if (notAvailable.length) {
|
|
85
|
-
this.log.verbose(
|
|
86
|
-
`Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
97
|
// This will request from the network any txs that are missing
|
|
91
|
-
|
|
92
|
-
const
|
|
98
|
+
// NOTE: this could still return missing txs so we need to (1) be careful to handle undefined and (2) keep the txs in the correct order for re-execution
|
|
99
|
+
const maybeRetrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
|
|
100
|
+
|
|
101
|
+
// Get the txs that we didn't get from the network, if any. This will be empty if we got them al
|
|
102
|
+
const missingTxs = compactArray(
|
|
103
|
+
maybeRetrievedTxs.map((tx, index) => (tx === undefined ? txHashes[index] : undefined)),
|
|
104
|
+
);
|
|
105
|
+
this.instrumentation.incMissingTxs(missingTxs.length);
|
|
106
|
+
|
|
107
|
+
const txsFromP2P = txHashes.length - txTakenFromProposal - txsInMempool - missingTxs.length;
|
|
108
|
+
this.instrumentation.incTxsFromP2P(txsFromP2P);
|
|
93
109
|
|
|
94
|
-
|
|
110
|
+
// if we found all txs, this is a noop. If we didn't find all txs then tell the validator to skip attestations because missingTxs.length > 0
|
|
111
|
+
const retrievedTxs = compactArray(maybeRetrievedTxs);
|
|
95
112
|
|
|
96
|
-
|
|
113
|
+
this.log.info(`Retrieved ${retrievedTxs.length}/${txHashes.length} txs for block proposal`, {
|
|
114
|
+
blockNumber: proposal.blockNumber.toNumber(),
|
|
115
|
+
slotNumber: proposal.slotNumber.toNumber(),
|
|
116
|
+
totalTxsInProposal: txHashes.length,
|
|
117
|
+
txsFromProposal: txTakenFromProposal,
|
|
118
|
+
txsFromMempool: txsInMempool,
|
|
119
|
+
txsFromP2P,
|
|
120
|
+
missingTxs: missingTxs.length,
|
|
121
|
+
});
|
|
122
|
+
return { txs: retrievedTxs, missing: missingTxs };
|
|
97
123
|
}
|
|
98
124
|
}
|
|
@@ -225,11 +225,17 @@ export const connectToPeers = async (nodes: ReqRespNode[]): Promise<void> => {
|
|
|
225
225
|
|
|
226
226
|
// Mock circuit verifier for testing - reimplementation from bb to avoid dependency
|
|
227
227
|
export class AlwaysTrueCircuitVerifier implements ClientProtocolCircuitVerifier {
|
|
228
|
+
stop(): Promise<void> {
|
|
229
|
+
return Promise.resolve();
|
|
230
|
+
}
|
|
228
231
|
verifyProof(_tx: Tx): Promise<boolean> {
|
|
229
232
|
return Promise.resolve(true);
|
|
230
233
|
}
|
|
231
234
|
}
|
|
232
235
|
export class AlwaysFalseCircuitVerifier implements ClientProtocolCircuitVerifier {
|
|
236
|
+
stop(): Promise<void> {
|
|
237
|
+
return Promise.resolve();
|
|
238
|
+
}
|
|
233
239
|
verifyProof(_tx: Tx): Promise<boolean> {
|
|
234
240
|
return Promise.resolve(false);
|
|
235
241
|
}
|