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"
16 // maxCachedValidatedTxs is the max number of validated txs to cache.
17 const maxCachedValidatedTxs = 1000
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")
25 // Store provides storage for blockchain data: blocks and state tree
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
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)
42 SaveBlock(*legacy.Block, *bc.TransactionStatus) error
43 SaveChainStatus(*legacy.Block, *state.UtxoViewpoint, map[uint64]*bc.Hash) error
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
54 // NewOrphanManage return a new orphan block
55 func NewOrphanManage() *OrphanManage {
57 orphan: make(map[bc.Hash]*legacy.Block),
58 preOrphans: make(map[bc.Hash][]*bc.Hash),
62 // BlockExist check is the block in OrphanManage
63 func (o *OrphanManage) BlockExist(hash *bc.Hash) bool {
65 _, ok := o.orphan[*hash]
70 // Add will add the block to OrphanManage
71 func (o *OrphanManage) Add(block *legacy.Block) {
72 blockHash := block.Hash()
76 if _, ok := o.orphan[blockHash]; ok {
80 o.orphan[blockHash] = block
81 o.preOrphans[block.PreviousBlockHash] = append(o.preOrphans[block.PreviousBlockHash], &blockHash)
84 // Delete will delelte the block from OrphanManage
85 func (o *OrphanManage) Delete(hash *bc.Hash) {
88 block, ok := o.orphan[*hash]
92 delete(o.orphan, *hash)
94 preOrphans, ok := o.preOrphans[block.PreviousBlockHash]
95 if !ok || len(preOrphans) == 1 {
96 delete(o.preOrphans, block.PreviousBlockHash)
100 for i, preOrphan := range preOrphans {
101 if preOrphan == hash {
102 o.preOrphans[block.PreviousBlockHash] = append(preOrphans[:i], preOrphans[i+1:]...)
108 // Get return the orphan block by hash
109 func (o *OrphanManage) Get(hash *bc.Hash) (*legacy.Block, bool) {
111 block, ok := o.orphan[*hash]
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.
121 InitialBlockHash bc.Hash
122 MaxIssuanceWindow time.Duration // only used by generators
124 orphanManage *OrphanManage
131 mainChain map[uint64]*bc.Hash
136 // NewChain returns a new Chain using store as the underlying storage.
137 func NewChain(initialBlockHash bc.Hash, store Store, txPool *TxPool) (*Chain, error) {
139 InitialBlockHash: initialBlockHash,
140 orphanManage: NewOrphanManage(),
144 c.state.cond.L = new(sync.Mutex)
145 storeStatus := store.GetStoreStatus()
147 if storeStatus.Hash == nil {
148 c.state.mainChain = make(map[uint64]*bc.Hash)
152 c.state.hash = storeStatus.Hash
154 if c.state.block, err = store.GetBlock(storeStatus.Hash); err != nil {
157 if c.state.mainChain, err = store.GetMainchain(storeStatus.Hash); err != nil {
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 {
170 return c.state.block.Height
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()
180 func (c *Chain) inMainchain(block *legacy.Block) bool {
181 hash, ok := c.state.mainChain[block.Height]
185 return *hash == block.Hash()
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()
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 {
207 return c.state.block.Timestamp
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()
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)
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)
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)
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
241 if err := c.store.SaveChainStatus(block, view, c.state.mainChain); err != nil {
245 c.state.cond.Broadcast()
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)
259 if height > c.Height()+slop {
260 ch <- ErrTheDistantFuture
265 case <-c.BlockWaiter(height):
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)
280 c.state.cond.L.Lock()
281 defer c.state.cond.L.Unlock()
282 for c.state.block.Height < height {