OSDN Git Service

Mining pool (#403)
[bytom/bytom.git] / protocol / protocol.go
1 package protocol
2
3 import (
4         "context"
5         "sync"
6         "time"
7
8         "github.com/bytom/blockchain/txdb"
9         "github.com/bytom/blockchain/txdb/storage"
10         "github.com/bytom/errors"
11         "github.com/bytom/protocol/bc"
12         "github.com/bytom/protocol/bc/legacy"
13         "github.com/bytom/protocol/state"
14 )
15
16 // maxCachedValidatedTxs is the max number of validated txs to cache.
17 const maxCachedValidatedTxs = 1000
18
19 var (
20         // ErrTheDistantFuture is returned when waiting for a blockheight
21         // too far in excess of the tip of the blockchain.
22         ErrTheDistantFuture = errors.New("block height too far in future")
23 )
24
25 // Store provides storage for blockchain data: blocks and state tree
26 // snapshots.
27 //
28 // Note, this is different from a state snapshot. A state snapshot
29 // provides access to the state at a given point in time -- outputs
30 // and issuance memory. The Chain type uses Store to load state
31 // from storage and persist validated data.
32 type Store interface {
33         BlockExist(*bc.Hash) bool
34
35         GetBlock(*bc.Hash) (*legacy.Block, error)
36         GetMainchain(*bc.Hash) (map[uint64]*bc.Hash, error)
37         GetStoreStatus() txdb.BlockStoreStateJSON
38         GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error)
39         GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error
40         GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)
41
42         SaveBlock(*legacy.Block, *bc.TransactionStatus) error
43         SaveChainStatus(*legacy.Block, *state.UtxoViewpoint, map[uint64]*bc.Hash) error
44 }
45
46 // OrphanManage is use to handle all the orphan block
47 type OrphanManage struct {
48         //TODO: add orphan cached block limit
49         orphan     map[bc.Hash]*legacy.Block
50         preOrphans map[bc.Hash][]*bc.Hash
51         mtx        sync.RWMutex
52 }
53
54 // NewOrphanManage return a new orphan block
55 func NewOrphanManage() *OrphanManage {
56         return &OrphanManage{
57                 orphan:     make(map[bc.Hash]*legacy.Block),
58                 preOrphans: make(map[bc.Hash][]*bc.Hash),
59         }
60 }
61
62 // BlockExist check is the block in OrphanManage
63 func (o *OrphanManage) BlockExist(hash *bc.Hash) bool {
64         o.mtx.RLock()
65         _, ok := o.orphan[*hash]
66         o.mtx.RUnlock()
67         return ok
68 }
69
70 // Add will add the block to OrphanManage
71 func (o *OrphanManage) Add(block *legacy.Block) {
72         blockHash := block.Hash()
73         o.mtx.Lock()
74         defer o.mtx.Unlock()
75
76         if _, ok := o.orphan[blockHash]; ok {
77                 return
78         }
79
80         o.orphan[blockHash] = block
81         o.preOrphans[block.PreviousBlockHash] = append(o.preOrphans[block.PreviousBlockHash], &blockHash)
82 }
83
84 // Delete will delelte the block from OrphanManage
85 func (o *OrphanManage) Delete(hash *bc.Hash) {
86         o.mtx.Lock()
87         defer o.mtx.Unlock()
88         block, ok := o.orphan[*hash]
89         if !ok {
90                 return
91         }
92         delete(o.orphan, *hash)
93
94         preOrphans, ok := o.preOrphans[block.PreviousBlockHash]
95         if !ok || len(preOrphans) == 1 {
96                 delete(o.preOrphans, block.PreviousBlockHash)
97                 return
98         }
99
100         for i, preOrphan := range preOrphans {
101                 if preOrphan == hash {
102                         o.preOrphans[block.PreviousBlockHash] = append(preOrphans[:i], preOrphans[i+1:]...)
103                         return
104                 }
105         }
106 }
107
108 // Get return the orphan block by hash
109 func (o *OrphanManage) Get(hash *bc.Hash) (*legacy.Block, bool) {
110         o.mtx.RLock()
111         block, ok := o.orphan[*hash]
112         o.mtx.RUnlock()
113         return block, ok
114 }
115
116 // Chain provides a complete, minimal blockchain database. It
117 // delegates the underlying storage to other objects, and uses
118 // validation logic from package validation to decide what
119 // objects can be safely stored.
120 type Chain struct {
121         InitialBlockHash  bc.Hash
122         MaxIssuanceWindow time.Duration // only used by generators
123
124         orphanManage *OrphanManage
125         txPool       *TxPool
126
127         state struct {
128                 cond      sync.Cond
129                 block     *legacy.Block
130                 hash      *bc.Hash
131                 mainChain map[uint64]*bc.Hash
132         }
133         store Store
134 }
135
136 // NewChain returns a new Chain using store as the underlying storage.
137 func NewChain(initialBlockHash bc.Hash, store Store, txPool *TxPool) (*Chain, error) {
138         c := &Chain{
139                 InitialBlockHash: initialBlockHash,
140                 orphanManage:     NewOrphanManage(),
141                 store:            store,
142                 txPool:           txPool,
143         }
144         c.state.cond.L = new(sync.Mutex)
145         storeStatus := store.GetStoreStatus()
146
147         if storeStatus.Hash == nil {
148                 c.state.mainChain = make(map[uint64]*bc.Hash)
149                 return c, nil
150         }
151
152         c.state.hash = storeStatus.Hash
153         var err error
154         if c.state.block, err = store.GetBlock(storeStatus.Hash); err != nil {
155                 return nil, err
156         }
157         if c.state.mainChain, err = store.GetMainchain(storeStatus.Hash); err != nil {
158                 return nil, err
159         }
160         return c, nil
161 }
162
163 // Height returns the current height of the blockchain.
164 func (c *Chain) Height() uint64 {
165         c.state.cond.L.Lock()
166         defer c.state.cond.L.Unlock()
167         if c.state.block == nil {
168                 return 0
169         }
170         return c.state.block.Height
171 }
172
173 // BestBlockHash return the hash of the chain tail block
174 func (c *Chain) BestBlockHash() *bc.Hash {
175         c.state.cond.L.Lock()
176         defer c.state.cond.L.Unlock()
177         return c.state.hash
178 }
179
180 func (c *Chain) inMainchain(block *legacy.Block) bool {
181         hash, ok := c.state.mainChain[block.Height]
182         if !ok {
183                 return false
184         }
185         return *hash == block.Hash()
186 }
187
188 // InMainChain checks wheather a block is in the main chain
189 func (c *Chain) InMainChain(height uint64, hash bc.Hash) bool {
190         c.state.cond.L.Lock()
191         h, ok := c.state.mainChain[height]
192         c.state.cond.L.Unlock()
193         if !ok {
194                 return false
195         }
196
197         return *h == hash
198 }
199
200 // Timestamp returns the latest known block timestamp.
201 func (c *Chain) Timestamp() uint64 {
202         c.state.cond.L.Lock()
203         defer c.state.cond.L.Unlock()
204         if c.state.block == nil {
205                 return 0
206         }
207         return c.state.block.Timestamp
208 }
209
210 // BestBlock returns the chain tail block
211 func (c *Chain) BestBlock() *legacy.Block {
212         c.state.cond.L.Lock()
213         defer c.state.cond.L.Unlock()
214         return c.state.block
215 }
216
217 // GetUtxo try to find the utxo status in db
218 func (c *Chain) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
219         return c.store.GetUtxo(hash)
220 }
221
222 // GetTransactionStatus return the transaction status of give block
223 func (c *Chain) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
224         return c.store.GetTransactionStatus(hash)
225 }
226
227 // GetTransactionsUtxo return all the utxos that related to the txs' inputs
228 func (c *Chain) GetTransactionsUtxo(view *state.UtxoViewpoint, txs []*bc.Tx) error {
229         return c.store.GetTransactionsUtxo(view, txs)
230 }
231
232 // This function must be called with mu lock in above level
233 func (c *Chain) setState(block *legacy.Block, view *state.UtxoViewpoint, m map[uint64]*bc.Hash) error {
234         blockHash := block.Hash()
235         c.state.block = block
236         c.state.hash = &blockHash
237         for k, v := range m {
238                 c.state.mainChain[k] = v
239         }
240
241         if err := c.store.SaveChainStatus(block, view, c.state.mainChain); err != nil {
242                 return err
243         }
244
245         c.state.cond.Broadcast()
246         return nil
247 }
248
249 // BlockSoonWaiter returns a channel that
250 // waits for the block at the given height,
251 // but it is an error to wait for a block far in the future.
252 // WaitForBlockSoon will timeout if the context times out.
253 // To wait unconditionally, the caller should use WaitForBlock.
254 func (c *Chain) BlockSoonWaiter(ctx context.Context, height uint64) <-chan error {
255         ch := make(chan error, 1)
256
257         go func() {
258                 const slop = 3
259                 if height > c.Height()+slop {
260                         ch <- ErrTheDistantFuture
261                         return
262                 }
263
264                 select {
265                 case <-c.BlockWaiter(height):
266                         ch <- nil
267                 case <-ctx.Done():
268                         ch <- ctx.Err()
269                 }
270         }()
271
272         return ch
273 }
274
275 // BlockWaiter returns a channel that
276 // waits for the block at the given height.
277 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
278         ch := make(chan struct{}, 1)
279         go func() {
280                 c.state.cond.L.Lock()
281                 defer c.state.cond.L.Unlock()
282                 for c.state.block.Height < height {
283                         c.state.cond.Wait()
284                 }
285                 ch <- struct{}{}
286         }()
287
288         return ch
289 }