From 4151d2ab2c5430f8b1e41f61a0b910e4de9eda59 Mon Sep 17 00:00:00 2001 From: quest Date: Sun, 19 Jul 2020 14:25:45 -0700 Subject: [PATCH 01/14] Revert "Fix compatibility with linters" This reverts commit fd438ce2f1e3f74c118ea688c0d5b50d049e9a6d. --- rpcserver.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 247034ccd..5e21b1941 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1143,8 +1143,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i blockReply = btcjson.GetBlockVerboseResult{ GetBlockBaseVerboseResult: baseBlockReply, - - Tx: txNames, + Tx: txNames, } } else { txns := blk.Transactions() @@ -1161,8 +1160,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i blockReply = btcjson.GetBlockVerboseTxResult{ GetBlockBaseVerboseResult: baseBlockReply, - - Tx: rawTxns, + Tx: rawTxns, } } From da8e353268fb333317d4a7dd10f499fe12ac8c19 Mon Sep 17 00:00:00 2001 From: quest Date: Sun, 19 Jul 2020 14:29:22 -0700 Subject: [PATCH 02/14] Reverted bad getblock --- btcjson/chainsvrresults.go | 46 ++++++++++++++------------------------ btcjson/example_test.go | 15 +++++++------ btcjson/help.go | 37 ++++++++++++------------------ btcjson/help_test.go | 2 +- rpcclient/chain.go | 31 +++++-------------------- rpcserver.go | 26 +++++++-------------- rpcserverhelp.go | 42 +++++++++++++++------------------- 7 files changed, 72 insertions(+), 127 deletions(-) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 1ef87d21f..3095c32a2 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -24,37 +24,25 @@ 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. When the verbose flag is not set, getblock returns a +// hex-encoded string. type GetBlockVerboseResult struct { - *GetBlockBaseVerboseResult - Tx []string `json:"tx,omitempty"` -} - -// GetBlockVerboseTxResult models the data from the getblock command when the -// verbose flag is set to 2. -type GetBlockVerboseTxResult struct { - *GetBlockBaseVerboseResult - Tx []TxRawResult `json:"tx,omitempty"` + 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"` + Tx []string `json:"tx,omitempty"` + RawTx []TxRawResult `json:"rawtx,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 diff --git a/btcjson/example_test.go b/btcjson/example_test.go index 8a78009ef..91e994e85 100644 --- a/btcjson/example_test.go +++ b/btcjson/example_test.go @@ -11,14 +11,15 @@ 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 NewCmdr 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 NewCmd 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) diff --git a/btcjson/help.go b/btcjson/help.go index ed3bd7931..f502d09fd 100644 --- a/btcjson/help.go +++ b/btcjson/help.go @@ -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 { @@ -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, @@ -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() @@ -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 @@ -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. @@ -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, diff --git a/btcjson/help_test.go b/btcjson/help_test.go index cd14fc036..e47c8a320 100644 --- a/btcjson/help_test.go +++ b/btcjson/help_test.go @@ -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, diff --git a/rpcclient/chain.go b/rpcclient/chain.go index d5e9410da..1d8adea40 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -141,7 +141,7 @@ func (c *Client) GetBlockVerboseAsync(blockHash *chainhash.Hash, verboseTx bool) hash = blockHash.String() } - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), &verboseTx) + cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), nil) return c.sendCmd(cmd) } @@ -154,41 +154,22 @@ func (c *Client) GetBlockVerbose(blockHash *chainhash.Hash, verboseTx bool) (*bt return c.GetBlockVerboseAsync(blockHash, verboseTx).Receive() } -// FutureGetBlockVerboseTxResult is a future promise to deliver the result of a -// GetBlockVerboseTxAsync RPC invocation (or an applicable error). -type FutureGetBlockVerboseTxResult 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 FutureGetBlockVerboseTxResult) Receive() (*btcjson.GetBlockVerboseTxResult, error) { - res, err := receiveFuture(r) - if err != nil { - return nil, err - } - - // Unmarshal the raw result into a BlockResult. - 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 // the result of the RPC at some future time by invoking the Receive function on // the returned instance. // // See GetBlockVerboseTx or the blocking version and more details. -func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBlockVerboseTxResult { - +func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBlockVerboseResult { hash := "" if blockHash != nil { hash = blockHash.String() } cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true)) +<<<<<<< HEAD +======= +>>>>>>> parent of 16110805... Update getblock command to 0.15.0+ syntax return c.sendCmd(cmd) } @@ -197,7 +178,7 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc // // See GetBlockVerbose if only transaction hashes are preferred. // See GetBlock to retrieve a raw block instead. -func (c *Client) GetBlockVerboseTx(blockHash *chainhash.Hash) (*btcjson.GetBlockVerboseTxResult, error) { +func (c *Client) GetBlockVerboseTx(blockHash *chainhash.Hash) (*btcjson.GetBlockVerboseResult, error) { return c.GetBlockVerboseTxAsync(blockHash).Receive() } diff --git a/rpcserver.go b/rpcserver.go index 5e21b1941..f87d61147 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1078,13 +1078,13 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i } } - // When the verbose flag isn't set, simply return the - // network-serialized block as a hex-encoded string. + // When the verbose flag isn't set, simply return the serialized block + // as a hex-encoded string. if c.Verbose != nil && !*c.Verbose { return hex.EncodeToString(blkBytes), nil } - // Generate the JSON object and return it. + // The verbose flag is set, so generate the JSON object and return it. // Deserialize the block. blk, err := bchutil.NewBlockFromBytes(blkBytes) @@ -1113,12 +1113,9 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i nextHashString = nextHash.String() } - var ( - blockReply interface{} - params = s.cfg.ChainParams - blockHeader = &blk.MsgBlock().Header - ) - baseBlockReply := &btcjson.GetBlockBaseVerboseResult{ + params := s.cfg.ChainParams + blockHeader := &blk.MsgBlock().Header + blockReply := btcjson.GetBlockVerboseResult{ Hash: c.Hash, Version: blockHeader.Version, VersionHex: fmt.Sprintf("%08x", blockHeader.Version), @@ -1141,10 +1138,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i txNames[i] = tx.Hash().String() } - blockReply = btcjson.GetBlockVerboseResult{ - GetBlockBaseVerboseResult: baseBlockReply, - Tx: txNames, - } + blockReply.Tx = txNames } else { txns := blk.Transactions() rawTxns := make([]btcjson.TxRawResult, len(txns)) @@ -1157,11 +1151,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i } rawTxns[i] = *rawTxn } - - blockReply = btcjson.GetBlockVerboseTxResult{ - GetBlockBaseVerboseResult: baseBlockReply, - Tx: rawTxns, - } + blockReply.RawTx = rawTxns } return blockReply, nil diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 429902f69..74614de4d 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -163,13 +163,10 @@ var helpDescsEnUS = map[string]string{ "getblock--synopsis": "Returns information about a block given its hash.", "getblock-hash": "The hash of the block", "getblock-verbose": "Specifies the block is returned as a JSON object instead of hex-encoded string", - "getblock-verbosetx": "Specifies that each transaction is returned as a JSON object and only applies if the verbose flag is true (dcrd extension)", + "getblock-verbosetx": "Specifies that each transaction is returned as a JSON object and only applies if the verbose flag is true (bchd extension)", "getblock--condition0": "verbose=false", "getblock--condition1": "verbose=true", - "getblock--condition2": "verbosetx=true", "getblock--result0": "Hex-encoded bytes of the serialized block", - "getblock--result1": "JSON object with information about block", - "getblock--result2": "JSON object with information about block and information about each transaction.", // GetBlockChainInfoCmd help. "getblockchaininfo--synopsis": "Returns information about the current blockchain state and the status of any active soft-fork deployments.", @@ -229,25 +226,22 @@ var helpDescsEnUS = map[string]string{ "searchrawtransactionsresult-vsize": "The virtual size of the transaction in bytes", // GetBlockVerboseResult help. - "getblockverboseresult-tx": "The transaction hashes", - - // GetBlockVerboseTxResult help - "getblockverbosetxresult-tx": "The transaction hashes (verbosity = 1) or the transactions as JSON objects (verbosity = 2)", - - // GetBlockBaseVerboseResult help. - "getblockbaseverboseresult-hash": "The hash of the block (same as provided)", - "getblockbaseverboseresult-confirmations": "The number of confirmations", - "getblockbaseverboseresult-size": "The size of the block", - "getblockbaseverboseresult-height": "The height of the block in the block chain", - "getblockbaseverboseresult-version": "The block version", - "getblockbaseverboseresult-versionHex": "The block version in hexadecimal", - "getblockbaseverboseresult-merkleroot": "Root hash of the merkle tree", - "getblockbaseverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", - "getblockbaseverboseresult-nonce": "The block nonce", - "getblockbaseverboseresult-bits": "The bits which represent the block difficulty", - "getblockbaseverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", - "getblockbaseverboseresult-previousblockhash": "The hash of the previous block", - "getblockbaseverboseresult-nextblockhash": "The hash of the next block (only if there is one)", + "getblockverboseresult-hash": "The hash of the block (same as provided)", + "getblockverboseresult-confirmations": "The number of confirmations", + "getblockverboseresult-size": "The size of the block", + "getblockverboseresult-height": "The height of the block in the block chain", + "getblockverboseresult-version": "The block version", + "getblockverboseresult-versionHex": "The block version in hexadecimal", + "getblockverboseresult-merkleroot": "Root hash of the merkle tree", + "getblockverboseresult-tx": "The transaction hashes (only when verbosetx=false)", + "getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosetx=true)", + "getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", + "getblockverboseresult-nonce": "The block nonce", + "getblockverboseresult-bits": "The bits which represent the block difficulty", + "getblockverboseresult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", + "getblockverboseresult-previousblockhash": "The hash of the previous block", + "getblockverboseresult-nextblockhash": "The hash of the next block (only if there is one)", + "getblockverboseresult-strippedsize": "The size of the block without witness data", // GetBlockCountCmd help. "getblockcount--synopsis": "Returns the number of blocks in the longest block chain.", @@ -733,7 +727,7 @@ var rpcResultTypes = map[string][]interface{}{ "getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)}, "getbestblock": {(*btcjson.GetBestBlockResult)(nil)}, "getbestblockhash": {(*string)(nil)}, - "getblock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil), (*btcjson.GetBlockVerboseTxResult)(nil)}, + "getblock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)}, "getblockcount": {(*int64)(nil)}, "getblockhash": {(*string)(nil)}, "getblockheader": {(*string)(nil), (*btcjson.GetBlockHeaderVerboseResult)(nil)}, From b5bf91c29f6fd6531c49e37ee0225c82639d3d0b Mon Sep 17 00:00:00 2001 From: quest Date: Sun, 19 Jul 2020 14:30:48 -0700 Subject: [PATCH 03/14] fix conflicts --- rpcclient/chain.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rpcclient/chain.go b/rpcclient/chain.go index 1d8adea40..858502b63 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -166,10 +166,6 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc } cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true)) -<<<<<<< HEAD - -======= ->>>>>>> parent of 16110805... Update getblock command to 0.15.0+ syntax return c.sendCmd(cmd) } From 101d60c38b4f8cf00712f9d93e6bd107b3ad1de6 Mon Sep 17 00:00:00 2001 From: JettScythe Date: Sun, 19 Jul 2020 20:29:50 -0300 Subject: [PATCH 04/14] Backport getBlockVerbosity fixes --- btcjson/chainsvrcmds.go | 8 +-- btcjson/chainsvrcmds_test.go | 41 +++++++----- btcjson/chainsvrresults.go | 34 +++++++++- btcjson/cmdinfo_test.go | 2 +- btcjson/example_test.go | 12 ++-- rpcclient/chain.go | 118 ++++++++++++++++++++++++++++++----- rpcserver.go | 9 ++- rpcserverhelp.go | 11 ++-- 8 files changed, 177 insertions(+), 58 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 962b51ca3..9df5afa97 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -130,8 +130,7 @@ 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 @@ -139,11 +138,10 @@ type GetBlockCmd struct { // // 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, } } diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index 383b9578e..e9a3f9641 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -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), }, }, { diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 3095c32a2..bb05dca2f 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -25,18 +25,46 @@ type GetBlockHeaderVerboseResult struct { } // GetBlockVerboseResult models the data from the getblock command when the -// verbose flag is set. When the verbose flag is not set, getblock returns a -// hex-encoded string. +// 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 { 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"` + 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. 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 { + 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"` diff --git a/btcjson/cmdinfo_test.go b/btcjson/cmdinfo_test.go index 66ee2e417..b982b2a5f 100644 --- a/btcjson/cmdinfo_test.go +++ b/btcjson/cmdinfo_test.go @@ -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)`, }, } diff --git a/btcjson/example_test.go b/btcjson/example_test.go index 91e994e85..6fd8d201b 100644 --- a/btcjson/example_test.go +++ b/btcjson/example_test.go @@ -21,7 +21,7 @@ func ExampleMarshalCmd() { // 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 @@ -38,7 +38,7 @@ 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 @@ -46,7 +46,7 @@ func ExampleMarshalCmd() { 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 @@ -84,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. diff --git a/rpcclient/chain.go b/rpcclient/chain.go index 858502b63..ef09dfb95 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -52,14 +52,60 @@ 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 } @@ -97,8 +143,12 @@ func (c *Client) GetBlockAsync(blockHash *chainhash.Hash) FutureGetBlockResult { hash = blockHash.String() } - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(false), nil) - return c.sendCmd(cmd) + cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(0)) + return FutureGetBlockResult{ + client: c, + hash: hash, + Response: c.sendCmd(cmd), + } } // GetBlock returns a raw block from the server given its hash. @@ -111,12 +161,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 } @@ -140,9 +194,14 @@ func (c *Client) GetBlockVerboseAsync(blockHash *chainhash.Hash, verboseTx bool) if blockHash != nil { hash = blockHash.String() } - - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), nil) - return c.sendCmd(cmd) + // 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 FutureGetBlockVerboseResult{ + client: c, + hash: hash, + Response: c.sendCmd(cmd), + } } // GetBlockVerbose returns a data structure from the server with information @@ -154,19 +213,50 @@ func (c *Client) GetBlockVerbose(blockHash *chainhash.Hash, verboseTx bool) (*bt return c.GetBlockVerboseAsync(blockHash, verboseTx).Receive() } +// 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 := r.client.waitForGetBlockRes(r.Response, r.hash, true, true) + 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 // the result of the RPC at some future time by invoking the Receive function on // the returned instance. // // 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 := "" if blockHash != nil { hash = blockHash.String() } - - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true)) - 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 @@ -174,7 +264,7 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc // // See GetBlockVerbose if only transaction hashes are preferred. // 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() } diff --git a/rpcserver.go b/rpcserver.go index f87d61147..b09d0d634 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1078,13 +1078,12 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i } } - // When the verbose flag isn't set, simply return the serialized block - // as a hex-encoded string. - if c.Verbose != nil && !*c.Verbose { + // When the verbose flag isn't set, return the serialized block as a hex-encoded string. + if c.Verbosity != nil && *c.Verbosity == 0 { return hex.EncodeToString(blkBytes), nil } - // The verbose flag is set, so generate the JSON object and return it. + // Otherwise, generate the JSON object and return it. // Deserialize the block. blk, err := bchutil.NewBlockFromBytes(blkBytes) @@ -1131,7 +1130,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i NextHash: nextHashString, } - if c.VerboseTx == nil || !*c.VerboseTx { + if *c.Verbosity == 1 { transactions := blk.Transactions() txNames := make([]string, len(transactions)) for i, tx := range transactions { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 74614de4d..5d1155516 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -162,10 +162,9 @@ var helpDescsEnUS = map[string]string{ // GetBlockCmd help. "getblock--synopsis": "Returns information about a block given its hash.", "getblock-hash": "The hash of the block", - "getblock-verbose": "Specifies the block is returned as a JSON object instead of hex-encoded string", - "getblock-verbosetx": "Specifies that each transaction is returned as a JSON object and only applies if the verbose flag is true (bchd extension)", - "getblock--condition0": "verbose=false", - "getblock--condition1": "verbose=true", + "getblock-verbosity": "Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2) ", + "getblock--condition0": "verbosity=0", + "getblock--condition1": "verbosity=1", "getblock--result0": "Hex-encoded bytes of the serialized block", // GetBlockChainInfoCmd help. @@ -233,8 +232,8 @@ var helpDescsEnUS = map[string]string{ "getblockverboseresult-version": "The block version", "getblockverboseresult-versionHex": "The block version in hexadecimal", "getblockverboseresult-merkleroot": "Root hash of the merkle tree", - "getblockverboseresult-tx": "The transaction hashes (only when verbosetx=false)", - "getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosetx=true)", + "getblockverboseresult-tx": "The transaction hashes (only when verbosity=1)", + "getblockverboseresult-rawtx": "The transactions as JSON objects (only when verbosity=2)", "getblockverboseresult-time": "The block time in seconds since 1 Jan 1970 GMT", "getblockverboseresult-nonce": "The block nonce", "getblockverboseresult-bits": "The bits which represent the block difficulty", From 33f13996533049e60e054b4314f52f276e83c30c Mon Sep 17 00:00:00 2001 From: JettScythe Date: Sun, 19 Jul 2020 21:00:35 -0300 Subject: [PATCH 05/14] included more results --- rpcserverhelp.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 5d1155516..eda4b3e35 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -165,7 +165,10 @@ var helpDescsEnUS = map[string]string{ "getblock-verbosity": "Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2) ", "getblock--condition0": "verbosity=0", "getblock--condition1": "verbosity=1", + "getblock--condition2": "verbosity=2", "getblock--result0": "Hex-encoded bytes of the serialized block", + "getblock--result1": "JSON object with information about block", + "getblock--result2": "JSON object with information about block and each transaction", // GetBlockChainInfoCmd help. "getblockchaininfo--synopsis": "Returns information about the current blockchain state and the status of any active soft-fork deployments.", From 5ee23300b189336cda3dd60358c1b971d901e7e0 Mon Sep 17 00:00:00 2001 From: JettScythe Date: Sun, 19 Jul 2020 21:07:36 -0300 Subject: [PATCH 06/14] Typo --- rpcserverhelp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcserverhelp.go b/rpcserverhelp.go index eda4b3e35..d78e3083f 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -167,8 +167,8 @@ var helpDescsEnUS = map[string]string{ "getblock--condition1": "verbosity=1", "getblock--condition2": "verbosity=2", "getblock--result0": "Hex-encoded bytes of the serialized block", - "getblock--result1": "JSON object with information about block", - "getblock--result2": "JSON object with information about block and each transaction", + "getblock--result1": "JSON object with information about the block", + "getblock--result2": "JSON object with information about the block and each transaction", // GetBlockChainInfoCmd help. "getblockchaininfo--synopsis": "Returns information about the current blockchain state and the status of any active soft-fork deployments.", From ea62b2865e172d92649acead5d58b939caa00bbe Mon Sep 17 00:00:00 2001 From: qqjettkgjzhxmwj <37233887+JettScythe@users.noreply.github.com> Date: Sun, 19 Jul 2020 22:50:15 -0300 Subject: [PATCH 07/14] Update json_rpc_api.md updated docs for getblock-verbosity fixes --- docs/json_rpc_api.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 647e0d9fa..92d42291c 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -271,13 +271,13 @@ the method name for further details such as parameter and return information. | | | |---|---| |Method|getblock| -|Parameters|1. block hash (string, required) - the hash of the block
2. verbose (boolean, optional, default=true) - specifies the block is returned as a JSON object instead of hex-encoded string
3. verbosetx (boolean, optional, default=false) - specifies that each transaction is returned as a JSON object and only applies if the `verbose` flag is true.**This parameter is a bchd extension**| +|Parameters|1. block hash (string, required) - the hash of the block
2. verbosity (int, optional, default=1) - specifies the block is returned as a JSON object instead of hex-encoded string.**This parameter is a bchd extension**| |Description|Returns information about a block given its hash.| -|Returns (verbose=false)|`"data" (string) hex-encoded bytes of the serialized block`| -|Returns (verbose=true, verbosetx=false)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"tx": [ (json array of string) the transaction hashes`
    `"transactionhash", (string) hash of the parent transaction`
    `...`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block (only if there is one)`
`}`| -|Returns (verbose=true, verbosetx=true)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"rawtx": [ (array of json objects) the transactions as json objects`
    `(see getrawtransaction json object details)`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block`
`}`| -|Example Return (verbose=false)|`"010000000000000000000000000000000000000000000000000000000000000000000000`
`3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49`
`ffff001d1dac2b7c01010000000100000000000000000000000000000000000000000000`
`00000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f`
`4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f`
`6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104`
`678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f`
`4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"`
**Newlines added for display purposes. The actual return does not contain newlines.**| -|Example Return (verbose=true, verbosetx=false)|`{`
  `"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",`
  `"confirmations": 277113,`
  `"size": 285,`
  `"height": 0,`
  `"version": 1,`
  `"merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",`
  `"tx": [`
    `"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"`
  `],`
  `"time": 1231006505,`
  `"nonce": 2083236893,`
  `"bits": "1d00ffff",`
  `"difficulty": 1,`
  `"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",`
  `"nextblockhash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048"`
`}`| +|Returns (verbosity=0)|`"data" (string) Hex-encoded bytes of the serialized block`| +|Returns (verbosity=1)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"tx": [ (json array of string) the transaction hashes`
    `"transactionhash", (string) hash of the parent transaction`
    `...`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block (only if there is one)`
`}`| +|Returns (verbosity=2)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"rawtx": [ (array of json objects) the transactions as json objects`
    `(see getrawtransaction json object details)`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block`
`}`| +|Example Return (verbostiy=0)|`"010000000000000000000000000000000000000000000000000000000000000000000000`
`3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49`
`ffff001d1dac2b7c01010000000100000000000000000000000000000000000000000000`
`00000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f`
`4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f`
`6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104`
`678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f`
`4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"`
**Newlines added for display purposes. The actual return does not contain newlines.**| +|Example Return (verbosity=1)|`{`
  `"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",`
  `"confirmations": 277113,`
  `"size": 285,`
  `"height": 0,`
  `"version": 1,`
  `"merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",`
  `"tx": [`
    `"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"`
  `],`
  `"time": 1231006505,`
  `"nonce": 2083236893,`
  `"bits": "1d00ffff",`
  `"difficulty": 1,`
  `"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",`
  `"nextblockhash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048"`
`}`| [Return to Overview](#MethodOverview)
*** From 28550d9825c05d174b0dcefbaafc7da5344c6e99 Mon Sep 17 00:00:00 2001 From: JettScythe Date: Mon, 20 Jul 2020 01:26:47 -0300 Subject: [PATCH 08/14] Add getbalances RPC client command --- btcjson/walletsvrcmds.go | 10 ++++++++++ btcjson/walletsvrcmds_test.go | 11 +++++++++++ btcjson/walletsvrresults.go | 14 +++++++++++++ rpcclient/wallet.go | 37 +++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/btcjson/walletsvrcmds.go b/btcjson/walletsvrcmds.go index 4a795fcac..72984de31 100644 --- a/btcjson/walletsvrcmds.go +++ b/btcjson/walletsvrcmds.go @@ -151,6 +151,15 @@ func NewGetBalanceCmd(account *string, minConf *int) *GetBalanceCmd { } } +// GetBalancesCmd defines the getbalances JSON-RPC command. +type GetBalancesCmd struct{} + +// NewGetBalancesCmd returns a new instance which can be used to issue a +// getbalances JSON-RPC command. +func NewGetBalancesCmd() *GetBalancesCmd { + return &GetBalancesCmd{} +} + // GetNewAddressCmd defines the getnewaddress JSON-RPC command. type GetNewAddressCmd struct { Account *string @@ -657,6 +666,7 @@ func init() { MustRegisterCmd("getaccountaddress", (*GetAccountAddressCmd)(nil), flags) MustRegisterCmd("getaddressesbyaccount", (*GetAddressesByAccountCmd)(nil), flags) MustRegisterCmd("getbalance", (*GetBalanceCmd)(nil), flags) + MustRegisterCmd("getbalances", (*GetBalancesCmd)(nil), flags) MustRegisterCmd("getnewaddress", (*GetNewAddressCmd)(nil), flags) MustRegisterCmd("getrawchangeaddress", (*GetRawChangeAddressCmd)(nil), flags) MustRegisterCmd("getreceivedbyaccount", (*GetReceivedByAccountCmd)(nil), flags) diff --git a/btcjson/walletsvrcmds_test.go b/btcjson/walletsvrcmds_test.go index 68f05484b..af5e05155 100644 --- a/btcjson/walletsvrcmds_test.go +++ b/btcjson/walletsvrcmds_test.go @@ -209,6 +209,17 @@ func TestWalletSvrCmds(t *testing.T) { MinConf: btcjson.Int(6), }, }, + { + name: "getbalances", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getbalances") + }, + staticCmd: func() interface{} { + return btcjson.NewGetBalancesCmd() + }, + marshalled: `{"jsonrpc":"1.0","method":"getbalances","params":[],"id":1}`, + unmarshalled: &btcjson.GetBalancesCmd{}, + }, { name: "getnewaddress", newCmd: func() (interface{}, error) { diff --git a/btcjson/walletsvrresults.go b/btcjson/walletsvrresults.go index 9246d131a..6e69ed906 100644 --- a/btcjson/walletsvrresults.go +++ b/btcjson/walletsvrresults.go @@ -159,3 +159,17 @@ type GetBestBlockResult struct { Hash string `json:"hash"` Height int32 `json:"height"` } + +// BalanceDetailsResult models the details data from the `getbalances` command. +type BalanceDetailsResult struct { + Trusted float64 `json:"trusted"` + UntrustedPending float64 `json:"untrusted_pending"` + Immature float64 `json:"immature"` + Used *float64 `json:"used"` +} + +// GetBalancesResult models the data returned from the getbalances command. +type GetBalancesResult struct { + Mine BalanceDetailsResult `json:"mine"` + WatchOnly *BalanceDetailsResult `json:"watchonly"` +} diff --git a/rpcclient/wallet.go b/rpcclient/wallet.go index f2fea4968..187d5c60d 100644 --- a/rpcclient/wallet.go +++ b/rpcclient/wallet.go @@ -1552,6 +1552,43 @@ func (c *Client) GetBalanceMinConf(account string, minConfirms int) (bchutil.Amo return c.GetBalanceMinConfAsync(account, minConfirms).Receive() } +// FutureGetBalancesResult is a future promise to deliver the result of a +// GetBalancesAsync RPC invocation (or an applicable error). +type FutureGetBalancesResult chan *response + +// Receive waits for the response promised by the future and returns the +// available balances from the server. +func (r FutureGetBalancesResult) Receive() (*btcjson.GetBalancesResult, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a floating point number. + var balances btcjson.GetBalancesResult + err = json.Unmarshal(res, &balances) + if err != nil { + return nil, err + } + + return &balances, nil +} + +// GetBalancesAsync 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 GetBalances for the blocking version and more details. +func (c *Client) GetBalancesAsync() FutureGetBalancesResult { + cmd := btcjson.NewGetBalancesCmd() + return c.sendCmd(cmd) +} + +// GetBalances returns the available balances from the server. +func (c *Client) GetBalances() (*btcjson.GetBalancesResult, error) { + return c.GetBalancesAsync().Receive() +} + // FutureGetReceivedByAccountResult is a future promise to deliver the result of // a GetReceivedByAccountAsync or GetReceivedByAccountMinConfAsync RPC // invocation (or an applicable error). From b6b44cea9436b77ededb4f57ea39708b9e55582e Mon Sep 17 00:00:00 2001 From: quest Date: Mon, 20 Jul 2020 19:20:23 -0700 Subject: [PATCH 09/14] Allow the API to accept either an integer or bool for getblock verbosity --- btcjson/chainsvrcmds.go | 25 +++++++++++++++++++++++-- btcjson/chainsvrcmds_test.go | 14 +++++++------- btcjson/cmdparse.go | 2 +- btcjson/example_test.go | 2 +- btcjson/helpers.go | 8 ++++++++ rpcclient/chain.go | 6 +++--- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 9df5afa97..c6d2ad072 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -9,6 +9,7 @@ package btcjson import ( "encoding/json" + "errors" "fmt" "github.com/gcash/bchd/wire" @@ -127,10 +128,30 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd { return &GetBestBlockHashCmd{} } +// VerbosityLevel is a type that can unmarshal a bool or an int into an int field! +// This allows the raw API to receive either an int or a bool, however from bchctl +// you must pass an int! +type VerbosityLevel int + +// UnmarshalJSON allows the VerbosityLevel to unmarshal either bool or int. +func (b *VerbosityLevel) UnmarshalJSON(dat []byte) error { + switch string(dat) { + case "0", "false": + *b = 0 + case "1", "true": + *b = 1 + case "2": + *b = 2 + default: + return errors.New("invalid VerbosityLevel value") + } + return nil +} + // GetBlockCmd defines the getblock JSON-RPC command. type GetBlockCmd struct { Hash string - Verbosity *int `jsonrpcdefault:"1"` + Verbosity *VerbosityLevel `jsonrpcdefault:"1"` } // NewGetBlockCmd returns a new instance which can be used to issue a getblock @@ -138,7 +159,7 @@ type GetBlockCmd struct { // // The parameters which are pointers indicate they are optional. Passing nil // for optional parameters will use the default value. -func NewGetBlockCmd(hash string, verbosity *int) *GetBlockCmd { +func NewGetBlockCmd(hash string, verbosity *VerbosityLevel) *GetBlockCmd { return &GetBlockCmd{ Hash: hash, Verbosity: verbosity, diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index e9a3f9641..0d8b9cdcd 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -145,12 +145,12 @@ func TestChainSvrCmds(t *testing.T) { return btcjson.NewCmd("getblock", "123", btcjson.Int(0)) }, staticCmd: func() interface{} { - return btcjson.NewGetBlockCmd("123", btcjson.Int(0)) + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(0)) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`, unmarshalled: &btcjson.GetBlockCmd{ Hash: "123", - Verbosity: btcjson.Int(0), + Verbosity: btcjson.Vlevel(0), }, }, { @@ -164,7 +164,7 @@ func TestChainSvrCmds(t *testing.T) { marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123"],"id":1}`, unmarshalled: &btcjson.GetBlockCmd{ Hash: "123", - Verbosity: btcjson.Int(1), + Verbosity: btcjson.Vlevel(1), }, }, { @@ -173,12 +173,12 @@ func TestChainSvrCmds(t *testing.T) { return btcjson.NewCmd("getblock", "123", btcjson.Int(1)) }, staticCmd: func() interface{} { - return btcjson.NewGetBlockCmd("123", btcjson.Int(1)) + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(1)) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`, unmarshalled: &btcjson.GetBlockCmd{ Hash: "123", - Verbosity: btcjson.Int(1), + Verbosity: btcjson.Vlevel(1), }, }, { @@ -187,12 +187,12 @@ func TestChainSvrCmds(t *testing.T) { return btcjson.NewCmd("getblock", "123", btcjson.Int(2)) }, staticCmd: func() interface{} { - return btcjson.NewGetBlockCmd("123", btcjson.Int(2)) + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(2)) }, marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",2],"id":1}`, unmarshalled: &btcjson.GetBlockCmd{ Hash: "123", - Verbosity: btcjson.Int(2), + Verbosity: btcjson.Vlevel(2), }, }, { diff --git a/btcjson/cmdparse.go b/btcjson/cmdparse.go index 57e14a285..51dd42cbc 100644 --- a/btcjson/cmdparse.go +++ b/btcjson/cmdparse.go @@ -471,7 +471,7 @@ func assignField(paramNum int, fieldName string, dest reflect.Value, src reflect err := json.Unmarshal([]byte(src.String()), &concreteVal) if err != nil { str := fmt.Sprintf("parameter #%d '%s' must "+ - "be valid JSON which unsmarshals to a %v", + "be valid JSON which unmarshals to a %v", paramNum, fieldName, destBaseType) return makeError(ErrInvalidType, str) } diff --git a/btcjson/example_test.go b/btcjson/example_test.go index 6fd8d201b..5f36d3453 100644 --- a/btcjson/example_test.go +++ b/btcjson/example_test.go @@ -21,7 +21,7 @@ func ExampleMarshalCmd() { // convenience function for creating a pointer out of a primitive for // optional parameters. blockHash := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" - gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Int(0)) + gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Vlevel(0)) // Marshal the command to the format suitable for sending to the RPC // server. Typically the client would increment the id here which is diff --git a/btcjson/helpers.go b/btcjson/helpers.go index d9b452e7c..a4506d38b 100644 --- a/btcjson/helpers.go +++ b/btcjson/helpers.go @@ -75,3 +75,11 @@ func String(v string) *string { *p = v return p } + +// Vlevel is a helper routine that allocates a new VerbosityLevel value to +// store v and returns a pointer to it. This is useful when assigning optional parameters. +func Vlevel(v VerbosityLevel) *VerbosityLevel { + p := new(VerbosityLevel) + *p = v + return p +} diff --git a/rpcclient/chain.go b/rpcclient/chain.go index ef09dfb95..52ee965ab 100644 --- a/rpcclient/chain.go +++ b/rpcclient/chain.go @@ -143,7 +143,7 @@ func (c *Client) GetBlockAsync(blockHash *chainhash.Hash) FutureGetBlockResult { hash = blockHash.String() } - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(0)) + cmd := btcjson.NewGetBlockCmd(hash, btcjson.Vlevel(0)) return FutureGetBlockResult{ client: c, hash: hash, @@ -196,7 +196,7 @@ func (c *Client) GetBlockVerboseAsync(blockHash *chainhash.Hash, verboseTx bool) } // From the bitcoin-cli getblock documentation: // "If verbosity is 1, returns an Object with information about block ." - cmd := btcjson.NewGetBlockCmd(hash, btcjson.Int(1)) + cmd := btcjson.NewGetBlockCmd(hash, btcjson.Vlevel(1)) return FutureGetBlockVerboseResult{ client: c, hash: hash, @@ -251,7 +251,7 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *chainhash.Hash) FutureGetBloc // 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.Vlevel(2)) return FutureGetBlockVerboseTxResult{ client: c, hash: hash, From e44322c7e4c5c4ffe69539fdd55abd8f13ea49c5 Mon Sep 17 00:00:00 2001 From: quest Date: Mon, 20 Jul 2020 19:25:05 -0700 Subject: [PATCH 10/14] Rename b to v --- btcjson/chainsvrcmds.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index c6d2ad072..869e6a4f2 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -134,14 +134,14 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd { type VerbosityLevel int // UnmarshalJSON allows the VerbosityLevel to unmarshal either bool or int. -func (b *VerbosityLevel) UnmarshalJSON(dat []byte) error { +func (v *VerbosityLevel) UnmarshalJSON(dat []byte) error { switch string(dat) { case "0", "false": - *b = 0 + *v = 0 case "1", "true": - *b = 1 + *v = 1 case "2": - *b = 2 + *v = 2 default: return errors.New("invalid VerbosityLevel value") } From 67616daa0e4d7d6d1e5d5280279dea857b30a1e4 Mon Sep 17 00:00:00 2001 From: quest Date: Mon, 20 Jul 2020 19:54:41 -0700 Subject: [PATCH 11/14] Support better handling of int/bool types --- btcjson/chainsvrcmds_test.go | 56 ++++++++++++++++++++++++++++++++++++ btcjson/cmdparse.go | 51 +++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index 0d8b9cdcd..e4c5d6dfd 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -195,6 +195,62 @@ func TestChainSvrCmds(t *testing.T) { Verbosity: btcjson.Vlevel(2), }, }, + { + name: "getblock required optional string true", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getblock", "123", btcjson.String("true")) + }, + staticCmd: func() interface{} { + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(1)) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`, + unmarshalled: &btcjson.GetBlockCmd{ + Hash: "123", + Verbosity: btcjson.Vlevel(1), + }, + }, + { + name: "getblock required optional string false", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getblock", "123", btcjson.String("false")) + }, + staticCmd: func() interface{} { + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(0)) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`, + unmarshalled: &btcjson.GetBlockCmd{ + Hash: "123", + Verbosity: btcjson.Vlevel(0), + }, + }, + { + name: "getblock required optional true", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getblock", "123", btcjson.Bool(true)) + }, + staticCmd: func() interface{} { + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(1)) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",1],"id":1}`, + unmarshalled: &btcjson.GetBlockCmd{ + Hash: "123", + Verbosity: btcjson.Vlevel(1), + }, + }, + { + name: "getblock required optional false", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getblock", "123", btcjson.Bool(false)) + }, + staticCmd: func() interface{} { + return btcjson.NewGetBlockCmd("123", btcjson.Vlevel(0)) + }, + marshalled: `{"jsonrpc":"1.0","method":"getblock","params":["123",0],"id":1}`, + unmarshalled: &btcjson.GetBlockCmd{ + Hash: "123", + Verbosity: btcjson.Vlevel(0), + }, + }, { name: "getblockchaininfo", newCmd: func() (interface{}, error) { diff --git a/btcjson/cmdparse.go b/btcjson/cmdparse.go index 51dd42cbc..7b31cbba8 100644 --- a/btcjson/cmdparse.go +++ b/btcjson/cmdparse.go @@ -190,6 +190,12 @@ func typesMaybeCompatible(dest reflect.Type, src reflect.Type) bool { return true } + if srcKind == reflect.Bool { + if isNumeric(destKind) { + return true + } + } + if srcKind == reflect.String { // Strings can potentially be converted to numeric types. if isNumeric(destKind) { @@ -289,6 +295,39 @@ func assignField(paramNum int, fieldName string, dest reflect.Value, src reflect // Perform supported type conversions. switch src.Kind() { + case reflect.Bool: + switch dest.Kind() { + // Destination is a signed integer of various magnitude. + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64: + + srcBool := src.Bool() + + switch srcBool { + case true: + dest.SetInt(1) + case false: + dest.SetInt(0) + } + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, + reflect.Uint64: + + srcBool := src.Bool() + + switch srcBool { + case true: + dest.SetUint(1) + case false: + dest.SetUint(0) + } + + default: + str := fmt.Sprintf("parameter #%d '%s' must be type "+ + "%v (got %v)", paramNum, fieldName, destBaseType, + srcBaseType) + return makeError(ErrInvalidType, str) + } // Source value is a signed integer of various magnitude. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -409,7 +448,17 @@ func assignField(paramNum int, fieldName string, dest reflect.Value, src reflect case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - srcInt, err := strconv.ParseInt(src.String(), 0, 0) + // Support coercing booleans into integers. + strVal := src.String() + + switch strVal { + case "false": + strVal = "0" + case "true": + strVal = "1" + } + + srcInt, err := strconv.ParseInt(strVal, 0, 0) if err != nil { str := fmt.Sprintf("parameter #%d '%s' must "+ "parse to a %v", paramNum, fieldName, From 57489efd6b311bf77e465b55aaf22734cc60814c Mon Sep 17 00:00:00 2001 From: quest Date: Mon, 20 Jul 2020 20:24:29 -0700 Subject: [PATCH 12/14] Fix bad comment --- btcjson/chainsvrcmds.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 869e6a4f2..3c373af23 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -129,8 +129,7 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd { } // VerbosityLevel is a type that can unmarshal a bool or an int into an int field! -// This allows the raw API to receive either an int or a bool, however from bchctl -// you must pass an int! +// This allows the raw API to receive either an int or a bool. type VerbosityLevel int // UnmarshalJSON allows the VerbosityLevel to unmarshal either bool or int. From 1bf5f131a2c57dd2c69077587afad30a2abf79c0 Mon Sep 17 00:00:00 2001 From: JettScythe Date: Tue, 21 Jul 2020 17:32:58 -0300 Subject: [PATCH 13/14] Better clarity on getBlock docs --- docs/json_rpc_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 92d42291c..72c87a33e 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -271,7 +271,7 @@ the method name for further details such as parameter and return information. | | | |---|---| |Method|getblock| -|Parameters|1. block hash (string, required) - the hash of the block
2. verbosity (int, optional, default=1) - specifies the block is returned as a JSON object instead of hex-encoded string.**This parameter is a bchd extension**| +|Parameters|1. block hash (string, required) - the hash of the block
2. verbosity (int, optional, default=1) - Specifies whether the block data should be returned as a hex-encoded string (0), as parsed data with a slice of TXIDs (1), or as parsed data with parsed transaction data (2).| |Description|Returns information about a block given its hash.| |Returns (verbosity=0)|`"data" (string) Hex-encoded bytes of the serialized block`| |Returns (verbosity=1)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"tx": [ (json array of string) the transaction hashes`
    `"transactionhash", (string) hash of the parent transaction`
    `...`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block (only if there is one)`
`}`| From 9e1e05d9324579d96a64e95d547bbb29be45003a Mon Sep 17 00:00:00 2001 From: JettScythe Date: Tue, 21 Jul 2020 17:38:55 -0300 Subject: [PATCH 14/14] Fix typo >.< --- docs/json_rpc_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 72c87a33e..077b9952c 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -276,7 +276,7 @@ the method name for further details such as parameter and return information. |Returns (verbosity=0)|`"data" (string) Hex-encoded bytes of the serialized block`| |Returns (verbosity=1)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"tx": [ (json array of string) the transaction hashes`
    `"transactionhash", (string) hash of the parent transaction`
    `...`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block (only if there is one)`
`}`| |Returns (verbosity=2)|`{ (json object)`
  `"hash": "blockhash", (string) the hash of the block (same as provided)`
  `"confirmations": n, (numeric) the number of confirmations`
  `"size": n, (numeric) the size of the block`
  `"height": n, (numeric) the height of the block in the block chain`
  `"version": n, (numeric) the block version`
  `"merkleroot": "hash", (string) root hash of the merkle tree`
  `"rawtx": [ (array of json objects) the transactions as json objects`
    `(see getrawtransaction json object details)`
  `]`
  `"time": n, (numeric) the block time in seconds since 1 Jan 1970 GMT`
  `"nonce": n, (numeric) the block nonce`
  `"bits", n, (numeric) the bits which represent the block difficulty`
  `difficulty: n.nn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty`
  `"previousblockhash": "hash", (string) the hash of the previous block`
  `"nextblockhash": "hash", (string) the hash of the next block`
`}`| -|Example Return (verbostiy=0)|`"010000000000000000000000000000000000000000000000000000000000000000000000`
`3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49`
`ffff001d1dac2b7c01010000000100000000000000000000000000000000000000000000`
`00000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f`
`4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f`
`6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104`
`678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f`
`4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"`
**Newlines added for display purposes. The actual return does not contain newlines.**| +|Example Return (verbosity=0)|`"010000000000000000000000000000000000000000000000000000000000000000000000`
`3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49`
`ffff001d1dac2b7c01010000000100000000000000000000000000000000000000000000`
`00000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f`
`4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f`
`6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104`
`678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f`
`4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"`
**Newlines added for display purposes. The actual return does not contain newlines.**| |Example Return (verbosity=1)|`{`
  `"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",`
  `"confirmations": 277113,`
  `"size": 285,`
  `"height": 0,`
  `"version": 1,`
  `"merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",`
  `"tx": [`
    `"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"`
  `],`
  `"time": 1231006505,`
  `"nonce": 2083236893,`
  `"bits": "1d00ffff",`
  `"difficulty": 1,`
  `"previousblockhash": "0000000000000000000000000000000000000000000000000000000000000000",`
  `"nextblockhash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048"`
`}`| [Return to Overview](#MethodOverview)