github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/protocol.go (about)

     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 current height of the blockchain.
    89  func (c *Chain) BestBlockHeight() uint64 {
    90  	c.cond.L.Lock()
    91  	defer c.cond.L.Unlock()
    92  	return c.bestNode.Height
    93  }
    94  
    95  // BestBlockHash return the hash of the chain tail block
    96  func (c *Chain) BestBlockHash() *bc.Hash {
    97  	c.cond.L.Lock()
    98  	defer c.cond.L.Unlock()
    99  	return &c.bestNode.Hash
   100  }
   101  
   102  // BestBlockHeader returns the chain tail block
   103  func (c *Chain) BestBlockHeader() *types.BlockHeader {
   104  	node := c.index.BestNode()
   105  	return node.BlockHeader()
   106  }
   107  
   108  // InMainChain checks wheather a block is in the main chain
   109  func (c *Chain) InMainChain(hash bc.Hash) bool {
   110  	return c.index.InMainchain(hash)
   111  }
   112  
   113  // CalcNextSeed return the seed for the given block
   114  func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) {
   115  	node := c.index.GetNode(preBlock)
   116  	if node == nil {
   117  		return nil, errors.New("can't find preblock in the blockindex")
   118  	}
   119  	return node.CalcNextSeed(), nil
   120  }
   121  
   122  // CalcNextBits return the seed for the given block
   123  func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) {
   124  	node := c.index.GetNode(preBlock)
   125  	if node == nil {
   126  		return 0, errors.New("can't find preblock in the blockindex")
   127  	}
   128  	return node.CalcNextBits(), nil
   129  }
   130  
   131  func (c *Chain) GetBlockIndex() *state.BlockIndex {
   132  	return c.index
   133  }
   134  
   135  // This function must be called with mu lock in above level
   136  func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
   137  	if err := c.store.SaveChainStatus(node, view); err != nil {
   138  		return err
   139  	}
   140  
   141  	c.cond.L.Lock()
   142  	defer c.cond.L.Unlock()
   143  
   144  	c.index.SetMainChain(node)
   145  	c.bestNode = node
   146  
   147  	log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
   148  	c.cond.Broadcast()
   149  	return nil
   150  }
   151  
   152  // BlockWaiter returns a channel that waits for the block at the given height.
   153  func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
   154  	ch := make(chan struct{}, 1)
   155  	go func() {
   156  		c.cond.L.Lock()
   157  		defer c.cond.L.Unlock()
   158  		for c.bestNode.Height < height {
   159  			c.cond.Wait()
   160  		}
   161  		ch <- struct{}{}
   162  	}()
   163  
   164  	return ch
   165  }
   166  
   167  // GetTxPool return chain txpool.
   168  func (c *Chain) GetTxPool() *TxPool {
   169  	return c.txPool
   170  }