OSDN Git Service

api add irreversible height (#1992)
[bytom/bytom.git] / protocol / protocol.go
1 package protocol
2
3 import (
4         "encoding/hex"
5         "sync"
6
7         log "github.com/sirupsen/logrus"
8
9         "github.com/bytom/bytom/config"
10         "github.com/bytom/bytom/consensus"
11         "github.com/bytom/bytom/errors"
12         "github.com/bytom/bytom/event"
13         "github.com/bytom/bytom/protocol/bc"
14         "github.com/bytom/bytom/protocol/bc/types"
15         "github.com/bytom/bytom/protocol/state"
16 )
17
18 const (
19         maxProcessBlockChSize  = 1024
20         maxProcessRollbackSize = 1024
21 )
22
23 // Chain provides functions for working with the Bytom block chain.
24 type Chain struct {
25         orphanManage      *OrphanManage
26         txPool            *TxPool
27         store             Store
28         casper            *Casper
29         processBlockCh    chan *processBlockMsg
30         processRollbackCh chan *rollbackMsg
31         eventDispatcher   *event.Dispatcher
32
33         cond            sync.Cond
34         bestBlockHeader *types.BlockHeader // the last block on current main chain
35 }
36
37 // NewChain returns a new Chain using store as the underlying storage.
38 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
39         return NewChainWithOrphanManage(store, txPool, NewOrphanManage(), eventDispatcher)
40 }
41
42 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage, eventDispatcher *event.Dispatcher) (*Chain, error) {
43         c := &Chain{
44                 orphanManage:      manage,
45                 eventDispatcher:   eventDispatcher,
46                 txPool:            txPool,
47                 store:             store,
48                 processRollbackCh: make(chan *rollbackMsg, maxProcessRollbackSize),
49                 processBlockCh:    make(chan *processBlockMsg, maxProcessBlockChSize),
50         }
51         c.cond.L = new(sync.Mutex)
52
53         storeStatus := store.GetStoreStatus()
54         if storeStatus == nil {
55                 if err := c.initChainStatus(); err != nil {
56                         return nil, err
57                 }
58                 storeStatus = store.GetStoreStatus()
59         }
60
61         var err error
62         c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
63         if err != nil {
64                 return nil, err
65         }
66
67         casper, err := newCasper(store, storeStatus, c.processRollbackCh)
68         if err != nil {
69                 return nil, err
70         }
71
72         c.casper = casper
73         go c.blockProcessor()
74         return c, nil
75 }
76
77 func (c *Chain) initChainStatus() error {
78         genesisBlock := config.GenesisBlock()
79         if err := c.store.SaveBlock(genesisBlock); err != nil {
80                 return err
81         }
82
83         checkpoint := &state.Checkpoint{
84                 Height:    0,
85                 Hash:      genesisBlock.Hash(),
86                 Timestamp: genesisBlock.Timestamp,
87                 Status:    state.Justified,
88         }
89
90         if err := c.store.SaveCheckpoints([]*state.Checkpoint{checkpoint}); err != nil {
91                 return err
92         }
93
94         utxoView := state.NewUtxoViewpoint()
95         bcBlock := types.MapBlock(genesisBlock)
96         if err := utxoView.ApplyBlock(bcBlock); err != nil {
97                 return err
98         }
99
100         contractView := state.NewContractViewpoint()
101         genesisBlockHeader := &genesisBlock.BlockHeader
102         return c.store.SaveChainStatus(genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, contractView, 0, &checkpoint.Hash)
103 }
104
105 func newCasper(store Store, storeStatus *BlockStoreState, rollbackCh chan *rollbackMsg) (*Casper, error) {
106         checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
107         if err != nil {
108                 return nil, err
109         }
110
111         return NewCasper(store, checkpoints, rollbackCh), nil
112 }
113
114 // LastJustifiedHeader return the last justified block header of the block chain
115 func (c *Chain) LastJustifiedHeader() (*types.BlockHeader, error) {
116         _, hash := c.casper.LastJustified()
117         return c.store.GetBlockHeader(&hash)
118 }
119
120 // LastFinalizedHeader return the last finalized block header of the block chain
121 func (c *Chain) LastFinalizedHeader() (*types.BlockHeader, error) {
122         _, hash := c.casper.LastFinalized()
123         return c.store.GetBlockHeader(&hash)
124 }
125
126 // ProcessBlockVerification process block verification
127 func (c *Chain) ProcessBlockVerification(v *Verification) error {
128         if err := c.casper.AuthVerification(v); err != nil {
129                 return err
130         }
131
132         pubKey, _ := hex.DecodeString(v.PubKey)
133         return c.eventDispatcher.Post(event.BlockVerificationEvent{
134                 SourceHeight: v.SourceHeight,
135                 SourceHash:   v.SourceHash,
136                 TargetHeight: v.TargetHeight,
137                 TargetHash:   v.TargetHash,
138                 PubKey:       pubKey,
139                 Signature:    v.Signature,
140         })
141 }
142
143 // BestBlockHeight returns the current height of the blockchain.
144 func (c *Chain) BestBlockHeight() uint64 {
145         c.cond.L.Lock()
146         defer c.cond.L.Unlock()
147         return c.bestBlockHeader.Height
148 }
149
150 // BestBlockHash return the hash of the chain tail block
151 func (c *Chain) BestBlockHash() *bc.Hash {
152         c.cond.L.Lock()
153         defer c.cond.L.Unlock()
154         bestHash := c.bestBlockHeader.Hash()
155         return &bestHash
156 }
157
158 // GetValidator return validator by specified blockHash and timestamp
159 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
160         prevCheckpoint, err := c.casper.parentCheckpointByPrevHash(prevHash)
161         if err != nil {
162                 return nil, err
163         }
164
165         validators := prevCheckpoint.Validators()
166         startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
167         order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
168         for _, validator := range validators {
169                 if validator.Order == int(order) {
170                         return validator, nil
171                 }
172         }
173         return nil, errors.New("get blocker failure")
174 }
175
176 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
177         // One round of product block time for all consensus nodes
178         roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
179         // The start time of the last round of product block
180         lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
181         // Order of blocker
182         return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
183 }
184
185 // BestBlockHeader returns the chain tail block
186 func (c *Chain) BestBlockHeader() *types.BlockHeader {
187         c.cond.L.Lock()
188         defer c.cond.L.Unlock()
189         return c.bestBlockHeader
190 }
191
192 // InMainChain checks wheather a block is in the main chain
193 func (c *Chain) InMainChain(hash bc.Hash) bool {
194         blockHeader, err := c.store.GetBlockHeader(&hash)
195         if err != nil {
196                 return false
197         }
198
199         blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
200         if err != nil {
201                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
202                 return false
203         }
204         return *blockHash == hash
205 }
206
207 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
208         xprv := config.CommonConfig.PrivateKey()
209         signature := xprv.Sign(blockHeader.Hash().Bytes())
210         blockHeader.Set(signature)
211 }
212
213 // This function must be called with mu lock in above level
214 func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
215         finalizedHeight, finalizedHash := c.casper.LastFinalized()
216         if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
217                 return err
218         }
219
220         c.cond.L.Lock()
221         defer c.cond.L.Unlock()
222
223         c.bestBlockHeader = blockHeader
224
225         hash := c.bestBlockHeader.Hash()
226         log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
227         c.cond.Broadcast()
228         return nil
229 }
230
231 // BlockWaiter returns a channel that waits for the block at the given height.
232 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
233         ch := make(chan struct{}, 1)
234         go func() {
235                 c.cond.L.Lock()
236                 defer c.cond.L.Unlock()
237                 for c.bestBlockHeader.Height < height {
238                         c.cond.Wait()
239                 }
240                 ch <- struct{}{}
241         }()
242
243         return ch
244 }
245
246 // GetTxPool return chain txpool.
247 func (c *Chain) GetTxPool() *TxPool {
248         return c.txPool
249 }
250
251 // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
252 func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
253         return c.casper.parentCheckpointByPrevHash(preBlockHash)
254 }