OSDN Git Service

abd6ddbd203181b6e19919181ed96b7fdae997d9
[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/config"
9         engine "github.com/vapor/consensus/consensus"
10         "github.com/vapor/errors"
11         "github.com/vapor/protocol/bc"
12         "github.com/vapor/protocol/bc/types"
13         "github.com/vapor/protocol/state"
14 )
15
16 const maxProcessBlockChSize = 1024
17
18 // Chain provides functions for working with the Bytom block chain.
19 type Chain struct {
20         index          *state.BlockIndex
21         orphanManage   *OrphanManage
22         txPool         *TxPool
23         store          Store
24         processBlockCh chan *processBlockMsg
25
26         cond       sync.Cond
27         bestNode   *state.BlockNode
28         Authoritys map[string]string
29         position   uint64
30         engine     engine.Engine
31 }
32
33 // NewChain returns a new Chain using store as the underlying storage.
34 func NewChain(store Store, txPool *TxPool) (*Chain, error) {
35         c := &Chain{
36                 orphanManage:   NewOrphanManage(),
37                 txPool:         txPool,
38                 store:          store,
39                 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
40         }
41         c.cond.L = new(sync.Mutex)
42
43         storeStatus := store.GetStoreStatus()
44         if storeStatus == nil {
45                 if err := c.initChainStatus(); err != nil {
46                         return nil, err
47                 }
48                 storeStatus = store.GetStoreStatus()
49         }
50
51         var err error
52         if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
53                 return nil, err
54         }
55
56         c.bestNode = c.index.GetNode(storeStatus.Hash)
57         c.index.SetMainChain(c.bestNode)
58         go c.blockProcesser()
59         return c, nil
60 }
61
62 func (c *Chain) SetAuthoritys(authoritys map[string]string) {
63         c.Authoritys = authoritys
64 }
65
66 func (c *Chain) SetPosition(position uint64) {
67         c.position = position
68 }
69
70 func (c *Chain) GetAuthoritys(key string) string {
71         return c.Authoritys[key]
72 }
73
74 func (c *Chain) SetConsensusEngine(engine engine.Engine) {
75         c.engine = engine
76 }
77
78 func (c *Chain) initChainStatus() error {
79         genesisBlock := config.GenesisBlock()
80         txStatus := bc.NewTransactionStatus()
81         for i := range genesisBlock.Transactions {
82                 if err := txStatus.SetStatus(i, false); err != nil {
83                         return err
84                 }
85         }
86
87         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
88                 return err
89         }
90
91         utxoView := state.NewUtxoViewpoint()
92         bcBlock := types.MapBlock(genesisBlock)
93         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
94                 return err
95         }
96
97         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
98         if err != nil {
99                 return err
100         }
101         return c.store.SaveChainStatus(node, utxoView)
102 }
103
104 // BestBlockHeight returns the current height of the blockchain.
105 func (c *Chain) BestBlockHeight() uint64 {
106         c.cond.L.Lock()
107         defer c.cond.L.Unlock()
108         return c.bestNode.Height
109 }
110
111 // BestBlockHash return the hash of the chain tail block
112 func (c *Chain) BestBlockHash() *bc.Hash {
113         c.cond.L.Lock()
114         defer c.cond.L.Unlock()
115         return &c.bestNode.Hash
116 }
117
118 // BestBlockHeader returns the chain tail block
119 func (c *Chain) BestBlockHeader() *types.BlockHeader {
120         node := c.index.BestNode()
121         return node.BlockHeader()
122 }
123
124 // InMainChain checks wheather a block is in the main chain
125 func (c *Chain) InMainChain(hash bc.Hash) bool {
126         return c.index.InMainchain(hash)
127 }
128
129 // CalcNextSeed return the seed for the given block
130 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
131         node := c.index.GetNode(preBlock)
132         if node == nil {
133                 return nil, errors.New("can't find preblock in the blockindex")
134         }
135         return node.CalcNextSeed(), nil
136 }
137
138 // CalcNextBits return the seed for the given block
139 func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) {
140         node := c.index.GetNode(preBlock)
141         if node == nil {
142                 return 0, errors.New("can't find preblock in the blockindex")
143         }
144         return node.CalcNextBits(), nil
145 }
146
147 // This function must be called with mu lock in above level
148 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
149         if err := c.store.SaveChainStatus(node, view); err != nil {
150                 return err
151         }
152
153         c.cond.L.Lock()
154         defer c.cond.L.Unlock()
155
156         c.index.SetMainChain(node)
157         c.bestNode = node
158
159         log.WithFields(log.Fields{"height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
160         c.cond.Broadcast()
161         return nil
162 }
163
164 // BlockWaiter returns a channel that waits for the block at the given height.
165 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
166         ch := make(chan struct{}, 1)
167         go func() {
168                 c.cond.L.Lock()
169                 defer c.cond.L.Unlock()
170                 for c.bestNode.Height < height {
171                         c.cond.Wait()
172                 }
173                 ch <- struct{}{}
174         }()
175
176         return ch
177 }
178
179 // GetTxPool return chain txpool.
180 func (c *Chain) GetTxPool() *TxPool {
181         return c.txPool
182 }