[NOD-423] Implement get selected tip RPC command (#469)

* [NOD-423] Rename BestBlock to SelectedTip

* [NOD-423] Implement GetSelectedTip RPC command

* [NOD-423] Add help to getSelectedTip command

* [NOD-423] Fix getSelectedTip test

* [NOD-423] Fix tests so they would compile. These tests will need to be rewriten at some point.

* [NOD-423] Make integration test compile. Test need to be revisited

* [NOD-423] Rename variables

* [NOD-423] Change comment s about best block to selected tip.

* [NOD-423] Update comment

* [NOD-423] Change height to bluescore
This commit is contained in:
Dan Aharoni 2019-11-20 12:04:22 +02:00 committed by Svarog
parent 7b07609fd8
commit 47214121a7
20 changed files with 217 additions and 127 deletions

View File

@ -72,13 +72,19 @@ func NewGenerateCmd(numBlocks uint32) *GenerateCmd {
}
}
// GetBestBlockCmd defines the getBestBlock JSON-RPC command.
type GetBestBlockCmd struct{}
// GetSelectedTipCmd defines the getSelectedTip JSON-RPC command.
type GetSelectedTipCmd struct {
Verbose *bool `jsonrpcdefault:"true"`
VerboseTx *bool `jsonrpcdefault:"false"`
}
// NewGetBestBlockCmd returns a new instance which can be used to issue a
// getBestBlock JSON-RPC command.
func NewGetBestBlockCmd() *GetBestBlockCmd {
return &GetBestBlockCmd{}
// NewGetSelectedTipCmd returns a new instance which can be used to issue a
// getSelectedTip JSON-RPC command.
func NewGetSelectedTipCmd(verbose, verboseTx *bool) *GetSelectedTipCmd {
return &GetSelectedTipCmd{
Verbose: verbose,
VerboseTx: verboseTx,
}
}
// GetCurrentNetCmd defines the getCurrentNet JSON-RPC command.
@ -144,7 +150,7 @@ func init() {
MustRegisterCmd("debugLevel", (*DebugLevelCmd)(nil), flags)
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
MustRegisterCmd("getBestBlock", (*GetBestBlockCmd)(nil), flags)
MustRegisterCmd("getSelectedTip", (*GetSelectedTipCmd)(nil), flags)
MustRegisterCmd("getCurrentNet", (*GetCurrentNetCmd)(nil), flags)
MustRegisterCmd("getHeaders", (*GetHeadersCmd)(nil), flags)
MustRegisterCmd("getTopHeaders", (*GetTopHeadersCmd)(nil), flags)

View File

@ -115,15 +115,18 @@ func TestBtcdExtCmds(t *testing.T) {
},
},
{
name: "getBestBlock",
name: "getSelectedTip",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getBestBlock")
return btcjson.NewCmd("getSelectedTip")
},
staticCmd: func() interface{} {
return btcjson.NewGetBestBlockCmd()
return btcjson.NewGetSelectedTipCmd(nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getSelectedTip","params":[],"id":1}`,
unmarshalled: &btcjson.GetSelectedTipCmd{
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(false),
},
marshalled: `{"jsonrpc":"1.0","method":"getBestBlock","params":[],"id":1}`,
unmarshalled: &btcjson.GetBestBlockCmd{},
},
{
name: "getCurrentNet",

View File

@ -124,13 +124,13 @@ func NewGetAllManualNodesInfoCmd(details *bool) *GetAllManualNodesInfoCmd {
}
}
// GetBestBlockHashCmd defines the getBestBlockHash JSON-RPC command.
type GetBestBlockHashCmd struct{}
// GetSelectedTipHashCmd defines the getSelectedTipHash JSON-RPC command.
type GetSelectedTipHashCmd struct{}
// NewGetBestBlockHashCmd returns a new instance which can be used to issue a
// getBestBlockHash JSON-RPC command.
func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
return &GetBestBlockHashCmd{}
// NewGetSelectedTipHashCmd returns a new instance which can be used to issue a
// getSelectedTipHash JSON-RPC command.
func NewGetSelectedTipHashCmd() *GetSelectedTipHashCmd {
return &GetSelectedTipHashCmd{}
}
// GetBlockCmd defines the getBlock JSON-RPC command.
@ -740,7 +740,7 @@ func init() {
MustRegisterCmd("decodeRawTransaction", (*DecodeRawTransactionCmd)(nil), flags)
MustRegisterCmd("decodeScript", (*DecodeScriptCmd)(nil), flags)
MustRegisterCmd("getAllManualNodesInfo", (*GetAllManualNodesInfoCmd)(nil), flags)
MustRegisterCmd("getBestBlockHash", (*GetBestBlockHashCmd)(nil), flags)
MustRegisterCmd("getSelectedTipHash", (*GetSelectedTipHashCmd)(nil), flags)
MustRegisterCmd("getBlock", (*GetBlockCmd)(nil), flags)
MustRegisterCmd("getBlocks", (*GetBlocksCmd)(nil), flags)
MustRegisterCmd("getBlockDagInfo", (*GetBlockDAGInfoCmd)(nil), flags)

View File

@ -115,15 +115,15 @@ func TestDAGSvrCmds(t *testing.T) {
unmarshalled: &btcjson.GetAllManualNodesInfoCmd{Details: btcjson.Bool(true)},
},
{
name: "getBestBlockHash",
name: "getSelectedTipHash",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getBestBlockHash")
return btcjson.NewCmd("getSelectedTipHash")
},
staticCmd: func() interface{} {
return btcjson.NewGetBestBlockHashCmd()
return btcjson.NewGetSelectedTipHashCmd()
},
marshalled: `{"jsonrpc":"1.0","method":"getBestBlockHash","params":[],"id":1}`,
unmarshalled: &btcjson.GetBestBlockHashCmd{},
marshalled: `{"jsonrpc":"1.0","method":"getSelectedTipHash","params":[],"id":1}`,
unmarshalled: &btcjson.GetSelectedTipHashCmd{},
},
{
name: "getBlock",

View File

@ -283,7 +283,7 @@ type GetSubnetworkResult struct {
// GetTxOutResult models the data from the gettxout command.
type GetTxOutResult struct {
BestBlock string `json:"bestBlock"`
SelectedTip string `json:"selectedTip"`
Confirmations *uint64 `json:"confirmations,omitempty"`
IsInMempool bool `json:"isInMempool"`
Value float64 `json:"value"`
@ -485,12 +485,6 @@ type ValidateAddressResult struct {
Address string `json:"address,omitempty"`
}
// GetBestBlockResult models the data from the getbestblock command.
type GetBestBlockResult struct {
Hash string `json:"hash"`
Height uint64 `json:"height"`
}
// ChainBlock models a block that is part of the selected parent chain.
type ChainBlock struct {
Hash string `json:"hash"`

View File

@ -54,7 +54,7 @@ const (
const (
ErrRPCBlockNotFound RPCErrorCode = -5
ErrRPCBlockCount RPCErrorCode = -5
ErrRPCBestBlockHash RPCErrorCode = -5
ErrRPCSelectedTipHash RPCErrorCode = -5
ErrRPCDifficulty RPCErrorCode = -5
ErrRPCOutOfRange RPCErrorCode = -1
ErrRPCNoTxInfo RPCErrorCode = -5

View File

@ -435,7 +435,7 @@ func TestBIP0068AndCsv(t *testing.T) {
// Now mine 10 additional blocks giving the inputs generated above a
// age of 11. Space out each block 10 minutes after the previous block.
parentBlockHash, err := r.Node.GetBestBlockHash()
parentBlockHash, err := r.Node.GetSelectedTipHash()
if err != nil {
t.Fatalf("unable to get prior block hash: %v", err)
}

View File

@ -18,10 +18,10 @@ import (
"github.com/daglabs/btcd/integration/rpctest"
)
func testGetBestBlock(r *rpctest.Harness, t *testing.T) {
_, prevbestHeight, err := r.Node.GetBestBlock()
func testGetSelectedTip(r *rpctest.Harness, t *testing.T) {
_, prevbestHeight, err := r.Node.GetSelectedTip()
if err != nil {
t.Fatalf("Call to `getbestblock` failed: %v", err)
t.Fatalf("Call to `GetSelectedTip` failed: %v", err)
}
// Create a new block connecting to the current tip.
@ -30,9 +30,9 @@ func testGetBestBlock(r *rpctest.Harness, t *testing.T) {
t.Fatalf("Unable to generate block: %v", err)
}
bestHash, bestHeight, err := r.Node.GetBestBlock()
bestHash, bestHeight, err := r.Node.GetSelectedTip()
if err != nil {
t.Fatalf("Call to `getbestblock` failed: %v", err)
t.Fatalf("Call to `GetSelectedTip` failed: %v", err)
}
// Hash should be the same as the newly submitted block.
@ -95,7 +95,7 @@ func testGetBlockHash(r *rpctest.Harness, t *testing.T) {
}
var rpcTestCases = []rpctest.HarnessTestCase{
testGetBestBlock,
testGetSelectedTip,
testGetBlockCount,
testGetBlockHash,
}

View File

@ -245,14 +245,15 @@ func (h *Harness) SetUp(createTestChain bool, numMatureOutputs uint32) error {
// Block until the wallet has fully synced up to the tip of the main
// chain.
_, height, err := h.Node.GetBestBlock()
selectedTip, err := h.Node.GetSelectedTip()
if err != nil {
return err
}
blueScore := selectedTip.BlueScore
ticker := time.NewTicker(time.Millisecond * 100)
for range ticker.C {
walletHeight := h.wallet.SyncedHeight()
if walletHeight == height {
if walletHeight == blueScore {
break
}
}
@ -429,16 +430,24 @@ func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs(
blockVersion = BlockVersion
}
parentBlockHash, parentBlockHeight, err := h.Node.GetBestBlock()
selectedTip, err := h.Node.GetSelectedTip()
if err != nil {
return nil, err
}
mBlock, err := h.Node.GetBlock(parentBlockHash, nil)
selectedTipHash, err := daghash.NewHashFromStr(selectedTip.Hash)
if err != nil {
return nil, err
}
selectedTipBlueScore := selectedTip.BlueScore
mBlock, err := h.Node.GetBlock(selectedTipHash, nil)
if err != nil {
return nil, err
}
parentBlock := util.NewBlock(mBlock)
parentBlock.SetChainHeight(parentBlockHeight)
parentBlock.SetChainHeight(selectedTipBlueScore)
// Create a new block including the specified transactions
newBlock, err := CreateBlock(parentBlock, txns, blockVersion,

View File

@ -81,19 +81,26 @@ func syncBlocks(nodes []*Harness) error {
retry:
for !blocksMatch {
var parentHash *daghash.Hash
var prevHeight uint64
var prevBlueScore uint64
for _, node := range nodes {
blockHash, blockHeight, err := node.Node.GetBestBlock()
selectedTip, err := node.Node.GetSelectedTip()
if err != nil {
return err
}
blockHash, err := daghash.NewHashFromStr(selectedTip.Hash)
if err != nil {
return err
}
blueScore := selectedTip.BlueScore
if parentHash != nil && (*blockHash != *parentHash ||
blockHeight != prevHeight) {
blueScore != prevBlueScore) {
time.Sleep(time.Millisecond * 100)
continue retry
}
parentHash, prevHeight = blockHash, blockHeight
parentHash, prevBlueScore = blockHash, blueScore
}
blocksMatch = true

View File

@ -15,13 +15,13 @@ import (
"github.com/daglabs/btcd/wire"
)
// FutureGetBestBlockHashResult is a future promise to deliver the result of a
// GetBestBlockAsync RPC invocation (or an applicable error).
type FutureGetBestBlockHashResult chan *response
// FutureGetSelectedTipHashResult is a future promise to deliver the result of a
// GetSelectedTipAsync RPC invocation (or an applicable error).
type FutureGetSelectedTipHashResult chan *response
// Receive waits for the response promised by the future and returns the hash of
// the best block in the longest block dag.
func (r FutureGetBestBlockHashResult) Receive() (*daghash.Hash, error) {
func (r FutureGetSelectedTipHashResult) Receive() (*daghash.Hash, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
@ -36,20 +36,20 @@ func (r FutureGetBestBlockHashResult) Receive() (*daghash.Hash, error) {
return daghash.NewHashFromStr(txHashStr)
}
// GetBestBlockHashAsync returns an instance of a type that can be used to get
// GetSelectedTipHashAsync 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 GetBestBlockHash for the blocking version and more details.
func (c *Client) GetBestBlockHashAsync() FutureGetBestBlockHashResult {
cmd := btcjson.NewGetBestBlockHashCmd()
// See GetSelectedTipHash for the blocking version and more details.
func (c *Client) GetSelectedTipHashAsync() FutureGetSelectedTipHashResult {
cmd := btcjson.NewGetSelectedTipHashCmd()
return c.sendCmd(cmd)
}
// GetBestBlockHash returns the hash of the best block in the longest block
// dag.
func (c *Client) GetBestBlockHash() (*daghash.Hash, error) {
return c.GetBestBlockHashAsync().Receive()
// GetSelectedTipHash returns the hash of the selected tip of the
// Block DAG.
func (c *Client) GetSelectedTipHash() (*daghash.Hash, error) {
return c.GetSelectedTipHashAsync().Receive()
}
// FutureGetBlockResult is a future promise to deliver the result of a

View File

@ -62,52 +62,87 @@ func (c *Client) DebugLevel(levelSpec string) (string, error) {
return c.DebugLevelAsync(levelSpec).Receive()
}
// FutureGetBestBlockResult is a future promise to deliver the result of a
// GetBestBlockAsync RPC invocation (or an applicable error).
type FutureGetBestBlockResult chan *response
// FutureGetSelectedTipResult is a future promise to deliver the result of a
// GetSelectedTipAsync RPC invocation (or an applicable error).
type FutureGetSelectedTipResult chan *response
// Receive waits for the response promised by the future and returns the hash
// and height of the block in the longest (best) chain.
func (r FutureGetBestBlockResult) Receive() (*daghash.Hash, uint64, error) {
// Receive waits for the response promised by the future and returns the
// selected tip block.
func (r FutureGetSelectedTipResult) Receive() (*wire.MsgBlock, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, 0, err
return nil, err
}
// Unmarshal result as a getbestblock result object.
var bestBlock btcjson.GetBestBlockResult
err = json.Unmarshal(res, &bestBlock)
// Unmarshal result as a string.
var blockHex string
err = json.Unmarshal(res, &blockHex)
if err != nil {
return nil, 0, err
return nil, err
}
// Convert to hash from string.
hash, err := daghash.NewHashFromStr(bestBlock.Hash)
// Decode the serialized block hex to raw bytes.
serializedBlock, err := hex.DecodeString(blockHex)
if err != nil {
return nil, 0, err
return nil, err
}
return hash, bestBlock.Height, nil
// Deserialize the block and return it.
var msgBlock wire.MsgBlock
err = msgBlock.Deserialize(bytes.NewReader(serializedBlock))
if err != nil {
return nil, err
}
return &msgBlock, nil
}
// GetBestBlockAsync returns an instance of a type that can be used to get the
// GetSelectedTipAsync 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 GetBestBlock for the blocking version and more details.
// See GetSelectedTip for the blocking version and more details.
//
// NOTE: This is a btcd extension.
func (c *Client) GetBestBlockAsync() FutureGetBestBlockResult {
cmd := btcjson.NewGetBestBlockCmd()
func (c *Client) GetSelectedTipAsync() FutureGetSelectedTipResult {
cmd := btcjson.NewGetSelectedTipCmd(btcjson.Bool(false), btcjson.Bool(false))
return c.sendCmd(cmd)
}
// GetBestBlock returns the hash and height of the block in the longest (best)
// chain.
//
// GetSelectedTip returns the block of the selected DAG tip
// NOTE: This is a btcd extension.
func (c *Client) GetBestBlock() (*daghash.Hash, uint64, error) {
return c.GetBestBlockAsync().Receive()
func (c *Client) GetSelectedTip() (*btcjson.GetBlockVerboseResult, error) {
return c.GetSelectedTipVerboseAsync().Receive()
}
// FutureGetSelectedTipVerboseResult is a future promise to deliver the result of a
// GetSelectedTipVerboseAsync RPC invocation (or an applicable error).
type FutureGetSelectedTipVerboseResult 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 FutureGetSelectedTipVerboseResult) Receive() (*btcjson.GetBlockVerboseResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
// Unmarshal the raw result into a BlockResult.
var blockResult btcjson.GetBlockVerboseResult
err = json.Unmarshal(res, &blockResult)
if err != nil {
return nil, err
}
return &blockResult, nil
}
// GetSelectedTipVerboseAsync 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 GeSelectedTipBlockVerbose for the blocking version and more details.
func (c *Client) GetSelectedTipVerboseAsync() FutureGetSelectedTipVerboseResult {
cmd := btcjson.NewGetSelectedTipCmd(btcjson.Bool(true), btcjson.Bool(false))
return c.sendCmd(cmd)
}
// FutureGetCurrentNetResult is a future promise to deliver the result of a

View File

@ -1,15 +0,0 @@
package rpc
import "github.com/daglabs/btcd/btcjson"
// handleGetBestBlock implements the getBestBlock command.
func handleGetBestBlock(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
// All other "get block" commands give either the height, the
// hash, or both but require the block SHA. This gets both for
// the best block.
result := &btcjson.GetBestBlockResult{
Hash: s.cfg.DAG.SelectedTipHash().String(),
Height: s.cfg.DAG.ChainHeight(), //TODO: (Ori) This is probably wrong. Done only for compilation
}
return result, nil
}

View File

@ -1,6 +0,0 @@
package rpc
// handleGetBestBlockHash implements the getBestBlockHash command.
func handleGetBestBlockHash(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
return s.cfg.DAG.SelectedTipHash().String(), nil
}

View File

@ -80,8 +80,8 @@ func handleGetBlock(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
}
}
// When the verbose flag isn't set, simply return the serialized block
// as a hex-encoded string.
// When the verbose flag is set to false, simply return the serialized block
// as a hex-encoded string (verbose flag is on by default).
if c.Verbose != nil && !*c.Verbose {
return hex.EncodeToString(blkBytes), nil
}

View File

@ -0,0 +1,46 @@
package rpc
import (
"encoding/hex"
"github.com/daglabs/btcd/btcjson"
"github.com/daglabs/btcd/database"
"github.com/daglabs/btcd/util"
)
// handleGetSelectedTip implements the getSelectedTip command.
func handleGetSelectedTip(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
getSelectedTipCmd := cmd.(*btcjson.GetSelectedTipCmd)
selectedTipHash := s.cfg.DAG.SelectedTipHash()
var blockBytes []byte
err := s.cfg.DB.View(func(dbTx database.Tx) error {
var err error
blockBytes, err = dbTx.FetchBlock(selectedTipHash)
return err
})
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCBlockNotFound,
Message: "Block not found",
}
}
// When the verbose flag is set to false, simply return the serialized block
// as a hex-encoded string (verbose flag is on by default).
if getSelectedTipCmd.Verbose != nil && !*getSelectedTipCmd.Verbose {
return hex.EncodeToString(blockBytes), nil
}
// Deserialize the block.
blk, err := util.NewBlockFromBytes(blockBytes)
if err != nil {
context := "Failed to deserialize block"
return nil, internalRPCError(err.Error(), context)
}
blockVerboseResult, err := buildGetBlockVerboseResult(s, blk, getSelectedTipCmd.VerboseTx == nil || !*getSelectedTipCmd.VerboseTx)
if err != nil {
return nil, err
}
return blockVerboseResult, nil
}

View File

@ -0,0 +1,6 @@
package rpc
// handleGetSelectedTipHash implements the getSelectedTipHash command.
func handleGetSelectedTipHash(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
return s.cfg.DAG.SelectedTipHash().String(), nil
}

View File

@ -22,7 +22,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
// If requested and the tx is available in the mempool try to fetch it
// from there, otherwise attempt to fetch from the block database.
var bestBlockHash string
var selectedTipHash string
var confirmations *uint64
var value uint64
var scriptPubKey []byte
@ -56,7 +56,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
return nil, internalRPCError(errStr, "")
}
bestBlockHash = s.cfg.DAG.SelectedTipHash().String()
selectedTipHash = s.cfg.DAG.SelectedTipHash().String()
value = txOut.Value
scriptPubKey = txOut.ScriptPubKey
isCoinbase = mtx.IsCoinBase()
@ -86,7 +86,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
confirmations = &txConfirmations
}
bestBlockHash = s.cfg.DAG.SelectedTipHash().String()
selectedTipHash = s.cfg.DAG.SelectedTipHash().String()
value = entry.Amount()
scriptPubKey = entry.ScriptPubKey()
isCoinbase = entry.IsCoinbase()
@ -108,7 +108,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
}
txOutReply := &btcjson.GetTxOutResult{
BestBlock: bestBlockHash,
SelectedTip: selectedTipHash,
Confirmations: confirmations,
IsInMempool: isInMempool,
Value: util.Amount(value).ToBTC(),

View File

@ -66,8 +66,8 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"decodeScript": handleDecodeScript,
"generate": handleGenerate,
"getAllManualNodesInfo": handleGetAllManualNodesInfo,
"getBestBlock": handleGetBestBlock,
"getBestBlockHash": handleGetBestBlockHash,
"getSelectedTip": handleGetSelectedTip,
"getSelectedTipHash": handleGetSelectedTipHash,
"getBlock": handleGetBlock,
"getBlocks": handleGetBlocks,
"getBlockDagInfo": handleGetBlockDAGInfo,
@ -140,8 +140,8 @@ var rpcLimited = map[string]struct{}{
"createRawTransaction": {},
"decodeRawTransaction": {},
"decodeScript": {},
"getBestBlock": {},
"getBestBlockHash": {},
"getSelectedTip": {},
"getSelectedTipHash": {},
"getBlock": {},
"getBlocks": {},
"getBlockCount": {},

View File

@ -149,17 +149,22 @@ var helpDescsEnUS = map[string]string{
"getManualNodeInfo--condition1": "details=true",
"getManualNodeInfo--result0": "List of added peers",
// GetBestBlockResult help.
"getBestBlockResult-hash": "Hex-encoded bytes of the best block hash",
"getBestBlockResult-height": "Height of the best block",
// GetSelectedTipResult help.
"getSelectedTipResult-hash": "Hex-encoded bytes of the best block hash",
"getSelectedTipResult-height": "Height of the best block",
// GetBestBlockCmd help.
"getBestBlock--synopsis": "Get block height and hash of best block in the main chain.",
"getBestBlock--result0": "Get block height and hash of best block in the main chain.",
// GetSelectedTipCmd help.
"getSelectedTip--synopsis": "Returns information about the selected tip of the blockDAG.",
"getSelectedTip-verbose": "Specifies the block is returned as a JSON object instead of hex-encoded string",
"getSelectedTip-verboseTx": "Specifies that each transaction is returned as a JSON object and only applies if the verbose flag is true (btcd extension)",
"getSelectedTip--condition0": "verbose=false",
"getSelectedTip--condition1": "verbose=true",
"getSelectedTip-acceptedTx": "Specifies if the transaction got accepted",
"getSelectedTip--result0": "Hex-encoded bytes of the serialized block",
// GetBestBlockHashCmd help.
"getBestBlockHash--synopsis": "Returns the hash of the of the best (most recent) block in the longest block chain.",
"getBestBlockHash--result0": "The hex-encoded block hash",
// GetSelectedTipHashCmd help.
"getSelectedTipHash--synopsis": "Returns the hash of the of the selected tip of the blockDAG.",
"getSelectedTipHash--result0": "The hex-encoded block hash",
// GetBlockCmd help.
"getBlock--synopsis": "Returns information about a block given its hash.",
@ -519,7 +524,7 @@ var helpDescsEnUS = map[string]string{
"getSubnetworkResult-gasLimit": "The gas limit of the subnetwork",
// GetTxOutResult help.
"getTxOutResult-bestBlock": "The block hash that contains the transaction output",
"getTxOutResult-selectedTip": "The block hash that contains the transaction output",
"getTxOutResult-confirmations": "The number of confirmations (Will be 'null' if txindex is not disabled)",
"getTxOutResult-isInMempool": "Whether the transaction is in the mempool",
"getTxOutResult-value": "The transaction amount in BTC",
@ -675,8 +680,8 @@ var rpcResultTypes = map[string][]interface{}{
"decodeScript": {(*btcjson.DecodeScriptResult)(nil)},
"generate": {(*[]string)(nil)},
"getAllManualNodesInfo": {(*[]string)(nil), (*[]btcjson.GetManualNodeInfoResult)(nil)},
"getBestBlock": {(*btcjson.GetBestBlockResult)(nil)},
"getBestBlockHash": {(*string)(nil)},
"getSelectedTip": {(*btcjson.GetBlockVerboseResult)(nil)},
"getSelectedTipHash": {(*string)(nil)},
"getBlock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)},
"getBlocks": {(*btcjson.GetBlocksResult)(nil)},
"getBlockCount": {(*int64)(nil)},