6 "github.com/golang/groupcache/lru"
7 log "github.com/sirupsen/logrus"
9 "github.com/vapor/config"
10 "github.com/vapor/event"
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
26 consensusNodeManager *consensusNodeManager
27 signatureCache *lru.Cache
28 eventDispatcher *event.Dispatcher
31 bestNode *state.BlockNode
32 bestIrreversibleNode *state.BlockNode
35 // NewChain returns a new Chain using store as the underlying storage.
36 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
38 orphanManage: NewOrphanManage(),
41 signatureCache: lru.New(maxSignatureCacheSize),
42 consensusNodeManager: newConsensusNodeManager(store, nil),
43 eventDispatcher: eventDispatcher,
44 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
46 c.cond.L = new(sync.Mutex)
48 storeStatus := store.GetStoreStatus()
49 if storeStatus == nil {
50 if err := c.initChainStatus(); err != nil {
53 storeStatus = store.GetStoreStatus()
57 if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
61 c.bestNode = c.index.GetNode(storeStatus.Hash)
62 c.bestIrreversibleNode = c.index.GetNode(storeStatus.IrreversibleHash)
63 c.index.SetMainChain(c.bestNode)
64 c.consensusNodeManager.blockIndex = c.index
69 func (c *Chain) initChainStatus() error {
70 genesisBlock := config.GenesisBlock()
71 txStatus := bc.NewTransactionStatus()
72 for i := range genesisBlock.Transactions {
73 if err := txStatus.SetStatus(i, false); err != nil {
78 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
82 utxoView := state.NewUtxoViewpoint()
83 bcBlock := types.MapBlock(genesisBlock)
84 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
88 voteResults := []*state.VoteResult{&state.VoteResult{
90 NumOfVote: map[string]uint64{},
91 BlockHash: genesisBlock.Hash(),
94 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
99 return c.store.SaveChainStatus(node, node, utxoView, voteResults)
102 // BestBlockHeight returns the current height of the blockchain.
103 func (c *Chain) BestBlockHeight() uint64 {
105 defer c.cond.L.Unlock()
106 return c.bestNode.Height
109 // BestBlockHash return the hash of the chain tail block
110 func (c *Chain) BestBlockHash() *bc.Hash {
112 defer c.cond.L.Unlock()
113 return &c.bestNode.Hash
116 // BestBlockHeader returns the chain tail block
117 func (c *Chain) BestBlockHeader() *types.BlockHeader {
118 node := c.index.BestNode()
119 return node.BlockHeader()
122 // InMainChain checks wheather a block is in the main chain
123 func (c *Chain) InMainChain(hash bc.Hash) bool {
124 return c.index.InMainchain(hash)
127 // This function must be called with mu lock in above level
128 func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteResults []*state.VoteResult) error {
129 if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteResults); err != nil {
134 defer c.cond.L.Unlock()
136 c.index.SetMainChain(node)
138 c.bestIrreversibleNode = irreversibleNode
140 log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
145 // BlockWaiter returns a channel that waits for the block at the given height.
146 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
147 ch := make(chan struct{}, 1)
150 defer c.cond.L.Unlock()
151 for c.bestNode.Height < height {
160 // GetTxPool return chain txpool.
161 func (c *Chain) GetTxPool() *TxPool {