@aztec/p2p 2.1.0-rc.9 → 2.1.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.
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/bootstrap/bootstrap.js +14 -4
- package/dest/client/factory.d.ts +1 -0
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +5 -3
- package/dest/client/interface.d.ts +1 -1
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/client/p2p_client.d.ts +2 -1
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +12 -2
- package/dest/config.d.ts +4 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +4 -3
- package/dest/enr/generate-enr.d.ts +1 -1
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +15 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +35 -4
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +2 -0
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +34 -2
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +2 -0
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +43 -7
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +5 -3
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +1 -0
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +6 -0
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +1 -0
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/memory_tx_pool.js +6 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +6 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -0
- package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
- package/dest/msg_validators/attestation_validator/attestation_validator.js +29 -2
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +4 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +16 -4
- package/dest/services/discv5/discV5_service.d.ts +2 -2
- package/dest/services/discv5/discV5_service.d.ts.map +1 -1
- package/dest/services/discv5/discV5_service.js +2 -2
- package/dest/services/dummy_service.d.ts +1 -1
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/encoding.d.ts +24 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/encoding.js +73 -5
- package/dest/services/libp2p/libp2p_service.d.ts +16 -9
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +89 -39
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +9 -3
- package/dest/services/reqresp/reqresp.js +2 -2
- package/dest/services/service.d.ts +1 -1
- package/dest/services/service.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/fast_tx_collection.js +6 -1
- package/dest/services/tx_collection/tx_collection.d.ts +2 -1
- package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
- package/dest/services/tx_collection/tx_collection.js +3 -2
- package/dest/services/tx_provider.d.ts +1 -1
- package/dest/services/tx_provider.d.ts.map +1 -1
- package/dest/services/tx_provider.js +7 -3
- package/dest/test-helpers/make-enrs.js +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +4 -3
- package/dest/testbench/p2p_client_testbench_worker.js +4 -1
- package/dest/versioning.d.ts +1 -1
- package/dest/versioning.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/bootstrap/bootstrap.ts +15 -4
- package/src/client/factory.ts +10 -3
- package/src/client/interface.ts +1 -1
- package/src/client/p2p_client.ts +12 -3
- package/src/config.ts +6 -4
- package/src/enr/generate-enr.ts +1 -1
- package/src/mem_pools/attestation_pool/attestation_pool.ts +17 -0
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +40 -4
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +43 -2
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +52 -7
- package/src/mem_pools/attestation_pool/mocks.ts +6 -3
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +5 -0
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +5 -0
- package/src/mem_pools/tx_pool/tx_pool.ts +7 -0
- package/src/msg_validators/attestation_validator/attestation_validator.ts +39 -2
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +20 -4
- package/src/services/discv5/discV5_service.ts +2 -2
- package/src/services/dummy_service.ts +1 -1
- package/src/services/encoding.ts +80 -5
- package/src/services/libp2p/libp2p_service.ts +93 -51
- package/src/services/peer-manager/peer_manager.ts +10 -3
- package/src/services/reqresp/reqresp.ts +2 -2
- package/src/services/service.ts +1 -1
- package/src/services/tx_collection/fast_tx_collection.ts +3 -1
- package/src/services/tx_collection/tx_collection.ts +3 -2
- package/src/services/tx_provider.ts +3 -2
- package/src/test-helpers/make-enrs.ts +1 -1
- package/src/test-helpers/reqresp-nodes.ts +3 -2
- package/src/testbench/p2p_client_testbench_worker.ts +3 -0
- package/src/versioning.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/p2p",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -67,19 +67,17 @@
|
|
|
67
67
|
]
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@aztec/constants": "2.1.
|
|
71
|
-
"@aztec/epoch-cache": "2.1.
|
|
72
|
-
"@aztec/ethereum": "2.1.
|
|
73
|
-
"@aztec/foundation": "2.1.
|
|
74
|
-
"@aztec/kv-store": "2.1.
|
|
75
|
-
"@aztec/noir-contracts.js": "2.1.
|
|
76
|
-
"@aztec/noir-protocol-circuits-types": "2.1.
|
|
77
|
-
"@aztec/protocol-contracts": "2.1.
|
|
78
|
-
"@aztec/simulator": "2.1.
|
|
79
|
-
"@aztec/stdlib": "2.1.
|
|
80
|
-
"@aztec/telemetry-client": "2.1.
|
|
81
|
-
"@chainsafe/discv5": "9.0.0",
|
|
82
|
-
"@chainsafe/enr": "3.0.0",
|
|
70
|
+
"@aztec/constants": "2.1.2",
|
|
71
|
+
"@aztec/epoch-cache": "2.1.2",
|
|
72
|
+
"@aztec/ethereum": "2.1.2",
|
|
73
|
+
"@aztec/foundation": "2.1.2",
|
|
74
|
+
"@aztec/kv-store": "2.1.2",
|
|
75
|
+
"@aztec/noir-contracts.js": "2.1.2",
|
|
76
|
+
"@aztec/noir-protocol-circuits-types": "2.1.2",
|
|
77
|
+
"@aztec/protocol-contracts": "2.1.2",
|
|
78
|
+
"@aztec/simulator": "2.1.2",
|
|
79
|
+
"@aztec/stdlib": "2.1.2",
|
|
80
|
+
"@aztec/telemetry-client": "2.1.2",
|
|
83
81
|
"@chainsafe/libp2p-gossipsub": "13.0.0",
|
|
84
82
|
"@chainsafe/libp2p-noise": "^15.0.0",
|
|
85
83
|
"@chainsafe/libp2p-yamux": "^6.0.2",
|
|
@@ -94,6 +92,8 @@
|
|
|
94
92
|
"@libp2p/prometheus-metrics": "^4.2.4",
|
|
95
93
|
"@libp2p/tcp": "9.0.24",
|
|
96
94
|
"@multiformats/multiaddr": "12.1.14",
|
|
95
|
+
"@nethermindeth/discv5": "9.0.0-backport-306-v4",
|
|
96
|
+
"@nethermindeth/enr": "3.0.0-backport-306-v4",
|
|
97
97
|
"interface-datastore": "^8.2.11",
|
|
98
98
|
"interface-store": "^5.1.8",
|
|
99
99
|
"libp2p": "1.5.0",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"xxhash-wasm": "^1.1.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@aztec/archiver": "2.1.
|
|
108
|
-
"@aztec/world-state": "2.1.
|
|
107
|
+
"@aztec/archiver": "2.1.2",
|
|
108
|
+
"@aztec/world-state": "2.1.2",
|
|
109
109
|
"@jest/globals": "^30.0.0",
|
|
110
110
|
"@types/jest": "^30.0.0",
|
|
111
111
|
"@types/node": "^22.15.17",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"ts-node": "^10.9.1",
|
|
118
118
|
"typescript": "^5.3.3",
|
|
119
119
|
"uint8arrays": "^5.0.3",
|
|
120
|
-
"viem": "2.
|
|
120
|
+
"viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
|
|
121
121
|
},
|
|
122
122
|
"files": [
|
|
123
123
|
"dest",
|
|
@@ -3,14 +3,14 @@ import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
|
3
3
|
import type { P2PBootstrapApi } from '@aztec/stdlib/interfaces/server';
|
|
4
4
|
import { OtelMetricsAdapter, type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
5
|
|
|
6
|
-
import { Discv5, type Discv5EventEmitter } from '@chainsafe/discv5';
|
|
7
|
-
import { ENR, type 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 } from '@nethermindeth/discv5';
|
|
9
|
+
import { ENR, type SignableENR } from '@nethermindeth/enr';
|
|
10
10
|
|
|
11
11
|
import type { BootnodeConfig } from '../config.js';
|
|
12
12
|
import { createBootnodeENRandPeerId } from '../enr/generate-enr.js';
|
|
13
|
-
import { convertToMultiaddr, getPeerIdPrivateKey } from '../util.js';
|
|
13
|
+
import { convertToMultiaddr, getPeerIdPrivateKey, getPublicIp } from '../util.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Encapsulates a 'Bootstrap' node, used for the purpose of assisting new joiners in acquiring peers.
|
|
@@ -31,7 +31,18 @@ export class BootstrapNode implements P2PBootstrapApi {
|
|
|
31
31
|
* @returns An empty promise.
|
|
32
32
|
*/
|
|
33
33
|
public async start(config: BootnodeConfig) {
|
|
34
|
-
const {
|
|
34
|
+
const { p2pPort, listenAddress, p2pBroadcastPort, queryForIp } = config;
|
|
35
|
+
let p2pIp = config.p2pIp;
|
|
36
|
+
this.logger.info(`Starting bootstrap node with config: ${JSON.stringify(config)}`);
|
|
37
|
+
if (!p2pIp) {
|
|
38
|
+
if (queryForIp) {
|
|
39
|
+
this.logger.info('Querying for public IP address...');
|
|
40
|
+
const publicIp = await getPublicIp();
|
|
41
|
+
p2pIp = publicIp;
|
|
42
|
+
this.logger.info(`Found public IP address: ${publicIp}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
if (!p2pIp) {
|
|
36
47
|
throw new Error('You need to provide a P2P IP address.');
|
|
37
48
|
}
|
package/src/client/factory.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-clien
|
|
|
14
14
|
import { P2PClient } from '../client/p2p_client.js';
|
|
15
15
|
import type { P2PConfig } from '../config.js';
|
|
16
16
|
import type { AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
|
|
17
|
-
import {
|
|
17
|
+
import { KvAttestationPool } from '../mem_pools/attestation_pool/kv_attestation_pool.js';
|
|
18
18
|
import type { MemPools } from '../mem_pools/interface.js';
|
|
19
19
|
import { AztecKVTxPool, type TxPool } from '../mem_pools/tx_pool/index.js';
|
|
20
20
|
import { DummyP2PService } from '../services/dummy_service.js';
|
|
@@ -35,6 +35,7 @@ export type P2PClientDeps<T extends P2PClientType> = {
|
|
|
35
35
|
export const P2P_STORE_NAME = 'p2p';
|
|
36
36
|
export const P2P_ARCHIVE_STORE_NAME = 'p2p-archive';
|
|
37
37
|
export const P2P_PEER_STORE_NAME = 'p2p-peers';
|
|
38
|
+
export const P2P_ATTESTATION_STORE_NAME = 'p2p-attestation';
|
|
38
39
|
|
|
39
40
|
export async function createP2PClient<T extends P2PClientType>(
|
|
40
41
|
clientType: T,
|
|
@@ -50,7 +51,7 @@ export async function createP2PClient<T extends P2PClientType>(
|
|
|
50
51
|
) {
|
|
51
52
|
const config = await configureP2PClientAddresses({
|
|
52
53
|
...inputConfig,
|
|
53
|
-
|
|
54
|
+
dataStoreMapSizeKb: inputConfig.p2pStoreMapSizeKb ?? inputConfig.dataStoreMapSizeKb,
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
const logger = deps.logger ?? createLogger('p2p');
|
|
@@ -64,6 +65,12 @@ export async function createP2PClient<T extends P2PClientType>(
|
|
|
64
65
|
const store = deps.store ?? (await createStore(P2P_STORE_NAME, 2, config, createLogger('p2p:lmdb-v2')));
|
|
65
66
|
const archive = await createStore(P2P_ARCHIVE_STORE_NAME, 1, config, createLogger('p2p-archive:lmdb-v2'));
|
|
66
67
|
const peerStore = await createStore(P2P_PEER_STORE_NAME, 1, config, createLogger('p2p-peer:lmdb-v2'));
|
|
68
|
+
const attestationStore = await createStore(
|
|
69
|
+
P2P_ATTESTATION_STORE_NAME,
|
|
70
|
+
1,
|
|
71
|
+
config,
|
|
72
|
+
createLogger('p2p-attestation:lmdb-v2'),
|
|
73
|
+
);
|
|
67
74
|
const l1Constants = await archiver.getL1Constants();
|
|
68
75
|
|
|
69
76
|
const mempools: MemPools<T> = {
|
|
@@ -75,7 +82,7 @@ export async function createP2PClient<T extends P2PClientType>(
|
|
|
75
82
|
}),
|
|
76
83
|
attestationPool:
|
|
77
84
|
clientType === P2PClientType.Full
|
|
78
|
-
? ((deps.attestationPool ?? new
|
|
85
|
+
? ((deps.attestationPool ?? new KvAttestationPool(attestationStore, telemetry)) as T extends P2PClientType.Full
|
|
79
86
|
? AttestationPool
|
|
80
87
|
: undefined)
|
|
81
88
|
: undefined,
|
package/src/client/interface.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { P2PApiFull } from '@aztec/stdlib/interfaces/server';
|
|
|
3
3
|
import type { BlockProposal, P2PClientType } from '@aztec/stdlib/p2p';
|
|
4
4
|
import type { 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
|
|
|
9
9
|
import type { P2PConfig } from '../config.js';
|
|
10
10
|
import type { AuthRequest, StatusMessage } from '../services/index.js';
|
package/src/client/p2p_client.ts
CHANGED
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
trackSpan,
|
|
27
27
|
} from '@aztec/telemetry-client';
|
|
28
28
|
|
|
29
|
-
import type { ENR } from '@chainsafe/enr';
|
|
30
29
|
import type { PeerId } from '@libp2p/interface';
|
|
30
|
+
import type { ENR } from '@nethermindeth/enr';
|
|
31
31
|
|
|
32
32
|
import { type P2PConfig, getP2PDefaultConfig } from '../config.js';
|
|
33
33
|
import type { AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
|
|
@@ -123,7 +123,13 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
123
123
|
const constants = this.txCollection.getConstants();
|
|
124
124
|
const nextSlotTimestampSeconds = Number(getTimestampForSlot(block.slotNumber.toBigInt() + 1n, constants));
|
|
125
125
|
const deadline = new Date(nextSlotTimestampSeconds * 1000);
|
|
126
|
-
await this.
|
|
126
|
+
const parentBlock = await this.l2BlockSource.getBlockHeaderByArchive(block.payload.header.lastArchiveRoot);
|
|
127
|
+
if (!parentBlock) {
|
|
128
|
+
this.log.debug(`Cannot collect txs for proposal as parent block not found`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const blockNumber = parentBlock.getBlockNumber() + 1;
|
|
132
|
+
await this.txProvider.getTxsForBlockProposal(block, blockNumber, { pinnedPeer: sender, deadline });
|
|
127
133
|
return undefined;
|
|
128
134
|
});
|
|
129
135
|
|
|
@@ -365,7 +371,6 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
365
371
|
}
|
|
366
372
|
|
|
367
373
|
@trackSpan('p2pClient.broadcastProposal', async proposal => ({
|
|
368
|
-
[Attributes.BLOCK_NUMBER]: proposal.blockNumber,
|
|
369
374
|
[Attributes.SLOT_NUMBER]: proposal.slotNumber.toNumber(),
|
|
370
375
|
[Attributes.BLOCK_ARCHIVE]: proposal.archive.toString(),
|
|
371
376
|
[Attributes.P2P_ID]: (await proposal.p2pMessageIdentifier()).toString(),
|
|
@@ -387,6 +392,10 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
387
392
|
return this.attestationPool?.addAttestations(attestations) ?? Promise.resolve();
|
|
388
393
|
}
|
|
389
394
|
|
|
395
|
+
public deleteAttestation(attestation: BlockAttestation): Promise<void> {
|
|
396
|
+
return this.attestationPool?.deleteAttestations([attestation]) ?? Promise.resolve();
|
|
397
|
+
}
|
|
398
|
+
|
|
390
399
|
// REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
391
400
|
// ^ This pattern is not my favorite (md)
|
|
392
401
|
public registerBlockProposalHandler(handler: P2PBlockReceivedCallback): void {
|
package/src/config.ts
CHANGED
|
@@ -127,7 +127,7 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig, TxCollectionCo
|
|
|
127
127
|
/** A list of preferred peers. */
|
|
128
128
|
preferredPeers: string[];
|
|
129
129
|
|
|
130
|
-
/** The maximum possible size of the P2P DB in KB. Overwrites the general
|
|
130
|
+
/** The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb. */
|
|
131
131
|
p2pStoreMapSizeKb?: number;
|
|
132
132
|
|
|
133
133
|
/** Which calls are allowed in the public setup phase of a tx. */
|
|
@@ -360,7 +360,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
|
|
|
360
360
|
p2pStoreMapSizeKb: {
|
|
361
361
|
env: 'P2P_STORE_MAP_SIZE_KB',
|
|
362
362
|
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
363
|
-
description: 'The maximum possible size of the P2P DB in KB. Overwrites the general
|
|
363
|
+
description: 'The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb.',
|
|
364
364
|
},
|
|
365
365
|
txPublicSetupAllowList: {
|
|
366
366
|
env: 'TX_PUBLIC_SETUP_ALLOWLIST',
|
|
@@ -449,9 +449,10 @@ export type BootnodeConfig = Pick<
|
|
|
449
449
|
| 'peerIdPrivateKeyPath'
|
|
450
450
|
| 'bootstrapNodes'
|
|
451
451
|
| 'listenAddress'
|
|
452
|
+
| 'queryForIp'
|
|
452
453
|
> &
|
|
453
454
|
Required<Pick<P2PConfig, 'p2pIp' | 'p2pPort'>> &
|
|
454
|
-
Pick<DataStoreConfig, 'dataDirectory' | '
|
|
455
|
+
Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKb'> &
|
|
455
456
|
Pick<ChainConfig, 'l1ChainId'>;
|
|
456
457
|
|
|
457
458
|
const bootnodeConfigKeys: (keyof BootnodeConfig)[] = [
|
|
@@ -462,9 +463,10 @@ const bootnodeConfigKeys: (keyof BootnodeConfig)[] = [
|
|
|
462
463
|
'peerIdPrivateKey',
|
|
463
464
|
'peerIdPrivateKeyPath',
|
|
464
465
|
'dataDirectory',
|
|
465
|
-
'
|
|
466
|
+
'dataStoreMapSizeKb',
|
|
466
467
|
'bootstrapNodes',
|
|
467
468
|
'l1ChainId',
|
|
469
|
+
'queryForIp',
|
|
468
470
|
];
|
|
469
471
|
|
|
470
472
|
export const bootnodeConfigMappings = pickConfigMappings(
|
package/src/enr/generate-enr.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { LogFn } from '@aztec/foundation/log';
|
|
|
2
2
|
import { type ChainConfig, emptyChainConfig } from '@aztec/stdlib/config';
|
|
3
3
|
import type { ComponentsVersions } from '@aztec/stdlib/versioning';
|
|
4
4
|
|
|
5
|
-
import { ENR, SignableENR } from '@chainsafe/enr';
|
|
6
5
|
import type { PeerId } from '@libp2p/interface';
|
|
7
6
|
import { type Multiaddr, multiaddr } from '@multiformats/multiaddr';
|
|
7
|
+
import { ENR, SignableENR } from '@nethermindeth/enr';
|
|
8
8
|
|
|
9
9
|
import { AZTEC_ENR_CLIENT_VERSION_KEY, AZTEC_ENR_KEY } from '../types/index.js';
|
|
10
10
|
import { convertToMultiaddr, createLibP2PPeerIdFromPrivateKey } from '../util.js';
|
|
@@ -21,6 +21,15 @@ export interface AttestationPool {
|
|
|
21
21
|
*/
|
|
22
22
|
getBlockProposal(id: string): Promise<BlockProposal | undefined>;
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Check if a block proposal exists in the pool
|
|
26
|
+
*
|
|
27
|
+
* @param idOrProposal - The ID of the block proposal or the block proposal itself to check. The ID is proposal.payload.archive
|
|
28
|
+
*
|
|
29
|
+
* @return True if the block proposal exists, false otherwise.
|
|
30
|
+
*/
|
|
31
|
+
hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean>;
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* AddAttestations
|
|
26
35
|
*
|
|
@@ -84,6 +93,14 @@ export interface AttestationPool {
|
|
|
84
93
|
*/
|
|
85
94
|
getAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<BlockAttestation[]>;
|
|
86
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Check if a specific attestation exists in the pool
|
|
98
|
+
*
|
|
99
|
+
* @param attestation - The attestation to check
|
|
100
|
+
* @return True if the attestation exists, false otherwise
|
|
101
|
+
*/
|
|
102
|
+
hasAttestation(attestation: BlockAttestation): Promise<boolean>;
|
|
103
|
+
|
|
87
104
|
/** Returns whether the pool is empty. */
|
|
88
105
|
isEmpty(): Promise<boolean>;
|
|
89
106
|
}
|
|
@@ -41,7 +41,6 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
const mockBlockProposal = (signer: Secp256k1Signer, slotNumber: number, archive: Fr = Fr.random()): BlockProposal => {
|
|
44
|
-
const blockNumber = 1;
|
|
45
44
|
const header = makeHeader(1, 2, slotNumber);
|
|
46
45
|
const payload = new ConsensusPayload(header.toPropose(), archive, header.state);
|
|
47
46
|
|
|
@@ -50,7 +49,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
50
49
|
|
|
51
50
|
const txHashes = [TxHash.random(), TxHash.random()]; // Mock tx hashes
|
|
52
51
|
|
|
53
|
-
return new BlockProposalClass(
|
|
52
|
+
return new BlockProposalClass(payload, signature, txHashes);
|
|
54
53
|
};
|
|
55
54
|
|
|
56
55
|
// We compare buffers as the objects can have cached values attached to them which are not serialised
|
|
@@ -73,6 +72,11 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
73
72
|
expect(retrievedAttestations.length).toBe(attestations.length);
|
|
74
73
|
compareAttestations(retrievedAttestations, attestations);
|
|
75
74
|
|
|
75
|
+
// Check hasAttestation for added attestations
|
|
76
|
+
for (const attestation of attestations) {
|
|
77
|
+
expect(await ap.hasAttestation(attestation)).toBe(true);
|
|
78
|
+
}
|
|
79
|
+
|
|
76
80
|
const retrievedAttestationsForSlot = await ap.getAttestationsForSlot(BigInt(slotNumber));
|
|
77
81
|
expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
|
|
78
82
|
compareAttestations(retrievedAttestationsForSlot, attestations);
|
|
@@ -86,6 +90,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
86
90
|
);
|
|
87
91
|
expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
|
|
88
92
|
compareAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
|
|
93
|
+
expect(await ap.hasAttestation(newAttestation)).toBe(true);
|
|
89
94
|
const retrievedAttestationsForSlotAfterAdd = await ap.getAttestationsForSlot(BigInt(slotNumber));
|
|
90
95
|
expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
|
|
91
96
|
compareAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
|
|
@@ -98,6 +103,11 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
98
103
|
archive.toString(),
|
|
99
104
|
);
|
|
100
105
|
expect(retreivedAttestationsAfterDelete.length).toBe(0);
|
|
106
|
+
// Check hasAttestation after deletion
|
|
107
|
+
for (const attestation of attestations) {
|
|
108
|
+
expect(await ap.hasAttestation(attestation)).toBe(false);
|
|
109
|
+
}
|
|
110
|
+
expect(await ap.hasAttestation(newAttestation)).toBe(false);
|
|
101
111
|
});
|
|
102
112
|
|
|
103
113
|
it('should handle duplicate proposals in a slot', async () => {
|
|
@@ -117,7 +127,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
117
127
|
const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
|
|
118
128
|
expect(retreivedAttestations.length).toBe(1);
|
|
119
129
|
expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
|
|
120
|
-
expect(retreivedAttestations[0].getSender()
|
|
130
|
+
expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
|
|
121
131
|
|
|
122
132
|
// Try adding them on another operation and check they are still not duplicated
|
|
123
133
|
await ap.addAttestations([attestations[0]]);
|
|
@@ -171,10 +181,20 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
171
181
|
expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
|
|
172
182
|
compareAttestations(retreivedAttestations, attestations);
|
|
173
183
|
|
|
184
|
+
// Check hasAttestation before deletion
|
|
185
|
+
for (const attestation of attestations) {
|
|
186
|
+
expect(await ap.hasAttestation(attestation)).toBe(true);
|
|
187
|
+
}
|
|
188
|
+
|
|
174
189
|
await ap.deleteAttestations(attestations);
|
|
175
190
|
|
|
176
191
|
const gottenAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
|
|
177
192
|
expect(gottenAfterDelete.length).toBe(0);
|
|
193
|
+
|
|
194
|
+
// Check hasAttestation after deletion
|
|
195
|
+
for (const attestation of attestations) {
|
|
196
|
+
expect(await ap.hasAttestation(attestation)).toBe(false);
|
|
197
|
+
}
|
|
178
198
|
});
|
|
179
199
|
|
|
180
200
|
it('should blanket delete attestations per slot', async () => {
|
|
@@ -266,12 +286,19 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
266
286
|
|
|
267
287
|
expect(retrievedProposal).toBeDefined();
|
|
268
288
|
expect(retrievedProposal!).toEqual(proposal);
|
|
289
|
+
|
|
290
|
+
// Check hasBlockProposal with both id and object
|
|
291
|
+
expect(await ap.hasBlockProposal(proposalId)).toBe(true);
|
|
292
|
+
expect(await ap.hasBlockProposal(proposal)).toBe(true);
|
|
269
293
|
});
|
|
270
294
|
|
|
271
295
|
it('should return undefined for non-existent block proposal', async () => {
|
|
272
296
|
const nonExistentId = Fr.random().toString();
|
|
273
297
|
const retrievedProposal = await ap.getBlockProposal(nonExistentId);
|
|
274
298
|
expect(retrievedProposal).toBeUndefined();
|
|
299
|
+
|
|
300
|
+
// Check hasBlockProposal returns false for non-existent proposal
|
|
301
|
+
expect(await ap.hasBlockProposal(nonExistentId)).toBe(false);
|
|
275
302
|
});
|
|
276
303
|
|
|
277
304
|
it('should update block proposal if added twice with same id', async () => {
|
|
@@ -291,7 +318,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
291
318
|
expect(retrievedProposal).toBeDefined();
|
|
292
319
|
// Should have the second proposal
|
|
293
320
|
expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toBuffer());
|
|
294
|
-
expect(retrievedProposal!.getSender()
|
|
321
|
+
expect(retrievedProposal!.getSender()?.toString()).toBe(signers[1].address.toString());
|
|
295
322
|
});
|
|
296
323
|
|
|
297
324
|
it('should handle block proposals with different slots and same archive', async () => {
|
|
@@ -324,6 +351,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
324
351
|
// Verify proposal exists
|
|
325
352
|
let retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
326
353
|
expect(retrievedProposal).toBeDefined();
|
|
354
|
+
expect(await ap.hasBlockProposal(proposalId)).toBe(true);
|
|
327
355
|
|
|
328
356
|
// Delete attestations for slot and proposal
|
|
329
357
|
await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
|
|
@@ -331,6 +359,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
331
359
|
// Proposal should be deleted
|
|
332
360
|
retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
333
361
|
expect(retrievedProposal).toBeUndefined();
|
|
362
|
+
expect(await ap.hasBlockProposal(proposalId)).toBe(false);
|
|
334
363
|
});
|
|
335
364
|
|
|
336
365
|
it('should delete block proposal when deleting attestations for slot', async () => {
|
|
@@ -345,6 +374,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
345
374
|
// Verify proposal exists
|
|
346
375
|
let retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
347
376
|
expect(retrievedProposal).toBeDefined();
|
|
377
|
+
expect(await ap.hasBlockProposal(proposal)).toBe(true);
|
|
348
378
|
|
|
349
379
|
// Delete attestations for slot
|
|
350
380
|
await ap.deleteAttestationsForSlot(BigInt(slotNumber));
|
|
@@ -352,6 +382,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
352
382
|
// Proposal should be deleted
|
|
353
383
|
retrievedProposal = await ap.getBlockProposal(proposalId);
|
|
354
384
|
expect(retrievedProposal).toBeUndefined();
|
|
385
|
+
expect(await ap.hasBlockProposal(proposal)).toBe(false);
|
|
355
386
|
});
|
|
356
387
|
|
|
357
388
|
it('should be able to fetch both block proposal and attestations', async () => {
|
|
@@ -373,8 +404,13 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
|
|
|
373
404
|
|
|
374
405
|
expect(retrievedProposal).toBeDefined();
|
|
375
406
|
expect(retrievedProposal).toEqual(proposal);
|
|
407
|
+
expect(await ap.hasBlockProposal(proposalId)).toBe(true);
|
|
376
408
|
|
|
377
409
|
compareAttestations(retrievedAttestations, attestations);
|
|
410
|
+
// Check hasAttestation for all attestations
|
|
411
|
+
for (const attestation of attestations) {
|
|
412
|
+
expect(await ap.hasAttestation(attestation)).toBe(true);
|
|
413
|
+
}
|
|
378
414
|
});
|
|
379
415
|
});
|
|
380
416
|
}
|
|
@@ -66,7 +66,19 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
66
66
|
for (const attestation of attestations) {
|
|
67
67
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
68
68
|
const proposalId = attestation.archive;
|
|
69
|
-
const
|
|
69
|
+
const sender = attestation.getSender();
|
|
70
|
+
|
|
71
|
+
// Skip attestations with invalid signatures
|
|
72
|
+
if (!sender) {
|
|
73
|
+
this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber.toBigInt()}`, {
|
|
74
|
+
signature: attestation.signature.toString(),
|
|
75
|
+
slotNumber,
|
|
76
|
+
proposalId,
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const address = sender.toString();
|
|
70
82
|
|
|
71
83
|
await this.attestations.set(this.getAttestationKey(slotNumber, proposalId, address), attestation.toBuffer());
|
|
72
84
|
|
|
@@ -176,7 +188,15 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
176
188
|
for (const attestation of attestations) {
|
|
177
189
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
178
190
|
const proposalId = attestation.archive;
|
|
179
|
-
const
|
|
191
|
+
const sender = attestation.getSender();
|
|
192
|
+
|
|
193
|
+
// Skip attestations with invalid signatures
|
|
194
|
+
if (!sender) {
|
|
195
|
+
this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber.toBigInt()}`);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const address = sender.toString();
|
|
180
200
|
const key = this.getAttestationKey(slotNumber, proposalId, address);
|
|
181
201
|
|
|
182
202
|
if (await this.attestations.hasAsync(key)) {
|
|
@@ -193,6 +213,22 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
193
213
|
});
|
|
194
214
|
}
|
|
195
215
|
|
|
216
|
+
public async hasAttestation(attestation: BlockAttestation): Promise<boolean> {
|
|
217
|
+
const slotNumber = attestation.payload.header.slotNumber;
|
|
218
|
+
const proposalId = attestation.archive;
|
|
219
|
+
const sender = attestation.getSender();
|
|
220
|
+
|
|
221
|
+
// Attestations with invalid signatures are never in the pool
|
|
222
|
+
if (!sender) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const address = sender.toString();
|
|
227
|
+
const key = this.getAttestationKey(slotNumber, proposalId, address);
|
|
228
|
+
|
|
229
|
+
return await this.attestations.hasAsync(key);
|
|
230
|
+
}
|
|
231
|
+
|
|
196
232
|
public async getBlockProposal(id: string): Promise<BlockProposal | undefined> {
|
|
197
233
|
const buffer = await this.proposals.getAsync(id);
|
|
198
234
|
try {
|
|
@@ -206,6 +242,11 @@ export class KvAttestationPool implements AttestationPool {
|
|
|
206
242
|
return Promise.resolve(undefined);
|
|
207
243
|
}
|
|
208
244
|
|
|
245
|
+
public async hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
|
|
246
|
+
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.payload.archive.toString();
|
|
247
|
+
return await this.proposals.hasAsync(id);
|
|
248
|
+
}
|
|
249
|
+
|
|
209
250
|
public async addBlockProposal(blockProposal: BlockProposal): Promise<void> {
|
|
210
251
|
await this.store.transactionAsync(async () => {
|
|
211
252
|
await this.proposalsForSlot.set(blockProposal.slotNumber.toString(), blockProposal.archive.toString());
|
|
@@ -55,16 +55,26 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
55
55
|
const slotNumber = attestation.payload.header.slotNumber;
|
|
56
56
|
|
|
57
57
|
const proposalId = attestation.archive.toString();
|
|
58
|
-
const
|
|
58
|
+
const sender = attestation.getSender();
|
|
59
|
+
|
|
60
|
+
// Skip attestations with invalid signatures
|
|
61
|
+
if (!sender) {
|
|
62
|
+
this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber.toBigInt()}`, {
|
|
63
|
+
signature: attestation.signature.toString(),
|
|
64
|
+
slotNumber,
|
|
65
|
+
proposalId,
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
59
69
|
|
|
60
70
|
const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber.toBigInt());
|
|
61
71
|
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
|
|
62
|
-
proposalAttestationMap.set(
|
|
72
|
+
proposalAttestationMap.set(sender.toString(), attestation);
|
|
63
73
|
|
|
64
|
-
this.log.verbose(`Added attestation for slot ${slotNumber.toBigInt()} from ${
|
|
74
|
+
this.log.verbose(`Added attestation for slot ${slotNumber.toBigInt()} from ${sender}`, {
|
|
65
75
|
signature: attestation.signature.toString(),
|
|
66
76
|
slotNumber,
|
|
67
|
-
address,
|
|
77
|
+
address: sender,
|
|
68
78
|
proposalId,
|
|
69
79
|
});
|
|
70
80
|
}
|
|
@@ -147,15 +157,45 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
147
157
|
const proposalId = attestation.archive.toString();
|
|
148
158
|
const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
|
|
149
159
|
if (proposalAttestationMap) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
const sender = attestation.getSender();
|
|
161
|
+
|
|
162
|
+
// Skip attestations with invalid signatures
|
|
163
|
+
if (!sender) {
|
|
164
|
+
this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber.toBigInt()}`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
proposalAttestationMap.delete(sender.toString());
|
|
169
|
+
this.log.debug(`Deleted attestation for slot ${slotNumber} from ${sender}`);
|
|
153
170
|
}
|
|
154
171
|
}
|
|
155
172
|
}
|
|
156
173
|
return Promise.resolve();
|
|
157
174
|
}
|
|
158
175
|
|
|
176
|
+
public hasAttestation(attestation: BlockAttestation): Promise<boolean> {
|
|
177
|
+
const slotNumber = attestation.payload.header.slotNumber;
|
|
178
|
+
const proposalId = attestation.archive.toString();
|
|
179
|
+
const sender = attestation.getSender();
|
|
180
|
+
|
|
181
|
+
// Attestations with invalid signatures are never in the pool
|
|
182
|
+
if (!sender) {
|
|
183
|
+
return Promise.resolve(false);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const slotAttestationMap = this.attestations.get(slotNumber.toBigInt());
|
|
187
|
+
if (!slotAttestationMap) {
|
|
188
|
+
return Promise.resolve(false);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const proposalAttestationMap = slotAttestationMap.get(proposalId);
|
|
192
|
+
if (!proposalAttestationMap) {
|
|
193
|
+
return Promise.resolve(false);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return Promise.resolve(proposalAttestationMap.has(sender.toString()));
|
|
197
|
+
}
|
|
198
|
+
|
|
159
199
|
public addBlockProposal(blockProposal: BlockProposal): Promise<void> {
|
|
160
200
|
// We initialize slot-proposal mapping if it does not exist
|
|
161
201
|
// This is important to ensure we can delete this proposal if there were not attestations for it
|
|
@@ -169,6 +209,11 @@ export class InMemoryAttestationPool implements AttestationPool {
|
|
|
169
209
|
public getBlockProposal(id: string): Promise<BlockProposal | undefined> {
|
|
170
210
|
return Promise.resolve(this.proposals.get(id));
|
|
171
211
|
}
|
|
212
|
+
|
|
213
|
+
public hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
|
|
214
|
+
const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.payload.archive.toString();
|
|
215
|
+
return Promise.resolve(this.proposals.has(id));
|
|
216
|
+
}
|
|
172
217
|
}
|
|
173
218
|
|
|
174
219
|
/**
|
|
@@ -35,8 +35,11 @@ export const mockAttestation = (
|
|
|
35
35
|
const header = makeHeader(1, 2, slot);
|
|
36
36
|
const payload = new ConsensusPayload(header.toPropose(), archive, header.state);
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
38
|
+
const attestationHash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
|
|
39
|
+
const attestationSignature = signer.sign(attestationHash);
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const proposalHash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockProposal);
|
|
42
|
+
const proposerSignature = signer.sign(proposalHash);
|
|
43
|
+
|
|
44
|
+
return new BlockAttestation(payload, attestationSignature, proposerSignature);
|
|
42
45
|
};
|
|
@@ -273,6 +273,11 @@ export class AztecKVTxPool extends (EventEmitter as new () => TypedEventEmitter<
|
|
|
273
273
|
return await Promise.all(txHashes.map(txHash => this.#txs.hasAsync(txHash.toString())));
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
async hasTx(txHash: TxHash): Promise<boolean> {
|
|
277
|
+
const result = await this.hasTxs([txHash]);
|
|
278
|
+
return result[0];
|
|
279
|
+
}
|
|
280
|
+
|
|
276
281
|
/**
|
|
277
282
|
* Checks if an archived tx exists and returns it.
|
|
278
283
|
* @param txHash - The tx hash.
|
|
@@ -151,6 +151,11 @@ export class InMemoryTxPool extends (EventEmitter as new () => TypedEventEmitter
|
|
|
151
151
|
return Promise.resolve(txHashes.map(txHash => this.txs.has(txHash.toBigInt())));
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
async hasTx(txHash: TxHash): Promise<boolean> {
|
|
155
|
+
const result = await this.hasTxs([txHash]);
|
|
156
|
+
return result[0];
|
|
157
|
+
}
|
|
158
|
+
|
|
154
159
|
public getArchivedTxByHash(): Promise<Tx | undefined> {
|
|
155
160
|
return Promise.resolve(undefined);
|
|
156
161
|
}
|
|
@@ -43,6 +43,13 @@ export interface TxPool extends TypedEventEmitter<TxPoolEvents> {
|
|
|
43
43
|
*/
|
|
44
44
|
hasTxs(txHashes: TxHash[]): Promise<boolean[]>;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Checks if a transaction exists in the pool
|
|
48
|
+
* @param txHash - The hash of the transaction to check for
|
|
49
|
+
* @returns True if the transaction exists, false otherwise
|
|
50
|
+
*/
|
|
51
|
+
hasTx(txHash: TxHash): Promise<boolean>;
|
|
52
|
+
|
|
46
53
|
/**
|
|
47
54
|
* Checks if an archived transaction exists in the pool and returns it.
|
|
48
55
|
* @param txHash - The hash of the transaction, used as an ID.
|