github.com/btcsuite/btcd@v0.24.0/rpcclient/extensions.go (about)

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