4e8e63e0d7
Rather than using bytes.NewBuffer, which is a read/write entity (io.ReadWriter), use bytes.NewReader which is only a read entitiy (io.Reader). Benchmarking shows it's slightly faster and it's also technically more accurate since it ensures the data is read-only.
503 lines
16 KiB
Go
503 lines
16 KiB
Go
// 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 (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/conformal/btcjson"
|
|
"github.com/conformal/btcutil"
|
|
"github.com/conformal/btcwire"
|
|
)
|
|
|
|
// FutureGetBestBlockHashResult is a future promise to deliver the result of a
|
|
// GetBestBlockAsync RPC invocation (or an applicable error).
|
|
type FutureGetBestBlockHashResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the hash of
|
|
// the best block in the longest block chain.
|
|
func (r FutureGetBestBlockHashResult) Receive() (*btcwire.ShaHash, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
txHashStr, ok := reply.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getbestblockhash: %T\n", reply)
|
|
}
|
|
|
|
return btcwire.NewShaHashFromStr(txHashStr)
|
|
}
|
|
|
|
// GetBestBlockHashAsync 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 GetBestBlockHash for the blocking version and more details.
|
|
func (c *Client) GetBestBlockHashAsync() FutureGetBestBlockHashResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetBestBlockHashCmd(id)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetBestBlockHash returns the hash of the best block in the longest block
|
|
// chain.
|
|
func (c *Client) GetBestBlockHash() (*btcwire.ShaHash, error) {
|
|
return c.GetBestBlockHashAsync().Receive()
|
|
}
|
|
|
|
// FutureGetBlockResult is a future promise to deliver the result of a
|
|
// GetBlockAsync RPC invocation (or an applicable error).
|
|
type FutureGetBlockResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the raw
|
|
// block requested from the server given its hash.
|
|
func (r FutureGetBlockResult) Receive() (*btcutil.Block, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
blockHex, ok := reply.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getblock (verbose=0): %T\n", reply)
|
|
}
|
|
|
|
// Decode the serialized block hex to raw bytes.
|
|
serializedBlock, err := hex.DecodeString(blockHex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Deserialize the block and return it.
|
|
var msgBlock btcwire.MsgBlock
|
|
msgBlock.Deserialize(bytes.NewReader(serializedBlock))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return btcutil.NewBlock(&msgBlock), nil
|
|
}
|
|
|
|
// GetBlockAsync 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 GetBlock for the blocking version and more details.
|
|
func (c *Client) GetBlockAsync(blockHash *btcwire.ShaHash) FutureGetBlockResult {
|
|
hash := ""
|
|
if blockHash != nil {
|
|
hash = blockHash.String()
|
|
}
|
|
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetBlockCmd(id, hash, false)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetBlock returns a raw block from the server given its hash.
|
|
//
|
|
// See GetBlockVerbose to retrieve a data structure with information about the
|
|
// block instead.
|
|
func (c *Client) GetBlock(blockHash *btcwire.ShaHash) (*btcutil.Block, error) {
|
|
return c.GetBlockAsync(blockHash).Receive()
|
|
}
|
|
|
|
// FutureGetBlockVerboseResult is a future promise to deliver the result of a
|
|
// GetBlockVerboseAsync RPC invocation (or an applicable error).
|
|
type FutureGetBlockVerboseResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the data
|
|
// structure from the server with information about the requested block.
|
|
func (r FutureGetBlockVerboseResult) Receive() (*btcjson.BlockResult, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
blockResult, ok := reply.(*btcjson.BlockResult)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getblock (verbose=1): %T\n", reply)
|
|
}
|
|
|
|
return blockResult, nil
|
|
}
|
|
|
|
// GetBlockVerboseAsync 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 GetBlockVerbose for the blocking version and more details.
|
|
func (c *Client) GetBlockVerboseAsync(blockHash *btcwire.ShaHash, verboseTx bool) FutureGetBlockVerboseResult {
|
|
hash := ""
|
|
if blockHash != nil {
|
|
hash = blockHash.String()
|
|
}
|
|
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetBlockCmd(id, hash, true, verboseTx)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetBlockVerbose returns a data structure from the server with information
|
|
// about a block given its hash.
|
|
//
|
|
// See GetBlock to retrieve a raw block instead.
|
|
func (c *Client) GetBlockVerbose(blockHash *btcwire.ShaHash, verboseTx bool) (*btcjson.BlockResult, error) {
|
|
return c.GetBlockVerboseAsync(blockHash, verboseTx).Receive()
|
|
}
|
|
|
|
// FutureGetBlockCountResult is a future promise to deliver the result of a
|
|
// GetBlockCountAsync RPC invocation (or an applicable error).
|
|
type FutureGetBlockCountResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the number
|
|
// of blocks in the longest block chain.
|
|
func (r FutureGetBlockCountResult) Receive() (int64, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
count, ok := reply.(float64)
|
|
if !ok {
|
|
return 0, fmt.Errorf("unexpected response type for "+
|
|
"getblockcount: %T\n", reply)
|
|
}
|
|
|
|
return int64(count), nil
|
|
}
|
|
|
|
// GetBlockCountAsync 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 GetBlockCount for the blocking version and more details.
|
|
func (c *Client) GetBlockCountAsync() FutureGetBlockCountResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetBlockCountCmd(id)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetBlockCount returns the number of blocks in the longest block chain.
|
|
func (c *Client) GetBlockCount() (int64, error) {
|
|
return c.GetBlockCountAsync().Receive()
|
|
}
|
|
|
|
// FutureGetDifficultyResult is a future promise to deliver the result of a
|
|
// GetDifficultyAsync RPC invocation (or an applicable error).
|
|
type FutureGetDifficultyResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the
|
|
// proof-of-work difficulty as a multiple of the minimum difficulty.
|
|
func (r FutureGetDifficultyResult) Receive() (float64, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
difficulty, ok := reply.(float64)
|
|
if !ok {
|
|
return 0, fmt.Errorf("unexpected response type for "+
|
|
"getdifficulty: %T\n", reply)
|
|
}
|
|
|
|
return difficulty, nil
|
|
}
|
|
|
|
// GetDifficultyAsync 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 GetDifficulty for the blocking version and more details.
|
|
func (c *Client) GetDifficultyAsync() FutureGetDifficultyResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetDifficultyCmd(id)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetDifficulty returns the proof-of-work difficulty as a multiple of the
|
|
// minimum difficulty.
|
|
func (c *Client) GetDifficulty() (float64, error) {
|
|
return c.GetDifficultyAsync().Receive()
|
|
}
|
|
|
|
// FutureGetBlockHashResult is a future promise to deliver the result of a
|
|
// GetBlockHashAsync RPC invocation (or an applicable error).
|
|
type FutureGetBlockHashResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the hash of
|
|
// the block in the best block chain at the given height.
|
|
func (r FutureGetBlockHashResult) Receive() (*btcwire.ShaHash, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
txHashStr, ok := reply.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getblockhash: %T\n", reply)
|
|
}
|
|
|
|
return btcwire.NewShaHashFromStr(txHashStr)
|
|
}
|
|
|
|
// GetBlockHashAsync 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 GetBlockHash for the blocking version and more details.
|
|
func (c *Client) GetBlockHashAsync(blockHeight int64) FutureGetBlockHashResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetBlockHashCmd(id, blockHeight)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetBlockHash returns the hash of the block in the best block chain at the
|
|
// given height.
|
|
func (c *Client) GetBlockHash(blockHeight int64) (*btcwire.ShaHash, error) {
|
|
return c.GetBlockHashAsync(blockHeight).Receive()
|
|
}
|
|
|
|
// FutureGetRawMempoolResult is a future promise to deliver the result of a
|
|
// GetRawMempoolAsync RPC invocation (or an applicable error).
|
|
type FutureGetRawMempoolResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns the hashes
|
|
// of all transactions in the memory pool.
|
|
func (r FutureGetRawMempoolResult) Receive() ([]*btcwire.ShaHash, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
txHashStrs, ok := reply.([]string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getrawmempool (verbose=false): %T\n", reply)
|
|
}
|
|
|
|
txHashes := make([]*btcwire.ShaHash, 0, len(txHashStrs))
|
|
for _, hashStr := range txHashStrs {
|
|
txHash, err := btcwire.NewShaHashFromStr(hashStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
txHashes = append(txHashes, txHash)
|
|
}
|
|
|
|
return txHashes, nil
|
|
}
|
|
|
|
// GetRawMempoolAsync 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 GetRawMempool for the blocking version and more details.
|
|
func (c *Client) GetRawMempoolAsync() FutureGetRawMempoolResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetRawMempoolCmd(id, false)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetRawMempool returns the hashes of all transactions in the memory pool.
|
|
//
|
|
// See GetRawMempoolVerbose to retrieve data structures with information about
|
|
// the transactions instead.
|
|
func (c *Client) GetRawMempool() ([]*btcwire.ShaHash, error) {
|
|
return c.GetRawMempoolAsync().Receive()
|
|
}
|
|
|
|
// FutureGetRawMempoolVerboseResult is a future promise to deliver the result of
|
|
// a GetRawMempoolVerboseAsync RPC invocation (or an applicable error).
|
|
type FutureGetRawMempoolVerboseResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns a map of
|
|
// transaction hashes to an associated data structure with information about the
|
|
// transaction for all transactions in the memory pool.
|
|
func (r FutureGetRawMempoolVerboseResult) Receive() (map[string]btcjson.GetRawMempoolResult, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
mempoolItems, ok := reply.(map[string]btcjson.GetRawMempoolResult)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unexpected response type for "+
|
|
"getrawmempool (verbose=true): %T\n", reply)
|
|
}
|
|
|
|
return mempoolItems, nil
|
|
}
|
|
|
|
// GetRawMempoolVerboseAsync 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 GetRawMempoolVerbose for the blocking version and more details.
|
|
func (c *Client) GetRawMempoolVerboseAsync() FutureGetRawMempoolVerboseResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewGetRawMempoolCmd(id, true)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// GetRawMempoolVerbose returns a map of transaction hashes to an associated
|
|
// data structure with information about the transaction for all transactions in
|
|
// the memory pool.
|
|
//
|
|
// See GetRawMempool to retrieve only the transaction hashes instead.
|
|
func (c *Client) GetRawMempoolVerbose() (map[string]btcjson.GetRawMempoolResult, error) {
|
|
return c.GetRawMempoolVerboseAsync().Receive()
|
|
}
|
|
|
|
// FutureVerifyChainResult is a future promise to deliver the result of a
|
|
// VerifyChainAsync, VerifyChainLevelAsyncRPC, or VerifyChainBlocksAsync
|
|
// invocation (or an applicable error).
|
|
type FutureVerifyChainResult chan *futureResult
|
|
|
|
// Receive waits for the response promised by the future and returns whether
|
|
// or not the chain verified based on the check level and number of blocks
|
|
// to verify specified in the original call.
|
|
func (r FutureVerifyChainResult) Receive() (bool, error) {
|
|
reply, err := receiveFuture(r)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Ensure the returned data is the expected type.
|
|
verified, ok := reply.(bool)
|
|
if !ok {
|
|
return false, fmt.Errorf("unexpected response type for "+
|
|
"verifychain: %T\n", reply)
|
|
}
|
|
|
|
return verified, nil
|
|
}
|
|
|
|
// VerifyChainAsync 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 VerifyChain for the blocking version and more details.
|
|
func (c *Client) VerifyChainAsync() FutureVerifyChainResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewVerifyChainCmd(id)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// VerifyChain requests the server to verify the block chain database using
|
|
// the default check level and number of blocks to verify.
|
|
//
|
|
// See VerifyChainLevel and VerifyChainBlocks to override the defaults.
|
|
func (c *Client) VerifyChain() (bool, error) {
|
|
return c.VerifyChainAsync().Receive()
|
|
}
|
|
|
|
// VerifyChainLevelAsync 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 VerifyChainLevel for the blocking version and more details.
|
|
func (c *Client) VerifyChainLevelAsync(checkLevel int32) FutureVerifyChainResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewVerifyChainCmd(id, checkLevel)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// VerifyChainLevel requests the server to verify the block chain database using
|
|
// the passed check level and default number of blocks to verify.
|
|
//
|
|
// The check level controls how thorough the verification is with higher numbers
|
|
// increasing the amount of checks done as consequently how long the
|
|
// verification takes.
|
|
//
|
|
// See VerifyChain to use the default check level and VerifyChainBlocks to
|
|
// override the number of blocks to verify.
|
|
func (c *Client) VerifyChainLevel(checkLevel int32) (bool, error) {
|
|
return c.VerifyChainLevelAsync(checkLevel).Receive()
|
|
}
|
|
|
|
// VerifyChainBlocksAsync 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 VerifyChainBlocks for the blocking version and more details.
|
|
func (c *Client) VerifyChainBlocksAsync(checkLevel, numBlocks int32) FutureVerifyChainResult {
|
|
id := c.NextID()
|
|
cmd, err := btcjson.NewVerifyChainCmd(id, checkLevel, numBlocks)
|
|
if err != nil {
|
|
return newFutureError(err)
|
|
}
|
|
|
|
return c.sendCmd(cmd)
|
|
}
|
|
|
|
// VerifyChainBlocks requests the server to verify the block chain database
|
|
// using the passed check level and number of blocks to verify.
|
|
//
|
|
// The check level controls how thorough the verification is with higher numbers
|
|
// increasing the amount of checks done as consequently how long the
|
|
// verification takes.
|
|
//
|
|
// The number of blocks refers to the number of blocks from the end of the
|
|
// current longest chain.
|
|
//
|
|
// See VerifyChain and VerifyChainLevel to use defaults.
|
|
func (c *Client) VerifyChainBlocks(checkLevel, numBlocks int32) (bool, error) {
|
|
return c.VerifyChainBlocksAsync(checkLevel, numBlocks).Receive()
|
|
}
|