OSDN Git Service

d9fafe2f1506646d4ec63a6ba29e37245f1d45a1
[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 maxProcessBlockChSize = 1024
19
20 // Chain provides functions for working with the Bytom block chain.
21 type Chain struct {
22         index            *state.BlockIndex
23         orphanManage     *OrphanManage
24         txPool           *TxPool
25         store            Store
26         casper           *Casper
27         processBlockCh   chan *processBlockMsg
28         rollbackNotifyCh chan bc.Hash
29         eventDispatcher  *event.Dispatcher
30
31         cond     sync.Cond
32         bestNode *state.BlockNode
33 }
34
35 // NewChain returns a new Chain using store as the underlying storage.
36 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
37         return NewChainWithOrphanManage(store, txPool, NewOrphanManage(), eventDispatcher)
38 }
39
40 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage, eventDispatcher *event.Dispatcher) (*Chain, error) {
41         c := &Chain{
42                 orphanManage:     manage,
43                 eventDispatcher:  eventDispatcher,
44                 txPool:           txPool,
45                 store:            store,
46                 rollbackNotifyCh: make(chan bc.Hash),
47                 processBlockCh:   make(chan *processBlockMsg, maxProcessBlockChSize),
48         }
49         c.cond.L = new(sync.Mutex)
50
51         storeStatus := store.GetStoreStatus()
52         if storeStatus == nil {
53                 if err := c.initChainStatus(); err != nil {
54                         return nil, err
55                 }
56                 storeStatus = store.GetStoreStatus()
57         }
58
59         var err error
60         if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
61                 return nil, err
62         }
63
64         c.bestNode = c.index.GetNode(storeStatus.Hash)
65         c.index.SetMainChain(c.bestNode)
66
67         casper, err := newCasper(store, storeStatus, c.rollbackNotifyCh)
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         utxoView := state.NewUtxoViewpoint()
91         bcBlock := types.MapBlock(genesisBlock)
92         if err := utxoView.ApplyBlock(bcBlock); err != nil {
93                 return err
94         }
95
96         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
97         if err != nil {
98                 return err
99         }
100
101         contractView := state.NewContractViewpoint()
102         return c.store.SaveChainStatus(node, utxoView, contractView, []*state.Checkpoint{checkpoint}, 0, &checkpoint.Hash)
103 }
104
105 func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan bc.Hash) (*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, rollbackNotifyCh), nil
112 }
113
114 // BestBlockHeight returns the last irreversible block header of the blockchain
115 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
116         _, hash := c.casper.LastFinalized()
117         node := c.index.GetNode(&hash)
118         return node.BlockHeader()
119 }
120
121 // ProcessBlockVerification process block verification
122 func (c *Chain) ProcessBlockVerification(v *Verification) error {
123         if err := c.casper.AuthVerification(v); err != nil {
124                 return err
125         }
126
127         pubKey, _ := hex.DecodeString(v.PubKey)
128         signature, _ := hex.DecodeString(v.Signature)
129         return c.eventDispatcher.Post(event.BlockVerificationEvent{
130                 SourceHeight: v.SourceHeight,
131                 SourceHash:   v.SourceHash,
132                 TargetHeight: v.TargetHeight,
133                 TargetHash:   v.TargetHash,
134                 PubKey:       pubKey,
135                 Signature:    signature,
136         })
137 }
138
139 // BestBlockHeight returns the current height of the blockchain.
140 func (c *Chain) BestBlockHeight() uint64 {
141         c.cond.L.Lock()
142         defer c.cond.L.Unlock()
143         return c.bestNode.Height
144 }
145
146 // BestBlockHash return the hash of the chain tail block
147 func (c *Chain) BestBlockHash() *bc.Hash {
148         c.cond.L.Lock()
149         defer c.cond.L.Unlock()
150         return &c.bestNode.Hash
151 }
152
153 // GetValidator return validator by specified blockHash and timestamp
154 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
155         prevCheckpoint, err := c.casper.prevCheckpointByPrevHash(prevHash)
156         if err != nil {
157                 return nil, err
158         }
159
160         validators := prevCheckpoint.Validators()
161         startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
162         order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
163         for _, validator := range validators {
164                 if validator.Order == int(order) {
165                         return validator, nil
166                 }
167         }
168         return nil, errors.New("get blocker failure")
169 }
170
171 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
172         // One round of product block time for all consensus nodes
173         roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
174         // The start time of the last round of product block
175         lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
176         // Order of blocker
177         return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
178 }
179
180 // BestBlockHeader returns the chain tail block
181 func (c *Chain) BestBlockHeader() *types.BlockHeader {
182         node := c.index.BestNode()
183         return node.BlockHeader()
184 }
185
186 // InMainChain checks wheather a block is in the main chain
187 func (c *Chain) InMainChain(hash bc.Hash) bool {
188         return c.index.InMainchain(hash)
189 }
190
191 func (c *Chain) GetBlockIndex() *state.BlockIndex {
192         return c.index
193 }
194
195 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
196         xprv := config.CommonConfig.PrivateKey()
197         signature := xprv.Sign(blockHeader.Hash().Bytes())
198         blockHeader.Set(signature)
199 }
200
201 // This function must be called with mu lock in above level
202 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint, contractView *state.ContractViewpoint, checkpoints ...*state.Checkpoint) error {
203         finalizedHeight, finalizedHash := c.casper.LastFinalized()
204         if err := c.store.SaveChainStatus(node, view, contractView, checkpoints, finalizedHeight, &finalizedHash); err != nil {
205                 return err
206         }
207
208         c.cond.L.Lock()
209         defer c.cond.L.Unlock()
210
211         c.index.SetMainChain(node)
212         c.bestNode = node
213
214         log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
215         c.cond.Broadcast()
216         return nil
217 }
218
219 // BlockWaiter returns a channel that waits for the block at the given height.
220 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
221         ch := make(chan struct{}, 1)
222         go func() {
223                 c.cond.L.Lock()
224                 defer c.cond.L.Unlock()
225                 for c.bestNode.Height < height {
226                         c.cond.Wait()
227                 }
228                 ch <- struct{}{}
229         }()
230
231         return ch
232 }
233
234 // GetTxPool return chain txpool.
235 func (c *Chain) GetTxPool() *TxPool {
236         return c.txPool
237 }