6 log "github.com/sirupsen/logrus"
8 "github.com/bytom/config"
9 "github.com/bytom/errors"
10 "github.com/bytom/protocol/bc"
11 "github.com/bytom/protocol/bc/types"
12 "github.com/bytom/protocol/state"
15 const maxProcessBlockChSize = 1024
17 // ErrTheDistantFuture is returned when waiting for a blockheight too far in
18 // excess of the tip of the blockchain.
19 var ErrTheDistantFuture = errors.New("block height too far in future")
21 // Chain provides functions for working with the Bytom block chain.
23 index *state.BlockIndex
24 orphanManage *OrphanManage
27 processBlockCh chan *processBlockMsg
30 bestNode *state.BlockNode
33 // NewChain returns a new Chain using store as the underlying storage.
34 func NewChain(store Store, txPool *TxPool) (*Chain, error) {
36 orphanManage: NewOrphanManage(),
39 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
41 c.cond.L = new(sync.Mutex)
43 storeStatus := store.GetStoreStatus()
44 if storeStatus == nil {
45 if err := c.initChainStatus(); err != nil {
48 storeStatus = store.GetStoreStatus()
52 if c.index, err = store.LoadBlockIndex(); err != nil {
56 c.bestNode = c.index.GetNode(storeStatus.Hash)
57 c.index.SetMainChain(c.bestNode)
62 func (c *Chain) initChainStatus() error {
63 genesisBlock := config.GenesisBlock()
64 txStatus := bc.NewTransactionStatus()
65 for i := range genesisBlock.Transactions {
66 txStatus.SetStatus(i, false)
69 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
73 utxoView := state.NewUtxoViewpoint()
74 bcBlock := types.MapBlock(genesisBlock)
75 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
79 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
83 return c.store.SaveChainStatus(node, utxoView)
86 // BestBlockHeight returns the current height of the blockchain.
87 func (c *Chain) BestBlockHeight() uint64 {
89 defer c.cond.L.Unlock()
90 return c.bestNode.Height
93 // BestBlockHash return the hash of the chain tail block
94 func (c *Chain) BestBlockHash() *bc.Hash {
96 defer c.cond.L.Unlock()
97 return &c.bestNode.Hash
100 // BestBlockHeader returns the chain tail block
101 func (c *Chain) BestBlockHeader() *types.BlockHeader {
102 node := c.index.BestNode()
103 return node.BlockHeader()
106 // InMainChain checks wheather a block is in the main chain
107 func (c *Chain) InMainChain(hash bc.Hash) bool {
108 return c.index.InMainchain(hash)
111 // CalcNextSeed return the seed for the given block
112 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
113 node := c.index.GetNode(preBlock)
115 return nil, errors.New("can't find preblock in the blockindex")
117 return node.CalcNextSeed(), nil
120 // CalcNextBits return the seed for the given block
121 func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) {
122 node := c.index.GetNode(preBlock)
124 return 0, errors.New("can't find preblock in the blockindex")
126 return node.CalcNextBits(), nil
129 // This function must be called with mu lock in above level
130 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
131 if err := c.store.SaveChainStatus(node, view); err != nil {
136 defer c.cond.L.Unlock()
138 c.index.SetMainChain(node)
141 log.WithFields(log.Fields{"height": c.bestNode.Height, "hash": c.bestNode.Hash}).Debug("chain best status has been update")
146 // BlockWaiter returns a channel that waits for the block at the given height.
147 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
148 ch := make(chan struct{}, 1)
151 defer c.cond.L.Unlock()
152 for c.bestNode.Height < height {
161 // GetTxPool return chain txpool.
162 func (c *Chain) GetTxPool() *TxPool {