diff --git a/blockdag/dag.go b/blockdag/dag.go index 5b944cfc5..86d73a398 100644 --- a/blockdag/dag.go +++ b/blockdag/dag.go @@ -1563,6 +1563,21 @@ func (dag *BlockDAG) ChildHashesByHash(hash *daghash.Hash) ([]*daghash.Hash, err return node.children.hashes(), nil } +// SelectedParentHash returns the selected parent hash of the block with the given hash in the +// DAG. +// +// This function is safe for concurrent access. +func (dag *BlockDAG) SelectedParentHash(blockHash *daghash.Hash) (*daghash.Hash, error) { + node := dag.index.LookupNode(blockHash) + if node == nil { + str := fmt.Sprintf("block %s is not in the DAG", blockHash) + return nil, errNotInDAG(str) + + } + + return node.selectedParent.hash, nil +} + // ChainHeightToHashRange returns a range of block hashes for the given start chain // height and end hash, inclusive on both ends. The hashes are for all blocks that // are ancestors of endHash with height greater than or equal to startChainHeight. diff --git a/rpcmodel/rpc_results.go b/rpcmodel/rpc_results.go index 5253f3a9c..cb6e4c105 100644 --- a/rpcmodel/rpc_results.go +++ b/rpcmodel/rpc_results.go @@ -22,6 +22,7 @@ type GetBlockHeaderVerboseResult struct { Bits string `json:"bits"` Difficulty float64 `json:"difficulty"` ParentHashes []string `json:"parentHashes,omitempty"` + SelectedParentHash string `json:"selectedParentHash"` NextHashes []string `json:"nextHashes,omitempty"` } @@ -47,6 +48,7 @@ type GetBlockVerboseResult struct { Bits string `json:"bits"` Difficulty float64 `json:"difficulty"` ParentHashes []string `json:"parentHashes"` + SelectedParentHash string `json:"selectedParentHash"` NextHashes []string `json:"nextHashes,omitempty"` } diff --git a/server/rpc/common.go b/server/rpc/common.go index 71f27ac09..3b871c278 100644 --- a/server/rpc/common.go +++ b/server/rpc/common.go @@ -240,6 +240,12 @@ func buildGetBlockVerboseResult(s *Server, block *util.Block, isVerboseTx bool) return nil, internalRPCError(err.Error(), context) } + selectedParentHash, err := s.cfg.DAG.SelectedParentHash(hash) + if err != nil { + context := "Could not get block selected parent" + return nil, internalRPCError(err.Error(), context) + } + isChainBlock := s.cfg.DAG.IsInSelectedParentChain(hash) result := &rpcmodel.GetBlockVerboseResult{ @@ -250,6 +256,7 @@ func buildGetBlockVerboseResult(s *Server, block *util.Block, isVerboseTx bool) AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(), UTXOCommitment: blockHeader.UTXOCommitment.String(), ParentHashes: daghash.Strings(blockHeader.ParentHashes), + SelectedParentHash: selectedParentHash.String(), Nonce: blockHeader.Nonce, Time: blockHeader.Timestamp.Unix(), Confirmations: blockConfirmations, diff --git a/server/rpc/handle_get_block_header.go b/server/rpc/handle_get_block_header.go index dd0d5dce5..0332a0dd2 100644 --- a/server/rpc/handle_get_block_header.go +++ b/server/rpc/handle_get_block_header.go @@ -64,6 +64,12 @@ func handleGetBlockHeader(s *Server, cmd interface{}, closeChan <-chan struct{}) return nil, internalRPCError(err.Error(), context) } + selectedParentHash, err := s.cfg.DAG.SelectedParentHash(hash) + if err != nil { + context := "Could not get block selected parent" + return nil, internalRPCError(err.Error(), context) + } + params := s.cfg.DAGParams blockHeaderReply := rpcmodel.GetBlockHeaderVerboseResult{ Hash: c.Hash, @@ -75,7 +81,8 @@ func handleGetBlockHeader(s *Server, cmd interface{}, closeChan <-chan struct{}) AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(), NextHashes: nextHashStrings, ParentHashes: daghash.Strings(blockHeader.ParentHashes), - Nonce: uint64(blockHeader.Nonce), + SelectedParentHash: selectedParentHash.String(), + Nonce: blockHeader.Nonce, Time: blockHeader.Timestamp.Unix(), Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: getDifficultyRatio(blockHeader.Bits, params), diff --git a/server/rpc/rpcserverhelp.go b/server/rpc/rpcserverhelp.go index 22ef0f646..fd74166ca 100644 --- a/server/rpc/rpcserverhelp.go +++ b/server/rpc/rpcserverhelp.go @@ -272,6 +272,7 @@ var helpDescsEnUS = map[string]string{ "getBlockVerboseResult-bits": "The bits which represent the block difficulty", "getBlockVerboseResult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", "getBlockVerboseResult-parentHashes": "The hashes of the parent blocks", + "getBlockVerboseResult-selectedParentHash": "The selected parent hash", "getBlockVerboseResult-nextHashes": "The hashes of the next blocks (only if there are any)", // GetBlockCountCmd help. @@ -299,6 +300,7 @@ var helpDescsEnUS = map[string]string{ "getBlockHeaderVerboseResult-bits": "The bits which represent the block difficulty", "getBlockHeaderVerboseResult-difficulty": "The proof-of-work difficulty as a multiple of the minimum difficulty", "getBlockHeaderVerboseResult-parentHashes": "The hashes of the parent blocks", + "getBlockHeaderVerboseResult-selectedParentHash": "The selected parent hash", "getBlockHeaderVerboseResult-nextHashes": "The hashes of the next blocks (only if there are any)", // TemplateRequest help.