doc.go raw

   1  /*Package rpcclient implements a websocket-enabled Bitcoin JSON-RPC client.
   2  
   3  Overview
   4  
   5  This client provides a robust and easy to use client for interfacing with a Bitcoin RPC server that uses a pod/bitcoin
   6  core compatible Bitcoin JSON-RPC API. This client has been tested with pod (https://github.com/p9c/monorepo), btcwallet
   7  (https://github.com/p9c/monorepo/wallet), and bitcoin core (https://github.com/bitcoin).
   8  
   9  In addition to the compatible standard HTTP POST JSON-RPC API, pod and btcwallet provide a websocket interface that is
  10  more efficient than the standard HTTP POST method of accessing RPC. The section below discusses the differences between
  11  HTTP POST and websockets.
  12  
  13  **TODO:** The sense of TLS is reversed because many third party apps don't understand it and it complicates setup, so this next paragraph is wrong:
  14  
  15  ~~By default, this client assumes the RPC server supports websockets and has TLS enabled. In practice, this currently
  16  means it assumes you are talking to pod or btcwallet by default. However, configuration options are provided to fall
  17  back to HTTP POST and disable TLS to support talking with inferior bitcoin core style RPC servers.~~
  18  
  19  SSL third party certification security is deeply antiquated and outdated model, and irrelevant for developers and
  20  servers running all on localhost or connected via already secured VPNs including Tor. In the future a protocol will be
  21  developed based on elliptic curve cryptographic accounts, Diffie Hellman Perfect Forward Secrecy session negotiation (as
  22  used in OTR and other messaging protocols), more along the lines of SSH.
  23  
  24  Websockets vs HTTP POST
  25  
  26  In HTTP POST-based JSON-RPC, every request creates a new HTTP connection, issues the call, waits for the response, and
  27  closes the connection. This adds quite a bit of overhead to every call and lacks flexibility for features such as
  28  notifications.
  29  
  30  In contrast, the websocket-based JSON-RPC interface provided by pod and btcwallet only uses a single connection that
  31  remains open and allows asynchronous bi-directional communication. The websocket interface supports all of the same
  32  commands as HTTP POST, but they can be invoked without having to go through a connect/disconnect cycle for every call.
  33  
  34  In addition, the websocket interface provides other nice features such as the ability to register for asynchronous
  35  notifications of various events.
  36  
  37  Synchronous vs Asynchronous API
  38  
  39  The client provides both a synchronous (blocking) and asynchronous API. The synchronous (blocking) API is typically
  40  sufficient for most use cases. It works by issuing the RPC and blocking until the response is received. This allows
  41  straightforward code where you have the response as soon as the function returns.
  42  
  43  The asynchronous API works on the concept of futures. When you invoke the async version of a command, it will quickly
  44  return an instance of a type that promises to provide the result of the RPC at some future time. In the background, the
  45  RPC call is issued and the result is stored in the returned instance.
  46  
  47  Invoking the Receive method on the returned instance will either return the result immediately if it has already
  48  arrived, or block until it has. This is useful since it provides the caller with greater control over concurrency.
  49  
  50  Notifications
  51  
  52  The first important part of notifications is to realize that they will only work when connected via websockets. This
  53  should intuitively make sense because HTTP POST mode does not keep a connection open!
  54  
  55  All notifications provided by pod require registration to opt-in.
  56  
  57  For example, if you want to be notified when funds are received by a set of addresses, you register the addresses via
  58  the NotifyReceived (or NotifyReceivedAsync) function.
  59  
  60  Notification Handlers
  61  
  62  Notifications are exposed by the client through the use of callback handlers which are setup via a NotificationHandlers
  63  instance that is specified by the caller when creating the client.
  64  
  65  It is important that these notification handlers complete quickly since they are intentionally in the main read loop and
  66  will block further reads until they complete.
  67  
  68  This provides the caller with the flexibility to decide what to do when notifications are coming in faster than they are
  69  being handled.
  70  
  71  In particular this means issuing a blocking RPC call from a callback handler will cause a deadlock as more server
  72  responses won't be read until the callback returns, but the callback would be waiting for a response.
  73  
  74  Thus, any additional RPCs must be issued an a completely decoupled manner.
  75  
  76  Automatic Reconnection
  77  
  78  By default, when running in websockets mode, this client will automatically keep trying to reconnect to the RPC server
  79  should the connection be lost.
  80  
  81  There is a back-off in between each connection attempt until it reaches one try per minute. Once a connection is
  82  re-established, all previously registered notifications are automatically re-registered and any in-flight commands are
  83  re-issued. This means from the caller's perspective, the request simply takes longer to complete.
  84  
  85  The caller may invoke the Shutdown method on the client to force the client to cease reconnect attempts and return
  86  ErrClientShutdown for all outstanding commands.
  87  
  88  The automatic reconnection can be disabled by setting the DisableAutoReconnect flag to true in the connection config
  89  when creating the client.
  90  
  91  Minor RPC Server Differences and Chain/Wallet Separation
  92  
  93  Some of the commands are extensions specific to a particular RPC server.
  94  
  95  For example, the DebugLevel call is an extension only provided by pod (and sac wallet passthrough). Therefore if you
  96  call one of these commands against an RPC server that doesn't provide them, you will get an unimplemented error from the
  97  server. An effort has been made to call out which commmands are extensions in their documentation.
  98  
  99  Also, it is important to realize that pod intentionally separates the wallet functionality into a separate process named
 100  btcwallet. This means if you are connected to the pod RPC server directly, only the RPCs which are related to chain
 101  services will be available. Depending on your application, you might only need chain-related RPCs. In contrast,
 102  btcwallet provides pass through treatment for chain-related RPCs, so it supports them in addition to wallet-related
 103  RPCs.
 104  
 105  Errors
 106  
 107  There are 3 categories of errors that will be returned throughout this package:
 108  
 109   - Errors related to the client connection such as authentication, endpoint, disconnect, and shutdown
 110  
 111   - Errors that occur before communicating with the remote RPC server such as command creation and marshaling errors or
 112   issues talking to the remote server
 113  
 114   - Errors returned from the remote RPC server like unimplemented commands, nonexistent requested blocks and
 115   transactions, malformed data, and incorrect networks
 116  
 117  The first category of errors are typically one of ErrInvalidAuth, ErrInvalidEndpoint, ErrClientDisconnect, or
 118  ErrClientShutdown.
 119  
 120  NOTE: The ErrClientDisconnect will not be returned unless the DisableAutoReconnect flag is set since the client
 121  automatically handles reconnect by default as previously described.
 122  
 123  The second category of errors typically indicates a programmer error and as such the type can vary, but usually will be
 124  best handled by simply showing/logging it.
 125  
 126  The third category of errors, that is errors returned by the server, can be detected by type asserting the error in a
 127  *btcjson.RPCError.
 128  
 129  For example, to detect if a command is unimplemented by the remote RPC server:
 130  
 131    amount, e := client.GetBalance("")
 132    if e != nil  {
 133  
 134    	if jerr, ok := err.(*btcjson.RPCError); ok {
 135  
 136    		switch jerr.Code {
 137  
 138    		case btcjson.ErrRPCUnimplemented:
 139    			// Handle not implemented error
 140    		// Handle other specific errors you care about
 141  		}
 142    	}
 143    	// Log or otherwise handle the error knowing it was not one returned
 144    	// from the remote RPC server.
 145    }
 146  
 147  Example Usage
 148  
 149  The following full-blown client examples are in the examples directory:
 150  
 151   - bitcoincorehttp
 152  
 153     Connects to a bitcoin core RPC server using HTTP POST mode with TLS disabled and gets the current block count
 154  
 155   - podwebsockets
 156  
 157     Connects to a pod RPC server using TLS-secured websockets, registers for block connected and block disconnected
 158     notifications, and gets the current block count
 159  
 160   - btcwalletwebsockets
 161  
 162     Connects to a btcwallet RPC server using TLS-secured websockets, registers for notifications about changes to account
 163     balances, and gets a list of unspent transaction outputs (utxos) the wallet can sign
 164  */
 165  package rpcclient
 166