Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chore] Backport GetBlockVerbosity Fixes & Add getbalances RPC client command #389

Merged
merged 15 commits into from
Jul 22, 2020
Merged
8 changes: 3 additions & 5 deletions btcjson/chainsvrcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,18 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
// GetBlockCmd defines the getblock JSON-RPC command.
type GetBlockCmd struct {
Hash string
Verbose *bool `jsonrpcdefault:"true"`
VerboseTx *bool `jsonrpcdefault:"false"`
Verbosity *int `jsonrpcdefault:"1"`
}

// NewGetBlockCmd returns a new instance which can be used to issue a getblock
// JSON-RPC command.
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetBlockCmd(hash string, verbose, verboseTx *bool) *GetBlockCmd {
func NewGetBlockCmd(hash string, verbosity *int) *GetBlockCmd {
return &GetBlockCmd{
Hash: hash,
Verbose: verbose,
VerboseTx: verboseTx,
Verbosity: verbosity,
}
}

Expand Down
41 changes: 24 additions & 17 deletions btcjson/chainsvrcmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,51 +141,58 @@ func TestChainSvrCmds(t *testing.T) {
},
{
name: "getblock",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123", btcjson.Int(0))
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Int(0))
},
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbosity: btcjson.Int(0),
},
},
{
name: "getblock default verbosity",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123")
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", nil, nil)
return btcjson.NewGetBlockCmd("123", nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(false),
Verbosity: btcjson.Int(1),
},
},
{
name: "getblock required optional1",
newCmd: func() (interface{}, error) {
// Intentionally use a source param that is
// more pointers than the destination to
// exercise that path.
verbosePtr := btcjson.Bool(true)
return btcjson.NewCmd("getblock", "123", &verbosePtr)
return btcjson.NewCmd("getblock", "123", btcjson.Int(1))
},
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{
Hash: "123",
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(false),
Verbosity: btcjson.Int(1),
},
},
{
name: "getblock required optional2",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getblock", "123", true, true)
return btcjson.NewCmd("getblock", "123", btcjson.Int(2))
},
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{
Hash: "123",
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(true),
Verbosity: btcjson.Int(2),
},
},
{
Expand Down
66 changes: 41 additions & 25 deletions btcjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,53 @@ type GetBlockHeaderVerboseResult struct {
NextHash string `json:"nextblockhash,omitempty"`
}

// GetBlockBaseVerboseResult models the common data from the getblock command when
// verbose flag set to 1 or 2. When the verbose flag is not set, getblock
// returns a hex-encoded string.
type GetBlockBaseVerboseResult struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Size int32 `json:"size"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
}

// GetBlockVerboseResult models the data from the getblock command when the
// verbose flag is set to 1 (default).
// verbose flag is set to 1. When the verbose flag is set to 0, getblock returns a
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
// whose tx field is an array of transaction hashes. When the verbose flag is set to 2,
// getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseTxResult to unmarshal data received from passing verbose=2 to getblock.
type GetBlockVerboseResult struct {
*GetBlockBaseVerboseResult
Tx []string `json:"tx,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []string `json:"tx,omitempty"`
RawTx []TxRawResult `json:"rawtx,omitempty"` // Note: this field is always empty when verbose != 2.
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
}

// GetBlockVerboseTxResult models the data from the getblock command when the
// verbose flag is set to 2.
// verbose flag is set to 2. When the verbose flag is set to 0, getblock returns a
// hex-encoded string. When the verbose flag is set to 1, getblock returns an object
// whose tx field is an array of transaction hashes. When the verbose flag is set to 2,
// getblock returns an object whose tx field is an array of raw transactions.
// Use GetBlockVerboseResult to unmarshal data received from passing verbose=1 to getblock.
type GetBlockVerboseTxResult struct {
*GetBlockBaseVerboseResult
Tx []TxRawResult `json:"tx,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
StrippedSize int32 `json:"strippedsize"`
Size int32 `json:"size"`
Height int64 `json:"height"`
Version int32 `json:"version"`
VersionHex string `json:"versionHex"`
MerkleRoot string `json:"merkleroot"`
Tx []TxRawResult `json:"tx,omitempty"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
}

// AddMultisigAddressResult models the data returned from the addmultisigaddress
Expand Down
2 changes: 1 addition & 1 deletion btcjson/cmdinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func TestMethodUsageText(t *testing.T) {
{
name: "getblock",
method: "getblock",
expected: `getblock "hash" (verbose=true verbosetx=false)`,
expected: `getblock "hash" (verbosity=1)`,
},
}

Expand Down
27 changes: 13 additions & 14 deletions btcjson/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ import (
"github.com/gcash/bchd/btcjson"
)

// Create a new getblock command. Notice the call to btcjson.Uint32 which is a
// convenience function for creating a pointer out of a primitive for
// optional parameters. Notice the nil parameter indicates
// to use the default parameter for that fields. This is a common
// pattern used in all of the New<Foo>Cmdr functions in this package for
// optional fields.
// This example demonstrates how to create and marshal a command into a JSON-RPC
// request.
func ExampleMarshalCmd() {
// Create a new getblock command.
// Create a new getblock command. Notice the nil parameter indicates
// to use the default parameter for that fields. This is a common
// pattern used in all of the New<Foo>Cmd functions in this package for
// optional fields. Also, notice the call to btcjson.Bool which is a
// convenience function for creating a pointer out of a primitive for
// optional parameters.
blockHash := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Bool(false), nil)
gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Int(0))

// Marshal the command to the format suitable for sending to the RPC
// server. Typically the client would increment the id here which is
Expand All @@ -37,15 +38,15 @@ func ExampleMarshalCmd() {
fmt.Printf("%s\n", marshalledBytes)

// Output:
// {"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",false],"id":1}
// {"jsonrpc":"1.0","method":"getblock","params":["000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",0],"id":1}
}

// This example demonstrates how to unmarshal a JSON-RPC request and then
// unmarshal the concrete request into a concrete command.
func ExampleUnmarshalCmd() {
// Ordinarily this would be read from the wire, but for this example,
// 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",0],"id":1}`)

// Unmarshal the raw bytes from the wire into a JSON-RPC request.
var request btcjson.Request
Expand Down Expand Up @@ -83,13 +84,11 @@ func ExampleUnmarshalCmd() {

// Display the fields in the concrete command.
fmt.Println("Hash:", gbCmd.Hash)
fmt.Println("Verbose:", *gbCmd.Verbose)
fmt.Println("VerboseTx:", *gbCmd.VerboseTx)
fmt.Println("Verbosity:", *gbCmd.Verbosity)

// Output:
// Hash: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// Verbose: false
// VerboseTx: false
// Verbosity: 0
}

// This example demonstrates how to marshal a JSON-RPC response.
Expand Down
37 changes: 14 additions & 23 deletions btcjson/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ func resultStructHelp(xT descLookupFunc, rt reflect.Type, indentLevel int) []str
fieldType := reflectTypeToJSONType(xT, rtfType)
fieldDescKey := typeName + "-" + fieldName
fieldExamples, isComplex := reflectTypeToJSONExample(xT,
rtfType, indentLevel, fieldDescKey, rtf.Anonymous)
if isComplex && !rtf.Anonymous {
rtfType, indentLevel, fieldDescKey)
if isComplex {
var brace string
kind := rtfType.Kind()
if kind == reflect.Array || kind == reflect.Slice {
Expand All @@ -123,8 +123,6 @@ func resultStructHelp(xT descLookupFunc, rt reflect.Type, indentLevel int) []str
fieldName, brace, fieldType, xT(fieldDescKey))
results = append(results, result)
results = append(results, fieldExamples...)
} else if isComplex && rtf.Anonymous {
results = append(results, fieldExamples...)
} else {
result := fmt.Sprintf("%s\"%s\": %s,\t(%s)\t%s", indent,
fieldName, fieldExamples[0], fieldType,
Expand All @@ -142,7 +140,7 @@ func resultStructHelp(xT descLookupFunc, rt reflect.Type, indentLevel int) []str
// a tab writer. A bool is also returned which specifies whether or not the
// type results in a complex JSON object since they need to be handled
// differently.
func reflectTypeToJSONExample(xT descLookupFunc, rt reflect.Type, indentLevel int, fieldDescKey string, embeddedStruct bool) ([]string, bool) {
func reflectTypeToJSONExample(xT descLookupFunc, rt reflect.Type, indentLevel int, fieldDescKey string) ([]string, bool) {
// Indirect pointer if needed.
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
Expand All @@ -165,12 +163,7 @@ func reflectTypeToJSONExample(xT descLookupFunc, rt reflect.Type, indentLevel in

case reflect.Struct:
indent := strings.Repeat(" ", indentLevel)
nextIndentLevel := indentLevel

if !embeddedStruct {
nextIndentLevel++
}
results := resultStructHelp(xT, rt, nextIndentLevel)
results := resultStructHelp(xT, rt, indentLevel+1)

// An opening brace is needed for the first indent level. For
// all others, it will be included as a part of the previous
Expand All @@ -181,22 +174,20 @@ func reflectTypeToJSONExample(xT descLookupFunc, rt reflect.Type, indentLevel in
copy(newResults[1:], results)
results = newResults
}
if !embeddedStruct {
// The closing brace has a comma after it except for the first
// indent level. The final tabs are necessary so the tab writer
// lines things up properly.
closingBrace := indent + "}"
if indentLevel > 0 {
closingBrace += ","
}
results = append(results, closingBrace+"\t\t")
}

// The closing brace has a comma after it except for the first
// indent level. The final tabs are necessary so the tab writer
// lines things up properly.
closingBrace := indent + "}"
if indentLevel > 0 {
closingBrace += ","
}
results = append(results, closingBrace+"\t\t")
return results, true

case reflect.Array, reflect.Slice:
results, isComplex := reflectTypeToJSONExample(xT, rt.Elem(),
indentLevel, fieldDescKey, false)
indentLevel, fieldDescKey)

// When the result is complex, it is because this is an array of
// objects.
Expand Down Expand Up @@ -260,7 +251,7 @@ func reflectTypeToJSONExample(xT descLookupFunc, rt reflect.Type, indentLevel in
// type.
func resultTypeHelp(xT descLookupFunc, rt reflect.Type, fieldDescKey string) string {
// Generate the JSON example for the result type.
results, isComplex := reflectTypeToJSONExample(xT, rt, 0, fieldDescKey, false)
results, isComplex := reflectTypeToJSONExample(xT, rt, 0, fieldDescKey)

// When this is a primitive type, add the associated JSON type and
// result description into the final string, format it accordingly,
Expand Down
2 changes: 1 addition & 1 deletion btcjson/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ func TestHelpReflectInternals(t *testing.T) {

// Ensure the generated example is as expected.
examples, isComplex := btcjson.TstReflectTypeToJSONExample(xT,
test.reflectType, test.indentLevel, "fdk", false)
test.reflectType, test.indentLevel, "fdk")
if isComplex != test.isComplex {
t.Errorf("Test #%d (%s) unexpected isComplex - got: %v, "+
"want: %v", i, test.name, isComplex,
Expand Down
Loading