OSDN Git Service

feat(net/netsync/p2p/pow): Change network lib and remove pow (#1864)
[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/errors"
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
25         cond     sync.Cond
26         bestNode *state.BlockNode
27 }
28
29 // NewChain returns a new Chain using store as the underlying storage.
30 func NewChain(store Store, txPool *TxPool) (*Chain, error) {
31         return NewChainWithOrphanManage(store, txPool, NewOrphanManage())
32 }
33
34 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage) (*Chain, error) {
35         c := &Chain{
36                 orphanManage:   manage,
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) initChainStatus() error {
63         genesisBlock := config.GenesisBlock()
64         txStatus := bc.NewTransactionStatus()
65         for i := range genesisBlock.Transactions {
66                 if err := txStatus.SetStatus(i, false); err != nil {
67                         return err
68                 }
69         }
70
71         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
72                 return err
73         }
74
75         utxoView := state.NewUtxoViewpoint()
76         bcBlock := types.MapBlock(genesisBlock)
77         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
78                 return err
79         }
80
81         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
82         if err != nil {
83                 return err
84         }
85         return c.store.SaveChainStatus(node, utxoView)
86 }
87
88 // BestBlockHeight returns the last irreversible block header of the blockchain
89 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
90         // TODO: LastIrreversibleHeader
91         return nil
92 }
93
94 // ProcessBlockSignature process blockchain signature
95 func (c *Chain) ProcessBlockSignature(signature, pubkey []byte, blockHash *bc.Hash) error {
96         // TODO: ProcessBlockSignature
97         return nil
98 }
99
100 // BestBlockHeight returns the current height of the blockchain.
101 func (c *Chain) BestBlockHeight() uint64 {
102         c.cond.L.Lock()
103         defer c.cond.L.Unlock()
104         return c.bestNode.Height
105 }
106
107 // BestBlockHash return the hash of the chain tail block
108 func (c *Chain) BestBlockHash() *bc.Hash {
109         c.cond.L.Lock()
110         defer c.cond.L.Unlock()
111         return &c.bestNode.Hash
112 }
113
114 // BestBlockHeader returns the chain tail block
115 func (c *Chain) BestBlockHeader() *types.BlockHeader {
116         node := c.index.BestNode()
117         return node.BlockHeader()
118 }
119
120 // InMainChain checks wheather a block is in the main chain
121 func (c *Chain) InMainChain(hash bc.Hash) bool {
122         return c.index.InMainchain(hash)
123 }
124
125 // CalcNextSeed return the seed for the given block
126 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
127         node := c.index.GetNode(preBlock)
128         if node == nil {
129                 return nil, errors.New("can't find preblock in the blockindex")
130         }
131         return node.CalcNextSeed(), nil
132 }
133
134 func (c *Chain) GetBlockIndex() *state.BlockIndex {
135         return c.index
136 }
137
138 // This function must be called with mu lock in above level
139 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
140         if err := c.store.SaveChainStatus(node, view); err != nil {
141                 return err
142         }
143
144         c.cond.L.Lock()
145         defer c.cond.L.Unlock()
146
147         c.index.SetMainChain(node)
148         c.bestNode = node
149
150         log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
151         c.cond.Broadcast()
152         return nil
153 }
154
155 // BlockWaiter returns a channel that waits for the block at the given height.
156 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
157         ch := make(chan struct{}, 1)
158         go func() {
159                 c.cond.L.Lock()
160                 defer c.cond.L.Unlock()
161                 for c.bestNode.Height < height {
162                         c.cond.Wait()
163                 }
164                 ch <- struct{}{}
165         }()
166
167         return ch
168 }
169
170 // GetTxPool return chain txpool.
171 func (c *Chain) GetTxPool() *TxPool {
172         return c.txPool
173 }