Skip to content

Commit 5ee8b9a

Browse files
committed
Implement txpool_status RPC method
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
1 parent 0f0e7b1 commit 5ee8b9a

File tree

18 files changed

+426
-12
lines changed

18 files changed

+426
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- Plugin API: Allow the registration of multiple PluginTransactionPoolValidatorFactory [#9964](https://github.com/hyperledger/besu/pull/9964)
2727
- Add `-Pcases` case name filtering to JMH benchmark suite [#9982](https://github.com/hyperledger/besu/pull/9982)
2828
- Use JDK SHA-256 provider to leverage hardware SHA-NI instructions instead of BouncyCastle [#9924](https://github.com/hyperledger/besu/pull/9924)
29+
- Implement `txpool_status` RPC method [#10002](https://github.com/hyperledger/besu/pull/10002)
2930

3031
## 26.2.0
3132

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
@@ -174,6 +174,7 @@ public enum RpcMethod {
174174
TX_POOL_BESU_STATISTICS("txpool_besuStatistics"),
175175
TX_POOL_BESU_TRANSACTIONS("txpool_besuTransactions"),
176176
TX_POOL_BESU_PENDING_TRANSACTIONS("txpool_besuPendingTransactions"),
177+
TX_POOL_STATUS("txpool_status"),
177178
WEB3_CLIENT_VERSION("web3_clientVersion"),
178179
WEB3_SHA3("web3_sha3"),
179180
PLUGINS_RELOAD_CONFIG("plugins_reloadPluginConfig"),
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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.ethereum.api.jsonrpc.RpcMethod;
18+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
19+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
20+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
21+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPoolStatusResult;
22+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
23+
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
24+
25+
public class TxPoolStatus implements JsonRpcMethod {
26+
27+
private final TransactionPool transactionPool;
28+
29+
public TxPoolStatus(final TransactionPool transactionPool) {
30+
this.transactionPool = transactionPool;
31+
}
32+
33+
@Override
34+
public String getName() {
35+
return RpcMethod.TX_POOL_STATUS.getMethodName();
36+
}
37+
38+
@Override
39+
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
40+
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), status());
41+
}
42+
43+
private TransactionPoolStatusResult status() {
44+
final PendingTransactions.Status status = transactionPool.getStatus();
45+
return new TransactionPoolStatusResult(status.pendingCount(), status.queuedCount());
46+
}
47+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 com.fasterxml.jackson.annotation.JsonGetter;
18+
19+
public class TransactionPoolStatusResult {
20+
21+
private final long pending;
22+
private final long queued;
23+
24+
public TransactionPoolStatusResult(final long pending, final long queued) {
25+
this.pending = pending;
26+
this.queued = queued;
27+
}
28+
29+
@JsonGetter
30+
public String getPending() {
31+
return Quantity.create(pending);
32+
}
33+
34+
@JsonGetter
35+
public String getQueued() {
36+
return Quantity.create(queued);
37+
}
38+
}

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.TxPoolStatus;
2223
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
2324

2425
import java.util.Map;
@@ -41,6 +42,7 @@ protected Map<String, JsonRpcMethod> create() {
4142
return mapOf(
4243
new TxPoolBesuTransactions(transactionPool),
4344
new TxPoolBesuPendingTransactions(transactionPool),
44-
new TxPoolBesuStatistics(transactionPool));
45+
new TxPoolBesuStatistics(transactionPool),
46+
new TxPoolStatus(transactionPool));
4547
}
4648
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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 static org.assertj.core.api.Assertions.assertThat;
18+
import static org.mockito.Mockito.when;
19+
20+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
21+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
22+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
23+
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPoolStatusResult;
24+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
25+
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
26+
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.extension.ExtendWith;
30+
import org.mockito.Mock;
31+
import org.mockito.junit.jupiter.MockitoExtension;
32+
33+
@ExtendWith(MockitoExtension.class)
34+
public class TxPoolStatusTest {
35+
36+
@Mock private TransactionPool transactionPool;
37+
private TxPoolStatus method;
38+
private static final String JSON_RPC_VERSION = "2.0";
39+
private static final String TXPOOL_STATUS_METHOD = "txpool_status";
40+
41+
@BeforeEach
42+
public void setUp() {
43+
method = new TxPoolStatus(transactionPool);
44+
}
45+
46+
@Test
47+
public void returnsCorrectMethodName() {
48+
assertThat(method.getName()).isEqualTo(TXPOOL_STATUS_METHOD);
49+
}
50+
51+
@Test
52+
public void shouldReturnZeroCountsWhenPoolIsEmpty() {
53+
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(0, 0));
54+
55+
final JsonRpcRequestContext request = buildRequest();
56+
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
57+
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();
58+
59+
assertThat(result.getPending()).isEqualTo("0x0");
60+
assertThat(result.getQueued()).isEqualTo("0x0");
61+
}
62+
63+
@Test
64+
public void shouldReturnCorrectCountsWithPendingAndQueuedTransactions() {
65+
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(10, 7));
66+
67+
final JsonRpcRequestContext request = buildRequest();
68+
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
69+
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();
70+
71+
assertThat(result.getPending()).isEqualTo("0xa");
72+
assertThat(result.getQueued()).isEqualTo("0x7");
73+
}
74+
75+
@Test
76+
public void shouldReturnCorrectCountsWithOnlyPendingTransactions() {
77+
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(5, 0));
78+
79+
final JsonRpcRequestContext request = buildRequest();
80+
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
81+
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();
82+
83+
assertThat(result.getPending()).isEqualTo("0x5");
84+
assertThat(result.getQueued()).isEqualTo("0x0");
85+
}
86+
87+
@Test
88+
public void shouldReturnCorrectCountsWithOnlyQueuedTransactions() {
89+
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(0, 3));
90+
91+
final JsonRpcRequestContext request = buildRequest();
92+
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
93+
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();
94+
95+
assertThat(result.getPending()).isEqualTo("0x0");
96+
assertThat(result.getQueued()).isEqualTo("0x3");
97+
}
98+
99+
@Test
100+
public void shouldReturnHexEncodedLargeValues() {
101+
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(256, 4096));
102+
103+
final JsonRpcRequestContext request = buildRequest();
104+
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
105+
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();
106+
107+
assertThat(result.getPending()).isEqualTo("0x100");
108+
assertThat(result.getQueued()).isEqualTo("0x1000");
109+
}
110+
111+
private JsonRpcRequestContext buildRequest() {
112+
return new JsonRpcRequestContext(
113+
new JsonRpcRequest(JSON_RPC_VERSION, TXPOOL_STATUS_METHOD, new Object[] {}));
114+
}
115+
}

ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/DisabledPendingTransactions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ public String logStats() {
117117
return "Disabled";
118118
}
119119

120+
@Override
121+
public Status getStatus() {
122+
return new Status(0, 0);
123+
}
124+
120125
@Override
121126
public Optional<Transaction> restoreBlob(final Transaction transaction) {
122127
return Optional.empty();

ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,15 @@ void manageBlockAdded(
7373

7474
String logStats();
7575

76+
Status getStatus();
77+
7678
Optional<Transaction> restoreBlob(Transaction transaction);
7779

7880
@FunctionalInterface
7981
interface PendingTransactionsSelector {
8082
Map<PendingTransaction, TransactionSelectionResult> evaluatePendingTransactions(
8183
List<PendingTransaction> candidatePendingTransactions);
8284
}
85+
86+
record Status(long pendingCount, long queuedCount) {}
8387
}

ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,10 @@ public String logStats() {
576576
return pendingTransactions.logStats();
577577
}
578578

579+
public PendingTransactions.Status getStatus() {
580+
return pendingTransactions.getStatus();
581+
}
582+
579583
@VisibleForTesting
580584
Class<? extends PendingTransactions> pendingTransactionsImplementation() {
581585
return pendingTransactions.getClass();

ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/layered/AbstractSequentialTransactionsLayer.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
2323
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
2424
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
25+
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
2526
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
2627
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
2728
import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason;
@@ -123,6 +124,13 @@ public OptionalLong getCurrentNonceFor(final Address sender) {
123124
return nextLayer.getCurrentNonceFor(sender);
124125
}
125126

127+
@Override
128+
public PendingTransactions.Status getStatus() {
129+
final PendingTransactions.Status nextLayerStatus = nextLayer.getStatus();
130+
return new PendingTransactions.Status(
131+
nextLayerStatus.pendingCount() + pendingTransactions.size(), nextLayerStatus.queuedCount());
132+
}
133+
126134
@Override
127135
protected void internalNotifyAdded(
128136
final NavigableMap<Long, PendingTransaction> senderTxs,

0 commit comments

Comments
 (0)