Fix javadoc for ethereum api module, graphql package (#7272)

* javadoc - Adding missing javadocs ethereum:api graphql package

Signed-off-by: Usman Saleem <usman@usmans.info>
pull/7278/head
Usman Saleem 5 months ago committed by GitHub
parent d7f851071c
commit 3c5ce8bb89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 62
      build.gradle
  2. 67
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java
  3. 78
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLConfiguration.java
  4. 21
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLContextType.java
  5. 38
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContext.java
  6. 33
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetcherContextImpl.java
  7. 89
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java
  8. 43
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpService.java
  9. 18
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLProvider.java
  10. 47
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/Scalars.java
  11. 21
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccessListEntryAdapter.java
  12. 55
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java
  13. 158
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java
  14. 29
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/CallResult.java
  15. 13
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/EmptyAccountAdapter.java
  16. 41
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java
  17. 59
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/NormalBlockAdapter.java
  18. 65
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java
  19. 30
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/SyncStateAdapter.java
  20. 253
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java
  21. 34
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/WithdrawalAdapter.java
  22. 133
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLError.java
  23. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLErrorResponse.java
  24. 41
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLJsonRequest.java
  25. 12
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLNoResponse.java
  26. 22
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLResponse.java
  27. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLResponseType.java
  28. 21
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/response/GraphQLSuccessResponse.java
  29. 5
      ethereum/mock-p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/testing/MockNetwork.java

@ -365,9 +365,65 @@ allprojects {
options.addBooleanOption('Xdoclint/package:-org.hyperledger.besu.privacy.contracts.generated,' +
'-org.hyperledger.besu.tests.acceptance.*,' +
'-org.hyperledger.besu.tests.web3j.generated,' +
// TODO: these are temporary disabled (ethereum and sub modules), it should be removed in a future PR.
'-org.hyperledger.besu.ethereum.*,' +
'-org.hyperledger.besu.evmtool',
// TODO: these are temporary excluded from lint (ethereum sub modules), it should be removed in a future PR.
// ethereum api module
'-org.hyperledger.besu.ethereum.api.handlers,' +
'-org.hyperledger.besu.ethereum.api.jsonrpc,' +
'-org.hyperledger.besu.ethereum.api.jsonrpc.*,' +
'-org.hyperledger.besu.ethereum.api.query,' +
'-org.hyperledger.besu.ethereum.api.query.*,' +
'-org.hyperledger.besu.ethereum.api.tls,' +
'-org.hyperledger.besu.ethereum.api.util,' +
// ethereum blockcreation module
'-org.hyperledger.besu.ethereum.blockcreation,' +
'-org.hyperledger.besu.ethereum.blockcreation.*,' +
// ethereum core module
'-org.hyperledger.besu.ethereum.chain,' +
'-org.hyperledger.besu.ethereum.core,' +
'-org.hyperledger.besu.ethereum.core.*,' +
'-org.hyperledger.besu.ethereum.debug,' +
'-org.hyperledger.besu.ethereum.difficulty.fixed,' +
'-org.hyperledger.besu.ethereum.forkid,' +
'-org.hyperledger.besu.ethereum.mainnet,' +
'-org.hyperledger.besu.ethereum.mainnet.*,' +
'-org.hyperledger.besu.ethereum.privacy,' +
'-org.hyperledger.besu.ethereum.privacy.*,' +
'-org.hyperledger.besu.ethereum.processing,' +
'-org.hyperledger.besu.ethereum.proof,' +
'-org.hyperledger.besu.ethereum.storage,' +
'-org.hyperledger.besu.ethereum.storage.*,' +
'-org.hyperledger.besu.ethereum.transaction,' +
'-org.hyperledger.besu.ethereum.trie.*,' +
'-org.hyperledger.besu.ethereum.util,' +
'-org.hyperledger.besu.ethereum.vm,' +
'-org.hyperledger.besu.ethereum.worldstate,' +
// ethereum eth module
'-org.hyperledger.besu.ethereum.eth.*,' +
'-org.hyperledger.besu.ethereum.eth,' +
'-org.hyperledger.besu.consensus.merge,' +
// evmtool module
'-org.hyperledger.besu.evmtool,' +
// p2p module
'-org.hyperledger.besu.ethereum.p2p,' +
'-org.hyperledger.besu.ethereum.p2p.*,' +
// permissioning module
'-org.hyperledger.besu.ethereum.permissioning,' +
'-org.hyperledger.besu.ethereum.permissioning.*,' +
// referencetests module
'-org.hyperledger.besu.ethereum.referencetests,' +
// retesteth module
'-org.hyperledger.besu.ethereum.retesteth.methods,' +
'-org.hyperledger.besu.ethereum.retesteth,' +
//rlp module
'-org.hyperledger.besu.ethereum.rlp,' +
// stratum module
'-org.hyperledger.besu.ethereum.stratum,' +
// trie module
'-org.hyperledger.besu.ethereum.trie.*,' +
'-org.hyperledger.besu.ethereum.trie,' +
// verkle trie module
'-org.hyperledger.besu.ethereum.verkletrie,' +
'-org.hyperledger.besu.ethereum.verkletrie.*',
true)
options.addStringOption('Xmaxerrs','65535')
options.addStringOption('Xmaxwarns','65535')

@ -18,58 +18,125 @@ import org.hyperledger.besu.datatypes.Wei;
import org.immutables.value.Value;
/**
* The ApiConfiguration class provides configuration for the API. It includes default values for gas
* price, max logs range, gas cap, and other parameters.
*/
@Value.Immutable
@Value.Style(allParameters = true)
public abstract class ApiConfiguration {
/**
* The default lower bound coefficient for gas and priority fee. This value is used as the default
* lower bound when calculating the gas and priority fee.
*/
public static final long DEFAULT_LOWER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT = 0L;
/**
* The default upper bound coefficient for gas and priority fee. This value is used as the default
* upper bound when calculating the gas and priority fee.
*/
public static final long DEFAULT_UPPER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT = Long.MAX_VALUE;
/** Constructs a new ApiConfiguration with default values. */
protected ApiConfiguration() {}
/**
* Returns the number of blocks to consider for gas price calculations. Default value is 100.
*
* @return the number of blocks for gas price calculations
*/
@Value.Default
public long getGasPriceBlocks() {
return 100;
}
/**
* Returns the percentile to use for gas price calculations. Default value is 50.0.
*
* @return the percentile for gas price calculations
*/
@Value.Default
public double getGasPricePercentile() {
return 50.0d;
}
/**
* Returns the maximum gas price. Default value is 500 GWei.
*
* @return the maximum gas price
*/
@Value.Default
public Wei getGasPriceMax() {
return Wei.of(500_000_000_000L); // 500 GWei
}
/**
* Returns the fraction to use for gas price calculations. This is derived from the gas price
* percentile.
*
* @return the fraction for gas price calculations
*/
@Value.Derived
public double getGasPriceFraction() {
return getGasPricePercentile() / 100.0;
}
/**
* Returns the maximum range for logs. Default value is 5000.
*
* @return the maximum range for logs
*/
@Value.Default
public Long getMaxLogsRange() {
return 5000L;
}
/**
* Returns the gas cap. Default value is 0.
*
* @return the gas cap
*/
@Value.Default
public Long getGasCap() {
return 0L;
}
/**
* Returns whether gas and priority fee limiting is enabled. Default value is false.
*
* @return true if gas and priority fee limiting is enabled, false otherwise
*/
@Value.Default
public boolean isGasAndPriorityFeeLimitingEnabled() {
return false;
}
/**
* Returns the lower bound coefficient for gas and priority fee. Default value is 0.
*
* @return the lower bound coefficient for gas and priority fee
*/
@Value.Default
public Long getLowerBoundGasAndPriorityFeeCoefficient() {
return DEFAULT_LOWER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT;
}
/**
* Returns the upper bound coefficient for gas and priority fee. Default value is Long.MAX_VALUE.
*
* @return the upper bound coefficient for gas and priority fee
*/
@Value.Default
public Long getUpperBoundGasAndPriorityFeeCoefficient() {
return DEFAULT_UPPER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT;
}
/**
* Returns the maximum range for trace filter. Default value is 1000.
*
* @return the maximum range for trace filter
*/
@Value.Default
public Long getMaxTraceFilterRange() {
return 1000L;

@ -26,17 +26,33 @@ import java.util.Objects;
import com.google.common.base.MoreObjects;
/**
* Represents the configuration for GraphQL. This class is used to set and get the configuration
* details for GraphQL such as enabling GraphQL, setting the port and host, setting the allowed
* domains for CORS, setting the hosts allowlist, and setting the HTTP timeout.
*/
public class GraphQLConfiguration {
private static final String DEFAULT_GRAPHQL_HTTP_HOST = "127.0.0.1";
/** The default port number for the GraphQL HTTP server. */
public static final int DEFAULT_GRAPHQL_HTTP_PORT = 8547;
private boolean enabled;
private int port;
private String host;
private List<String> corsAllowedDomains = Collections.emptyList();
private List<String> hostsAllowlist = Arrays.asList("localhost", "127.0.0.1");
private List<String> hostsAllowlist = Arrays.asList("localhost", DEFAULT_GRAPHQL_HTTP_HOST);
private long httpTimeoutSec = TimeoutOptions.defaultOptions().getTimeoutSeconds();
/**
* Creates a default configuration for GraphQL.
*
* <p>This method initializes a new GraphQLConfiguration object with default settings. The default
* settings are: - GraphQL is not enabled - The port is set to the default GraphQL HTTP port - The
* host is set to the default GraphQL HTTP host - The HTTP timeout is set to the default timeout
*
* @return a GraphQLConfiguration object with default settings
*/
public static GraphQLConfiguration createDefault() {
final GraphQLConfiguration config = new GraphQLConfiguration();
config.setEnabled(false);
@ -48,52 +64,112 @@ public class GraphQLConfiguration {
private GraphQLConfiguration() {}
/**
* Checks if GraphQL is enabled.
*
* @return true if GraphQL is enabled, false otherwise
*/
public boolean isEnabled() {
return enabled;
}
/**
* Sets the enabled status of GraphQL.
*
* @param enabled the status to set. true to enable GraphQL, false to disable it
*/
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
/**
* Retrieves the port number for the GraphQL HTTP server.
*
* @return the port number
*/
public int getPort() {
return port;
}
/**
* Sets the port number for the GraphQL HTTP server.
*
* @param port the port number to set
*/
public void setPort(final int port) {
this.port = port;
}
/**
* Retrieves the host for the GraphQL HTTP server.
*
* @return the host
*/
public String getHost() {
return host;
}
/**
* Sets the host for the GraphQL HTTP server.
*
* @param host the host to set
*/
public void setHost(final String host) {
this.host = host;
}
/**
* Retrieves the allowed domains for CORS.
*
* @return a collection of allowed domains for CORS
*/
Collection<String> getCorsAllowedDomains() {
return corsAllowedDomains;
}
/**
* Sets the allowed domains for CORS.
*
* @param corsAllowedDomains a list of allowed domains for CORS
*/
public void setCorsAllowedDomains(final List<String> corsAllowedDomains) {
checkNotNull(corsAllowedDomains);
this.corsAllowedDomains = corsAllowedDomains;
}
/**
* Retrieves the hosts allowlist.
*
* @return a collection of hosts in the allowlist
*/
Collection<String> getHostsAllowlist() {
return Collections.unmodifiableCollection(this.hostsAllowlist);
}
/**
* Sets the hosts allowlist.
*
* @param hostsAllowlist a list of hosts to be added to the allowlist
*/
public void setHostsAllowlist(final List<String> hostsAllowlist) {
checkNotNull(hostsAllowlist);
this.hostsAllowlist = hostsAllowlist;
}
/**
* Retrieves the HTTP timeout in seconds.
*
* @return the HTTP timeout in seconds
*/
public Long getHttpTimeoutSec() {
return httpTimeoutSec;
}
/**
* Sets the HTTP timeout in seconds.
*
* @param httpTimeoutSec the HTTP timeout to set in seconds
*/
public void setHttpTimeoutSec(final long httpTimeoutSec) {
this.httpTimeoutSec = httpTimeoutSec;
}

@ -14,14 +14,33 @@
*/
package org.hyperledger.besu.ethereum.api.graphql;
/** Internal GraphQL Context */
/**
* Enum representing various context types for GraphQL.
*
* <p>These context types are used internally by GraphQL to manage different aspects of the system.
*/
public enum GraphQLContextType {
/** Represents blockchain queries context. */
BLOCKCHAIN_QUERIES,
/** Represents protocol schedule context. */
PROTOCOL_SCHEDULE,
/** Represents transaction pool context. */
TRANSACTION_POOL,
/** Represents mining coordinator context. */
MINING_COORDINATOR,
/** Represents synchronizer context. */
SYNCHRONIZER,
/** Represents is alive handler context. */
IS_ALIVE_HANDLER,
/** Represents chain ID context. */
CHAIN_ID,
/** Represents gas cap context. */
GAS_CAP
}

@ -21,18 +21,56 @@ import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
/**
* Interface representing the context for a GraphQL data fetcher.
*
* <p>This context provides access to various components of the system such as the transaction pool,
* blockchain queries, mining coordinator, synchronizer, and protocol schedule.
*/
public interface GraphQLDataFetcherContext {
/**
* Retrieves the transaction pool.
*
* @return the transaction pool
*/
TransactionPool getTransactionPool();
/**
* Retrieves the blockchain queries.
*
* @return the blockchain queries
*/
BlockchainQueries getBlockchainQueries();
/**
* Retrieves the mining coordinator.
*
* @return the mining coordinator
*/
MiningCoordinator getMiningCoordinator();
/**
* Retrieves the synchronizer.
*
* @return the synchronizer
*/
Synchronizer getSynchronizer();
/**
* Retrieves the protocol schedule.
*
* @return the protocol schedule
*/
ProtocolSchedule getProtocolSchedule();
/**
* Retrieves the is alive handler.
*
* <p>By default, this method returns a new IsAliveHandler instance with a status of true.
*
* @return the is alive handler
*/
default IsAliveHandler getIsAliveHandler() {
return new IsAliveHandler(true);
}

@ -21,6 +21,12 @@ import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
/**
* Implementation of the GraphQLDataFetcherContext interface.
*
* <p>This class provides access to various components of the system such as the transaction pool,
* blockchain queries, mining coordinator, synchronizer, and protocol schedule.
*/
public class GraphQLDataFetcherContextImpl implements GraphQLDataFetcherContext {
private final BlockchainQueries blockchainQueries;
@ -30,6 +36,12 @@ public class GraphQLDataFetcherContextImpl implements GraphQLDataFetcherContext
private final TransactionPool transactionPool;
private final IsAliveHandler isAliveHandler;
/**
* Constructor that takes a GraphQLDataFetcherContext and an IsAliveHandler.
*
* @param context the GraphQLDataFetcherContext
* @param isAliveHandler the IsAliveHandler
*/
public GraphQLDataFetcherContextImpl(
final GraphQLDataFetcherContext context, final IsAliveHandler isAliveHandler) {
this(
@ -41,6 +53,16 @@ public class GraphQLDataFetcherContextImpl implements GraphQLDataFetcherContext
isAliveHandler);
}
/**
* Constructor that takes a BlockchainQueries, ProtocolSchedule, TransactionPool,
* MiningCoordinator, and Synchronizer.
*
* @param blockchainQueries the BlockchainQueries
* @param protocolSchedule the ProtocolSchedule
* @param transactionPool the TransactionPool
* @param miningCoordinator the MiningCoordinator
* @param synchronizer the Synchronizer
*/
public GraphQLDataFetcherContextImpl(
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
@ -56,6 +78,17 @@ public class GraphQLDataFetcherContextImpl implements GraphQLDataFetcherContext
new IsAliveHandler(true));
}
/**
* Constructor that takes a BlockchainQueries, ProtocolSchedule, TransactionPool,
* MiningCoordinator, Synchronizer, and IsAliveHandler.
*
* @param blockchainQueries the BlockchainQueries
* @param protocolSchedule the ProtocolSchedule
* @param transactionPool the TransactionPool
* @param miningCoordinator the MiningCoordinator
* @param synchronizer the Synchronizer
* @param isAliveHandler the IsAliveHandler
*/
public GraphQLDataFetcherContextImpl(
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,

@ -61,10 +61,34 @@ import graphql.schema.DataFetcher;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
/**
* This class contains data fetchers for GraphQL queries.
*
* <p>Data fetchers are responsible for fetching data for a specific field. Each field in the schema
* is associated with a data fetcher. When the field is being processed during a query, the
* associated data fetcher is invoked to get the data for that field.
*
* <p>This class contains data fetchers for various fields such as protocol version, syncing state,
* pending state, gas price, chain ID, max priority fee per gas, range block, block, account, logs,
* and transaction.
*
* <p>Each data fetcher is a method that returns a `DataFetcher` object. The `DataFetcher` object
* defines how to fetch the data for the field. It takes a `DataFetchingEnvironment` object as input
* which contains all the context needed to fetch the data.
*/
public class GraphQLDataFetchers {
private final Integer highestEthVersion;
/**
* Constructs a new GraphQLDataFetchers instance.
*
* <p>This constructor takes a set of supported capabilities and determines the highest Ethereum
* protocol version supported by these capabilities. This version is then stored and can be
* fetched using the getProtocolVersionDataFetcher method.
*
* @param supportedCapabilities a set of capabilities supported by the Ethereum node
*/
public GraphQLDataFetchers(final Set<Capability> supportedCapabilities) {
final OptionalInt version =
supportedCapabilities.stream()
@ -74,10 +98,30 @@ public class GraphQLDataFetchers {
highestEthVersion = version.isPresent() ? version.getAsInt() : null;
}
/**
* Returns a DataFetcher that fetches the highest Ethereum protocol version supported by the node.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input and returns the highest Ethereum protocol version as an
* Optional<Integer>.
*
* @return a DataFetcher that fetches the highest Ethereum protocol version
*/
DataFetcher<Optional<Integer>> getProtocolVersionDataFetcher() {
return dataFetchingEnvironment -> Optional.of(highestEthVersion);
}
/**
* Returns a DataFetcher that fetches the result of sending a raw transaction.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input and returns the hash of the transaction if it is valid
* and added to the transaction pool. If the transaction is invalid, it throws a GraphQLException
* with the invalid reason. If the raw transaction data cannot be read, it throws a
* GraphQLException with INVALID_PARAMS error.
*
* @return a DataFetcher that fetches the result of sending a raw transaction
*/
DataFetcher<Optional<Bytes32>> getSendRawTransactionDataFetcher() {
return dataFetchingEnvironment -> {
try {
@ -99,6 +143,19 @@ public class GraphQLDataFetchers {
};
}
/**
* Returns a DataFetcher that fetches the syncing state of the Ethereum node.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input and returns the syncing state as an
* Optional<SyncStateAdapter>.
*
* <p>The SyncStateAdapter is a wrapper around the SyncStatus of the Ethereum node. It provides
* information about the current syncing state of the node such as the current block, highest
* block, and starting block.
*
* @return a DataFetcher that fetches the syncing state of the Ethereum node
*/
DataFetcher<Optional<SyncStateAdapter>> getSyncingDataFetcher() {
return dataFetchingEnvironment -> {
final Synchronizer synchronizer =
@ -125,6 +182,15 @@ public class GraphQLDataFetchers {
};
}
/**
* Returns a DataFetcher that fetches the chain ID of the Ethereum node.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input and returns the chain ID as an {@code
* Optional<BigInteger>}.
*
* @return a DataFetcher that fetches the chain ID of the Ethereum node
*/
public DataFetcher<Optional<BigInteger>> getChainIdDataFetcher() {
return dataFetchingEnvironment -> {
final GraphQLContext graphQLContext = dataFetchingEnvironment.getGraphQlContext();
@ -132,6 +198,15 @@ public class GraphQLDataFetchers {
};
}
/**
* Returns a DataFetcher that fetches the maximum priority fee per gas of the Ethereum node.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input and returns the maximum priority fee per gas as a Wei
* object. If the maximum priority fee per gas is not available, it returns Wei.ZERO.
*
* @return a DataFetcher that fetches the maximum priority fee per gas of the Ethereum node
*/
public DataFetcher<Wei> getMaxPriorityFeePerGasDataFetcher() {
return dataFetchingEnvironment -> {
final BlockchainQueries blockchainQuery =
@ -167,6 +242,20 @@ public class GraphQLDataFetchers {
};
}
/**
* Returns a DataFetcher that fetches a specific block in the Ethereum blockchain.
*
* <p>The DataFetcher is a functional interface. It has a single method that takes a
* DataFetchingEnvironment object as input. This method fetches a block based on either a block
* number or a block hash. If both a block number and a block hash are provided, it throws a
* GraphQLException with INVALID_PARAMS error. If neither a block number nor a block hash is
* provided, it fetches the latest block.
*
* <p>The fetched block is then wrapped in a {@link NormalBlockAdapter} and returned as an {@code
* Optional<NormalBlockAdapter>}.
*
* @return a DataFetcher that fetches a specific block in the Ethereum blockchain
*/
public DataFetcher<Optional<NormalBlockAdapter>> getBlockDataFetcher() {
return dataFetchingEnvironment -> {

@ -68,6 +68,15 @@ import io.vertx.ext.web.handler.TimeoutHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class handles the HTTP service for GraphQL. It sets up the server, handles requests and
* responses, and manages the lifecycle of the server.
*
* <p>It is responsible for processing GraphQL requests, executing them using the provided GraphQL
* engine, and returning the results in the HTTP response.
*
* <p>It also handles errors and exceptions that may occur during the processing of a request.
*/
public class GraphQLHttpService {
private static final Logger LOG = LoggerFactory.getLogger(GraphQLHttpService.class);
@ -126,6 +135,15 @@ public class GraphQLHttpService {
checkArgument(config.getHost() != null, "Required host is not configured.");
}
/**
* Starts the GraphQL HTTP service.
*
* <p>This method initializes the HTTP server and sets up the necessary routes for handling
* GraphQL requests. It also validates the configuration and sets up the necessary handlers for
* different types of requests.
*
* @return a CompletableFuture that will be completed when the server is successfully started.
*/
public CompletableFuture<?> start() {
LOG.info("Starting GraphQL HTTP service on {}:{}", config.getHost(), config.getPort());
// Create the HTTP server and a router object.
@ -230,6 +248,14 @@ public class GraphQLHttpService {
}
}
/**
* Stops the GraphQL HTTP service.
*
* <p>This method stops the HTTP server that was created and started by the start() method. If the
* server is not running, this method will do nothing.
*
* @return a CompletableFuture that will be completed when the server is successfully stopped.
*/
public CompletableFuture<?> stop() {
if (httpServer == null) {
return CompletableFuture.completedFuture(null);
@ -248,6 +274,15 @@ public class GraphQLHttpService {
return resultFuture;
}
/**
* Returns the socket address of the GraphQL HTTP service.
*
* <p>This method returns the socket address that the HTTP server is bound to. If the server is
* not running, it returns an empty socket address.
*
* @return the socket address of the HTTP server, or an empty socket address if the server is not
* running.
*/
public InetSocketAddress socketAddress() {
if (httpServer == null) {
return EMPTY_SOCKET_ADDRESS;
@ -255,6 +290,14 @@ public class GraphQLHttpService {
return new InetSocketAddress(config.getHost(), httpServer.actualPort());
}
/**
* Returns the URL of the GraphQL HTTP service.
*
* <p>This method constructs and returns the URL that the HTTP server is bound to. If the server
* is not running, it returns an empty string.
*
* @return the URL of the HTTP server, or an empty string if the server is not running.
*/
@VisibleForTesting
public String url() {
if (httpServer == null) {

@ -31,12 +31,30 @@ import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import graphql.schema.idl.TypeRuntimeWiring;
/**
* This class provides the GraphQL service.
*
* <p>It contains a method to build the GraphQL service with the provided data fetchers.
*/
public class GraphQLProvider {
/**
* The maximum complexity allowed for a GraphQL query.
*
* <p>This constant is used to prevent overly complex queries from being executed. A query's
* complexity is calculated based on the number and type of fields it contains.
*/
public static final int MAX_COMPLEXITY = 200;
private GraphQLProvider() {}
/**
* Builds the GraphQL service with the provided data fetchers.
*
* @param graphQLDataFetchers the data fetchers to be used in the GraphQL service.
* @return the built GraphQL service.
* @throws IOException if there is an error reading the schema file.
*/
public static GraphQL buildGraphQL(final GraphQLDataFetchers graphQLDataFetchers)
throws IOException {
final URL url = Resources.getResource("schema.graphqls");

@ -35,6 +35,13 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/**
* The Scalars class provides methods for creating GraphQLScalarType objects. These objects
* represent the scalar types used in GraphQL, such as Address, BigInt, Bytes, Bytes32, and Long.
* Each method in this class returns a GraphQLScalarType object that has been configured with a
* specific Coercing implementation. The Coercing implementation defines how that type is
* serialized, deserialized and validated.
*/
public class Scalars {
private Scalars() {}
@ -366,6 +373,14 @@ public class Scalars {
}
};
/**
* Creates a new GraphQLScalarType object for an Address.
*
* <p>The object is configured with a specific Coercing implementation that defines how the
* Address type is serialized, deserialized and validated.
*
* @return a GraphQLScalarType object for an Address.
*/
public static GraphQLScalarType addressScalar() {
return GraphQLScalarType.newScalar()
.name("Address")
@ -374,6 +389,14 @@ public class Scalars {
.build();
}
/**
* Creates a new GraphQLScalarType object for a BigInt.
*
* <p>The object is configured with a specific Coercing implementation that defines how the BigInt
* type is serialized, deserialized and validated.
*
* @return a GraphQLScalarType object for a BigInt.
*/
public static GraphQLScalarType bigIntScalar() {
return GraphQLScalarType.newScalar()
.name("BigInt")
@ -382,6 +405,14 @@ public class Scalars {
.build();
}
/**
* Creates a new GraphQLScalarType object for Bytes.
*
* <p>The object is configured with a specific Coercing implementation that defines how the Bytes
* type is serialized, deserialized and validated.
*
* @return a GraphQLScalarType object for Bytes.
*/
public static GraphQLScalarType bytesScalar() {
return GraphQLScalarType.newScalar()
.name("Bytes")
@ -390,6 +421,14 @@ public class Scalars {
.build();
}
/**
* Creates a new GraphQLScalarType object for Bytes32.
*
* <p>The object is configured with a specific Coercing implementation that defines how the
* Bytes32 type is serialized, deserialized and validated.
*
* @return a GraphQLScalarType object for Bytes32.
*/
public static GraphQLScalarType bytes32Scalar() {
return GraphQLScalarType.newScalar()
.name("Bytes32")
@ -398,6 +437,14 @@ public class Scalars {
.build();
}
/**
* Creates a new GraphQLScalarType object for a Long.
*
* <p>The object is configured with a specific Coercing implementation that defines how the Long
* type is serialized, deserialized and validated.
*
* @return a GraphQLScalarType object for a Long.
*/
public static GraphQLScalarType longScalar() {
return GraphQLScalarType.newScalar()
.name("Long")

@ -23,19 +23,40 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
/**
* The AccessListEntryAdapter class extends the AdapterBase class. It provides methods to get the
* storage keys and address from an AccessListEntry.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class AccessListEntryAdapter extends AdapterBase {
/** The AccessListEntry object that this adapter wraps. */
private final AccessListEntry accessListEntry;
/**
* Constructs a new AccessListEntryAdapter with the given AccessListEntry.
*
* @param accessListEntry the AccessListEntry to be adapted
*/
public AccessListEntryAdapter(final AccessListEntry accessListEntry) {
this.accessListEntry = accessListEntry;
}
/**
* Returns the storage keys from the AccessListEntry.
*
* @return a list of storage keys
*/
public List<Bytes32> getStorageKeys() {
final var storage = accessListEntry.storageKeys();
return new ArrayList<>(storage);
}
/**
* Returns the address from the AccessListEntry.
*
* @return an Optional containing the address if it exists, otherwise an empty Optional
*/
public Optional<Address> getAddress() {
return Optional.of(accessListEntry.address());
}

@ -28,6 +28,10 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/**
* The AccountAdapter class extends the AdapterBase class. It provides methods to get the account
* details such as address, balance, transaction count, code, and storage.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class AccountAdapter extends AdapterBase {
@ -35,18 +39,42 @@ public class AccountAdapter extends AdapterBase {
private final Address address;
private final Optional<Long> blockNumber;
/**
* Constructs a new AccountAdapter with the given Account.
*
* @param account the Account to be adapted
*/
public AccountAdapter(final Account account) {
this(account == null ? null : account.getAddress(), account, Optional.empty());
}
/**
* Constructs a new AccountAdapter with the given Account and block number.
*
* @param account the Account to be adapted
* @param blockNumber the block number associated with the account
*/
public AccountAdapter(final Account account, final Optional<Long> blockNumber) {
this(account == null ? null : account.getAddress(), account, blockNumber);
}
/**
* Constructs a new AccountAdapter with the given address and Account.
*
* @param address the address of the account
* @param account the Account to be adapted
*/
public AccountAdapter(final Address address, final Account account) {
this(address, account, Optional.empty());
}
/**
* Constructs a new AccountAdapter with the given address, Account, and block number.
*
* @param address the address of the account
* @param account the Account to be adapted
* @param blockNumber the block number associated with the account
*/
public AccountAdapter(
final Address address, final Account account, final Optional<Long> blockNumber) {
this.account = Optional.ofNullable(account);
@ -54,18 +82,39 @@ public class AccountAdapter extends AdapterBase {
this.blockNumber = blockNumber;
}
/**
* Returns the address of the account.
*
* @return the address of the account
*/
public Address getAddress() {
return address;
}
/**
* Returns the balance of the account.
*
* @return the balance of the account
*/
public Wei getBalance() {
return account.map(AccountState::getBalance).orElse(Wei.ZERO);
}
/**
* Returns the transaction count of the account.
*
* @return the transaction count of the account
*/
public Long getTransactionCount() {
return account.map(AccountState::getNonce).orElse(0L);
}
/**
* Returns the code of the account.
*
* @param environment the DataFetchingEnvironment
* @return the code of the account
*/
public Bytes getCode(final DataFetchingEnvironment environment) {
if (account.get() instanceof BonsaiAccount) {
@ -80,6 +129,12 @@ public class AccountAdapter extends AdapterBase {
}
}
/**
* Returns the storage of the account.
*
* @param environment the DataFetchingEnvironment
* @return the storage of the account
*/
public Bytes32 getStorage(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Bytes32 slot = environment.getArgument("slot");

@ -48,15 +48,30 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/**
* The BlockAdapterBase class extends the AdapterBase class. It provides methods to get and
* manipulate block data.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class BlockAdapterBase extends AdapterBase {
private final BlockHeader header;
/**
* Constructs a new BlockAdapterBase with the given BlockHeader.
*
* @param header the BlockHeader to be adapted
*/
BlockAdapterBase(final BlockHeader header) {
this.header = header;
}
/**
* Returns the parent block of the current block.
*
* @param environment the DataFetchingEnvironment
* @return an Optional containing the parent block if it exists, otherwise an empty Optional
*/
public Optional<NormalBlockAdapter> getParent(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Hash parentHash = header.getParentHash();
@ -65,28 +80,59 @@ public class BlockAdapterBase extends AdapterBase {
return block.map(NormalBlockAdapter::new);
}
/**
* Returns the hash of the current block.
*
* @return the hash of the block
*/
public Bytes32 getHash() {
return header.getHash();
}
/**
* Returns the nonce of the current block.
*
* @return the nonce of the block
*/
public Bytes getNonce() {
final long nonce = header.getNonce();
final byte[] bytes = Longs.toByteArray(nonce);
return Bytes.wrap(bytes);
}
/**
* Returns the transactions root of the current block.
*
* @return the transactions root of the block
*/
public Bytes32 getTransactionsRoot() {
return header.getTransactionsRoot();
}
/**
* Returns the state root of the current block.
*
* @return the state root of the block
*/
public Bytes32 getStateRoot() {
return header.getStateRoot();
}
/**
* Returns the receipts root of the current block.
*
* @return the receipts root of the block
*/
public Bytes32 getReceiptsRoot() {
return header.getReceiptsRoot();
}
/**
* Returns the miner of the current block.
*
* @param environment the DataFetchingEnvironment
* @return an AccountAdapter instance representing the miner of the block
*/
public AccountAdapter getMiner(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
@ -102,46 +148,103 @@ public class BlockAdapterBase extends AdapterBase {
.orElseGet(() -> new EmptyAccountAdapter(header.getCoinbase()));
}
/**
* Returns the extra data of the current block.
*
* @return the extra data of the block
*/
public Bytes getExtraData() {
return header.getExtraData();
}
/**
* Returns the base fee per gas of the current block.
*
* @return the base fee per gas of the block
*/
public Optional<Wei> getBaseFeePerGas() {
return header.getBaseFee();
}
/**
* Returns the gas limit of the current block.
*
* @return the gas limit of the block
*/
public Long getGasLimit() {
return header.getGasLimit();
}
/**
* Returns the gas used by the current block.
*
* @return the gas used by the block
*/
public Long getGasUsed() {
return header.getGasUsed();
}
/**
* Returns the timestamp of the current block.
*
* @return the timestamp of the block
*/
public Long getTimestamp() {
return header.getTimestamp();
}
/**
* Returns the logs bloom of the current block.
*
* @return the logs bloom of the block
*/
public Bytes getLogsBloom() {
return header.getLogsBloom();
}
/**
* Returns the mix hash of the current block.
*
* @return the mix hash of the block
*/
public Bytes32 getMixHash() {
return header.getMixHash();
}
/**
* Returns the difficulty of the current block.
*
* @return the difficulty of the block
*/
public Difficulty getDifficulty() {
return header.getDifficulty();
}
/**
* Returns the ommer hash of the current block.
*
* @return the ommer hash of the block
*/
public Bytes32 getOmmerHash() {
return header.getOmmersHash();
}
/**
* Returns the number of the current block.
*
* @return the number of the block
*/
public Long getNumber() {
return header.getNumber();
}
/**
* Returns an AccountAdapter instance for a given address at the current block.
*
* @param environment the DataFetchingEnvironment
* @return an AccountAdapter instance representing the account of the given address at the current
* block
*/
public AccountAdapter getAccount(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final long bn = header.getNumber();
@ -152,6 +255,13 @@ public class BlockAdapterBase extends AdapterBase {
.get();
}
/**
* Returns a list of logs for the current block that match a given filter.
*
* @param environment the DataFetchingEnvironment
* @return a list of LogAdapter instances representing the logs of the current block that match
* the filter
*/
public List<LogAdapter> getLogs(final DataFetchingEnvironment environment) {
final Map<String, Object> filter = environment.getArgument("filter");
@ -183,11 +293,24 @@ public class BlockAdapterBase extends AdapterBase {
return results;
}
/**
* Estimates the gas used for a call execution.
*
* @param environment the DataFetchingEnvironment
* @return the estimated gas used for the call execution
*/
public Long getEstimateGas(final DataFetchingEnvironment environment) {
final Optional<CallResult> result = executeCall(environment);
return result.map(CallResult::getGasUsed).orElse(0L);
}
/**
* Executes a call and returns the result.
*
* @param environment the DataFetchingEnvironment
* @return an Optional containing the result of the call execution if it exists, otherwise an
* empty Optional
*/
public Optional<CallResult> getCall(final DataFetchingEnvironment environment) {
return executeCall(environment);
}
@ -259,12 +382,23 @@ public class BlockAdapterBase extends AdapterBase {
header);
}
/**
* Returns the raw header of the current block.
*
* @return the raw header of the block
*/
Bytes getRawHeader() {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
header.writeTo(rlpOutput);
return rlpOutput.encoded();
}
/**
* Returns the raw data of the current block.
*
* @param environment the DataFetchingEnvironment
* @return the raw data of the block
*/
Bytes getRaw(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
return query
@ -279,10 +413,22 @@ public class BlockAdapterBase extends AdapterBase {
.orElse(Bytes.EMPTY);
}
/**
* Returns the withdrawals root of the current block.
*
* @return an Optional containing the withdrawals root if it exists, otherwise an empty Optional
*/
Optional<Bytes32> getWithdrawalsRoot() {
return header.getWithdrawalsRoot().map(Function.identity());
}
/**
* Returns a list of withdrawals for the current block.
*
* @param environment the DataFetchingEnvironment
* @return an Optional containing a list of WithdrawalAdapter instances representing the
* withdrawals of the current block if they exist, otherwise an empty Optional
*/
Optional<List<WithdrawalAdapter>> getWithdrawals(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
return query
@ -295,10 +441,22 @@ public class BlockAdapterBase extends AdapterBase {
.map(wl -> wl.stream().map(WithdrawalAdapter::new).toList()));
}
/**
* Returns the blob gas used by the current block.
*
* @return an Optional containing the blob gas used by the current block if it exists, otherwise
* an empty Optional
*/
public Optional<Long> getBlobGasUsed() {
return header.getBlobGasUsed();
}
/**
* Returns the excess blob gas of the current block.
*
* @return an Optional containing the excess blob gas of the current block if it exists, otherwise
* an empty Optional
*/
public Optional<Long> getExcessBlobGas() {
return header.getExcessBlobGas().map(BlobGas::toLong);
}

@ -16,26 +16,55 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.apache.tuweni.bytes.Bytes;
/**
* Represents the result of a call execution. This class is used to encapsulate the status, gas
* used, and data returned by a call execution. It is used in conjunction with the {@link
* org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.BlockAdapterBase} class.
*
* @see org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.BlockAdapterBase
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class CallResult {
private final Long status;
private final Long gasUsed;
private final Bytes data;
/**
* Constructs a new CallResult.
*
* @param status the status of the call execution
* @param gasUsed the amount of gas used by the call
* @param data the data returned by the call
*/
CallResult(final Long status, final Long gasUsed, final Bytes data) {
this.status = status;
this.gasUsed = gasUsed;
this.data = data;
}
/**
* Returns the status of the call execution.
*
* @return the status of the call execution
*/
public Long getStatus() {
return status;
}
/**
* Returns the amount of gas used by the call.
*
* @return the amount of gas used by the call
*/
public Long getGasUsed() {
return gasUsed;
}
/**
* Returns the data returned by the call.
*
* @return the data returned by the call
*/
public Bytes getData() {
return data;
}

@ -21,9 +21,22 @@ import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
/**
* Represents an empty account in the Ethereum blockchain. This class is used when an account does
* not exist at a specific address. It provides default values for the account's properties. It
* extends the {@link org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.AccountAdapter}
* class.
*
* @see org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter.AccountAdapter
*/
public class EmptyAccountAdapter extends AccountAdapter {
private final Address address;
/**
* Constructs a new EmptyAccountAdapter.
*
* @param address the address of the account
*/
public EmptyAccountAdapter(final Address address) {
super(null);
this.address = address;

@ -28,27 +28,62 @@ import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
/**
* This class is an adapter for the LogWithMetadata class.
*
* <p>It extends the AdapterBase class and provides methods to get the index, topics, data,
* transaction, and account associated with a log.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class LogAdapter extends AdapterBase {
private final LogWithMetadata logWithMetadata;
/**
* Constructor for LogAdapter.
*
* <p>It initializes the logWithMetadata field with the provided argument.
*
* @param logWithMetadata the log with metadata to be adapted.
*/
public LogAdapter(final LogWithMetadata logWithMetadata) {
this.logWithMetadata = logWithMetadata;
}
/**
* Returns the index of the log.
*
* @return the index of the log.
*/
public Integer getIndex() {
return logWithMetadata.getLogIndex();
}
/**
* Returns the topics of the log.
*
* @return a list of topics of the log.
*/
public List<LogTopic> getTopics() {
final List<LogTopic> topics = logWithMetadata.getTopics();
return new ArrayList<>(topics);
}
/**
* Returns the data of the log.
*
* @return the data of the log.
*/
public Bytes getData() {
return logWithMetadata.getData();
}
/**
* Returns the transaction associated with the log.
*
* @param environment the data fetching environment.
* @return a TransactionAdapter for the transaction associated with the log.
* @throws java.util.NoSuchElementException if the transaction is not found.
*/
public TransactionAdapter getTransaction(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Hash hash = logWithMetadata.getTransactionHash();
@ -56,6 +91,12 @@ public class LogAdapter extends AdapterBase {
return tran.map(TransactionAdapter::new).orElseThrow();
}
/**
* Returns the account associated with the log.
*
* @param environment the data fetching environment.
* @return an AccountAdapter for the account associated with the log.
*/
public AccountAdapter getAccount(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
long blockNumber = logWithMetadata.getBlockNumber();

@ -27,9 +27,24 @@ import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
/**
* This class is an adapter for the BlockWithMetadata class.
*
* <p>It extends the BlockAdapterBase class and provides methods to get the transaction count, total
* difficulty, ommer count, ommers, transactions, and specific ommer and transaction at a given
* index associated with a block.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class NormalBlockAdapter extends BlockAdapterBase {
/**
* Constructor for NormalBlockAdapter.
*
* <p>It initializes the blockWithMetaData field with the provided argument and calls the parent
* constructor with the header of the provided blockWithMetaData.
*
* @param blockWithMetaData the block with metadata to be adapted.
*/
public NormalBlockAdapter(
final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetaData) {
super(blockWithMetaData.getHeader());
@ -38,18 +53,39 @@ public class NormalBlockAdapter extends BlockAdapterBase {
private final BlockWithMetadata<TransactionWithMetadata, Hash> blockWithMetaData;
/**
* Returns the transaction count of the block.
*
* @return the transaction count of the block.
*/
public Optional<Integer> getTransactionCount() {
return Optional.of(blockWithMetaData.getTransactions().size());
}
/**
* Returns the total difficulty of the block.
*
* @return the total difficulty of the block.
*/
public Difficulty getTotalDifficulty() {
return blockWithMetaData.getTotalDifficulty();
}
/**
* Returns the ommer count of the block.
*
* @return the ommer count of the block.
*/
public Optional<Integer> getOmmerCount() {
return Optional.of(blockWithMetaData.getOmmers().size());
}
/**
* Returns the ommers of the block.
*
* @param environment the data fetching environment.
* @return a list of UncleBlockAdapter for the ommers of the block.
*/
public List<UncleBlockAdapter> getOmmers(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final List<Hash> ommers = blockWithMetaData.getOmmers();
@ -63,6 +99,12 @@ public class NormalBlockAdapter extends BlockAdapterBase {
return results;
}
/**
* Returns the ommer at a given index of the block.
*
* @param environment the data fetching environment.
* @return an UncleBlockAdapter for the ommer at the given index of the block.
*/
public Optional<UncleBlockAdapter> getOmmerAt(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final int index = ((Number) environment.getArgument("index")).intValue();
@ -75,6 +117,13 @@ public class NormalBlockAdapter extends BlockAdapterBase {
return Optional.empty();
}
/**
* Returns a list of TransactionAdapter objects for the transactions in the block.
*
* <p>Each TransactionAdapter object is created by adapting a TransactionWithMetadata object.
*
* @return a list of TransactionAdapter objects for the transactions in the block.
*/
public List<TransactionAdapter> getTransactions() {
final List<TransactionWithMetadata> trans = blockWithMetaData.getTransactions();
final List<TransactionAdapter> results = new ArrayList<>();
@ -84,6 +133,16 @@ public class NormalBlockAdapter extends BlockAdapterBase {
return results;
}
/**
* Returns a TransactionAdapter object for the transaction at the given index in the block.
*
* <p>The index is retrieved from the data fetching environment. If there is no transaction at the
* given index, an empty Optional is returned.
*
* @param environment the data fetching environment.
* @return an Optional containing a TransactionAdapter object for the transaction at the given
* index in the block, or an empty Optional if there is no transaction at the given index.
*/
public Optional<TransactionAdapter> getTransactionAt(final DataFetchingEnvironment environment) {
final int index = ((Number) environment.getArgument("index")).intValue();
final List<TransactionWithMetadata> trans = blockWithMetaData.getTransactions();

@ -36,19 +36,41 @@ import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
/**
* This class represents the pending state of transactions in the Ethereum network.
*
* <p>It extends the AdapterBase class and provides methods to interact with the transaction pool.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class PendingStateAdapter extends AdapterBase {
private final TransactionPool transactionPool;
/**
* Constructor for PendingStateAdapter.
*
* <p>It initializes the transactionPool field with the provided argument.
*
* @param transactionPool the transaction pool to be used.
*/
public PendingStateAdapter(final TransactionPool transactionPool) {
this.transactionPool = transactionPool;
}
/**
* Returns the count of transactions in the transaction pool.
*
* @return the count of transactions in the transaction pool.
*/
public Integer getTransactionCount() {
return transactionPool.count();
}
/**
* Returns a list of TransactionAdapter objects for the transactions in the transaction pool.
*
* @return a list of TransactionAdapter objects for the transactions in the transaction pool.
*/
public List<TransactionAdapter> getTransactions() {
return transactionPool.getPendingTransactions().stream()
.map(PendingTransaction::getTransaction)
@ -57,9 +79,17 @@ public class PendingStateAdapter extends AdapterBase {
.toList();
}
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
/**
* Returns an AccountAdapter object for the account associated with the provided address.
*
* <p>The account state is estimated against the latest block.
*
* @param dataFetchingEnvironment the data fetching environment.
* @return an AccountAdapter object for the account associated with the provided address.
*/
public AccountAdapter getAccount(final DataFetchingEnvironment dataFetchingEnvironment) {
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
final BlockchainQueries blockchainQuery =
dataFetchingEnvironment.getGraphQlContext().get(GraphQLContextType.BLOCKCHAIN_QUERIES);
final Address addr = dataFetchingEnvironment.getArgument("address");
@ -71,16 +101,39 @@ public class PendingStateAdapter extends AdapterBase {
.orElseGet(() -> new AccountAdapter(null));
}
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
/**
* Estimates the gas required for a transaction.
*
* <p>This method calls the getCall method to simulate the transaction and then retrieves the gas
* used by the transaction. The gas estimation is done against the latest block as there is
* currently no way to expose the current "proposed block" for a speculative environment.
*
* @param environment the data fetching environment.
* @return an Optional containing the estimated gas for the transaction, or an empty Optional if
* the transaction simulation was not successful.
*/
public Optional<Long> getEstimateGas(final DataFetchingEnvironment environment) {
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
final Optional<CallResult> result = getCall(environment);
return result.map(CallResult::getGasUsed);
}
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
/**
* Simulates the execution of a transaction.
*
* <p>This method retrieves the transaction parameters from the data fetching environment, creates
* a CallParameter object, and then uses a TransactionSimulator to simulate the execution of the
* transaction. The simulation is done against the latest block as there is currently no way to
* expose the current "proposed block" for a speculative environment.
*
* @param environment the data fetching environment.
* @return an Optional containing the result of the transaction simulation, or an empty Optional
* if the transaction simulation was not successful.
*/
public Optional<CallResult> getCall(final DataFetchingEnvironment environment) {
// until the miner can expose the current "proposed block" we have no
// speculative environment, so estimate against latest.
final Map<String, Object> callData = environment.getArgument("data");
final Address from = (Address) callData.get("from");
final Address to = (Address) callData.get("to");

@ -16,22 +16,52 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.plugin.data.SyncStatus;
/**
* The SyncStateAdapter class provides methods to retrieve the synchronization status of the
* blockchain.
*
* <p>This class is used to adapt a SyncStatus object into a format that can be used by GraphQL. The
* SyncStatus object is provided at construction time.
*
* <p>The class provides methods to retrieve the starting block, current block, and highest block of
* the synchronization status.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class SyncStateAdapter {
private final SyncStatus syncStatus;
/**
* Constructs a new SyncStateAdapter object.
*
* @param syncStatus the SyncStatus object to adapt.
*/
public SyncStateAdapter(final SyncStatus syncStatus) {
this.syncStatus = syncStatus;
}
/**
* Returns the starting block of the synchronization status.
*
* @return the starting block of the synchronization status.
*/
public Long getStartingBlock() {
return syncStatus.getStartingBlock();
}
/**
* Returns the current block of the synchronization status.
*
* @return the current block of the synchronization status.
*/
public Long getCurrentBlock() {
return syncStatus.getCurrentBlock();
}
/**
* Returns the highest block of the synchronization status.
*
* @return the highest block of the synchronization status.
*/
public Long getHighestBlock() {
return syncStatus.getHighestBlock();
}

@ -38,11 +38,28 @@ import javax.annotation.Nonnull;
import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
/**
* The TransactionAdapter class provides methods to retrieve the transaction details.
*
* <p>This class is used to adapt a TransactionWithMetadata object into a format that can be used by
* GraphQL. The TransactionWithMetadata object is provided at construction time.
*
* <p>The class provides methods to retrieve the hash, type, nonce, index, from, to, value, gas
* price, max fee per gas, max priority fee per gas, max fee per blob gas, effective tip, gas, input
* data, block, status, gas used, cumulative gas used, effective gas price, blob gas used, blob gas
* price, created contract, logs, R, S, V, Y parity, access list, raw, raw receipt, and blob
* versioned hashes of the transaction.
*/
@SuppressWarnings("unused") // reflected by GraphQL
public class TransactionAdapter extends AdapterBase {
private final TransactionWithMetadata transactionWithMetadata;
private Optional<TransactionReceiptWithMetadata> transactionReceiptWithMetadata;
/**
* Constructs a new TransactionAdapter object.
*
* @param transactionWithMetadata the TransactionWithMetadata object to adapt.
*/
public TransactionAdapter(final @Nonnull TransactionWithMetadata transactionWithMetadata) {
this.transactionWithMetadata = transactionWithMetadata;
}
@ -65,22 +82,53 @@ public class TransactionAdapter extends AdapterBase {
return transactionReceiptWithMetadata;
}
/**
* Returns the hash of the transaction.
*
* @return the hash of the transaction.
*/
public Hash getHash() {
return transactionWithMetadata.getTransaction().getHash();
}
/**
* Returns the type of the transaction.
*
* @return the type of the transaction.
*/
public Optional<Integer> getType() {
return Optional.of(transactionWithMetadata.getTransaction().getType().ordinal());
}
/**
* Returns the nonce of the transaction.
*
* @return the nonce of the transaction.
*/
public Long getNonce() {
return transactionWithMetadata.getTransaction().getNonce();
}
/**
* Returns the index of the transaction.
*
* @return the index of the transaction.
*/
public Optional<Integer> getIndex() {
return transactionWithMetadata.getTransactionIndex();
}
/**
* Retrieves the sender of the transaction.
*
* <p>This method uses the BlockchainQueries to get the block number and then retrieves the sender
* of the transaction. It then uses the getAndMapWorldState method to get the state of the
* sender's account at the given block number.
*
* @param environment the data fetching environment.
* @return an AccountAdapter object representing the sender's account state at the given block
* number.
*/
public AccountAdapter getFrom(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Long blockNumber =
@ -96,6 +144,18 @@ public class TransactionAdapter extends AdapterBase {
.orElse(new EmptyAccountAdapter(addr));
}
/**
* Retrieves the recipient of the transaction.
*
* <p>This method uses the BlockchainQueries to get the block number and then retrieves the
* recipient of the transaction. It then uses the getAndMapWorldState method to get the state of
* the recipient's account at the given block number.
*
* @param environment the data fetching environment.
* @return an Optional containing an AccountAdapter object representing the recipient's account
* state at the given block number, or an empty Optional if the transaction does not have a
* recipient (i.e., it is a contract creation transaction).
*/
public Optional<AccountAdapter> getTo(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Long blockNumber =
@ -115,39 +175,95 @@ public class TransactionAdapter extends AdapterBase {
.or(() -> Optional.of(new EmptyAccountAdapter(address))));
}
/**
* Retrieves the value of the transaction.
*
* @return a Wei object representing the value of the transaction.
*/
public Wei getValue() {
return transactionWithMetadata.getTransaction().getValue();
}
/**
* Retrieves the gas price of the transaction.
*
* @return a Wei object representing the gas price of the transaction. If the transaction does not
* specify a gas price, this method returns zero.
*/
public Wei getGasPrice() {
return transactionWithMetadata.getTransaction().getGasPrice().orElse(Wei.ZERO);
}
/**
* Retrieves the maximum fee per gas of the transaction.
*
* @return an Optional containing a Wei object representing the maximum fee per gas of the
* transaction, or an empty Optional if the transaction does not specify a maximum fee per
* gas.
*/
public Optional<Wei> getMaxFeePerGas() {
return transactionWithMetadata.getTransaction().getMaxFeePerGas();
}
/**
* Retrieves the maximum priority fee per gas of the transaction.
*
* @return an Optional containing a Wei object representing the maximum priority fee per gas of
* the transaction, or an empty Optional if the transaction does not specify a maximum
* priority fee per gas.
*/
public Optional<Wei> getMaxPriorityFeePerGas() {
return transactionWithMetadata.getTransaction().getMaxPriorityFeePerGas();
}
/**
* Retrieves the maximum fee per blob gas of the transaction.
*
* @return an Optional containing a Wei object representing the maximum fee per blob gas of the
* transaction, or an empty Optional if the transaction does not specify a maximum fee per
* blob gas.
*/
public Optional<Wei> getMaxFeePerBlobGas() {
return transactionWithMetadata.getTransaction().getMaxFeePerBlobGas();
}
/**
* Retrieves the effective tip of the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Wei object representing the effective tip of the transaction,
* or an empty Optional if the transaction does not specify an effective tip.
*/
public Optional<Wei> getEffectiveTip(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(rwm -> rwm.getTransaction().getEffectivePriorityFeePerGas(rwm.getBaseFee()));
}
/**
* Retrieves the gas limit of the transaction.
*
* @return a Long object representing the gas limit of the transaction.
*/
public Long getGas() {
return transactionWithMetadata.getTransaction().getGasLimit();
}
/**
* Retrieves the input data of the transaction.
*
* @return a Bytes object representing the input data of the transaction.
*/
public Bytes getInputData() {
return transactionWithMetadata.getTransaction().getPayload();
}
/**
* Retrieves the block of the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a NormalBlockAdapter object representing the block of the
* transaction, or an empty Optional if the transaction does not specify a block.
*/
public Optional<NormalBlockAdapter> getBlock(final DataFetchingEnvironment environment) {
return transactionWithMetadata
.getBlockHash()
@ -155,6 +271,17 @@ public class TransactionAdapter extends AdapterBase {
.map(NormalBlockAdapter::new);
}
/**
* Retrieves the status of the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then checks
* the status of the receipt. If the status is -1, it returns an empty Optional. Otherwise, it
* returns an Optional containing the status of the receipt.
*
* @param environment the data fetching environment.
* @return an Optional containing a Long object representing the status of the transaction, or an
* empty Optional if the status of the receipt is -1.
*/
public Optional<Long> getStatus(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(TransactionReceiptWithMetadata::getReceipt)
@ -165,27 +292,87 @@ public class TransactionAdapter extends AdapterBase {
: Optional.of((long) receipt.getStatus()));
}
/**
* Retrieves the gas used by the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then
* returns an Optional containing the gas used by the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Long object representing the gas used by the transaction.
*/
public Optional<Long> getGasUsed(final DataFetchingEnvironment environment) {
return getReceipt(environment).map(TransactionReceiptWithMetadata::getGasUsed);
}
/**
* Retrieves the cumulative gas used by the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then
* returns an Optional containing the cumulative gas used by the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Long object representing the cumulative gas used by the
* transaction.
*/
public Optional<Long> getCumulativeGasUsed(final DataFetchingEnvironment environment) {
return getReceipt(environment).map(rpt -> rpt.getReceipt().getCumulativeGasUsed());
}
/**
* Retrieves the effective gas price of the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then
* returns an Optional containing the effective gas price of the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Wei object representing the effective gas price of the
* transaction.
*/
public Optional<Wei> getEffectiveGasPrice(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(rwm -> rwm.getTransaction().getEffectiveGasPrice(rwm.getBaseFee()));
}
/**
* Retrieves the blob gas used by the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then
* returns an Optional containing the blob gas used by the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Long object representing the blob gas used by the transaction.
*/
public Optional<Long> getBlobGasUsed(final DataFetchingEnvironment environment) {
return getReceipt(environment).flatMap(TransactionReceiptWithMetadata::getBlobGasUsed);
}
/**
* Retrieves the blob gas price of the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then
* returns an Optional containing the blob gas price of the transaction.
*
* @param environment the data fetching environment.
* @return an Optional containing a Wei object representing the blob gas price of the transaction.
*/
public Optional<Wei> getBlobGasPrice(final DataFetchingEnvironment environment) {
return getReceipt(environment).flatMap(TransactionReceiptWithMetadata::getBlobGasPrice);
}
/**
* Retrieves the contract created by the transaction.
*
* <p>This method checks if the transaction is a contract creation transaction. If it is, it
* retrieves the address of the created contract. It then uses the BlockchainQueries to get the
* block number and then retrieves the state of the created contract's account at the given block
* number.
*
* @param environment the data fetching environment.
* @return an Optional containing an AccountAdapter object representing the created contract's
* account state at the given block number, or an empty Optional if the transaction is not a
* contract creation transaction or if the block number is not specified.
*/
public Optional<AccountAdapter> getCreatedContract(final DataFetchingEnvironment environment) {
final boolean contractCreated = transactionWithMetadata.getTransaction().isContractCreation();
if (contractCreated) {
@ -208,6 +395,17 @@ public class TransactionAdapter extends AdapterBase {
return Optional.empty();
}
/**
* Retrieves the logs of the transaction.
*
* <p>This method uses the BlockchainQueries to get the block header and the receipt of the
* transaction. It then retrieves the logs of the transaction and adapts them into a format that
* can be used by GraphQL.
*
* @param environment the data fetching environment.
* @return a List of LogAdapter objects representing the logs of the transaction. If the
* transaction does not have a receipt, this method returns an empty list.
*/
public List<LogAdapter> getLogs(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final ProtocolSchedule protocolSchedule =
@ -240,14 +438,34 @@ public class TransactionAdapter extends AdapterBase {
return results;
}
/**
* Retrieves the R component of the transaction's signature.
*
* @return a BigInteger object representing the R component of the transaction's signature.
*/
public BigInteger getR() {
return transactionWithMetadata.getTransaction().getR();
}
/**
* Retrieves the S component of the transaction's signature.
*
* @return a BigInteger object representing the S component of the transaction's signature.
*/
public BigInteger getS() {
return transactionWithMetadata.getTransaction().getS();
}
/**
* Retrieves the V component of the transaction's signature.
*
* <p>If the transaction type is less than the BLOB transaction type and V is null, it returns the
* Y parity of the transaction. Otherwise, it returns V.
*
* @return an Optional containing a BigInteger object representing the V component of the
* transaction's signature, or an Optional containing the Y parity of the transaction if V is
* null and the transaction type is less than the BLOB transaction type.
*/
public Optional<BigInteger> getV() {
BigInteger v = transactionWithMetadata.getTransaction().getV();
return Optional.ofNullable(
@ -258,10 +476,22 @@ public class TransactionAdapter extends AdapterBase {
: v);
}
/**
* Retrieves the Y parity of the transaction's signature.
*
* @return an Optional containing a BigInteger object representing the Y parity of the
* transaction's signature.
*/
public Optional<BigInteger> getYParity() {
return Optional.ofNullable(transactionWithMetadata.getTransaction().getYParity());
}
/**
* Retrieves the access list of the transaction.
*
* @return a List of AccessListEntryAdapter objects representing the access list of the
* transaction.
*/
public List<AccessListEntryAdapter> getAccessList() {
return transactionWithMetadata
.getTransaction()
@ -270,12 +500,30 @@ public class TransactionAdapter extends AdapterBase {
.orElse(List.of());
}
/**
* Retrieves the raw transaction data.
*
* <p>This method uses the writeTo method of the transaction to write the transaction data to a
* BytesValueRLPOutput object. It then encodes the BytesValueRLPOutput object and returns it.
*
* @return an Optional containing a Bytes object representing the raw transaction data.
*/
public Optional<Bytes> getRaw() {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
transactionWithMetadata.getTransaction().writeTo(rlpOutput);
return Optional.of(rlpOutput.encoded());
}
/**
* Retrieves the raw receipt of the transaction.
*
* <p>This method uses the getReceipt method to get the receipt of the transaction. It then writes
* the receipt data to a BytesValueRLPOutput object using the writeToForNetwork method of the
* receipt. It then encodes the BytesValueRLPOutput object and returns it.
*
* @param environment the data fetching environment.
* @return an Optional containing a Bytes object representing the raw receipt of the transaction.
*/
public Optional<Bytes> getRawReceipt(final DataFetchingEnvironment environment) {
return getReceipt(environment)
.map(
@ -286,6 +534,11 @@ public class TransactionAdapter extends AdapterBase {
});
}
/**
* Retrieves the versioned hashes of the transaction.
*
* @return a List of VersionedHash objects representing the versioned hashes of the transaction.
*/
public List<VersionedHash> getBlobVersionedHashes() {
return transactionWithMetadata.getTransaction().getVersionedHashes().orElse(List.of());
}

@ -17,26 +17,60 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.plugin.data.Withdrawal;
/**
* The WithdrawalAdapter class provides methods to retrieve the withdrawal details.
*
* <p>This class is used to adapt a Withdrawal object into a format that can be used by GraphQL. The
* Withdrawal object is provided at construction time.
*
* <p>The class provides methods to retrieve the index, validator, address, and amount of the
* withdrawal.
*/
public class WithdrawalAdapter {
Withdrawal withdrawal;
/**
* Constructs a new WithdrawalAdapter object.
*
* @param withdrawal the Withdrawal object to adapt.
*/
public WithdrawalAdapter(final Withdrawal withdrawal) {
this.withdrawal = withdrawal;
}
/**
* Returns the index of the withdrawal.
*
* @return the index of the withdrawal.
*/
public Long getIndex() {
return withdrawal.getIndex().toLong();
}
/**
* Returns the validator of the withdrawal.
*
* @return the validator of the withdrawal.
*/
public Long getValidator() {
return withdrawal.getValidatorIndex().toLong();
}
/**
* Returns the address of the withdrawal.
*
* @return the address of the withdrawal.
*/
public Address getAddress() {
return withdrawal.getAddress();
}
/**
* Returns the amount of the withdrawal.
*
* @return the amount of the withdrawal.
*/
public Long getAmount() {
return withdrawal.getAmount().getAsBigInteger().longValue();
}

@ -19,30 +19,96 @@ import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonGetter;
/**
* Enum representing various types of GraphQL errors.
*
* <p>Each error is associated with a specific code and message. The code is an integer that
* uniquely identifies the error. The message is a string that provides a human-readable description
* of the error.
*
* <p>This enum includes standard errors such as INVALID_PARAMS and INTERNAL_ERROR, transaction
* validation failures such as NONCE_TOO_LOW and INVALID_TRANSACTION_SIGNATURE, and private
* transaction errors such as PRIVATE_TRANSACTION_FAILED and PRIVATE_NONCE_TOO_LOW.
*
* <p>The {@code of} method is used to map a {@code TransactionInvalidReason} to a corresponding
* {@code GraphQLError}.
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum GraphQLError {
// Standard errors
/** Error code -32602. This error occurs when the parameters provided are invalid. */
INVALID_PARAMS(-32602, "Invalid params"),
/** Error code -32603. This error occurs when there is an internal error. */
INTERNAL_ERROR(-32603, "Internal error"),
// Transaction validation failures
/** Error code -32001. This error occurs when the nonce value is too low. */
NONCE_TOO_LOW(-32001, "Nonce too low"),
/** Error code -32002. This error occurs when the transaction signature is invalid. */
INVALID_TRANSACTION_SIGNATURE(-32002, "Invalid signature"),
/** Error code -32003. This error occurs when the intrinsic gas exceeds the gas limit. */
INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"),
/**
* Error code -32004. This error occurs when the upfront cost of the transaction exceeds the
* account balance.
*/
TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"),
/**
* Error code -32005. This error occurs when the transaction gas limit exceeds the block gas
* limit.
*/
EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"),
/** Error code -32006. This error occurs when the nonce value is too high. */
INCORRECT_NONCE(-32006, "Nonce too high"),
/**
* Error code -32007. This error occurs when the sender account is not authorized to send
* transactions.
*/
TX_SENDER_NOT_AUTHORIZED(-32007, "Sender account not authorized to send transactions"),
/** Error code -32008. This error occurs when the initial sync is still in progress. */
CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"),
/**
* Error code -32009. This error occurs when the gas price is below the configured minimum gas
* price.
*/
GAS_PRICE_TOO_LOW(-32009, "Gas price below configured minimum gas price"),
/**
* Error code -32000. This error occurs when the Chain ID in the transaction signature is wrong.
*/
WRONG_CHAIN_ID(-32000, "Wrong Chain ID in transaction signature"),
/**
* Error code -32000. This error occurs when signatures with replay protection are not supported.
*/
REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED(
-32000, "Signatures with replay protection are not supported"),
/** Error code -32000. This error occurs when the transaction fee cap is exceeded. */
TX_FEECAP_EXCEEDED(-32000, "Transaction fee cap exceeded"),
// Private Transaction Errors
/** Error code -32000. This error occurs when a private transaction fails. */
PRIVATE_TRANSACTION_FAILED(-32000, "Private transaction failed"),
/**
* Error code -50100. This error occurs when the nonce value for a private transaction is too low.
*/
PRIVATE_NONCE_TOO_LOW(-50100, "Private transaction nonce too low"),
/**
* Error code -50100. This error occurs when the nonce value for a private transaction is
* incorrect.
*/
INCORRECT_PRIVATE_NONCE(-50100, "Private transaction nonce is incorrect");
private final int code;
@ -53,49 +119,52 @@ public enum GraphQLError {
this.message = message;
}
/**
* Returns the error code associated with this GraphQL error.
*
* @return the error code as an integer.
*/
@JsonGetter("code")
public int getCode() {
return code;
}
/**
* Returns the error message associated with this GraphQL error.
*
* @return the error message as a string.
*/
@JsonGetter("message")
public String getMessage() {
return message;
}
/**
* Maps a {@code TransactionInvalidReason} to a corresponding {@code GraphQLError}.
*
* <p>This method is used to convert a transaction invalid reason to a GraphQL error, which can be
* used to provide more detailed error information to the client.
*
* @param transactionInvalidReason the transaction invalid reason to be converted.
* @return the corresponding GraphQL error.
*/
public static GraphQLError of(final TransactionInvalidReason transactionInvalidReason) {
switch (transactionInvalidReason) {
case WRONG_CHAIN_ID:
return WRONG_CHAIN_ID;
case REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED:
return REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED;
case INVALID_SIGNATURE:
return INVALID_TRANSACTION_SIGNATURE;
case UPFRONT_COST_EXCEEDS_BALANCE:
return TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE;
case NONCE_TOO_LOW:
case PRIVATE_NONCE_TOO_LOW:
return NONCE_TOO_LOW;
case NONCE_TOO_HIGH:
case PRIVATE_NONCE_TOO_HIGH:
return INCORRECT_NONCE;
case INTRINSIC_GAS_EXCEEDS_GAS_LIMIT:
return INTRINSIC_GAS_EXCEEDS_LIMIT;
case EXCEEDS_BLOCK_GAS_LIMIT:
return EXCEEDS_BLOCK_GAS_LIMIT;
case TX_SENDER_NOT_AUTHORIZED:
return TX_SENDER_NOT_AUTHORIZED;
case CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE:
return CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE;
return switch (transactionInvalidReason) {
case WRONG_CHAIN_ID -> WRONG_CHAIN_ID;
case REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED -> REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED;
case INVALID_SIGNATURE -> INVALID_TRANSACTION_SIGNATURE;
case UPFRONT_COST_EXCEEDS_BALANCE -> TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE;
case NONCE_TOO_LOW, PRIVATE_NONCE_TOO_LOW -> NONCE_TOO_LOW;
case NONCE_TOO_HIGH, PRIVATE_NONCE_TOO_HIGH -> INCORRECT_NONCE;
case INTRINSIC_GAS_EXCEEDS_GAS_LIMIT -> INTRINSIC_GAS_EXCEEDS_LIMIT;
case EXCEEDS_BLOCK_GAS_LIMIT -> EXCEEDS_BLOCK_GAS_LIMIT;
case TX_SENDER_NOT_AUTHORIZED -> TX_SENDER_NOT_AUTHORIZED;
case CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE -> CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE;
// Private Transaction Invalid Reasons
case PRIVATE_TRANSACTION_FAILED:
return PRIVATE_TRANSACTION_FAILED;
case GAS_PRICE_TOO_LOW:
return GAS_PRICE_TOO_LOW;
case TX_FEECAP_EXCEEDED:
return TX_FEECAP_EXCEEDED;
default:
return INTERNAL_ERROR;
}
case PRIVATE_TRANSACTION_FAILED -> PRIVATE_TRANSACTION_FAILED;
case GAS_PRICE_TOO_LOW -> GAS_PRICE_TOO_LOW;
case TX_FEECAP_EXCEEDED -> TX_FEECAP_EXCEEDED;
default -> INTERNAL_ERROR;
};
}
}

@ -16,12 +16,26 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.response;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Represents a GraphQL error response. This class extends the GraphQLResponse class and overrides
* the getType method to return ERROR.
*/
public class GraphQLErrorResponse extends GraphQLResponse {
/**
* Constructs a new GraphQLErrorResponse with the specified errors.
*
* @param errors the errors to be included in the response.
*/
public GraphQLErrorResponse(final Object errors) {
super(errors);
}
/**
* Returns the type of this GraphQL response.
*
* @return GraphQLResponseType.ERROR, indicating that this is an error response.
*/
@Override
@JsonIgnore
public GraphQLResponseType getType() {

@ -19,36 +19,77 @@ import java.util.Map;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonSetter;
/**
* This class represents a GraphQL JSON request.
*
* <p>It contains the query, operation name, and variables for a GraphQL request. The query is a
* string that represents the GraphQL query. The operation name is a string that represents the
* operation to be performed. The variables is a map that contains the variables for the GraphQL
* query.
*/
public class GraphQLJsonRequest {
private String query;
private String operationName;
private Map<String, Object> variables;
/** Default constructor for GraphQLJsonRequest. */
public GraphQLJsonRequest() {}
/**
* Gets the query of the GraphQL request.
*
* @return the query of the GraphQL request.
*/
@JsonGetter
public String getQuery() {
return query;
}
/**
* Sets the query of the GraphQL request.
*
* @param query the query of the GraphQL request.
*/
@JsonSetter
public void setQuery(final String query) {
this.query = query;
}
/**
* Gets the operation name of the GraphQL request.
*
* @return the operation name of the GraphQL request.
*/
@JsonGetter
public String getOperationName() {
return operationName;
}
/**
* Sets the operation name of the GraphQL request.
*
* @param operationName the operation name of the GraphQL request.
*/
@JsonSetter
public void setOperationName(final String operationName) {
this.operationName = operationName;
}
/**
* Gets the variables of the GraphQL request.
*
* @return the variables of the GraphQL request.
*/
@JsonGetter
public Map<String, Object> getVariables() {
return variables;
}
/**
* Sets the variables of the GraphQL request.
*
* @param variables the variables of the GraphQL request.
*/
@JsonSetter
public void setVariables(final Map<String, Object> variables) {
this.variables = variables;

@ -14,8 +14,20 @@
*/
package org.hyperledger.besu.ethereum.api.graphql.internal.response;
/**
* This class represents a GraphQL response with no content.
*
* <p>It extends the GraphQLResponse class and overrides the getType method to return
* GraphQLResponseType.NONE.
*/
public class GraphQLNoResponse extends GraphQLResponse {
/**
* Default constructor for GraphQLNoResponse.
*
* <p>It calls the parent constructor with null as the argument, indicating no content for this
* response.
*/
public GraphQLNoResponse() {
super(null);
}

@ -16,15 +16,35 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.response;
import java.util.Objects;
/**
* Represents a GraphQL response. This abstract class provides a structure for different types of
* GraphQL responses.
*/
public abstract class GraphQLResponse {
public abstract GraphQLResponseType getType();
private final Object result;
/**
* Constructs a new GraphQLResponse with the specified result.
*
* @param result the result to be included in the response.
*/
GraphQLResponse(final Object result) {
this.result = result;
}
/**
* Returns the type of this GraphQL response.
*
* @return the type of this GraphQL response as a GraphQLResponseType.
*/
public abstract GraphQLResponseType getType();
/**
* Returns the result of this GraphQL response.
*
* @return the result of this GraphQL response as an Object.
*/
public Object getResult() {
return result;
}

@ -16,8 +16,15 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.response;
/** Various types of responses that the JSON-RPC component may produce. */
public enum GraphQLResponseType {
/** Represents a response type where there is no content. */
NONE,
/** Represents a successful response type. */
SUCCESS,
/** Represents an error response type. */
ERROR,
/** Represents an unauthorized response type. */
UNAUTHORIZED
}

@ -16,12 +16,33 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.response;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* This class represents a successful GraphQL response.
*
* <p>It extends the GraphQLResponse class and overrides the getType method to return
* GraphQLResponseType.SUCCESS.
*/
public class GraphQLSuccessResponse extends GraphQLResponse {
/**
* Constructor for GraphQLSuccessResponse.
*
* <p>It calls the parent constructor with the provided data as the argument.
*
* @param data the data to be included in the successful response.
*/
public GraphQLSuccessResponse(final Object data) {
super(data);
}
/**
* Returns the type of the GraphQL response.
*
* <p>This method is overridden to return GraphQLResponseType.SUCCESS, indicating a successful
* response.
*
* @return GraphQLResponseType.SUCCESS
*/
@Override
@JsonIgnore
public GraphQLResponseType getType() {

@ -55,6 +55,11 @@ public final class MockNetwork {
private final Map<Peer, MockNetwork.MockP2PNetwork> nodes = new HashMap<>();
private final List<Capability> capabilities;
/**
* Constructs a new MockNetwork with the specified capabilities.
*
* @param capabilities a list of capabilities that the mock network should have.
*/
public MockNetwork(final List<Capability> capabilities) {
this.capabilities = capabilities;
}

Loading…
Cancel
Save