Merge pull request #1577 from wpaulino/getblock-compat

rpcclient: send legacy GetBlock request for backwards compatibility
This commit is contained in:
Olaoluwa Osuntokun 2020-05-15 16:24:29 -07:00 committed by GitHub
commit 9f0179fd2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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