mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-05 21:56:50 +00:00
[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:
parent
7b07609fd8
commit
47214121a7
@ -72,13 +72,19 @@ func NewGenerateCmd(numBlocks uint32) *GenerateCmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBestBlockCmd defines the getBestBlock JSON-RPC command.
|
// GetSelectedTipCmd defines the getSelectedTip JSON-RPC command.
|
||||||
type GetBestBlockCmd struct{}
|
type GetSelectedTipCmd struct {
|
||||||
|
Verbose *bool `jsonrpcdefault:"true"`
|
||||||
|
VerboseTx *bool `jsonrpcdefault:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewGetBestBlockCmd returns a new instance which can be used to issue a
|
// NewGetSelectedTipCmd returns a new instance which can be used to issue a
|
||||||
// getBestBlock JSON-RPC command.
|
// getSelectedTip JSON-RPC command.
|
||||||
func NewGetBestBlockCmd() *GetBestBlockCmd {
|
func NewGetSelectedTipCmd(verbose, verboseTx *bool) *GetSelectedTipCmd {
|
||||||
return &GetBestBlockCmd{}
|
return &GetSelectedTipCmd{
|
||||||
|
Verbose: verbose,
|
||||||
|
VerboseTx: verboseTx,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentNetCmd defines the getCurrentNet JSON-RPC command.
|
// GetCurrentNetCmd defines the getCurrentNet JSON-RPC command.
|
||||||
@ -144,7 +150,7 @@ func init() {
|
|||||||
MustRegisterCmd("debugLevel", (*DebugLevelCmd)(nil), flags)
|
MustRegisterCmd("debugLevel", (*DebugLevelCmd)(nil), flags)
|
||||||
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
|
MustRegisterCmd("node", (*NodeCmd)(nil), flags)
|
||||||
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
|
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
|
||||||
MustRegisterCmd("getBestBlock", (*GetBestBlockCmd)(nil), flags)
|
MustRegisterCmd("getSelectedTip", (*GetSelectedTipCmd)(nil), flags)
|
||||||
MustRegisterCmd("getCurrentNet", (*GetCurrentNetCmd)(nil), flags)
|
MustRegisterCmd("getCurrentNet", (*GetCurrentNetCmd)(nil), flags)
|
||||||
MustRegisterCmd("getHeaders", (*GetHeadersCmd)(nil), flags)
|
MustRegisterCmd("getHeaders", (*GetHeadersCmd)(nil), flags)
|
||||||
MustRegisterCmd("getTopHeaders", (*GetTopHeadersCmd)(nil), flags)
|
MustRegisterCmd("getTopHeaders", (*GetTopHeadersCmd)(nil), flags)
|
||||||
|
@ -115,15 +115,18 @@ func TestBtcdExtCmds(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getBestBlock",
|
name: "getSelectedTip",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("getBestBlock")
|
return btcjson.NewCmd("getSelectedTip")
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
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",
|
name: "getCurrentNet",
|
||||||
|
@ -124,13 +124,13 @@ func NewGetAllManualNodesInfoCmd(details *bool) *GetAllManualNodesInfoCmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBestBlockHashCmd defines the getBestBlockHash JSON-RPC command.
|
// GetSelectedTipHashCmd defines the getSelectedTipHash JSON-RPC command.
|
||||||
type GetBestBlockHashCmd struct{}
|
type GetSelectedTipHashCmd struct{}
|
||||||
|
|
||||||
// NewGetBestBlockHashCmd returns a new instance which can be used to issue a
|
// NewGetSelectedTipHashCmd returns a new instance which can be used to issue a
|
||||||
// getBestBlockHash JSON-RPC command.
|
// getSelectedTipHash JSON-RPC command.
|
||||||
func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
|
func NewGetSelectedTipHashCmd() *GetSelectedTipHashCmd {
|
||||||
return &GetBestBlockHashCmd{}
|
return &GetSelectedTipHashCmd{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockCmd defines the getBlock JSON-RPC command.
|
// GetBlockCmd defines the getBlock JSON-RPC command.
|
||||||
@ -740,7 +740,7 @@ func init() {
|
|||||||
MustRegisterCmd("decodeRawTransaction", (*DecodeRawTransactionCmd)(nil), flags)
|
MustRegisterCmd("decodeRawTransaction", (*DecodeRawTransactionCmd)(nil), flags)
|
||||||
MustRegisterCmd("decodeScript", (*DecodeScriptCmd)(nil), flags)
|
MustRegisterCmd("decodeScript", (*DecodeScriptCmd)(nil), flags)
|
||||||
MustRegisterCmd("getAllManualNodesInfo", (*GetAllManualNodesInfoCmd)(nil), flags)
|
MustRegisterCmd("getAllManualNodesInfo", (*GetAllManualNodesInfoCmd)(nil), flags)
|
||||||
MustRegisterCmd("getBestBlockHash", (*GetBestBlockHashCmd)(nil), flags)
|
MustRegisterCmd("getSelectedTipHash", (*GetSelectedTipHashCmd)(nil), flags)
|
||||||
MustRegisterCmd("getBlock", (*GetBlockCmd)(nil), flags)
|
MustRegisterCmd("getBlock", (*GetBlockCmd)(nil), flags)
|
||||||
MustRegisterCmd("getBlocks", (*GetBlocksCmd)(nil), flags)
|
MustRegisterCmd("getBlocks", (*GetBlocksCmd)(nil), flags)
|
||||||
MustRegisterCmd("getBlockDagInfo", (*GetBlockDAGInfoCmd)(nil), flags)
|
MustRegisterCmd("getBlockDagInfo", (*GetBlockDAGInfoCmd)(nil), flags)
|
||||||
|
@ -115,15 +115,15 @@ func TestDAGSvrCmds(t *testing.T) {
|
|||||||
unmarshalled: &btcjson.GetAllManualNodesInfoCmd{Details: btcjson.Bool(true)},
|
unmarshalled: &btcjson.GetAllManualNodesInfoCmd{Details: btcjson.Bool(true)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getBestBlockHash",
|
name: "getSelectedTipHash",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("getBestBlockHash")
|
return btcjson.NewCmd("getSelectedTipHash")
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewGetBestBlockHashCmd()
|
return btcjson.NewGetSelectedTipHashCmd()
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"getBestBlockHash","params":[],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"getSelectedTipHash","params":[],"id":1}`,
|
||||||
unmarshalled: &btcjson.GetBestBlockHashCmd{},
|
unmarshalled: &btcjson.GetSelectedTipHashCmd{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "getBlock",
|
name: "getBlock",
|
||||||
|
@ -283,7 +283,7 @@ type GetSubnetworkResult struct {
|
|||||||
|
|
||||||
// GetTxOutResult models the data from the gettxout command.
|
// GetTxOutResult models the data from the gettxout command.
|
||||||
type GetTxOutResult struct {
|
type GetTxOutResult struct {
|
||||||
BestBlock string `json:"bestBlock"`
|
SelectedTip string `json:"selectedTip"`
|
||||||
Confirmations *uint64 `json:"confirmations,omitempty"`
|
Confirmations *uint64 `json:"confirmations,omitempty"`
|
||||||
IsInMempool bool `json:"isInMempool"`
|
IsInMempool bool `json:"isInMempool"`
|
||||||
Value float64 `json:"value"`
|
Value float64 `json:"value"`
|
||||||
@ -485,12 +485,6 @@ type ValidateAddressResult struct {
|
|||||||
Address string `json:"address,omitempty"`
|
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.
|
// ChainBlock models a block that is part of the selected parent chain.
|
||||||
type ChainBlock struct {
|
type ChainBlock struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
|
@ -54,7 +54,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
ErrRPCBlockNotFound RPCErrorCode = -5
|
ErrRPCBlockNotFound RPCErrorCode = -5
|
||||||
ErrRPCBlockCount RPCErrorCode = -5
|
ErrRPCBlockCount RPCErrorCode = -5
|
||||||
ErrRPCBestBlockHash RPCErrorCode = -5
|
ErrRPCSelectedTipHash RPCErrorCode = -5
|
||||||
ErrRPCDifficulty RPCErrorCode = -5
|
ErrRPCDifficulty RPCErrorCode = -5
|
||||||
ErrRPCOutOfRange RPCErrorCode = -1
|
ErrRPCOutOfRange RPCErrorCode = -1
|
||||||
ErrRPCNoTxInfo RPCErrorCode = -5
|
ErrRPCNoTxInfo RPCErrorCode = -5
|
||||||
|
@ -435,7 +435,7 @@ func TestBIP0068AndCsv(t *testing.T) {
|
|||||||
|
|
||||||
// Now mine 10 additional blocks giving the inputs generated above a
|
// Now mine 10 additional blocks giving the inputs generated above a
|
||||||
// age of 11. Space out each block 10 minutes after the previous block.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("unable to get prior block hash: %v", err)
|
t.Fatalf("unable to get prior block hash: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,10 @@ import (
|
|||||||
"github.com/daglabs/btcd/integration/rpctest"
|
"github.com/daglabs/btcd/integration/rpctest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testGetBestBlock(r *rpctest.Harness, t *testing.T) {
|
func testGetSelectedTip(r *rpctest.Harness, t *testing.T) {
|
||||||
_, prevbestHeight, err := r.Node.GetBestBlock()
|
_, prevbestHeight, err := r.Node.GetSelectedTip()
|
||||||
if err != nil {
|
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.
|
// 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)
|
t.Fatalf("Unable to generate block: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bestHash, bestHeight, err := r.Node.GetBestBlock()
|
bestHash, bestHeight, err := r.Node.GetSelectedTip()
|
||||||
if err != nil {
|
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.
|
// 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{
|
var rpcTestCases = []rpctest.HarnessTestCase{
|
||||||
testGetBestBlock,
|
testGetSelectedTip,
|
||||||
testGetBlockCount,
|
testGetBlockCount,
|
||||||
testGetBlockHash,
|
testGetBlockHash,
|
||||||
}
|
}
|
||||||
|
@ -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
|
// Block until the wallet has fully synced up to the tip of the main
|
||||||
// chain.
|
// chain.
|
||||||
_, height, err := h.Node.GetBestBlock()
|
selectedTip, err := h.Node.GetSelectedTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
blueScore := selectedTip.BlueScore
|
||||||
ticker := time.NewTicker(time.Millisecond * 100)
|
ticker := time.NewTicker(time.Millisecond * 100)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
walletHeight := h.wallet.SyncedHeight()
|
walletHeight := h.wallet.SyncedHeight()
|
||||||
if walletHeight == height {
|
if walletHeight == blueScore {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,16 +430,24 @@ func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs(
|
|||||||
blockVersion = BlockVersion
|
blockVersion = BlockVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
parentBlockHash, parentBlockHeight, err := h.Node.GetBestBlock()
|
selectedTip, err := h.Node.GetSelectedTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mBlock, err := h.Node.GetBlock(parentBlockHash, nil)
|
|
||||||
|
selectedTipHash, err := daghash.NewHashFromStr(selectedTip.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedTipBlueScore := selectedTip.BlueScore
|
||||||
|
mBlock, err := h.Node.GetBlock(selectedTipHash, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
parentBlock := util.NewBlock(mBlock)
|
parentBlock := util.NewBlock(mBlock)
|
||||||
parentBlock.SetChainHeight(parentBlockHeight)
|
parentBlock.SetChainHeight(selectedTipBlueScore)
|
||||||
|
|
||||||
// Create a new block including the specified transactions
|
// Create a new block including the specified transactions
|
||||||
newBlock, err := CreateBlock(parentBlock, txns, blockVersion,
|
newBlock, err := CreateBlock(parentBlock, txns, blockVersion,
|
||||||
|
@ -81,19 +81,26 @@ func syncBlocks(nodes []*Harness) error {
|
|||||||
retry:
|
retry:
|
||||||
for !blocksMatch {
|
for !blocksMatch {
|
||||||
var parentHash *daghash.Hash
|
var parentHash *daghash.Hash
|
||||||
var prevHeight uint64
|
var prevBlueScore uint64
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
blockHash, blockHeight, err := node.Node.GetBestBlock()
|
selectedTip, err := node.Node.GetSelectedTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockHash, err := daghash.NewHashFromStr(selectedTip.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blueScore := selectedTip.BlueScore
|
||||||
|
|
||||||
if parentHash != nil && (*blockHash != *parentHash ||
|
if parentHash != nil && (*blockHash != *parentHash ||
|
||||||
blockHeight != prevHeight) {
|
blueScore != prevBlueScore) {
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
continue retry
|
continue retry
|
||||||
}
|
}
|
||||||
parentHash, prevHeight = blockHash, blockHeight
|
parentHash, prevBlueScore = blockHash, blueScore
|
||||||
}
|
}
|
||||||
|
|
||||||
blocksMatch = true
|
blocksMatch = true
|
||||||
|
@ -15,13 +15,13 @@ import (
|
|||||||
"github.com/daglabs/btcd/wire"
|
"github.com/daglabs/btcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FutureGetBestBlockHashResult is a future promise to deliver the result of a
|
// FutureGetSelectedTipHashResult is a future promise to deliver the result of a
|
||||||
// GetBestBlockAsync RPC invocation (or an applicable error).
|
// GetSelectedTipAsync RPC invocation (or an applicable error).
|
||||||
type FutureGetBestBlockHashResult chan *response
|
type FutureGetSelectedTipHashResult chan *response
|
||||||
|
|
||||||
// Receive waits for the response promised by the future and returns the hash of
|
// Receive waits for the response promised by the future and returns the hash of
|
||||||
// the best block in the longest block dag.
|
// 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)
|
res, err := receiveFuture(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -36,20 +36,20 @@ func (r FutureGetBestBlockHashResult) Receive() (*daghash.Hash, error) {
|
|||||||
return daghash.NewHashFromStr(txHashStr)
|
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 result of the RPC at some future time by invoking the Receive function on
|
||||||
// the returned instance.
|
// the returned instance.
|
||||||
//
|
//
|
||||||
// See GetBestBlockHash for the blocking version and more details.
|
// See GetSelectedTipHash for the blocking version and more details.
|
||||||
func (c *Client) GetBestBlockHashAsync() FutureGetBestBlockHashResult {
|
func (c *Client) GetSelectedTipHashAsync() FutureGetSelectedTipHashResult {
|
||||||
cmd := btcjson.NewGetBestBlockHashCmd()
|
cmd := btcjson.NewGetSelectedTipHashCmd()
|
||||||
return c.sendCmd(cmd)
|
return c.sendCmd(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBestBlockHash returns the hash of the best block in the longest block
|
// GetSelectedTipHash returns the hash of the selected tip of the
|
||||||
// dag.
|
// Block DAG.
|
||||||
func (c *Client) GetBestBlockHash() (*daghash.Hash, error) {
|
func (c *Client) GetSelectedTipHash() (*daghash.Hash, error) {
|
||||||
return c.GetBestBlockHashAsync().Receive()
|
return c.GetSelectedTipHashAsync().Receive()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FutureGetBlockResult is a future promise to deliver the result of a
|
// FutureGetBlockResult is a future promise to deliver the result of a
|
||||||
|
@ -62,52 +62,87 @@ func (c *Client) DebugLevel(levelSpec string) (string, error) {
|
|||||||
return c.DebugLevelAsync(levelSpec).Receive()
|
return c.DebugLevelAsync(levelSpec).Receive()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FutureGetBestBlockResult is a future promise to deliver the result of a
|
// FutureGetSelectedTipResult is a future promise to deliver the result of a
|
||||||
// GetBestBlockAsync RPC invocation (or an applicable error).
|
// GetSelectedTipAsync RPC invocation (or an applicable error).
|
||||||
type FutureGetBestBlockResult chan *response
|
type FutureGetSelectedTipResult chan *response
|
||||||
|
|
||||||
// Receive waits for the response promised by the future and returns the hash
|
// Receive waits for the response promised by the future and returns the
|
||||||
// and height of the block in the longest (best) chain.
|
// selected tip block.
|
||||||
func (r FutureGetBestBlockResult) Receive() (*daghash.Hash, uint64, error) {
|
func (r FutureGetSelectedTipResult) Receive() (*wire.MsgBlock, error) {
|
||||||
res, err := receiveFuture(r)
|
res, err := receiveFuture(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal result as a getbestblock result object.
|
// Unmarshal result as a string.
|
||||||
var bestBlock btcjson.GetBestBlockResult
|
var blockHex string
|
||||||
err = json.Unmarshal(res, &bestBlock)
|
err = json.Unmarshal(res, &blockHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to hash from string.
|
// Decode the serialized block hex to raw bytes.
|
||||||
hash, err := daghash.NewHashFromStr(bestBlock.Hash)
|
serializedBlock, err := hex.DecodeString(blockHex)
|
||||||
if err != nil {
|
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
|
// result of the RPC at some future time by invoking the Receive function on the
|
||||||
// returned instance.
|
// 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.
|
// NOTE: This is a btcd extension.
|
||||||
func (c *Client) GetBestBlockAsync() FutureGetBestBlockResult {
|
func (c *Client) GetSelectedTipAsync() FutureGetSelectedTipResult {
|
||||||
cmd := btcjson.NewGetBestBlockCmd()
|
cmd := btcjson.NewGetSelectedTipCmd(btcjson.Bool(false), btcjson.Bool(false))
|
||||||
return c.sendCmd(cmd)
|
return c.sendCmd(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBestBlock returns the hash and height of the block in the longest (best)
|
// GetSelectedTip returns the block of the selected DAG tip
|
||||||
// chain.
|
|
||||||
//
|
|
||||||
// NOTE: This is a btcd extension.
|
// NOTE: This is a btcd extension.
|
||||||
func (c *Client) GetBestBlock() (*daghash.Hash, uint64, error) {
|
func (c *Client) GetSelectedTip() (*btcjson.GetBlockVerboseResult, error) {
|
||||||
return c.GetBestBlockAsync().Receive()
|
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
|
// FutureGetCurrentNetResult is a future promise to deliver the result of a
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
@ -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
|
// When the verbose flag is set to false, simply return the serialized block
|
||||||
// as a hex-encoded string.
|
// as a hex-encoded string (verbose flag is on by default).
|
||||||
if c.Verbose != nil && !*c.Verbose {
|
if c.Verbose != nil && !*c.Verbose {
|
||||||
return hex.EncodeToString(blkBytes), nil
|
return hex.EncodeToString(blkBytes), nil
|
||||||
}
|
}
|
||||||
|
46
server/rpc/handle_get_selected_tip.go
Normal file
46
server/rpc/handle_get_selected_tip.go
Normal 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
|
||||||
|
}
|
6
server/rpc/handle_get_selected_tip_hash.go
Normal file
6
server/rpc/handle_get_selected_tip_hash.go
Normal 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
|
||||||
|
}
|
@ -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
|
// If requested and the tx is available in the mempool try to fetch it
|
||||||
// from there, otherwise attempt to fetch from the block database.
|
// from there, otherwise attempt to fetch from the block database.
|
||||||
var bestBlockHash string
|
var selectedTipHash string
|
||||||
var confirmations *uint64
|
var confirmations *uint64
|
||||||
var value uint64
|
var value uint64
|
||||||
var scriptPubKey []byte
|
var scriptPubKey []byte
|
||||||
@ -56,7 +56,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
|
|||||||
return nil, internalRPCError(errStr, "")
|
return nil, internalRPCError(errStr, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
bestBlockHash = s.cfg.DAG.SelectedTipHash().String()
|
selectedTipHash = s.cfg.DAG.SelectedTipHash().String()
|
||||||
value = txOut.Value
|
value = txOut.Value
|
||||||
scriptPubKey = txOut.ScriptPubKey
|
scriptPubKey = txOut.ScriptPubKey
|
||||||
isCoinbase = mtx.IsCoinBase()
|
isCoinbase = mtx.IsCoinBase()
|
||||||
@ -86,7 +86,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
|
|||||||
confirmations = &txConfirmations
|
confirmations = &txConfirmations
|
||||||
}
|
}
|
||||||
|
|
||||||
bestBlockHash = s.cfg.DAG.SelectedTipHash().String()
|
selectedTipHash = s.cfg.DAG.SelectedTipHash().String()
|
||||||
value = entry.Amount()
|
value = entry.Amount()
|
||||||
scriptPubKey = entry.ScriptPubKey()
|
scriptPubKey = entry.ScriptPubKey()
|
||||||
isCoinbase = entry.IsCoinbase()
|
isCoinbase = entry.IsCoinbase()
|
||||||
@ -108,7 +108,7 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
txOutReply := &btcjson.GetTxOutResult{
|
txOutReply := &btcjson.GetTxOutResult{
|
||||||
BestBlock: bestBlockHash,
|
SelectedTip: selectedTipHash,
|
||||||
Confirmations: confirmations,
|
Confirmations: confirmations,
|
||||||
IsInMempool: isInMempool,
|
IsInMempool: isInMempool,
|
||||||
Value: util.Amount(value).ToBTC(),
|
Value: util.Amount(value).ToBTC(),
|
||||||
|
@ -66,8 +66,8 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
|||||||
"decodeScript": handleDecodeScript,
|
"decodeScript": handleDecodeScript,
|
||||||
"generate": handleGenerate,
|
"generate": handleGenerate,
|
||||||
"getAllManualNodesInfo": handleGetAllManualNodesInfo,
|
"getAllManualNodesInfo": handleGetAllManualNodesInfo,
|
||||||
"getBestBlock": handleGetBestBlock,
|
"getSelectedTip": handleGetSelectedTip,
|
||||||
"getBestBlockHash": handleGetBestBlockHash,
|
"getSelectedTipHash": handleGetSelectedTipHash,
|
||||||
"getBlock": handleGetBlock,
|
"getBlock": handleGetBlock,
|
||||||
"getBlocks": handleGetBlocks,
|
"getBlocks": handleGetBlocks,
|
||||||
"getBlockDagInfo": handleGetBlockDAGInfo,
|
"getBlockDagInfo": handleGetBlockDAGInfo,
|
||||||
@ -140,8 +140,8 @@ var rpcLimited = map[string]struct{}{
|
|||||||
"createRawTransaction": {},
|
"createRawTransaction": {},
|
||||||
"decodeRawTransaction": {},
|
"decodeRawTransaction": {},
|
||||||
"decodeScript": {},
|
"decodeScript": {},
|
||||||
"getBestBlock": {},
|
"getSelectedTip": {},
|
||||||
"getBestBlockHash": {},
|
"getSelectedTipHash": {},
|
||||||
"getBlock": {},
|
"getBlock": {},
|
||||||
"getBlocks": {},
|
"getBlocks": {},
|
||||||
"getBlockCount": {},
|
"getBlockCount": {},
|
||||||
|
@ -149,17 +149,22 @@ var helpDescsEnUS = map[string]string{
|
|||||||
"getManualNodeInfo--condition1": "details=true",
|
"getManualNodeInfo--condition1": "details=true",
|
||||||
"getManualNodeInfo--result0": "List of added peers",
|
"getManualNodeInfo--result0": "List of added peers",
|
||||||
|
|
||||||
// GetBestBlockResult help.
|
// GetSelectedTipResult help.
|
||||||
"getBestBlockResult-hash": "Hex-encoded bytes of the best block hash",
|
"getSelectedTipResult-hash": "Hex-encoded bytes of the best block hash",
|
||||||
"getBestBlockResult-height": "Height of the best block",
|
"getSelectedTipResult-height": "Height of the best block",
|
||||||
|
|
||||||
// GetBestBlockCmd help.
|
// GetSelectedTipCmd help.
|
||||||
"getBestBlock--synopsis": "Get block height and hash of best block in the main chain.",
|
"getSelectedTip--synopsis": "Returns information about the selected tip of the blockDAG.",
|
||||||
"getBestBlock--result0": "Get block height and hash of best block in the main chain.",
|
"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.
|
// GetSelectedTipHashCmd help.
|
||||||
"getBestBlockHash--synopsis": "Returns the hash of the of the best (most recent) block in the longest block chain.",
|
"getSelectedTipHash--synopsis": "Returns the hash of the of the selected tip of the blockDAG.",
|
||||||
"getBestBlockHash--result0": "The hex-encoded block hash",
|
"getSelectedTipHash--result0": "The hex-encoded block hash",
|
||||||
|
|
||||||
// GetBlockCmd help.
|
// GetBlockCmd help.
|
||||||
"getBlock--synopsis": "Returns information about a block given its hash.",
|
"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",
|
"getSubnetworkResult-gasLimit": "The gas limit of the subnetwork",
|
||||||
|
|
||||||
// GetTxOutResult help.
|
// 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-confirmations": "The number of confirmations (Will be 'null' if txindex is not disabled)",
|
||||||
"getTxOutResult-isInMempool": "Whether the transaction is in the mempool",
|
"getTxOutResult-isInMempool": "Whether the transaction is in the mempool",
|
||||||
"getTxOutResult-value": "The transaction amount in BTC",
|
"getTxOutResult-value": "The transaction amount in BTC",
|
||||||
@ -675,8 +680,8 @@ var rpcResultTypes = map[string][]interface{}{
|
|||||||
"decodeScript": {(*btcjson.DecodeScriptResult)(nil)},
|
"decodeScript": {(*btcjson.DecodeScriptResult)(nil)},
|
||||||
"generate": {(*[]string)(nil)},
|
"generate": {(*[]string)(nil)},
|
||||||
"getAllManualNodesInfo": {(*[]string)(nil), (*[]btcjson.GetManualNodeInfoResult)(nil)},
|
"getAllManualNodesInfo": {(*[]string)(nil), (*[]btcjson.GetManualNodeInfoResult)(nil)},
|
||||||
"getBestBlock": {(*btcjson.GetBestBlockResult)(nil)},
|
"getSelectedTip": {(*btcjson.GetBlockVerboseResult)(nil)},
|
||||||
"getBestBlockHash": {(*string)(nil)},
|
"getSelectedTipHash": {(*string)(nil)},
|
||||||
"getBlock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)},
|
"getBlock": {(*string)(nil), (*btcjson.GetBlockVerboseResult)(nil)},
|
||||||
"getBlocks": {(*btcjson.GetBlocksResult)(nil)},
|
"getBlocks": {(*btcjson.GetBlocksResult)(nil)},
|
||||||
"getBlockCount": {(*int64)(nil)},
|
"getBlockCount": {(*int64)(nil)},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user