OSDN Git Service

845577c0b335c6d867055c5ebec0fddb5a966bb8
[bytom/bytom.git] / protocol / protocol.go
1 package protocol
2
3 import (
4         "sync"
5
6         log "github.com/sirupsen/logrus"
7
8         "github.com/bytom/bytom/config"
9         "github.com/bytom/bytom/event"
10         "github.com/bytom/bytom/protocol/bc"
11         "github.com/bytom/bytom/protocol/bc/types"
12         "github.com/bytom/bytom/protocol/state"
13 )
14
15 const maxProcessBlockChSize = 1024
16
17 // Chain provides functions for working with the Bytom block chain.
18 type Chain struct {
19         index           *state.BlockIndex
20         orphanManage    *OrphanManage
21         txPool          *TxPool
22         store           Store
23         processBlockCh  chan *processBlockMsg
24         rollbackBlockCh chan bc.Hash
25         casper          CasperConsensus
26         eventDispatcher *event.Dispatcher
27
28         cond     sync.Cond
29         bestNode *state.BlockNode
30 }
31
32 // NewChain returns a new Chain using store as the underlying storage.
33 func NewChain(store Store, txPool *TxPool) (*Chain, error) {
34         return NewChainWithOrphanManage(store, txPool, NewOrphanManage())
35 }
36
37 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage) (*Chain, error) {
38         c := &Chain{
39                 orphanManage:   manage,
40                 txPool:         txPool,
41                 store:          store,
42                 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
43         }
44         c.cond.L = new(sync.Mutex)
45
46         storeStatus := store.GetStoreStatus()
47         if storeStatus == nil {
48                 if err := c.initChainStatus(); err != nil {
49                         return nil, err
50                 }
51                 storeStatus = store.GetStoreStatus()
52         }
53
54         var err error
55         if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
56                 return nil, err
57         }
58
59         c.bestNode = c.index.GetNode(storeStatus.Hash)
60         c.index.SetMainChain(c.bestNode)
61         go c.blockProcesser()
62         return c, nil
63 }
64
65 func (c *Chain) initChainStatus() error {
66         genesisBlock := config.GenesisBlock()
67         if err := c.store.SaveBlock(genesisBlock); err != nil {
68                 return err
69         }
70
71         utxoView := state.NewUtxoViewpoint()
72         bcBlock := types.MapBlock(genesisBlock)
73         if err := utxoView.ApplyBlock(bcBlock); err != nil {
74                 return err
75         }
76
77         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
78         if err != nil {
79                 return err
80         }
81
82         contractView := state.NewContractViewpoint()
83         return c.store.SaveChainStatus(node, utxoView, contractView)
84 }
85
86 // BestBlockHeight returns the last irreversible block header of the blockchain
87 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
88         _, hash := c.casper.LastFinalized()
89         node := c.index.GetNode(&hash)
90         return node.BlockHeader()
91 }
92
93 // ProcessBlockVerification process block verification
94 func (c *Chain) ProcessBlockVerification(v *Verification) error {
95         return c.casper.AuthVerification(v)
96 }
97
98 // BestBlockHeight returns the current height of the blockchain.
99 func (c *Chain) BestBlockHeight() uint64 {
100         c.cond.L.Lock()
101         defer c.cond.L.Unlock()
102         return c.bestNode.Height
103 }
104
105 // BestBlockHash return the hash of the chain tail block
106 func (c *Chain) BestBlockHash() *bc.Hash {
107         c.cond.L.Lock()
108         defer c.cond.L.Unlock()
109         return &c.bestNode.Hash
110 }
111
112 // BestBlockHeader returns the chain tail block
113 func (c *Chain) BestBlockHeader() *types.BlockHeader {
114         node := c.index.BestNode()
115         return node.BlockHeader()
116 }
117
118 // InMainChain checks wheather a block is in the main chain
119 func (c *Chain) InMainChain(hash bc.Hash) bool {
120         return c.index.InMainchain(hash)
121 }
122
123 func (c *Chain) GetBlockIndex() *state.BlockIndex {
124         return c.index
125 }
126
127 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
128         c.cond.L.Lock()
129         defer c.cond.L.Unlock()
130         xprv := config.CommonConfig.PrivateKey()
131         signature := xprv.Sign(blockHeader.Hash().Bytes())
132         blockHeader.Set(signature)
133 }
134
135 // This function must be called with mu lock in above level
136 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
137         if err := c.store.SaveChainStatus(node, view, contractView); err != nil {
138                 return err
139         }
140
141         c.cond.L.Lock()
142         defer c.cond.L.Unlock()
143
144         c.index.SetMainChain(node)
145         c.bestNode = node
146
147         log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
148         c.cond.Broadcast()
149         return nil
150 }
151
152 // BlockWaiter returns a channel that waits for the block at the given height.
153 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
154         ch := make(chan struct{}, 1)
155         go func() {
156                 c.cond.L.Lock()
157                 defer c.cond.L.Unlock()
158                 for c.bestNode.Height < height {
159                         c.cond.Wait()
160                 }
161                 ch <- struct{}{}
162         }()
163
164         return ch
165 }
166
167 // GetTxPool return chain txpool.
168 func (c *Chain) GetTxPool() *TxPool {
169         return c.txPool
170 }