@aztec/p2p 0.67.1 → 0.68.1

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.
Files changed (211) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +5 -3
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +17 -15
  4. package/dest/client/factory.d.ts +19 -0
  5. package/dest/client/factory.d.ts.map +1 -0
  6. package/dest/client/factory.js +40 -0
  7. package/dest/client/index.d.ts +1 -15
  8. package/dest/client/index.d.ts.map +1 -1
  9. package/dest/client/index.js +2 -37
  10. package/dest/client/p2p_client.d.ts +6 -6
  11. package/dest/client/p2p_client.d.ts.map +1 -1
  12. package/dest/client/p2p_client.js +12 -11
  13. package/dest/config.d.ts +1 -1
  14. package/dest/config.d.ts.map +1 -1
  15. package/dest/config.js +3 -3
  16. package/dest/errors/reqresp.error.d.ts +12 -1
  17. package/dest/errors/reqresp.error.d.ts.map +1 -1
  18. package/dest/errors/reqresp.error.js +15 -2
  19. package/dest/index.d.ts +2 -2
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +3 -3
  22. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +9 -0
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +3 -0
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -0
  26. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +171 -0
  27. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +29 -0
  28. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -0
  29. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +114 -0
  30. package/dest/mem_pools/interface.d.ts +4 -3
  31. package/dest/mem_pools/interface.d.ts.map +1 -1
  32. package/dest/mocks/index.d.ts +7 -6
  33. package/dest/mocks/index.d.ts.map +1 -1
  34. package/dest/mocks/index.js +8 -8
  35. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +8 -0
  36. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -0
  37. package/dest/msg_validators/attestation_validator/attestation_validator.js +19 -0
  38. package/dest/msg_validators/attestation_validator/index.d.ts +2 -0
  39. package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -0
  40. package/dest/msg_validators/attestation_validator/index.js +2 -0
  41. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +8 -0
  42. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -0
  43. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +21 -0
  44. package/dest/msg_validators/block_proposal_validator/index.d.ts +2 -0
  45. package/dest/msg_validators/block_proposal_validator/index.d.ts.map +1 -0
  46. package/dest/msg_validators/block_proposal_validator/index.js +2 -0
  47. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts +8 -0
  48. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts.map +1 -0
  49. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.js +16 -0
  50. package/dest/msg_validators/epoch_proof_quote_validator/index.d.ts +2 -0
  51. package/dest/msg_validators/epoch_proof_quote_validator/index.d.ts.map +1 -0
  52. package/dest/msg_validators/epoch_proof_quote_validator/index.js +2 -0
  53. package/dest/msg_validators/index.d.ts +4 -0
  54. package/dest/msg_validators/index.d.ts.map +1 -0
  55. package/dest/msg_validators/index.js +4 -0
  56. package/dest/{tx_validator → msg_validators/tx_validator}/aggregate_tx_validator.d.ts +1 -1
  57. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -0
  58. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +34 -0
  59. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -0
  60. package/dest/{tx_validator → msg_validators/tx_validator}/data_validator.js +1 -1
  61. package/dest/{tx_validator → msg_validators/tx_validator}/double_spend_validator.d.ts +3 -2
  62. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -0
  63. package/dest/msg_validators/tx_validator/double_spend_validator.js +56 -0
  64. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -0
  65. package/dest/{tx_validator → msg_validators/tx_validator}/index.js +1 -1
  66. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -0
  67. package/dest/{tx_validator → msg_validators/tx_validator}/metadata_validator.js +1 -1
  68. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -0
  69. package/dest/msg_validators/tx_validator/tx_proof_validator.js +29 -0
  70. package/dest/services/data_store.d.ts.map +1 -0
  71. package/dest/services/data_store.js +188 -0
  72. package/dest/{service → services/discv5}/discV5_service.d.ts +3 -9
  73. package/dest/services/discv5/discV5_service.d.ts.map +1 -0
  74. package/dest/services/discv5/discV5_service.js +139 -0
  75. package/dest/services/dummy_service.d.ts.map +1 -0
  76. package/dest/{service → services}/dummy_service.js +1 -1
  77. package/dest/{service → services}/encoding.d.ts +5 -0
  78. package/dest/services/encoding.d.ts.map +1 -0
  79. package/dest/services/encoding.js +65 -0
  80. package/dest/services/index.d.ts +3 -0
  81. package/dest/services/index.d.ts.map +1 -0
  82. package/dest/services/index.js +3 -0
  83. package/dest/services/libp2p/libp2p_service.d.ts +222 -0
  84. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -0
  85. package/dest/services/libp2p/libp2p_service.js +697 -0
  86. package/dest/services/peer-scoring/peer_scoring.d.ts +25 -0
  87. package/dest/services/peer-scoring/peer_scoring.d.ts.map +1 -0
  88. package/dest/services/peer-scoring/peer_scoring.js +75 -0
  89. package/dest/services/peer_manager.d.ts +60 -0
  90. package/dest/services/peer_manager.d.ts.map +1 -0
  91. package/dest/services/peer_manager.js +358 -0
  92. package/dest/services/reqresp/config.d.ts.map +1 -0
  93. package/dest/{service → services}/reqresp/config.js +1 -1
  94. package/dest/services/reqresp/handlers.d.ts.map +1 -0
  95. package/dest/{service → services}/reqresp/handlers.js +1 -1
  96. package/dest/services/reqresp/index.d.ts.map +1 -0
  97. package/dest/{service → services}/reqresp/index.js +1 -1
  98. package/dest/services/reqresp/interface.d.ts.map +1 -0
  99. package/dest/{service → services}/reqresp/interface.js +1 -1
  100. package/dest/services/reqresp/rate_limiter/index.d.ts.map +1 -0
  101. package/dest/{service → services}/reqresp/rate_limiter/index.js +1 -1
  102. package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.d.ts +0 -5
  103. package/dest/services/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -0
  104. package/dest/{service → services}/reqresp/rate_limiter/rate_limiter.js +7 -2
  105. package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +1 -0
  106. package/dest/{service → services}/reqresp/rate_limiter/rate_limits.js +1 -1
  107. package/dest/{service → services}/reqresp/reqresp.d.ts +16 -0
  108. package/dest/services/reqresp/reqresp.d.ts.map +1 -0
  109. package/dest/services/reqresp/reqresp.js +279 -0
  110. package/dest/services/service.d.ts.map +1 -0
  111. package/dest/{service → services}/service.js +1 -1
  112. package/dest/services/types.d.ts +38 -0
  113. package/dest/services/types.d.ts.map +1 -0
  114. package/dest/services/types.js +43 -0
  115. package/package.json +14 -11
  116. package/src/bootstrap/bootstrap.ts +25 -20
  117. package/src/client/factory.ts +97 -0
  118. package/src/client/index.ts +1 -73
  119. package/src/client/p2p_client.ts +28 -15
  120. package/src/config.ts +2 -2
  121. package/src/errors/reqresp.error.ts +15 -1
  122. package/src/index.ts +2 -2
  123. package/src/mem_pools/attestation_pool/attestation_pool.ts +10 -0
  124. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +237 -0
  125. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +153 -0
  126. package/src/mem_pools/interface.ts +5 -3
  127. package/src/mocks/index.ts +16 -10
  128. package/src/msg_validators/attestation_validator/attestation_validator.ts +26 -0
  129. package/src/msg_validators/attestation_validator/index.ts +1 -0
  130. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +29 -0
  131. package/src/msg_validators/block_proposal_validator/index.ts +1 -0
  132. package/src/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.ts +22 -0
  133. package/src/msg_validators/epoch_proof_quote_validator/index.ts +1 -0
  134. package/src/msg_validators/index.ts +3 -0
  135. package/src/{tx_validator → msg_validators/tx_validator}/aggregate_tx_validator.ts +5 -3
  136. package/src/{tx_validator → msg_validators/tx_validator}/double_spend_validator.ts +6 -8
  137. package/src/{service → services/discv5}/discV5_service.ts +19 -23
  138. package/src/{service → services}/encoding.ts +21 -3
  139. package/src/services/index.ts +2 -0
  140. package/src/{service → services/libp2p}/libp2p_service.ts +350 -90
  141. package/src/{service → services/peer-scoring}/peer_scoring.ts +27 -23
  142. package/src/services/peer_manager.ts +422 -0
  143. package/src/{service → services}/reqresp/rate_limiter/rate_limiter.ts +2 -1
  144. package/src/{service → services}/reqresp/reqresp.ts +86 -20
  145. package/src/services/types.ts +44 -0
  146. package/dest/service/data_store.d.ts.map +0 -1
  147. package/dest/service/data_store.js +0 -188
  148. package/dest/service/discV5_service.d.ts.map +0 -1
  149. package/dest/service/discV5_service.js +0 -144
  150. package/dest/service/dummy_service.d.ts.map +0 -1
  151. package/dest/service/encoding.d.ts.map +0 -1
  152. package/dest/service/encoding.js +0 -49
  153. package/dest/service/index.d.ts +0 -3
  154. package/dest/service/index.d.ts.map +0 -1
  155. package/dest/service/index.js +0 -3
  156. package/dest/service/libp2p_service.d.ts +0 -136
  157. package/dest/service/libp2p_service.d.ts.map +0 -1
  158. package/dest/service/libp2p_service.js +0 -500
  159. package/dest/service/peer_manager.d.ts +0 -33
  160. package/dest/service/peer_manager.d.ts.map +0 -1
  161. package/dest/service/peer_manager.js +0 -214
  162. package/dest/service/peer_scoring.d.ts +0 -35
  163. package/dest/service/peer_scoring.d.ts.map +0 -1
  164. package/dest/service/peer_scoring.js +0 -72
  165. package/dest/service/reqresp/config.d.ts.map +0 -1
  166. package/dest/service/reqresp/handlers.d.ts.map +0 -1
  167. package/dest/service/reqresp/index.d.ts.map +0 -1
  168. package/dest/service/reqresp/interface.d.ts.map +0 -1
  169. package/dest/service/reqresp/rate_limiter/index.d.ts.map +0 -1
  170. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +0 -1
  171. package/dest/service/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
  172. package/dest/service/reqresp/reqresp.d.ts.map +0 -1
  173. package/dest/service/reqresp/reqresp.js +0 -230
  174. package/dest/service/service.d.ts.map +0 -1
  175. package/dest/tx_validator/aggregate_tx_validator.d.ts.map +0 -1
  176. package/dest/tx_validator/aggregate_tx_validator.js +0 -32
  177. package/dest/tx_validator/data_validator.d.ts.map +0 -1
  178. package/dest/tx_validator/double_spend_validator.d.ts.map +0 -1
  179. package/dest/tx_validator/double_spend_validator.js +0 -56
  180. package/dest/tx_validator/index.d.ts.map +0 -1
  181. package/dest/tx_validator/metadata_validator.d.ts.map +0 -1
  182. package/dest/tx_validator/tx_proof_validator.d.ts.map +0 -1
  183. package/dest/tx_validator/tx_proof_validator.js +0 -29
  184. package/src/service/index.ts +0 -2
  185. package/src/service/peer_manager.ts +0 -266
  186. /package/dest/{tx_validator → msg_validators/tx_validator}/data_validator.d.ts +0 -0
  187. /package/dest/{tx_validator → msg_validators/tx_validator}/index.d.ts +0 -0
  188. /package/dest/{tx_validator → msg_validators/tx_validator}/metadata_validator.d.ts +0 -0
  189. /package/dest/{tx_validator → msg_validators/tx_validator}/tx_proof_validator.d.ts +0 -0
  190. /package/dest/{service → services}/data_store.d.ts +0 -0
  191. /package/dest/{service → services}/dummy_service.d.ts +0 -0
  192. /package/dest/{service → services}/reqresp/config.d.ts +0 -0
  193. /package/dest/{service → services}/reqresp/handlers.d.ts +0 -0
  194. /package/dest/{service → services}/reqresp/index.d.ts +0 -0
  195. /package/dest/{service → services}/reqresp/interface.d.ts +0 -0
  196. /package/dest/{service → services}/reqresp/rate_limiter/index.d.ts +0 -0
  197. /package/dest/{service → services}/reqresp/rate_limiter/rate_limits.d.ts +0 -0
  198. /package/dest/{service → services}/service.d.ts +0 -0
  199. /package/src/{tx_validator → msg_validators/tx_validator}/data_validator.ts +0 -0
  200. /package/src/{tx_validator → msg_validators/tx_validator}/index.ts +0 -0
  201. /package/src/{tx_validator → msg_validators/tx_validator}/metadata_validator.ts +0 -0
  202. /package/src/{tx_validator → msg_validators/tx_validator}/tx_proof_validator.ts +0 -0
  203. /package/src/{service → services}/data_store.ts +0 -0
  204. /package/src/{service → services}/dummy_service.ts +0 -0
  205. /package/src/{service → services}/reqresp/config.ts +0 -0
  206. /package/src/{service → services}/reqresp/handlers.ts +0 -0
  207. /package/src/{service → services}/reqresp/index.ts +0 -0
  208. /package/src/{service → services}/reqresp/interface.ts +0 -0
  209. /package/src/{service → services}/reqresp/rate_limiter/index.ts +0 -0
  210. /package/src/{service → services}/reqresp/rate_limiter/rate_limits.ts +0 -0
  211. /package/src/{service → services}/service.ts +0 -0
@@ -6,16 +6,19 @@ import {
6
6
  type Gossipable,
7
7
  type L2BlockSource,
8
8
  MerkleTreeId,
9
+ PeerErrorSeverity,
9
10
  type PeerInfo,
10
11
  type RawGossipMessage,
11
- TopicType,
12
12
  TopicTypeMap,
13
13
  Tx,
14
14
  TxHash,
15
15
  type WorldStateSynchronizer,
16
+ getTopicTypeForClientType,
16
17
  metricsTopicStrToLabels,
17
18
  } from '@aztec/circuit-types';
19
+ import { P2PClientType } from '@aztec/circuit-types';
18
20
  import { Fr } from '@aztec/circuits.js';
21
+ import { type EpochCache } from '@aztec/epoch-cache';
19
22
  import { createLogger } from '@aztec/foundation/log';
20
23
  import { SerialQueue } from '@aztec/foundation/queue';
21
24
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -23,31 +26,37 @@ import type { AztecKVStore } from '@aztec/kv-store';
23
26
  import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
24
27
 
25
28
  import { type ENR } from '@chainsafe/enr';
26
- import { type GossipSub, type GossipSubComponents, gossipsub } from '@chainsafe/libp2p-gossipsub';
29
+ import {
30
+ type GossipSub,
31
+ type GossipSubComponents,
32
+ type GossipsubMessage,
33
+ gossipsub,
34
+ } from '@chainsafe/libp2p-gossipsub';
27
35
  import { createPeerScoreParams, createTopicScoreParams } from '@chainsafe/libp2p-gossipsub/score';
28
36
  import { noise } from '@chainsafe/libp2p-noise';
29
37
  import { yamux } from '@chainsafe/libp2p-yamux';
30
38
  import { identify } from '@libp2p/identify';
31
- import type { PeerId } from '@libp2p/interface';
39
+ import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
32
40
  import '@libp2p/kad-dht';
33
41
  import { mplex } from '@libp2p/mplex';
34
42
  import { tcp } from '@libp2p/tcp';
35
43
  import { createLibp2p } from 'libp2p';
36
44
 
37
- import { type P2PConfig } from '../config.js';
38
- import { type MemPools } from '../mem_pools/interface.js';
45
+ import { type P2PConfig } from '../../config.js';
46
+ import { type MemPools } from '../../mem_pools/interface.js';
47
+ import { EpochProofQuoteValidator } from '../../msg_validators/epoch_proof_quote_validator/index.js';
48
+ import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
39
49
  import {
40
50
  DataTxValidator,
41
51
  DoubleSpendTxValidator,
42
52
  MetadataTxValidator,
43
53
  TxProofValidator,
44
- } from '../tx_validator/index.js';
45
- import { type PubSubLibp2p, convertToMultiaddr } from '../util.js';
46
- import { AztecDatastore } from './data_store.js';
47
- import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from './encoding.js';
48
- import { PeerManager } from './peer_manager.js';
49
- import { PeerErrorSeverity } from './peer_scoring.js';
50
- import { pingHandler, statusHandler } from './reqresp/handlers.js';
54
+ } from '../../msg_validators/tx_validator/index.js';
55
+ import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
56
+ import { AztecDatastore } from '../data_store.js';
57
+ import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
58
+ import { PeerManager } from '../peer_manager.js';
59
+ import { pingHandler, statusHandler } from '../reqresp/handlers.js';
51
60
  import {
52
61
  DEFAULT_SUB_PROTOCOL_HANDLERS,
53
62
  DEFAULT_SUB_PROTOCOL_VALIDATORS,
@@ -57,18 +66,39 @@ import {
57
66
  STATUS_PROTOCOL,
58
67
  type SubProtocolMap,
59
68
  TX_REQ_PROTOCOL,
60
- } from './reqresp/interface.js';
61
- import { ReqResp } from './reqresp/reqresp.js';
62
- import type { P2PService, PeerDiscoveryService } from './service.js';
69
+ } from '../reqresp/interface.js';
70
+ import { ReqResp } from '../reqresp/reqresp.js';
71
+ import type { P2PService, PeerDiscoveryService } from '../service.js';
72
+ import { GossipSubEvent } from '../types.js';
73
+
74
+ interface MessageValidator {
75
+ validator: {
76
+ validateTx(tx: Tx): Promise<boolean>;
77
+ };
78
+ severity: PeerErrorSeverity;
79
+ }
80
+
81
+ interface ValidationResult {
82
+ name: string;
83
+ isValid: boolean;
84
+ severity: PeerErrorSeverity;
85
+ }
86
+
87
+ type ValidationOutcome = { allPassed: true } | { allPassed: false; failure: ValidationResult };
63
88
 
64
89
  /**
65
90
  * Lib P2P implementation of the P2PService interface.
66
91
  */
67
- export class LibP2PService extends WithTracer implements P2PService {
92
+ export class LibP2PService<T extends P2PClientType> extends WithTracer implements P2PService {
68
93
  private jobQueue: SerialQueue = new SerialQueue();
69
94
  private peerManager: PeerManager;
70
95
  private discoveryRunningPromise?: RunningPromise;
71
96
 
97
+ // Message validators
98
+ private attestationValidator: AttestationValidator;
99
+ private blockProposalValidator: BlockProposalValidator;
100
+ private epochProofQuoteValidator: EpochProofQuoteValidator;
101
+
72
102
  // Request and response sub service
73
103
  public reqresp: ReqResp;
74
104
 
@@ -80,11 +110,13 @@ export class LibP2PService extends WithTracer implements P2PService {
80
110
  private blockReceivedCallback: (block: BlockProposal) => Promise<BlockAttestation | undefined>;
81
111
 
82
112
  constructor(
113
+ private clientType: T,
83
114
  private config: P2PConfig,
84
115
  private node: PubSubLibp2p,
85
116
  private peerDiscoveryService: PeerDiscoveryService,
86
- private mempools: MemPools,
117
+ private mempools: MemPools<T>,
87
118
  private l2BlockSource: L2BlockSource,
119
+ private epochCache: EpochCache,
88
120
  private proofVerifier: ClientProtocolCircuitVerifier,
89
121
  private worldStateSynchronizer: WorldStateSynchronizer,
90
122
  private telemetry: TelemetryClient,
@@ -93,13 +125,17 @@ export class LibP2PService extends WithTracer implements P2PService {
93
125
  ) {
94
126
  super(telemetry, 'LibP2PService');
95
127
 
96
- this.peerManager = new PeerManager(node, peerDiscoveryService, config, logger);
128
+ this.peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, logger);
97
129
  this.node.services.pubsub.score.params.appSpecificScore = (peerId: string) => {
98
130
  return this.peerManager.getPeerScore(peerId);
99
131
  };
100
132
  this.node.services.pubsub.score.params.appSpecificWeight = 10;
101
133
  this.reqresp = new ReqResp(config, node, this.peerManager);
102
134
 
135
+ this.attestationValidator = new AttestationValidator(epochCache);
136
+ this.blockProposalValidator = new BlockProposalValidator(epochCache);
137
+ this.epochProofQuoteValidator = new EpochProofQuoteValidator(epochCache);
138
+
103
139
  this.blockReceivedCallback = (block: BlockProposal): Promise<BlockAttestation | undefined> => {
104
140
  this.logger.verbose(
105
141
  `[WARNING] handler not yet registered: Block received callback not set. Received block ${block.p2pMessageIdentifier()} from peer.`,
@@ -131,22 +167,32 @@ export class LibP2PService extends WithTracer implements P2PService {
131
167
  await this.node.start();
132
168
 
133
169
  // Subscribe to standard GossipSub topics by default
134
- for (const topic in TopicType) {
170
+ for (const topic of getTopicTypeForClientType(this.clientType)) {
135
171
  this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
136
172
  }
137
173
 
138
- // add GossipSub listener
139
- this.node.services.pubsub.addEventListener('gossipsub:message', async e => {
140
- const { msg, propagationSource: peerId } = e.detail;
141
- this.logger.trace(`Received PUBSUB message.`);
174
+ // Add p2p topic validators
175
+ // As they are stored within a kv pair, there is no need to register them conditionally
176
+ // based on the client type
177
+ const topicValidators = {
178
+ [Tx.p2pTopic]: this.validatePropagatedTxFromMessage.bind(this),
179
+ [BlockAttestation.p2pTopic]: this.validatePropagatedAttestationFromMessage.bind(this),
180
+ [BlockProposal.p2pTopic]: this.validatePropagatedBlockFromMessage.bind(this),
181
+ [EpochProofQuote.p2pTopic]: this.validatePropagatedEpochProofQuoteFromMessage.bind(this),
182
+ };
183
+ for (const [topic, validator] of Object.entries(topicValidators)) {
184
+ this.node.services.pubsub.topicValidators.set(topic, validator);
185
+ }
142
186
 
143
- await this.jobQueue.put(() => this.handleNewGossipMessage(msg, peerId));
144
- });
187
+ // add GossipSub listener
188
+ this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
145
189
 
146
190
  // Start running promise for peer discovery
147
- this.discoveryRunningPromise = new RunningPromise(() => {
148
- this.peerManager.heartbeat();
149
- }, this.config.peerCheckIntervalMS);
191
+ this.discoveryRunningPromise = new RunningPromise(
192
+ () => this.peerManager.heartbeat(),
193
+ this.logger,
194
+ this.config.peerCheckIntervalMS,
195
+ );
150
196
  this.discoveryRunningPromise.start();
151
197
 
152
198
  // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
@@ -167,6 +213,13 @@ export class LibP2PService extends WithTracer implements P2PService {
167
213
  * @returns An empty promise.
168
214
  */
169
215
  public async stop() {
216
+ // Remove gossip sub listener
217
+ this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
218
+
219
+ // Stop peer manager
220
+ this.logger.debug('Stopping peer manager...');
221
+ this.peerManager.stop();
222
+
170
223
  this.logger.debug('Stopping job queue...');
171
224
  await this.jobQueue.end();
172
225
  this.logger.debug('Stopping running promise...');
@@ -186,12 +239,14 @@ export class LibP2PService extends WithTracer implements P2PService {
186
239
  * @param txPool - The transaction pool to be accessed by the service.
187
240
  * @returns The new service.
188
241
  */
189
- public static async new(
242
+ public static async new<T extends P2PClientType>(
243
+ clientType: T,
190
244
  config: P2PConfig,
191
245
  peerDiscoveryService: PeerDiscoveryService,
192
246
  peerId: PeerId,
193
- mempools: MemPools,
247
+ mempools: MemPools<T>,
194
248
  l2BlockSource: L2BlockSource,
249
+ epochCache: EpochCache,
195
250
  proofVerifier: ClientProtocolCircuitVerifier,
196
251
  worldStateSynchronizer: WorldStateSynchronizer,
197
252
  store: AztecKVStore,
@@ -251,6 +306,7 @@ export class LibP2PService extends WithTracer implements P2PService {
251
306
  dataTransform: new SnappyTransform(),
252
307
  metricsRegister: otelMetricsAdapter,
253
308
  metricsTopicStrToLabel: metricsTopicStrToLabels(),
309
+ asyncValidation: true,
254
310
  scoreParams: createPeerScoreParams({
255
311
  topics: {
256
312
  [Tx.p2pTopic]: createTopicScoreParams({
@@ -299,11 +355,13 @@ export class LibP2PService extends WithTracer implements P2PService {
299
355
  };
300
356
 
301
357
  return new LibP2PService(
358
+ clientType,
302
359
  config,
303
360
  node,
304
361
  peerDiscoveryService,
305
362
  mempools,
306
363
  l2BlockSource,
364
+ epochCache,
307
365
  proofVerifier,
308
366
  worldStateSynchronizer,
309
367
  telemetry,
@@ -315,6 +373,13 @@ export class LibP2PService extends WithTracer implements P2PService {
315
373
  return this.peerManager.getPeers(includePending);
316
374
  }
317
375
 
376
+ private async handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
377
+ const { msg } = e.detail;
378
+ this.logger.trace(`Received PUBSUB message.`);
379
+
380
+ await this.jobQueue.put(() => this.handleNewGossipMessage(msg));
381
+ }
382
+
318
383
  /**
319
384
  * Send Request via the ReqResp service
320
385
  * The subprotocol defined will determine the request and response types
@@ -376,12 +441,12 @@ export class LibP2PService extends WithTracer implements P2PService {
376
441
  * @param topic - The message's topic.
377
442
  * @param data - The message data
378
443
  */
379
- private async handleNewGossipMessage(message: RawGossipMessage, peerId: PeerId) {
444
+ private async handleNewGossipMessage(message: RawGossipMessage) {
380
445
  if (message.topic === Tx.p2pTopic) {
381
446
  const tx = Tx.fromBuffer(Buffer.from(message.data));
382
- await this.processTxFromPeer(tx, peerId);
447
+ await this.processTxFromPeer(tx);
383
448
  }
384
- if (message.topic === BlockAttestation.p2pTopic) {
449
+ if (message.topic === BlockAttestation.p2pTopic && this.clientType === P2PClientType.Full) {
385
450
  const attestation = BlockAttestation.fromBuffer(Buffer.from(message.data));
386
451
  await this.processAttestationFromPeer(attestation);
387
452
  }
@@ -410,7 +475,7 @@ export class LibP2PService extends WithTracer implements P2PService {
410
475
  }))
411
476
  private async processAttestationFromPeer(attestation: BlockAttestation): Promise<void> {
412
477
  this.logger.debug(`Received attestation ${attestation.p2pMessageIdentifier()} from external peer.`);
413
- await this.mempools.attestationPool.addAttestations([attestation]);
478
+ await this.mempools.attestationPool!.addAttestations([attestation]);
414
479
  }
415
480
 
416
481
  /**Process block from peer
@@ -468,16 +533,11 @@ export class LibP2PService extends WithTracer implements P2PService {
468
533
  });
469
534
  }
470
535
 
471
- private async processTxFromPeer(tx: Tx, peerId: PeerId): Promise<void> {
536
+ private async processTxFromPeer(tx: Tx): Promise<void> {
472
537
  const txHash = tx.getTxHash();
473
538
  const txHashString = txHash.toString();
474
539
  this.logger.verbose(`Received tx ${txHashString} from external peer.`);
475
-
476
- const isValidTx = await this.validatePropagatedTx(tx, peerId);
477
-
478
- if (isValidTx) {
479
- await this.mempools.txPool.addTxs([tx]);
480
- }
540
+ await this.mempools.txPool.addTxs([tx]);
481
541
  }
482
542
 
483
543
  /**
@@ -494,6 +554,9 @@ export class LibP2PService extends WithTracer implements P2PService {
494
554
  * @param peerId - The peer ID of the peer that sent the tx.
495
555
  * @returns True if the tx is valid, false otherwise.
496
556
  */
557
+ @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
558
+ [Attributes.TX_HASH]: requestedTxHash.toString(),
559
+ }))
497
560
  private async validateRequestedTx(requestedTxHash: TxHash, responseTx: Tx, peerId: PeerId): Promise<boolean> {
498
561
  const proofValidator = new TxProofValidator(this.proofVerifier);
499
562
  const validProof = await proofValidator.validateTx(responseTx);
@@ -514,67 +577,264 @@ export class LibP2PService extends WithTracer implements P2PService {
514
577
  return true;
515
578
  }
516
579
 
580
+ /**
581
+ * Validate a tx from a peer.
582
+ * @param propagationSource - The peer ID of the peer that sent the tx.
583
+ * @param msg - The tx message.
584
+ * @returns True if the tx is valid, false otherwise.
585
+ */
586
+ private async validatePropagatedTxFromMessage(
587
+ propagationSource: PeerId,
588
+ msg: Message,
589
+ ): Promise<TopicValidatorResult> {
590
+ const tx = Tx.fromBuffer(Buffer.from(msg.data));
591
+ const isValid = await this.validatePropagatedTx(tx, propagationSource);
592
+ this.logger.trace(`validatePropagatedTx: ${isValid}`, {
593
+ [Attributes.TX_HASH]: tx.getTxHash().toString(),
594
+ [Attributes.P2P_ID]: propagationSource.toString(),
595
+ });
596
+ return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
597
+ }
598
+
599
+ /**
600
+ * Validate an attestation from a peer.
601
+ * @param propagationSource - The peer ID of the peer that sent the attestation.
602
+ * @param msg - The attestation message.
603
+ * @returns True if the attestation is valid, false otherwise.
604
+ */
605
+ private async validatePropagatedAttestationFromMessage(
606
+ propagationSource: PeerId,
607
+ msg: Message,
608
+ ): Promise<TopicValidatorResult> {
609
+ const attestation = BlockAttestation.fromBuffer(Buffer.from(msg.data));
610
+ const isValid = await this.validateAttestation(propagationSource, attestation);
611
+ this.logger.trace(`validatePropagatedAttestation: ${isValid}`, {
612
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toString(),
613
+ [Attributes.P2P_ID]: propagationSource.toString(),
614
+ });
615
+ return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
616
+ }
617
+
618
+ /**
619
+ * Validate a block proposal from a peer.
620
+ * @param propagationSource - The peer ID of the peer that sent the block.
621
+ * @param msg - The block proposal message.
622
+ * @returns True if the block proposal is valid, false otherwise.
623
+ */
624
+ private async validatePropagatedBlockFromMessage(
625
+ propagationSource: PeerId,
626
+ msg: Message,
627
+ ): Promise<TopicValidatorResult> {
628
+ const block = BlockProposal.fromBuffer(Buffer.from(msg.data));
629
+ const isValid = await this.validateBlockProposal(propagationSource, block);
630
+ this.logger.trace(`validatePropagatedBlock: ${isValid}`, {
631
+ [Attributes.SLOT_NUMBER]: block.payload.header.globalVariables.slotNumber.toString(),
632
+ [Attributes.P2P_ID]: propagationSource.toString(),
633
+ });
634
+ return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
635
+ }
636
+
637
+ /**
638
+ * Validate an epoch proof quote from a peer.
639
+ * @param propagationSource - The peer ID of the peer that sent the epoch proof quote.
640
+ * @param msg - The epoch proof quote message.
641
+ * @returns True if the epoch proof quote is valid, false otherwise.
642
+ */
643
+ private async validatePropagatedEpochProofQuoteFromMessage(
644
+ propagationSource: PeerId,
645
+ msg: Message,
646
+ ): Promise<TopicValidatorResult> {
647
+ const epochProofQuote = EpochProofQuote.fromBuffer(Buffer.from(msg.data));
648
+ const isValid = await this.validateEpochProofQuote(propagationSource, epochProofQuote);
649
+ this.logger.trace(`validatePropagatedEpochProofQuote: ${isValid}`, {
650
+ [Attributes.EPOCH_NUMBER]: epochProofQuote.payload.epochToProve.toString(),
651
+ [Attributes.P2P_ID]: propagationSource.toString(),
652
+ });
653
+ return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
654
+ }
655
+
656
+ @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
657
+ [Attributes.TX_HASH]: tx.getTxHash().toString(),
658
+ }))
517
659
  private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
518
660
  const blockNumber = (await this.l2BlockSource.getBlockNumber()) + 1;
519
- // basic data validation
520
- const dataValidator = new DataTxValidator();
521
- const validData = await dataValidator.validateTx(tx);
522
- if (!validData) {
523
- // penalize
524
- this.node.services.pubsub.score.markInvalidMessageDelivery(peerId.toString(), Tx.p2pTopic);
525
- return false;
661
+ const messageValidators = this.createMessageValidators(blockNumber);
662
+ const outcome = await this.runValidations(tx, messageValidators);
663
+
664
+ if (outcome.allPassed) {
665
+ return true;
526
666
  }
527
667
 
528
- // metadata validation
529
- const metadataValidator = new MetadataTxValidator(new Fr(this.config.l1ChainId), new Fr(blockNumber));
530
- const validMetadata = await metadataValidator.validateTx(tx);
531
- if (!validMetadata) {
532
- // penalize
533
- this.node.services.pubsub.score.markInvalidMessageDelivery(peerId.toString(), Tx.p2pTopic);
668
+ const { name, severity } = outcome.failure;
669
+
670
+ // Double spend validator has a special case handler
671
+ if (name === 'doubleSpendValidator') {
672
+ const isValid = await this.handleDoubleSpendFailure(tx, blockNumber, peerId);
673
+ if (isValid) {
674
+ return true;
675
+ }
676
+ }
677
+
678
+ this.peerManager.penalizePeer(peerId, severity);
679
+ return false;
680
+ }
681
+
682
+ /**
683
+ * Create message validators for the given block number.
684
+ *
685
+ * Each validator is a pair of a validator and a severity.
686
+ * If a validator fails, the peer is penalized with the severity of the validator.
687
+ *
688
+ * @param blockNumber - The block number to create validators for.
689
+ * @returns The message validators.
690
+ */
691
+ private createMessageValidators(blockNumber: number): Record<string, MessageValidator> {
692
+ return {
693
+ dataValidator: {
694
+ validator: new DataTxValidator(),
695
+ severity: PeerErrorSeverity.HighToleranceError,
696
+ },
697
+ metadataValidator: {
698
+ validator: new MetadataTxValidator(new Fr(this.config.l1ChainId), new Fr(blockNumber)),
699
+ severity: PeerErrorSeverity.HighToleranceError,
700
+ },
701
+ proofValidator: {
702
+ validator: new TxProofValidator(this.proofVerifier),
703
+ severity: PeerErrorSeverity.MidToleranceError,
704
+ },
705
+ doubleSpendValidator: {
706
+ validator: new DoubleSpendTxValidator({
707
+ getNullifierIndices: (nullifiers: Buffer[]) => {
708
+ const merkleTree = this.worldStateSynchronizer.getCommitted();
709
+ return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
710
+ },
711
+ }),
712
+ severity: PeerErrorSeverity.HighToleranceError,
713
+ },
714
+ };
715
+ }
716
+
717
+ /**
718
+ * Run validations on a tx.
719
+ * @param tx - The tx to validate.
720
+ * @param messageValidators - The message validators to run.
721
+ * @returns The validation outcome.
722
+ */
723
+ private async runValidations(
724
+ tx: Tx,
725
+ messageValidators: Record<string, MessageValidator>,
726
+ ): Promise<ValidationOutcome> {
727
+ const validationPromises = Object.entries(messageValidators).map(async ([name, { validator, severity }]) => {
728
+ const isValid = await validator.validateTx(tx);
729
+ return { name, isValid, severity };
730
+ });
731
+
732
+ // A promise that resolves when all validations have been run
733
+ const allValidations = Promise.all(validationPromises);
734
+
735
+ // A promise that resolves when the first validation fails
736
+ const firstFailure = Promise.race(
737
+ validationPromises.map(async promise => {
738
+ const result = await promise;
739
+ return result.isValid ? new Promise(() => {}) : result;
740
+ }),
741
+ );
742
+
743
+ // Wait for the first validation to fail or all validations to pass
744
+ const result = await Promise.race([
745
+ allValidations.then(() => ({ allPassed: true as const })),
746
+ firstFailure.then(failure => ({ allPassed: false as const, failure: failure as ValidationResult })),
747
+ ]);
748
+
749
+ // If all validations pass, allPassed will be true, if failed, then the failure will be the first validation to fail
750
+ return result;
751
+ }
752
+
753
+ /**
754
+ * Handle a double spend failure.
755
+ *
756
+ * Double spend failures are managed on their own because they are a special case.
757
+ * We must check if the double spend is recent or old, if it is past a threshold, then we heavily penalize the peer.
758
+ *
759
+ * @param tx - The tx that failed the double spend validator.
760
+ * @param blockNumber - The block number of the tx.
761
+ * @param peerId - The peer ID of the peer that sent the tx.
762
+ * @returns True if the tx is valid, false otherwise.
763
+ */
764
+ private async handleDoubleSpendFailure(tx: Tx, blockNumber: number, peerId: PeerId): Promise<boolean> {
765
+ if (blockNumber <= this.config.severePeerPenaltyBlockLength) {
534
766
  return false;
535
767
  }
536
768
 
537
- // double spend validation
538
- const doubleSpendValidator = new DoubleSpendTxValidator({
539
- getNullifierIndex: async (nullifier: Fr) => {
540
- const merkleTree = this.worldStateSynchronizer.getCommitted();
541
- const index = await merkleTree.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
542
- return index;
769
+ const snapshotValidator = new DoubleSpendTxValidator({
770
+ getNullifierIndices: (nullifiers: Buffer[]) => {
771
+ const merkleTree = this.worldStateSynchronizer.getSnapshot(
772
+ blockNumber - this.config.severePeerPenaltyBlockLength,
773
+ );
774
+ return merkleTree.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, nullifiers);
543
775
  },
544
776
  });
545
- const validDoubleSpend = await doubleSpendValidator.validateTx(tx);
546
- if (!validDoubleSpend) {
547
- // check if nullifier is older than 20 blocks
548
- if (blockNumber - this.config.severePeerPenaltyBlockLength > 0) {
549
- const snapshotValidator = new DoubleSpendTxValidator({
550
- getNullifierIndex: async (nullifier: Fr) => {
551
- const merkleTree = this.worldStateSynchronizer.getSnapshot(
552
- blockNumber - this.config.severePeerPenaltyBlockLength,
553
- );
554
- const index = await merkleTree.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
555
- return index;
556
- },
557
- });
558
-
559
- const validSnapshot = await snapshotValidator.validateTx(tx);
560
- // High penalty if nullifier is older than 20 blocks
561
- if (!validSnapshot) {
562
- // penalize
563
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
564
- return false;
565
- }
566
- }
567
- // penalize
568
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.HighToleranceError);
777
+
778
+ const validSnapshot = await snapshotValidator.validateTx(tx);
779
+ if (!validSnapshot) {
780
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
569
781
  return false;
570
782
  }
571
783
 
572
- // proof validation
573
- const proofValidator = new TxProofValidator(this.proofVerifier);
574
- const validProof = await proofValidator.validateTx(tx);
575
- if (!validProof) {
576
- // penalize
577
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
784
+ return true;
785
+ }
786
+
787
+ /**
788
+ * Validate an attestation.
789
+ *
790
+ * @param attestation - The attestation to validate.
791
+ * @returns True if the attestation is valid, false otherwise.
792
+ */
793
+ @trackSpan('Libp2pService.validateAttestation', (_peerId, attestation) => ({
794
+ [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toString(),
795
+ }))
796
+ public async validateAttestation(peerId: PeerId, attestation: BlockAttestation): Promise<boolean> {
797
+ const severity = await this.attestationValidator.validate(attestation);
798
+ if (severity) {
799
+ this.peerManager.penalizePeer(peerId, severity);
800
+ return false;
801
+ }
802
+
803
+ return true;
804
+ }
805
+
806
+ /**
807
+ * Validate a block proposal.
808
+ *
809
+ * @param block - The block proposal to validate.
810
+ * @returns True if the block proposal is valid, false otherwise.
811
+ */
812
+ @trackSpan('Libp2pService.validateBlockProposal', (_peerId, block) => ({
813
+ [Attributes.SLOT_NUMBER]: block.payload.header.globalVariables.slotNumber.toString(),
814
+ }))
815
+ public async validateBlockProposal(peerId: PeerId, block: BlockProposal): Promise<boolean> {
816
+ const severity = await this.blockProposalValidator.validate(block);
817
+ if (severity) {
818
+ this.peerManager.penalizePeer(peerId, severity);
819
+ return false;
820
+ }
821
+
822
+ return true;
823
+ }
824
+
825
+ /**
826
+ * Validate an epoch proof quote.
827
+ *
828
+ * @param epochProofQuote - The epoch proof quote to validate.
829
+ * @returns True if the epoch proof quote is valid, false otherwise.
830
+ */
831
+ @trackSpan('Libp2pService.validateEpochProofQuote', (_peerId, epochProofQuote) => ({
832
+ [Attributes.EPOCH_NUMBER]: epochProofQuote.payload.epochToProve.toString(),
833
+ }))
834
+ public async validateEpochProofQuote(peerId: PeerId, epochProofQuote: EpochProofQuote): Promise<boolean> {
835
+ const severity = await this.epochProofQuoteValidator.validate(epochProofQuote);
836
+ if (severity) {
837
+ this.peerManager.penalizePeer(peerId, severity);
578
838
  return false;
579
839
  }
580
840