@aztec/p2p 2.1.0-rc.9 → 3.0.0-devnet.2

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 (110) hide show
  1. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  2. package/dest/bootstrap/bootstrap.js +14 -4
  3. package/dest/client/factory.d.ts +1 -0
  4. package/dest/client/factory.d.ts.map +1 -1
  5. package/dest/client/factory.js +5 -3
  6. package/dest/client/interface.d.ts +1 -1
  7. package/dest/client/interface.d.ts.map +1 -1
  8. package/dest/client/p2p_client.d.ts +2 -1
  9. package/dest/client/p2p_client.d.ts.map +1 -1
  10. package/dest/client/p2p_client.js +14 -4
  11. package/dest/config.d.ts +4 -4
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +4 -3
  14. package/dest/enr/generate-enr.d.ts +1 -1
  15. package/dest/enr/generate-enr.d.ts.map +1 -1
  16. package/dest/enr/generate-enr.js +1 -1
  17. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  18. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -7
  19. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  20. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +18 -2
  21. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  22. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +21 -7
  23. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/mocks.js +8 -6
  25. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +1 -1
  26. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -0
  27. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  28. package/dest/msg_validators/attestation_validator/attestation_validator.js +29 -2
  29. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +4 -1
  30. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
  31. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +24 -4
  32. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  33. package/dest/msg_validators/tx_validator/factory.d.ts +1 -1
  34. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  35. package/dest/msg_validators/tx_validator/factory.js +10 -4
  36. package/dest/msg_validators/tx_validator/index.d.ts +1 -0
  37. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  38. package/dest/msg_validators/tx_validator/index.js +1 -0
  39. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -4
  40. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  41. package/dest/msg_validators/tx_validator/metadata_validator.js +6 -24
  42. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +12 -0
  43. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -0
  44. package/dest/msg_validators/tx_validator/timestamp_validator.js +32 -0
  45. package/dest/services/discv5/discV5_service.d.ts +2 -2
  46. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  47. package/dest/services/discv5/discV5_service.js +2 -2
  48. package/dest/services/dummy_service.d.ts +1 -1
  49. package/dest/services/dummy_service.d.ts.map +1 -1
  50. package/dest/services/libp2p/libp2p_service.d.ts +11 -1
  51. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  52. package/dest/services/libp2p/libp2p_service.js +72 -34
  53. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  54. package/dest/services/peer-manager/peer_manager.js +9 -3
  55. package/dest/services/service.d.ts +1 -1
  56. package/dest/services/service.d.ts.map +1 -1
  57. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  58. package/dest/services/tx_collection/fast_tx_collection.js +6 -1
  59. package/dest/services/tx_collection/tx_collection.d.ts +2 -1
  60. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  61. package/dest/services/tx_collection/tx_collection.js +3 -2
  62. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  63. package/dest/services/tx_collection/tx_collection_sink.js +34 -4
  64. package/dest/services/tx_collection/tx_source.js +2 -2
  65. package/dest/services/tx_provider.d.ts +1 -1
  66. package/dest/services/tx_provider.d.ts.map +1 -1
  67. package/dest/services/tx_provider.js +7 -3
  68. package/dest/test-helpers/make-enrs.js +1 -1
  69. package/dest/test-helpers/mock-tx-helpers.d.ts +12 -0
  70. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -0
  71. package/dest/test-helpers/mock-tx-helpers.js +19 -0
  72. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  73. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  74. package/dest/test-helpers/reqresp-nodes.js +4 -3
  75. package/dest/versioning.d.ts +1 -1
  76. package/dest/versioning.d.ts.map +1 -1
  77. package/dest/versioning.js +2 -2
  78. package/package.json +17 -17
  79. package/src/bootstrap/bootstrap.ts +15 -4
  80. package/src/client/factory.ts +10 -3
  81. package/src/client/interface.ts +1 -1
  82. package/src/client/p2p_client.ts +14 -5
  83. package/src/config.ts +6 -4
  84. package/src/enr/generate-enr.ts +1 -1
  85. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -7
  86. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +22 -2
  87. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +24 -7
  88. package/src/mem_pools/attestation_pool/mocks.ts +9 -6
  89. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +1 -1
  90. package/src/msg_validators/attestation_validator/attestation_validator.ts +39 -2
  91. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +29 -4
  92. package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
  93. package/src/msg_validators/tx_validator/factory.ts +10 -4
  94. package/src/msg_validators/tx_validator/index.ts +1 -0
  95. package/src/msg_validators/tx_validator/metadata_validator.ts +7 -41
  96. package/src/msg_validators/tx_validator/timestamp_validator.ts +46 -0
  97. package/src/services/discv5/discV5_service.ts +2 -2
  98. package/src/services/dummy_service.ts +1 -1
  99. package/src/services/libp2p/libp2p_service.ts +100 -52
  100. package/src/services/peer-manager/peer_manager.ts +10 -3
  101. package/src/services/service.ts +1 -1
  102. package/src/services/tx_collection/fast_tx_collection.ts +3 -1
  103. package/src/services/tx_collection/tx_collection.ts +3 -2
  104. package/src/services/tx_collection/tx_collection_sink.ts +34 -3
  105. package/src/services/tx_collection/tx_source.ts +2 -2
  106. package/src/services/tx_provider.ts +3 -2
  107. package/src/test-helpers/make-enrs.ts +1 -1
  108. package/src/test-helpers/mock-tx-helpers.ts +24 -0
  109. package/src/test-helpers/reqresp-nodes.ts +3 -2
  110. package/src/versioning.ts +3 -3
@@ -20,6 +20,7 @@ import { DoubleSpendTxValidator } from './double_spend_validator.js';
20
20
  import { GasTxValidator } from './gas_validator.js';
21
21
  import { MetadataTxValidator } from './metadata_validator.js';
22
22
  import { PhasesTxValidator } from './phases_validator.js';
23
+ import { TimestampTxValidator } from './timestamp_validator.js';
23
24
  import { TxPermittedValidator } from './tx_permitted_validator.js';
24
25
  import { TxProofValidator } from './tx_proof_validator.js';
25
26
 
@@ -37,7 +38,7 @@ export function createTxMessageValidators(
37
38
  gasFees: GasFees,
38
39
  l1ChainId: number,
39
40
  rollupVersion: number,
40
- protocolContractTreeRoot: Fr,
41
+ protocolContractsHash: Fr,
41
42
  contractDataSource: ContractDataSource,
42
43
  proofVerifier: ClientProtocolCircuitVerifier,
43
44
  txsPermitted: boolean,
@@ -59,13 +60,18 @@ export function createTxMessageValidators(
59
60
  validator: new MetadataTxValidator({
60
61
  l1ChainId: new Fr(l1ChainId),
61
62
  rollupVersion: new Fr(rollupVersion),
62
- timestamp,
63
- blockNumber,
64
- protocolContractTreeRoot,
63
+ protocolContractsHash,
65
64
  vkTreeRoot: getVKTreeRoot(),
66
65
  }),
67
66
  severity: PeerErrorSeverity.HighToleranceError,
68
67
  },
68
+ timestampValidator: {
69
+ validator: new TimestampTxValidator<Tx>({
70
+ timestamp,
71
+ blockNumber,
72
+ }),
73
+ severity: PeerErrorSeverity.MidToleranceError,
74
+ },
69
75
  doubleSpendValidator: {
70
76
  validator: new DoubleSpendTxValidator({
71
77
  nullifiersExist: async (nullifiers: Buffer[]) => {
@@ -10,3 +10,4 @@ export * from './test_utils.js';
10
10
  export * from './allowed_public_setup.js';
11
11
  export * from './archive_cache.js';
12
12
  export * from './tx_permitted_validator.js';
13
+ export * from './timestamp_validator.js';
@@ -3,15 +3,12 @@ import { createLogger } from '@aztec/foundation/log';
3
3
  import {
4
4
  type AnyTx,
5
5
  TX_ERROR_INCORRECT_L1_CHAIN_ID,
6
- TX_ERROR_INCORRECT_PROTOCOL_CONTRACT_TREE_ROOT,
6
+ TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH,
7
7
  TX_ERROR_INCORRECT_ROLLUP_VERSION,
8
8
  TX_ERROR_INCORRECT_VK_TREE_ROOT,
9
- TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP,
10
9
  type TxValidationResult,
11
10
  type TxValidator,
12
- getTxHash,
13
11
  } from '@aztec/stdlib/tx';
14
- import type { UInt64 } from '@aztec/stdlib/types';
15
12
 
16
13
  export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
17
14
  #log = createLogger('p2p:tx_validator:tx_metadata');
@@ -20,13 +17,8 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
20
17
  private values: {
21
18
  l1ChainId: Fr;
22
19
  rollupVersion: Fr;
23
- // Timestamp at which we will validate that the tx is not expired. This is typically the timestamp of the block
24
- // being built.
25
- timestamp: UInt64;
26
- // Block number in which the tx is considered to be included.
27
- blockNumber: number;
28
20
  vkTreeRoot: Fr;
29
- protocolContractTreeRoot: Fr;
21
+ protocolContractsHash: Fr;
30
22
  },
31
23
  ) {}
32
24
 
@@ -38,14 +30,11 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
38
30
  if (!this.#hasCorrectRollupVersion(tx)) {
39
31
  errors.push(TX_ERROR_INCORRECT_ROLLUP_VERSION);
40
32
  }
41
- if (!this.#isValidForTimestamp(tx)) {
42
- errors.push(TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP);
43
- }
44
33
  if (!this.#hasCorrectVkTreeRoot(tx)) {
45
34
  errors.push(TX_ERROR_INCORRECT_VK_TREE_ROOT);
46
35
  }
47
- if (!this.#hasCorrectProtocolContractTreeRoot(tx)) {
48
- errors.push(TX_ERROR_INCORRECT_PROTOCOL_CONTRACT_TREE_ROOT);
36
+ if (!this.#hasCorrectprotocolContractsHash(tx)) {
37
+ errors.push(TX_ERROR_INCORRECT_PROTOCOL_CONTRACTS_HASH);
49
38
  }
50
39
  return Promise.resolve(errors.length > 0 ? { result: 'invalid', reason: errors } : { result: 'valid' });
51
40
  }
@@ -62,10 +51,10 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
62
51
  }
63
52
  }
64
53
 
65
- #hasCorrectProtocolContractTreeRoot(tx: T): boolean {
66
- if (!tx.data.constants.protocolContractTreeRoot.equals(this.values.protocolContractTreeRoot)) {
54
+ #hasCorrectprotocolContractsHash(tx: T): boolean {
55
+ if (!tx.data.constants.protocolContractsHash.equals(this.values.protocolContractsHash)) {
67
56
  this.#log.verbose(
68
- `Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect protocol contract tree root ${tx.data.constants.protocolContractTreeRoot.toString()} != ${this.values.protocolContractTreeRoot.toString()}`,
57
+ `Rejecting tx ${'txHash' in tx ? tx.txHash : tx.hash} because of incorrect protocol contracts hash ${tx.data.constants.protocolContractsHash.toString()} != ${this.values.protocolContractsHash.toString()}`,
69
58
  );
70
59
  return false;
71
60
  }
@@ -83,29 +72,6 @@ export class MetadataTxValidator<T extends AnyTx> implements TxValidator<T> {
83
72
  }
84
73
  }
85
74
 
86
- #isValidForTimestamp(tx: T): boolean {
87
- const includeByTimestamp = tx.data.includeByTimestamp;
88
- // If building block 1, we skip the expiration check. For details on why see the `validate_include_by_timestamp`
89
- // function in `noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/validation_requests.nr`.
90
- const buildingBlock1 = this.values.blockNumber === 1;
91
-
92
- if (!buildingBlock1 && includeByTimestamp < this.values.timestamp) {
93
- if (tx.data.constants.historicalHeader.globalVariables.blockNumber === 0) {
94
- this.#log.warn(
95
- `A tx built against a genesis block failed to be included in block 1 which is the only block in which txs built against a genesis block are allowed to be included.`,
96
- );
97
- }
98
- this.#log.verbose(
99
- `Rejecting tx ${getTxHash(tx)} for low expiration timestamp. Tx expiration timestamp: ${includeByTimestamp}, timestamp: ${
100
- this.values.timestamp
101
- }.`,
102
- );
103
- return false;
104
- } else {
105
- return true;
106
- }
107
- }
108
-
109
75
  #hasCorrectRollupVersion(tx: T): boolean {
110
76
  if (!tx.data.constants.txContext.version.equals(this.values.rollupVersion)) {
111
77
  this.#log.verbose(
@@ -0,0 +1,46 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import {
3
+ type AnyTx,
4
+ TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP,
5
+ type TxValidationResult,
6
+ type TxValidator,
7
+ getTxHash,
8
+ } from '@aztec/stdlib/tx';
9
+ import type { UInt64 } from '@aztec/stdlib/types';
10
+
11
+ export class TimestampTxValidator<T extends AnyTx> implements TxValidator<T> {
12
+ #log = createLogger('p2p:tx_validator:timestamp');
13
+
14
+ constructor(
15
+ private values: {
16
+ // Timestamp at which we will validate that the tx is not expired. This is typically the timestamp of the block
17
+ // being built.
18
+ timestamp: UInt64;
19
+ // Block number in which the tx is considered to be included.
20
+ blockNumber: number;
21
+ },
22
+ ) {}
23
+
24
+ validateTx(tx: T): Promise<TxValidationResult> {
25
+ const includeByTimestamp = tx.data.includeByTimestamp;
26
+ // If building block 1, we skip the expiration check. For details on why see the `validate_include_by_timestamp`
27
+ // function in `noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/validation_requests.nr`.
28
+ const buildingBlock1 = this.values.blockNumber === 1;
29
+
30
+ if (!buildingBlock1 && includeByTimestamp < this.values.timestamp) {
31
+ if (tx.data.constants.anchorBlockHeader.globalVariables.blockNumber === 0) {
32
+ this.#log.warn(
33
+ `A tx built against a genesis block failed to be included in block 1 which is the only block in which txs built against a genesis block are allowed to be included.`,
34
+ );
35
+ }
36
+ this.#log.verbose(
37
+ `Rejecting tx ${getTxHash(tx)} for low expiration timestamp. Tx expiration timestamp: ${includeByTimestamp}, timestamp: ${
38
+ this.values.timestamp
39
+ }.`,
40
+ );
41
+ return Promise.resolve({ result: 'invalid', reason: [TX_ERROR_INVALID_INCLUDE_BY_TIMESTAMP] });
42
+ } else {
43
+ return Promise.resolve({ result: 'valid' });
44
+ }
45
+ }
46
+ }
@@ -3,10 +3,10 @@ import { sleep } from '@aztec/foundation/sleep';
3
3
  import { type ComponentsVersions, checkCompressedComponentVersion } from '@aztec/stdlib/versioning';
4
4
  import { OtelMetricsAdapter, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
5
5
 
6
- import { Discv5, type Discv5EventEmitter, type IDiscv5CreateOptions } from '@chainsafe/discv5';
7
- import { ENR, SignableENR } from '@chainsafe/enr';
8
6
  import type { PeerId } from '@libp2p/interface';
9
7
  import { type Multiaddr, multiaddr } from '@multiformats/multiaddr';
8
+ import { Discv5, type Discv5EventEmitter, type IDiscv5CreateOptions } from '@nethermindeth/discv5';
9
+ import { ENR, SignableENR } from '@nethermindeth/enr';
10
10
  import EventEmitter from 'events';
11
11
 
12
12
  import type { P2PConfig } from '../../config.js';
@@ -3,8 +3,8 @@ import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
3
3
  import type { Gossipable, PeerErrorSeverity } from '@aztec/stdlib/p2p';
4
4
  import { Tx, TxHash } from '@aztec/stdlib/tx';
5
5
 
6
- import type { ENR } from '@chainsafe/enr';
7
6
  import type { PeerId } from '@libp2p/interface';
7
+ import type { ENR } from '@nethermindeth/enr';
8
8
  import EventEmitter from 'events';
9
9
 
10
10
  import type { PeerManagerInterface } from './peer-manager/interface.js';
@@ -1,11 +1,13 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { randomInt } from '@aztec/foundation/crypto';
3
+ import { Fr } from '@aztec/foundation/fields';
3
4
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
4
5
  import { SerialQueue } from '@aztec/foundation/queue';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
6
7
  import { Timer } from '@aztec/foundation/timer';
7
8
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
8
- import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
9
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
10
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
9
11
  import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
10
12
  import type { ContractDataSource } from '@aztec/stdlib/contract';
11
13
  import { GasFees } from '@aztec/stdlib/gas';
@@ -23,12 +25,11 @@ import {
23
25
  metricsTopicStrToLabels,
24
26
  } from '@aztec/stdlib/p2p';
25
27
  import { MerkleTreeId } from '@aztec/stdlib/trees';
26
- import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
28
+ import { Tx, type TxHash, type TxValidationResult, type TxValidator } from '@aztec/stdlib/tx';
27
29
  import type { UInt64 } from '@aztec/stdlib/types';
28
30
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
29
31
  import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
30
32
 
31
- import { ENR } from '@chainsafe/enr';
32
33
  import {
33
34
  type GossipSub,
34
35
  type GossipSubComponents,
@@ -45,6 +46,7 @@ import { type Message, type MultiaddrConnection, type PeerId, TopicValidatorResu
45
46
  import type { ConnectionManager } from '@libp2p/interface-internal';
46
47
  import { mplex } from '@libp2p/mplex';
47
48
  import { tcp } from '@libp2p/tcp';
49
+ import { ENR } from '@nethermindeth/enr';
48
50
  import { createLibp2p } from 'libp2p';
49
51
 
50
52
  import type { P2PConfig } from '../../config.js';
@@ -53,7 +55,13 @@ import { AttestationValidator, BlockProposalValidator } from '../../msg_validato
53
55
  import { MessageSeenValidator } from '../../msg_validators/msg_seen_validator/msg_seen_validator.js';
54
56
  import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
55
57
  import { type MessageValidator, createTxMessageValidators } from '../../msg_validators/tx_validator/factory.js';
56
- import { DoubleSpendTxValidator, TxProofValidator } from '../../msg_validators/tx_validator/index.js';
58
+ import {
59
+ AggregateTxValidator,
60
+ DataTxValidator,
61
+ DoubleSpendTxValidator,
62
+ MetadataTxValidator,
63
+ TxProofValidator,
64
+ } from '../../msg_validators/tx_validator/index.js';
57
65
  import { GossipSubEvent } from '../../types/index.js';
58
66
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
59
67
  import { getVersions } from '../../versioning.js';
@@ -79,6 +87,8 @@ import { reqRespBlockTxsHandler } from '../reqresp/protocols/block_txs/block_txs
79
87
  import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
80
88
  import {
81
89
  AuthRequest,
90
+ BlockTxsRequest,
91
+ BlockTxsResponse,
82
92
  StatusMessage,
83
93
  pingHandler,
84
94
  reqRespBlockHandler,
@@ -160,7 +170,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
160
170
  );
161
171
 
162
172
  this.attestationValidator = new AttestationValidator(epochCache);
163
- this.blockProposalValidator = new BlockProposalValidator(epochCache);
173
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
164
174
 
165
175
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
166
176
 
@@ -487,7 +497,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
487
497
  const reqrespSubProtocolValidators = {
488
498
  ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
489
499
  // TODO(#11336): A request validator for blocks
490
- [ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
500
+ [ReqRespSubProtocol.TX]: this.validateRequestedTxs.bind(this),
501
+ [ReqRespSubProtocol.BLOCK_TXS]: this.validateRequestedBlockTxs.bind(this),
491
502
  };
492
503
  await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
493
504
  this.logger.info(`Started P2P service`, {
@@ -745,12 +756,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
745
756
  return;
746
757
  }
747
758
  this.logger.debug(
748
- `Received attestation for block ${attestation.blockNumber} slot ${attestation.slotNumber.toNumber()} from external peer ${source.toString()}`,
759
+ `Received attestation for slot ${attestation.slotNumber.toNumber()} from external peer ${source.toString()}`,
749
760
  {
750
761
  p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
751
762
  slot: attestation.slotNumber.toNumber(),
752
763
  archive: attestation.archive.toString(),
753
- block: attestation.blockNumber,
754
764
  source: source.toString(),
755
765
  },
756
766
  );
@@ -783,7 +793,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
783
793
 
784
794
  // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
785
795
  @trackSpan('Libp2pService.processValidBlockProposal', async block => ({
786
- [Attributes.BLOCK_NUMBER]: block.blockNumber,
787
796
  [Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
788
797
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
789
798
  [Attributes.P2P_ID]: await block.p2pMessageIdentifier().then(i => i.toString()),
@@ -791,16 +800,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
791
800
  private async processValidBlockProposal(block: BlockProposal, sender: PeerId) {
792
801
  const slot = block.slotNumber.toBigInt();
793
802
  const previousSlot = slot - 1n;
794
- this.logger.verbose(
795
- `Received block ${block.blockNumber} for slot ${slot} from external peer ${sender.toString()}.`,
796
- {
797
- p2pMessageIdentifier: await block.p2pMessageIdentifier(),
798
- slot: block.slotNumber.toNumber(),
799
- archive: block.archive.toString(),
800
- block: block.blockNumber,
801
- source: sender.toString(),
802
- },
803
- );
803
+ this.logger.verbose(`Received block proposal for slot ${slot} from external peer ${sender.toString()}.`, {
804
+ p2pMessageIdentifier: await block.p2pMessageIdentifier(),
805
+ slot: block.slotNumber.toNumber(),
806
+ archive: block.archive.toString(),
807
+ source: sender.toString(),
808
+ });
804
809
  const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
805
810
  if (attestationsForPreviousSlot !== undefined) {
806
811
  this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
@@ -815,15 +820,11 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
815
820
  // The attestation can be undefined if no handler is registered / the validator deems the block invalid
816
821
  if (attestations?.length) {
817
822
  for (const attestation of attestations) {
818
- this.logger.verbose(
819
- `Broadcasting attestation for block ${attestation.blockNumber} slot ${attestation.slotNumber.toNumber()}`,
820
- {
821
- p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
822
- slot: attestation.slotNumber.toNumber(),
823
- archive: attestation.archive.toString(),
824
- block: attestation.blockNumber,
825
- },
826
- );
823
+ this.logger.verbose(`Broadcasting attestation for slot ${attestation.slotNumber.toNumber()}`, {
824
+ p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
825
+ slot: attestation.slotNumber.toNumber(),
826
+ archive: attestation.archive.toString(),
827
+ });
827
828
  await this.broadcastAttestation(attestation);
828
829
  }
829
830
  }
@@ -834,7 +835,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
834
835
  * @param attestation - The attestation to broadcast.
835
836
  */
836
837
  @trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
837
- [Attributes.BLOCK_NUMBER]: attestation.blockNumber,
838
838
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
839
839
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
840
840
  [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
@@ -859,6 +859,38 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
859
859
  });
860
860
  }
861
861
 
862
+ /**
863
+ * Validate the requested block transactions.
864
+ * @param request - The block transactions request.
865
+ * @param response - The block transactions response.
866
+ * @param peerId - The ID of the peer that made the request.
867
+ * @returns True if the requested block transactions are valid, false otherwise.
868
+ */
869
+ @trackSpan('Libp2pService.validateRequestedBlockTxs', request => ({
870
+ [Attributes.BLOCK_HASH]: request.blockHash.toString(),
871
+ }))
872
+ private async validateRequestedBlockTxs(
873
+ _request: BlockTxsRequest,
874
+ response: BlockTxsResponse,
875
+ peerId: PeerId,
876
+ ): Promise<boolean> {
877
+ const requestedTxValidator = this.createRequestedTxValidator();
878
+
879
+ try {
880
+ // TODO(palla/txs): Validate that this tx belongs to the block hash being requested
881
+ await Promise.all(response.txs.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator)));
882
+ return true;
883
+ } catch (e: any) {
884
+ if (e instanceof ValidationError) {
885
+ this.logger.warn(`Failed validation for requested block txs from peer ${peerId.toString()}`);
886
+ } else {
887
+ this.logger.error(`Error during validation of requested block txs`, e);
888
+ }
889
+
890
+ return false;
891
+ }
892
+ }
893
+
862
894
  /**
863
895
  * Validate a collection of txs that has been requested from a peer.
864
896
  *
@@ -873,43 +905,60 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
873
905
  * @param peerId - The peer ID of the peer that sent the tx.
874
906
  * @returns True if the whole collection of txs is valid, false otherwise.
875
907
  */
876
- //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
877
- // I think we should still extract the valid txs and return them, so that we can still use the response.
878
908
  @trackSpan('Libp2pService.validateRequestedTx', (requestedTxHash, _responseTx) => ({
879
909
  [Attributes.TX_HASH]: requestedTxHash.toString(),
880
910
  }))
881
- private async validateRequestedTx(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
911
+ private async validateRequestedTxs(requestedTxHash: TxHash[], responseTx: Tx[], peerId: PeerId): Promise<boolean> {
882
912
  const requested = new Set(requestedTxHash.map(h => h.toString()));
913
+ const requestedTxValidator = this.createRequestedTxValidator();
883
914
 
884
- const proofValidator = new TxProofValidator(this.proofVerifier);
885
-
915
+ //TODO: (mralj) - this is somewhat naive implementation, if single tx is invlid we consider the whole response invalid.
916
+ // I think we should still extract the valid txs and return them, so that we can still use the response.
886
917
  try {
887
- await Promise.all(
888
- responseTx.map(async tx => {
889
- if (!requested.has(tx.getTxHash().toString())) {
890
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
891
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
892
- }
893
-
894
- const { result } = await proofValidator.validateTx(tx);
895
- if (result === 'invalid') {
896
- this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
897
- throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
898
- }
899
- }),
900
- );
918
+ await Promise.all(responseTx.map(tx => this.validateRequestedTx(tx, peerId, requestedTxValidator, requested)));
901
919
  return true;
902
920
  } catch (e: any) {
903
921
  if (e instanceof ValidationError) {
904
- this.logger.debug(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
922
+ this.logger.warn(`Failed to validate requested txs from peer ${peerId.toString()}, reason ${e.message}`);
905
923
  } else {
906
- this.logger.warn(`Error during validation of requested txs`, e);
924
+ this.logger.error(`Error during validation of requested txs`, e);
907
925
  }
908
926
 
909
927
  return false;
910
928
  }
911
929
  }
912
930
 
931
+ private createRequestedTxValidator(): TxValidator {
932
+ return new AggregateTxValidator(
933
+ new DataTxValidator(),
934
+ new MetadataTxValidator({
935
+ l1ChainId: new Fr(this.config.l1ChainId),
936
+ rollupVersion: new Fr(this.config.rollupVersion),
937
+ protocolContractsHash,
938
+ vkTreeRoot: getVKTreeRoot(),
939
+ }),
940
+ new TxProofValidator(this.proofVerifier),
941
+ );
942
+ }
943
+
944
+ private async validateRequestedTx(tx: Tx, peerId: PeerId, txValidator: TxValidator, requested?: Set<`0x${string}`>) {
945
+ if (!(await tx.validateTxHash())) {
946
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
947
+ throw new ValidationError(`Received tx with invalid hash ${tx.getTxHash().toString()}.`);
948
+ }
949
+
950
+ if (requested && !requested.has(tx.getTxHash().toString())) {
951
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
952
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that was not requested.`);
953
+ }
954
+
955
+ const { result } = await txValidator.validateTx(tx);
956
+ if (result === 'invalid') {
957
+ this.peerManager.penalizePeer(peerId, PeerErrorSeverity.LowToleranceError);
958
+ throw new ValidationError(`Received tx with hash ${tx.getTxHash().toString()} that is invalid.`);
959
+ }
960
+ }
961
+
913
962
  @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
914
963
  [Attributes.TX_HASH]: tx.getTxHash().toString(),
915
964
  }))
@@ -997,7 +1046,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
997
1046
  gasFees,
998
1047
  this.config.l1ChainId,
999
1048
  this.config.rollupVersion,
1000
- protocolContractTreeRoot,
1049
+ protocolContractsHash,
1001
1050
  this.archiver,
1002
1051
  this.proofVerifier,
1003
1052
  !this.config.disableTransactions,
@@ -1080,7 +1129,6 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1080
1129
  * @returns True if the attestation is valid, false otherwise.
1081
1130
  */
1082
1131
  @trackSpan('Libp2pService.validateAttestation', async (_, attestation) => ({
1083
- [Attributes.BLOCK_NUMBER]: attestation.blockNumber,
1084
1132
  [Attributes.SLOT_NUMBER]: attestation.payload.header.slotNumber.toNumber(),
1085
1133
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
1086
1134
  [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
@@ -1,5 +1,5 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
- import { makeEthSignDigest, recoverAddress } from '@aztec/foundation/crypto';
2
+ import { makeEthSignDigest, tryRecoverAddress } from '@aztec/foundation/crypto';
3
3
  import type { EthAddress } from '@aztec/foundation/eth-address';
4
4
  import { Fr } from '@aztec/foundation/fields';
5
5
  import { createLogger } from '@aztec/foundation/log';
@@ -9,10 +9,10 @@ import type { PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/
9
9
  import type { PeerErrorSeverity } from '@aztec/stdlib/p2p';
10
10
  import { type TelemetryClient, trackSpan } from '@aztec/telemetry-client';
11
11
 
12
- import { ENR } from '@chainsafe/enr';
13
12
  import type { Connection, PeerId } from '@libp2p/interface';
14
13
  import { peerIdFromString } from '@libp2p/peer-id';
15
14
  import type { Multiaddr } from '@multiformats/multiaddr';
15
+ import { ENR } from '@nethermindeth/enr';
16
16
  import { inspect } from 'util';
17
17
 
18
18
  import type { P2PConfig } from '../../config.js';
@@ -907,7 +907,14 @@ export class PeerManager implements PeerManagerInterface {
907
907
 
908
908
  const hashToRecover = authRequest.getPayloadToSign();
909
909
  const ethSignedHash = makeEthSignDigest(hashToRecover);
910
- const sender = recoverAddress(ethSignedHash, peerAuthResponse.signature);
910
+ const sender = tryRecoverAddress(ethSignedHash, peerAuthResponse.signature);
911
+ if (!sender) {
912
+ this.logger.verbose(`Disconnecting peer ${peerId} due to failed auth handshake, invalid signature.`, logData);
913
+ this.markAuthHandshakeFailed(peerId);
914
+ this.markPeerForDisconnect(peerId);
915
+ return;
916
+ }
917
+
911
918
  const registeredValidators = await this.epochCache.getRegisteredValidators();
912
919
  const found = registeredValidators.find(v => v.toString() === sender.toString()) !== undefined;
913
920
  if (!found) {
@@ -3,8 +3,8 @@ import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
3
3
  import type { BlockAttestation, BlockProposal, Gossipable } from '@aztec/stdlib/p2p';
4
4
  import type { Tx } from '@aztec/stdlib/tx';
5
5
 
6
- import type { ENR } from '@chainsafe/enr';
7
6
  import type { PeerId } from '@libp2p/interface';
7
+ import type { ENR } from '@nethermindeth/enr';
8
8
  import type EventEmitter from 'events';
9
9
 
10
10
  import type { P2PReqRespConfig } from './reqresp/config.js';
@@ -55,7 +55,9 @@ export class FastTxCollection {
55
55
  }
56
56
 
57
57
  const blockInfo: L2BlockInfo =
58
- input.type === 'proposal' ? input.blockProposal.toBlockInfo() : input.block.toBlockInfo();
58
+ input.type === 'proposal'
59
+ ? { ...input.blockProposal.toBlockInfo(), blockNumber: input.blockNumber }
60
+ : { ...input.block.toBlockInfo() };
59
61
 
60
62
  // This promise is used to await for the collection to finish during the main collectFast method.
61
63
  // It gets resolved in `foundTxs` when all txs have been collected, or rejected if the request is aborted or hits the deadline.
@@ -25,7 +25,7 @@ export type MissingTxInfo = { blockNumber: number; deadline: Date; readyForReqRe
25
25
 
26
26
  export type FastCollectionRequestInput =
27
27
  | { type: 'block'; block: L2Block }
28
- | { type: 'proposal'; blockProposal: BlockProposal };
28
+ | { type: 'proposal'; blockProposal: BlockProposal; blockNumber: number };
29
29
 
30
30
  export type FastCollectionRequest = FastCollectionRequestInput & {
31
31
  missingTxHashes: Set<string>;
@@ -152,10 +152,11 @@ export class TxCollection {
152
152
  /** Collects the set of txs for the given block proposal as fast as possible */
153
153
  public collectFastForProposal(
154
154
  blockProposal: BlockProposal,
155
+ blockNumber: number,
155
156
  txHashes: TxHash[] | string[],
156
157
  opts: { deadline: Date; pinnedPeer?: PeerId },
157
158
  ) {
158
- return this.collectFastFor({ type: 'proposal', blockProposal }, txHashes, opts);
159
+ return this.collectFastFor({ type: 'proposal', blockProposal, blockNumber }, txHashes, opts);
159
160
  }
160
161
 
161
162
  /** Collects the set of txs for the given mined block as fast as possible */
@@ -58,17 +58,48 @@ export class TxCollectionSink extends (EventEmitter as new () => TypedEventEmitt
58
58
  return { txs, requested, duration };
59
59
  }
60
60
 
61
+ // Validate tx hashes for all collected txs from external sources
62
+ const validTxs: Tx[] = [];
63
+ const invalidTxHashes: string[] = [];
64
+ await Promise.all(
65
+ txs.map(async tx => {
66
+ const isValid = await tx.validateTxHash();
67
+ if (isValid) {
68
+ validTxs.push(tx);
69
+ } else {
70
+ invalidTxHashes.push(tx.getTxHash().toString());
71
+ }
72
+ }),
73
+ );
74
+
75
+ if (invalidTxHashes.length > 0) {
76
+ this.log.warn(`Rejecting ${invalidTxHashes.length} txs with invalid hashes from ${info.description}`, {
77
+ ...info,
78
+ invalidTxHashes,
79
+ });
80
+ }
81
+
82
+ if (validTxs.length === 0) {
83
+ this.log.trace(`No valid txs found via ${info.description} after validation`, {
84
+ ...info,
85
+ requestedTxs: requested.map(t => t.toString()),
86
+ invalidTxHashes,
87
+ });
88
+ return { txs: [], requested, duration };
89
+ }
90
+
61
91
  this.log.verbose(
62
- `Collected ${txs.length} txs out of ${requested.length} requested via ${info.description} in ${duration}ms`,
92
+ `Collected ${validTxs.length} txs out of ${requested.length} requested via ${info.description} in ${duration}ms`,
63
93
  {
64
94
  ...info,
65
95
  duration,
66
- txs: txs.map(t => t.getTxHash().toString()),
96
+ txs: validTxs.map(t => t.getTxHash().toString()),
67
97
  requestedTxs: requested.map(t => t.toString()),
98
+ rejectedCount: invalidTxHashes.length,
68
99
  },
69
100
  );
70
101
 
71
- return await this.foundTxs(txs, { ...info, duration });
102
+ return await this.foundTxs(validTxs, { ...info, duration });
72
103
  }
73
104
 
74
105
  private async foundTxs(
@@ -1,5 +1,5 @@
1
1
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
2
- import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
2
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
3
3
  import type { ChainConfig } from '@aztec/stdlib/config';
4
4
  import { type AztecNode, createAztecNodeClient } from '@aztec/stdlib/interfaces/client';
5
5
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
@@ -32,6 +32,6 @@ export class NodeRpcTxSource implements TxSource {
32
32
  }
33
33
 
34
34
  export function createNodeRpcTxSources(urls: string[], chainConfig: ChainConfig) {
35
- const versions = getComponentsVersionsFromConfig(chainConfig, protocolContractTreeRoot, getVKTreeRoot());
35
+ const versions = getComponentsVersionsFromConfig(chainConfig, protocolContractsHash, getVKTreeRoot());
36
36
  return urls.map(url => NodeRpcTxSource.fromUrl(url, versions));
37
37
  }
@@ -55,11 +55,12 @@ export class TxProvider implements ITxProvider {
55
55
  /** Gathers txs from the tx pool, proposal body, remote rpc nodes, and reqresp. */
56
56
  public getTxsForBlockProposal(
57
57
  blockProposal: BlockProposal,
58
+ blockNumber: number,
58
59
  opts: { pinnedPeer: PeerId | undefined; deadline: Date },
59
60
  ): Promise<{ txs: Tx[]; missingTxs: TxHash[] }> {
60
61
  return this.getOrderedTxsFromAllSources(
61
- { type: 'proposal', blockProposal },
62
- blockProposal.toBlockInfo(),
62
+ { type: 'proposal', blockProposal, blockNumber },
63
+ { ...blockProposal.toBlockInfo(), blockNumber },
63
64
  blockProposal.txHashes,
64
65
  { ...opts, pinnedPeer: opts.pinnedPeer },
65
66
  );