9 "github.com/bytom/common"
10 "github.com/bytom/consensus"
11 "github.com/bytom/consensus/difficulty"
12 "github.com/bytom/protocol/bc"
13 "github.com/bytom/protocol/bc/types"
14 "github.com/bytom/testutil"
17 // approxNodesPerDay is an approximation of the number of new blocks there are
18 // in a day on average.
19 const approxNodesPerDay = 24 * 24
21 // BlockNode represents a block within the block chain and is primarily used to
22 // aid in selecting the best chain to be the main chain.
23 type BlockNode struct {
24 Parent *BlockNode // parent is the parent block for this node.
25 Hash bc.Hash // hash of the block.
26 Seed *bc.Hash // seed hash of the block
27 WorkSum *big.Int // total amount of work in the chain up to
34 TransactionsMerkleRoot bc.Hash
35 TransactionStatusHash bc.Hash
38 func NewBlockNode(bh *types.BlockHeader, parent *BlockNode) (*BlockNode, error) {
39 if bh.Height != 0 && parent == nil {
40 return nil, errors.New("parent node can not be nil")
46 WorkSum: difficulty.CalcWork(bh.Bits),
49 Timestamp: bh.Timestamp,
52 TransactionsMerkleRoot: bh.TransactionsMerkleRoot,
53 TransactionStatusHash: bh.TransactionStatusHash,
57 node.Seed = consensus.InitialSeed
59 node.Seed = parent.CalcNextSeed()
60 node.WorkSum = node.WorkSum.Add(parent.WorkSum, node.WorkSum)
65 // blockHeader convert a node to the header struct
66 func (node *BlockNode) BlockHeader() *types.BlockHeader {
67 previousBlockHash := bc.Hash{}
68 if node.Parent != nil {
69 previousBlockHash = node.Parent.Hash
71 return &types.BlockHeader{
72 Version: node.Version,
74 PreviousBlockHash: previousBlockHash,
75 Timestamp: node.Timestamp,
78 BlockCommitment: types.BlockCommitment{
79 TransactionsMerkleRoot: node.TransactionsMerkleRoot,
80 TransactionStatusHash: node.TransactionStatusHash,
85 func (node *BlockNode) CalcPastMedianTime() uint64 {
86 timestamps := []uint64{}
88 for i := 0; i < consensus.MedianTimeBlocks && iterNode != nil; i++ {
89 timestamps = append(timestamps, iterNode.Timestamp)
90 iterNode = iterNode.Parent
93 sort.Sort(common.TimeSorter(timestamps))
94 return timestamps[len(timestamps)/2]
97 // CalcNextBits calculate the bits for next block
98 func (node *BlockNode) CalcNextBits() uint64 {
99 if node.Height%consensus.BlocksPerRetarget != 0 || node.Height == 0 {
103 compareNode := node.Parent
104 for compareNode.Height%consensus.BlocksPerRetarget != 0 {
105 compareNode = compareNode.Parent
107 return difficulty.CalcNextRequiredDifficulty(node.BlockHeader(), compareNode.BlockHeader())
110 // CalcNextSeed calculate the seed for next block
111 func (node *BlockNode) CalcNextSeed() *bc.Hash {
112 if node.Height == 0 {
113 return consensus.InitialSeed
115 if node.Height%consensus.SeedPerRetarget == 0 {
121 // BlockIndex is the struct for help chain trace block chain as tree
122 type BlockIndex struct {
125 index map[bc.Hash]*BlockNode
126 mainChain []*BlockNode
129 // NewBlockIndex will create a empty BlockIndex
130 func NewBlockIndex() *BlockIndex {
132 index: make(map[bc.Hash]*BlockNode),
133 mainChain: make([]*BlockNode, 0, approxNodesPerDay),
137 func NewBlockIndexWithInitData(index map[bc.Hash]*BlockNode, mainChain []*BlockNode) *BlockIndex {
138 return &BlockIndex{index: index, mainChain: mainChain}
141 // AddNode will add node to the index map
142 func (bi *BlockIndex) AddNode(node *BlockNode) {
144 bi.index[node.Hash] = node
148 func (bi *BlockIndex) BestNode() *BlockNode {
151 return bi.mainChain[len(bi.mainChain)-1]
154 // BlockExist check does the block existed in blockIndex
155 func (bi *BlockIndex) BlockExist(hash *bc.Hash) bool {
157 _, ok := bi.index[*hash]
162 func (bi *BlockIndex) Equals(bi1 *BlockIndex) bool {
166 return testutil.DeepEqual(bi.index, bi1.index) && testutil.DeepEqual(bi.mainChain, bi1.mainChain)
169 // GetNode will search node from the index map
170 func (bi *BlockIndex) GetNode(hash *bc.Hash) *BlockNode {
173 return bi.index[*hash]
176 // TODO: THIS FUNCTION MIGHT BE DELETED
177 func (bi *BlockIndex) InMainchain(hash bc.Hash) bool {
181 node, ok := bi.index[hash]
185 return bi.nodeByHeight(node.Height) == node
188 // NodeByHeight returns the block node at the specified height.
189 func (bi *BlockIndex) NodeByHeight(height uint64) *BlockNode {
192 return bi.nodeByHeight(height)
195 // SetMainChain will set the the mainChain array
196 func (bi *BlockIndex) SetMainChain(node *BlockNode) {
200 needed := node.Height + 1
201 if uint64(cap(bi.mainChain)) < needed {
202 nodes := make([]*BlockNode, needed, needed+approxNodesPerDay)
203 copy(nodes, bi.mainChain)
206 i := uint64(len(bi.mainChain))
207 bi.mainChain = bi.mainChain[0:needed]
208 for ; i < needed; i++ {
209 bi.mainChain[i] = nil
213 for node != nil && bi.mainChain[node.Height] != node {
214 bi.mainChain[node.Height] = node
219 func (bi *BlockIndex) nodeByHeight(height uint64) *BlockNode {
220 if height >= uint64(len(bi.mainChain)) {
223 return bi.mainChain[height]