Skip to content

Commit 179f391

Browse files
fab-10claude
andcommitted
Add txpool_content JSON-RPC method (#txpool-content)
Implements the spec-defined `txpool_content` endpoint that returns all pending and queued transactions in the pool, grouped by sender address and nonce. - Add `TxPoolContent` RPC handler and `TransactionPoolContentResult` - Add `getPendingTransactionsBySender()` to `PendingTransactions` interface - Add `getAllBySender()` to `TransactionsLayer` interface - Implement in `LayeredPendingTransactions` and `AbstractPendingTransactionsSorter` - Unit tests: 8 cases covering empty pool, all-pending, all-queued, mixed split, multiple senders, and nonce ordering Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 530f182 commit 179f391

13 files changed

Lines changed: 442 additions & 1 deletion

File tree

ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public enum RpcMethod {
170170
TX_POOL_BESU_PENDING_TRANSACTIONS("txpool_besuPendingTransactions"),
171171
TX_POOL_STATUS("txpool_status"),
172172
TX_POOL_CONTENT_FROM("txpool_contentFrom"),
173+
TX_POOL_CONTENT("txpool_content"),
173174
WEB3_CLIENT_VERSION("web3_clientVersion"),
174175
WEB3_SHA3("web3_sha3"),
175176
PLUGINS_RELOAD_CONFIG("plugins_reloadPluginConfig"),
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright contributors to Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
16+
17+
import org.hyperledger.besu.datatypes.Address;
18+
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
19+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
20+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
21+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
22+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPendingResult;
23+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPoolContentResult;
24+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
25+
import org.hyperledger.besu.ethereum.eth.transactions.SenderPendingTransactionsData;
26+
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
27+
28+
import java.util.HashMap;
29+
import java.util.LinkedHashMap;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.SequencedMap;
33+
import java.util.stream.Collectors;
34+
35+
public class TxPoolContent implements JsonRpcMethod {
36+
37+
private final TransactionPool transactionPool;
38+
39+
public TxPoolContent(final TransactionPool transactionPool) {
40+
this.transactionPool = transactionPool;
41+
}
42+
43+
@Override
44+
public String getName() {
45+
return RpcMethod.TX_POOL_CONTENT.getMethodName();
46+
}
47+
48+
@Override
49+
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
50+
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), content());
51+
}
52+
53+
private TransactionPoolContentResult content() {
54+
final Map<Address, SenderPendingTransactionsData> pendingTransactionsBySender =
55+
transactionPool.getPendingTransactionsBySender();
56+
57+
final Map<String, SequencedMap<String, TransactionPendingResult>> pending = new HashMap<>();
58+
final Map<String, SequencedMap<String, TransactionPendingResult>> queued = new HashMap<>();
59+
60+
pendingTransactionsBySender.forEach(
61+
(sender, pendingTransactionsData) -> {
62+
final List<PendingTransaction> pendingTransactions =
63+
pendingTransactionsData.pendingTransactions();
64+
long expectedNonce = pendingTransactionsData.nonce();
65+
int idx = 0;
66+
while (idx < pendingTransactions.size()
67+
&& expectedNonce == pendingTransactions.get(idx).getNonce()) {
68+
++expectedNonce;
69+
++idx;
70+
}
71+
72+
final SequencedMap<String, TransactionPendingResult> pendingByNonce =
73+
pendingTransactions.subList(0, idx).stream()
74+
.map(PendingTransaction::getTransaction)
75+
.collect(
76+
Collectors.toMap(
77+
tx -> Long.toString(tx.getNonce()),
78+
TransactionPendingResult::new,
79+
(a, b) -> a,
80+
LinkedHashMap::new));
81+
82+
final SequencedMap<String, TransactionPendingResult> queuedByNonce =
83+
pendingTransactions.subList(idx, pendingTransactions.size()).stream()
84+
.map(PendingTransaction::getTransaction)
85+
.collect(
86+
Collectors.toMap(
87+
tx -> Long.toString(tx.getNonce()),
88+
TransactionPendingResult::new,
89+
(a, b) -> a,
90+
LinkedHashMap::new));
91+
92+
if (!pendingByNonce.isEmpty()) {
93+
pending.put(sender.toString(), pendingByNonce);
94+
}
95+
if (!queuedByNonce.isEmpty()) {
96+
queued.put(sender.toString(), queuedByNonce);
97+
}
98+
});
99+
return new TransactionPoolContentResult(pending, queued);
100+
}
101+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright contributors to Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
16+
17+
import java.util.Map;
18+
import java.util.SequencedMap;
19+
20+
import com.fasterxml.jackson.annotation.JsonGetter;
21+
22+
public class TransactionPoolContentResult {
23+
24+
private final Map<String, SequencedMap<String, TransactionPendingResult>> pending;
25+
private final Map<String, SequencedMap<String, TransactionPendingResult>> queued;
26+
27+
public TransactionPoolContentResult(
28+
final Map<String, SequencedMap<String, TransactionPendingResult>> pending,
29+
final Map<String, SequencedMap<String, TransactionPendingResult>> queued) {
30+
this.pending = pending;
31+
this.queued = queued;
32+
}
33+
34+
@JsonGetter(value = "pending")
35+
public Map<String, SequencedMap<String, TransactionPendingResult>> getPending() {
36+
return pending;
37+
}
38+
39+
@JsonGetter(value = "queued")
40+
public Map<String, SequencedMap<String, TransactionPendingResult>> getQueued() {
41+
return queued;
42+
}
43+
}

ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TxPoolJsonRpcMethods.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuPendingTransactions;
2020
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuStatistics;
2121
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuTransactions;
22+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolContent;
2223
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolContentFrom;
2324
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolStatus;
2425
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -45,6 +46,7 @@ protected Map<String, JsonRpcMethod> create() {
4546
new TxPoolBesuPendingTransactions(transactionPool),
4647
new TxPoolBesuStatistics(transactionPool),
4748
new TxPoolStatus(transactionPool),
48-
new TxPoolContentFrom(transactionPool));
49+
new TxPoolContentFrom(transactionPool),
50+
new TxPoolContent(transactionPool));
4951
}
5052
}

0 commit comments

Comments
 (0)