package com.msgilligan.bitcoinj.rpc; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.msgilligan.bitcoinj.json.conversion.HexUtil; import com.msgilligan.bitcoinj.json.pojo.AddressGroupingItem; import com.msgilligan.bitcoinj.json.pojo.BlockChainInfo; import com.msgilligan.bitcoinj.json.pojo.BlockInfo; import com.msgilligan.bitcoinj.json.pojo.ChainTip; import com.msgilligan.bitcoinj.json.pojo.NetworkInfo; import com.msgilligan.bitcoinj.json.pojo.Outpoint; import com.msgilligan.bitcoinj.json.pojo.RawTransactionInfo; import com.msgilligan.bitcoinj.json.pojo.ReceivedByAddressInfo; import com.msgilligan.bitcoinj.json.pojo.ServerInfo; import com.msgilligan.bitcoinj.json.pojo.SignedRawTransaction; import com.msgilligan.bitcoinj.json.pojo.TxOutInfo; import com.msgilligan.bitcoinj.json.pojo.UnspentOutput; import com.msgilligan.bitcoinj.json.conversion.RpcClientModule; import com.msgilligan.bitcoinj.json.pojo.WalletTransactionInfo; import org.bitcoinj.core.Address; import org.bitcoinj.core.Block; import org.bitcoinj.core.Coin; import org.bitcoinj.core.Context; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Transaction; import org.bitcoinj.params.RegTestParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.EOFException; import java.io.IOException; import java.net.SocketException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * = JSON-RPC Client for *Bitcoin Core* * * A strongly-typed wrapper for the * https://bitcoin.org/en/developer-reference#bitcoin-core-apis[Bitcoin Core JSON-RPC API]. * https://bitcoinj.github.io[bitcoinj] types are used where appropriate. * For example, requesting a block hash will return a {@link org.bitcoinj.core.Sha256Hash}: * * [source,java] * -- * Sha256Hash hash = client.getBlockHash(342650); * -- * * Requesting a Bitcoin balance will return the amount as a {@link org.bitcoinj.core.Coin}: * [source,java] * -- * Coin balance = client.getBalance(); * -- * * This version is written to be compatible with Bitcoin Core 0.10.4 and later. If used with * Omni Core (an enhanced Bitcoin Core with Omni Protocol support) Omni Core 0.0.11.1 * or later is required. * * NOTE: This is still a work-in-progress and the API will change. * */ public class BitcoinClient extends RPCClient implements NetworkParametersProperty { private static final Logger log = LoggerFactory.getLogger(BitcoinClient.class); private static final int SECOND_IN_MSEC = 1000; private static final int RETRY_SECONDS = 1; private static final int MESSAGE_SECONDS = 10; private int serverVersion = 0; // 0 means unknown serverVersion protected final Context context; /** * Construct a BitcoinClient from URI, user name, and password. * @param server URI of the Bitcoin RPC server * @param rpcuser Username (if required) * @param rpcpassword Password (if required) * @deprecated You need to specify NetworkParameters, this constructor defaults to RegTest * @see BitcoinClient#BitcoinClient(NetworkParameters, URI, String, String) */ @Deprecated public BitcoinClient(URI server, String rpcuser, String rpcpassword) { this(RegTestParams.get(), server, rpcuser, rpcpassword); } /** * Construct a BitcoinClient from Network Parameters, URI, user name, and password. * @param netParams Correct Network Parameters for destination server * @param server URI of the Bitcoin RPC server * @param rpcuser Username (if required) * @param rpcpassword Password (if required) */ public BitcoinClient(NetworkParameters netParams, URI server, String rpcuser, String rpcpassword) { super(server, rpcuser, rpcpassword); this.context = new Context(netParams); mapper.registerModule(new RpcClientModule(context.getParams())); } /** * Construct a BitcoinClient from an RPCConfig data object. * @param config Contains URI, user name, and password */ public BitcoinClient(RPCConfig config) { this(config.getNetParams(), config.getURI(), config.getUsername(), config.getPassword()); } /** * Get network parameters * @return network parameters for the server */ @Override public NetworkParameters getNetParams() { return context.getParams(); } /** * Get a (cached after first call) serverVersion number * @return serverVersion number of bitcoin node * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ private int getServerVersion() throws IOException, JsonRPCStatusException { if (serverVersion == 0) { serverVersion = getNetworkInfo().getVersion(); } return serverVersion; } /** * Wait until the server is available. * * Keep trying, ignoring (and logging) a known list of exception conditions that may occur while waiting for * a `bitcoind` server to start up. This is similar to the behavior enabled by the `-rpcwait` * option to the `bitcoin-cli` command-line tool. * * @param timeout Timeout in seconds * @return true if ready, false if timeout */ public Boolean waitForServer(int timeout) throws JsonRPCException { log.debug("Waiting for server RPC ready..."); String status; // Status message for logging String statusLast = null; int seconds = 0; while (seconds < timeout) { try { Integer block = this.getBlockCount(); if (block != null) { log.debug("RPC Ready."); return true; } status = "getBlock returned null"; } catch (SocketException se) { // These are expected exceptions while waiting for a server if (se.getMessage().equals("Unexpected end of file from server") || se.getMessage().equals("Connection reset") || se.getMessage().equals("Connection refused") || se.getMessage().equals("recvfrom failed: ECONNRESET (Connection reset by peer)")) { status = se.getMessage(); } else { throw new JsonRPCException("Unexpected exception in waitForServer", se) ; } } catch (EOFException ignored) { /* Android exception, ignore */ // Expected exceptions on Android, RoboVM status = ignored.getMessage(); } catch (IOException e) { status = e.getMessage(); } catch (JsonRPCStatusException e) { // If server is in "warm-up" mode, e.g. validating/parsing the blockchain... if (e.jsonRPCCode == -28) { // ...then grab text message for status logging status = e.getMessage(); } else { throw e; } } try { // Log status messages only once, if new or updated if (!status.equals(statusLast)) { log.info("RPC Status: " + status); statusLast = status; } Thread.sleep(RETRY_SECONDS * SECOND_IN_MSEC); seconds += RETRY_SECONDS; } catch (InterruptedException e) { log.error(e.toString()); } } log.error("waitForServer() timed out after {} seconds.", timeout); return false; } /** * Wait for RPC server to reach specified block height. * * @param blockHeight Block height to wait for * @param timeout Timeout in seconds * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error * @return True if blockHeight reached, false if timeout */ public Boolean waitForBlock(int blockHeight, int timeout) throws JsonRPCStatusException, IOException { log.info("Waiting for server to reach block " + blockHeight); int seconds = 0; while (seconds < timeout) { Integer block = this.getBlockCount(); if (block >= blockHeight) { log.info("Server is at block " + block + " returning 'true'."); return true; } else { try { if (seconds % MESSAGE_SECONDS == 0) { log.debug("Server at block " + block); } Thread.sleep(RETRY_SECONDS * SECOND_IN_MSEC); seconds += RETRY_SECONDS; } catch (InterruptedException e) { log.error(e.toString()); } } } log.error("Timeout waiting for block " + blockHeight); return false; } /** * Returns the number of blocks in the longest block chain. * * @return The current block count * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Integer getBlockCount() throws JsonRPCStatusException, IOException { return send("getblockcount"); } /** * Returns the hash of block in best-block-chain at index provided. * * @param index The block index * @return The block hash * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Sha256Hash getBlockHash(Integer index) throws JsonRPCStatusException, IOException { return send("getblockhash", Sha256Hash.class, index); } /** * Returns information about a block with the given block hash. * * @param hash The block hash * @return The information about the block * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public BlockInfo getBlockInfo(Sha256Hash hash) throws JsonRPCStatusException, IOException { // Use "verbose = true" return send("getblock", BlockInfo.class, hash, true); } public Block getBlock(Sha256Hash hash) throws JsonRPCStatusException, IOException { // Use "verbose = false" return send("getblock", Block.class, hash, false); } /** * Returns information about a block at index provided. * * @param index The block index * @return The information about the block * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Block getBlock(Integer index) throws JsonRPCStatusException, IOException { Sha256Hash blockHash = getBlockHash(index); return getBlock(blockHash); } /** * Turn generation on/off * * Note: `setgenerate` has been removed from regtest mode in recent Bitcoin Core, as `generate` * should be used instead) * * @param generate turn generation on or off * @param genproclimit Generation is limited to [genproclimit] processors, -1 is unlimited * @return List<Sha256Hash> list containing block header hashes of the generated blocks or empty list * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error * */ public List<Sha256Hash> setGenerate(Boolean generate, Long genproclimit) throws JsonRPCStatusException, IOException { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, Sha256Hash.class); return send("setgenerate", resultType, generate, genproclimit); } /** * generate blocks (RegTest mode only) * @since Bitcoin Core 0.11.0 * * @param numBlocks number of blocks to generate * @return list containing block header hashes of the generated blocks * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<Sha256Hash> generate(int numBlocks) throws JsonRPCStatusException, IOException { if (getServerVersion() > 110000) { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, Sha256Hash.class); return send("generate", resultType, numBlocks); } else { // For backward compatibility, to be removed eventually return setGenerate(true, (long) numBlocks); } } /** * Convenience method for generating a single block when in RegTest mode * @see BitcoinClient#generate(int numBlocks) */ public List<Sha256Hash> generate() throws IOException, JsonRPCStatusException { return generate(1); } /** * Convenience method for generating a single block when in RegTest mode * @deprecated Use BitcoinClient#generate() * @see BitcoinClient#generate() */ // the Deprecated annotation was causing Groovy in OmniJ to do // something weird (like not find the method), // I can't remember exactly what it was -- try adding it back as part // of testing for release 0.2.2 @Deprecated public List<Sha256Hash> generateBlock() throws JsonRPCStatusException, IOException { return generate(); } /** * Convenience method for generating blocks when in RegTest mode * * @param blocks number of blocks to generate * @deprecated Use BitcoinClient#generate(int) * @see BitcoinClient#generate(int) */ @Deprecated public List<Sha256Hash> generateBlocks(Long blocks) throws JsonRPCStatusException, IOException { return generate(blocks.intValue()); } /** * Creates a new Bitcoin address for receiving payments, linked to the default account "". * * @return A new Bitcoin address * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Address getNewAddress() throws JsonRPCStatusException, IOException { return getNewAddress(null); } /** * Creates a new Bitcoin address for receiving payments. * * @param account The account name for the address to be linked to. * @return A new Bitcoin address * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Address getNewAddress(String account) throws JsonRPCStatusException, IOException { return send("getnewaddress", Address.class, account); } /** * Returns the Bitcoin address linked to the given account. * * @param account The account name linked to the address. * @return The Bitcoin address * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Address getAccountAddress(String account) throws JsonRPCStatusException, IOException { return send("getaccountaddress", Address.class, account); } /** * Return the private key from the server. * * Note: must be in wallet mode with unlocked or unencrypted wallet. * * @param address Address corresponding to the private key to return * @return The private key * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public ECKey dumpPrivKey(Address address) throws JsonRPCStatusException, IOException { return send("dumpprivkey", ECKey.class, address); } /** * Move a specified amount from one account in your wallet to another. * * @param fromaccount The name of the account to move funds from, which may be the default account using "" * @param toaccount The name of the account to move funds to, which may be the default account using "" * @param amount The amount to move * @param minconf Only use funds with at least this many confirmations * @param comment An optional comment, stored in the wallet only * @return True, if successful, and false otherwise * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Boolean moveFunds(Address fromaccount, Address toaccount, Coin amount, Integer minconf, String comment) throws JsonRPCStatusException, IOException { return send("move", fromaccount, toaccount, amount, minconf, comment); } /** * Creates a raw transaction spending the given inputs to the given destinations. * * Note: the transaction inputs are not signed, and the transaction is not stored in the wallet or transmitted to * the network. * * @param inputs The outpoints to spent * @param outputs The destinations and amounts to transfer * @return The hex-encoded raw transaction * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public String createRawTransaction(List<Outpoint> inputs, Map<Address, Coin> outputs) throws JsonRPCStatusException, IOException { return send("createrawtransaction", inputs, outputs); } /** * Signs inputs of a raw transaction. * * @param unsignedTransaction The hex-encoded raw transaction * @return The signed transaction and information whether it has a complete set of signature * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public SignedRawTransaction signRawTransaction(String unsignedTransaction) throws JsonRPCStatusException, IOException { return send("signrawtransaction", SignedRawTransaction.class, unsignedTransaction); } /** * Get raw transaction info as hex->bitcoinj or verbose (json->POJO) * @param txid Transaction ID/hash * @param verbose `true` to return JSON transaction * @return RawTransactionInfo if verbose, otherwise Transaction * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error * @deprecated Use getRawTransaction or getRawTransactionInfo as appropriate */ @Deprecated public Object getRawTransaction(Sha256Hash txid, Boolean verbose) throws JsonRPCStatusException, IOException { Object result; if (verbose) { result = getRawTransactionInfo(txid); // Verbose means JSON } else { result = getRawTransaction(txid); // Not-verbose is bitcoinj Transaction } return result; } /** * Get a "raw" transaction (which we map to a bitcoinj transaction) * @param txid Transaction ID/hash * @return bitcoinj Transaction * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Transaction getRawTransaction(Sha256Hash txid) throws JsonRPCStatusException, IOException { String hexEncoded = send("getrawtransaction", txid); byte[] raw = HexUtil.hexStringToByteArray(hexEncoded); return new Transaction(context.getParams(), raw); } /** * Get a "raw" transaction as JSON (which we map to a RawTransactionInfo POJO) * @param txid Transaction ID/hash * @return RawTransactionInfo POJO * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public RawTransactionInfo getRawTransactionInfo(Sha256Hash txid) throws JsonRPCStatusException, IOException { return send("getrawtransaction", RawTransactionInfo.class, txid, 1); } public Sha256Hash sendRawTransaction(Transaction tx) throws JsonRPCStatusException, IOException { return sendRawTransaction(tx, null); } public Sha256Hash sendRawTransaction(String hexTx) throws JsonRPCStatusException, IOException { return sendRawTransaction(hexTx, null); } public Sha256Hash sendRawTransaction(Transaction tx, Boolean allowHighFees) throws JsonRPCStatusException, IOException { return send("sendrawtransaction", Sha256Hash.class, tx, allowHighFees); } public Sha256Hash sendRawTransaction(String hexTx, Boolean allowHighFees) throws JsonRPCStatusException, IOException { return send("sendrawtransaction", Sha256Hash.class, hexTx, allowHighFees); } public Coin getReceivedByAddress(Address address) throws JsonRPCStatusException, IOException { return getReceivedByAddress(address, 1); // Default to 1 or more confirmations } /** * get total amount received by an address. * * @param address Address to query * @param minConf minimum number of confirmations * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Coin getReceivedByAddress(Address address, Integer minConf) throws JsonRPCStatusException, IOException { return send("getreceivedbyaddress", Coin.class, address, minConf); } public List<ReceivedByAddressInfo> listReceivedByAddress(Integer minConf, Boolean includeEmpty) throws JsonRPCStatusException, IOException { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, ReceivedByAddressInfo.class); return send("listreceivedbyaddress", resultType, minConf, includeEmpty); } /** * Returns a list of unspent transaction outputs with at least one confirmation. * * @return The unspent transaction outputs * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<UnspentOutput> listUnspent() throws JsonRPCStatusException, IOException { return listUnspent(null, null, null); } /** * Returns a list of unspent transaction outputs with at least {@code minConf} and not more than {@code maxConf} * confirmations. * * @param minConf The minimum confirmations to filter * @param maxConf The maximum confirmations to filter * @return The unspent transaction outputs * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf) throws JsonRPCStatusException, IOException { return listUnspent(minConf, maxConf, null); } /** * Returns a list of unspent transaction outputs with at least {@code minConf} and not more than {@code maxConf} * confirmations, filtered by a list of addresses. * * @param minConf The minimum confirmations to filter * @param maxConf The maximum confirmations to filter * @param filter Include only transaction outputs to the specified addresses * @return The unspent transaction outputs * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf, Iterable<Address> filter) throws JsonRPCStatusException, IOException { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, UnspentOutput.class); return send("listunspent", resultType, minConf, maxConf, filter); } /** * Returns details about an unspent transaction output. * * @param txid The transaction hash * @param vout The transaction output index * @return Details about an unspent output or nothing, if the output was already spent * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public TxOutInfo getTxOut(Sha256Hash txid, Integer vout) throws JsonRPCStatusException, IOException { return getTxOut(txid, vout, null); } /** * Returns details about an unspent transaction output. * * @param txid The transaction hash * @param vout The transaction output index * @param includeMemoryPool Whether to included the memory pool * @return Details about an unspent output or nothing, if the output was already spent * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public TxOutInfo getTxOut(Sha256Hash txid, Integer vout, Boolean includeMemoryPool) throws JsonRPCStatusException, IOException { return send("gettxout", TxOutInfo.class, txid, vout, includeMemoryPool); } /** * Get the balance for a the default Bitcoin "account" * * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Coin getBalance() throws JsonRPCStatusException, IOException { return getBalance(null, null); } /** * Get the balance for a Bitcoin "account" * * @param account A Bitcoin "account". (Be wary of using this feature.) * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Coin getBalance(String account) throws JsonRPCStatusException, IOException { return getBalance(account, null); } /** * Get the balance for a Bitcoin "account" * * @param account A Bitcoin "account". (Be wary of using this feature.) * @param minConf minimum number of confirmations * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Coin getBalance(String account, Integer minConf) throws JsonRPCStatusException, IOException { return send("getbalance", Coin.class, account, minConf); } public Sha256Hash sendToAddress(Address address, Coin amount) throws JsonRPCStatusException, IOException { return sendToAddress(address, amount, null, null); } public Sha256Hash sendToAddress(Address address, Coin amount, String comment, String commentTo) throws JsonRPCStatusException, IOException { return send("sendtoaddress", Sha256Hash.class, address, amount, comment, commentTo); } public Sha256Hash sendFrom(String account, Address address, Coin amount) throws JsonRPCStatusException, IOException { return send("sendfrom", Sha256Hash.class, account, address, amount); } public Sha256Hash sendMany(String account, Map<Address, Coin> amounts) throws JsonRPCStatusException, IOException { return send("sendmany", Sha256Hash.class, account, amounts); } /** * Set the transaction fee per kB. * * @param amount The transaction fee in BTC/kB rounded to the nearest 0.00000001. * @return True if successful * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Boolean setTxFee(Coin amount) throws JsonRPCStatusException, IOException { return send("settxfee", amount); } public WalletTransactionInfo getTransaction(Sha256Hash txid) throws JsonRPCStatusException, IOException { return send("gettransaction", WalletTransactionInfo.class, txid); } /** * Deprecated getinfo function * * Use GetBlockChainInfo and other alternatives instead * * @return Structure with various info fields * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ @Deprecated public ServerInfo getInfo() throws JsonRPCStatusException, IOException { return send("getinfo", ServerInfo.class); } /** * The getblockchaininfo RPC provides information about the current state of the block chain. * * @return An object containing information about the current state of the block chain. * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public BlockChainInfo getBlockChainInfo() throws JsonRPCStatusException, IOException { return send("getblockchaininfo", BlockChainInfo.class); } /** * The getnetworkinfo RPC returns information about the node’s connection to the network. * * @return information about the node’s connection to the network * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public NetworkInfo getNetworkInfo() throws JsonRPCStatusException, IOException { return send("getnetworkinfo", NetworkInfo.class); } /** * Returns list of related addresses * Also useful for finding all change addresses in the wallet * @return a lost of address groupings * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<List<AddressGroupingItem>> listAddressGroupings() throws JsonRPCStatusException, IOException { // TODO: I'm not sure how to make Jackson mapping work automatically here. List<List<List<Object>>> raw = send("listaddressgroupings"); List<List<AddressGroupingItem>> result = new ArrayList<>(); for (List<List<Object>> rawGrouping : raw) { List<AddressGroupingItem> grouping = new ArrayList<>(); for (List<Object> addressItem : rawGrouping) { AddressGroupingItem item = new AddressGroupingItem(addressItem, getNetParams()); grouping.add(item); } result.add(grouping); } return result; } /** * Returns a human readable list of available commands. * <p> * Bitcoin Core 0.9 returns an alphabetical list of commands, and Bitcoin Core 0.10 returns a categorized list of * commands. * * @return The list of commands as string * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public String help() throws JsonRPCStatusException, IOException { return help(null); } /** * Returns helpful information for a specific command. * * @param command The name of the command to get help for * @return The help text * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public String help(String command) throws JsonRPCStatusException, IOException { return send("help", command); } /** * Returns a list of available commands. * * Commands which are unavailable will not be listed, such as wallet RPCs, if wallet support is disabled. * * @return The list of commands * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<String> getCommands() throws JsonRPCStatusException, IOException { List<String> commands = new ArrayList<String>(); for (String entry : help().split("\n")) { if (!entry.isEmpty() && !entry.matches("== (.+) ==")) { String command = entry.split(" ")[0]; commands.add(command); } } return commands; } /** * Checks whether a command exists. * * This is done indirectly, by using {help(String) help} to get information about the command, and if information * about the command is available, then the command exists. The absence of information does not necessarily imply * the non-existence of a command. * * @param command The name of the command to check * @return True if the command exists * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public Boolean commandExists(String command) throws JsonRPCStatusException, IOException { return !help(command).contains("help: unknown command"); } /** * Permanently marks a block as invalid, as if it violated a consensus rule. * * @param hash The block hash * @since Bitcoin Core 0.10 * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public void invalidateBlock(Sha256Hash hash) throws JsonRPCStatusException, IOException { send("invalidateblock", hash); } /** * Removes invalidity status of a block and its descendants, reconsider them for activation. * <p> * This can be used to undo the effects of {link invalidateBlock(Sha256Hash) invalidateBlock}. * * @param hash The hash of the block to reconsider * @since Bitcoin Core 0.10 * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public void reconsiderBlock(Sha256Hash hash) throws JsonRPCStatusException, IOException { send("reconsiderblock", hash); } /** * Return information about all known tips in the block tree, including the main chain as well as orphaned branches. * * @return A list of chain tip information * @since Bitcoin Core 0.10 * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<ChainTip> getChainTips() throws JsonRPCStatusException, IOException { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, ChainTip.class); return send("getchaintips",resultType); } /** * Attempt to add or remove a node from the addnode list, or to try a connection to a node once. * * @param node node to add as a string in the form of <IP address>:<port> * @param command `add`, `remove`, or `onetry` * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public void addNode(String node, String command) throws JsonRPCStatusException, IOException { send("addnode", node, command); } /** * Return information about the given added node * * @param details `true` to return detailed information * @param node the node to provide information about * @return A Jackson JsonNode object (until we define a POJO) * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public JsonNode getAddedNodeInfo(boolean details, String node) throws JsonRPCStatusException, IOException { return send("getaddednodeinfo", JsonNode.class, details, node); } /** * Return information about all added nodes * * @param details `true` to return detailed information * @return A Jackson JsonNode object (until we define a POJO) * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public JsonNode getAddedNodeInfo(boolean details) throws JsonRPCStatusException, IOException { return getAddedNodeInfo(details, null); } /** * Clears the memory pool and returns a list of the removed transactions. * * Note: this is a customized command, which is currently not part of Bitcoin Core. * See https://github.com/OmniLayer/OmniJ/pull/72[Pull Request #72] on GitHub * * @return A list of transaction hashes of the removed transactions * @throws JsonRPCStatusException JSON RPC status exception * @throws IOException network error */ public List<Sha256Hash> clearMemPool() throws JsonRPCStatusException, IOException { JavaType resultType = mapper.getTypeFactory().constructCollectionType(List.class, Sha256Hash.class); return send("clearmempool", resultType); } }