Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- Plugin API: Allow the registration of multiple PluginTransactionPoolValidatorFactory [#9964](https://github.com/hyperledger/besu/pull/9964)
- Add `-Pcases` case name filtering to JMH benchmark suite [#9982](https://github.com/hyperledger/besu/pull/9982)
- Use JDK SHA-256 provider to leverage hardware SHA-NI instructions instead of BouncyCastle [#9924](https://github.com/hyperledger/besu/pull/9924)
- Implement `txpool_status` RPC method [#10002](https://github.com/hyperledger/besu/pull/10002)
- Support [EIP-7975](https://eips.ethereum.org/EIPS/eip-7975): eth/70 - partial block receipt lists
- Limit pooled tx requests by size and remove pre-eth/68 transaction announcement support [#9990](https://github.com/besu-eth/besu/pull/9990)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ public enum RpcMethod {
TX_POOL_BESU_STATISTICS("txpool_besuStatistics"),
TX_POOL_BESU_TRANSACTIONS("txpool_besuTransactions"),
TX_POOL_BESU_PENDING_TRANSACTIONS("txpool_besuPendingTransactions"),
TX_POOL_STATUS("txpool_status"),
WEB3_CLIENT_VERSION("web3_clientVersion"),
WEB3_SHA3("web3_sha3"),
PLUGINS_RELOAD_CONFIG("plugins_reloadPluginConfig"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;

import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPoolStatusResult;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;

public class TxPoolStatus implements JsonRpcMethod {

private final TransactionPool transactionPool;

public TxPoolStatus(final TransactionPool transactionPool) {
this.transactionPool = transactionPool;
}

@Override
public String getName() {
return RpcMethod.TX_POOL_STATUS.getMethodName();
}

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), status());
}

private TransactionPoolStatusResult status() {
final PendingTransactions.Status status = transactionPool.getStatus();
return new TransactionPoolStatusResult(status.pendingCount(), status.queuedCount());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;

import com.fasterxml.jackson.annotation.JsonGetter;

public class TransactionPoolStatusResult {

private final long pending;
private final long queued;

public TransactionPoolStatusResult(final long pending, final long queued) {
this.pending = pending;
this.queued = queued;
}

@JsonGetter
public String getPending() {
return Quantity.create(pending);
}

@JsonGetter
Comment thread
fab-10 marked this conversation as resolved.
public String getQueued() {
return Quantity.create(queued);
}
Comment thread
fab-10 marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuPendingTransactions;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuStatistics;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolBesuTransactions;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.TxPoolStatus;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;

import java.util.Map;
Expand All @@ -41,6 +42,7 @@ protected Map<String, JsonRpcMethod> create() {
return mapOf(
new TxPoolBesuTransactions(transactionPool),
new TxPoolBesuPendingTransactions(transactionPool),
new TxPoolBesuStatistics(transactionPool));
new TxPoolBesuStatistics(transactionPool),
new TxPoolStatus(transactionPool));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionPoolStatusResult;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class TxPoolStatusTest {

@Mock private TransactionPool transactionPool;
private TxPoolStatus method;
private static final String JSON_RPC_VERSION = "2.0";
private static final String TXPOOL_STATUS_METHOD = "txpool_status";

@BeforeEach
public void setUp() {
method = new TxPoolStatus(transactionPool);
}

@Test
public void returnsCorrectMethodName() {
assertThat(method.getName()).isEqualTo(TXPOOL_STATUS_METHOD);
}

@Test
public void shouldReturnZeroCountsWhenPoolIsEmpty() {
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(0, 0));

final JsonRpcRequestContext request = buildRequest();
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();

assertThat(result.getPending()).isEqualTo("0x0");
assertThat(result.getQueued()).isEqualTo("0x0");
}

@Test
public void shouldReturnCorrectCountsWithPendingAndQueuedTransactions() {
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(10, 7));

final JsonRpcRequestContext request = buildRequest();
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();

assertThat(result.getPending()).isEqualTo("0xa");
assertThat(result.getQueued()).isEqualTo("0x7");
}

@Test
public void shouldReturnCorrectCountsWithOnlyPendingTransactions() {
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(5, 0));

final JsonRpcRequestContext request = buildRequest();
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();

assertThat(result.getPending()).isEqualTo("0x5");
assertThat(result.getQueued()).isEqualTo("0x0");
}

@Test
public void shouldReturnCorrectCountsWithOnlyQueuedTransactions() {
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(0, 3));

final JsonRpcRequestContext request = buildRequest();
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();

assertThat(result.getPending()).isEqualTo("0x0");
assertThat(result.getQueued()).isEqualTo("0x3");
}

@Test
public void shouldReturnHexEncodedLargeValues() {
when(transactionPool.getStatus()).thenReturn(new PendingTransactions.Status(256, 4096));

final JsonRpcRequestContext request = buildRequest();
final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) method.response(request);
final TransactionPoolStatusResult result = (TransactionPoolStatusResult) response.getResult();

assertThat(result.getPending()).isEqualTo("0x100");
assertThat(result.getQueued()).isEqualTo("0x1000");
}

private JsonRpcRequestContext buildRequest() {
return new JsonRpcRequestContext(
new JsonRpcRequest(JSON_RPC_VERSION, TXPOOL_STATUS_METHOD, new Object[] {}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ public String logStats() {
return "Disabled";
}

@Override
public Status getStatus() {
return new Status(0, 0);
}

@Override
public Optional<Transaction> restoreBlob(final Transaction transaction) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,15 @@ void manageBlockAdded(

String logStats();

Status getStatus();

Optional<Transaction> restoreBlob(Transaction transaction);

@FunctionalInterface
interface PendingTransactionsSelector {
Map<PendingTransaction, TransactionSelectionResult> evaluatePendingTransactions(
List<PendingTransaction> candidatePendingTransactions);
}

record Status(long pendingCount, long queuedCount) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,10 @@ public String logStats() {
return pendingTransactions.logStats();
}

public PendingTransactions.Status getStatus() {
return pendingTransactions.getStatus();
}

@VisibleForTesting
Class<? extends PendingTransactions> pendingTransactionsImplementation() {
return pendingTransactions.getClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason;
Expand Down Expand Up @@ -123,6 +124,13 @@ public OptionalLong getCurrentNonceFor(final Address sender) {
return nextLayer.getCurrentNonceFor(sender);
}

@Override
public PendingTransactions.Status getStatus() {
final PendingTransactions.Status nextLayerStatus = nextLayer.getStatus();
return new PendingTransactions.Status(
nextLayerStatus.pendingCount() + pendingTransactions.size(), nextLayerStatus.queuedCount());
}

@Override
protected void internalNotifyAdded(
final NavigableMap<Long, PendingTransaction> senderTxs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionAddedListener;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionDroppedListener;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason;
Expand Down Expand Up @@ -183,6 +184,11 @@ public String logStats() {
return "Dropped: " + droppedCount;
}

@Override
public PendingTransactions.Status getStatus() {
return new PendingTransactions.Status(0, 0);
}

@Override
public String logSender(final Address sender) {
return "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,11 @@ public synchronized String logStats() {
return prioritizedTransactions.logStats();
}

@Override
public synchronized Status getStatus() {
return prioritizedTransactions.getStatus();
}

@Override
public Optional<Transaction> restoreBlob(final Transaction transaction) {
return prioritizedTransactions.getBlobCache().restoreBlob(transaction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
Expand Down Expand Up @@ -216,6 +217,23 @@ public List<PendingTransaction> promote(
return promotedTxs;
}

@Override
public PendingTransactions.Status getStatus() {
final PendingTransactions.Status nextLayerStatus = nextLayer.getStatus();
long pendingCount = nextLayerStatus.pendingCount();
long queueCount = nextLayerStatus.queuedCount();
for (final Map.Entry<Address, Integer> entry : gapBySender.entrySet()) {
final Address sender = entry.getKey();
final int gap = entry.getValue();
if (gap == 0) {
pendingCount += txsBySender.get(sender).size();
} else {
queueCount += txsBySender.get(sender).size();
}
}
return new PendingTransactions.Status(pendingCount, queueCount);
}

private NavigableMap<Long, PendingTransaction> getSequentialSubset(
final NavigableMap<Long, PendingTransaction> senderTxs) {
long lastSequentialNonce = senderTxs.firstKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionAddedListener;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionDroppedListener;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult;
import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
Expand Down Expand Up @@ -127,5 +128,7 @@ List<PendingTransaction> promote(

String logStats();

PendingTransactions.Status getStatus();

String logSender(Address sender);
}
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,20 @@ public String logStats() {
return "Pending " + pendingTransactions.size();
}

@Override
public Status getStatus() {
long pendingCount = 0;
long queuedCount = 0;
synchronized (lock) {
for (final PendingTransactionsForSender pendingTxsForSender : transactionsBySender.values()) {
final Status accountStatus = pendingTxsForSender.getStatus();
pendingCount += accountStatus.pendingCount();
queuedCount += accountStatus.queuedCount();
}
}
return new Status(pendingCount, queuedCount);
Comment thread
fab-10 marked this conversation as resolved.
}

@Override
public String toTraceLog() {
synchronized (lock) {
Expand Down
Loading
Loading