OSDN Git Service

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