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 }