@aztec/p2p 0.72.1 → 0.74.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 (78) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +2 -2
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +1 -1
  4. package/dest/client/factory.d.ts +2 -2
  5. package/dest/client/factory.d.ts.map +1 -1
  6. package/dest/client/factory.js +4 -4
  7. package/dest/client/p2p_client.d.ts +13 -16
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +50 -62
  10. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  11. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +11 -19
  12. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +6 -13
  13. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +74 -80
  15. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  16. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +5 -5
  17. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -1
  18. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  19. package/dest/mem_pools/attestation_pool/mocks.js +3 -3
  20. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +9 -9
  21. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +59 -53
  23. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +7 -7
  24. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool/memory_tx_pool.js +17 -18
  26. package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -7
  27. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +48 -47
  30. package/dest/mocks/index.js +3 -3
  31. package/dest/msg_validators/attestation_validator/attestation_validator.js +2 -2
  32. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +2 -2
  33. package/dest/msg_validators/tx_validator/block_header_validator.js +3 -3
  34. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  35. package/dest/msg_validators/tx_validator/data_validator.js +7 -7
  36. package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -3
  37. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  38. package/dest/msg_validators/tx_validator/metadata_validator.js +9 -9
  39. package/dest/services/data_store.d.ts +4 -4
  40. package/dest/services/data_store.d.ts.map +1 -1
  41. package/dest/services/data_store.js +7 -7
  42. package/dest/services/libp2p/libp2p_service.d.ts +3 -3
  43. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  44. package/dest/services/libp2p/libp2p_service.js +56 -35
  45. package/dest/services/peer-manager/peer_manager.d.ts +1 -0
  46. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  47. package/dest/services/peer-manager/peer_manager.js +6 -3
  48. package/dest/services/reqresp/protocols/tx.js +4 -4
  49. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  50. package/dest/services/reqresp/reqresp.js +2 -2
  51. package/dest/util.d.ts +2 -2
  52. package/dest/util.d.ts.map +1 -1
  53. package/dest/util.js +2 -2
  54. package/package.json +7 -7
  55. package/src/bootstrap/bootstrap.ts +2 -2
  56. package/src/client/factory.ts +5 -5
  57. package/src/client/p2p_client.ts +63 -75
  58. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +14 -22
  59. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +100 -94
  60. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +4 -4
  61. package/src/mem_pools/attestation_pool/mocks.ts +3 -3
  62. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +84 -72
  63. package/src/mem_pools/tx_pool/memory_tx_pool.ts +26 -23
  64. package/src/mem_pools/tx_pool/tx_pool.ts +7 -7
  65. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +50 -47
  66. package/src/mocks/index.ts +2 -2
  67. package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
  68. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
  69. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  70. package/src/msg_validators/tx_validator/data_validator.ts +12 -9
  71. package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
  72. package/src/msg_validators/tx_validator/metadata_validator.ts +8 -8
  73. package/src/services/data_store.ts +9 -9
  74. package/src/services/libp2p/libp2p_service.ts +70 -36
  75. package/src/services/peer-manager/peer_manager.ts +7 -2
  76. package/src/services/reqresp/protocols/tx.ts +3 -3
  77. package/src/services/reqresp/reqresp.ts +7 -1
  78. package/src/util.ts +7 -4
@@ -1,7 +1,8 @@
1
1
  import { BlockAttestation } from '@aztec/circuit-types';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
+ import { toArray } from '@aztec/foundation/iterable';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
- import { type AztecKVStore, type AztecMapWithSize, type AztecMultiMap } from '@aztec/kv-store';
5
+ import { type AztecAsyncKVStore, type AztecAsyncMap, type AztecAsyncMultiMap } from '@aztec/kv-store';
5
6
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
6
7
 
7
8
  import { PoolInstrumentation, PoolName } from '../instrumentation.js';
@@ -10,144 +11,149 @@ import { type AttestationPool } from './attestation_pool.js';
10
11
  export class KvAttestationPool implements AttestationPool {
11
12
  private metrics: PoolInstrumentation<BlockAttestation>;
12
13
 
13
- // Index of all proposal ids in a slot
14
- private attestations: AztecMultiMap<string, string>;
14
+ private attestations: AztecAsyncMap<string, Buffer>;
15
+ private proposalsForSlot: AztecAsyncMultiMap<string, string>;
16
+ private attestationsForProposal: AztecAsyncMultiMap<string, string>;
15
17
 
16
18
  constructor(
17
- private store: AztecKVStore,
19
+ private store: AztecAsyncKVStore,
18
20
  telemetry: TelemetryClient = getTelemetryClient(),
19
21
  private log = createLogger('aztec:attestation_pool'),
20
22
  ) {
21
- this.attestations = store.openMultiMap('attestations');
23
+ this.attestations = store.openMap('attestations');
24
+ this.proposalsForSlot = store.openMultiMap('proposals_for_slot');
25
+ this.attestationsForProposal = store.openMultiMap('attestations_for_proposal');
26
+
22
27
  this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL);
23
28
  }
24
29
 
25
- private getProposalMapKey(slot: string, proposalId: string): string {
26
- return `proposal-${slot}-${proposalId}`;
30
+ private getProposalKey(slot: number | bigint | Fr | string, proposalId: Fr | string | Buffer): string {
31
+ const slotStr = typeof slot === 'string' ? slot : new Fr(slot).toString();
32
+ const proposalIdStr =
33
+ typeof proposalId === 'string'
34
+ ? proposalId
35
+ : Buffer.isBuffer(proposalId)
36
+ ? Fr.fromBuffer(proposalId).toString()
37
+ : proposalId.toString();
38
+
39
+ return `${slotStr}-${proposalIdStr}`;
27
40
  }
28
41
 
29
- /**
30
- * Get the proposal map for a given slot and proposalId
31
- *
32
- * Essentially a nested mapping of address -> attestation
33
- *
34
- * @param slot - The slot to get the proposal map for
35
- * @param proposalId - The proposalId to get the map for
36
- * @returns The proposal map
37
- */
38
- private getProposalMap(slot: string, proposalId: string): AztecMapWithSize<string, Buffer> {
39
- const mapKey = this.getProposalMapKey(slot, proposalId);
40
- return this.store.openMapWithSize(mapKey);
42
+ private getAttestationKey(slot: number | bigint | Fr | string, proposalId: Fr | string, address: string): string {
43
+ return `${this.getProposalKey(slot, proposalId)}-${address}`;
41
44
  }
42
45
 
43
46
  public async addAttestations(attestations: BlockAttestation[]): Promise<void> {
44
- for (const attestation of attestations) {
45
- const slotNumber = attestation.payload.header.globalVariables.slotNumber.toString();
46
- const proposalId = attestation.archive.toString();
47
- const address = attestation.getSender().toString();
47
+ await this.store.transactionAsync(async () => {
48
+ for (const attestation of attestations) {
49
+ const slotNumber = attestation.payload.header.globalVariables.slotNumber;
50
+ const proposalId = attestation.archive;
51
+ const address = (await attestation.getSender()).toString();
48
52
 
49
- // Index the proposalId in the slot map
50
- await this.attestations.set(slotNumber, proposalId);
53
+ await this.attestations.set(this.getAttestationKey(slotNumber, proposalId, address), attestation.toBuffer());
51
54
 
52
- // Store the actual attestation in the proposal map
53
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
54
- await proposalMap.set(address, attestation.toBuffer());
55
+ await this.proposalsForSlot.set(slotNumber.toString(), proposalId.toString());
56
+ await this.attestationsForProposal.set(
57
+ this.getProposalKey(slotNumber, proposalId),
58
+ this.getAttestationKey(slotNumber, proposalId, address),
59
+ );
55
60
 
56
- this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`);
57
- }
61
+ this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`);
62
+ }
63
+ });
58
64
 
59
65
  this.metrics.recordAddedObjects(attestations.length);
60
66
  }
61
67
 
62
- public getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
63
- const slotNumber = new Fr(slot).toString();
64
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
65
- const attestations = proposalMap.values();
66
- const attestationsArray = Array.from(attestations).map(attestation => BlockAttestation.fromBuffer(attestation));
67
- return Promise.resolve(attestationsArray);
68
- }
68
+ public async getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
69
+ const attestationIds = await toArray(
70
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
71
+ );
72
+ const attestations: BlockAttestation[] = [];
69
73
 
70
- public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
71
- const olderThan = [];
74
+ // alternatively iterate this.attestaions starting from slot-proposal-EthAddress.zero
75
+ for (const id of attestationIds) {
76
+ const buf = await this.attestations.getAsync(id);
72
77
 
73
- const slots = this.attestations.keys();
74
- for (const slot of slots) {
75
- if (BigInt(slot) < oldestSlot) {
76
- olderThan.push(slot);
78
+ if (!buf) {
79
+ // this should not happen unless we lost writes
80
+ throw new Error('Attestation not found ' + id);
77
81
  }
82
+
83
+ const attestation = BlockAttestation.fromBuffer(buf);
84
+ attestations.push(attestation);
78
85
  }
79
86
 
80
- await Promise.all(olderThan.map(oldSlot => this.deleteAttestationsForSlot(BigInt(oldSlot))));
81
- return Promise.resolve();
87
+ return attestations;
82
88
  }
83
89
 
84
- public async deleteAttestationsForSlot(slot: bigint): Promise<void> {
85
- const deletionPromises = [];
90
+ public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
91
+ const olderThan = await toArray(this.proposalsForSlot.keysAsync({ end: new Fr(oldestSlot).toString() }));
92
+ for (const oldSlot of olderThan) {
93
+ await this.deleteAttestationsForSlot(BigInt(oldSlot));
94
+ }
95
+ }
86
96
 
87
- const slotString = new Fr(slot).toString();
97
+ public async deleteAttestationsForSlot(slot: bigint): Promise<void> {
98
+ const slotFr = new Fr(slot);
88
99
  let numberOfAttestations = 0;
89
- const proposalIds = this.attestations.getValues(slotString);
90
-
91
- if (proposalIds) {
100
+ await this.store.transactionAsync(async () => {
101
+ const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slotFr.toString()));
92
102
  for (const proposalId of proposalIds) {
93
- const proposalMap = this.getProposalMap(slotString, proposalId);
94
- numberOfAttestations += proposalMap.size();
95
- deletionPromises.push(proposalMap.clear());
96
- }
97
- }
103
+ const attestations = await toArray(
104
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slotFr, proposalId)),
105
+ );
98
106
 
99
- await Promise.all(deletionPromises);
107
+ numberOfAttestations += attestations.length;
108
+ for (const attestation of attestations) {
109
+ await this.attestations.delete(attestation);
110
+ }
111
+
112
+ await this.attestationsForProposal.delete(this.getProposalKey(slotFr, proposalId));
113
+ }
114
+ });
100
115
 
101
116
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
102
117
  this.metrics.recordRemovedObjects(numberOfAttestations);
103
- return Promise.resolve();
104
118
  }
105
119
 
106
120
  public async deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void> {
107
- const deletionPromises = [];
108
-
109
- const slotString = new Fr(slot).toString();
110
- const exists = this.attestations.get(slotString);
111
-
112
- if (exists) {
113
- // Remove the proposalId from the slot index
114
- deletionPromises.push(this.attestations.deleteValue(slotString, proposalId));
115
-
116
- // Delete all attestations for the proposalId
117
- const proposalMap = this.getProposalMap(slotString, proposalId);
118
- const numberOfAttestations = proposalMap.size();
119
- deletionPromises.push(proposalMap.clear());
121
+ let numberOfAttestations = 0;
122
+ await this.store.transactionAsync(async () => {
123
+ const slotString = new Fr(slot).toString();
124
+ const attestations = await toArray(
125
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
126
+ );
127
+
128
+ numberOfAttestations += attestations.length;
129
+ for (const attestation of attestations) {
130
+ await this.attestations.delete(attestation);
131
+ }
120
132
 
121
- this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
122
- this.metrics.recordRemovedObjects(numberOfAttestations);
123
- }
133
+ await this.proposalsForSlot.deleteValue(slotString, proposalId);
134
+ await this.attestationsForProposal.delete(this.getProposalKey(slotString, proposalId));
135
+ });
124
136
 
125
- await Promise.all(deletionPromises);
126
- return Promise.resolve();
137
+ this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
138
+ this.metrics.recordRemovedObjects(numberOfAttestations);
127
139
  }
128
140
 
129
141
  public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
130
- const deletionPromises = [];
131
-
132
- for (const attestation of attestations) {
133
- const slotNumber = attestation.payload.header.globalVariables.slotNumber.toString();
134
- const proposalId = attestation.archive.toString();
135
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
142
+ await this.store.transactionAsync(async () => {
143
+ for (const attestation of attestations) {
144
+ const slotNumber = attestation.payload.header.globalVariables.slotNumber;
145
+ const proposalId = attestation.archive;
146
+ const address = (await attestation.getSender()).toString();
147
+
148
+ await this.attestations.delete(this.getAttestationKey(slotNumber, proposalId, address));
149
+ await this.attestationsForProposal.deleteValue(
150
+ this.getProposalKey(slotNumber, proposalId),
151
+ this.getAttestationKey(slotNumber, proposalId, address),
152
+ );
136
153
 
137
- if (proposalMap) {
138
- const address = attestation.getSender().toString();
139
- deletionPromises.push(proposalMap.delete(address));
140
154
  this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
141
155
  }
142
-
143
- if (proposalMap.size() === 0) {
144
- deletionPromises.push(this.attestations.deleteValue(slotNumber, proposalId));
145
- }
146
- }
147
-
148
- await Promise.all(deletionPromises);
149
-
156
+ });
150
157
  this.metrics.recordRemovedObjects(attestations.length);
151
- return Promise.resolve();
152
158
  }
153
159
  }
@@ -26,13 +26,13 @@ export class InMemoryAttestationPool implements AttestationPool {
26
26
  return Promise.resolve([]);
27
27
  }
28
28
 
29
- public addAttestations(attestations: BlockAttestation[]): Promise<void> {
29
+ public async addAttestations(attestations: BlockAttestation[]): Promise<void> {
30
30
  for (const attestation of attestations) {
31
31
  // Perf: order and group by slot before insertion
32
32
  const slotNumber = attestation.payload.header.globalVariables.slotNumber;
33
33
 
34
34
  const proposalId = attestation.archive.toString();
35
- const address = attestation.getSender();
35
+ const address = await attestation.getSender();
36
36
 
37
37
  const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber.toBigInt());
38
38
  const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
@@ -105,7 +105,7 @@ export class InMemoryAttestationPool implements AttestationPool {
105
105
  return Promise.resolve();
106
106
  }
107
107
 
108
- public deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
108
+ public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
109
109
  for (const attestation of attestations) {
110
110
  const slotNumber = attestation.payload.header.globalVariables.slotNumber;
111
111
  const slotAttestationMap = this.attestations.get(slotNumber.toBigInt());
@@ -113,7 +113,7 @@ export class InMemoryAttestationPool implements AttestationPool {
113
113
  const proposalId = attestation.archive.toString();
114
114
  const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
115
115
  if (proposalAttestationMap) {
116
- const address = attestation.getSender();
116
+ const address = await attestation.getSender();
117
117
  proposalAttestationMap.delete(address.toString());
118
118
  this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
119
119
  }
@@ -27,17 +27,17 @@ export const generateAccount = (): LocalAccount => {
27
27
  * @param slot The slot number the attestation is for
28
28
  * @returns A Block Attestation
29
29
  */
30
- export const mockAttestation = (
30
+ export const mockAttestation = async (
31
31
  signer: Secp256k1Signer,
32
32
  slot: number = 0,
33
33
  archive: Fr = Fr.random(),
34
34
  txs: TxHash[] = [0, 1, 2, 3, 4, 5].map(() => TxHash.random()),
35
- ): BlockAttestation => {
35
+ ): Promise<BlockAttestation> => {
36
36
  // Use arbitrary numbers for all other than slot
37
37
  const header = makeHeader(1, 2, slot);
38
38
  const payload = new ConsensusPayload(header, archive, txs);
39
39
 
40
- const hash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
40
+ const hash = await getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
41
41
  const signature = signer.sign(hash);
42
42
 
43
43
  return new BlockAttestation(payload, signature);
@@ -1,8 +1,9 @@
1
1
  import { Tx, TxHash } from '@aztec/circuit-types';
2
2
  import { type TxAddedToPoolStats } from '@aztec/circuit-types/stats';
3
3
  import { ClientIvcProof } from '@aztec/circuits.js';
4
+ import { toArray } from '@aztec/foundation/iterable';
4
5
  import { type Logger, createLogger } from '@aztec/foundation/log';
5
- import { type AztecKVStore, type AztecMap, type AztecMultiMap } from '@aztec/kv-store';
6
+ import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
6
7
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
7
8
 
8
9
  import { PoolInstrumentation, PoolName } from '../instrumentation.js';
@@ -13,25 +14,25 @@ import { type TxPool } from './tx_pool.js';
13
14
  * KV implementation of the Transaction Pool.
14
15
  */
15
16
  export class AztecKVTxPool implements TxPool {
16
- #store: AztecKVStore;
17
+ #store: AztecAsyncKVStore;
17
18
 
18
19
  /** Our tx pool, stored as a Map, with K: tx hash and V: the transaction. */
19
- #txs: AztecMap<string, Buffer>;
20
+ #txs: AztecAsyncMap<string, Buffer>;
20
21
 
21
22
  /** Index from tx hash to the block number in which they were mined, filtered by mined txs. */
22
- #minedTxHashToBlock: AztecMap<string, number>;
23
+ #minedTxHashToBlock: AztecAsyncMap<string, number>;
23
24
 
24
25
  /** Index from tx priority (stored as hex) to its tx hash, filtered by pending txs. */
25
- #pendingTxPriorityToHash: AztecMultiMap<string, string>;
26
+ #pendingTxPriorityToHash: AztecAsyncMultiMap<string, string>;
26
27
 
27
28
  /** KV store for archived txs. */
28
- #archive: AztecKVStore;
29
+ #archive: AztecAsyncKVStore;
29
30
 
30
31
  /** Archived txs map for future lookup. */
31
- #archivedTxs: AztecMap<string, Buffer>;
32
+ #archivedTxs: AztecAsyncMap<string, Buffer>;
32
33
 
33
34
  /** Indexes of the archived txs by insertion order. */
34
- #archivedTxIndices: AztecMap<number, string>;
35
+ #archivedTxIndices: AztecAsyncMap<number, string>;
35
36
 
36
37
  /** Number of txs to archive. */
37
38
  #archivedTxLimit: number;
@@ -49,8 +50,8 @@ export class AztecKVTxPool implements TxPool {
49
50
  * @param log - A logger.
50
51
  */
51
52
  constructor(
52
- store: AztecKVStore,
53
- archive: AztecKVStore,
53
+ store: AztecAsyncKVStore,
54
+ archive: AztecAsyncKVStore,
54
55
  telemetry: TelemetryClient = getTelemetryClient(),
55
56
  archivedTxLimit: number = 0,
56
57
  log = createLogger('p2p:tx_pool'),
@@ -75,16 +76,16 @@ export class AztecKVTxPool implements TxPool {
75
76
  }
76
77
 
77
78
  let deletedPending = 0;
78
- return this.#store.transaction(() => {
79
+ return this.#store.transactionAsync(async () => {
79
80
  for (const hash of txHashes) {
80
81
  const key = hash.toString();
81
- void this.#minedTxHashToBlock.set(key, blockNumber);
82
+ await this.#minedTxHashToBlock.set(key, blockNumber);
82
83
 
83
- const tx = this.getTxByHash(hash);
84
+ const tx = await this.getTxByHash(hash);
84
85
  if (tx) {
85
86
  deletedPending++;
86
87
  const fee = getPendingTxPriority(tx);
87
- void this.#pendingTxPriorityToHash.deleteValue(fee, key);
88
+ await this.#pendingTxPriorityToHash.deleteValue(fee, key);
88
89
  }
89
90
  }
90
91
  this.#metrics.recordAddedObjects(txHashes.length, 'mined');
@@ -98,14 +99,14 @@ export class AztecKVTxPool implements TxPool {
98
99
  }
99
100
 
100
101
  let markedAsPending = 0;
101
- return this.#store.transaction(() => {
102
+ return this.#store.transactionAsync(async () => {
102
103
  for (const hash of txHashes) {
103
104
  const key = hash.toString();
104
- void this.#minedTxHashToBlock.delete(key);
105
+ await this.#minedTxHashToBlock.delete(key);
105
106
 
106
- const tx = this.getTxByHash(hash);
107
+ const tx = await this.getTxByHash(hash);
107
108
  if (tx) {
108
- void this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
109
+ await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
109
110
  markedAsPending++;
110
111
  }
111
112
  }
@@ -115,22 +116,23 @@ export class AztecKVTxPool implements TxPool {
115
116
  });
116
117
  }
117
118
 
118
- public getPendingTxHashes(): TxHash[] {
119
- return Array.from(this.#pendingTxPriorityToHash.values({ reverse: true })).map(x => TxHash.fromString(x));
119
+ public async getPendingTxHashes(): Promise<TxHash[]> {
120
+ const vals = await toArray(this.#pendingTxPriorityToHash.valuesAsync({ reverse: true }));
121
+ return vals.map(x => TxHash.fromString(x));
120
122
  }
121
123
 
122
- public getMinedTxHashes(): [TxHash, number][] {
123
- return Array.from(this.#minedTxHashToBlock.entries()).map(([txHash, blockNumber]) => [
124
- TxHash.fromString(txHash),
125
- blockNumber,
126
- ]);
124
+ public async getMinedTxHashes(): Promise<[TxHash, number][]> {
125
+ const vals = await toArray(this.#minedTxHashToBlock.entriesAsync());
126
+ return vals.map(([txHash, blockNumber]) => [TxHash.fromString(txHash), blockNumber]);
127
127
  }
128
128
 
129
- public getTxStatus(txHash: TxHash): 'pending' | 'mined' | undefined {
129
+ public async getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | undefined> {
130
130
  const key = txHash.toString();
131
- if (this.#minedTxHashToBlock.has(key)) {
131
+ const [isMined, isKnown] = await Promise.all([this.#minedTxHashToBlock.hasAsync(key), this.#txs.hasAsync(key)]);
132
+
133
+ if (isMined) {
132
134
  return 'mined';
133
- } else if (this.#txs.has(key)) {
135
+ } else if (isKnown) {
134
136
  return 'pending';
135
137
  } else {
136
138
  return undefined;
@@ -142,8 +144,8 @@ export class AztecKVTxPool implements TxPool {
142
144
  * @param txHash - The generated tx hash.
143
145
  * @returns The transaction, if found, 'undefined' otherwise.
144
146
  */
145
- public getTxByHash(txHash: TxHash): Tx | undefined {
146
- const buffer = this.#txs.get(txHash.toString());
147
+ public async getTxByHash(txHash: TxHash): Promise<Tx | undefined> {
148
+ const buffer = await this.#txs.getAsync(txHash.toString());
147
149
  if (buffer) {
148
150
  const tx = Tx.fromBuffer(buffer);
149
151
  tx.setTxHash(txHash);
@@ -157,8 +159,8 @@ export class AztecKVTxPool implements TxPool {
157
159
  * @param txHash - The tx hash.
158
160
  * @returns The transaction metadata, if found, 'undefined' otherwise.
159
161
  */
160
- public getArchivedTxByHash(txHash: TxHash): Tx | undefined {
161
- const buffer = this.#archivedTxs.get(txHash.toString());
162
+ public async getArchivedTxByHash(txHash: TxHash): Promise<Tx | undefined> {
163
+ const buffer = await this.#archivedTxs.getAsync(txHash.toString());
162
164
  if (buffer) {
163
165
  const tx = Tx.fromBuffer(buffer);
164
166
  tx.setTxHash(txHash);
@@ -172,26 +174,31 @@ export class AztecKVTxPool implements TxPool {
172
174
  * @param txs - An array of txs to be added to the pool.
173
175
  * @returns Empty promise.
174
176
  */
175
- public addTxs(txs: Tx[]): Promise<void> {
176
- return this.#store.transaction(() => {
177
+ public async addTxs(txs: Tx[]): Promise<void> {
178
+ const hashesAndStats = await Promise.all(
179
+ txs.map(async tx => ({ txHash: await tx.getTxHash(), txStats: await tx.getStats() })),
180
+ );
181
+ await this.#store.transactionAsync(async () => {
177
182
  let pendingCount = 0;
178
- for (const tx of txs) {
179
- const txHash = tx.getTxHash();
180
- this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
181
- eventName: 'tx-added-to-pool',
182
- ...tx.getStats(),
183
- } satisfies TxAddedToPoolStats);
184
-
185
- const key = txHash.toString();
186
- void this.#txs.set(key, tx.toBuffer());
187
-
188
- if (!this.#minedTxHashToBlock.has(key)) {
189
- pendingCount++;
190
- // REFACTOR: Use an lmdb conditional write to avoid race conditions with this write tx
191
- void this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
192
- this.#metrics.recordSize(tx);
193
- }
194
- }
183
+ await Promise.all(
184
+ txs.map(async (tx, i) => {
185
+ const { txHash, txStats } = hashesAndStats[i];
186
+ this.#log.verbose(`Adding tx ${txHash.toString()} to pool`, {
187
+ eventName: 'tx-added-to-pool',
188
+ ...txStats,
189
+ } satisfies TxAddedToPoolStats);
190
+
191
+ const key = txHash.toString();
192
+ await this.#txs.set(key, tx.toBuffer());
193
+
194
+ if (!(await this.#minedTxHashToBlock.hasAsync(key))) {
195
+ pendingCount++;
196
+ // REFACTOR: Use an lmdb conditional write to avoid race conditions with this write tx
197
+ await this.#pendingTxPriorityToHash.set(getPendingTxPriority(tx), key);
198
+ this.#metrics.recordSize(tx);
199
+ }
200
+ }),
201
+ );
195
202
 
196
203
  this.#metrics.recordAddedObjects(pendingCount, 'pending');
197
204
  });
@@ -207,16 +214,16 @@ export class AztecKVTxPool implements TxPool {
207
214
  let minedDeleted = 0;
208
215
 
209
216
  const deletedTxs: Tx[] = [];
210
- const poolDbTx = this.#store.transaction(() => {
217
+ const poolDbTx = this.#store.transactionAsync(async () => {
211
218
  for (const hash of txHashes) {
212
219
  const key = hash.toString();
213
- const tx = this.getTxByHash(hash);
220
+ const tx = await this.getTxByHash(hash);
214
221
 
215
222
  if (tx) {
216
223
  const fee = getPendingTxPriority(tx);
217
- void this.#pendingTxPriorityToHash.deleteValue(fee, key);
224
+ await this.#pendingTxPriorityToHash.deleteValue(fee, key);
218
225
 
219
- const isMined = this.#minedTxHashToBlock.has(key);
226
+ const isMined = await this.#minedTxHashToBlock.hasAsync(key);
220
227
  if (isMined) {
221
228
  minedDeleted++;
222
229
  } else {
@@ -227,8 +234,8 @@ export class AztecKVTxPool implements TxPool {
227
234
  deletedTxs.push(tx);
228
235
  }
229
236
 
230
- void this.#txs.delete(key);
231
- void this.#minedTxHashToBlock.delete(key);
237
+ await this.#txs.delete(key);
238
+ await this.#minedTxHashToBlock.delete(key);
232
239
  }
233
240
  }
234
241
 
@@ -243,8 +250,9 @@ export class AztecKVTxPool implements TxPool {
243
250
  * Gets all the transactions stored in the pool.
244
251
  * @returns Array of tx objects in the order they were added to the pool.
245
252
  */
246
- public getAllTxs(): Tx[] {
247
- return Array.from(this.#txs.entries()).map(([hash, buffer]) => {
253
+ public async getAllTxs(): Promise<Tx[]> {
254
+ const vals = await toArray(this.#txs.entriesAsync());
255
+ return vals.map(([hash, buffer]) => {
248
256
  const tx = Tx.fromBuffer(buffer);
249
257
  tx.setTxHash(TxHash.fromString(hash));
250
258
  return tx;
@@ -255,8 +263,9 @@ export class AztecKVTxPool implements TxPool {
255
263
  * Gets the hashes of all transactions currently in the tx pool.
256
264
  * @returns An array of transaction hashes found in the tx pool.
257
265
  */
258
- public getAllTxHashes(): TxHash[] {
259
- return Array.from(this.#txs.keys()).map(x => TxHash.fromString(x));
266
+ public async getAllTxHashes(): Promise<TxHash[]> {
267
+ const vals = await toArray(this.#txs.keysAsync());
268
+ return vals.map(x => TxHash.fromString(x));
260
269
  }
261
270
 
262
271
  /**
@@ -264,18 +273,21 @@ export class AztecKVTxPool implements TxPool {
264
273
  * @param txs - The list of transactions to archive.
265
274
  * @returns Empty promise.
266
275
  */
267
- private archiveTxs(txs: Tx[]): Promise<void> {
268
- return this.#archive.transaction(() => {
276
+ private async archiveTxs(txs: Tx[]): Promise<void> {
277
+ const txHashes = await Promise.all(txs.map(tx => tx.getTxHash()));
278
+ await this.#archive.transactionAsync(async () => {
269
279
  // calcualte the head and tail indices of the archived txs by insertion order.
270
- let headIdx = (this.#archivedTxIndices.entries({ limit: 1, reverse: true }).next().value?.[0] ?? -1) + 1;
271
- let tailIdx = this.#archivedTxIndices.entries({ limit: 1 }).next().value?.[0] ?? 0;
280
+ let headIdx =
281
+ ((await this.#archivedTxIndices.entriesAsync({ limit: 1, reverse: true }).next()).value?.[0] ?? -1) + 1;
282
+ let tailIdx = (await this.#archivedTxIndices.entriesAsync({ limit: 1 }).next()).value?.[0] ?? 0;
272
283
 
273
- for (const tx of txs) {
284
+ for (let i = 0; i < txs.length; i++) {
285
+ const tx = txs[i];
274
286
  while (headIdx - tailIdx >= this.#archivedTxLimit) {
275
- const txHash = this.#archivedTxIndices.get(tailIdx);
287
+ const txHash = await this.#archivedTxIndices.getAsync(tailIdx);
276
288
  if (txHash) {
277
- void this.#archivedTxs.delete(txHash);
278
- void this.#archivedTxIndices.delete(tailIdx);
289
+ await this.#archivedTxs.delete(txHash);
290
+ await this.#archivedTxIndices.delete(tailIdx);
279
291
  }
280
292
  tailIdx++;
281
293
  }
@@ -287,9 +299,9 @@ export class AztecKVTxPool implements TxPool {
287
299
  tx.enqueuedPublicFunctionCalls,
288
300
  tx.publicTeardownFunctionCall,
289
301
  );
290
- const txHash = tx.getTxHash().toString();
291
- void this.#archivedTxs.set(txHash, archivedTx.toBuffer());
292
- void this.#archivedTxIndices.set(headIdx, txHash);
302
+ const txHash = txHashes[i].toString();
303
+ await this.#archivedTxs.set(txHash, archivedTx.toBuffer());
304
+ await this.#archivedTxIndices.set(headIdx, txHash);
293
305
  headIdx++;
294
306
  }
295
307
  });