OSDN Git Service

modify variable name
[bytom/vapor.git] / protocol / protocol.go
1 package protocol
2
3 import (
4         "sync"
5
6         log "github.com/sirupsen/logrus"
7
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"
14 )
15
16 const maxProcessBlockChSize = 1024
17
18 // Chain provides functions for working with the Bytom block chain.
19 type Chain struct {
20         orphanManage   *OrphanManage
21         txPool         *TxPool
22         store          Store
23         processBlockCh chan *processBlockMsg
24
25         signatureCache  *common.Cache
26         eventDispatcher *event.Dispatcher
27
28         cond               sync.Cond
29         bestBlockHeader    *types.BlockHeader
30         bestIrrBlockHeader *types.BlockHeader
31 }
32
33 // NewChain returns a new Chain using store as the underlying storage.
34 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
35         c := &Chain{
36                 orphanManage:    NewOrphanManage(),
37                 txPool:          txPool,
38                 store:           store,
39                 signatureCache:  common.NewCache(maxSignatureCacheSize),
40                 eventDispatcher: eventDispatcher,
41                 processBlockCh:  make(chan *processBlockMsg, maxProcessBlockChSize),
42         }
43         c.cond.L = new(sync.Mutex)
44
45         storeStatus := store.GetStoreStatus()
46         if storeStatus == nil {
47                 if err := c.initChainStatus(); err != nil {
48                         return nil, err
49                 }
50                 storeStatus = store.GetStoreStatus()
51         }
52
53         var err error
54         c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
55         if err != nil {
56                 return nil, err
57         }
58
59         c.bestIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
60         if err != nil {
61                 return nil, err
62         }
63         go c.blockProcesser()
64         return c, nil
65 }
66
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 {
72                         return err
73                 }
74         }
75
76         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
77                 return err
78         }
79
80         utxoView := state.NewUtxoViewpoint()
81         bcBlock := types.MapBlock(genesisBlock)
82         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
83                 return err
84         }
85
86         consensusResults := []*state.ConsensusResult{&state.ConsensusResult{
87                 Seq:            0,
88                 NumOfVote:      make(map[string]uint64),
89                 CoinbaseReward: make(map[string]uint64),
90                 BlockHash:      genesisBlock.Hash(),
91                 BlockHeight:    0,
92         }}
93
94         genesisBlockHeader := &genesisBlock.BlockHeader
95         return c.store.SaveChainStatus(genesisBlockHeader, genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, consensusResults)
96 }
97
98 // BestBlockHeight returns the current height of the blockchain.
99 func (c *Chain) BestBlockHeight() uint64 {
100         c.cond.L.Lock()
101         defer c.cond.L.Unlock()
102         return c.bestBlockHeader.Height
103 }
104
105 // BestBlockHash return the hash of the chain tail block
106 func (c *Chain) BestBlockHash() *bc.Hash {
107         c.cond.L.Lock()
108         defer c.cond.L.Unlock()
109         bestHash := c.bestBlockHeader.Hash()
110         return &bestHash
111 }
112
113 // BestIrreversibleHeader returns the chain best irreversible block header
114 func (c *Chain) BestIrreversibleHeader() *types.BlockHeader {
115         c.cond.L.Lock()
116         defer c.cond.L.Unlock()
117         return c.bestIrrBlockHeader
118 }
119
120 // BestBlockHeader returns the chain best block header
121 func (c *Chain) BestBlockHeader() *types.BlockHeader {
122         c.cond.L.Lock()
123         defer c.cond.L.Unlock()
124         return c.bestBlockHeader
125 }
126
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)
130         if err != nil {
131                 return false
132         }
133
134         blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
135         if err != nil {
136                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
137                 return false
138         }
139         return *blockHash == hash
140 }
141
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 {
145                 return err
146         }
147
148         c.bestBlockHeader = blockHeader
149         c.bestIrrBlockHeader = irrBlockHeader
150
151         blockHash := blockHeader.Hash()
152         log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
153         c.cond.Broadcast()
154         return nil
155 }
156
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)
160         go func() {
161                 c.cond.L.Lock()
162                 defer c.cond.L.Unlock()
163                 for c.bestBlockHeader.Height < height {
164                         c.cond.Wait()
165                 }
166                 ch <- struct{}{}
167         }()
168
169         return ch
170 }
171
172 // GetTxPool return chain txpool.
173 func (c *Chain) GetTxPool() *TxPool {
174         return c.txPool
175 }