OSDN Git Service

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