@aztec/p2p 0.83.1 → 0.84.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.
Files changed (44) hide show
  1. package/dest/client/factory.d.ts +2 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +3 -3
  4. package/dest/client/p2p_client.d.ts +2 -1
  5. package/dest/client/p2p_client.d.ts.map +1 -1
  6. package/dest/config.d.ts +16 -1
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +53 -0
  9. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +3 -0
  10. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -0
  11. package/dest/msg_validators/tx_validator/allowed_public_setup.js +27 -0
  12. package/dest/msg_validators/tx_validator/gas_validator.d.ts +10 -0
  13. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -0
  14. package/dest/msg_validators/tx_validator/gas_validator.js +76 -0
  15. package/dest/msg_validators/tx_validator/index.d.ts +4 -0
  16. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  17. package/dest/msg_validators/tx_validator/index.js +4 -0
  18. package/dest/msg_validators/tx_validator/phases_validator.d.ts +13 -0
  19. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -0
  20. package/dest/msg_validators/tx_validator/phases_validator.js +83 -0
  21. package/dest/msg_validators/tx_validator/test_utils.d.ts +17 -0
  22. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -0
  23. package/dest/msg_validators/tx_validator/test_utils.js +22 -0
  24. package/dest/services/libp2p/libp2p_service.d.ts +6 -3
  25. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  26. package/dest/services/libp2p/libp2p_service.js +36 -9
  27. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  28. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  29. package/dest/services/peer-manager/peer_manager.js +14 -9
  30. package/dest/test-helpers/reqresp-nodes.d.ts +2 -1
  31. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  32. package/dest/test-helpers/reqresp-nodes.js +2 -2
  33. package/package.json +12 -10
  34. package/src/client/factory.ts +4 -3
  35. package/src/client/p2p_client.ts +2 -1
  36. package/src/config.ts +64 -1
  37. package/src/msg_validators/tx_validator/allowed_public_setup.ts +35 -0
  38. package/src/msg_validators/tx_validator/gas_validator.ts +95 -0
  39. package/src/msg_validators/tx_validator/index.ts +4 -0
  40. package/src/msg_validators/tx_validator/phases_validator.ts +104 -0
  41. package/src/msg_validators/tx_validator/test_utils.ts +43 -0
  42. package/src/services/libp2p/libp2p_service.ts +42 -7
  43. package/src/services/peer-manager/peer_manager.ts +19 -11
  44. package/src/test-helpers/reqresp-nodes.ts +3 -2
@@ -0,0 +1,104 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { PublicContractsDB, getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
3
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
4
+ import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
5
+ import {
6
+ type PublicCallRequestWithCalldata,
7
+ Tx,
8
+ TxExecutionPhase,
9
+ type TxValidationResult,
10
+ type TxValidator,
11
+ } from '@aztec/stdlib/tx';
12
+
13
+ export class PhasesTxValidator implements TxValidator<Tx> {
14
+ #log = createLogger('sequencer:tx_validator:tx_phases');
15
+ private contractsDB: PublicContractsDB;
16
+
17
+ constructor(contracts: ContractDataSource, private setupAllowList: AllowedElement[], private blockNumber: number) {
18
+ this.contractsDB = new PublicContractsDB(contracts);
19
+ }
20
+
21
+ async validateTx(tx: Tx): Promise<TxValidationResult> {
22
+ try {
23
+ // TODO(@spalladino): We add this just to handle public authwit-check calls during setup
24
+ // which are needed for public FPC flows, but fail if the account contract hasnt been deployed yet,
25
+ // which is what we're trying to do as part of the current txs.
26
+ await this.contractsDB.addNewContracts(tx);
27
+
28
+ if (!tx.data.forPublic) {
29
+ this.#log.debug(
30
+ `Tx ${await Tx.getHash(tx)} does not contain enqueued public functions. Skipping phases validation.`,
31
+ );
32
+ return { result: 'valid' };
33
+ }
34
+
35
+ const setupFns = getCallRequestsWithCalldataByPhase(tx, TxExecutionPhase.SETUP);
36
+ for (const setupFn of setupFns) {
37
+ if (!(await this.isOnAllowList(setupFn, this.setupAllowList))) {
38
+ this.#log.warn(
39
+ `Rejecting tx ${await Tx.getHash(tx)} because it calls setup function not on allow list: ${
40
+ setupFn.request.contractAddress
41
+ }:${setupFn.functionSelector}`,
42
+ { allowList: this.setupAllowList },
43
+ );
44
+
45
+ return { result: 'invalid', reason: ['Setup function not on allow list'] };
46
+ }
47
+ }
48
+
49
+ return { result: 'valid' };
50
+ } finally {
51
+ this.contractsDB.clearContractsForTx();
52
+ }
53
+ }
54
+
55
+ private async isOnAllowList(
56
+ publicCall: PublicCallRequestWithCalldata,
57
+ allowList: AllowedElement[],
58
+ ): Promise<boolean> {
59
+ if (publicCall.isEmpty()) {
60
+ return true;
61
+ }
62
+
63
+ const contractAddress = publicCall.request.contractAddress;
64
+ const functionSelector = publicCall.functionSelector;
65
+
66
+ // do these checks first since they don't require the contract class
67
+ for (const entry of allowList) {
68
+ if ('address' in entry && !('selector' in entry)) {
69
+ if (contractAddress.equals(entry.address)) {
70
+ return true;
71
+ }
72
+ }
73
+
74
+ if ('address' in entry && 'selector' in entry) {
75
+ if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
76
+ return true;
77
+ }
78
+ }
79
+
80
+ const contractClass = await this.contractsDB.getContractInstance(contractAddress, this.blockNumber);
81
+
82
+ if (!contractClass) {
83
+ throw new Error(`Contract not found: ${contractAddress}`);
84
+ }
85
+
86
+ if ('classId' in entry && !('selector' in entry)) {
87
+ if (contractClass.currentContractClassId.equals(entry.classId)) {
88
+ return true;
89
+ }
90
+ }
91
+
92
+ if ('classId' in entry && 'selector' in entry) {
93
+ if (
94
+ contractClass.currentContractClassId.equals(entry.classId) &&
95
+ (entry.selector === undefined || entry.selector.equals(functionSelector))
96
+ ) {
97
+ return true;
98
+ }
99
+ }
100
+ }
101
+
102
+ return false;
103
+ }
104
+ }
@@ -0,0 +1,43 @@
1
+ import type { Fr } from '@aztec/foundation/fields';
2
+ import type { FunctionSelector } from '@aztec/stdlib/abi';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import { HashedValues, type Tx } from '@aztec/stdlib/tx';
5
+
6
+ export function patchNonRevertibleFn(
7
+ tx: Tx,
8
+ index: number,
9
+ overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
10
+ ): Promise<AztecAddress> {
11
+ return patchFn('nonRevertibleAccumulatedData', tx, index, overrides);
12
+ }
13
+
14
+ export function patchRevertibleFn(
15
+ tx: Tx,
16
+ index: number,
17
+ overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
18
+ ): Promise<AztecAddress> {
19
+ return patchFn('revertibleAccumulatedData', tx, index, overrides);
20
+ }
21
+
22
+ async function patchFn(
23
+ where: 'revertibleAccumulatedData' | 'nonRevertibleAccumulatedData',
24
+ tx: Tx,
25
+ index: number,
26
+ overrides: { address?: AztecAddress; selector: FunctionSelector; args?: Fr[]; msgSender?: AztecAddress },
27
+ ): Promise<AztecAddress> {
28
+ const calldataIndex =
29
+ where === 'nonRevertibleAccumulatedData'
30
+ ? index
31
+ : index + tx.data.forPublic!.nonRevertibleAccumulatedData.publicCallRequests.length;
32
+ const calldata = [overrides.selector.toField(), ...(overrides.args ?? [])];
33
+ const hashedCalldata = await HashedValues.fromCalldata(calldata);
34
+ tx.publicFunctionCalldata[calldataIndex] = hashedCalldata;
35
+
36
+ const request = tx.data.forPublic![where].publicCallRequests[index];
37
+ request.contractAddress = overrides.address ?? request.contractAddress;
38
+ request.msgSender = overrides.msgSender ?? request.msgSender;
39
+ request.calldataHash = hashedCalldata.hash;
40
+ tx.data.forPublic![where].publicCallRequests[index] = request;
41
+
42
+ return request.contractAddress;
43
+ }
@@ -4,7 +4,10 @@ import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log
4
4
  import { SerialQueue } from '@aztec/foundation/queue';
5
5
  import { RunningPromise } from '@aztec/foundation/running-promise';
6
6
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
7
+ import { ProtocolContractAddress } from '@aztec/protocol-contracts';
7
8
  import type { L2BlockSource } from '@aztec/stdlib/block';
9
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
10
+ import { GasFees } from '@aztec/stdlib/gas';
8
11
  import type { ClientProtocolCircuitVerifier, PeerInfo, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
9
12
  import {
10
13
  BlockAttestation,
@@ -16,7 +19,7 @@ import {
16
19
  getTopicTypeForClientType,
17
20
  metricsTopicStrToLabels,
18
21
  } from '@aztec/stdlib/p2p';
19
- import { MerkleTreeId } from '@aztec/stdlib/trees';
22
+ import { DatabasePublicStateSource, MerkleTreeId } from '@aztec/stdlib/trees';
20
23
  import { Tx, type TxHash, type TxValidationResult } from '@aztec/stdlib/tx';
21
24
  import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
22
25
 
@@ -43,10 +46,13 @@ import { createLibp2p } from 'libp2p';
43
46
  import type { P2PConfig } from '../../config.js';
44
47
  import type { MemPools } from '../../mem_pools/interface.js';
45
48
  import { AttestationValidator, BlockProposalValidator } from '../../msg_validators/index.js';
49
+ import { getDefaultAllowedSetupFunctions } from '../../msg_validators/tx_validator/allowed_public_setup.js';
46
50
  import {
47
51
  DataTxValidator,
48
52
  DoubleSpendTxValidator,
53
+ GasTxValidator,
49
54
  MetadataTxValidator,
55
+ PhasesTxValidator,
50
56
  TxProofValidator,
51
57
  } from '../../msg_validators/tx_validator/index.js';
52
58
  import { GossipSubEvent } from '../../types/index.js';
@@ -95,6 +101,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
95
101
  // Trusted peers ids
96
102
  private trustedPeersIds: PeerId[] = [];
97
103
 
104
+ private feesCache: { blockNumber: number; gasFees: GasFees } | undefined;
105
+
98
106
  /**
99
107
  * Callback for when a block is received from a peer.
100
108
  * @param block - The block received from the peer.
@@ -110,7 +118,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
110
118
  private node: PubSubLibp2p,
111
119
  private peerDiscoveryService: PeerDiscoveryService,
112
120
  private mempools: MemPools<T>,
113
- private l2BlockSource: L2BlockSource,
121
+ private archiver: L2BlockSource & ContractDataSource,
114
122
  epochCache: EpochCacheInterface,
115
123
  private proofVerifier: ClientProtocolCircuitVerifier,
116
124
  private worldStateSynchronizer: WorldStateSynchronizer,
@@ -164,7 +172,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
164
172
  peerDiscoveryService: PeerDiscoveryService,
165
173
  peerId: PeerId,
166
174
  mempools: MemPools<T>,
167
- l2BlockSource: L2BlockSource,
175
+ l2BlockSource: L2BlockSource & ContractDataSource,
168
176
  epochCache: EpochCacheInterface,
169
177
  proofVerifier: ClientProtocolCircuitVerifier,
170
178
  worldStateSynchronizer: WorldStateSynchronizer,
@@ -322,7 +330,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
322
330
  // Create request response protocol handlers
323
331
  const txHandler = reqRespTxHandler(this.mempools);
324
332
  const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
325
- const blockHandler = reqRespBlockHandler(this.l2BlockSource);
333
+ const blockHandler = reqRespBlockHandler(this.archiver);
326
334
 
327
335
  const requestResponseHandlers = {
328
336
  [ReqRespSubProtocol.PING]: pingHandler,
@@ -686,8 +694,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
686
694
  [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
687
695
  }))
688
696
  private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
689
- const blockNumber = (await this.l2BlockSource.getBlockNumber()) + 1;
690
- const messageValidators = this.createMessageValidators(blockNumber);
697
+ const blockNumber = (await this.archiver.getBlockNumber()) + 1;
698
+ const messageValidators = await this.createMessageValidators(blockNumber);
691
699
  const outcome = await this.runValidations(tx, messageValidators);
692
700
 
693
701
  if (outcome.allPassed) {
@@ -705,6 +713,17 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
705
713
  return false;
706
714
  }
707
715
 
716
+ private async getGasFees(blockNumber: number): Promise<GasFees> {
717
+ if (blockNumber === this.feesCache?.blockNumber) {
718
+ return this.feesCache.gasFees;
719
+ }
720
+
721
+ const header = await this.archiver.getBlockHeader(blockNumber);
722
+ const gasFees = header?.globalVariables.gasFees ?? GasFees.empty();
723
+ this.feesCache = { blockNumber, gasFees };
724
+ return gasFees;
725
+ }
726
+
708
727
  /**
709
728
  * Create message validators for the given block number.
710
729
  *
@@ -714,7 +733,11 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
714
733
  * @param blockNumber - The block number to create validators for.
715
734
  * @returns The message validators.
716
735
  */
717
- private createMessageValidators(blockNumber: number): Record<string, MessageValidator> {
736
+ private async createMessageValidators(blockNumber: number): Promise<Record<string, MessageValidator>> {
737
+ const merkleTree = this.worldStateSynchronizer.getCommitted();
738
+ const gasFees = await this.getGasFees(blockNumber - 1);
739
+ const allowedInSetup = this.config.txPublicSetupAllowList ?? (await getDefaultAllowedSetupFunctions());
740
+
718
741
  return {
719
742
  dataValidator: {
720
743
  validator: new DataTxValidator(),
@@ -742,6 +765,18 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
742
765
  }),
743
766
  severity: PeerErrorSeverity.HighToleranceError,
744
767
  },
768
+ gasValidator: {
769
+ validator: new GasTxValidator(
770
+ new DatabasePublicStateSource(merkleTree),
771
+ ProtocolContractAddress.FeeJuice,
772
+ gasFees,
773
+ ),
774
+ severity: PeerErrorSeverity.HighToleranceError,
775
+ },
776
+ phasesValidator: {
777
+ validator: new PhasesTxValidator(this.archiver, allowedInSetup, blockNumber),
778
+ severity: PeerErrorSeverity.MidToleranceError,
779
+ },
745
780
  };
746
781
  }
747
782
 
@@ -45,7 +45,11 @@ export class PeerManager {
45
45
  private trustedPeersInitialized: boolean = false;
46
46
 
47
47
  private metrics: PeerManagerMetrics;
48
- private discoveredPeerHandler;
48
+ private handlers: {
49
+ handleConnectedPeerEvent: (e: CustomEvent<PeerId>) => void;
50
+ handleDisconnectedPeerEvent: (e: CustomEvent<PeerId>) => void;
51
+ handleDiscoveredPeer: (enr: ENR) => Promise<void>;
52
+ } = {} as any;
49
53
 
50
54
  constructor(
51
55
  private libP2PNode: PubSubLibp2p,
@@ -58,17 +62,21 @@ export class PeerManager {
58
62
  ) {
59
63
  this.metrics = new PeerManagerMetrics(telemetryClient, 'PeerManager');
60
64
 
65
+ // Handle Discovered peers
66
+ this.handlers = {
67
+ handleConnectedPeerEvent: this.handleConnectedPeerEvent.bind(this),
68
+ handleDisconnectedPeerEvent: this.handleDisconnectedPeerEvent.bind(this),
69
+ handleDiscoveredPeer: (enr: ENR) =>
70
+ this.handleDiscoveredPeer(enr).catch(e => this.logger.error('Error handling discovered peer', e)),
71
+ };
72
+
61
73
  // Handle new established connections
62
- this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent.bind(this));
74
+ this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handlers.handleConnectedPeerEvent);
63
75
  // Handle lost connections
64
- this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent.bind(this));
65
-
66
- // Handle Discovered peers
67
- this.discoveredPeerHandler = (enr: ENR) =>
68
- this.handleDiscoveredPeer(enr).catch(e => this.logger.error('Error handling discovered peer', e));
76
+ this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handlers.handleDisconnectedPeerEvent);
69
77
 
70
78
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
71
- this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
79
+ this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.handlers.handleDiscoveredPeer);
72
80
 
73
81
  // Display peer counts every 60 seconds
74
82
  this.displayPeerCountsPeerHeartbeat = Math.floor(60_000 / this.config.peerCheckIntervalMS);
@@ -538,15 +546,15 @@ export class PeerManager {
538
546
  */
539
547
  public async stop() {
540
548
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
541
- this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
549
+ this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.handlers.handleDiscoveredPeer);
542
550
 
543
551
  // Send goodbyes to all peers
544
552
  await Promise.all(
545
553
  this.libP2PNode.getPeers().map(peer => this.goodbyeAndDisconnectPeer(peer, GoodByeReason.SHUTDOWN)),
546
554
  );
547
555
 
548
- this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent);
549
- this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent);
556
+ this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handlers.handleConnectedPeerEvent);
557
+ this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handlers.handleDisconnectedPeerEvent);
550
558
  }
551
559
  }
552
560
 
@@ -4,6 +4,7 @@ import type { DataStoreConfig } from '@aztec/kv-store/config';
4
4
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
5
5
  import type { L2BlockSource } from '@aztec/stdlib/block';
6
6
  import { type ChainConfig, emptyChainConfig } from '@aztec/stdlib/config';
7
+ import type { ContractDataSource } from '@aztec/stdlib/contract';
7
8
  import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
8
9
  import type { P2PClientType } from '@aztec/stdlib/p2p';
9
10
  import type { Tx } from '@aztec/stdlib/tx';
@@ -98,7 +99,7 @@ export async function createLibp2pNode(
98
99
  export async function createTestLibP2PService<T extends P2PClientType>(
99
100
  clientType: T,
100
101
  boostrapAddrs: string[] = [],
101
- l2BlockSource: L2BlockSource,
102
+ archiver: L2BlockSource & ContractDataSource,
102
103
  worldStateSynchronizer: WorldStateSynchronizer,
103
104
  epochCache: EpochCache,
104
105
  mempools: MemPools<T>,
@@ -131,7 +132,7 @@ export async function createTestLibP2PService<T extends P2PClientType>(
131
132
  p2pNode as PubSubLibp2p,
132
133
  discoveryService,
133
134
  mempools,
134
- l2BlockSource,
135
+ archiver,
135
136
  epochCache,
136
137
  proofVerifier,
137
138
  worldStateSynchronizer,