6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/config"
9 "github.com/vapor/protocol/bc"
10 "github.com/vapor/protocol/bc/types"
11 "github.com/vapor/protocol/state"
14 const maxProcessBlockChSize = 1024
16 // Chain provides functions for working with the Bytom block chain.
18 index *state.BlockIndex
19 orphanManage *OrphanManage
22 processBlockCh chan *processBlockMsg
25 bestNode *state.BlockNode
28 // NewChain returns a new Chain using store as the underlying storage.
29 func NewChain(store Store, txPool *TxPool) (*Chain, error) {
31 orphanManage: NewOrphanManage(),
34 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
36 c.cond.L = new(sync.Mutex)
38 storeStatus := store.GetStoreStatus()
39 if storeStatus == nil {
40 if err := c.initChainStatus(); err != nil {
43 storeStatus = store.GetStoreStatus()
47 if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
51 c.bestNode = c.index.GetNode(storeStatus.Hash)
52 c.index.SetMainChain(c.bestNode)
57 func (c *Chain) initChainStatus() error {
58 genesisBlock := config.GenesisBlock()
59 txStatus := bc.NewTransactionStatus()
60 for i := range genesisBlock.Transactions {
61 if err := txStatus.SetStatus(i, false); err != nil {
66 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
70 utxoView := state.NewUtxoViewpoint()
71 bcBlock := types.MapBlock(genesisBlock)
72 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
76 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
80 return c.store.SaveChainStatus(node, utxoView)
83 // BestBlockHeight returns the current height of the blockchain.
84 func (c *Chain) BestBlockHeight() uint64 {
86 defer c.cond.L.Unlock()
87 return c.bestNode.Height
90 // BestBlockHash return the hash of the chain tail block
91 func (c *Chain) BestBlockHash() *bc.Hash {
93 defer c.cond.L.Unlock()
94 return &c.bestNode.Hash
97 // BestBlockHeader returns the chain tail block
98 func (c *Chain) BestBlockHeader() *types.BlockHeader {
99 node := c.index.BestNode()
100 return node.BlockHeader()
103 // InMainChain checks wheather a block is in the main chain
104 func (c *Chain) InMainChain(hash bc.Hash) bool {
105 return c.index.InMainchain(hash)
108 // This function must be called with mu lock in above level
109 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
110 if err := c.store.SaveChainStatus(node, view); err != nil {
115 defer c.cond.L.Unlock()
117 c.index.SetMainChain(node)
120 log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
125 // BlockWaiter returns a channel that waits for the block at the given height.
126 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
127 ch := make(chan struct{}, 1)
130 defer c.cond.L.Unlock()
131 for c.bestNode.Height < height {
140 // GetTxPool return chain txpool.
141 func (c *Chain) GetTxPool() *TxPool {