"time"
"github.com/bytom/blockchain/txdb"
+ "github.com/bytom/blockchain/txdb/storage"
"github.com/bytom/errors"
"github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/legacy"
GetBlock(*bc.Hash) (*legacy.Block, error)
GetMainchain(*bc.Hash) (map[uint64]*bc.Hash, error)
- GetSnapshot(*bc.Hash) (*state.Snapshot, error)
GetStoreStatus() txdb.BlockStoreStateJSON
+ GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error)
+ GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error
+ GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)
- SaveBlock(*legacy.Block) error
- SaveMainchain(map[uint64]*bc.Hash, *bc.Hash) error
- SaveSnapshot(*state.Snapshot, *bc.Hash) error
- SaveStoreStatus(uint64, *bc.Hash)
+ SaveBlock(*legacy.Block, *bc.TransactionStatus) error
+ SaveChainStatus(*legacy.Block, *state.UtxoViewpoint, map[uint64]*bc.Hash) error
}
+// OrphanManage is use to handle all the orphan block
type OrphanManage struct {
//TODO: add orphan cached block limit
orphan map[bc.Hash]*legacy.Block
mtx sync.RWMutex
}
+// NewOrphanManage return a new orphan block
func NewOrphanManage() *OrphanManage {
return &OrphanManage{
orphan: make(map[bc.Hash]*legacy.Block),
}
}
+// BlockExist check is the block in OrphanManage
func (o *OrphanManage) BlockExist(hash *bc.Hash) bool {
o.mtx.RLock()
_, ok := o.orphan[*hash]
return ok
}
+// Add will add the block to OrphanManage
func (o *OrphanManage) Add(block *legacy.Block) {
blockHash := block.Hash()
o.mtx.Lock()
o.preOrphans[block.PreviousBlockHash] = append(o.preOrphans[block.PreviousBlockHash], &blockHash)
}
+// Delete will delelte the block from OrphanManage
func (o *OrphanManage) Delete(hash *bc.Hash) {
o.mtx.Lock()
defer o.mtx.Unlock()
}
}
+// Get return the orphan block by hash
func (o *OrphanManage) Get(hash *bc.Hash) (*legacy.Block, bool) {
o.mtx.RLock()
block, ok := o.orphan[*hash]
state struct {
cond sync.Cond
block *legacy.Block
- height uint64
hash *bc.Hash
mainChain map[uint64]*bc.Hash
- snapshot *state.Snapshot
}
store Store
}
}
c.state.cond.L = new(sync.Mutex)
storeStatus := store.GetStoreStatus()
- c.state.height = storeStatus.Height
- if c.state.height == 0 {
- c.state.snapshot = state.Empty()
+ if storeStatus.Hash == nil {
c.state.mainChain = make(map[uint64]*bc.Hash)
return c, nil
}
if c.state.block, err = store.GetBlock(storeStatus.Hash); err != nil {
return nil, err
}
- if c.state.snapshot, err = store.GetSnapshot(storeStatus.Hash); err != nil {
- return nil, err
- }
if c.state.mainChain, err = store.GetMainchain(storeStatus.Hash); err != nil {
return nil, err
}
func (c *Chain) Height() uint64 {
c.state.cond.L.Lock()
defer c.state.cond.L.Unlock()
- return c.state.height
+ if c.state.block == nil {
+ return 0
+ }
+ return c.state.block.Height
+}
+
+// BestBlockHash return the hash of the chain tail block
+func (c *Chain) BestBlockHash() *bc.Hash {
+ c.state.cond.L.Lock()
+ defer c.state.cond.L.Unlock()
+ return c.state.hash
}
func (c *Chain) inMainchain(block *legacy.Block) bool {
return *hash == block.Hash()
}
-// TimestampMS returns the latest known block timestamp.
-func (c *Chain) TimestampMS() uint64 {
+// InMainChain checks wheather a block is in the main chain
+func (c *Chain) InMainChain(height uint64, hash bc.Hash) bool {
+ c.state.cond.L.Lock()
+ h, ok := c.state.mainChain[height]
+ c.state.cond.L.Unlock()
+ if !ok {
+ return false
+ }
+
+ return *h == hash
+}
+
+// Timestamp returns the latest known block timestamp.
+func (c *Chain) Timestamp() uint64 {
c.state.cond.L.Lock()
defer c.state.cond.L.Unlock()
if c.state.block == nil {
return 0
}
- return c.state.block.TimestampMS
+ return c.state.block.Timestamp
}
-// State returns the most recent state available. It will not be current
-// unless the current process is the leader. Callers should examine the
-// returned block header's height if they need to verify the current state.
-func (c *Chain) State() (*legacy.Block, *state.Snapshot) {
+// BestBlock returns the chain tail block
+func (c *Chain) BestBlock() *legacy.Block {
c.state.cond.L.Lock()
defer c.state.cond.L.Unlock()
- return c.state.block, c.state.snapshot
+ return c.state.block
}
-// This function must be called with mu lock in above level
-func (c *Chain) setState(block *legacy.Block, s *state.Snapshot, m map[uint64]*bc.Hash) error {
- if block.AssetsMerkleRoot != s.Tree.RootHash() {
- return ErrBadStateRoot
- }
+// GetUtxo try to find the utxo status in db
+func (c *Chain) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) {
+ return c.store.GetUtxo(hash)
+}
+// GetTransactionStatus return the transaction status of give block
+func (c *Chain) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
+ return c.store.GetTransactionStatus(hash)
+}
+
+// GetTransactionsUtxo return all the utxos that related to the txs' inputs
+func (c *Chain) GetTransactionsUtxo(view *state.UtxoViewpoint, txs []*bc.Tx) error {
+ return c.store.GetTransactionsUtxo(view, txs)
+}
+
+// This function must be called with mu lock in above level
+func (c *Chain) setState(block *legacy.Block, view *state.UtxoViewpoint, m map[uint64]*bc.Hash) error {
blockHash := block.Hash()
c.state.block = block
- c.state.height = block.Height
c.state.hash = &blockHash
- c.state.snapshot = s
for k, v := range m {
c.state.mainChain[k] = v
}
- if err := c.store.SaveSnapshot(c.state.snapshot, &blockHash); err != nil {
- return err
- }
- if err := c.store.SaveMainchain(c.state.mainChain, &blockHash); err != nil {
+ if err := c.store.SaveChainStatus(block, view, c.state.mainChain); err != nil {
return err
}
- c.store.SaveStoreStatus(block.Height, &blockHash)
c.state.cond.Broadcast()
return nil
go func() {
c.state.cond.L.Lock()
defer c.state.cond.L.Unlock()
- for c.state.height < height {
+ for c.state.block.Height < height {
c.state.cond.Wait()
}
ch <- struct{}{}