Refactor FutureGetBlockVerboseResult into two types: FutureGetBlockVerboseResult, and FutureGetBlockVerboseTxResult.

Due to differences in how getblock returns data based on the provided verbosity parameter, it's necessary
to have two separate return types based on verbosity. This necessitates a separate unmarshalling function
(represented throughout rpcclient/chain.go as Result.Receive()) to ensure that data is correctly unmarshalled
and returned to the user.
This commit is contained in:
jalavosus 2020-01-31 12:31:47 -05:00
parent 468154a052
commit 57cb8e4b11
5 changed files with 46 additions and 35 deletions

View file

@ -142,50 +142,43 @@ func TestChainSvrCmds(t *testing.T) {
{ {
name: "getblock", name: "getblock",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123") return btcjson.NewCmd("getblock", "123", btcjson.Int(0))
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", nil, nil) return btcjson.NewGetBlockCmd("123", btcjson.Int(0))
}, },
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{ unmarshalled: &btcjson.GetBlockCmd{
Hash: "123", Hash: "123",
Verbose: btcjson.Bool(true), Verbosity: btcjson.Int(0),
VerboseTx: btcjson.Bool(false),
}, },
}, },
{ {
name: "getblock required optional1", name: "getblock required optional1",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
// Intentionally use a source param that is return btcjson.NewCmd("getblock", "123", btcjson.Int(1))
// more pointers than the destination to
// exercise that path.
verbosePtr := btcjson.Bool(true)
return btcjson.NewCmd("getblock", "123", &verbosePtr)
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil) return btcjson.NewGetBlockCmd("123", btcjson.Int(1))
}, },
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{ unmarshalled: &btcjson.GetBlockCmd{
Hash: "123", Hash: "123",
Verbose: btcjson.Bool(true), Verbosity: btcjson.Int(1),
VerboseTx: btcjson.Bool(false),
}, },
}, },
{ {
name: "getblock required optional2", name: "getblock required optional2",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123", true, true) return btcjson.NewCmd("getblock", "123", btcjson.Int(2))
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true)) return btcjson.NewGetBlockCmd("123", btcjson.Int(2))
}, },
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",true,true],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",2],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{ unmarshalled: &btcjson.GetBlockCmd{
Hash: "123", Hash: "123",
Verbose: btcjson.Bool(true), Verbosity: btcjson.Int(2),
VerboseTx: btcjson.Bool(true),
}, },
}, },
{ {

View file

@ -151,7 +151,7 @@ func TestMethodUsageText(t *testing.T) {
{ {
name: "getblock", name: "getblock",
method: "getblock", method: "getblock",
expected: `getblock "hash" (verbose=true verbosetx=false)`, expected: `getblock "hash" (verbosity=1)`,
}, },
} }

View file

@ -21,7 +21,7 @@ func ExampleMarshalCmd() {
// convenience function for creating a pointer out of a primitive for // convenience function for creating a pointer out of a primitive for
// optional parameters. // optional parameters.
blockHash := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" blockHash := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Bool(false), nil) gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Int(1))
// Marshal the command to the format suitable for sending to the RPC // Marshal the command to the format suitable for sending to the RPC
// server. Typically the client would increment the id here which is // server. Typically the client would increment the id here which is
@ -38,7 +38,7 @@ func ExampleMarshalCmd() {
fmt.Printf("%s\n", marshalledBytes) fmt.Printf("%s\n", marshalledBytes)
// Output: // Output:
// {"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",false],"id":1} // {"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",1],"id":1}
} }
// This example demonstrates how to unmarshal a JSON-RPC request and then // This example demonstrates how to unmarshal a JSON-RPC request and then
@ -46,7 +46,7 @@ func ExampleMarshalCmd() {
func ExampleUnmarshalCmd() { func ExampleUnmarshalCmd() {
// Ordinarily this would be read from the wire, but for this example, // Ordinarily this would be read from the wire, but for this example,
// it is hard coded here for clarity. // it is hard coded here for clarity.
data := []byte(`{"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",false],"id":1}`) data := []byte(`{"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",1],"id":1}`)
// Unmarshal the raw bytes from the wire into a JSON-RPC request. // Unmarshal the raw bytes from the wire into a JSON-RPC request.
var request btcjson.Request var request btcjson.Request
@ -84,13 +84,11 @@ func ExampleUnmarshalCmd() {
// Display the fields in the concrete command. // Display the fields in the concrete command.
fmt.Println("Hash:", gbCmd.Hash) fmt.Println("Hash:", gbCmd.Hash)
fmt.Println("Verbose:", *gbCmd.Verbose) fmt.Println("Verbosity:", *gbCmd.Verbosity)
fmt.Println("VerboseTx:", *gbCmd.VerboseTx)
// Output: // Output:
// Hash: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f // Hash: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// Verbose: false // Verbosity: 0
// VerboseTx: false
} }
// This example demonstrates how to marshal a JSON-RPC response. // This example demonstrates how to marshal a JSON-RPC response.

View file

@ -97,7 +97,7 @@ func (c *Client) GetBlockAsync(blockHash *chainhash.Hash) FutureGetBlockResult {
hash = blockHash.String() hash = blockHash.String()
} }
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(false), nil) cmd := btcjson.NewGetBlockCmd(hash, nil)
return c.sendCmd(cmd) return c.sendCmd(cmd)
} }
@ -140,8 +140,9 @@ func (c *Client) GetBlockVerboseAsync(blockHash *chainhash.Hash) FutureGetBlockV
if blockHash != nil { if blockHash != nil {
hash = blockHash.String() hash = blockHash.String()
} }
// From the bitcoin-cli getblock documentation:
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), nil) // "If verbosity is 1, returns an Object with information about block ."
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(1))
return c.sendCmd(cmd) return c.sendCmd(cmd)
} }
@ -154,18 +155,37 @@ func (c *Client) GetBlockVerbose(blockHash *chainhash.Hash) (*btcjson.GetBlockVe
return c.GetBlockVerboseAsync(blockHash).Receive() return c.GetBlockVerboseAsync(blockHash).Receive()
} }
type FutureGetBlockVerboseTxResult chan *response
func (r FutureGetBlockVerboseTxResult) Receive() (*btcjson.GetBlockVerboseTxResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
var blockResult btcjson.GetBlockVerboseTxResult
err = json.Unmarshal(res, &blockResult)
if err != nil {
return nil, err
}
return &blockResult, nil
}
// GetBlockVerboseTxAsync returns an instance of a type that can be used to get // GetBlockVerboseTxAsync 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 result of the RPC at some future time by invoking the Receive function on
// the returned instance. // the returned instance.
// //
// See GetBlockVerboseTx or the blocking version and more details. // See GetBlockVerboseTx or the blocking version and more details.
func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBlockVerboseResult { func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBlockVerboseTxResult {
hash := "" hash := ""
if blockHash != nil { if blockHash != nil {
hash = blockHash.String() 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))
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true))
return c.sendCmd(cmd) return c.sendCmd(cmd)
} }
@ -174,7 +194,7 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc
// //
// See GetBlockVerbose if only transaction hashes are preferred. // See GetBlockVerbose if only transaction hashes are preferred.
// See GetBlock to retrieve a raw block instead. // See GetBlock to retrieve a raw block instead.
func (c *Client) GetBlockVerboseTx(blockHash *chainhash.Hash) (*btcjson.GetBlockVerboseResult, error) { func (c *Client) GetBlockVerboseTx(blockHash *chainhash.Hash) (*btcjson.GetBlockVerboseTxResult, error) {
return c.GetBlockVerboseTxAsync(blockHash).Receive() return c.GetBlockVerboseTxAsync(blockHash).Receive()
} }

View file

@ -1084,7 +1084,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
// When the verbose flag isn't set, simply return the serialized block // When the verbose flag isn't set, simply return the serialized block
// as a hex-encoded string. // as a hex-encoded string.
if c.Verbose != nil && !*c.Verbose { if c.Verbosity != nil && *c.Verbosity == 0 {
return hex.EncodeToString(blkBytes), nil return hex.EncodeToString(blkBytes), nil
} }
@ -1137,7 +1137,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
NextHash: nextHashString, NextHash: nextHashString,
} }
if c.VerboseTx == nil || !*c.VerboseTx { if *c.Verbosity == 1 {
transactions := blk.Transactions() transactions := blk.Transactions()
txNames := make([]string, len(transactions)) txNames := make([]string, len(transactions))
for i, tx := range transactions { for i, tx := range transactions {