@aztec/p2p 0.86.0 → 0.87.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.
- package/dest/bootstrap/bootstrap.d.ts.map +1 -1
- package/dest/client/factory.d.ts +4 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +16 -14
- package/dest/client/index.d.ts +1 -0
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +1 -0
- package/dest/client/interface.d.ts +155 -0
- package/dest/client/interface.d.ts.map +1 -0
- package/dest/client/interface.js +9 -0
- package/dest/client/p2p_client.d.ts +26 -164
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +185 -114
- package/dest/config.d.ts +5 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -11
- package/dest/enr/generate-enr.d.ts +9 -1
- package/dest/enr/generate-enr.d.ts.map +1 -1
- package/dest/enr/generate-enr.js +24 -2
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +2 -0
- package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +4 -4
- package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -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 +8 -2
- package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -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 +5 -2
- package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/mem_pools/attestation_pool/mocks.js +2 -2
- package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +4 -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 +50 -14
- package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +3 -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 +9 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts +9 -0
- package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
- package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +13 -5
- package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
- package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +1 -1
- package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
- package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/data_validator.js +15 -14
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +0 -2
- package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/double_spend_validator.js +2 -2
- package/dest/msg_validators/tx_validator/factory.d.ts +14 -0
- package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -0
- package/dest/msg_validators/tx_validator/factory.js +62 -0
- package/dest/msg_validators/tx_validator/gas_validator.js +3 -3
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts +8 -4
- package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/metadata_validator.js +35 -17
- package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
- package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
- package/dest/msg_validators/tx_validator/tx_proof_validator.js +1 -1
- 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 +9 -13
- package/dest/services/dummy_service.d.ts +3 -3
- package/dest/services/dummy_service.d.ts.map +1 -1
- package/dest/services/dummy_service.js +6 -1
- package/dest/services/encoding.d.ts +1 -3
- package/dest/services/encoding.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.d.ts +4 -2
- package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
- package/dest/services/libp2p/libp2p_service.js +94 -88
- package/dest/services/peer-manager/metrics.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts +1 -1
- package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
- package/dest/services/peer-manager/peer_manager.js +11 -2
- package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -2
- package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
- package/dest/services/reqresp/connection-sampler/connection_sampler.js +41 -21
- package/dest/services/reqresp/interface.d.ts +1 -3
- package/dest/services/reqresp/interface.d.ts.map +1 -1
- package/dest/services/reqresp/metrics.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.d.ts +0 -2
- package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/goodbye.js +1 -1
- package/dest/services/reqresp/protocols/ping.d.ts +0 -2
- package/dest/services/reqresp/protocols/ping.d.ts.map +1 -1
- package/dest/services/reqresp/protocols/status.d.ts +0 -2
- package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
- package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.d.ts +1 -3
- package/dest/services/reqresp/reqresp.d.ts.map +1 -1
- package/dest/services/reqresp/reqresp.js +13 -10
- package/dest/services/service.d.ts +4 -3
- package/dest/services/service.d.ts.map +1 -1
- package/dest/test-helpers/get-ports.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
- package/dest/test-helpers/make-test-p2p-clients.js +2 -2
- package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
- package/dest/test-helpers/reqresp-nodes.js +1 -1
- package/dest/testbench/p2p_client_testbench_worker.js +11 -6
- package/dest/testbench/testbench.js +1 -1
- package/dest/testbench/worker_client_manager.d.ts +0 -1
- package/dest/testbench/worker_client_manager.d.ts.map +1 -1
- package/dest/testbench/worker_client_manager.js +2 -2
- package/dest/types/index.d.ts +1 -0
- package/dest/types/index.d.ts.map +1 -1
- package/dest/types/index.js +1 -0
- package/dest/versioning.d.ts +2 -2
- package/dest/versioning.d.ts.map +1 -1
- package/dest/versioning.js +6 -1
- package/package.json +15 -15
- package/src/bootstrap/bootstrap.ts +1 -1
- package/src/client/factory.ts +38 -33
- package/src/client/index.ts +1 -0
- package/src/client/interface.ts +186 -0
- package/src/client/p2p_client.ts +226 -287
- package/src/config.ts +11 -18
- package/src/enr/generate-enr.ts +35 -3
- package/src/index.ts +1 -0
- package/src/mem_pools/attestation_pool/attestation_pool.ts +3 -0
- package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +4 -4
- package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +11 -4
- package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +10 -3
- package/src/mem_pools/attestation_pool/mocks.ts +2 -2
- package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +79 -34
- package/src/mem_pools/tx_pool/memory_tx_pool.ts +16 -1
- package/src/mem_pools/tx_pool/tx_pool.ts +12 -0
- package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +9 -3
- package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
- package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
- package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
- package/src/msg_validators/tx_validator/data_validator.ts +24 -18
- package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
- package/src/msg_validators/tx_validator/factory.ts +94 -0
- package/src/msg_validators/tx_validator/gas_validator.ts +3 -3
- package/src/msg_validators/tx_validator/metadata_validator.ts +50 -14
- package/src/msg_validators/tx_validator/phases_validator.ts +6 -2
- package/src/msg_validators/tx_validator/tx_proof_validator.ts +1 -1
- package/src/services/discv5/discV5_service.ts +14 -12
- package/src/services/dummy_service.ts +8 -2
- package/src/services/libp2p/libp2p_service.ts +102 -111
- package/src/services/peer-manager/metrics.ts +4 -1
- package/src/services/peer-manager/peer_manager.ts +18 -1
- package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +5 -1
- package/src/services/reqresp/connection-sampler/connection_sampler.ts +42 -19
- package/src/services/reqresp/metrics.ts +4 -1
- package/src/services/reqresp/protocols/goodbye.ts +1 -1
- package/src/services/reqresp/rate-limiter/rate_limiter.ts +4 -1
- package/src/services/reqresp/reqresp.ts +12 -12
- package/src/services/service.ts +7 -1
- package/src/test-helpers/make-test-p2p-clients.ts +2 -1
- package/src/test-helpers/reqresp-nodes.ts +1 -1
- package/src/testbench/p2p_client_testbench_worker.ts +10 -4
- package/src/testbench/testbench.ts +1 -1
- package/src/testbench/worker_client_manager.ts +2 -2
- package/src/types/index.ts +1 -0
- package/src/versioning.ts +8 -1
package/src/client/p2p_client.ts
CHANGED
|
@@ -5,13 +5,14 @@ import type {
|
|
|
5
5
|
L2Block,
|
|
6
6
|
L2BlockId,
|
|
7
7
|
L2BlockSource,
|
|
8
|
+
L2BlockStream,
|
|
8
9
|
L2BlockStreamEvent,
|
|
9
10
|
L2Tips,
|
|
10
11
|
PublishedL2Block,
|
|
11
12
|
} from '@aztec/stdlib/block';
|
|
12
13
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
13
|
-
import type {
|
|
14
|
-
import { BlockAttestation, type BlockProposal,
|
|
14
|
+
import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
|
|
15
|
+
import { BlockAttestation, type BlockProposal, type P2PClientType } from '@aztec/stdlib/p2p';
|
|
15
16
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
16
17
|
import {
|
|
17
18
|
Attributes,
|
|
@@ -30,172 +31,7 @@ import type { MemPools } from '../mem_pools/interface.js';
|
|
|
30
31
|
import type { TxPool } from '../mem_pools/tx_pool/index.js';
|
|
31
32
|
import { ReqRespSubProtocol } from '../services/reqresp/interface.js';
|
|
32
33
|
import type { P2PService } from '../services/service.js';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Enum defining the possible states of the p2p client.
|
|
36
|
-
*/
|
|
37
|
-
export enum P2PClientState {
|
|
38
|
-
IDLE,
|
|
39
|
-
SYNCHING,
|
|
40
|
-
RUNNING,
|
|
41
|
-
STOPPED,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The synchronization status of the P2P client.
|
|
46
|
-
*/
|
|
47
|
-
export interface P2PSyncState {
|
|
48
|
-
/**
|
|
49
|
-
* The current state of the p2p client.
|
|
50
|
-
*/
|
|
51
|
-
state: P2PClientState;
|
|
52
|
-
/**
|
|
53
|
-
* The block number that the p2p client is synced to.
|
|
54
|
-
*/
|
|
55
|
-
syncedToL2Block: L2BlockId;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Interface of a P2P client.
|
|
60
|
-
**/
|
|
61
|
-
export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
|
|
62
|
-
/**
|
|
63
|
-
* Broadcasts a block proposal to other peers.
|
|
64
|
-
*
|
|
65
|
-
* @param proposal - the block proposal
|
|
66
|
-
*/
|
|
67
|
-
broadcastProposal(proposal: BlockProposal): void;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Registers a callback from the validator client that determines how to behave when
|
|
71
|
-
* foreign block proposals are received
|
|
72
|
-
*
|
|
73
|
-
* @param handler - A function taking a received block proposal and producing an attestation
|
|
74
|
-
*/
|
|
75
|
-
// REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
|
|
76
|
-
// ^ This pattern is not my favorite (md)
|
|
77
|
-
registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Request a list of transactions from another peer by their tx hashes.
|
|
81
|
-
* @param txHashes - Hashes of the txs to query.
|
|
82
|
-
* @returns A list of transactions or undefined if the transactions are not found.
|
|
83
|
-
*/
|
|
84
|
-
requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Request a transaction from another peer by its tx hash.
|
|
88
|
-
* @param txHash - Hash of the tx to query.
|
|
89
|
-
*/
|
|
90
|
-
requestTxByHash(txHash: TxHash): Promise<Tx | undefined>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers.
|
|
94
|
-
* @param tx - The transaction.
|
|
95
|
-
**/
|
|
96
|
-
sendTx(tx: Tx): Promise<void>;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Adds transactions to the pool. Does not send to peers or validate the tx.
|
|
100
|
-
* @param txs - The transactions.
|
|
101
|
-
**/
|
|
102
|
-
addTxs(txs: Tx[]): Promise<void>;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Deletes 'txs' from the pool, given hashes.
|
|
106
|
-
* NOT used if we use sendTx as reconcileTxPool will handle this.
|
|
107
|
-
* @param txHashes - Hashes to check.
|
|
108
|
-
**/
|
|
109
|
-
deleteTxs(txHashes: TxHash[]): Promise<void>;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Returns a transaction in the transaction pool by its hash.
|
|
113
|
-
* @param txHash - Hash of tx to return.
|
|
114
|
-
* @returns A single tx or undefined.
|
|
115
|
-
*/
|
|
116
|
-
getTxByHashFromPool(txHash: TxHash): Promise<Tx | undefined>;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Returns transactions in the transaction pool by hash.
|
|
120
|
-
* @param txHashes - Hashes of txs to return.
|
|
121
|
-
* @returns An array of txs or undefined.
|
|
122
|
-
*/
|
|
123
|
-
getTxsByHashFromPool(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Checks if transactions exist in the pool
|
|
127
|
-
* @param txHashes - The hashes of the transactions to check for
|
|
128
|
-
* @returns True or False for each hash
|
|
129
|
-
*/
|
|
130
|
-
hasTxsInPool(txHashes: TxHash[]): Promise<boolean[]>;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Returns a transaction in the transaction pool by its hash, requesting it from the network if it is not found.
|
|
134
|
-
* @param txHash - Hash of tx to return.
|
|
135
|
-
* @returns A single tx or undefined.
|
|
136
|
-
*/
|
|
137
|
-
getTxByHash(txHash: TxHash): Promise<Tx | undefined>;
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Returns transactions in the transaction pool by hash, requesting from the network if not found.
|
|
141
|
-
* @param txHashes - Hashes of tx to return.
|
|
142
|
-
* @returns An array of tx or undefined.
|
|
143
|
-
*/
|
|
144
|
-
getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Returns an archived transaction from the transaction pool by its hash.
|
|
148
|
-
* @param txHash - Hash of tx to return.
|
|
149
|
-
* @returns A single tx or undefined.
|
|
150
|
-
*/
|
|
151
|
-
getArchivedTxByHash(txHash: TxHash): Promise<Tx | undefined>;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Returns whether the given tx hash is flagged as pending or mined.
|
|
155
|
-
* @param txHash - Hash of the tx to query.
|
|
156
|
-
* @returns Pending or mined depending on its status, or undefined if not found.
|
|
157
|
-
*/
|
|
158
|
-
getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | undefined>;
|
|
159
|
-
|
|
160
|
-
/** Returns an iterator over pending txs on the mempool. */
|
|
161
|
-
iteratePendingTxs(): AsyncIterableIterator<Tx>;
|
|
162
|
-
|
|
163
|
-
/** Returns the number of pending txs in the mempool. */
|
|
164
|
-
getPendingTxCount(): Promise<number>;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Starts the p2p client.
|
|
168
|
-
* @returns A promise signalling the completion of the block sync.
|
|
169
|
-
*/
|
|
170
|
-
start(): Promise<void>;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Stops the p2p client.
|
|
174
|
-
* @returns A promise signalling the completion of the stop process.
|
|
175
|
-
*/
|
|
176
|
-
stop(): Promise<void>;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Indicates if the p2p client is ready for transaction submission.
|
|
180
|
-
* @returns A boolean flag indicating readiness.
|
|
181
|
-
*/
|
|
182
|
-
isReady(): boolean;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Returns the current status of the p2p client.
|
|
186
|
-
*/
|
|
187
|
-
getStatus(): Promise<P2PSyncState>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Returns the ENR of this node, if any.
|
|
191
|
-
*/
|
|
192
|
-
getEnr(): ENR | undefined;
|
|
193
|
-
|
|
194
|
-
/** Identifies a p2p client. */
|
|
195
|
-
isP2PClient(): true;
|
|
196
|
-
|
|
197
|
-
updateP2PConfig(config: Partial<P2PConfig>): Promise<void>;
|
|
198
|
-
};
|
|
34
|
+
import { type P2P, P2PClientState, type P2PSyncState } from './interface.js';
|
|
199
35
|
|
|
200
36
|
/**
|
|
201
37
|
* The P2P client implementation.
|
|
@@ -212,69 +48,55 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
212
48
|
private syncResolve?: () => void = undefined;
|
|
213
49
|
private latestBlockNumberAtStart = -1;
|
|
214
50
|
private provenBlockNumberAtStart = -1;
|
|
51
|
+
private finalizedBlockNumberAtStart = -1;
|
|
215
52
|
|
|
216
53
|
private synchedBlockHashes: AztecAsyncMap<number, string>;
|
|
217
54
|
private synchedLatestBlockNumber: AztecAsyncSingleton<number>;
|
|
218
55
|
private synchedProvenBlockNumber: AztecAsyncSingleton<number>;
|
|
56
|
+
private synchedFinalizedBlockNumber: AztecAsyncSingleton<number>;
|
|
219
57
|
private synchedLatestSlot: AztecAsyncSingleton<bigint>;
|
|
220
58
|
|
|
221
59
|
private txPool: TxPool;
|
|
222
60
|
private attestationPool: T extends P2PClientType.Full ? AttestationPool : undefined;
|
|
223
61
|
|
|
224
|
-
/** How many slots to keep attestations for. */
|
|
225
|
-
private keepAttestationsInPoolFor: number;
|
|
226
|
-
/** How many slots to keep proven txs for. */
|
|
227
|
-
private keepProvenTxsFor: number;
|
|
228
|
-
|
|
229
|
-
private blockStream;
|
|
230
|
-
|
|
231
62
|
private config: P2PConfig;
|
|
232
63
|
|
|
64
|
+
private blockStream: L2BlockStream | undefined;
|
|
65
|
+
|
|
233
66
|
/**
|
|
234
67
|
* In-memory P2P client constructor.
|
|
235
68
|
* @param store - The client's instance of the KV store.
|
|
236
69
|
* @param l2BlockSource - P2P client's source for fetching existing blocks.
|
|
237
70
|
* @param txPool - The client's instance of a transaction pool. Defaults to in-memory implementation.
|
|
238
71
|
* @param p2pService - The concrete instance of p2p networking to use.
|
|
239
|
-
* @param keepProvenTxsFor - How many blocks have to pass after a block is proven before its txs are deleted (zero to delete immediately once proven).
|
|
240
72
|
* @param log - A logger.
|
|
241
73
|
*/
|
|
242
74
|
constructor(
|
|
243
75
|
_clientType: T,
|
|
244
|
-
store: AztecAsyncKVStore,
|
|
76
|
+
private store: AztecAsyncKVStore,
|
|
245
77
|
private l2BlockSource: L2BlockSource & ContractDataSource,
|
|
246
78
|
mempools: MemPools<T>,
|
|
247
79
|
private p2pService: P2PService,
|
|
248
80
|
config: Partial<P2PConfig> = {},
|
|
249
|
-
telemetry: TelemetryClient = getTelemetryClient(),
|
|
81
|
+
private telemetry: TelemetryClient = getTelemetryClient(),
|
|
250
82
|
private log = createLogger('p2p'),
|
|
251
83
|
) {
|
|
252
84
|
super(telemetry, 'P2PClient');
|
|
253
85
|
|
|
254
|
-
this.config = {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const { keepProvenTxsInPoolFor, blockCheckIntervalMS, blockRequestBatchSize, keepAttestationsInPoolFor } =
|
|
260
|
-
this.config;
|
|
261
|
-
this.keepProvenTxsFor = keepProvenTxsInPoolFor;
|
|
262
|
-
this.keepAttestationsInPoolFor = keepAttestationsInPoolFor;
|
|
263
|
-
|
|
264
|
-
const tracer = telemetry.getTracer('P2PL2BlockStream');
|
|
265
|
-
const logger = createLogger('p2p:l2-block-stream');
|
|
266
|
-
this.blockStream = new TraceableL2BlockStream(l2BlockSource, this, this, tracer, 'P2PL2BlockStream', logger, {
|
|
267
|
-
batchSize: blockRequestBatchSize,
|
|
268
|
-
pollIntervalMS: blockCheckIntervalMS,
|
|
269
|
-
});
|
|
86
|
+
this.config = { ...getP2PDefaultConfig(), ...config };
|
|
87
|
+
this.txPool = mempools.txPool;
|
|
88
|
+
this.attestationPool = mempools.attestationPool!;
|
|
270
89
|
|
|
90
|
+
// REFACTOR: Try replacing these with an L2TipsStore
|
|
271
91
|
this.synchedBlockHashes = store.openMap('p2p_pool_block_hashes');
|
|
272
92
|
this.synchedLatestBlockNumber = store.openSingleton('p2p_pool_last_l2_block');
|
|
273
93
|
this.synchedProvenBlockNumber = store.openSingleton('p2p_pool_last_proven_l2_block');
|
|
94
|
+
this.synchedFinalizedBlockNumber = store.openSingleton('p2p_pool_last_finalized_l2_block');
|
|
274
95
|
this.synchedLatestSlot = store.openSingleton('p2p_pool_last_l2_slot');
|
|
96
|
+
}
|
|
275
97
|
|
|
276
|
-
|
|
277
|
-
this.
|
|
98
|
+
public clear(): Promise<void> {
|
|
99
|
+
return this.store.clear();
|
|
278
100
|
}
|
|
279
101
|
|
|
280
102
|
public isP2PClient(): true {
|
|
@@ -299,30 +121,39 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
299
121
|
public async getL2Tips(): Promise<L2Tips> {
|
|
300
122
|
const latestBlockNumber = await this.getSyncedLatestBlockNum();
|
|
301
123
|
let latestBlockHash: string | undefined;
|
|
124
|
+
|
|
302
125
|
const provenBlockNumber = await this.getSyncedProvenBlockNum();
|
|
303
126
|
let provenBlockHash: string | undefined;
|
|
304
127
|
|
|
128
|
+
const finalizedBlockNumber = await this.getSyncedFinalizedBlockNum();
|
|
129
|
+
let finalizedBlockHash: string | undefined;
|
|
130
|
+
|
|
305
131
|
if (latestBlockNumber > 0) {
|
|
306
132
|
latestBlockHash = await this.synchedBlockHashes.getAsync(latestBlockNumber);
|
|
307
133
|
if (typeof latestBlockHash === 'undefined') {
|
|
308
|
-
|
|
309
|
-
throw new Error();
|
|
134
|
+
throw new Error(`Block hash for latest block ${latestBlockNumber} not found in p2p client`);
|
|
310
135
|
}
|
|
311
136
|
}
|
|
312
137
|
|
|
313
138
|
if (provenBlockNumber > 0) {
|
|
314
139
|
provenBlockHash = await this.synchedBlockHashes.getAsync(provenBlockNumber);
|
|
315
140
|
if (typeof provenBlockHash === 'undefined') {
|
|
316
|
-
|
|
317
|
-
|
|
141
|
+
throw new Error(`Block hash for proven block ${provenBlockNumber} not found in p2p client`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (finalizedBlockNumber > 0) {
|
|
146
|
+
finalizedBlockHash = await this.synchedBlockHashes.getAsync(finalizedBlockNumber);
|
|
147
|
+
if (typeof finalizedBlockHash === 'undefined') {
|
|
148
|
+
throw new Error(`Block hash for finalized block ${finalizedBlockNumber} not found in p2p client`);
|
|
318
149
|
}
|
|
319
150
|
}
|
|
320
151
|
|
|
321
|
-
return
|
|
152
|
+
return {
|
|
322
153
|
latest: { hash: latestBlockHash!, number: latestBlockNumber },
|
|
323
154
|
proven: { hash: provenBlockHash!, number: provenBlockNumber },
|
|
324
|
-
finalized: { hash:
|
|
325
|
-
}
|
|
155
|
+
finalized: { hash: finalizedBlockHash!, number: finalizedBlockNumber },
|
|
156
|
+
};
|
|
326
157
|
}
|
|
327
158
|
|
|
328
159
|
public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
|
|
@@ -331,16 +162,23 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
331
162
|
case 'blocks-added':
|
|
332
163
|
await this.handleLatestL2Blocks(event.blocks);
|
|
333
164
|
break;
|
|
334
|
-
case 'chain-finalized':
|
|
165
|
+
case 'chain-finalized': {
|
|
335
166
|
// TODO (alexg): I think we can prune the block hashes map here
|
|
167
|
+
await this.setBlockHash(event.block);
|
|
168
|
+
const from = (await this.getSyncedFinalizedBlockNum()) + 1;
|
|
169
|
+
const limit = event.block.number - from + 1;
|
|
170
|
+
if (limit > 0) {
|
|
171
|
+
await this.handleFinalizedL2Blocks(await this.l2BlockSource.getBlocks(from, limit));
|
|
172
|
+
}
|
|
336
173
|
break;
|
|
174
|
+
}
|
|
337
175
|
case 'chain-proven': {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
await this.handleProvenL2Blocks(await this.l2BlockSource.getBlocks(from, limit));
|
|
176
|
+
await this.setBlockHash(event.block);
|
|
177
|
+
await this.synchedProvenBlockNumber.set(event.block.number);
|
|
341
178
|
break;
|
|
342
179
|
}
|
|
343
180
|
case 'chain-pruned':
|
|
181
|
+
await this.setBlockHash(event.block);
|
|
344
182
|
await this.handlePruneL2Blocks(event.block.number);
|
|
345
183
|
break;
|
|
346
184
|
default: {
|
|
@@ -350,6 +188,12 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
350
188
|
}
|
|
351
189
|
}
|
|
352
190
|
|
|
191
|
+
private async setBlockHash(block: L2BlockId): Promise<void> {
|
|
192
|
+
if (block.hash !== undefined) {
|
|
193
|
+
await this.synchedBlockHashes.set(block.number, block.hash.toString());
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
353
197
|
#assertIsReady() {
|
|
354
198
|
// this.log.info('Checking if p2p client is ready, current state: ', this.currentState);
|
|
355
199
|
if (!this.isReady()) {
|
|
@@ -370,33 +214,74 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
370
214
|
}
|
|
371
215
|
|
|
372
216
|
// get the current latest block numbers
|
|
373
|
-
|
|
374
|
-
this.
|
|
217
|
+
const latestBlockNumbers = await this.l2BlockSource.getL2Tips();
|
|
218
|
+
this.latestBlockNumberAtStart = latestBlockNumbers.latest.number;
|
|
219
|
+
this.provenBlockNumberAtStart = latestBlockNumbers.proven.number;
|
|
220
|
+
this.finalizedBlockNumberAtStart = latestBlockNumbers.finalized.number;
|
|
375
221
|
|
|
376
222
|
const syncedLatestBlock = (await this.getSyncedLatestBlockNum()) + 1;
|
|
377
223
|
const syncedProvenBlock = (await this.getSyncedProvenBlockNum()) + 1;
|
|
224
|
+
const syncedFinalizedBlock = (await this.getSyncedFinalizedBlockNum()) + 1;
|
|
378
225
|
|
|
379
|
-
|
|
380
|
-
|
|
226
|
+
if (
|
|
227
|
+
(await this.txPool.isEmpty()) &&
|
|
228
|
+
(this.attestationPool === undefined || (await this.attestationPool?.isEmpty()))
|
|
229
|
+
) {
|
|
230
|
+
// if mempools are empty, we don't care about syncing prior blocks
|
|
231
|
+
this.initBlockStream(this.latestBlockNumberAtStart);
|
|
232
|
+
this.setCurrentState(P2PClientState.RUNNING);
|
|
233
|
+
this.syncPromise = Promise.resolve();
|
|
234
|
+
await this.p2pService.start();
|
|
235
|
+
this.log.info(`Starting p2p client from block ${this.latestBlockNumberAtStart} with empty mempools`);
|
|
236
|
+
} else if (
|
|
237
|
+
syncedLatestBlock <= this.latestBlockNumberAtStart ||
|
|
238
|
+
syncedProvenBlock <= this.provenBlockNumberAtStart ||
|
|
239
|
+
syncedFinalizedBlock <= this.finalizedBlockNumberAtStart
|
|
240
|
+
) {
|
|
241
|
+
// if there are blocks to be retrieved, go to a synching state
|
|
242
|
+
// this gets resolved on `startServiceIfSynched`
|
|
243
|
+
this.initBlockStream();
|
|
381
244
|
this.setCurrentState(P2PClientState.SYNCHING);
|
|
382
245
|
this.syncPromise = new Promise(resolve => {
|
|
383
246
|
this.syncResolve = resolve;
|
|
384
247
|
});
|
|
385
|
-
this.log.
|
|
248
|
+
this.log.info(`Initiating p2p sync from ${syncedLatestBlock}`, {
|
|
249
|
+
syncedLatestBlock,
|
|
250
|
+
syncedProvenBlock,
|
|
251
|
+
syncedFinalizedBlock,
|
|
252
|
+
});
|
|
386
253
|
} else {
|
|
387
254
|
// if no blocks to be retrieved, go straight to running
|
|
255
|
+
this.initBlockStream();
|
|
388
256
|
this.setCurrentState(P2PClientState.RUNNING);
|
|
389
257
|
this.syncPromise = Promise.resolve();
|
|
390
258
|
await this.p2pService.start();
|
|
391
|
-
this.log.
|
|
259
|
+
this.log.info(`Starting P2P client synced to ${syncedLatestBlock}`, {
|
|
260
|
+
syncedLatestBlock,
|
|
261
|
+
syncedProvenBlock,
|
|
262
|
+
syncedFinalizedBlock,
|
|
263
|
+
});
|
|
392
264
|
}
|
|
393
265
|
|
|
394
|
-
this.blockStream
|
|
395
|
-
this.log.verbose(`Started block downloader from block ${syncedLatestBlock}`);
|
|
396
|
-
|
|
266
|
+
this.blockStream!.start();
|
|
397
267
|
return this.syncPromise;
|
|
398
268
|
}
|
|
399
269
|
|
|
270
|
+
private initBlockStream(startingBlock?: number) {
|
|
271
|
+
if (!this.blockStream) {
|
|
272
|
+
const { blockRequestBatchSize: batchSize, blockCheckIntervalMS: pollIntervalMS } = this.config;
|
|
273
|
+
this.blockStream = new TraceableL2BlockStream(
|
|
274
|
+
this.l2BlockSource,
|
|
275
|
+
this,
|
|
276
|
+
this,
|
|
277
|
+
this.telemetry.getTracer('P2PL2BlockStream'),
|
|
278
|
+
'P2PL2BlockStream',
|
|
279
|
+
createLogger('p2p:l2-block-stream'),
|
|
280
|
+
{ batchSize, pollIntervalMS, startingBlock },
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
400
285
|
/**
|
|
401
286
|
* Allows consumers to stop the instance of the P2P client.
|
|
402
287
|
* 'ready' will now return 'false' and the running promise that keeps the client synced is interrupted.
|
|
@@ -405,7 +290,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
405
290
|
this.log.debug('Stopping p2p client...');
|
|
406
291
|
await this.p2pService.stop();
|
|
407
292
|
this.log.debug('Stopped p2p service');
|
|
408
|
-
await this.blockStream
|
|
293
|
+
await this.blockStream?.stop();
|
|
409
294
|
this.log.debug('Stopped block downloader');
|
|
410
295
|
await this.runningPromise;
|
|
411
296
|
this.setCurrentState(P2PClientState.STOPPED);
|
|
@@ -414,7 +299,8 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
414
299
|
|
|
415
300
|
/** Triggers a sync to the archiver. Used for testing. */
|
|
416
301
|
public async sync() {
|
|
417
|
-
|
|
302
|
+
this.initBlockStream();
|
|
303
|
+
await this.blockStream!.sync();
|
|
418
304
|
}
|
|
419
305
|
|
|
420
306
|
@trackSpan('p2pClient.broadcastProposal', async proposal => ({
|
|
@@ -423,7 +309,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
423
309
|
[Attributes.BLOCK_ARCHIVE]: proposal.archive.toString(),
|
|
424
310
|
[Attributes.P2P_ID]: (await proposal.p2pMessageIdentifier()).toString(),
|
|
425
311
|
}))
|
|
426
|
-
public broadcastProposal(proposal: BlockProposal): void {
|
|
312
|
+
public broadcastProposal(proposal: BlockProposal): Promise<void> {
|
|
427
313
|
this.log.verbose(`Broadcasting proposal for slot ${proposal.slotNumber.toNumber()} to peers`);
|
|
428
314
|
return this.p2pService.propagate(proposal);
|
|
429
315
|
}
|
|
@@ -446,20 +332,6 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
446
332
|
this.p2pService.registerBlockReceivedCallback(handler);
|
|
447
333
|
}
|
|
448
334
|
|
|
449
|
-
/**
|
|
450
|
-
* Requests the transactions with the given hashes from the network.
|
|
451
|
-
*
|
|
452
|
-
* If a transaction can be retrieved, it will be returned, if not an undefined
|
|
453
|
-
* will be returned. In place.
|
|
454
|
-
*
|
|
455
|
-
* @param txHashes - The hashes of the transactions to request.
|
|
456
|
-
* @returns A promise that resolves to an array of transactions or undefined.
|
|
457
|
-
*/
|
|
458
|
-
public async requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
|
|
459
|
-
const res = await this.p2pService.sendBatchRequest(ReqRespSubProtocol.TX, txHashes);
|
|
460
|
-
return Promise.resolve(res ?? []);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
335
|
/**
|
|
464
336
|
* Uses the Request Response protocol to request a transaction from the network.
|
|
465
337
|
*
|
|
@@ -486,25 +358,36 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
486
358
|
* Uses the batched Request Response protocol to request a set of transactions from the network.
|
|
487
359
|
*/
|
|
488
360
|
public async requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
|
|
489
|
-
const
|
|
361
|
+
const timeoutMs = 8000; // Longer timeout for now
|
|
362
|
+
const maxPeers = Math.min(Math.ceil(txHashes.length / 3), 10);
|
|
363
|
+
const maxRetryAttempts = 10; // Keep retrying within the timeout
|
|
364
|
+
|
|
365
|
+
const txs = await this.p2pService.sendBatchRequest(
|
|
366
|
+
ReqRespSubProtocol.TX,
|
|
367
|
+
txHashes,
|
|
368
|
+
timeoutMs,
|
|
369
|
+
maxPeers,
|
|
370
|
+
maxRetryAttempts,
|
|
371
|
+
);
|
|
490
372
|
|
|
491
373
|
// Some transactions may return undefined, so we filter them out
|
|
492
374
|
const filteredTxs = txs.filter((tx): tx is Tx => !!tx);
|
|
493
|
-
|
|
375
|
+
if (filteredTxs.length > 0) {
|
|
376
|
+
await this.txPool.addTxs(filteredTxs);
|
|
377
|
+
}
|
|
494
378
|
const txHashesStr = txHashes.map(tx => tx.toString()).join(', ');
|
|
495
|
-
this.log.debug(`
|
|
379
|
+
this.log.debug(`Requested txs ${txHashesStr} (${filteredTxs.length} / ${txHashes.length}}) from peers`);
|
|
496
380
|
|
|
497
381
|
// We return all transactions, even the not found ones to the caller, such they can handle missing items themselves.
|
|
498
382
|
return txs;
|
|
499
383
|
}
|
|
500
384
|
|
|
501
385
|
public getPendingTxs(): Promise<Tx[]> {
|
|
502
|
-
return
|
|
386
|
+
return this.getTxs('pending');
|
|
503
387
|
}
|
|
504
388
|
|
|
505
|
-
public
|
|
506
|
-
|
|
507
|
-
return pendingTxs.length;
|
|
389
|
+
public getPendingTxCount(): Promise<number> {
|
|
390
|
+
return this.txPool.getPendingTxCount();
|
|
508
391
|
}
|
|
509
392
|
|
|
510
393
|
public async *iteratePendingTxs(): AsyncIterableIterator<Tx> {
|
|
@@ -577,9 +460,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
577
460
|
* Returns transactions in the transaction pool by hash.
|
|
578
461
|
* If a transaction is not in the pool, it will be requested from the network.
|
|
579
462
|
* @param txHashes - Hashes of the transactions to look for.
|
|
580
|
-
* @returns The txs found, not
|
|
463
|
+
* @returns The txs found, or undefined if not found in the order requested.
|
|
581
464
|
*/
|
|
582
|
-
async getTxsByHash(txHashes: TxHash[]): Promise<Tx[]> {
|
|
465
|
+
async getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
|
|
583
466
|
const txs = await Promise.all(txHashes.map(txHash => this.txPool.getTxByHash(txHash)));
|
|
584
467
|
const missingTxHashes = txs
|
|
585
468
|
.map((tx, index) => [tx, index] as const)
|
|
@@ -592,7 +475,29 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
592
475
|
|
|
593
476
|
const missingTxs = await this.requestTxsByHash(missingTxHashes);
|
|
594
477
|
const fetchedMissingTxs = missingTxs.filter((tx): tx is Tx => !!tx);
|
|
595
|
-
|
|
478
|
+
|
|
479
|
+
// TODO: optimize
|
|
480
|
+
// Merge the found txs in order
|
|
481
|
+
const mergingTxsPromises = txHashes.map(async txHash => {
|
|
482
|
+
// Is it in the txs list from the mempool?
|
|
483
|
+
for (const tx of txs) {
|
|
484
|
+
if (tx !== undefined && (await tx.getTxHash()).equals(txHash)) {
|
|
485
|
+
return tx;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Is it in the fetched missing txs?
|
|
490
|
+
for (const tx of fetchedMissingTxs) {
|
|
491
|
+
if (tx !== undefined && (await tx.getTxHash()).equals(txHash)) {
|
|
492
|
+
return tx;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Otherwise return undefined
|
|
497
|
+
return undefined;
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
return await Promise.all(mergingTxsPromises);
|
|
596
501
|
}
|
|
597
502
|
|
|
598
503
|
/**
|
|
@@ -611,7 +516,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
611
516
|
**/
|
|
612
517
|
public async sendTx(tx: Tx): Promise<void> {
|
|
613
518
|
await this.addTxs([tx]);
|
|
614
|
-
this.p2pService.propagate(tx);
|
|
519
|
+
await this.p2pService.propagate(tx);
|
|
615
520
|
}
|
|
616
521
|
|
|
617
522
|
/**
|
|
@@ -675,6 +580,10 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
675
580
|
return (await this.synchedProvenBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
|
|
676
581
|
}
|
|
677
582
|
|
|
583
|
+
public async getSyncedFinalizedBlockNum(): Promise<number> {
|
|
584
|
+
return (await this.synchedFinalizedBlockNumber.getAsync()) ?? INITIAL_L2_BLOCK_NUM - 1;
|
|
585
|
+
}
|
|
586
|
+
|
|
678
587
|
/** Returns latest L2 slot for which we have seen an L2 block. */
|
|
679
588
|
public async getSyncedLatestSlot(): Promise<bigint> {
|
|
680
589
|
return (await this.synchedLatestSlot.getAsync()) ?? BigInt(0);
|
|
@@ -712,16 +621,6 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
712
621
|
}
|
|
713
622
|
}
|
|
714
623
|
|
|
715
|
-
private async addAttestationsToPool(blocks: PublishedL2Block[]): Promise<void> {
|
|
716
|
-
const attestations = blocks.flatMap(block => {
|
|
717
|
-
const payload = ConsensusPayload.fromBlock(block.block);
|
|
718
|
-
return block.signatures.filter(sig => !sig.isEmpty).map(signature => new BlockAttestation(payload, signature));
|
|
719
|
-
});
|
|
720
|
-
await this.attestationPool?.addAttestations(attestations);
|
|
721
|
-
const slots = blocks.map(b => b.block.header.getSlot()).sort((a, b) => Number(a - b));
|
|
722
|
-
this.log.debug(`Added ${attestations.length} attestations for slots ${slots[0]}-${slots.at(-1)} to the pool`);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
624
|
/**
|
|
726
625
|
* Deletes txs from these blocks.
|
|
727
626
|
* @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with.
|
|
@@ -746,50 +645,67 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
746
645
|
}
|
|
747
646
|
|
|
748
647
|
await this.markTxsAsMinedFromBlocks(blocks.map(b => b.block));
|
|
749
|
-
|
|
648
|
+
void this.requestMissingTxsFromUnprovenBlocks(blocks.map(b => b.block));
|
|
649
|
+
|
|
750
650
|
const lastBlock = blocks.at(-1)!.block;
|
|
651
|
+
|
|
751
652
|
await Promise.all(
|
|
752
|
-
blocks.map(async block =>
|
|
653
|
+
blocks.map(async block =>
|
|
654
|
+
this.setBlockHash({
|
|
655
|
+
number: block.block.number,
|
|
656
|
+
hash: await block.block.hash().then(h => h.toString()),
|
|
657
|
+
}),
|
|
658
|
+
),
|
|
753
659
|
);
|
|
660
|
+
|
|
754
661
|
await this.synchedLatestBlockNumber.set(lastBlock.number);
|
|
755
662
|
await this.synchedLatestSlot.set(lastBlock.header.getSlot());
|
|
756
663
|
this.log.verbose(`Synched to latest block ${lastBlock.number}`);
|
|
757
664
|
await this.startServiceIfSynched();
|
|
758
665
|
}
|
|
759
666
|
|
|
667
|
+
/** Request txs for unproven blocks so the prover node has more chances to get them. */
|
|
668
|
+
private async requestMissingTxsFromUnprovenBlocks(blocks: L2Block[]): Promise<void> {
|
|
669
|
+
try {
|
|
670
|
+
const provenBlockNumber = Math.max(await this.getSyncedProvenBlockNum(), this.provenBlockNumberAtStart);
|
|
671
|
+
const unprovenBlocks = blocks.filter(block => block.number > provenBlockNumber);
|
|
672
|
+
const txHashes = unprovenBlocks.flatMap(block => block.body.txEffects.map(txEffect => txEffect.txHash));
|
|
673
|
+
const missingTxHashes = await this.txPool
|
|
674
|
+
.hasTxs(txHashes)
|
|
675
|
+
.then(availability => txHashes.filter((_, index) => !availability[index]));
|
|
676
|
+
if (missingTxHashes.length > 0) {
|
|
677
|
+
this.log.verbose(
|
|
678
|
+
`Requesting ${missingTxHashes.length} missing txs from peers for ${unprovenBlocks.length} unproven mined blocks`,
|
|
679
|
+
{ missingTxHashes, unprovenBlockNumbers: unprovenBlocks.map(block => block.number) },
|
|
680
|
+
);
|
|
681
|
+
await this.requestTxsByHash(missingTxHashes);
|
|
682
|
+
}
|
|
683
|
+
} catch (err) {
|
|
684
|
+
this.log.error(`Error requesting missing txs from unproven blocks`, err, {
|
|
685
|
+
blocks: blocks.map(block => block.number),
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
760
690
|
/**
|
|
761
|
-
* Handles new
|
|
762
|
-
* @param blocks - A list of
|
|
691
|
+
* Handles new finalized blocks by deleting the txs and attestations in them.
|
|
692
|
+
* @param blocks - A list of finalized L2 blocks.
|
|
763
693
|
* @returns Empty promise.
|
|
764
694
|
*/
|
|
765
|
-
private async
|
|
695
|
+
private async handleFinalizedL2Blocks(blocks: L2Block[]): Promise<void> {
|
|
696
|
+
this.log.trace(`Handling finalized blocks ${blocks.length} up to ${blocks.at(-1)?.number}`);
|
|
766
697
|
if (!blocks.length) {
|
|
767
698
|
return Promise.resolve();
|
|
768
699
|
}
|
|
769
700
|
|
|
770
|
-
const firstBlockNum = blocks[0].number;
|
|
771
701
|
const lastBlockNum = blocks[blocks.length - 1].number;
|
|
772
|
-
const lastBlockSlot = blocks[blocks.length - 1].header.
|
|
773
|
-
|
|
774
|
-
// If keepProvenTxsFor is 0, we delete all txs from all proven blocks.
|
|
775
|
-
if (this.keepProvenTxsFor === 0) {
|
|
776
|
-
await this.deleteTxsFromBlocks(blocks);
|
|
777
|
-
} else if (lastBlockNum - this.keepProvenTxsFor >= INITIAL_L2_BLOCK_NUM) {
|
|
778
|
-
const fromBlock = Math.max(INITIAL_L2_BLOCK_NUM, firstBlockNum - this.keepProvenTxsFor);
|
|
779
|
-
const toBlock = lastBlockNum - this.keepProvenTxsFor;
|
|
780
|
-
const limit = toBlock - fromBlock + 1;
|
|
781
|
-
const blocksToDeleteTxsFrom = await this.l2BlockSource.getBlocks(fromBlock, limit, true);
|
|
782
|
-
await this.deleteTxsFromBlocks(blocksToDeleteTxsFrom);
|
|
783
|
-
}
|
|
702
|
+
const lastBlockSlot = blocks[blocks.length - 1].header.getSlot();
|
|
784
703
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
if (lastBlockSlotMinusKeepAttestationsInPoolFor >= BigInt(INITIAL_L2_BLOCK_NUM)) {
|
|
788
|
-
await this.attestationPool?.deleteAttestationsOlderThan(lastBlockSlotMinusKeepAttestationsInPoolFor);
|
|
789
|
-
}
|
|
704
|
+
await this.deleteTxsFromBlocks(blocks);
|
|
705
|
+
await this.attestationPool?.deleteAttestationsOlderThan(lastBlockSlot);
|
|
790
706
|
|
|
791
|
-
await this.
|
|
792
|
-
this.log.debug(`Synched to
|
|
707
|
+
await this.synchedFinalizedBlockNumber.set(lastBlockNum);
|
|
708
|
+
this.log.debug(`Synched to finalized block ${lastBlockNum}`);
|
|
793
709
|
|
|
794
710
|
await this.startServiceIfSynched();
|
|
795
711
|
}
|
|
@@ -801,11 +717,11 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
801
717
|
private async handlePruneL2Blocks(latestBlock: number): Promise<void> {
|
|
802
718
|
// NOTE: temporary fix for alphanet, deleting ALL txs that were in the epoch from the pool #13723
|
|
803
719
|
// TODO: undo once fixed: #13770
|
|
804
|
-
const txsToDelete = new
|
|
720
|
+
const txsToDelete = new Map<string, TxHash>();
|
|
805
721
|
const minedTxs = await this.txPool.getMinedTxHashes();
|
|
806
722
|
for (const [txHash, blockNumber] of minedTxs) {
|
|
807
723
|
if (blockNumber > latestBlock) {
|
|
808
|
-
txsToDelete.
|
|
724
|
+
txsToDelete.set(txHash.toString(), txHash);
|
|
809
725
|
}
|
|
810
726
|
}
|
|
811
727
|
|
|
@@ -814,7 +730,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
814
730
|
// every tx that's been generated against a block that has now been pruned is no longer valid
|
|
815
731
|
if (tx.data.constants.historicalHeader.globalVariables.blockNumber.toNumber() > latestBlock) {
|
|
816
732
|
const txHash = await tx.getTxHash();
|
|
817
|
-
txsToDelete.
|
|
733
|
+
txsToDelete.set(txHash.toString(), txHash);
|
|
818
734
|
}
|
|
819
735
|
}
|
|
820
736
|
|
|
@@ -825,7 +741,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
825
741
|
);
|
|
826
742
|
|
|
827
743
|
// delete invalid txs (both pending and mined)
|
|
828
|
-
await this.txPool.deleteTxs(Array.from(txsToDelete));
|
|
744
|
+
await this.txPool.deleteTxs(Array.from(txsToDelete.values()));
|
|
829
745
|
|
|
830
746
|
// everything left in the mined set was built against a block on the proven chain so its still valid
|
|
831
747
|
// move back to pending the txs that were reorged out of the chain
|
|
@@ -849,12 +765,23 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
849
765
|
}
|
|
850
766
|
|
|
851
767
|
private async startServiceIfSynched() {
|
|
768
|
+
if (this.currentState !== P2PClientState.SYNCHING) {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const syncedFinalizedBlock = await this.getSyncedFinalizedBlockNum();
|
|
772
|
+
const syncedProvenBlock = await this.getSyncedProvenBlockNum();
|
|
773
|
+
const syncedLatestBlock = await this.getSyncedLatestBlockNum();
|
|
774
|
+
|
|
852
775
|
if (
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
776
|
+
syncedLatestBlock >= this.latestBlockNumberAtStart &&
|
|
777
|
+
syncedProvenBlock >= this.provenBlockNumberAtStart &&
|
|
778
|
+
syncedFinalizedBlock >= this.finalizedBlockNumberAtStart
|
|
856
779
|
) {
|
|
857
|
-
this.log.
|
|
780
|
+
this.log.info(`Completed P2P client sync to block ${syncedLatestBlock}. Starting service.`, {
|
|
781
|
+
syncedLatestBlock,
|
|
782
|
+
syncedProvenBlock,
|
|
783
|
+
syncedFinalizedBlock,
|
|
784
|
+
});
|
|
858
785
|
this.setCurrentState(P2PClientState.RUNNING);
|
|
859
786
|
if (this.syncResolve !== undefined) {
|
|
860
787
|
this.syncResolve();
|
|
@@ -872,4 +799,16 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
|
|
|
872
799
|
this.currentState = newState;
|
|
873
800
|
this.log.debug(`Moved from state ${P2PClientState[oldState]} to ${P2PClientState[this.currentState]}`);
|
|
874
801
|
}
|
|
802
|
+
|
|
803
|
+
public validate(txs: Tx[]): Promise<void> {
|
|
804
|
+
return this.p2pService.validate(txs);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Marks transactions as non-evictable in the pool.
|
|
809
|
+
* @param txHashes - Hashes of the transactions to mark as non-evictable.
|
|
810
|
+
*/
|
|
811
|
+
public markTxsAsNonEvictable(txHashes: TxHash[]): Promise<void> {
|
|
812
|
+
return this.txPool.markTxsAsNonEvictable(txHashes);
|
|
813
|
+
}
|
|
875
814
|
}
|