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}