1 package rpcclient
2 3 import (
4 "bytes"
5 "encoding/base64"
6 "encoding/hex"
7 js "encoding/json"
8 "fmt"
9 "github.com/p9c/p9/pkg/btcaddr"
10 11 "github.com/p9c/p9/pkg/btcjson"
12 "github.com/p9c/p9/pkg/chainhash"
13 "github.com/p9c/p9/pkg/wire"
14 )
15 16 // FutureDebugLevelResult is a future promise to deliver the result of a DebugLevelAsync RPC invocation (or an
17 // applicable error).
18 type FutureDebugLevelResult chan *response
19 20 // Receive waits for the response promised by the future and returns the result of setting the debug logging level to
21 // the passed level specification or the list of of the available subsystems for the special keyword 'show'.
22 func (r FutureDebugLevelResult) Receive() (string, error) {
23 res, e := receiveFuture(r)
24 if e != nil {
25 return "", e
26 }
27 // Unmashal the result as a string.
28 var result string
29 e = js.Unmarshal(res, &result)
30 if e != nil {
31 return "", e
32 }
33 return result, nil
34 }
35 36 // DebugLevelAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
37 // invoking the Receive function on the returned instance. See DebugLevel for the blocking version and more details.
38 // NOTE: This is a pod extension.
39 func (c *Client) DebugLevelAsync(levelSpec string) FutureDebugLevelResult {
40 cmd := btcjson.NewDebugLevelCmd(levelSpec)
41 return c.sendCmd(cmd)
42 }
43 44 // DebugLevel dynamically sets the debug logging level to the passed level specification. The levelspec can be either a
45 // debug level or of the form:
46 //
47 // <subsystem>=<level>,<subsystem2>=<level2>,...
48 //
49 // Additionally, the special keyword 'show' can be used to get a list of the available subsystems.
50 //
51 // NOTE: This is a pod extension.
52 func (c *Client) DebugLevel(levelSpec string) (string, error) {
53 return c.DebugLevelAsync(levelSpec).Receive()
54 }
55 56 // FutureCreateEncryptedWalletResult is a future promise to deliver the error result of a CreateEncryptedWalletAsync RPC
57 // invocation.
58 type FutureCreateEncryptedWalletResult chan *response
59 60 // Receive waits for and returns the error response promised by the future.
61 func (r FutureCreateEncryptedWalletResult) Receive() (e error) {
62 _, e = receiveFuture(r)
63 return e
64 }
65 66 // CreateEncryptedWalletAsync returns an instance of a type that can be used to get the result of the RPC at some future
67 // time by invoking the Receive function on the returned instance. See CreateEncryptedWallet for the blocking version
68 // and more details. NOTE: This is a btcwallet extension.
69 func (c *Client) CreateEncryptedWalletAsync(passphrase string) FutureCreateEncryptedWalletResult {
70 cmd := btcjson.NewCreateEncryptedWalletCmd(passphrase)
71 return c.sendCmd(cmd)
72 }
73 74 // CreateEncryptedWallet requests the creation of an encrypted wallet. Wallets managed by btcwallet are only written to
75 // disk with encrypted private keys, and generating wallets on the fly is impossible as it requires user input for the
76 // encryption passphrase.
77 //
78 // This RPC specifies the passphrase and instructs the wallet creation. This may error if a
79 // wallet is already opened, or the new wallet cannot be written to disk. NOTE: This is a btcwallet extension.
80 func (c *Client) CreateEncryptedWallet(passphrase string) (e error) {
81 return c.CreateEncryptedWalletAsync(passphrase).Receive()
82 }
83 84 // FutureListAddressTransactionsResult is a future promise to deliver the result of a ListAddressTransactionsAsync RPC
85 // invocation (or an applicable error).
86 type FutureListAddressTransactionsResult chan *response
87 88 // Receive waits for the response promised by the future and returns information about all transactions associated with
89 // the provided addresses.
90 func (r FutureListAddressTransactionsResult) Receive() ([]btcjson.ListTransactionsResult, error) {
91 res, e := receiveFuture(r)
92 if e != nil {
93 return nil, e
94 }
95 // Unmarshal the result as an array of listtransactions objects.
96 var transactions []btcjson.ListTransactionsResult
97 e = js.Unmarshal(res, &transactions)
98 if e != nil {
99 return nil, e
100 }
101 return transactions, nil
102 }
103 104 // ListAddressTransactionsAsync returns an instance of a type that can be used get the result of the RPC at some future
105 // time by invoking the Receive function on the returned instance. See ListAddressTransactions for the blocking version
106 // and more details. NOTE: This is a pod extension.
107 func (c *Client) ListAddressTransactionsAsync(
108 addresses []btcaddr.Address,
109 account string,
110 ) FutureListAddressTransactionsResult {
111 // Convert addresses to strings.
112 addrs := make([]string, 0, len(addresses))
113 for _, addr := range addresses {
114 addrs = append(addrs, addr.EncodeAddress())
115 }
116 cmd := btcjson.NewListAddressTransactionsCmd(addrs, &account)
117 return c.sendCmd(cmd)
118 }
119 120 // ListAddressTransactions returns information about all transactions associated with the provided addresses. NOTE: This
121 // is a btcwallet extension.
122 func (c *Client) ListAddressTransactions(addresses []btcaddr.Address, account string) (
123 []btcjson.ListTransactionsResult,
124 error,
125 ) {
126 return c.ListAddressTransactionsAsync(addresses, account).Receive()
127 }
128 129 // FutureGetBestBlockResult is a future promise to deliver the result of a GetBestBlockAsync RPC invocation (or an
130 // applicable error).
131 type FutureGetBestBlockResult chan *response
132 133 // Receive waits for the response promised by the future and returns the hash and height of the block in the longest
134 // (best) chain.
135 func (r FutureGetBestBlockResult) Receive() (*chainhash.Hash, int32, error) {
136 res, e := receiveFuture(r)
137 if e != nil {
138 return nil, 0, e
139 }
140 // Unmarshal result as a getbestblock result object.
141 var bestBlock btcjson.GetBestBlockResult
142 e = js.Unmarshal(res, &bestBlock)
143 if e != nil {
144 return nil, 0, e
145 }
146 // Convert to hash from string.
147 hash, e := chainhash.NewHashFromStr(bestBlock.Hash)
148 if e != nil {
149 return nil, 0, e
150 }
151 return hash, bestBlock.Height, nil
152 }
153 154 // GetBestBlockAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
155 // invoking the Receive function on the returned instance. See GetBestBlock for the blocking version and more details.
156 //
157 // NOTE: This is a pod extension.
158 func (c *Client) GetBestBlockAsync() FutureGetBestBlockResult {
159 cmd := btcjson.NewGetBestBlockCmd()
160 return c.sendCmd(cmd)
161 }
162 163 // GetBestBlock returns the hash and height of the block in the longest (best) chain.
164 //
165 // NOTE: This is a pod extension.
166 func (c *Client) GetBestBlock() (*chainhash.Hash, int32, error) {
167 return c.GetBestBlockAsync().Receive()
168 }
169 170 // FutureGetCurrentNetResult is a future promise to deliver the result of a GetCurrentNetAsync RPC invocation (or an
171 // applicable error).
172 type FutureGetCurrentNetResult chan *response
173 174 // Receive waits for the response promised by the future and returns the network the server is running on.
175 func (r FutureGetCurrentNetResult) Receive() (wire.BitcoinNet, error) {
176 res, e := receiveFuture(r)
177 if e != nil {
178 return 0, e
179 }
180 // Unmarshal result as an int64.
181 var net int64
182 e = js.Unmarshal(res, &net)
183 if e != nil {
184 return 0, e
185 }
186 return wire.BitcoinNet(net), nil
187 }
188 189 // GetCurrentNetAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
190 // invoking the Receive function on the returned instance. See GetCurrentNet for the blocking version and more details.
191 //
192 // NOTE: This is a pod extension.
193 func (c *Client) GetCurrentNetAsync() FutureGetCurrentNetResult {
194 cmd := btcjson.NewGetCurrentNetCmd()
195 return c.sendCmd(cmd)
196 }
197 198 // GetCurrentNet returns the network the server is running on.
199 //
200 // NOTE: This is a pod extension.
201 func (c *Client) GetCurrentNet() (wire.BitcoinNet, error) {
202 return c.GetCurrentNetAsync().Receive()
203 }
204 205 // FutureGetHeadersResult is a future promise to deliver the result of a getheaders RPC invocation (or an applicable
206 // error).
207 //
208 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
209 type FutureGetHeadersResult chan *response
210 211 // Receive waits for the response promised by the future and returns the getheaders result.
212 //
213 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
214 func (r FutureGetHeadersResult) Receive() ([]wire.BlockHeader, error) {
215 res, e := receiveFuture(r)
216 if e != nil {
217 return nil, e
218 }
219 // Unmarshal result as a slice of strings.
220 var result []string
221 e = js.Unmarshal(res, &result)
222 if e != nil {
223 return nil, e
224 }
225 // Deserialize the []string into []wire.BlockHeader.
226 headers := make([]wire.BlockHeader, len(result))
227 for i, headerHex := range result {
228 serialized, e := hex.DecodeString(headerHex)
229 if e != nil {
230 return nil, e
231 }
232 e = headers[i].Deserialize(bytes.NewReader(serialized))
233 if e != nil {
234 return nil, e
235 }
236 }
237 return headers, nil
238 }
239 240 // GetHeadersAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
241 // invoking the Receive function on the returned instance. See GetHeaders for the blocking version and more details.
242 //
243 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
244 func (c *Client) GetHeadersAsync(blockLocators []chainhash.Hash, hashStop *chainhash.Hash) FutureGetHeadersResult {
245 locators := make([]string, len(blockLocators))
246 for i := range blockLocators {
247 locators[i] = blockLocators[i].String()
248 }
249 hash := ""
250 if hashStop != nil {
251 hash = hashStop.String()
252 }
253 cmd := btcjson.NewGetHeadersCmd(locators, hash)
254 return c.sendCmd(cmd)
255 }
256 257 // GetHeaders mimics the wire protocol getheaders and headers messages by returning all headers on the main chain after
258 // the first known block in the locators, up until a block hash matches hashStop.
259 //
260 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
261 func (c *Client) GetHeaders(blockLocators []chainhash.Hash, hashStop *chainhash.Hash) ([]wire.BlockHeader, error) {
262 return c.GetHeadersAsync(blockLocators, hashStop).Receive()
263 }
264 265 // FutureExportWatchingWalletResult is a future promise to deliver the result of an ExportWatchingWalletAsync RPC
266 // invocation (or an applicable error).
267 type FutureExportWatchingWalletResult chan *response
268 269 // Receive waits for the response promised by the future and returns the exported wallet.
270 func (r FutureExportWatchingWalletResult) Receive() ([]byte, []byte, error) {
271 res, e := receiveFuture(r)
272 if e != nil {
273 return nil, nil, e
274 }
275 // Unmarshal result as a JSON object.
276 var obj map[string]interface{}
277 e = js.Unmarshal(res, &obj)
278 if e != nil {
279 return nil, nil, e
280 }
281 // Chk for the wallet and tx string fields in the object.
282 base64Wallet, ok := obj["wallet"].(string)
283 if !ok {
284 return nil, nil, fmt.Errorf(
285 "unexpected response type for exportwatchingwallet 'wallet' field: %T\n",
286 obj["wallet"],
287 )
288 }
289 base64TxStore, ok := obj["tx"].(string)
290 if !ok {
291 return nil, nil, fmt.Errorf(
292 "unexpected response type for exportwatchingwallet 'tx' field: %T\n",
293 obj["tx"],
294 )
295 }
296 walletBytes, e := base64.StdEncoding.DecodeString(base64Wallet)
297 if e != nil {
298 return nil, nil, e
299 }
300 txStoreBytes, e := base64.StdEncoding.DecodeString(base64TxStore)
301 if e != nil {
302 return nil, nil, e
303 }
304 return walletBytes, txStoreBytes, nil
305 }
306 307 // ExportWatchingWalletAsync returns an instance of a type that can be used to get the result of the RPC at some future
308 // time by invoking the Receive function on the returned instance. See ExportWatchingWallet for the blocking version and
309 // more details.
310 //
311 // NOTE: This is a btcwallet extension.
312 func (c *Client) ExportWatchingWalletAsync(account string) FutureExportWatchingWalletResult {
313 cmd := btcjson.NewExportWatchingWalletCmd(&account, btcjson.Bool(true))
314 return c.sendCmd(cmd)
315 }
316 317 // ExportWatchingWallet returns the raw bytes for a watching-only version of wallet.bin and tx.bin, respectively, for
318 // the specified account that can be used by btcwallet to enable a wallet which does not have the private keys necessary
319 // to spend funds.
320 //
321 // NOTE: This is a btcwallet extension.
322 func (c *Client) ExportWatchingWallet(account string) ([]byte, []byte, error) {
323 return c.ExportWatchingWalletAsync(account).Receive()
324 }
325 326 // FutureSessionResult is a future promise to deliver the result of a SessionAsync RPC invocation (or an applicable
327 // error).
328 type FutureSessionResult chan *response
329 330 // Receive waits for the response promised by the future and returns the session result.
331 func (r FutureSessionResult) Receive() (*btcjson.SessionResult, error) {
332 res, e := receiveFuture(r)
333 if e != nil {
334 return nil, e
335 }
336 // Unmarshal result as a session result object.
337 var session btcjson.SessionResult
338 e = js.Unmarshal(res, &session)
339 if e != nil {
340 return nil, e
341 }
342 return &session, nil
343 }
344 345 // SessionAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
346 // invoking the Receive function on the returned instance. See Session for the blocking version and more details.
347 //
348 // NOTE: This is a btcsuite extension.
349 func (c *Client) SessionAsync() FutureSessionResult {
350 // Not supported in HTTP POST mode.
351 if c.config.HTTPPostMode {
352 return newFutureError(ErrWebsocketsRequired)
353 }
354 cmd := btcjson.NewSessionCmd()
355 return c.sendCmd(cmd)
356 }
357 358 // Session returns details regarding a websocket client's current connection. This RPC requires the client to be running
359 // in websocket mode.
360 //
361 // NOTE: This is a btcsuite extension.
362 func (c *Client) Session() (*btcjson.SessionResult, error) {
363 return c.SessionAsync().Receive()
364 }
365 366 // FutureVersionResult is a future promise to deliver the result of a version RPC invocation (or an applicable error).
367 //
368 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
369 type FutureVersionResult chan *response
370 371 // Receive waits for the response promised by the future and returns the version result.
372 //
373 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
374 func (r FutureVersionResult) Receive() (
375 map[string]btcjson.VersionResult,
376 error,
377 ) {
378 res, e := receiveFuture(r)
379 if e != nil {
380 return nil, e
381 }
382 // Unmarshal result as a version result object.
383 var vr map[string]btcjson.VersionResult
384 e = js.Unmarshal(res, &vr)
385 if e != nil {
386 return nil, e
387 }
388 return vr, nil
389 }
390 391 // VersionAsync returns an instance of a type that can be used to get the result of the RPC at some future time by
392 // invoking the Receive function on the returned instance. See Version for the blocking version and more details.
393 //
394 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
395 func (c *Client) VersionAsync() FutureVersionResult {
396 cmd := btcjson.NewVersionCmd()
397 return c.sendCmd(cmd)
398 }
399 400 // Version returns information about the server's JSON-RPC API versions.
401 //
402 // NOTE: This is a btcsuite extension ported from github.com/decred/dcrrpcclient.
403 func (c *Client) Version() (map[string]btcjson.VersionResult, error) {
404 return c.VersionAsync().Receive()
405 }
406