6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/common"
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 orphanManage *OrphanManage
23 processBlockCh chan *processBlockMsg
25 signatureCache *common.Cache
26 eventDispatcher *event.Dispatcher
29 bestBlockHeader *types.BlockHeader
30 bestIrrBlockHeader *types.BlockHeader
33 // NewChain returns a new Chain using store as the underlying storage.
34 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
36 orphanManage: NewOrphanManage(),
39 signatureCache: common.NewCache(maxSignatureCacheSize),
40 eventDispatcher: eventDispatcher,
41 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
43 c.cond.L = new(sync.Mutex)
45 storeStatus := store.GetStoreStatus()
46 if storeStatus == nil {
47 if err := c.initChainStatus(); err != nil {
50 storeStatus = store.GetStoreStatus()
54 c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
59 c.bestIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
67 func (c *Chain) initChainStatus() error {
68 genesisBlock := config.GenesisBlock()
69 txStatus := bc.NewTransactionStatus()
70 for i := range genesisBlock.Transactions {
71 if err := txStatus.SetStatus(i, false); err != nil {
76 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
80 utxoView := state.NewUtxoViewpoint()
81 bcBlock := types.MapBlock(genesisBlock)
82 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
86 consensusResults := []*state.ConsensusResult{&state.ConsensusResult{
88 NumOfVote: make(map[string]uint64),
89 CoinbaseReward: make(map[string]uint64),
90 BlockHash: genesisBlock.Hash(),
94 genesisBlockHeader := &genesisBlock.BlockHeader
95 return c.store.SaveChainStatus(genesisBlockHeader, genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, consensusResults)
98 // BestBlockHeight returns the current height of the blockchain.
99 func (c *Chain) BestBlockHeight() uint64 {
101 defer c.cond.L.Unlock()
102 return c.bestBlockHeader.Height
105 // BestBlockHash return the hash of the chain tail block
106 func (c *Chain) BestBlockHash() *bc.Hash {
108 defer c.cond.L.Unlock()
109 bestHash := c.bestBlockHeader.Hash()
113 // BestIrreversibleHeader returns the chain best irreversible block header
114 func (c *Chain) BestIrreversibleHeader() *types.BlockHeader {
116 defer c.cond.L.Unlock()
117 return c.bestIrrBlockHeader
120 // BestBlockHeader returns the chain best block header
121 func (c *Chain) BestBlockHeader() *types.BlockHeader {
123 defer c.cond.L.Unlock()
124 return c.bestBlockHeader
127 // InMainChain checks wheather a block is in the main chain
128 func (c *Chain) InMainChain(hash bc.Hash) bool {
129 blockHeader, err := c.store.GetBlockHeader(&hash)
134 blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
136 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
139 return *blockHash == hash
142 // This function must be called with mu lock in above level
143 func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
144 if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
148 c.bestBlockHeader = blockHeader
149 c.bestIrrBlockHeader = irrBlockHeader
151 blockHash := blockHeader.Hash()
152 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
157 // BlockWaiter returns a channel that waits for the block at the given height.
158 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
159 ch := make(chan struct{}, 1)
162 defer c.cond.L.Unlock()
163 for c.bestBlockHeader.Height < height {
172 // GetTxPool return chain txpool.
173 func (c *Chain) GetTxPool() *TxPool {