rpcclient: send legacy GetBlock request for backwards compatibility
Without this, users of this library wouldn't be able to issue GetBlock requests to nodes which haven't updated to support the latest request format, namely the use of a single `int` parameter to denote verbosity instead of two `bool`s.
This commit is contained in:
parent
d38279ee74
commit
742935e3a9
1 changed files with 85 additions and 12 deletions
|
@ -52,14 +52,61 @@ func (c *Client) GetBestBlockHash() (*chainhash.Hash, error) {
|
|||
return c.GetBestBlockHashAsync().Receive()
|
||||
}
|
||||
|
||||
// legacyGetBlockRequest constructs and sends a legacy getblock request which
|
||||
// contains two separate bools to denote verbosity, in contract to a single int
|
||||
// parameter.
|
||||
func (c *Client) legacyGetBlockRequest(hash string, verbose,
|
||||
verboseTx bool) ([]byte, error) {
|
||||
|
||||
hashJSON, err := json.Marshal(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verboseJSON, err := json.Marshal(btcjson.Bool(verbose))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verboseTxJSON, err := json.Marshal(btcjson.Bool(verboseTx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.RawRequest("getblock", []json.RawMessage{
|
||||
hashJSON, verboseJSON, verboseTxJSON,
|
||||
})
|
||||
}
|
||||
|
||||
// waitForGetBlockRes waits for the response of a getblock request. If the
|
||||
// response indicates an invalid parameter was provided, a legacy style of the
|
||||
// request is resent and its response is returned instead.
|
||||
func (c *Client) waitForGetBlockRes(respChan chan *response, hash string,
|
||||
verbose, verboseTx bool) ([]byte, error) {
|
||||
|
||||
res, err := receiveFuture(respChan)
|
||||
|
||||
// If we receive an invalid parameter error, then we may be
|
||||
// communicating with a btcd node which only understands the legacy
|
||||
// request, so we'll try that.
|
||||
if err, ok := err.(*btcjson.RPCError); ok &&
|
||||
err.Code == btcjson.ErrRPCInvalidParams.Code {
|
||||
return c.legacyGetBlockRequest(hash, verbose, verboseTx)
|
||||
}
|
||||
|
||||
// Otherwise, we can return the response as is.
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FutureGetBlockResult is a future promise to deliver the result of a
|
||||
// GetBlockAsync RPC invocation (or an applicable error).
|
||||
type FutureGetBlockResult chan *response
|
||||
type FutureGetBlockResult struct {
|
||||
client *Client
|
||||
hash string
|
||||
Response chan *response
|
||||
}
|
||||
|
||||
// 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() (*wire.MsgBlock, error) {
|
||||
res, err := receiveFuture(r)
|
||||
res, err := r.client.waitForGetBlockRes(r.Response, r.hash, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -98,7 +145,11 @@ func (c *Client) GetBlockAsync(blockHash *chainhash.Hash) FutureGetBlockResult {
|
|||
}
|
||||
|
||||
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(0))
|
||||
return c.sendCmd(cmd)
|
||||
return FutureGetBlockResult{
|
||||
client: c,
|
||||
hash: hash,
|
||||
Response: c.sendCmd(cmd),
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlock returns a raw block from the server given its hash.
|
||||
|
@ -111,12 +162,16 @@ func (c *Client) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
|
|||
|
||||
// FutureGetBlockVerboseResult is a future promise to deliver the result of a
|
||||
// GetBlockVerboseAsync RPC invocation (or an applicable error).
|
||||
type FutureGetBlockVerboseResult chan *response
|
||||
type FutureGetBlockVerboseResult struct {
|
||||
client *Client
|
||||
hash string
|
||||
Response chan *response
|
||||
}
|
||||
|
||||
// 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.GetBlockVerboseResult, error) {
|
||||
res, err := receiveFuture(r)
|
||||
res, err := r.client.waitForGetBlockRes(r.Response, r.hash, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -143,7 +198,11 @@ func (c *Client) GetBlockVerboseAsync(blockHash *chainhash.Hash) FutureGetBlockV
|
|||
// From the bitcoin-cli getblock documentation:
|
||||
// "If verbosity is 1, returns an Object with information about block ."
|
||||
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(1))
|
||||
return c.sendCmd(cmd)
|
||||
return FutureGetBlockVerboseResult{
|
||||
client: c,
|
||||
hash: hash,
|
||||
Response: c.sendCmd(cmd),
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlockVerbose returns a data structure from the server with information
|
||||
|
@ -155,10 +214,18 @@ func (c *Client) GetBlockVerbose(blockHash *chainhash.Hash) (*btcjson.GetBlockVe
|
|||
return c.GetBlockVerboseAsync(blockHash).Receive()
|
||||
}
|
||||
|
||||
type FutureGetBlockVerboseTxResult chan *response
|
||||
// FutureGetBlockVerboseTxResult is a future promise to deliver the result of a
|
||||
// GetBlockVerboseTxResult RPC invocation (or an applicable error).
|
||||
type FutureGetBlockVerboseTxResult struct {
|
||||
client *Client
|
||||
hash string
|
||||
Response chan *response
|
||||
}
|
||||
|
||||
// Receive waits for the response promised by the future and returns a verbose
|
||||
// version of the block including detailed information about its transactions.
|
||||
func (r FutureGetBlockVerboseTxResult) Receive() (*btcjson.GetBlockVerboseTxResult, error) {
|
||||
res, err := receiveFuture(r)
|
||||
res, err := r.client.waitForGetBlockRes(r.Response, r.hash, true, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -182,11 +249,17 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc
|
|||
if blockHash != nil {
|
||||
hash = blockHash.String()
|
||||
}
|
||||
// From the bitcoin-cli getblock documentation:
|
||||
// "If verbosity is 2, returns an Object with information about block and information about each transaction."
|
||||
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(2))
|
||||
|
||||
return c.sendCmd(cmd)
|
||||
// From the bitcoin-cli getblock documentation:
|
||||
//
|
||||
// If verbosity is 2, returns an Object with information about block
|
||||
// and information about each transaction.
|
||||
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(2))
|
||||
return FutureGetBlockVerboseTxResult{
|
||||
client: c,
|
||||
hash: hash,
|
||||
Response: c.sendCmd(cmd),
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlockVerboseTx returns a data structure from the server with information
|
||||
|
|
Loading…
Add table
Reference in a new issue