OSDN Git Service

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