6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/config"
9 "github.com/vapor/event"
10 "github.com/vapor/protocol/bc"
11 "github.com/vapor/protocol/bc/types"
12 "github.com/vapor/protocol/state"
15 const maxProcessBlockChSize = 1024
17 // Chain provides functions for working with the Bytom block chain.
19 index *state.BlockIndex
20 orphanManage *OrphanManage
24 processBlockCh chan *processBlockMsg
27 bestNode *state.BlockNode
28 bestIrreversibleNode *state.BlockNode
31 // NewChain returns a new Chain using store as the underlying storage.
32 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
34 orphanManage: NewOrphanManage(),
37 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
39 c.cond.L = new(sync.Mutex)
41 c.bbft = newBbft(store, nil, c.orphanManage, eventDispatcher)
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.bestIrreversibleNode = c.index.GetNode(storeStatus.IrreversibleHash)
57 c.index.SetMainChain(c.bestNode)
58 c.bbft.SetBlockIndex(c.index)
63 func (c *Chain) initChainStatus() error {
64 genesisBlock := config.GenesisBlock()
65 txStatus := bc.NewTransactionStatus()
66 for i := range genesisBlock.Transactions {
67 if err := txStatus.SetStatus(i, false); err != nil {
72 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
76 utxoView := state.NewUtxoViewpoint()
77 bcBlock := types.MapBlock(genesisBlock)
78 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
82 voteResultMap := make(map[uint64]*state.VoteResult)
83 if err := c.bbft.ApplyBlock(voteResultMap, genesisBlock); err != nil {
87 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
92 return c.store.SaveChainStatus(node, node, utxoView, voteResultMap)
95 // BestBlockHeight returns the current height of the blockchain.
96 func (c *Chain) BestBlockHeight() uint64 {
98 defer c.cond.L.Unlock()
99 return c.bestNode.Height
102 // BestBlockHash return the hash of the chain tail block
103 func (c *Chain) BestBlockHash() *bc.Hash {
105 defer c.cond.L.Unlock()
106 return &c.bestNode.Hash
109 // BestBlockHeader returns the chain tail block
110 func (c *Chain) BestBlockHeader() *types.BlockHeader {
111 node := c.index.BestNode()
112 return node.BlockHeader()
115 // InMainChain checks wheather a block is in the main chain
116 func (c *Chain) InMainChain(hash bc.Hash) bool {
117 return c.index.InMainchain(hash)
120 // This function must be called with mu lock in above level
121 func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error {
122 if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteMap); err != nil {
127 defer c.cond.L.Unlock()
129 c.index.SetMainChain(node)
131 c.bestIrreversibleNode = irreversibleNode
133 log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
138 // BlockWaiter returns a channel that waits for the block at the given height.
139 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
140 ch := make(chan struct{}, 1)
143 defer c.cond.L.Unlock()
144 for c.bestNode.Height < height {
153 // GetTxPool return chain txpool.
154 func (c *Chain) GetTxPool() *TxPool {
158 // GetBBFT return chain bbft
159 func (c *Chain) GetBBFT() *bbft {