OSDN Git Service

edit dup sup link struct (#1988)
[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 // LastFinalizedHeader returns the last finalized 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 // ProcessBlockVerification process block verification
121 func (c *Chain) ProcessBlockVerification(v *Verification) error {
122         if err := c.casper.AuthVerification(v); err != nil {
123                 return err
124         }
125
126         pubKey, _ := hex.DecodeString(v.PubKey)
127         return c.eventDispatcher.Post(event.BlockVerificationEvent{
128                 SourceHeight: v.SourceHeight,
129                 SourceHash:   v.SourceHash,
130                 TargetHeight: v.TargetHeight,
131                 TargetHash:   v.TargetHash,
132                 PubKey:       pubKey,
133                 Signature:    v.Signature,
134         })
135 }
136
137 // BestBlockHeight returns the current height of the blockchain.
138 func (c *Chain) BestBlockHeight() uint64 {
139         c.cond.L.Lock()
140         defer c.cond.L.Unlock()
141         return c.bestBlockHeader.Height
142 }
143
144 // BestBlockHash return the hash of the chain tail block
145 func (c *Chain) BestBlockHash() *bc.Hash {
146         c.cond.L.Lock()
147         defer c.cond.L.Unlock()
148         bestHash := c.bestBlockHeader.Hash()
149         return &bestHash
150 }
151
152 // GetValidator return validator by specified blockHash and timestamp
153 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
154         prevCheckpoint, err := c.casper.parentCheckpointByPrevHash(prevHash)
155         if err != nil {
156                 return nil, err
157         }
158
159         validators := prevCheckpoint.Validators()
160         startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
161         order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
162         for _, validator := range validators {
163                 if validator.Order == int(order) {
164                         return validator, nil
165                 }
166         }
167         return nil, errors.New("get blocker failure")
168 }
169
170 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
171         // One round of product block time for all consensus nodes
172         roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
173         // The start time of the last round of product block
174         lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
175         // Order of blocker
176         return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
177 }
178
179 // BestBlockHeader returns the chain tail block
180 func (c *Chain) BestBlockHeader() *types.BlockHeader {
181         c.cond.L.Lock()
182         defer c.cond.L.Unlock()
183         return c.bestBlockHeader
184 }
185
186 // InMainChain checks wheather a block is in the main chain
187 func (c *Chain) InMainChain(hash bc.Hash) bool {
188         blockHeader, err := c.store.GetBlockHeader(&hash)
189         if err != nil {
190                 return false
191         }
192
193         blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
194         if err != nil {
195                 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
196                 return false
197         }
198         return *blockHash == hash
199 }
200
201 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
202         xprv := config.CommonConfig.PrivateKey()
203         signature := xprv.Sign(blockHeader.Hash().Bytes())
204         blockHeader.Set(signature)
205 }
206
207 // This function must be called with mu lock in above level
208 func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
209         finalizedHeight, finalizedHash := c.casper.LastFinalized()
210         if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
211                 return err
212         }
213
214         c.cond.L.Lock()
215         defer c.cond.L.Unlock()
216
217         c.bestBlockHeader = blockHeader
218
219         hash := c.bestBlockHeader.Hash()
220         log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
221         c.cond.Broadcast()
222         return nil
223 }
224
225 // BlockWaiter returns a channel that waits for the block at the given height.
226 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
227         ch := make(chan struct{}, 1)
228         go func() {
229                 c.cond.L.Lock()
230                 defer c.cond.L.Unlock()
231                 for c.bestBlockHeader.Height < height {
232                         c.cond.Wait()
233                 }
234                 ch <- struct{}{}
235         }()
236
237         return ch
238 }
239
240 // GetTxPool return chain txpool.
241 func (c *Chain) GetTxPool() *TxPool {
242         return c.txPool
243 }
244
245 // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
246 func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
247         return c.casper.parentCheckpointByPrevHash(preBlockHash)
248 }