// Copyright (c) 2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package btcrpcclient import ( "encoding/base64" "encoding/json" "fmt" "github.com/conformal/btcjson" "github.com/conformal/btcutil" "github.com/conformal/btcwire" "github.com/conformal/btcws" ) // FutureDebugLevelResult is a future promise to deliver the result of a // DebugLevelAsync RPC invocation (or an applicable error). type FutureDebugLevelResult chan *response // Receive waits for the response promised by the future and returns the result // of setting the debug logging level to the passed level specification or the // list of of the available subsystems for the special keyword 'show'. func (r FutureDebugLevelResult) Receive() (string, error) { res, err := receiveFuture(r) if err != nil { return "", err } // Unmashal the result as a string. var result string err = json.Unmarshal(res, &result) if err != nil { return "", err } return result, nil } // DebugLevelAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on // the returned instance. // // See DebugLevel for the blocking version and more details. // // NOTE: This is a btcd extension. func (c *Client) DebugLevelAsync(levelSpec string) FutureDebugLevelResult { id := c.NextID() cmd, err := btcjson.NewDebugLevelCmd(id, levelSpec) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // DebugLevel dynamically sets the debug logging level to the passed level // specification. // // The levelspec can either a debug level or of the form: // =,=,... // // Additionally, the special keyword 'show' can be used to get a list of the // available subsystems. // // NOTE: This is a btcd extension. func (c *Client) DebugLevel(levelSpec string) (string, error) { return c.DebugLevelAsync(levelSpec).Receive() } // FutureCreateEncryptedWalletResult is a future promise to deliver the error // result of a CreateEncryptedWalletAsync RPC invocation. type FutureCreateEncryptedWalletResult chan *response // Receive waits for and returns the error response promised by the future. func (r FutureCreateEncryptedWalletResult) Receive() error { _, err := receiveFuture(r) return err } // CreateEncryptedWalletAsync returns an instance of a type that can be used to // get the result of the RPC at some future time by invoking the Receive // function on the returned instance. // // See CreateEncryptedWallet for the blocking version and more details. // // NOTE: This is a btcwallet extension. func (c *Client) CreateEncryptedWalletAsync(passphrase string) FutureCreateEncryptedWalletResult { id := c.NextID() cmd := btcws.NewCreateEncryptedWalletCmd(id, passphrase) return c.sendCmd(cmd) } // CreateEncryptedWallet requests the creation of an encrypted wallet. Wallets // managed by btcwallet are only written to disk with encrypted private keys, // and generating wallets on the fly is impossible as it requires user input for // the encryption passphrase. This RPC specifies the passphrase and instructs // the wallet creation. This may error if a wallet is already opened, or the // new wallet cannot be written to disk. // // NOTE: This is a btcwallet extension. func (c *Client) CreateEncryptedWallet(passphrase string) error { return c.CreateEncryptedWalletAsync(passphrase).Receive() } // FutureListAddressTransactionsResult is a future promise to deliver the result // of a ListAddressTransactionsAsync RPC invocation (or an applicable error). type FutureListAddressTransactionsResult chan *response // Receive waits for the response promised by the future and returns information // about all transactions associated with the provided addresses. func (r FutureListAddressTransactionsResult) Receive() ([]btcjson.ListTransactionsResult, error) { res, err := receiveFuture(r) if err != nil { return nil, err } // Unmarshal the result as an array of listtransactions objects. var transactions []btcjson.ListTransactionsResult err = json.Unmarshal(res, &transactions) if err != nil { return nil, err } return transactions, nil } // ListAddressTransactionsAsync returns an instance of a type that can be used // to get the result of the RPC at some future time by invoking the Receive // function on the returned instance. // // See ListAddressTransactions for the blocking version and more details. // // NOTE: This is a btcd extension. func (c *Client) ListAddressTransactionsAsync(addresses []btcutil.Address, account string) FutureListAddressTransactionsResult { // Convert addresses to strings. addrs := make([]string, 0, len(addresses)) for _, addr := range addresses { addrs = append(addrs, addr.EncodeAddress()) } id := c.NextID() cmd, err := btcws.NewListAddressTransactionsCmd(id, addrs, account) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // ListAddressTransactions returns information about all transactions associated // with the provided addresses. // // NOTE: This is a btcwallet extension. func (c *Client) ListAddressTransactions(addresses []btcutil.Address, account string) ([]btcjson.ListTransactionsResult, error) { return c.ListAddressTransactionsAsync(addresses, account).Receive() } // FutureGetBestBlockResult is a future promise to deliver the result of a // GetBestBlockAsync RPC invocation (or an applicable error). type FutureGetBestBlockResult chan *response // Receive waits for the response promised by the future and returns the hash // and height of the block in the longest (best) chain. func (r FutureGetBestBlockResult) Receive() (*btcwire.ShaHash, int32, error) { res, err := receiveFuture(r) if err != nil { return nil, 0, err } // Unmarsal result as a getbestblock result object. var bestBlock btcws.GetBestBlockResult err = json.Unmarshal(res, &bestBlock) if err != nil { return nil, 0, err } // Convert hash string. hash, err := btcwire.NewShaHashFromStr(bestBlock.Hash) if err != nil { return nil, 0, err } return hash, bestBlock.Height, nil } // GetBestBlockAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on the // returned instance. // // See GetBestBlock for the blocking version and more details. // // NOTE: This is a btcd extension. func (c *Client) GetBestBlockAsync() FutureGetBestBlockResult { id := c.NextID() cmd := btcws.NewGetBestBlockCmd(id) return c.sendCmd(cmd) } // GetBestBlock returns the hash and height of the block in the longest (best) // chain. // // NOTE: This is a btcd extension. func (c *Client) GetBestBlock() (*btcwire.ShaHash, int32, error) { return c.GetBestBlockAsync().Receive() } // FutureGetCurrentNetResult is a future promise to deliver the result of a // GetCurrentNetAsync RPC invocation (or an applicable error). type FutureGetCurrentNetResult chan *response // Receive waits for the response promised by the future and returns the network // the server is running on. func (r FutureGetCurrentNetResult) Receive() (btcwire.BitcoinNet, error) { res, err := receiveFuture(r) if err != nil { return 0, err } // Unmarshal result as an int64. var net int64 err = json.Unmarshal(res, &net) if err != nil { return 0, err } return btcwire.BitcoinNet(net), nil } // GetCurrentNetAsync returns an instance of a type that can be used to get the // result of the RPC at some future time by invoking the Receive function on the // returned instance. // // See GetCurrentNet for the blocking version and more details. // // NOTE: This is a btcd extension. func (c *Client) GetCurrentNetAsync() FutureGetCurrentNetResult { id := c.NextID() cmd := btcws.NewGetCurrentNetCmd(id) return c.sendCmd(cmd) } // GetCurrentNet returns the network the server is running on. // // NOTE: This is a btcd extension. func (c *Client) GetCurrentNet() (btcwire.BitcoinNet, error) { return c.GetCurrentNetAsync().Receive() } // FutureExportWatchingWalletResult is a future promise to deliver the result of // an ExportWatchingWalletAsync RPC invocation (or an applicable error). type FutureExportWatchingWalletResult chan *response // Receive waits for the response promised by the future and returns the // exported wallet. func (r FutureExportWatchingWalletResult) Receive() ([]byte, []byte, error) { res, err := receiveFuture(r) if err != nil { return nil, nil, err } // Unmarshal result as a JSON object. var obj map[string]interface{} err = json.Unmarshal(res, &obj) if err != nil { return nil, nil, err } // Check for the wallet and tx string fields in the object. base64Wallet, ok := obj["wallet"].(string) if !ok { return nil, nil, fmt.Errorf("unexpected response type for "+ "exportwatchingwallet 'wallet' field: %T\n", obj["wallet"]) } base64TxStore, ok := obj["tx"].(string) if !ok { return nil, nil, fmt.Errorf("unexpected response type for "+ "exportwatchingwallet 'tx' field: %T\n", obj["tx"]) } walletBytes, err := base64.StdEncoding.DecodeString(base64Wallet) if err != nil { return nil, nil, err } txStoreBytes, err := base64.StdEncoding.DecodeString(base64TxStore) if err != nil { return nil, nil, err } return walletBytes, txStoreBytes, nil } // ExportWatchingWalletAsync returns an instance of a type that can be used to // get the result of the RPC at some future time by invoking the Receive // function on the returned instance. // // See ExportWatchingWallet for the blocking version and more details. // // NOTE: This is a btcwallet extension. func (c *Client) ExportWatchingWalletAsync(account string) FutureExportWatchingWalletResult { id := c.NextID() cmd, err := btcws.NewExportWatchingWalletCmd(id, account, true) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // ExportWatchingWallet returns the raw bytes for a watching-only version of // wallet.bin and tx.bin, respectively, for the specified account that can be // used by btcwallet to enable a wallet which does not have the private keys // necessary to spend funds. // // NOTE: This is a btcwallet extension. func (c *Client) ExportWatchingWallet(account string) ([]byte, []byte, error) { return c.ExportWatchingWalletAsync(account).Receive() }