// 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/hex" "encoding/json" "errors" "github.com/conformal/btcjson" "github.com/conformal/btcutil" ) // FutureGetGenerateResult is a future promise to deliver the result of a // GetGenerateAsync RPC invocation (or an applicable error). type FutureGetGenerateResult chan *response // Receive waits for the response promised by the future and returns true if the // server is set to mine, otherwise false. func (r FutureGetGenerateResult) Receive() (bool, error) { res, err := receiveFuture(r) if err != nil { return false, err } // Unmarshal result as a boolean. var result bool err = json.Unmarshal(res, &result) if err != nil { return false, err } return result, nil } // GetGenerateAsync 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 GetGenerate for the blocking version and more details. func (c *Client) GetGenerateAsync() FutureGetGenerateResult { id := c.NextID() cmd, err := btcjson.NewGetGenerateCmd(id) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetGenerate returns true if the server is set to mine, otherwise false. func (c *Client) GetGenerate() (bool, error) { return c.GetGenerateAsync().Receive() } // FutureSetGenerateResult is a future promise to deliver the result of a // SetGenerateAsync RPC invocation (or an applicable error). type FutureSetGenerateResult chan *response // Receive waits for the response promised by the future and returns an error if // any occurred when setting the server to generate coins (mine) or not. func (r FutureSetGenerateResult) Receive() error { _, err := receiveFuture(r) if err != nil { return err } return nil } // SetGenerateAsync 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 SetGenerate for the blocking version and more details. func (c *Client) SetGenerateAsync(enable bool, numCPUs int) FutureSetGenerateResult { id := c.NextID() cmd, err := btcjson.NewSetGenerateCmd(id, enable, numCPUs) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // SetGenerate sets the server to generate coins (mine) or not. func (c *Client) SetGenerate(enable bool, numCPUs int) error { return c.SetGenerateAsync(enable, numCPUs).Receive() } // FutureGetHashesPerSecResult is a future promise to deliver the result of a // GetHashesPerSecAsync RPC invocation (or an applicable error). type FutureGetHashesPerSecResult chan *response // Receive waits for the response promised by the future and returns a recent // hashes per second performance measurement while generating coins (mining). // Zero is returned if the server is not mining. func (r FutureGetHashesPerSecResult) Receive() (int64, error) { res, err := receiveFuture(r) if err != nil { return -1, err } // Unmarshal result as an int64. var result int64 err = json.Unmarshal(res, &result) if err != nil { return 0, err } return result, nil } // GetHashesPerSecAsync 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 GetHashesPerSec for the blocking version and more details. func (c *Client) GetHashesPerSecAsync() FutureGetHashesPerSecResult { id := c.NextID() cmd, err := btcjson.NewGetHashesPerSecCmd(id) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetHashesPerSec returns a recent hashes per second performance measurement // while generating coins (mining). Zero is returned if the server is not // mining. func (c *Client) GetHashesPerSec() (int64, error) { return c.GetHashesPerSecAsync().Receive() } // FutureGetMiningInfoResult is a future promise to deliver the result of a // GetMiningInfoAsync RPC invocation (or an applicable error). type FutureGetMiningInfoResult chan *response // Receive waits for the response promised by the future and returns the mining // information. func (r FutureGetMiningInfoResult) Receive() (*btcjson.GetMiningInfoResult, error) { res, err := receiveFuture(r) if err != nil { return nil, err } // Unmarshal result as a getmininginfo result object. var infoResult btcjson.GetMiningInfoResult err = json.Unmarshal(res, &infoResult) if err != nil { return nil, err } return &infoResult, nil } // GetMiningInfoAsync 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 GetMiningInfo for the blocking version and more details. func (c *Client) GetMiningInfoAsync() FutureGetMiningInfoResult { id := c.NextID() cmd, err := btcjson.NewGetMiningInfoCmd(id) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetMiningInfo returns mining information. func (c *Client) GetMiningInfo() (*btcjson.GetMiningInfoResult, error) { return c.GetMiningInfoAsync().Receive() } // FutureGetNetworkHashPS is a future promise to deliver the result of a // GetNetworkHashPSAsync RPC invocation (or an applicable error). type FutureGetNetworkHashPS chan *response // Receive waits for the response promised by the future and returns the // estimated network hashes per second for the block heights provided by the // parameters. func (r FutureGetNetworkHashPS) Receive() (int64, error) { res, err := receiveFuture(r) if err != nil { return -1, err } // Unmarshal result as an int64. var result int64 err = json.Unmarshal(res, &result) if err != nil { return 0, err } return result, nil } // GetNetworkHashPSAsync 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 GetNetworkHashPS for the blocking version and more details. func (c *Client) GetNetworkHashPSAsync() FutureGetNetworkHashPS { id := c.NextID() cmd, err := btcjson.NewGetNetworkHashPSCmd(id) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetNetworkHashPS returns the estimated network hashes per second using the // default number of blocks and the most recent block height. // // See GetNetworkHashPS2 to override the number of blocks to use and // GetNetworkHashPS3 to override the height at which to calculate the estimate. func (c *Client) GetNetworkHashPS() (int64, error) { return c.GetNetworkHashPSAsync().Receive() } // GetNetworkHashPS2Async 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 GetNetworkHashPS2 for the blocking version and more details. func (c *Client) GetNetworkHashPS2Async(blocks int) FutureGetNetworkHashPS { id := c.NextID() cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetNetworkHashPS2 returns the estimated network hashes per second for the // specified previous number of blocks working backwards from the most recent // block height. The blocks parameter can also be -1 in which case the number // of blocks since the last difficulty change will be used. // // See GetNetworkHashPS to use defaults and GetNetworkHashPS3 to override the // height at which to calculate the estimate. func (c *Client) GetNetworkHashPS2(blocks int) (int64, error) { return c.GetNetworkHashPS2Async(blocks).Receive() } // GetNetworkHashPS3Async 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 GetNetworkHashPS3 for the blocking version and more details. func (c *Client) GetNetworkHashPS3Async(blocks, height int) FutureGetNetworkHashPS { id := c.NextID() cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks, height) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetNetworkHashPS3 returns the estimated network hashes per second for the // specified previous number of blocks working backwards from the specified // block height. The blocks parameter can also be -1 in which case the number // of blocks since the last difficulty change will be used. // // See GetNetworkHashPS and GetNetworkHashPS2 to use defaults. func (c *Client) GetNetworkHashPS3(blocks, height int) (int64, error) { return c.GetNetworkHashPS3Async(blocks, height).Receive() } // FutureGetWork is a future promise to deliver the result of a // GetWorkAsync RPC invocation (or an applicable error). type FutureGetWork chan *response // Receive waits for the response promised by the future and returns the hash // data to work on. func (r FutureGetWork) Receive() (*btcjson.GetWorkResult, error) { res, err := receiveFuture(r) if err != nil { return nil, err } // Unmarshal result as a getwork result object. var result btcjson.GetWorkResult err = json.Unmarshal(res, &result) if err != nil { return nil, err } return &result, nil } // GetWorkAsync 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 GetWork for the blocking version and more details. func (c *Client) GetWorkAsync() FutureGetWork { id := c.NextID() cmd, err := btcjson.NewGetWorkCmd(id) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetWork returns hash data to work on. // // See GetWorkSubmit to submit the found solution. func (c *Client) GetWork() (*btcjson.GetWorkResult, error) { return c.GetWorkAsync().Receive() } // FutureGetWorkSubmit is a future promise to deliver the result of a // GetWorkSubmitAsync RPC invocation (or an applicable error). type FutureGetWorkSubmit chan *response // Receive waits for the response promised by the future and returns whether // or not the submitted block header was accepted. func (r FutureGetWorkSubmit) Receive() (bool, error) { res, err := receiveFuture(r) if err != nil { return false, err } // Unmarshal result as a boolean. var accepted bool err = json.Unmarshal(res, &accepted) if err != nil { return false, err } return accepted, nil } // GetWorkSubmitAsync 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 GetWorkSubmit for the blocking version and more details. func (c *Client) GetWorkSubmitAsync(data string) FutureGetWorkSubmit { id := c.NextID() cmd, err := btcjson.NewGetWorkCmd(id, data) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // GetWorkSubmit submits a block header which is a solution to previously // requested data and returns whether or not the solution was accepted. // // See GetWork to request data to work on. func (c *Client) GetWorkSubmit(data string) (bool, error) { return c.GetWorkSubmitAsync(data).Receive() } // FutureSubmitBlockResult is a future promise to deliver the result of a // SubmitBlockAsync RPC invocation (or an applicable error). type FutureSubmitBlockResult chan *response // Receive waits for the response promised by the future and returns an error if // any occurred when submitting the block. func (r FutureSubmitBlockResult) Receive() error { res, err := receiveFuture(r) if err != nil { return err } if string(res) != "null" { var result string err = json.Unmarshal(res, &result) if err != nil { return err } return errors.New(result) } return nil } // SubmitBlockAsync 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 SubmitBlock for the blocking version and more details. func (c *Client) SubmitBlockAsync(block *btcutil.Block, options *btcjson.SubmitBlockOptions) FutureSubmitBlockResult { blockHex := "" if block != nil { blockBytes, err := block.Bytes() if err != nil { return newFutureError(err) } blockHex = hex.EncodeToString(blockBytes) } id := c.NextID() cmd, err := btcjson.NewSubmitBlockCmd(id, blockHex, options) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) } // SubmitBlock attempts to submit a new block into the bitcoin network. func (c *Client) SubmitBlock(block *btcutil.Block, options *btcjson.SubmitBlockOptions) error { return c.SubmitBlockAsync(block, options).Receive() } // TODO(davec): Implement GetBlockTemplate