exts.go raw

   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