OSDN Git Service

modify multi sign result for same password (#1232)
[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/config"
9         "github.com/bytom/errors"
10         "github.com/bytom/protocol/bc"
11         "github.com/bytom/protocol/bc/types"
12         "github.com/bytom/protocol/state"
13 )
14
15 const maxProcessBlockChSize = 1024
16
17 // ErrTheDistantFuture is returned when waiting for a blockheight too far in
18 // excess of the tip of the blockchain.
19 var ErrTheDistantFuture = errors.New("block height too far in future")
20
21 // Chain provides functions for working with the Bytom block chain.
22 type Chain struct {
23         index          *state.BlockIndex
24         orphanManage   *OrphanManage
25         txPool         *TxPool
26         store          Store
27         processBlockCh chan *processBlockMsg
28
29         cond     sync.Cond
30         bestNode *state.BlockNode
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(); 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                 txStatus.SetStatus(i, false)
67         }
68
69         if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil {
70                 return err
71         }
72
73         utxoView := state.NewUtxoViewpoint()
74         bcBlock := types.MapBlock(genesisBlock)
75         if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil {
76                 return err
77         }
78
79         node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
80         if err != nil {
81                 return err
82         }
83         return c.store.SaveChainStatus(node, utxoView)
84 }
85
86 // BestBlockHeight returns the current height of the blockchain.
87 func (c *Chain) BestBlockHeight() uint64 {
88         c.cond.L.Lock()
89         defer c.cond.L.Unlock()
90         return c.bestNode.Height
91 }
92
93 // BestBlockHash return the hash of the chain tail block
94 func (c *Chain) BestBlockHash() *bc.Hash {
95         c.cond.L.Lock()
96         defer c.cond.L.Unlock()
97         return &c.bestNode.Hash
98 }
99
100 // BestBlockHeader returns the chain tail block
101 func (c *Chain) BestBlockHeader() *types.BlockHeader {
102         node := c.index.BestNode()
103         return node.BlockHeader()
104 }
105
106 // InMainChain checks wheather a block is in the main chain
107 func (c *Chain) InMainChain(hash bc.Hash) bool {
108         return c.index.InMainchain(hash)
109 }
110
111 // CalcNextSeed return the seed for the given block
112 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
113         node := c.index.GetNode(preBlock)
114         if node == nil {
115                 return nil, errors.New("can't find preblock in the blockindex")
116         }
117         return node.CalcNextSeed(), nil
118 }
119
120 // CalcNextBits return the seed for the given block
121 func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) {
122         node := c.index.GetNode(preBlock)
123         if node == nil {
124                 return 0, errors.New("can't find preblock in the blockindex")
125         }
126         return node.CalcNextBits(), nil
127 }
128
129 // This function must be called with mu lock in above level
130 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
131         if err := c.store.SaveChainStatus(node, view); err != nil {
132                 return err
133         }
134
135         c.cond.L.Lock()
136         defer c.cond.L.Unlock()
137
138         c.index.SetMainChain(node)
139         c.bestNode = node
140
141         log.WithFields(log.Fields{"height": c.bestNode.Height, "hash": c.bestNode.Hash}).Debug("chain best status has been update")
142         c.cond.Broadcast()
143         return nil
144 }
145
146 // BlockWaiter returns a channel that waits for the block at the given height.
147 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
148         ch := make(chan struct{}, 1)
149         go func() {
150                 c.cond.L.Lock()
151                 defer c.cond.L.Unlock()
152                 for c.bestNode.Height < height {
153                         c.cond.Wait()
154                 }
155                 ch <- struct{}{}
156         }()
157
158         return ch
159 }
160
161 // GetTxPool return chain txpool.
162 func (c *Chain) GetTxPool() *TxPool {
163         return c.txPool
164 }