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