-
Notifications
You must be signed in to change notification settings - Fork 6
RPC Queries
A query request is simply a command which can be sent to the official Nano node through RPC commands. Requests can be used for changing the state of a node or it's configured wallets, or for obtaining information from it about its current status or retrieving the block details from the ledger.
Requests are first serialized into the relevant JSON syntax and then sent over the HTTP protocol to the specified node address and port. From here the node will execute the command and feedback any necessary information as a response, which is then deserialized into the appropriate class.
Note: If you're using an external or public RPC service, consider reading the section on third-party services.
View the official Nano documentation for further detailed information on node configuration.
In order to make RPC requests, the external node needs to be correctly configured to accept and listen for them. To do this, you will need to open the following configuration files in the node's local working directory:
-
config-node.toml
:-
rpc.enable
must be set totrue
in order for the node to accept RPC commands
-
-
config-rpc.toml
:-
address
should be set to the network the RPC sever should bind to — for local connections, use::1
-
port
is the port which the RPC server binds to — default is7076
-
enable_control
needs to be set totrue
if you wish to use the control commands
-
Use the RpcQueryNode class to specify a remote node which accepts RPC requests and handles all requests. Each instance represents a different node endpoint (ip/port), allowing your program to operate with multiple nodes if necessary. If an IP address and port are not specified, then the library will default to using localhost on port 7076.
To specify a request and parameters, use one of the available pre-defined classes listed in the lookup table at the bottom of this page, or create your own for unsupported operations or custom nodes.
Interacting with the node, the ledger and its wallets is a relatively simple process. The following sample sends a request to the node to create a new account from a given seed and index.
try {
// Configure a connection to localhost:7076
RpcQueryNode rpc = new RpcQueryNode();
// Construct the request and arguments
RequestBlockInfo req = new RequestBlockInfo(
"B3B23FD0AB8B6E440953D443402EEE14BC7A3A1E3F71D60C43D001587EAD80F7");
// Process the query
ResponseBlockInfo info = rpc.processRequest(req);
// Handle/print retrieved information
System.out.println("Amount: " + info.getAmount());
System.out.println("Type: " + info.getContents().getType());
System.out.println("Height: " + info.getHeight());
} catch (RpcException | IOException e) {
e.printStackTrace();
}
This outputs the following text to the console:
Amount: 15.628446… Nano
Type: state
Height: 525576
You can also make asynchronous requests to the node, which will prevent the called thread from locking up by utilizing a thread pool and callbacks. The following example code queries the balance of the specified account, and prints it to the console:
// Configure a connection to localhost:7076
RpcQueryNode rpc = new RpcQueryNode();
// Construct the request and arguments
RequestAccountBalance req = new RequestAccountBalance(
"nano_3x4ui45q1cw8hydmfdn4ec5ijsdqi4ryp14g4ayh71jcdkwmddrq7ca9xzn9");
// Process the request and define callback as anonymous class
rpc.processRequestAsync(req, new QueryCallback<>() {
@Override
public void onResponse(ResponseBalance response, RequestAccountBalance request) {
// Print the balance
System.out.println("Account balance: " + response.getTotal());
}
@Override
public void onFailure(RpcException ex, RequestAccountBalance request) {
ex.printStackTrace();
}
@Override
public void onFailure(IOException ex, RequestAccountBalance request) {
ex.printStackTrace();
}
});
This gives the following response output in the console:
Account balance: 12,888,717.767914… Nano
You can also retrieve a Future
object from the call, like so:
Future<ResponseVersion> versionRes = node.processRequestAsync(new RequestVersion());
// ... elsewhere in your program ...
if (versionRes.isDone()) {
ResponseVersion ver = versionRes.get();
System.out.println("Node version: " + ver.getNodeVendor());
}
A range of pre-defined public RPC providers are available in the RpcServiceProviders
class through static methods. These offer additional parsing of their own special exception messages and allow you to easily provide any API keys.
If you want to perform wallet-related actions when using an untrusted or unsafe RPC service, you should consider using the LocalRpcWalletAccount
class. This allows you to send and receive funds without exposing the private key to the node, as all blocks are created and signed locally. Consider the example code below:
RpcQueryNode rpcClient = RpcServiceProviders.nanex(); // Use nanex.cc public RPC API
// Construct a block producer object with your configuration
BlockProducer blockProducer = new StateBlockProducer(
BlockProducerSpecification.builder()
.defaultRepresentative("nano_3caprkc56ebsaakn4j4n7g9p8h358mycfjcyzkrfw1nai6prbyk8ihc5yjjk")
.workGenerator(new NodeWorkGenerator(rpcClient)) // Generate work on the node
.build()
);
// Create account from private key
LocalRpcWalletAccount account = new LocalRpcWalletAccount(
new HexData("183A1DEDCA9CD37029456C8A2ED31460A0E9A8D18032676010AC11B02A442417"), // Private key
rpcClient, blockProducer); // Using the RPC client and BlockProducer defined above
// Print account info
System.out.printf("Using account address %s%n", account.getAccount());
System.out.printf("Initial balance: %s%n", account.getBalance());
// Receive all pending funds
System.out.printf("Received %,d blocks%n", account.receiveAll().size());
System.out.printf("Balance: %s%n", account.getBalance());
// Send funds to another account
System.out.printf("Send block hash: %s%n", account.send(
NanoAccount.parseAddress("nano_34qjpc8t1u6wnb584pc4iwsukwa8jhrobpx4oea5gbaitnqafm6qsgoacpiz"),
NanoAmount.valueOfNano("0.01"))
.getHash());
The below table contains a list of supported RPC exceptions that are automatically parsed and thrown. While these can be helpful, the actual exception class thrown should not be relied upon for any critical components of your program due to inconsistencies in the error response from the node. In cases where the appropriate exception category cannot be parsed, an RpcUnrecognizedException
will be thrown.
Exception class | Description |
---|---|
RpcException Base exception class |
The default superclass RPC exception, thrown if there is an error with the query or node. |
RpcExternalException |
Base exception for errors returned by the node. |
RpcInvalidArgumentException |
Thrown if one of the given request arguments are not valid. |
RpcEntityNotFoundException |
Thrown if one of the referenced entities (eg. account, wallet, block hash) do not exist. |
RpcWalletLockedException |
Thrown when a query needs access to a wallet which is currently locked. |
RpcConfigForbiddenException |
Thrown if a requested command is disallowed due to a configuration option on the node. You will need to change the relevant settings in the node's configuration. |
RpcFeatureDisabledException Extends RpcConfigForbiddenException
|
Thrown if a requested command requires a feature which is disabled on the node. You will need to change the relevant settings in the node's configuration. |
RpcControlDisabledException Extends RpcFeatureDisabledException
|
Thrown when a request needs control access (which isn't enabled on the node). Refer to configuration section above to change this. |
RpcCommandNotAllowedException Extends RpcFeatureDisabledException
|
Thrown when a request command is blocked. These could be unsafe commands available only on the beta network, or blocked commands from a third-party node gateway. |
RpcRequestCancelledException |
Thrown if a request was cancelled before it could be completed (eg. work generation request through work_cancel ). |
RpcInvalidRequestJsonException |
Thrown if the node was unable to parse the sent request. Ensure you are using the right version of jNano for the node version you are using. |
RpcUnknownCommandException |
Thrown if the node does not understand the request command. Ensure you are using the right version of jNano for the node version you are using. |
RpcInternalException |
Thrown if the node encounters an internal error. |
RpcUnrecognizedException |
Thrown if the underlying exception type, category or details could not be determined. |
RpcInvalidResponseException |
Thrown if the node returns an invalid JSON response. Ensure you are using the right version of jNano for the node version you are using. |
Below is a list of request and response commands currently supported by jNano. Request classes are located in the uk.oczadly.karl.jnano.rpc.request.{category}
packages, and response classes are in the uk.oczadly.karl.jnano.rpc.response
package.
For more information on commands, view the official Nano RPC documentation.