6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/config"
9 engine "github.com/vapor/consensus/consensus"
10 "github.com/vapor/errors"
11 "github.com/vapor/protocol/bc"
12 "github.com/vapor/protocol/bc/types"
13 "github.com/vapor/protocol/state"
16 const maxProcessBlockChSize = 1024
18 // Chain provides functions for working with the Bytom block chain.
20 index *state.BlockIndex
21 orphanManage *OrphanManage
24 processBlockCh chan *processBlockMsg
27 bestNode *state.BlockNode
31 // NewChain returns a new Chain using store as the underlying storage.
32 func NewChain(store Store, txPool *TxPool, engine engine.Engine) (*Chain, error) {
34 orphanManage: NewOrphanManage(),
37 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
40 c.cond.L = new(sync.Mutex)
42 storeStatus := store.GetStoreStatus()
43 if storeStatus == nil {
44 if err := c.initChainStatus(); err != nil {
47 storeStatus = store.GetStoreStatus()
51 if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
55 c.bestNode = c.index.GetNode(storeStatus.Hash)
56 c.index.SetMainChain(c.bestNode)
61 func (c *Chain) SetConsensusEngine(engine engine.Engine) {
65 func (c *Chain) initChainStatus() error {
66 genesisBlock := config.GenesisBlock()
67 txStatus := bc.NewTransactionStatus()
68 for i := range genesisBlock.Transactions {
69 if err := txStatus.SetStatus(i, false); err != nil {
74 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
78 utxoView := state.NewUtxoViewpoint()
79 bcBlock := types.MapBlock(genesisBlock)
80 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
84 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
88 return c.store.SaveChainStatus(node, utxoView)
91 // BestBlockHeight returns the current height of the blockchain.
92 func (c *Chain) BestBlockHeight() uint64 {
94 defer c.cond.L.Unlock()
95 return c.bestNode.Height
98 // BestBlockHash return the hash of the chain tail block
99 func (c *Chain) BestBlockHash() *bc.Hash {
101 defer c.cond.L.Unlock()
102 return &c.bestNode.Hash
105 // BestBlockHeader returns the chain tail block
106 func (c *Chain) BestBlockHeader() *types.BlockHeader {
107 node := c.index.BestNode()
108 return node.BlockHeader()
111 // InMainChain checks wheather a block is in the main chain
112 func (c *Chain) InMainChain(hash bc.Hash) bool {
113 return c.index.InMainchain(hash)
116 // CalcNextSeed return the seed for the given block
117 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
118 node := c.index.GetNode(preBlock)
120 return nil, errors.New("can't find preblock in the blockindex")
122 return node.CalcNextSeed(), nil
125 // CalcNextBits return the seed for the given block
126 func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) {
127 node := c.index.GetNode(preBlock)
129 return 0, errors.New("can't find preblock in the blockindex")
131 return node.CalcNextBits(), nil
134 // This function must be called with mu lock in above level
135 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
136 if err := c.store.SaveChainStatus(node, view); err != nil {
141 defer c.cond.L.Unlock()
143 c.index.SetMainChain(node)
146 log.WithFields(log.Fields{"height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
151 // BlockWaiter returns a channel that waits for the block at the given height.
152 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
153 ch := make(chan struct{}, 1)
156 defer c.cond.L.Unlock()
157 for c.bestNode.Height < height {
166 // GetTxPool return chain txpool.
167 func (c *Chain) GetTxPool() *TxPool {