@aztec/p2p 0.65.2 → 0.67.0
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/bootstrap/bootstrap.d.ts +7 -2
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +25 -12
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +11 -7
- package/dest/client/p2p_client.d.ts +11 -16
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +32 -8
- package/dest/config.d.ts +40 -2
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +10 -2
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +8 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- 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 +22 -3
- package/dest/mem_pools/instrumentation.d.ts +2 -7
- package/dest/mem_pools/instrumentation.d.ts.map +1 -1
- package/dest/mem_pools/instrumentation.js +4 -25
- 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 +5 -7
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +4 -4
- package/dest/mocks/index.d.ts.map +1 -1
- package/dest/mocks/index.js +12 -6
- package/dest/service/discV5_service.d.ts +2 -0
- package/dest/service/discV5_service.d.ts.map +1 -1
- package/dest/service/discV5_service.js +14 -11
- package/dest/service/dummy_service.d.ts +3 -1
- package/dest/service/dummy_service.d.ts.map +1 -1
- package/dest/service/dummy_service.js +5 -1
- package/dest/service/encoding.d.ts +26 -0
- package/dest/service/encoding.d.ts.map +1 -0
- package/dest/service/encoding.js +49 -0
- package/dest/service/libp2p_service.d.ts +2 -7
- package/dest/service/libp2p_service.d.ts.map +1 -1
- package/dest/service/libp2p_service.js +24 -31
- package/dest/service/peer_manager.d.ts +3 -0
- package/dest/service/peer_manager.d.ts.map +1 -1
- package/dest/service/peer_manager.js +59 -21
- package/dest/service/peer_scoring.d.ts +4 -1
- package/dest/service/peer_scoring.d.ts.map +1 -1
- package/dest/service/peer_scoring.js +6 -1
- package/dest/service/reqresp/handlers.d.ts +4 -2
- package/dest/service/reqresp/handlers.d.ts.map +1 -1
- package/dest/service/reqresp/handlers.js +3 -3
- package/dest/service/reqresp/interface.d.ts +1 -1
- package/dest/service/reqresp/interface.d.ts.map +1 -1
- package/dest/service/reqresp/interface.js +2 -2
- package/dest/service/reqresp/reqresp.d.ts +3 -0
- package/dest/service/reqresp/reqresp.d.ts.map +1 -1
- package/dest/service/reqresp/reqresp.js +14 -9
- package/dest/service/service.d.ts +2 -1
- package/dest/service/service.d.ts.map +1 -1
- package/dest/tx_validator/data_validator.js +3 -3
- package/dest/tx_validator/double_spend_validator.js +3 -3
- package/dest/tx_validator/metadata_validator.js +3 -3
- package/dest/tx_validator/tx_proof_validator.js +3 -3
- package/dest/util.d.ts +20 -2
- package/dest/util.d.ts.map +1 -1
- package/dest/util.js +39 -3
- package/package.json +14 -9
- package/src/bootstrap/bootstrap.ts +33 -13
- package/src/client/index.ts +10 -6
- package/src/client/p2p_client.ts +47 -24
- package/src/config.ts +17 -2
- package/src/mem_pools/attestation_pool/attestation_pool.ts +9 -0
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +23 -2
- package/src/mem_pools/instrumentation.ts +4 -26
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +4 -6
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
- package/src/mocks/index.ts +11 -5
- package/src/service/discV5_service.ts +17 -12
- package/src/service/dummy_service.ts +6 -1
- package/src/service/encoding.ts +61 -0
- package/src/service/libp2p_service.ts +26 -32
- package/src/service/peer_manager.ts +68 -22
- package/src/service/peer_scoring.ts +8 -1
- package/src/service/reqresp/handlers.ts +4 -4
- package/src/service/reqresp/interface.ts +3 -3
- package/src/service/reqresp/reqresp.ts +13 -8
- package/src/service/service.ts +3 -1
- package/src/tx_validator/data_validator.ts +2 -2
- package/src/tx_validator/double_spend_validator.ts +2 -2
- package/src/tx_validator/metadata_validator.ts +2 -2
- package/src/tx_validator/tx_proof_validator.ts +2 -2
- package/src/util.ts +48 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type BlockAttestation } from '@aztec/circuit-types';
|
|
2
|
-
import {
|
|
2
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
4
|
|
|
5
5
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
@@ -10,7 +10,7 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
10
10
|
|
|
11
11
|
private attestations: Map</*slot=*/ bigint, Map</*proposalId*/ string, Map</*address=*/ string, BlockAttestation>>>;
|
|
12
12
|
|
|
13
|
-
constructor(telemetry: TelemetryClient, private log =
|
|
13
|
+
constructor(telemetry: TelemetryClient, private log = createLogger('p2p:attestation_pool')) {
|
|
14
14
|
this.attestations = new Map();
|
|
15
15
|
this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL);
|
|
16
16
|
}
|
|
@@ -58,6 +58,27 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
58
58
|
return total;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
|
|
62
|
+
const olderThan = [];
|
|
63
|
+
|
|
64
|
+
// Entries are iterated in insertion order, so we can break as soon as we find a slot that is older than the oldestSlot.
|
|
65
|
+
// Note: this will only prune correctly if attestations are added in order of rising slot, it is important that we do not allow
|
|
66
|
+
// insertion of attestations that are old. #(https://github.com/AztecProtocol/aztec-packages/issues/10322)
|
|
67
|
+
const slots = this.attestations.keys();
|
|
68
|
+
for (const slot of slots) {
|
|
69
|
+
if (slot < oldestSlot) {
|
|
70
|
+
olderThan.push(slot);
|
|
71
|
+
} else {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const oldSlot of olderThan) {
|
|
77
|
+
await this.deleteAttestationsForSlot(oldSlot);
|
|
78
|
+
}
|
|
79
|
+
return Promise.resolve();
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
public deleteAttestationsForSlot(slot: bigint): Promise<void> {
|
|
62
83
|
// We count the number of attestations we are removing
|
|
63
84
|
const numberOfAttestations = this.#getNumberOfAttestationsInSlot(slot);
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Attributes,
|
|
4
4
|
type Histogram,
|
|
5
5
|
LmdbMetrics,
|
|
6
|
+
type LmdbStatsCallback,
|
|
6
7
|
Metrics,
|
|
7
8
|
type TelemetryClient,
|
|
8
9
|
type UpDownCounter,
|
|
@@ -58,7 +59,7 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
58
59
|
|
|
59
60
|
private defaultAttributes;
|
|
60
61
|
|
|
61
|
-
constructor(telemetry: TelemetryClient, name: PoolName) {
|
|
62
|
+
constructor(telemetry: TelemetryClient, name: PoolName, dbStats?: LmdbStatsCallback) {
|
|
62
63
|
const meter = telemetry.getMeter(name);
|
|
63
64
|
this.defaultAttributes = { [Attributes.POOL_NAME]: name };
|
|
64
65
|
|
|
@@ -71,40 +72,17 @@ export class PoolInstrumentation<PoolObject extends Gossipable> {
|
|
|
71
72
|
this.objectSize = meter.createHistogram(metricsLabels.objectSize, {
|
|
72
73
|
unit: 'By',
|
|
73
74
|
description: 'The size of transactions in the mempool',
|
|
74
|
-
advice: {
|
|
75
|
-
explicitBucketBoundaries: [
|
|
76
|
-
5_000, // 5KB
|
|
77
|
-
10_000,
|
|
78
|
-
20_000,
|
|
79
|
-
50_000,
|
|
80
|
-
75_000,
|
|
81
|
-
100_000, // 100KB
|
|
82
|
-
200_000,
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
75
|
});
|
|
86
76
|
|
|
87
77
|
this.dbMetrics = new LmdbMetrics(
|
|
88
78
|
meter,
|
|
89
79
|
{
|
|
90
|
-
|
|
91
|
-
description: 'Database map size for the Tx mempool',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
name: Metrics.MEMPOOL_DB_USED_SIZE,
|
|
95
|
-
description: 'Database used size for the Tx mempool',
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: Metrics.MEMPOOL_DB_NUM_ITEMS,
|
|
99
|
-
description: 'Num items in database for the Tx mempool',
|
|
80
|
+
[Attributes.DB_DATA_TYPE]: 'tx-pool',
|
|
100
81
|
},
|
|
82
|
+
dbStats,
|
|
101
83
|
);
|
|
102
84
|
}
|
|
103
85
|
|
|
104
|
-
public recordDBMetrics(metrics: { mappingSize: number; numItems: number; actualSize: number }) {
|
|
105
|
-
this.dbMetrics.recordDBMetrics(metrics);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
86
|
public recordSize(poolObject: PoolObject) {
|
|
109
87
|
this.objectSize.record(poolObject.getSize());
|
|
110
88
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Tx, TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { type TxAddedToPoolStats } from '@aztec/circuit-types/stats';
|
|
3
|
-
import { type Logger,
|
|
3
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { type AztecKVStore, type AztecMap, type AztecSet } from '@aztec/kv-store';
|
|
5
5
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
6
6
|
|
|
@@ -30,14 +30,14 @@ export class AztecKVTxPool implements TxPool {
|
|
|
30
30
|
* @param store - A KV store.
|
|
31
31
|
* @param log - A logger.
|
|
32
32
|
*/
|
|
33
|
-
constructor(store: AztecKVStore, telemetry: TelemetryClient, log =
|
|
33
|
+
constructor(store: AztecKVStore, telemetry: TelemetryClient, log = createLogger('p2p:tx_pool')) {
|
|
34
34
|
this.#txs = store.openMap('txs');
|
|
35
35
|
this.#minedTxs = store.openMap('minedTxs');
|
|
36
36
|
this.#pendingTxs = store.openSet('pendingTxs');
|
|
37
37
|
|
|
38
38
|
this.#store = store;
|
|
39
39
|
this.#log = log;
|
|
40
|
-
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL);
|
|
40
|
+
this.#metrics = new PoolInstrumentation(telemetry, PoolName.TX_POOL, () => store.estimateSize());
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
public markAsMined(txHashes: TxHash[], blockNumber: number): Promise<void> {
|
|
@@ -53,8 +53,6 @@ export class AztecKVTxPool implements TxPool {
|
|
|
53
53
|
}
|
|
54
54
|
this.#metrics.recordRemovedObjects(deleted, 'pending');
|
|
55
55
|
this.#metrics.recordAddedObjects(txHashes.length, 'mined');
|
|
56
|
-
const storeSizes = this.#store.estimateSize();
|
|
57
|
-
this.#metrics.recordDBMetrics(storeSizes);
|
|
58
56
|
});
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -127,7 +125,7 @@ export class AztecKVTxPool implements TxPool {
|
|
|
127
125
|
let pendingCount = 0;
|
|
128
126
|
for (const [i, tx] of txs.entries()) {
|
|
129
127
|
const txHash = txHashes[i];
|
|
130
|
-
this.#log.
|
|
128
|
+
this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
131
129
|
eventName: 'tx-added-to-pool',
|
|
132
130
|
...tx.getStats(),
|
|
133
131
|
} satisfies TxAddedToPoolStats);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Tx, TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { type TxAddedToPoolStats } from '@aztec/circuit-types/stats';
|
|
3
|
-
import {
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
5
|
|
|
6
6
|
import { PoolInstrumentation, PoolName } from '../instrumentation.js';
|
|
@@ -23,7 +23,7 @@ export class InMemoryTxPool implements TxPool {
|
|
|
23
23
|
* Class constructor for in-memory TxPool. Initiates our transaction pool as a JS Map.
|
|
24
24
|
* @param log - A logger.
|
|
25
25
|
*/
|
|
26
|
-
constructor(telemetry: TelemetryClient, private log =
|
|
26
|
+
constructor(telemetry: TelemetryClient, private log = createLogger('p2p:tx_pool')) {
|
|
27
27
|
this.txs = new Map<bigint, Tx>();
|
|
28
28
|
this.minedTxs = new Map();
|
|
29
29
|
this.pendingTxs = new Set();
|
|
@@ -105,7 +105,7 @@ export class InMemoryTxPool implements TxPool {
|
|
|
105
105
|
let pending = 0;
|
|
106
106
|
for (const tx of txs) {
|
|
107
107
|
const txHash = tx.getTxHash();
|
|
108
|
-
this.log.
|
|
108
|
+
this.log.verbose(`Adding tx ${txHash.toString()} to pool`, {
|
|
109
109
|
eventName: 'tx-added-to-pool',
|
|
110
110
|
...tx.getStats(),
|
|
111
111
|
} satisfies TxAddedToPoolStats);
|
package/src/mocks/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type WorldStateSynchronizer,
|
|
6
6
|
} from '@aztec/circuit-types';
|
|
7
7
|
import { type DataStoreConfig } from '@aztec/kv-store/config';
|
|
8
|
+
import { openTmpStore } from '@aztec/kv-store/lmdb';
|
|
8
9
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
9
10
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
10
11
|
|
|
@@ -14,6 +15,7 @@ import { yamux } from '@chainsafe/libp2p-yamux';
|
|
|
14
15
|
import { bootstrap } from '@libp2p/bootstrap';
|
|
15
16
|
import { identify } from '@libp2p/identify';
|
|
16
17
|
import { type PeerId } from '@libp2p/interface';
|
|
18
|
+
import { createSecp256k1PeerId } from '@libp2p/peer-id-factory';
|
|
17
19
|
import { tcp } from '@libp2p/tcp';
|
|
18
20
|
import getPort from 'get-port';
|
|
19
21
|
import { type Libp2p, type Libp2pOptions, createLibp2p } from 'libp2p';
|
|
@@ -22,7 +24,7 @@ import { BootstrapNode } from '../bootstrap/bootstrap.js';
|
|
|
22
24
|
import { type BootnodeConfig, type P2PConfig } from '../config.js';
|
|
23
25
|
import { type MemPools } from '../mem_pools/interface.js';
|
|
24
26
|
import { DiscV5Service } from '../service/discV5_service.js';
|
|
25
|
-
import { LibP2PService
|
|
27
|
+
import { LibP2PService } from '../service/libp2p_service.js';
|
|
26
28
|
import { type PeerManager } from '../service/peer_manager.js';
|
|
27
29
|
import { type P2PReqRespConfig } from '../service/reqresp/config.js';
|
|
28
30
|
import { pingHandler, statusHandler } from '../service/reqresp/handlers.js';
|
|
@@ -102,7 +104,7 @@ export async function createTestLibP2PService(
|
|
|
102
104
|
port: number = 0,
|
|
103
105
|
peerId?: PeerId,
|
|
104
106
|
) {
|
|
105
|
-
peerId = peerId ?? (await
|
|
107
|
+
peerId = peerId ?? (await createSecp256k1PeerId());
|
|
106
108
|
const config = {
|
|
107
109
|
tcpAnnounceAddress: `127.0.0.1:${port}`,
|
|
108
110
|
udpAnnounceAddress: `127.0.0.1:${port}`,
|
|
@@ -146,7 +148,7 @@ export type ReqRespNode = {
|
|
|
146
148
|
export const MOCK_SUB_PROTOCOL_HANDLERS: ReqRespSubProtocolHandlers = {
|
|
147
149
|
[PING_PROTOCOL]: pingHandler,
|
|
148
150
|
[STATUS_PROTOCOL]: statusHandler,
|
|
149
|
-
[TX_REQ_PROTOCOL]: (_msg: any) => Promise.resolve(
|
|
151
|
+
[TX_REQ_PROTOCOL]: (_msg: any) => Promise.resolve(Buffer.from('tx')),
|
|
150
152
|
};
|
|
151
153
|
|
|
152
154
|
// By default, all requests are valid
|
|
@@ -231,6 +233,8 @@ export function createBootstrapNodeConfig(privateKey: string, port: number): Boo
|
|
|
231
233
|
peerIdPrivateKey: privateKey,
|
|
232
234
|
minPeerCount: 10,
|
|
233
235
|
maxPeerCount: 100,
|
|
236
|
+
dataDirectory: undefined,
|
|
237
|
+
dataStoreMapSizeKB: 0,
|
|
234
238
|
};
|
|
235
239
|
}
|
|
236
240
|
|
|
@@ -247,14 +251,16 @@ export async function createBootstrapNode(
|
|
|
247
251
|
port: number,
|
|
248
252
|
telemetry: TelemetryClient = new NoopTelemetryClient(),
|
|
249
253
|
): Promise<BootstrapNode> {
|
|
250
|
-
const peerId = await
|
|
254
|
+
const peerId = await createSecp256k1PeerId();
|
|
251
255
|
const config = createBootstrapNodeConfig(Buffer.from(peerId.privateKey!).toString('hex'), port);
|
|
252
256
|
|
|
253
257
|
return startBootstrapNode(config, telemetry);
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
async function startBootstrapNode(config: BootnodeConfig, telemetry: TelemetryClient) {
|
|
257
|
-
|
|
261
|
+
// Open an ephemeral store that will only exist in memory
|
|
262
|
+
const store = openTmpStore(true);
|
|
263
|
+
const bootstrapNode = new BootstrapNode(store, telemetry);
|
|
258
264
|
await bootstrapNode.start(config);
|
|
259
265
|
return bootstrapNode;
|
|
260
266
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { sleep } from '@aztec/foundation/sleep';
|
|
3
3
|
import { OtelMetricsAdapter, type TelemetryClient } from '@aztec/telemetry-client';
|
|
4
4
|
|
|
5
5
|
import { Discv5, type Discv5EventEmitter } from '@chainsafe/discv5';
|
|
6
6
|
import { ENR, SignableENR } from '@chainsafe/enr';
|
|
7
7
|
import type { PeerId } from '@libp2p/interface';
|
|
8
|
-
import { multiaddr } from '@multiformats/multiaddr';
|
|
8
|
+
import { type Multiaddr, multiaddr } from '@multiformats/multiaddr';
|
|
9
9
|
import EventEmitter from 'events';
|
|
10
10
|
|
|
11
11
|
import type { P2PConfig } from '../config.js';
|
|
@@ -35,6 +35,9 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
35
35
|
/** This instance's ENR */
|
|
36
36
|
private enr: SignableENR;
|
|
37
37
|
|
|
38
|
+
/** UDP listen addr */
|
|
39
|
+
private listenMultiAddrUdp: Multiaddr;
|
|
40
|
+
|
|
38
41
|
private currentState = PeerDiscoveryState.STOPPED;
|
|
39
42
|
|
|
40
43
|
private bootstrapNodes: string[];
|
|
@@ -46,7 +49,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
46
49
|
private peerId: PeerId,
|
|
47
50
|
config: P2PConfig,
|
|
48
51
|
telemetry: TelemetryClient,
|
|
49
|
-
private logger =
|
|
52
|
+
private logger = createLogger('p2p:discv5_service'),
|
|
50
53
|
) {
|
|
51
54
|
super();
|
|
52
55
|
const { tcpAnnounceAddress, udpAnnounceAddress, udpListenAddress, bootstrapNodes } = config;
|
|
@@ -66,7 +69,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
66
69
|
`${convertToMultiaddr(udpAnnounceAddress || tcpAnnounceAddress, 'udp')}/p2p/${peerId.toString()}`,
|
|
67
70
|
);
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
this.listenMultiAddrUdp = multiaddr(convertToMultiaddr(udpListenAddress, 'udp'));
|
|
70
73
|
|
|
71
74
|
// set location multiaddr in ENR record
|
|
72
75
|
this.enr.setLocationMultiaddr(multiAddrUdp);
|
|
@@ -76,7 +79,7 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
76
79
|
this.discv5 = Discv5.create({
|
|
77
80
|
enr: this.enr,
|
|
78
81
|
peerId,
|
|
79
|
-
bindAddrs: { ip4: listenMultiAddrUdp },
|
|
82
|
+
bindAddrs: { ip4: this.listenMultiAddrUdp },
|
|
80
83
|
config: {
|
|
81
84
|
lookupTimeout: 2000,
|
|
82
85
|
requestTimeout: 2000,
|
|
@@ -85,14 +88,11 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
85
88
|
metricsRegistry,
|
|
86
89
|
});
|
|
87
90
|
|
|
88
|
-
this.logger.info(`ENR NodeId: ${this.enr.nodeId}`);
|
|
89
|
-
this.logger.info(`ENR UDP: ${multiAddrUdp.toString()}`);
|
|
90
|
-
|
|
91
91
|
(this.discv5 as Discv5EventEmitter).on('discovered', (enr: ENR) => this.onDiscovered(enr));
|
|
92
92
|
(this.discv5 as Discv5EventEmitter).on('enrAdded', async (enr: ENR) => {
|
|
93
93
|
const multiAddrTcp = await enr.getFullMultiaddr('tcp');
|
|
94
94
|
const multiAddrUdp = await enr.getFullMultiaddr('udp');
|
|
95
|
-
this.logger.debug(`ENR
|
|
95
|
+
this.logger.debug(`Added ENR ${enr.encodeTxt()}`, { multiAddrTcp, multiAddrUdp, nodeId: enr.nodeId });
|
|
96
96
|
this.onDiscovered(enr);
|
|
97
97
|
});
|
|
98
98
|
}
|
|
@@ -101,18 +101,23 @@ export class DiscV5Service extends EventEmitter implements PeerDiscoveryService
|
|
|
101
101
|
if (this.currentState === PeerDiscoveryState.RUNNING) {
|
|
102
102
|
throw new Error('DiscV5Service already started');
|
|
103
103
|
}
|
|
104
|
-
this.logger.
|
|
104
|
+
this.logger.debug('Starting DiscV5');
|
|
105
105
|
await this.discv5.start();
|
|
106
106
|
this.startTime = Date.now();
|
|
107
107
|
|
|
108
|
-
this.logger.info(
|
|
108
|
+
this.logger.info(`DiscV5 service started`, {
|
|
109
|
+
nodeId: this.enr.nodeId,
|
|
110
|
+
peerId: this.peerId,
|
|
111
|
+
enrUdp: await this.enr.getFullMultiaddr('udp'),
|
|
112
|
+
enrTcp: await this.enr.getFullMultiaddr('tcp'),
|
|
113
|
+
});
|
|
109
114
|
this.currentState = PeerDiscoveryState.RUNNING;
|
|
110
115
|
|
|
111
116
|
// Add bootnode ENR if provided
|
|
112
117
|
if (this.bootstrapNodes?.length) {
|
|
113
118
|
// Do this conversion once since it involves an async function call
|
|
114
119
|
this.bootstrapNodePeerIds = await Promise.all(this.bootstrapNodes.map(enr => ENR.decodeTxt(enr).peerId()));
|
|
115
|
-
this.logger.info(`Adding bootstrap ENRs: ${this.bootstrapNodes.join(', ')}`);
|
|
120
|
+
this.logger.info(`Adding bootstrap nodes ENRs: ${this.bootstrapNodes.join(', ')}`);
|
|
116
121
|
try {
|
|
117
122
|
this.bootstrapNodes.forEach(enr => {
|
|
118
123
|
this.discv5.addEnr(enr);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlockAttestation, BlockProposal, Gossipable, TxHash } from '@aztec/circuit-types';
|
|
1
|
+
import type { BlockAttestation, BlockProposal, Gossipable, PeerInfo, TxHash } from '@aztec/circuit-types';
|
|
2
2
|
|
|
3
3
|
import type { PeerId } from '@libp2p/interface';
|
|
4
4
|
import EventEmitter from 'events';
|
|
@@ -10,6 +10,11 @@ import { type P2PService, type PeerDiscoveryService, PeerDiscoveryState } from '
|
|
|
10
10
|
* A dummy implementation of the P2P Service.
|
|
11
11
|
*/
|
|
12
12
|
export class DummyP2PService implements P2PService {
|
|
13
|
+
/** Returns an empty array for peers. */
|
|
14
|
+
getPeers(): PeerInfo[] {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
/**
|
|
14
19
|
* Starts the dummy implementation.
|
|
15
20
|
* @returns A resolved promise.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Taken from lodestar: https://github.com/ChainSafe/lodestar
|
|
2
|
+
import { sha256 } from '@aztec/foundation/crypto';
|
|
3
|
+
|
|
4
|
+
import { type RPC } from '@chainsafe/libp2p-gossipsub/message';
|
|
5
|
+
import { type DataTransform } from '@chainsafe/libp2p-gossipsub/types';
|
|
6
|
+
import { type Message } from '@libp2p/interface';
|
|
7
|
+
import { compressSync, uncompressSync } from 'snappy';
|
|
8
|
+
import xxhashFactory from 'xxhash-wasm';
|
|
9
|
+
|
|
10
|
+
// Load WASM
|
|
11
|
+
const xxhash = await xxhashFactory();
|
|
12
|
+
|
|
13
|
+
// Use salt to prevent msgId from being mined for collisions
|
|
14
|
+
const h64Seed = BigInt(Math.floor(Math.random() * 1e9));
|
|
15
|
+
|
|
16
|
+
// Shared buffer to convert msgId to string
|
|
17
|
+
const sharedMsgIdBuf = Buffer.alloc(20);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The function used to generate a gossipsub message id
|
|
21
|
+
* We use the first 8 bytes of SHA256(data) for content addressing
|
|
22
|
+
*/
|
|
23
|
+
export function fastMsgIdFn(rpcMsg: RPC.Message): string {
|
|
24
|
+
if (rpcMsg.data) {
|
|
25
|
+
return xxhash.h64Raw(rpcMsg.data, h64Seed).toString(16);
|
|
26
|
+
}
|
|
27
|
+
return '0000000000000000';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function msgIdToStrFn(msgId: Uint8Array): string {
|
|
31
|
+
// This happens serially, no need to reallocate the buffer
|
|
32
|
+
sharedMsgIdBuf.set(msgId);
|
|
33
|
+
return `0x${sharedMsgIdBuf.toString('hex')}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the message identifier from a libp2p message
|
|
38
|
+
*
|
|
39
|
+
* Follows similarly to:
|
|
40
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.7/specs/altair/p2p-interface.md#topics-and-messages
|
|
41
|
+
*
|
|
42
|
+
* @param message - The libp2p message
|
|
43
|
+
* @returns The message identifier
|
|
44
|
+
*/
|
|
45
|
+
export function getMsgIdFn(message: Message) {
|
|
46
|
+
const { topic } = message;
|
|
47
|
+
|
|
48
|
+
const vec = [Buffer.from(topic), message.data];
|
|
49
|
+
return sha256(Buffer.concat(vec)).subarray(0, 20);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class SnappyTransform implements DataTransform {
|
|
53
|
+
inboundTransform(_topicStr: string, data: Uint8Array): Uint8Array {
|
|
54
|
+
const uncompressed = Buffer.from(uncompressSync(Buffer.from(data), { asBuffer: true }));
|
|
55
|
+
return new Uint8Array(uncompressed);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
outboundTransform(_topicStr: string, data: Uint8Array): Uint8Array {
|
|
59
|
+
return new Uint8Array(compressSync(Buffer.from(data)));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type Gossipable,
|
|
7
7
|
type L2BlockSource,
|
|
8
8
|
MerkleTreeId,
|
|
9
|
+
type PeerInfo,
|
|
9
10
|
type RawGossipMessage,
|
|
10
11
|
TopicType,
|
|
11
12
|
TopicTypeMap,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
metricsTopicStrToLabels,
|
|
16
17
|
} from '@aztec/circuit-types';
|
|
17
18
|
import { Fr } from '@aztec/circuits.js';
|
|
18
|
-
import {
|
|
19
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
19
20
|
import { SerialQueue } from '@aztec/foundation/queue';
|
|
20
21
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
21
22
|
import type { AztecKVStore } from '@aztec/kv-store';
|
|
@@ -30,7 +31,6 @@ import { identify } from '@libp2p/identify';
|
|
|
30
31
|
import type { PeerId } from '@libp2p/interface';
|
|
31
32
|
import '@libp2p/kad-dht';
|
|
32
33
|
import { mplex } from '@libp2p/mplex';
|
|
33
|
-
import { createFromJSON, createSecp256k1PeerId } from '@libp2p/peer-id-factory';
|
|
34
34
|
import { tcp } from '@libp2p/tcp';
|
|
35
35
|
import { createLibp2p } from 'libp2p';
|
|
36
36
|
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
} from '../tx_validator/index.js';
|
|
45
45
|
import { type PubSubLibp2p, convertToMultiaddr } from '../util.js';
|
|
46
46
|
import { AztecDatastore } from './data_store.js';
|
|
47
|
+
import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from './encoding.js';
|
|
47
48
|
import { PeerManager } from './peer_manager.js';
|
|
48
49
|
import { PeerErrorSeverity } from './peer_scoring.js';
|
|
49
50
|
import { pingHandler, statusHandler } from './reqresp/handlers.js';
|
|
@@ -60,22 +61,6 @@ import {
|
|
|
60
61
|
import { ReqResp } from './reqresp/reqresp.js';
|
|
61
62
|
import type { P2PService, PeerDiscoveryService } from './service.js';
|
|
62
63
|
|
|
63
|
-
/**
|
|
64
|
-
* Create a libp2p peer ID from the private key if provided, otherwise creates a new random ID.
|
|
65
|
-
* @param privateKey - Optional peer ID private key as hex string
|
|
66
|
-
* @returns The peer ID.
|
|
67
|
-
*/
|
|
68
|
-
export async function createLibP2PPeerId(privateKey?: string): Promise<PeerId> {
|
|
69
|
-
if (!privateKey?.length) {
|
|
70
|
-
return await createSecp256k1PeerId();
|
|
71
|
-
}
|
|
72
|
-
const base64 = Buffer.from(privateKey, 'hex').toString('base64');
|
|
73
|
-
return await createFromJSON({
|
|
74
|
-
id: '',
|
|
75
|
-
privKey: base64,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
64
|
/**
|
|
80
65
|
* Lib P2P implementation of the P2PService interface.
|
|
81
66
|
*/
|
|
@@ -104,7 +89,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
104
89
|
private worldStateSynchronizer: WorldStateSynchronizer,
|
|
105
90
|
private telemetry: TelemetryClient,
|
|
106
91
|
private requestResponseHandlers: ReqRespSubProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS,
|
|
107
|
-
private logger =
|
|
92
|
+
private logger = createLogger('p2p:libp2p_service'),
|
|
108
93
|
) {
|
|
109
94
|
super(telemetry, 'LibP2PService');
|
|
110
95
|
|
|
@@ -133,20 +118,17 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
133
118
|
throw new Error('P2P service already started');
|
|
134
119
|
}
|
|
135
120
|
|
|
136
|
-
//
|
|
121
|
+
// Get listen & announce addresses for logging
|
|
137
122
|
const { tcpListenAddress, tcpAnnounceAddress } = this.config;
|
|
138
|
-
this.logger.info(`Starting P2P node on ${tcpListenAddress}`);
|
|
139
123
|
if (!tcpAnnounceAddress) {
|
|
140
124
|
throw new Error('Announce address not provided.');
|
|
141
125
|
}
|
|
142
126
|
const announceTcpMultiaddr = convertToMultiaddr(tcpAnnounceAddress, 'tcp');
|
|
143
|
-
this.logger.info(`Announcing at ${announceTcpMultiaddr}`);
|
|
144
127
|
|
|
145
128
|
// Start job queue, peer discovery service and libp2p node
|
|
146
129
|
this.jobQueue.start();
|
|
147
130
|
await this.peerDiscoveryService.start();
|
|
148
131
|
await this.node.start();
|
|
149
|
-
this.logger.info(`Started P2P client with Peer ID ${this.node.peerId.toString()}`);
|
|
150
132
|
|
|
151
133
|
// Subscribe to standard GossipSub topics by default
|
|
152
134
|
for (const topic in TopicType) {
|
|
@@ -156,7 +138,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
156
138
|
// add GossipSub listener
|
|
157
139
|
this.node.services.pubsub.addEventListener('gossipsub:message', async e => {
|
|
158
140
|
const { msg, propagationSource: peerId } = e.detail;
|
|
159
|
-
this.logger.
|
|
141
|
+
this.logger.trace(`Received PUBSUB message.`);
|
|
160
142
|
|
|
161
143
|
await this.jobQueue.put(() => this.handleNewGossipMessage(msg, peerId));
|
|
162
144
|
});
|
|
@@ -173,6 +155,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
173
155
|
[TX_REQ_PROTOCOL]: this.validateRequestedTx.bind(this),
|
|
174
156
|
};
|
|
175
157
|
await this.reqresp.start(this.requestResponseHandlers, reqrespSubProtocolValidators);
|
|
158
|
+
this.logger.info(`Started P2P service`, {
|
|
159
|
+
listen: tcpListenAddress,
|
|
160
|
+
announce: announceTcpMultiaddr,
|
|
161
|
+
peerId: this.node.peerId.toString(),
|
|
162
|
+
});
|
|
176
163
|
}
|
|
177
164
|
|
|
178
165
|
/**
|
|
@@ -191,7 +178,6 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
191
178
|
this.logger.debug('Stopping LibP2P...');
|
|
192
179
|
await this.stopLibP2P();
|
|
193
180
|
this.logger.info('LibP2P service stopped');
|
|
194
|
-
this.logger.debug('Stopping request response service...');
|
|
195
181
|
}
|
|
196
182
|
|
|
197
183
|
/**
|
|
@@ -259,6 +245,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
259
245
|
heartbeatInterval: config.gossipsubInterval,
|
|
260
246
|
mcacheLength: config.gossipsubMcacheLength,
|
|
261
247
|
mcacheGossip: config.gossipsubMcacheGossip,
|
|
248
|
+
msgIdFn: getMsgIdFn,
|
|
249
|
+
msgIdToStrFn: msgIdToStrFn,
|
|
250
|
+
fastMsgIdFn: fastMsgIdFn,
|
|
251
|
+
dataTransform: new SnappyTransform(),
|
|
262
252
|
metricsRegister: otelMetricsAdapter,
|
|
263
253
|
metricsTopicStrToLabel: metricsTopicStrToLabels(),
|
|
264
254
|
scoreParams: createPeerScoreParams({
|
|
@@ -295,11 +285,11 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
295
285
|
* @param msg - the tx request message
|
|
296
286
|
* @returns the tx response message
|
|
297
287
|
*/
|
|
298
|
-
const txHandler = (msg: Buffer): Promise<
|
|
288
|
+
const txHandler = (msg: Buffer): Promise<Buffer> => {
|
|
299
289
|
const txHash = TxHash.fromBuffer(msg);
|
|
300
290
|
const foundTx = mempools.txPool.getTxByHash(txHash);
|
|
301
|
-
const
|
|
302
|
-
return Promise.resolve(
|
|
291
|
+
const buf = foundTx ? foundTx.toBuffer() : Buffer.alloc(0);
|
|
292
|
+
return Promise.resolve(buf);
|
|
303
293
|
};
|
|
304
294
|
|
|
305
295
|
const requestResponseHandlers = {
|
|
@@ -321,6 +311,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
321
311
|
);
|
|
322
312
|
}
|
|
323
313
|
|
|
314
|
+
public getPeers(includePending?: boolean): PeerInfo[] {
|
|
315
|
+
return this.peerManager.getPeers(includePending);
|
|
316
|
+
}
|
|
317
|
+
|
|
324
318
|
/**
|
|
325
319
|
* Send Request via the ReqResp service
|
|
326
320
|
* The subprotocol defined will determine the request and response types
|
|
@@ -468,7 +462,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
468
462
|
* @param message - The message to propagate.
|
|
469
463
|
*/
|
|
470
464
|
public propagate<T extends Gossipable>(message: T): void {
|
|
471
|
-
this.logger.
|
|
465
|
+
this.logger.trace(`[${message.p2pMessageIdentifier()}] queued`);
|
|
472
466
|
void this.jobQueue.put(async () => {
|
|
473
467
|
await this.sendToPeers(message);
|
|
474
468
|
});
|
|
@@ -595,10 +589,10 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
595
589
|
const parent = message.constructor as typeof Gossipable;
|
|
596
590
|
|
|
597
591
|
const identifier = message.p2pMessageIdentifier().toString();
|
|
598
|
-
this.logger.
|
|
592
|
+
this.logger.trace(`Sending message ${identifier}`);
|
|
599
593
|
|
|
600
594
|
const recipientsNum = await this.publishToTopic(parent.p2pTopic, message.toBuffer());
|
|
601
|
-
this.logger.
|
|
595
|
+
this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`);
|
|
602
596
|
}
|
|
603
597
|
|
|
604
598
|
// Libp2p seems to hang sometimes if new peers are initiating connections.
|
|
@@ -609,7 +603,7 @@ export class LibP2PService extends WithTracer implements P2PService {
|
|
|
609
603
|
});
|
|
610
604
|
try {
|
|
611
605
|
await Promise.race([this.node.stop(), timeout]);
|
|
612
|
-
this.logger.debug('
|
|
606
|
+
this.logger.debug('LibP2P stopped');
|
|
613
607
|
} catch (error) {
|
|
614
608
|
this.logger.error('Error during stop or timeout:', error);
|
|
615
609
|
}
|