github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/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/event"
    10  	"github.com/bytom/bytom/protocol/bc"
    11  	"github.com/bytom/bytom/protocol/bc/types"
    12  	"github.com/bytom/bytom/protocol/casper"
    13  	"github.com/bytom/bytom/protocol/state"
    14  )
    15  
    16  const (
    17  	maxProcessBlockChSize = 1024
    18  )
    19  
    20  // Chain provides functions for working with the Bytom block chain.
    21  type Chain struct {
    22  	orphanManage    *OrphanManage
    23  	txPool          *TxPool
    24  	store           state.Store
    25  	casper          *casper.Casper
    26  	processBlockCh  chan *processBlockMsg
    27  	eventDispatcher *event.Dispatcher
    28  
    29  	cond            sync.Cond
    30  	bestBlockHeader *types.BlockHeader // the last block on current main chain
    31  }
    32  
    33  // NewChain returns a new Chain using store as the underlying storage.
    34  func NewChain(store state.Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
    35  	return NewChainWithOrphanManage(store, txPool, NewOrphanManage(), eventDispatcher)
    36  }
    37  
    38  func NewChainWithOrphanManage(store state.Store, txPool *TxPool, manage *OrphanManage, eventDispatcher *event.Dispatcher) (*Chain, error) {
    39  	c := &Chain{
    40  		orphanManage:    manage,
    41  		eventDispatcher: eventDispatcher,
    42  		txPool:          txPool,
    43  		store:           store,
    44  		processBlockCh:  make(chan *processBlockMsg, maxProcessBlockChSize),
    45  	}
    46  	c.cond.L = new(sync.Mutex)
    47  
    48  	storeStatus := store.GetStoreStatus()
    49  	if storeStatus == nil {
    50  		if err := c.initChainStatus(); err != nil {
    51  			return nil, err
    52  		}
    53  		storeStatus = store.GetStoreStatus()
    54  	}
    55  
    56  	var err error
    57  	c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	casper, err := newCasper(store, eventDispatcher, storeStatus)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	c.casper = casper
    68  	go c.blockProcessor()
    69  	return c, nil
    70  }
    71  
    72  func (c *Chain) initChainStatus() error {
    73  	genesisBlock := config.GenesisBlock()
    74  	if err := c.store.SaveBlock(genesisBlock); err != nil {
    75  		return err
    76  	}
    77  
    78  	checkpoint := &state.Checkpoint{
    79  		Height:    0,
    80  		Hash:      genesisBlock.Hash(),
    81  		Timestamp: genesisBlock.Timestamp,
    82  		Status:    state.Justified,
    83  	}
    84  
    85  	if err := c.store.SaveCheckpoints([]*state.Checkpoint{checkpoint}); err != nil {
    86  		return err
    87  	}
    88  
    89  	utxoView := state.NewUtxoViewpoint()
    90  	bcBlock := types.MapBlock(genesisBlock)
    91  	if err := utxoView.ApplyBlock(bcBlock); err != nil {
    92  		return err
    93  	}
    94  
    95  	contractView := state.NewContractViewpoint()
    96  	genesisBlockHeader := &genesisBlock.BlockHeader
    97  	return c.store.SaveChainStatus(genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, contractView, 0, &checkpoint.Hash)
    98  }
    99  
   100  func newCasper(store state.Store, e *event.Dispatcher, storeStatus *state.BlockStoreState) (*casper.Casper, error) {
   101  	checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	return casper.NewCasper(store, e, checkpoints), nil
   107  }
   108  
   109  // LastJustifiedHeader return the last justified block header of the block chain
   110  func (c *Chain) LastJustifiedHeader() (*types.BlockHeader, error) {
   111  	_, hash := c.casper.LastJustified()
   112  	return c.store.GetBlockHeader(&hash)
   113  }
   114  
   115  // LastFinalizedHeader return the last finalized block header of the block chain
   116  func (c *Chain) LastFinalizedHeader() (*types.BlockHeader, error) {
   117  	_, hash := c.casper.LastFinalized()
   118  	return c.store.GetBlockHeader(&hash)
   119  }
   120  
   121  // ProcessBlockVerification process block verification
   122  func (c *Chain) ProcessBlockVerification(v *casper.ValidCasperSignMsg) error {
   123  	return c.casper.AuthVerification(v)
   124  }
   125  
   126  // BestBlockHeight returns the current height of the blockchain.
   127  func (c *Chain) BestBlockHeight() uint64 {
   128  	c.cond.L.Lock()
   129  	defer c.cond.L.Unlock()
   130  	return c.bestBlockHeader.Height
   131  }
   132  
   133  // BestBlockHash return the hash of the chain tail block
   134  func (c *Chain) BestBlockHash() *bc.Hash {
   135  	c.cond.L.Lock()
   136  	defer c.cond.L.Unlock()
   137  	bestHash := c.bestBlockHeader.Hash()
   138  	return &bestHash
   139  }
   140  
   141  // BestChain return the current height and block hash of the chain
   142  func (c *Chain) BestChain() (uint64, bc.Hash) {
   143  	c.cond.L.Lock()
   144  	defer c.cond.L.Unlock()
   145  	return c.bestBlockHeader.Height, c.bestBlockHeader.Hash()
   146  }
   147  
   148  func (c *Chain) FinalizedHeight() uint64 {
   149  	finalizedHeight, _ := c.casper.LastFinalized()
   150  	return finalizedHeight
   151  }
   152  
   153  // AllValidators return all validators has vote num
   154  func (c *Chain) AllValidators(blockHash *bc.Hash) ([]*state.Validator, error) {
   155  	parentCheckpoint, err := c.casper.ParentCheckpoint(blockHash)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	return parentCheckpoint.AllValidators(), nil
   161  }
   162  
   163  // GetValidator return validator by specified blockHash and timestamp
   164  func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
   165  	parentCheckpoint, err := c.casper.ParentCheckpointByPrevHash(prevHash)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	return parentCheckpoint.GetValidator(timeStamp), nil
   171  }
   172  
   173  // BestBlockHeader returns the chain tail block
   174  func (c *Chain) BestBlockHeader() *types.BlockHeader {
   175  	c.cond.L.Lock()
   176  	defer c.cond.L.Unlock()
   177  	return c.bestBlockHeader
   178  }
   179  
   180  // InMainChain checks wheather a block is in the main chain
   181  func (c *Chain) InMainChain(hash bc.Hash) bool {
   182  	blockHeader, err := c.store.GetBlockHeader(&hash)
   183  	if err != nil {
   184  		return false
   185  	}
   186  
   187  	blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
   188  	if err != nil {
   189  		log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
   190  		return false
   191  	}
   192  	return *blockHash == hash
   193  }
   194  
   195  func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
   196  	xprv := config.CommonConfig.PrivateKey()
   197  	signature := xprv.Sign(blockHeader.Hash().Bytes())
   198  	blockHeader.Set(signature)
   199  }
   200  
   201  // This function must be called with mu lock in above level
   202  func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
   203  	finalizedHeight, finalizedHash := c.casper.LastFinalized()
   204  	if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
   205  		return err
   206  	}
   207  
   208  	c.cond.L.Lock()
   209  	defer c.cond.L.Unlock()
   210  
   211  	c.bestBlockHeader = blockHeader
   212  
   213  	hash := c.bestBlockHeader.Hash()
   214  	log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
   215  	c.cond.Broadcast()
   216  	return nil
   217  }
   218  
   219  // BlockWaiter returns a channel that waits for the block at the given height.
   220  func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
   221  	ch := make(chan struct{}, 1)
   222  	go func() {
   223  		c.cond.L.Lock()
   224  		defer c.cond.L.Unlock()
   225  		for c.bestBlockHeader.Height < height {
   226  			c.cond.Wait()
   227  		}
   228  		ch <- struct{}{}
   229  	}()
   230  
   231  	return ch
   232  }
   233  
   234  // GetTxPool return chain txpool.
   235  func (c *Chain) GetTxPool() *TxPool {
   236  	return c.txPool
   237  }
   238  
   239  // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
   240  func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
   241  	return c.casper.ParentCheckpointByPrevHash(preBlockHash)
   242  }