001package org.consensusj.bitcoin.jsonrpc; 002 003import com.fasterxml.jackson.databind.JavaType; 004import com.fasterxml.jackson.databind.JsonNode; 005import com.fasterxml.jackson.databind.type.TypeFactory; 006import org.bitcoinj.base.BitcoinNetwork; 007import org.bitcoinj.base.LegacyAddress; 008import org.bitcoinj.base.Network; 009import org.consensusj.bitcoin.json.conversion.HexUtil; 010import org.consensusj.bitcoin.json.pojo.AddressGroupingItem; 011import org.consensusj.bitcoin.json.pojo.AddressInfo; 012import org.consensusj.bitcoin.json.pojo.BitcoinTransactionInfo; 013import org.consensusj.bitcoin.json.pojo.BlockChainInfo; 014import org.consensusj.bitcoin.json.pojo.BlockInfo; 015import org.consensusj.bitcoin.json.pojo.ChainTip; 016import org.consensusj.bitcoin.json.pojo.LoadWalletResult; 017import org.consensusj.bitcoin.json.pojo.MethodHelpEntry; 018import org.consensusj.bitcoin.json.pojo.NetworkInfo; 019import org.consensusj.bitcoin.json.pojo.Outpoint; 020import org.consensusj.bitcoin.json.pojo.RawTransactionInfo; 021import org.consensusj.bitcoin.json.pojo.ReceivedByAddressInfo; 022import org.consensusj.bitcoin.json.pojo.SignedRawTransaction; 023import org.consensusj.bitcoin.json.pojo.TxOutInfo; 024import org.consensusj.bitcoin.json.pojo.TxOutSetInfo; 025import org.consensusj.bitcoin.json.pojo.UnloadWalletResult; 026import org.consensusj.bitcoin.json.pojo.UnspentOutput; 027import org.consensusj.bitcoin.json.conversion.RpcClientModule; 028import org.consensusj.bitcoin.json.pojo.WalletTransactionInfo; 029import org.consensusj.bitcoin.json.pojo.ZmqNotification; 030import org.consensusj.bitcoin.json.pojo.bitcore.AddressBalanceInfo; 031import org.consensusj.bitcoin.json.pojo.bitcore.AddressRequest; 032import org.consensusj.bitcoin.json.pojo.bitcore.AddressUtxoInfo; 033import org.consensusj.bitcoin.jsonrpc.internal.BitcoinClientThreadFactory; 034import org.consensusj.jsonrpc.DefaultRpcClient; 035import org.consensusj.jsonrpc.JsonRpcError; 036import org.consensusj.jsonrpc.JsonRpcErrorException; 037import org.consensusj.jsonrpc.JsonRpcException; 038import org.consensusj.jsonrpc.JsonRpcMessage; 039import org.consensusj.jsonrpc.JsonRpcRequest; 040import org.consensusj.jsonrpc.JsonRpcResponse; 041import org.consensusj.jsonrpc.JsonRpcStatusException; 042import org.bitcoinj.base.Address; 043import org.bitcoinj.core.Block; 044import org.bitcoinj.base.Coin; 045import org.bitcoinj.core.Context; 046import org.bitcoinj.crypto.ECKey; 047import org.bitcoinj.base.Sha256Hash; 048import org.bitcoinj.core.Transaction; 049import org.consensusj.jsonrpc.JsonRpcTransport; 050import org.slf4j.Logger; 051import org.slf4j.LoggerFactory; 052 053import javax.net.ssl.SSLContext; 054import java.io.EOFException; 055import java.io.IOException; 056import java.net.ConnectException; 057import java.net.SocketException; 058import java.net.URI; 059import java.nio.ByteBuffer; 060import java.time.Duration; 061import java.util.List; 062import java.util.Map; 063import java.util.concurrent.CompletableFuture; 064import java.util.concurrent.CompletionException; 065import java.util.concurrent.ExecutorService; 066import java.util.concurrent.Executors; 067import java.util.concurrent.ThreadFactory; 068import java.util.concurrent.TimeUnit; 069import java.util.concurrent.TimeoutException; 070import java.util.function.Function; 071import java.util.function.Supplier; 072import java.util.stream.Collectors; 073import java.util.stream.Stream; 074 075/** 076 * JSON-RPC Client for <b>Bitcoin Core</b>. 077 * <p> 078 * A strongly-typed wrapper for a Bitcoin Core JSON-RPC client using the 079 * <a href="https://bitcoincore.org/en/doc/">Bitcoin Core JSON-RPC API</a>. 080 * <p> 081 * <a href="https://bitcoinj.org">bitcoinj</a> types are used where appropriate. 082 * For example, requesting a block hash will return a {@link org.bitcoinj.base.Sha256Hash}: 083 * 084 * <pre> {@code 085 * Sha256Hash hash = client.getBlockHash(342650); 086 * }</pre> 087 * 088 * Requesting a Bitcoin balance will return the amount as a {@link org.bitcoinj.base.Coin}: 089 * 090 * <pre> {@code 091 * Coin balance = client.getBalance(); 092 * }</pre> 093 * 094 * This version is written to be compatible with Bitcoin Core 0.20 and later. If used with 095 * Omni Core (an enhanced version of Bitcoin Core with Omni Protocol support) Omni Core 0.11.0 or later is required. 096 * <p> 097 * Note that according to <a href="https://github.com/bitcoin/bitcoin/issues/2960">Issue #2960: Support JSON-RPC 2.0</a> Bitcoin Core 098 * does not correctly follow the JSON-RPC 2.0 specification. 099 * @see org.consensusj.jsonrpc.JsonRpcClient 100 * @see <a href="https://bitcoincore.org/en/doc/">Bitcoin Core JSON-RPC API reference</a> 101 * @see <a href="https://github.com/bitcoin/bitcoin/issues/2960">Bitcoin Core Issue #2960: Support JSON-RPC 2.0</a> 102 * <p> 103 * <b>This is still a work-in-progress and the API will change.</b> 104 * 105 */ 106public class BitcoinClient extends DefaultRpcClient implements ChainTipClient { 107 private static final Logger log = LoggerFactory.getLogger(BitcoinClient.class); 108 109 private static final int THREAD_POOL_SIZE = 5; 110 111 // Delay between retries in waitForServer and waitForBlock 112 private static final Duration RETRY_DELAY = Duration.ofSeconds(5); 113 // Delay between log messages in waitForBlock 114 private static final Duration MESSAGE_DELAY = Duration.ofSeconds(30); 115 116 public static final int BITCOIN_CORE_VERSION_MIN = 200000; // Minimum Bitcoin Core supported (tested) version 117 public static final int BITCOIN_CORE_VERSION_DESC_DEFAULT = 230000; // Bitcoin Core version that DEFAULTS to descriptor wallets 118 119 // CompletableFuture<Network> is used to handle optional lazy (from-remote) initialization 120 private final CompletableFuture<Network> fNetwork = new CompletableFuture<>(); 121 // This tells us that we have successfully connected to the server at least once via any of the methods 122 // that eventually call waitForBlockchainInfoAsync() 123 private final CompletableFuture<Void> fConnectedOnce = new CompletableFuture<>(); 124 private final ExecutorService executorService; 125 126 private int serverVersion = 0; // 0 means unknown serverVersion 127 private boolean isAddressIndexSuccessfullyTested = false; 128 private boolean isAddressIndexEnabled; 129 130 public BitcoinClient(SSLContext sslContext, Network network, URI server, String rpcuser, String rpcpassword) { 131 super(sslContext, JsonRpcMessage.Version.V2, server, rpcuser, rpcpassword); 132 if (network != null) { 133 this.fNetwork.complete(network); // Non-lazy initialization case 134 } 135 ThreadFactory threadFactory = new BitcoinClientThreadFactory(new Context(), "Bitcoin RPC Client"); 136 // TODO: Tune and/or make configurable the thread pool size. 137 // Current pool size of 5 is chosen to minimize simultaneous active RPC 138 // calls in `bitcoind` -- which is not designed for serving multiple clients. 139 executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE, threadFactory); 140 mapper.registerModule(new RpcClientModule()); 141 } 142 143 // TODO: Reconcile this constructor mode with {@link #waitForServer(int)} 144 /** 145 * Incubating constructor that doesn't require a {@link Network}. 146 * <p> 147 * When using this constructor, it is recommended that {@link #getNetwork()} be called after construction 148 * and before any other methods are called, to allow the Bitcoin network type to be initialized. 149 * @param sslContext Custom socket factory 150 * @param server URI of the Bitcoin RPC server 151 * @param rpcuser Username (if required) 152 * @param rpcpassword Password (if required) 153 */ 154 public BitcoinClient(SSLContext sslContext, URI server, String rpcuser, String rpcpassword) { 155 this(sslContext, null, server, rpcuser, rpcpassword); 156 // Lazy initialization of network. Should we send a request from the constructor? 157 } 158 159 /** 160 * Incubating constructor that doesn't require a {@link Network}. 161 * <p> 162 * When using this constructor, it is recommended that {@link #getNetwork()} be called after construction 163 * and before any other methods are called, to allow the Bitcoin network type to be initialized. 164 * @param server URI of the Bitcoin RPC server 165 * @param rpcuser Username (if required) 166 * @param rpcpassword Password (if required) 167 */ 168 public BitcoinClient(URI server, String rpcuser, String rpcpassword) { 169 this(JsonRpcTransport.getDefaultSSLContext(), server, rpcuser, rpcpassword); 170 } 171 172 /** 173 * Construct a BitcoinClient from Network, URI, user name, and password. 174 * @param network Correct Network Parameters for destination server 175 * @param server URI of the Bitcoin RPC server 176 * @param rpcuser Username (if required) 177 * @param rpcpassword Password (if required) 178 */ 179 public BitcoinClient(Network network, URI server, String rpcuser, String rpcpassword) { 180 this(JsonRpcTransport.getDefaultSSLContext(), network, server, rpcuser, rpcpassword); 181 } 182 183 /** 184 * Construct a BitcoinClient from an RPCConfig data object. 185 * @param config Contains URI, user name, and password 186 */ 187 public BitcoinClient(RpcConfig config) { 188 this(config.network(), config.getURI(), config.getUsername(), config.getPassword()); 189 } 190 191 /** 192 * Get network. 193 * <p> 194 * Historically the Bitcoin network has been required as a constructor parameter and required to match 195 * the mode of the server. However, to simplify client configuration we have added a constructor 196 * that doesn't require specification of a network. This changes some assumptions about how {@code BitcoinClient} works. 197 * Previously, no JSON-RPC I/O calls would be performed unless something was explicitly requested -- which 198 * also gave users of {@code BitcoinClient} the ability to call {@link #waitForServer(Duration)} 199 * before calling any RPCs. 200 * <p> 201 * Until further improvements/changes are made, if you use one of the constructors that does not specify a 202 * {@code Network} you should call {@link #connectToServer(Duration)} as soon as possible after calling the constructor 203 * (especially before calling any JSON-RPC I/O methods. 204 * <p> 205 * Well-behaved users of {@code BitcoinClient} should only call this method <i>after</i> either providing 206 * a {@link Network} in the constructor or calling one of the methods that makes a connection. Because this 207 * method is also used internally and indirectly, there is a short timeout specified for extra safety. 208 * @return network for the server 209 */ 210 public synchronized Network getNetwork() { 211 // TODO: Should this auto-connect? 212 return fNetwork.orTimeout(1, TimeUnit.MINUTES).join(); 213 } 214 215 @Override 216 public ExecutorService getDefaultAsyncExecutor() { 217 return executorService; 218 } 219 220 /** 221 * Shutdown our thread pool, etc. 222 * 223 * @throws InterruptedException if one happens 224 */ 225 @Override 226 public void close() throws InterruptedException { 227 // TODO: See shutdownAndAwaitTermination method in the ExecutorService JavaDoc for how to correctly implement this. 228 executorService.shutdown(); 229 boolean successfullyTerminated = executorService.awaitTermination(10, TimeUnit.SECONDS); 230 if (!successfullyTerminated) { 231 log.warn("timeout while closing"); 232 } 233 } 234 235 /** 236 * Get a (cached after first call) serverVersion number 237 * @return serverVersion version of bitcoin server node 238 */ 239 synchronized int getServerVersion() { 240 if (serverVersion == 0) { 241 try { 242 serverVersion = getNetworkInfo().getVersion(); 243 } catch (IOException e) { 244 throw new RuntimeException(e); 245 } 246 if (serverVersion < BITCOIN_CORE_VERSION_MIN) { 247 throw new RuntimeException("Unsupported server version"); 248 } 249 } 250 return serverVersion; 251 } 252 253 /** 254 * Get the {@link Network} for this client by asking the server. 255 * @return A future for the server-side {@code Network} 256 */ 257 private CompletableFuture<Network> getNetworkFromServer() { 258 return getBlockChainInfoAsync().thenApply(BlockChainInfo::chainToNetwork); 259 } 260 261 /** 262 * Test if address index is enabled, caching the result of the first successful check 263 * 264 * @return true if enabled, false if not enabled 265 * @throws JsonRpcException an exception other than 1 of the two expected exceptions is thrown 266 * @throws IOException something else went wrong 267 */ 268 public synchronized boolean isAddressIndexEnabled() throws JsonRpcException, IOException { 269 if (!isAddressIndexSuccessfullyTested) { 270 try { 271 AddressBalanceInfo info = getAddressBalance(getTestAddress()); 272 isAddressIndexSuccessfullyTested = true; 273 isAddressIndexEnabled = true; 274 } catch (JsonRpcErrorException ee) { 275 // If method not found, the method we use for the test isn't even present, so definitely 276 // no address index support is available 277 if (ee.getError().getCode() == JsonRpcError.Error.METHOD_NOT_FOUND.getCode()) { 278 isAddressIndexSuccessfullyTested = true; 279 isAddressIndexEnabled = false; 280 } else { 281 // Some other, unexpected exception, throw it 282 throw ee; 283 } 284 } catch (JsonRpcStatusException se) { 285 // If the method is there and it returns an error of "Address index not enabled" then we also 286 // know that no address index support is available 287 if (se.getMessage().equals("Address index not enabled")) { 288 isAddressIndexSuccessfullyTested = true; 289 isAddressIndexEnabled = false; 290 } else if ( se.jsonRpcCode == JsonRpcError.Error.METHOD_NOT_FOUND.getCode()) { 291 // It looks like the behavior changed in Bitcoin Core v23.0 and we end up here rather than in the JsonRpcErrorException handler above 292 isAddressIndexSuccessfullyTested = true; 293 isAddressIndexEnabled = false; 294 } else { 295 // Some other, unexpected exception, throw it 296 throw se; 297 } 298 } 299 } 300 return isAddressIndexEnabled; 301 } 302 303 private Address getTestAddress() { 304 BitcoinNetwork network = (BitcoinNetwork) getNetwork(); 305 switch (network) { 306 case MAINNET: 307 return LegacyAddress.fromBase58( "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", network); 308 case TESTNET: 309 case REGTEST: 310 case SIGNET: 311 default: 312 return LegacyAddress.fromBase58( "moneyqMan7uh8FqdCA2BV5yZ8qVrc9ikLP", network); 313 } 314 } 315 316 /** 317 * Wait until the server is available. 318 * <p> 319 * Keep trying, ignoring (and logging) a known list of exception conditions that may occur while waiting for 320 * a {@code bitcoind} server to start up. This is similar to the behavior enabled by the {@code -rpcwait} 321 * option to the {@code bitcoin-cli} command-line tool. 322 * 323 * @param timeoutSeconds Timeout in seconds 324 * @return true if ready, false if timeout or interrupted 325 * @throws JsonRpcException if an "unexpected" exception happens (i.e. an error other than what happens during normal server startup) 326 * @deprecated Use {@link #waitForServer(Duration)} 327 */ 328 @Deprecated 329 public boolean waitForServer(int timeoutSeconds) throws JsonRpcException { 330 return waitForServer(Duration.ofSeconds(timeoutSeconds)); 331 } 332 333 /** 334 * Poll the server regularly until it responds. 335 * @param timeout how long to wait for server 336 * @return Completes with {@code true} if server responded, {@code false} for timeout 337 * @throws JsonRpcException if an unexpected JsonRpcException occurs 338 */ 339 public boolean waitForServer(Duration timeout) throws JsonRpcException { 340 try { 341 return syncGet(waitForServerAsync(timeout, RETRY_DELAY)); 342 } catch (JsonRpcException je) { 343 throw je; 344 } catch (IOException ioe) { 345 throw new RuntimeException(ioe); 346 } 347 } 348 349 /** 350 * Actively connect to server (one time) waiting for it to start if necessary 351 * @param timeout how long to wait 352 * @return completes successfully on connection or exceptionally on fatal error or timeout 353 */ 354 public CompletableFuture<Void> connectToServer(Duration timeout) { 355 return waitForBlockchainInfoAsync(timeout, RETRY_DELAY) 356 .thenApply(info -> null); 357 } 358 359 /** 360 * This is like waitForServer but does not initiate a connection. It depends upon 361 * something else having done so. 362 * @return a future (possibly already completed) that indicates we have connected at least once to the server 363 */ 364 public CompletableFuture<Void> waitForConnected() { 365 return fConnectedOnce.minimalCompletionStage().toCompletableFuture(); 366 } 367 368 public CompletableFuture<Void> waitForConnected(Duration timeout) { 369 return waitForConnected().orTimeout(timeout.toSeconds(), TimeUnit.SECONDS); 370 } 371 372 // TODO: Consider renaming this method "connect" 373 // TODO: Consider having this method automatically get the Bitcoin Network, Server Version, RegTest mining address, etc once connection is made (the generic waitForServer() method is capable of doing that) 374 /** 375 * Wait for a connection to the server. Uses {@code getblockchaininfo} to poll server. 376 * @param timeout how long to wait for server 377 * @param retry time to wait between retries 378 * @return Completes with {@code true} if server responded, {@code false} for timeout, exceptionally for unexpected errors. 379 */ 380 protected CompletableFuture<Boolean> waitForServerAsync(Duration timeout, Duration retry) { 381 return waitForBlockchainInfoAsync(timeout, retry) 382 .handle((i, t) -> { 383 if (i != null) { 384 return CompletableFuture.completedFuture(Boolean.TRUE); 385 } else if (t instanceof TimeoutException) { 386 return CompletableFuture.completedFuture(Boolean.FALSE); 387 } else { 388 return CompletableFuture.<Boolean>failedFuture(t); 389 } 390 }) 391 .thenCompose(Function.identity()); 392 } 393 394 protected CompletableFuture<BlockChainInfo> waitForBlockchainInfoAsync(Duration timeout, Duration retry) { 395 Supplier<JsonRpcRequest> requestSupplier = () -> buildJsonRequest("getblockchaininfo"); 396 CompletableFuture<BlockChainInfo> cf = waitForServer(timeout, retry, requestSupplier, typeForClass(BlockChainInfo.class), this::mapBitcoinTransientErrors); 397 return cf.whenComplete((info, t) -> { 398 if (info != null) { 399 fConnectedOnce.complete(null); 400 fNetwork.complete(BlockChainInfo.chainToNetwork(info)); 401 } 402 }); 403 } 404 405 /** 406 * Wait for RPC server to reach specified block height. 407 * 408 * @param blockHeight Block height to wait for 409 * @param timeout Timeout in seconds 410 * @throws JsonRpcStatusException JSON RPC status exception 411 * @throws IOException network error 412 * @return True if blockHeight reached, false if timeout or interrupted 413 */ 414 public Boolean waitForBlock(int blockHeight, int timeout) throws JsonRpcStatusException, IOException { 415 416 log.info("Waiting for server to reach block " + blockHeight); 417 418 long seconds = 0; 419 while (seconds < timeout) { 420 Integer block = this.getBlockCount(); 421 if (block >= blockHeight) { 422 log.info("Server is at block " + block + " returning 'true'."); 423 return true; 424 } else { 425 try { 426 if (seconds % MESSAGE_DELAY.toSeconds() == 0) { 427 log.debug("Server at block " + block); 428 } 429 Thread.sleep(RETRY_DELAY.toMillis()); 430 seconds += RETRY_DELAY.toSeconds(); 431 } catch (InterruptedException e) { 432 log.error(e.toString()); 433 Thread.currentThread().interrupt(); 434 return false; 435 } 436 } 437 } 438 439 log.error("Timeout waiting for block " + blockHeight); 440 return false; 441 } 442 443 /** 444 * TransientErrorMapper suitable for waiting for a temporarily down or restarting Bitcoin JSON-RPC server. This 445 * can be used to implement the {@code -rpcwait} command-line option, for instance. 446 */ 447 protected <T> CompletableFuture<JsonRpcResponse<T>> mapBitcoinTransientErrors(JsonRpcRequest request, JsonRpcResponse<T> response, Throwable t) { 448 if (response != null) { 449 return CompletableFuture.completedFuture(response); 450 } else { 451 if (t instanceof CompletionException) { 452 // Java.net.http driver 453 if (t.getCause() != null) { 454 if (t.getCause() instanceof ConnectException) { 455 return CompletableFuture.completedFuture(temporarilyUnavailableResponse(request, t)); 456 } else { 457 return CompletableFuture.failedFuture(t); 458 } 459 } 460 } 461 if (t instanceof SocketException) { 462 // Java HttpUrlConnection driver 463 SocketException se = (SocketException) t; 464 // These are expected exceptions while waiting for a server 465 if (se.getMessage().equals("Unexpected end of file from server") || 466 se.getMessage().equals("Connection reset") || 467 se.getMessage().contains("Connection refused") || 468 se.getMessage().equals("recvfrom failed: ECONNRESET (Connection reset by peer)")) { 469 // Transient error, generate synthetic JSON-RPC error response with appropriate values 470 return CompletableFuture.completedFuture(temporarilyUnavailableResponse(request, t)); 471 } else { 472 return CompletableFuture.failedFuture(se); 473 } 474 } else if (t instanceof EOFException) { 475 /* Android exception, ignore */ 476 // Expected exceptions on Android, RoboVM 477 return CompletableFuture.completedFuture(temporarilyUnavailableResponse(request, t)); 478 } else if (t instanceof JsonRpcStatusException) { 479 JsonRpcStatusException e = (JsonRpcStatusException) t; 480 // If server is in "warm-up" mode, e.g. validating/parsing the blockchain... 481 if (e.jsonRpcCode == -28) { 482 // ...then grab text message for status logging 483 return CompletableFuture.completedFuture(temporarilyUnavailableResponse(request, t)); 484 } else { 485 return CompletableFuture.failedFuture(e); 486 } 487 } else if (t instanceof IOException) { 488 // Ignore all IOExceptions 489 return CompletableFuture.completedFuture(temporarilyUnavailableResponse(request, t)); 490 } else { 491 return CompletableFuture.failedFuture(t); 492 } 493 } 494 } 495 496 /** 497 * Tell the server to stop 498 * @return A status string 499 * @throws JsonRpcStatusException JSON RPC status exception 500 * @throws IOException network error 501 */ 502 public String stop() throws JsonRpcStatusException, IOException { 503 return send("stop"); 504 } 505 506 /** 507 * Returns the number of blocks in the longest block chain. 508 * 509 * @return The current block count 510 * @throws JsonRpcStatusException JSON RPC status exception 511 * @throws IOException network error 512 */ 513 public Integer getBlockCount() throws JsonRpcStatusException, IOException { 514 return send("getblockcount"); 515 } 516 517 /** 518 * Returns the hash of block in best-block-chain at index provided. 519 * 520 * @param index The block index 521 * @return The block hash 522 * @throws JsonRpcStatusException JSON RPC status exception 523 * @throws IOException network error 524 */ 525 public Sha256Hash getBlockHash(Integer index) throws JsonRpcStatusException, IOException { 526 return send("getblockhash", Sha256Hash.class, index); 527 } 528 529 /** 530 * Returns information about a block with the given block hash. 531 * 532 * @param hash The block hash 533 * @return The information about the block (JSON/POJO object) 534 * @throws JsonRpcStatusException JSON RPC status exception 535 * @throws IOException network error 536 */ 537 public BlockInfo getBlockInfo(Sha256Hash hash) throws JsonRpcStatusException, IOException { 538 // Use "verbose = true" 539 return send("getblock", BlockInfo.class, hash, true); 540 } 541 542 /** 543 * Returns information about a block with the given block hash. 544 * 545 * @param hash The block hash 546 * @return The information about the block (bitcoinj {@link Block} object) 547 * @throws JsonRpcStatusException JSON RPC status exception 548 * @throws IOException network error 549 */ 550 public Block getBlock(Sha256Hash hash) throws JsonRpcStatusException, IOException { 551 return syncGet(getBlockAsync(hash)); 552 } 553 554 public CompletableFuture<Block> getBlockAsync(Sha256Hash hash) { 555 // Use "verbosity = 0" for raw block data 556 return sendAsync("getblock", Block.class, hash, 0); 557 } 558 559 /** 560 * Composite query that first calls ChainTips, then gets best block for the active tip 561 * @return The current best block 562 */ 563 public CompletableFuture<Block> getBestBlock() { 564 return getChainTipsAsync() 565 .thenCompose(tips -> ChainTip.findActiveChainTip(tips) 566 .map(tip -> getBlockAsync(tip.getHash())) 567 .orElseGet(() -> CompletableFuture.failedFuture(new RuntimeException("No active ChainTip"))) 568 ); 569 } 570 571 /** 572 * Mine blocks immediately (RegTest mode) 573 * @since Bitcoin Core 0.13.0 574 * 575 * @param numBlocks Number of blocks to mine 576 * @param address Address to send mined coins to 577 * @param maxtries How many iterations to try (or null to use server default -- currently 1,000,000) 578 * @return list containing block header hashes of the generated blocks 579 * @throws JsonRpcStatusException JSON RPC status exception 580 * @throws IOException network error 581 */ 582 public List<Sha256Hash> generateToAddress(int numBlocks, Address address, Integer maxtries) throws IOException { 583 JavaType resultType = collectionTypeForClasses(List.class, Sha256Hash.class); 584 return send("generatetoaddress", resultType, (long) numBlocks, address, maxtries); 585 } 586 587 /** 588 * Mine blocks immediately (RegTest mode) 589 * @since Bitcoin Core 0.13.0 590 * 591 * @param numBlocks Number of blocks to mine 592 * @param address Address to send mined coins to 593 * @return list containing block header hashes of the generated blocks 594 * @throws JsonRpcStatusException JSON RPC status exception 595 * @throws IOException network error 596 */ 597 public List<Sha256Hash> generateToAddress(int numBlocks, Address address) throws IOException { 598 return generateToAddress(numBlocks,address, null); 599 } 600 601 public List<String> listWallets() throws JsonRpcStatusException, IOException { 602 JavaType resultType = collectionTypeForClasses(List.class, String.class); 603 return send("listwallets", resultType); 604 } 605 606 public LoadWalletResult createWallet(String name, Boolean disablePrivateKeys, Boolean blank) throws JsonRpcStatusException, IOException { 607 return createWallet(name, disablePrivateKeys, blank, null, null, null, null, null); 608 } 609 610 public LoadWalletResult createWallet(String name, Boolean disablePrivateKeys, Boolean blank, String passPhrase, 611 Boolean avoidReuse) throws JsonRpcStatusException, IOException { 612 return send("createwallet", LoadWalletResult.class, name, disablePrivateKeys, blank, passPhrase, avoidReuse); 613 } 614 615 // To use all these params server must be "recent" 616 public LoadWalletResult createWallet(String name, Boolean disablePrivateKeys, Boolean blank, String passPhrase, 617 Boolean avoidReuse, Boolean descriptors, Boolean loadOnStartup, 618 Boolean externalSigner) throws JsonRpcStatusException, IOException { 619 return send("createwallet", LoadWalletResult.class, name, disablePrivateKeys, blank, passPhrase, avoidReuse, descriptors, loadOnStartup, externalSigner); 620 } 621 622 public UnloadWalletResult unloadWallet() throws JsonRpcStatusException, IOException { 623 return unloadWallet(null, null); 624 } 625 626 public UnloadWalletResult unloadWallet(String name, Boolean loadOnStartup) throws JsonRpcStatusException, IOException { 627 return send("unloadwallet", UnloadWalletResult.class, name, loadOnStartup); 628 } 629 630 /** 631 * Creates a new Bitcoin address for receiving payments, linked to the default account "". 632 * 633 * @return A new Bitcoin address 634 * @throws JsonRpcStatusException JSON RPC status exception 635 * @throws IOException network error 636 */ 637 public Address getNewAddress() throws JsonRpcStatusException, IOException { 638 return getNewAddress(null); 639 } 640 641 /** 642 * Creates a new Bitcoin address for receiving payments. 643 * 644 * @param label The label name for the address to be linked to. 645 * @return A new Bitcoin address 646 * @throws JsonRpcStatusException JSON RPC status exception 647 * @throws IOException network error 648 */ 649 public Address getNewAddress(String label) throws JsonRpcStatusException, IOException { 650 return send("getnewaddress", Address.class, label); 651 } 652 653 /** 654 * Return the private key from the server. 655 * 656 * Note: must be in wallet mode with unlocked or unencrypted wallet. 657 * 658 * @param address Address corresponding to the private key to return 659 * @return The private key 660 * @throws JsonRpcStatusException JSON RPC status exception 661 * @throws IOException network error 662 */ 663 public ECKey dumpPrivKey(Address address) throws JsonRpcStatusException, IOException { 664 return send("dumpprivkey", ECKey.class, address); 665 } 666 667 /** 668 * Import a private key into the server's wallet 669 * 670 * @param privateKey An ECKey (containing a private key) 671 * @param label The server-side label for the key 672 * @param rescan Rescan the blockchain to find transactions for this key 673 * @throws JsonRpcStatusException JSON RPC status exception 674 * @throws IOException network error 675 */ 676 public void importPrivKey(ECKey privateKey, String label, boolean rescan) throws JsonRpcStatusException, IOException { 677 send("importprivkey", Void.class, privateKey.getPrivateKeyEncoded(this.getNetwork()).toBase58(), label, rescan); 678 } 679 680 /** 681 * Creates a raw transaction spending the given inputs to the given destinations. 682 * 683 * Note: the transaction inputs are not signed, and the transaction is not stored in the wallet or transmitted to 684 * the network. 685 * 686 * @param inputs The outpoints to spent 687 * @param outputs The destinations and amounts to transfer 688 * @return The hex-encoded raw transaction 689 * @throws JsonRpcStatusException JSON RPC status exception 690 * @throws IOException network error 691 */ 692 public String createRawTransaction(List<Outpoint> inputs, Map<Address, Coin> outputs) 693 throws JsonRpcStatusException, IOException { 694 return send("createrawtransaction", inputs, outputs); 695 } 696 697 /** 698 * Signs inputs of a raw transaction using the wallet. Arguments 2 and 3 of the RPC are currently 699 * not supported, which means UTXOs not currently in the blockchain can't be used and `sighashtype` 700 * defaults to `ALL`. 701 * 702 * @param unsignedTransaction The hex-encoded raw transaction 703 * @return The signed transaction and information whether it has a complete set of signature 704 * @throws JsonRpcStatusException JSON RPC status exception 705 * @throws IOException network error 706 * @since Bitcoin Core v0.17 707 */ 708 public SignedRawTransaction signRawTransactionWithWallet(String unsignedTransaction) throws JsonRpcStatusException, IOException { 709 return send("signrawtransactionwithwallet", SignedRawTransaction.class, unsignedTransaction); 710 } 711 712 /** 713 * Get a "raw" transaction (which we use to construct a bitcoinj {@code Transaction}) 714 * @param txid Transaction ID/hash 715 * @return bitcoinj Transaction 716 * @throws JsonRpcStatusException JSON RPC status exception 717 * @throws IOException network error 718 */ 719 public Transaction getRawTransaction(Sha256Hash txid) throws JsonRpcStatusException, IOException { 720 String hexEncoded = send("getrawtransaction", txid); 721 byte[] raw = HexUtil.hexStringToByteArray(hexEncoded); 722 return Transaction.read(ByteBuffer.wrap(raw)); 723 } 724 725 /** 726 * Get a "raw" transaction as JSON (which we map to a RawTransactionInfo POJO) 727 * @param txid Transaction ID/hash 728 * @return RawTransactionInfo POJO 729 * @throws JsonRpcStatusException JSON RPC status exception 730 * @throws IOException network error 731 */ 732 public RawTransactionInfo getRawTransactionInfo(Sha256Hash txid) throws JsonRpcStatusException, IOException { 733 return send("getrawtransaction", RawTransactionInfo.class, txid, 1); 734 } 735 736 /** 737 * Submit a raw transaction to local node and network 738 * 739 * @since Bitcoin Core 0.19 740 * @param tx The raw transaction 741 * @param maxFeeRate Reject transactions whose fee rate is higher than this value, expressed in BTC/kB. 742 * Set to 0 to accept any fee rate. 743 * @return SHA256 Transaction ID 744 * @throws JsonRpcStatusException JSON RPC status exception 745 * @throws IOException network error 746 */ 747 public Sha256Hash sendRawTransaction(Transaction tx, Coin maxFeeRate) throws JsonRpcStatusException, IOException { 748 return send("sendrawtransaction", Sha256Hash.class, tx, maxFeeRate); 749 } 750 751 /** 752 * Submit a raw transaction to local node and network 753 * 754 * @since Bitcoin Core 0.19 755 * @param hexTx The raw transaction as a hex-encoded string 756 * @param maxFeeRate Reject transactions whose fee rate is higher than this value, expressed in BTC/kB. 757 * Set to 0 to accept any fee rate. 758 * @return SHA256 Transaction ID 759 * @throws JsonRpcStatusException JSON RPC status exception 760 * @throws IOException network error 761 */ 762 public Sha256Hash sendRawTransaction(String hexTx, Coin maxFeeRate) throws JsonRpcStatusException, IOException { 763 return send("sendrawtransaction", Sha256Hash.class, hexTx, maxFeeRate); 764 } 765 766 /** 767 * Submit a raw transaction to local node and network using server's default `maxFeeRate` 768 * 769 * @param tx The raw transaction 770 * @return SHA256 Transaction ID 771 * @throws JsonRpcStatusException JSON RPC status exception 772 * @throws IOException network error 773 */ 774 public Sha256Hash sendRawTransaction(Transaction tx) throws JsonRpcStatusException, IOException { 775 return sendRawTransaction(tx, (Coin) null); 776 } 777 778 /** 779 * Submit a raw transaction to local node and network using server's default `maxFeeRate` 780 * 781 * @since Bitcoin Core 0.19 782 * @param hexTx The raw transaction as a hex-encoded string 783 * @return SHA256 Transaction ID 784 * @throws JsonRpcStatusException JSON RPC status exception 785 * @throws IOException network error 786 */ 787 public Sha256Hash sendRawTransaction(String hexTx) throws JsonRpcStatusException, IOException { 788 return sendRawTransaction(hexTx, (Coin) null); 789 } 790 791 public AddressInfo getAddressInfo(Address address) throws JsonRpcStatusException, IOException { 792 return send("getaddressinfo", AddressInfo.class, address); 793 } 794 795 public Coin getReceivedByAddress(Address address) throws JsonRpcStatusException, IOException { 796 return getReceivedByAddress(address, 1); // Default to 1 or more confirmations 797 } 798 799 /** 800 * get total amount received by an address. 801 * 802 * @param address Address to query 803 * @param minConf minimum number of confirmations 804 * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` 805 * @throws JsonRpcStatusException JSON RPC status exception 806 * @throws IOException network error 807 */ 808 public Coin getReceivedByAddress(Address address, Integer minConf) throws JsonRpcStatusException, IOException { 809 return send("getreceivedbyaddress", Coin.class, address, minConf); 810 } 811 812 public List<ReceivedByAddressInfo> listReceivedByAddress(Integer minConf, Boolean includeEmpty) 813 throws JsonRpcStatusException, IOException { 814 JavaType resultType = collectionTypeForClasses(List.class, ReceivedByAddressInfo.class); 815 return send("listreceivedbyaddress", resultType, minConf, includeEmpty); 816 } 817 818 /** 819 * Returns a list of unspent transaction outputs with at least one confirmation. 820 * 821 * @return The unspent transaction outputs 822 * @throws JsonRpcStatusException JSON RPC status exception 823 * @throws IOException network error 824 */ 825 public List<UnspentOutput> listUnspent() throws JsonRpcStatusException, IOException { 826 return listUnspent(null, null, null, null); 827 } 828 829 /** 830 * Returns a list of unspent transaction outputs with at least {@code minConf} and not more than {@code maxConf} 831 * confirmations. 832 * 833 * @param minConf The minimum confirmations to filter 834 * @param maxConf The maximum confirmations to filter 835 * @return The unspent transaction outputs 836 * @throws JsonRpcStatusException JSON RPC status exception 837 * @throws IOException network error 838 */ 839 public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf) 840 throws JsonRpcStatusException, IOException { 841 return listUnspent(minConf, maxConf, null, null); 842 } 843 844 public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf, Address address) 845 throws JsonRpcStatusException, IOException { 846 return listUnspent(minConf, maxConf, List.of(address), true); 847 } 848 849 public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf, List<Address> filter) 850 throws JsonRpcStatusException, IOException { 851 return listUnspent(minConf, maxConf, filter, true); 852 } 853 854 /** 855 * Returns a list of unspent transaction outputs with at least {@code minConf} and not more than {@code maxConf} 856 * confirmations, filtered by a list of addresses. 857 * 858 * @param minConf The minimum confirmations to filter 859 * @param maxConf The maximum confirmations to filter 860 * @param filter Include only transaction outputs to the specified addresses 861 * @param includeUnsafe optional 862 * @return The unspent transaction outputs 863 * @throws JsonRpcStatusException JSON RPC status exception 864 * @throws IOException network error 865 */ 866 public List<UnspentOutput> listUnspent(Integer minConf, Integer maxConf, List<Address> filter, Boolean includeUnsafe) 867 throws JsonRpcStatusException, IOException { 868 JavaType resultType = collectionTypeForClasses(List.class, UnspentOutput.class); 869 return send("listunspent", resultType, minConf, maxConf, filter, includeUnsafe); 870 } 871 872 /** 873 * Returns details about an unspent transaction output. 874 * 875 * @param txid The transaction hash 876 * @param vout The transaction output index 877 * @return Details about an unspent output or nothing, if the output was already spent 878 * @throws JsonRpcStatusException JSON RPC status exception 879 * @throws IOException network error 880 */ 881 public TxOutInfo getTxOut(Sha256Hash txid, Integer vout) throws JsonRpcStatusException, IOException { 882 return getTxOut(txid, vout, null); 883 } 884 885 886 /** 887 * Returns details about an unspent transaction output. 888 * 889 * @param txid The transaction hash 890 * @param vout The transaction output index 891 * @param includeMemoryPool Whether to included the memory pool 892 * @return Details about an unspent output or nothing, if the output was already spent 893 * @throws JsonRpcStatusException JSON RPC status exception 894 * @throws IOException network error 895 */ 896 public TxOutInfo getTxOut(Sha256Hash txid, Integer vout, Boolean includeMemoryPool) 897 throws JsonRpcStatusException, IOException { 898 return send("gettxout", TxOutInfo.class, txid, vout, includeMemoryPool); 899 } 900 901 /** 902 * Returns statistics about the unspent transaction output set. 903 * Note this call may take some time. 904 * 905 * @return statistics about the unspent transaction output set 906 * @throws JsonRpcStatusException JSON RPC status exception 907 * @throws IOException network error 908 */ 909 public TxOutSetInfo getTxOutSetInfo() throws JsonRpcStatusException, IOException { 910 return send("gettxoutsetinfo", TxOutSetInfo.class); 911 } 912 913 /** 914 * Get the balance for a the default Bitcoin "account" 915 * 916 * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` 917 * @throws JsonRpcStatusException JSON RPC status exception 918 * @throws IOException network error 919 */ 920 public Coin getBalance() throws JsonRpcStatusException, IOException { 921 return getBalance(null, null); 922 } 923 924 /** 925 * Get the balance for a Bitcoin "account" 926 * 927 * @param account A Bitcoin "account". (Be wary of using this feature.) 928 * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` 929 * @throws JsonRpcStatusException JSON RPC status exception 930 * @throws IOException network error 931 */ 932 public Coin getBalance(String account) throws JsonRpcStatusException, IOException { 933 return getBalance(account, null); 934 } 935 936 /** 937 * Get the balance for a Bitcoin "account" 938 * 939 * @param account A Bitcoin "account". (Be wary of using this feature.) 940 * @param minConf minimum number of confirmations 941 * @return Is now returning `Coin`, if you need to convert use `BitcoinMath.btcToCoin(result)` 942 * @throws JsonRpcStatusException JSON RPC status exception 943 * @throws IOException network error 944 */ 945 public Coin getBalance(String account, Integer minConf) throws JsonRpcStatusException, IOException { 946 return send("getbalance", Coin.class, account, minConf); 947 } 948 949 public Sha256Hash sendToAddress(Address address, Coin amount) throws JsonRpcStatusException, IOException { 950 return sendToAddress(address, amount, null, null); 951 } 952 953 public Sha256Hash sendToAddress(Address address, Coin amount, String comment, String commentTo) 954 throws JsonRpcStatusException, IOException { 955 return send("sendtoaddress", Sha256Hash.class, address, amount, comment, commentTo); 956 } 957 958 public Sha256Hash sendFrom(String account, Address address, Coin amount) 959 throws JsonRpcStatusException, IOException { 960 return send("sendfrom", Sha256Hash.class, account, address, amount); 961 } 962 963 public Sha256Hash sendMany(String account, Map<Address, Coin> amounts) throws JsonRpcStatusException, IOException { 964 return send("sendmany", Sha256Hash.class, account, amounts); 965 } 966 967 /** 968 * Set the transaction fee per kB. 969 * 970 * @param amount The transaction fee in BTC/kB rounded to the nearest 0.00000001. 971 * @return True if successful 972 * @throws JsonRpcStatusException JSON RPC status exception 973 * @throws IOException network error 974 */ 975 public Boolean setTxFee(Coin amount) throws JsonRpcStatusException, IOException { 976 return send("settxfee", amount); 977 } 978 979 public WalletTransactionInfo getTransaction(Sha256Hash txid) throws JsonRpcStatusException, IOException { 980 return getTransaction(txid, null, null); 981 } 982 983 public WalletTransactionInfo getTransaction(Sha256Hash txid, Boolean includeWatchOnly, Boolean verbose) throws JsonRpcStatusException, IOException { 984 return send("gettransaction", WalletTransactionInfo.class, txid, includeWatchOnly, verbose); 985 } 986 987 /** 988 * List the default number (10) of wallet transactions. 989 * @return A list of wallet transactions 990 * @throws JsonRpcStatusException JSON RPC status exception 991 * @throws IOException network error 992 */ 993 public List<BitcoinTransactionInfo> listTransactions() throws JsonRpcStatusException, IOException { 994 return listTransactions(null, null, null, null); 995 } 996 997 /** 998 * List wallet transactions. 999 * @param label Return transactions matching this address label, use "*" to return all transactions. {@code null} will use the server default ({@code "*"}) 1000 * @param count Maximum number of transactions to return. {@code null} will use the sever default number (10) 1001 * @return A list of wallet transactions 1002 * @throws JsonRpcStatusException JSON RPC status exception 1003 * @throws IOException network error 1004 */ 1005 public List<BitcoinTransactionInfo> listTransactions(String label, Integer count) throws JsonRpcStatusException, IOException { 1006 return listTransactions(label, count, null, null); 1007 } 1008 /** 1009 * List wallet transactions 1010 * @param label Return transactions matching this address label, use "*" to return all transactions. {@code null} will use the server default ({@code "*"}) 1011 * @param count Maximum number of transactions to return. {@code null} will use the sever default number (10) 1012 * @param skip Number of transactions to skip. {@code null} will use the server default (0) 1013 * @param includeWatchOnly Include transactions to/from watch-only addresses. {@code null} will use the server default, which is ({@code true}) for watch-only wallets, {@code false} otherwise. 1014 * @return A list of wallet transactions 1015 * @throws JsonRpcStatusException JSON RPC status exception 1016 * @throws IOException network error 1017 */ 1018 public List<BitcoinTransactionInfo> listTransactions(String label, Integer count, Integer skip, Boolean includeWatchOnly) throws JsonRpcStatusException, IOException { 1019 JavaType resultType = collectionTypeForClasses(List.class, BitcoinTransactionInfo.class); 1020 return send("listtransactions", resultType, label, count, skip, includeWatchOnly); 1021 } 1022 1023 /** 1024 * The getblockchaininfo RPC provides information about the current state of the block chain. 1025 * 1026 * @return An object containing information about the current state of the block chain. 1027 * @throws JsonRpcStatusException JSON RPC status exception 1028 * @throws IOException network error 1029 */ 1030 public BlockChainInfo getBlockChainInfo() throws JsonRpcStatusException, IOException { 1031 return syncGet(getBlockChainInfoAsync()); 1032 } 1033 1034 public CompletableFuture<BlockChainInfo> getBlockChainInfoAsync() { 1035 return sendAsync("getblockchaininfo", BlockChainInfo.class); 1036 } 1037 1038 /** 1039 * The getnetworkinfo RPC returns information about the node's connection to the network. 1040 * 1041 * @return information about the node's connection to the network 1042 * @throws JsonRpcStatusException JSON RPC status exception 1043 * @throws IOException network error 1044 */ 1045 public NetworkInfo getNetworkInfo() throws JsonRpcStatusException, IOException { 1046 return send("getnetworkinfo", NetworkInfo.class); 1047 } 1048 1049 /** 1050 * The {@code getzmqnotifications} RPC returns information about which configured ZMQ notifications are enabled 1051 * and on which ports. 1052 * 1053 * @return A List of ZMQ Notification info records 1054 * @throws JsonRpcStatusException JSON RPC status exception 1055 * @throws IOException network error 1056 */ 1057 public List<ZmqNotification> getZmqNotifications() throws JsonRpcStatusException, IOException { 1058 return syncGet(getZmqNotificationsAsync()); 1059 } 1060 1061 public CompletableFuture<List<ZmqNotification>> getZmqNotificationsAsync() { 1062 JavaType resultType = collectionTypeForClasses(List.class, ZmqNotification.class); 1063 return sendAsync("getzmqnotifications", resultType); 1064 } 1065 1066 /** 1067 * Returns list of related addresses. 1068 * Also useful for finding all change addresses in the wallet 1069 * @return a list of address groupings 1070 * @throws JsonRpcStatusException JSON RPC status exception 1071 * @throws IOException network error 1072 */ 1073 public List<List<AddressGroupingItem>> listAddressGroupings() throws JsonRpcStatusException, IOException { 1074 JavaType agiListType = collectionTypeForClasses(List.class, AddressGroupingItem.class); 1075 JavaType resultType = collectionTypeForClasses(List.class, agiListType); 1076 return send("listaddressgroupings", resultType); 1077 } 1078 1079 /** 1080 * Returns a human-readable list of available commands. 1081 * <p> 1082 * Bitcoin Core 0.10+ returns a categorized list of commands including blank lines 1083 * and header lines. 1084 * 1085 * @return The list of commands as string 1086 * @throws JsonRpcStatusException JSON RPC status exception 1087 * @throws IOException network error 1088 */ 1089 public String help() throws JsonRpcStatusException, IOException { 1090 return help(null); 1091 } 1092 1093 /** 1094 * Returns a human-readable list of available commands. 1095 * 1096 * @return The response as a stream of one {@link String} for each line 1097 * @throws JsonRpcStatusException JSON RPC status exception 1098 * @throws IOException network error 1099 */ 1100 public Stream<String> helpAsStream() throws JsonRpcStatusException, IOException { 1101 return lines(help()); 1102 } 1103 1104 /** 1105 * Returns a human-readable list of available commands. 1106 * 1107 * @return The response as a list one {@link String} for each line 1108 * @throws JsonRpcStatusException JSON RPC status exception 1109 * @throws IOException network error 1110 */ 1111 public List<String> helpAsLines() throws JsonRpcStatusException, IOException { 1112 return helpAsStream().collect(Collectors.toList()); 1113 } 1114 1115 /** 1116 * Returns a human-readable list of available commands. 1117 * 1118 * @return The response as a list one {@link MethodHelpEntry} for each method 1119 * @throws JsonRpcStatusException JSON RPC status exception 1120 * @throws IOException network error 1121 */ 1122 public List<MethodHelpEntry> helpAsMethodEntries() throws JsonRpcStatusException, IOException { 1123 return helpAsStream() 1124 .filter(this::isMethodEntry) 1125 .map(MethodHelpEntry::new) 1126 .collect(Collectors.toList()); 1127 } 1128 1129 /** 1130 * Returns helpful information for a specific command. 1131 * 1132 * @param command The name of the command to get help for 1133 * @return The help text 1134 * @throws JsonRpcStatusException JSON RPC status exception 1135 * @throws IOException network error 1136 */ 1137 public String help(String command) throws JsonRpcStatusException, IOException { 1138 return send("help", command); 1139 } 1140 1141 /** 1142 * Returns a list of available commands. 1143 * <p> 1144 * Commands which are unavailable will not be listed, such as wallet RPCs, if wallet support is disabled. 1145 * 1146 * @return The list of commands 1147 * @throws JsonRpcStatusException JSON RPC status exception 1148 * @throws IOException network error 1149 */ 1150 public List<String> getCommands() throws JsonRpcStatusException, IOException { 1151 return helpAsMethodEntries().stream() 1152 .map(MethodHelpEntry::getMethodName) 1153 .collect(Collectors.toList()); 1154 } 1155 1156 private Stream<String> lines(String string) { 1157 // In JDK 11 this can be replaced by String::lines 1158 return Stream.of(string.split("\n")); 1159 } 1160 1161 private boolean isMethodEntry(String line) { 1162 // Filter out blank and header lines 1163 return !line.isEmpty() && !line.matches("== (.+) =="); 1164 } 1165 1166 /** 1167 * Checks whether a command exists. 1168 * <p> 1169 * This is done indirectly, by using {help(String) help} to get information about the command, and if information 1170 * about the command is available, then the command exists. The absence of information does not necessarily imply 1171 * the non-existence of a command. 1172 * 1173 * @param command The name of the command to check 1174 * @return True if the command exists 1175 * @throws JsonRpcStatusException JSON RPC status exception 1176 * @throws IOException network error 1177 */ 1178 public Boolean commandExists(String command) throws JsonRpcStatusException, IOException { 1179 return !help(command).contains("help: unknown command"); 1180 } 1181 1182 /** 1183 * Permanently marks a block as invalid, as if it violated a consensus rule. 1184 * 1185 * @param hash The block hash 1186 * @since Bitcoin Core 0.10 1187 * @throws JsonRpcStatusException JSON RPC status exception 1188 * @throws IOException network error 1189 */ 1190 public void invalidateBlock(Sha256Hash hash) throws JsonRpcStatusException, IOException { 1191 send("invalidateblock", hash); 1192 } 1193 1194 /** 1195 * Removes invalidity status of a block and its descendants, reconsider them for activation. 1196 * <p> 1197 * This can be used to undo the effects of {link invalidateBlock(Sha256Hash) invalidateBlock}. 1198 * 1199 * @param hash The hash of the block to reconsider 1200 * @since Bitcoin Core 0.10 1201 * @throws JsonRpcStatusException JSON RPC status exception 1202 * @throws IOException network error 1203 */ 1204 public void reconsiderBlock(Sha256Hash hash) throws JsonRpcStatusException, IOException { 1205 send("reconsiderblock", hash); 1206 } 1207 1208 /** 1209 * Return information about all known tips in the block tree, including the main chain as well as orphaned branches. 1210 * 1211 * @return A list of chain tip information 1212 * @since Bitcoin Core 0.10 1213 * @throws JsonRpcStatusException JSON RPC status exception 1214 * @throws IOException network error 1215 * @deprecated Use {@link #getChainTipsAsync()} 1216 */ 1217 @Override 1218 public List<ChainTip> getChainTips() throws JsonRpcStatusException, IOException { 1219 return syncGet(getChainTipsAsync()); 1220 } 1221 1222 @Override 1223 public CompletableFuture<List<ChainTip>> getChainTipsAsync() { 1224 JavaType resultType = collectionTypeForClasses(List.class, ChainTip.class); 1225 return sendAsync("getchaintips", resultType); 1226 } 1227 1228 /** 1229 * Attempt to add or remove a node from the addnode list, or to try a connection to a node once. 1230 * 1231 * @param node node to add as a string in the form of {@code IP_address:port} 1232 * @param command `add`, `remove`, or `onetry` 1233 * @throws JsonRpcStatusException JSON RPC status exception 1234 * @throws IOException network error 1235 */ 1236 public void addNode(String node, String command) throws JsonRpcStatusException, IOException { 1237 send("addnode", node, command); 1238 } 1239 1240 /** 1241 * Return information about the given added node 1242 * 1243 * @param details `true` to return detailed information 1244 * @param node the node to provide information about 1245 * @return A Jackson JsonNode object (until we define a POJO) 1246 * @throws JsonRpcStatusException JSON RPC status exception 1247 * @throws IOException network error 1248 */ 1249 public JsonNode getAddedNodeInfo(boolean details, String node) throws JsonRpcStatusException, IOException { 1250 return send("getaddednodeinfo", JsonNode.class, details, node); 1251 } 1252 1253 /** 1254 * Return information about all added nodes 1255 * 1256 * @param details `true` to return detailed information 1257 * @return A Jackson JsonNode object (until we define a POJO) 1258 * @throws JsonRpcStatusException JSON RPC status exception 1259 * @throws IOException network error 1260 */ 1261 public JsonNode getAddedNodeInfo(boolean details) throws JsonRpcStatusException, IOException { 1262 return getAddedNodeInfo(details, null); 1263 } 1264 1265 // Bitcore/Omni transaction for getting non-wallet address balances 1266 public AddressBalanceInfo getAddressBalance(Address address) throws JsonRpcException, IOException { 1267 return send("getaddressbalance", AddressBalanceInfo.class, address); 1268 } 1269 1270 // Bitcore/Omni transaction for getting non-wallet address balances 1271 public AddressBalanceInfo getAddressBalance(List<Address> addressList) throws JsonRpcException, IOException { 1272 return send("getaddressbalance", AddressBalanceInfo.class, new AddressRequest(addressList)); 1273 } 1274 1275 // Bitcore/Omni transaction for getting non-wallet address UTXO Info 1276 public List<AddressUtxoInfo> getAddressUtxos(Address address) throws JsonRpcException, IOException { 1277 JavaType resultType = collectionTypeForClasses(List.class, AddressUtxoInfo.class); 1278 return send("getaddressutxos", resultType, address); 1279 } 1280 1281 // Bitcore/Omni transaction for getting non-wallet address UTXO Info 1282 public List<AddressUtxoInfo> getAddressUtxos(List<Address> addressList) throws JsonRpcException, IOException { 1283 JavaType resultType = collectionTypeForClasses(List.class, AddressUtxoInfo.class); 1284 return send("getaddressutxos", resultType, new AddressRequest(addressList)); 1285 } 1286}