github.com/decred/dcrd/blockchain@v1.2.1/chainquery.go (about)

     1  // Copyright (c) 2018 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package blockchain
     6  
     7  import (
     8  	"bytes"
     9  	"sort"
    10  
    11  	"github.com/decred/dcrd/chaincfg/chainhash"
    12  )
    13  
    14  // nodeHeightSorter implements sort.Interface to allow a slice of nodes to
    15  // be sorted by height in ascending order.
    16  type nodeHeightSorter []*blockNode
    17  
    18  // Len returns the number of nodes in the slice.  It is part of the
    19  // sort.Interface implementation.
    20  func (s nodeHeightSorter) Len() int {
    21  	return len(s)
    22  }
    23  
    24  // Swap swaps the nodes at the passed indices.  It is part of the
    25  // sort.Interface implementation.
    26  func (s nodeHeightSorter) Swap(i, j int) {
    27  	s[i], s[j] = s[j], s[i]
    28  }
    29  
    30  // Less returns whether the node with index i should sort before the node with
    31  // index j.  It is part of the sort.Interface implementation.
    32  func (s nodeHeightSorter) Less(i, j int) bool {
    33  	// To ensure stable order when the heights are the same, fall back to
    34  	// sorting based on hash.
    35  	if s[i].height == s[j].height {
    36  		return bytes.Compare(s[i].hash[:], s[j].hash[:]) < 0
    37  	}
    38  	return s[i].height < s[j].height
    39  }
    40  
    41  // ChainTipInfo models information about a chain tip.
    42  type ChainTipInfo struct {
    43  	// Height specifies the block height of the chain tip.
    44  	Height int64
    45  
    46  	// Hash specifies the block hash of the chain tip.
    47  	Hash chainhash.Hash
    48  
    49  	// BranchLen specifies the length of the branch that connects the chain tip
    50  	// to the main chain.  It will be zero for the main chain tip.
    51  	BranchLen int64
    52  
    53  	// Status specifies the validation status of chain formed by the chain tip.
    54  	//
    55  	// active:
    56  	//   The current best chain tip.
    57  	//
    58  	// invalid:
    59  	//   The block or one of its ancestors is invalid.
    60  	//
    61  	// headers-only:
    62  	//   The block or one of its ancestors does not have the full block data
    63  	//   available which also means the block can't be validated or connected.
    64  	//
    65  	// valid-fork:
    66  	//   The block is fully validated which implies it was probably part of the
    67  	//   main chain at one point and was reorganized.
    68  	//
    69  	// valid-headers:
    70  	//   The full block data is available and the header is valid, but the block
    71  	//   was never validated which implies it was probably never part of the
    72  	//   main chain.
    73  	Status string
    74  }
    75  
    76  // ChainTips returns information, in JSON-RPC format, about all of the currently
    77  // known chain tips in the block index.
    78  func (b *BlockChain) ChainTips() []ChainTipInfo {
    79  	b.index.RLock()
    80  	var chainTips []*blockNode
    81  	for _, nodes := range b.index.chainTips {
    82  		chainTips = append(chainTips, nodes...)
    83  	}
    84  	b.index.RUnlock()
    85  
    86  	// Generate the results sorted by descending height.
    87  	sort.Sort(sort.Reverse(nodeHeightSorter(chainTips)))
    88  	results := make([]ChainTipInfo, len(chainTips))
    89  	bestTip := b.bestChain.Tip()
    90  	for i, tip := range chainTips {
    91  		result := &results[i]
    92  		result.Height = tip.height
    93  		result.Hash = tip.hash
    94  		result.BranchLen = tip.height - b.bestChain.FindFork(tip).height
    95  
    96  		// Determine the status of the chain tip.
    97  		//
    98  		// active:
    99  		//   The current best chain tip.
   100  		//
   101  		// invalid:
   102  		//   The block or one of its ancestors is invalid.
   103  		//
   104  		// headers-only:
   105  		//   The block or one of its ancestors does not have the full block data
   106  		//   available which also means the block can't be validated or
   107  		//   connected.
   108  		//
   109  		// valid-fork:
   110  		//   The block is fully validated which implies it was probably part of
   111  		//   main chain at one point and was reorganized.
   112  		//
   113  		// valid-headers:
   114  		//   The full block data is available and the header is valid, but the
   115  		//   block was never validated which implies it was probably never part
   116  		//   of the main chain.
   117  		tipStatus := b.index.NodeStatus(tip)
   118  		if tip == bestTip {
   119  			result.Status = "active"
   120  		} else if tipStatus.KnownInvalid() {
   121  			result.Status = "invalid"
   122  		} else if !tipStatus.HaveData() {
   123  			result.Status = "headers-only"
   124  		} else if tipStatus.KnownValid() {
   125  			result.Status = "valid-fork"
   126  		} else {
   127  			result.Status = "valid-headers"
   128  		}
   129  	}
   130  	return results
   131  }