OSDN Git Service

versoin1.1.9 (#594)
[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/bytom/vapor/common"
9         "github.com/bytom/vapor/config"
10         "github.com/bytom/vapor/errors"
11         "github.com/bytom/vapor/event"
12         "github.com/bytom/vapor/protocol/bc"
13         "github.com/bytom/vapor/protocol/bc/types"
14         "github.com/bytom/vapor/protocol/state"
15 )
16
17 const (
18         maxProcessBlockChSize = 1024
19         maxKnownTxs           = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
20 )
21
22 // ErrNotInitSubProtocolChainStatus represent the node state of sub protocol has not been initialized
23 var ErrNotInitSubProtocolChainStatus = errors.New("node state of sub protocol has not been initialized")
24
25 // SubProtocol is interface for layer 2 consensus protocol
26 type SubProtocol interface {
27         Name() string
28         StartHeight() uint64
29         BeforeProposalBlock(block *types.Block, gasLeft int64, isTimeout func() bool) ([]*types.Tx, error)
30
31         // ChainStatus return the the current block height and block hash of sub protocol.
32         // it will return ErrNotInitSubProtocolChainStatus if not initialized.
33         ChainStatus() (uint64, *bc.Hash, error)
34         InitChainStatus(*bc.Hash) error
35         ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
36         ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error
37         ApplyBlock(block *types.Block) error
38         DetachBlock(block *types.Block) error
39 }
40
41 // Chain provides functions for working with the Bytom block chain.
42 type Chain struct {
43         orphanManage   *OrphanManage
44         txPool         *TxPool
45         store          Store
46         processBlockCh chan *processBlockMsg
47         subProtocols   []SubProtocol
48
49         signatureCache  *common.Cache
50         eventDispatcher *event.Dispatcher
51
52         cond               sync.Cond
53         bestBlockHeader    *types.BlockHeader // the last block on current main chain
54         lastIrrBlockHeader *types.BlockHeader // the last irreversible block
55
56         knownTxs *common.OrderedSet
57 }
58
59 // NewChain returns a new Chain using store as the underlying storage.
60 func NewChain(store Store, txPool *TxPool, subProtocols []SubProtocol, eventDispatcher *event.Dispatcher) (*Chain, error) {
61         knownTxs, _ := common.NewOrderedSet(maxKnownTxs)
62         c := &Chain{
63                 orphanManage:    NewOrphanManage(),
64                 txPool:          txPool,
65                 store:           store,
66                 subProtocols:    subProtocols,
67                 signatureCache:  common.NewCache(maxSignatureCacheSize),
68                 eventDispatcher: eventDispatcher,
69                 processBlockCh:  make(chan *processBlockMsg, maxProcessBlockChSize),
70                 knownTxs:        knownTxs,
71         }
72         c.cond.L = new(sync.Mutex)
73
74         storeStatus := store.GetStoreStatus()
75         if storeStatus == nil {
76                 if err := c.initChainStatus(); err != nil {
77                         return nil, err
78                 }
79                 storeStatus = store.GetStoreStatus()
80         }
81
82         var err error
83         c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
84         if err != nil {
85                 return nil, err
86         }
87
88         c.lastIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
89         if err != nil {
90                 return nil, err
91         }
92
93         for _, p := range c.subProtocols {
94                 if err := c.syncProtocolStatus(p); err != nil {
95                         return nil, errors.Wrap(err, p.Name(), "sync sub protocol status")
96                 }
97         }
98
99         go c.blockProcesser()
100         return c, nil
101 }
102
103 func (c *Chain) initChainStatus() error {
104         genesisBlock := config.GenesisBlock()
105         txStatus := bc.NewTransactionStatus()
106         for i := range genesisBlock.Transactions {
107                 if err := txStatus.SetStatus(i, false); err != nil {
108                         return err
109                 }
110         }
111
112         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
113                 return err
114         }
115
116         utxoView := state.NewUtxoViewpoint()
117         bcBlock := types.MapBlock(genesisBlock)
118         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
119                 return err
120         }
121
122         for _, subProtocol := range c.subProtocols {
123                 if err := subProtocol.ApplyBlock(genesisBlock); err != nil {
124                         return err
125                 }
126         }
127
128         consensusResults := []*state.ConsensusResult{{
129                 Seq:            0,
130                 NumOfVote:      make(map[string]uint64),
131                 CoinbaseReward: make(map[string]uint64),
132                 BlockHash:      genesisBlock.Hash(),
133                 BlockHeight:    0,
134         }}
135
136         genesisBlockHeader := &genesisBlock.BlockHeader
137         return c.store.SaveChainStatus(genesisBlockHeader, genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, consensusResults)
138 }
139
140 // BestBlockHeight returns the current height of the blockchain.
141 func (c *Chain) BestBlockHeight() uint64 {
142         c.cond.L.Lock()
143         defer c.cond.L.Unlock()
144         return c.bestBlockHeader.Height
145 }
146
147 // BestBlockHash return the hash of the main chain tail block
148 func (c *Chain) BestBlockHash() *bc.Hash {
149         c.cond.L.Lock()
150         defer c.cond.L.Unlock()
151         bestHash := c.bestBlockHeader.Hash()
152         return &bestHash
153 }
154
155 // LastIrreversibleHeader returns the chain last irreversible block header
156 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
157         c.cond.L.Lock()
158         defer c.cond.L.Unlock()
159         return c.lastIrrBlockHeader
160 }
161
162 // BestBlockHeader returns the chain best block header
163 func (c *Chain) BestBlockHeader() *types.BlockHeader {
164         c.cond.L.Lock()
165         defer c.cond.L.Unlock()
166         return c.bestBlockHeader
167 }
168
169 // InMainChain checks wheather a block is in the main chain
170 func (c *Chain) InMainChain(hash bc.Hash) bool {
171         blockHeader, err := c.store.GetBlockHeader(&hash)
172         if err != nil {
173                 return false
174         }
175
176         blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
177         if err != nil {
178                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
179                 return false
180         }
181         return *blockHash == hash
182 }
183
184 // SubProtocols return list of layer 2 consensus protocol
185 func (c *Chain) SubProtocols() []SubProtocol {
186         return c.subProtocols
187 }
188
189 // trace back to the tail of the chain from the given block header
190 func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) {
191         longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader}
192
193         for ; len(workQueue) > 0; workQueue = workQueue[1:] {
194                 currentHeader := workQueue[0]
195                 currentHash := currentHeader.Hash()
196                 hashes, err := c.store.GetBlockHashesByHeight(currentHeader.Height + 1)
197                 if err != nil {
198                         return nil, err
199                 }
200
201                 for _, h := range hashes {
202                         if header, err := c.store.GetBlockHeader(h); err != nil {
203                                 return nil, err
204                         } else if header.PreviousBlockHash == currentHash {
205                                 if longestTail.Height < header.Height {
206                                         longestTail = header
207                                 }
208                                 workQueue = append(workQueue, header)
209                         }
210                 }
211         }
212         return longestTail, nil
213 }
214
215 func (c *Chain) hasSeenTx(tx *types.Tx) bool {
216         return c.knownTxs.Has(tx.ID.String())
217 }
218
219 func (c *Chain) markTransactions(txs ...*types.Tx) {
220         for _, tx := range txs {
221                 c.knownTxs.Add(tx.ID.String())
222         }
223 }
224
225 func (c *Chain) syncProtocolStatus(subProtocol SubProtocol) error {
226         if c.bestBlockHeader.Height < subProtocol.StartHeight() {
227                 return nil
228         }
229
230         protocolHeight, protocolHash, err := subProtocol.ChainStatus()
231         if err == ErrNotInitSubProtocolChainStatus {
232                 startHash, err := c.store.GetMainChainHash(subProtocol.StartHeight())
233                 if err != nil {
234                         return errors.Wrap(err, subProtocol.Name(), "can't get block hash by height")
235                 }
236
237                 if err := subProtocol.InitChainStatus(startHash); err != nil {
238                         return errors.Wrap(err, subProtocol.Name(), "fail init chain status")
239                 }
240
241                 protocolHeight, protocolHash = subProtocol.StartHeight(), startHash
242         } else if err != nil {
243                 return errors.Wrap(err, subProtocol.Name(), "can't get chain status")
244         }
245
246         if *protocolHash == c.bestBlockHeader.Hash() {
247                 return nil
248         }
249
250         for !c.InMainChain(*protocolHash) {
251                 block, err := c.GetBlockByHash(protocolHash)
252                 if err != nil {
253                         return errors.Wrap(err, subProtocol.Name(), "can't get block by hash in chain")
254                 }
255
256                 if err := subProtocol.DetachBlock(block); err != nil {
257                         return errors.Wrap(err, subProtocol.Name(), "sub protocol detach block err")
258                 }
259
260                 protocolHeight, protocolHash = block.Height-1, &block.PreviousBlockHash
261         }
262
263         for height := protocolHeight + 1; height <= c.bestBlockHeader.Height; height++ {
264                 block, err := c.GetBlockByHeight(height)
265                 if err != nil {
266                         return errors.Wrap(err, subProtocol.Name(), "can't get block by height in chain")
267                 }
268
269                 if err := subProtocol.ApplyBlock(block); err != nil {
270                         return errors.Wrap(err, subProtocol.Name(), "sub protocol apply block err")
271                 }
272
273                 blockHash := block.Hash()
274                 protocolHeight, protocolHash = block.Height, &blockHash
275         }
276
277         return nil
278 }
279
280 // This function must be called with mu lock in above level
281 func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
282         if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
283                 return err
284         }
285
286         c.bestBlockHeader = blockHeader
287         c.lastIrrBlockHeader = irrBlockHeader
288
289         blockHash := blockHeader.Hash()
290         log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
291         c.cond.Broadcast()
292         return nil
293 }
294
295 // BlockWaiter returns a channel that waits for the block at the given height.
296 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
297         ch := make(chan struct{}, 1)
298         go func() {
299                 c.cond.L.Lock()
300                 defer c.cond.L.Unlock()
301                 for c.bestBlockHeader.Height < height {
302                         c.cond.Wait()
303                 }
304                 ch <- struct{}{}
305         }()
306
307         return ch
308 }
309
310 // GetTxPool return chain txpool.
311 func (c *Chain) GetTxPool() *TxPool {
312         return c.txPool
313 }