github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/casper/casper.go (about)

     1  package casper
     2  
     3  import (
     4  	"sync"
     5  
     6  	log "github.com/sirupsen/logrus"
     7  
     8  	"github.com/bytom/bytom/common"
     9  	"github.com/bytom/bytom/consensus"
    10  	"github.com/bytom/bytom/errors"
    11  	"github.com/bytom/bytom/protocol/bc"
    12  	"github.com/bytom/bytom/protocol/state"
    13  )
    14  
    15  var (
    16  	logModule = "casper"
    17  
    18  	errPubKeyIsNotValidator     = errors.New("pub key is not in validators of target checkpoint")
    19  	errVoteToGrowingCheckpoint  = errors.New("validator publish vote to growing checkpoint")
    20  	errVoteToSameCheckpoint     = errors.New("source height and target height in verification is equals")
    21  	errSameHeightInVerification = errors.New("validator publish two distinct votes for the same target height")
    22  	errSpanHeightInVerification = errors.New("validator publish vote within the span of its other votes")
    23  )
    24  
    25  // RollbackMsg sent the rollback msg to chain core
    26  type RollbackMsg struct {
    27  	BestHash bc.Hash
    28  	Reply    chan error
    29  }
    30  
    31  type msgQueue interface {
    32  	Post(interface{}) error
    33  }
    34  
    35  // Casper is BFT based proof of stack consensus algorithm, it provides safety and liveness in theory,
    36  // it's design mainly refers to https://github.com/ethereum/research/blob/master/papers/casper-basics/casper_basics.pdf
    37  type Casper struct {
    38  	mu       sync.RWMutex
    39  	store    state.Store
    40  	msgQueue msgQueue
    41  	tree     *treeNode
    42  
    43  	// block hash -> previous checkpoint hash
    44  	prevCheckpointCache *common.Cache
    45  	// block hash + pubKey -> verification
    46  	verificationCache *common.Cache
    47  
    48  	rollbackCh chan *RollbackMsg
    49  	newEpochCh chan bc.Hash
    50  }
    51  
    52  // NewCasper create a new instance of Casper
    53  // argument checkpoints load the checkpoints from leveldb
    54  // the first element of checkpoints must genesis checkpoint or the last finalized checkpoint in order to reduce memory space
    55  // the others must be successors of first one
    56  func NewCasper(store state.Store, queue msgQueue, checkpoints []*state.Checkpoint) *Casper {
    57  	if checkpoints[0].Height != 0 && checkpoints[0].Status != state.Finalized {
    58  		log.WithFields(log.Fields{"module": logModule}).Panic("first element of checkpoints must genesis or in finalized status")
    59  	}
    60  
    61  	casper := &Casper{
    62  		store:               store,
    63  		msgQueue:            queue,
    64  		tree:                makeTree(checkpoints[0], checkpoints[1:]),
    65  		prevCheckpointCache: common.NewCache(1024),
    66  		verificationCache:   common.NewCache(1024),
    67  		rollbackCh:          make(chan *RollbackMsg, 64),
    68  		newEpochCh:          make(chan bc.Hash, 64),
    69  	}
    70  	go casper.authVerificationLoop()
    71  	return casper
    72  }
    73  
    74  // LastFinalized return the block height and block hash which is finalized at last
    75  func (c *Casper) LastFinalized() (uint64, bc.Hash) {
    76  	c.mu.RLock()
    77  	defer c.mu.RUnlock()
    78  
    79  	root := c.tree.Checkpoint
    80  	return root.Height, root.Hash
    81  }
    82  
    83  // LastJustified return the block height and block hash which is justified at last
    84  func (c *Casper) LastJustified() (uint64, bc.Hash) {
    85  	c.mu.RLock()
    86  	defer c.mu.RUnlock()
    87  	node := c.tree.lastJustified()
    88  	return node.Height, node.Hash
    89  }
    90  
    91  func (c *Casper) RollbackCh() <-chan *RollbackMsg {
    92  	return c.rollbackCh
    93  }
    94  
    95  // Validators return the validators by specified block hash
    96  // e.g. if the block num of epoch is 100, and the block height corresponding to the block hash is 130, then will return the voting results of height in 0~100
    97  func (c *Casper) validators(blockHash *bc.Hash) (map[string]*state.Validator, error) {
    98  	checkpoint, err := c.ParentCheckpoint(blockHash)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return checkpoint.EffectiveValidators(), nil
   104  }
   105  
   106  func (c *Casper) ParentCheckpoint(blockHash *bc.Hash) (*state.Checkpoint, error) {
   107  	hash, err := c.parentCheckpointHash(blockHash)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	return c.store.GetCheckpoint(hash)
   113  }
   114  
   115  func (c *Casper) ParentCheckpointByPrevHash(prevBlockHash *bc.Hash) (*state.Checkpoint, error) {
   116  	hash, err := c.parentCheckpointHashByPrevHash(prevBlockHash)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	return c.store.GetCheckpoint(hash)
   122  }
   123  
   124  func (c *Casper) BestChain() bc.Hash {
   125  	c.mu.RLock()
   126  	defer c.mu.RUnlock()
   127  	return c.bestChain()
   128  }
   129  
   130  func (c *Casper) bestChain() bc.Hash {
   131  	// root is init justified
   132  	bestNode, _ := c.tree.bestNode(c.tree.Height)
   133  	return bestNode.Hash
   134  }
   135  
   136  func (c *Casper) parentCheckpointHash(blockHash *bc.Hash) (*bc.Hash, error) {
   137  	if data, ok := c.prevCheckpointCache.Get(*blockHash); ok {
   138  		return data.(*bc.Hash), nil
   139  	}
   140  
   141  	block, err := c.store.GetBlockHeader(blockHash)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	result, err := c.parentCheckpointHashByPrevHash(&block.PreviousBlockHash)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	c.prevCheckpointCache.Add(*blockHash, result)
   152  	return result, nil
   153  }
   154  
   155  func (c *Casper) parentCheckpointHashByPrevHash(prevBlockHash *bc.Hash) (*bc.Hash, error) {
   156  	for iterHash := prevBlockHash; ; {
   157  		block, err := c.store.GetBlockHeader(iterHash)
   158  		if err != nil {
   159  			return nil, err
   160  		}
   161  
   162  		if mod := block.Height % consensus.ActiveNetParams.BlocksOfEpoch; mod == 0 {
   163  			return iterHash, nil
   164  		} else if mod == 1 {
   165  			return &block.PreviousBlockHash, nil
   166  		}
   167  
   168  		if data, ok := c.prevCheckpointCache.Get(*iterHash); ok {
   169  			c.prevCheckpointCache.Add(*prevBlockHash, data)
   170  			return data.(*bc.Hash), nil
   171  		}
   172  
   173  		iterHash = &block.PreviousBlockHash
   174  	}
   175  }