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

     1  package casper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	log "github.com/sirupsen/logrus"
     7  
     8  	"github.com/bytom/bytom/errors"
     9  	"github.com/bytom/bytom/protocol/bc"
    10  	"github.com/bytom/bytom/protocol/state"
    11  )
    12  
    13  // AuthVerification verify whether the Verification is legal.
    14  // the status of source checkpoint must justified, and an individual validator ν must not publish two distinct Verification
    15  // ⟨ν,s1,t1,h(s1),h(t1)⟩ and ⟨ν,s2,t2,h(s2),h(t2)⟩, such that either:
    16  // h(t1) = h(t2) OR h(s1) < h(s2) < h(t2) < h(t1)
    17  func (c *Casper) AuthVerification(msg *ValidCasperSignMsg) error {
    18  	c.mu.Lock()
    19  	defer c.mu.Unlock()
    20  	targetNode := c.tree.nodeByHash(msg.TargetHash)
    21  	if targetNode == nil {
    22  		c.verificationCache.Add(verificationCacheKey(msg.TargetHash, msg.PubKey), msg)
    23  		return nil
    24  	}
    25  
    26  	source, err := c.store.GetCheckpoint(&msg.SourceHash)
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	v, err := convertVerification(source, targetNode.Checkpoint, msg)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	if targetNode.ContainsVerification(v.order, &v.SourceHash) {
    37  		return nil
    38  	}
    39  
    40  	oldBestHash := c.bestChain()
    41  	if err := c.authVerification(v, targetNode.Checkpoint); err != nil {
    42  		return err
    43  	}
    44  
    45  	return c.tryRollback(oldBestHash)
    46  }
    47  
    48  func (c *Casper) authVerification(v *verification, target *state.Checkpoint) error {
    49  	if err := c.verifyVerification(v); err != nil {
    50  		return err
    51  	}
    52  
    53  	checkpoints, err := c.addVerificationToCheckpoint(target, v)
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	if err := c.msgQueue.Post(v.toValidCasperSignMsg()); err != nil {
    59  		return err
    60  	}
    61  
    62  	if err := c.store.SaveCheckpoints(checkpoints); err != nil {
    63  		return err
    64  	}
    65  
    66  	return c.saveVerificationToHeader(v)
    67  }
    68  
    69  func (c *Casper) addVerificationToCheckpoint(target *state.Checkpoint, verifications ...*verification) ([]*state.Checkpoint, error) {
    70  	validatorSize := len(target.Parent.EffectiveValidators())
    71  	affectedCheckpoints := []*state.Checkpoint{target}
    72  	for _, v := range verifications {
    73  		source, err := c.store.GetCheckpoint(&v.SourceHash)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  
    78  		supLink := target.AddVerification(v.SourceHash, v.SourceHeight, v.order, v.Signature)
    79  		if target.Status != state.Unjustified || !supLink.IsMajority(validatorSize) || source.Status == state.Finalized {
    80  			continue
    81  		}
    82  
    83  		c.setJustified(source, target)
    84  		affectedCheckpoints = append(affectedCheckpoints, source)
    85  	}
    86  	return affectedCheckpoints, nil
    87  }
    88  
    89  func (c *Casper) saveVerificationToHeader(v *verification) error {
    90  	blockHeader, err := c.store.GetBlockHeader(&v.TargetHash)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	blockHeader.SupLinks.AddSupLink(v.SourceHeight, v.SourceHash, v.Signature, v.order)
    96  	return c.store.SaveBlockHeader(blockHeader)
    97  }
    98  
    99  // source status is justified, and exist a super majority link from source to target
   100  func (c *Casper) setJustified(source, target *state.Checkpoint) {
   101  	target.Status = state.Justified
   102  	// must direct child
   103  	if target.ParentHash == source.Hash {
   104  		c.setFinalized(source)
   105  	}
   106  }
   107  
   108  func (c *Casper) setFinalized(checkpoint *state.Checkpoint) {
   109  	checkpoint.Status = state.Finalized
   110  	newRoot := c.tree.nodeByHash(checkpoint.Hash)
   111  	if newRoot == nil {
   112  		log.WithFields(log.Fields{"module": logModule, "hash": checkpoint.Hash}).Warn("source checkpoint before the last finalized checkpoint")
   113  		return
   114  	}
   115  
   116  	// update the checkpoint state in memory
   117  	newRoot.Status = state.Finalized
   118  	newRoot.Parent = nil
   119  	c.tree = newRoot
   120  }
   121  
   122  func (c *Casper) tryRollback(oldBestHash bc.Hash) error {
   123  	if newBestHash := c.bestChain(); oldBestHash != newBestHash {
   124  		msg := &RollbackMsg{BestHash: newBestHash, Reply: make(chan error)}
   125  		c.rollbackCh <- msg
   126  		return <-msg.Reply
   127  	}
   128  	return nil
   129  }
   130  
   131  func (c *Casper) authVerificationLoop() {
   132  	for blockHash := range c.newEpochCh {
   133  		validators, err := c.validators(&blockHash)
   134  		if err != nil {
   135  			log.WithFields(log.Fields{"err": err, "module": logModule}).Error("get validators when auth verification")
   136  			continue
   137  		}
   138  
   139  		for _, validator := range validators {
   140  			key := verificationCacheKey(blockHash, validator.PubKey)
   141  			data, ok := c.verificationCache.Get(key)
   142  			if !ok {
   143  				continue
   144  			}
   145  
   146  			if err := c.authCachedMsg(data.(*ValidCasperSignMsg), key); err != nil {
   147  				log.WithFields(log.Fields{"err": err, "module": logModule}).Error("auth cached message")
   148  			}
   149  		}
   150  	}
   151  }
   152  
   153  func (c *Casper) authCachedMsg(msg *ValidCasperSignMsg, msgKey string) error {
   154  	defer c.verificationCache.Remove(msgKey)
   155  
   156  	source, err := c.store.GetCheckpoint(&msg.SourceHash)
   157  	if err != nil {
   158  		return errors.Wrap(err, "get source checkpoint")
   159  	}
   160  
   161  	targetNode := c.tree.nodeByHash(msg.TargetHash)
   162  	if targetNode == nil {
   163  		return errors.New("get target checkpoint")
   164  	}
   165  
   166  	target := targetNode.Checkpoint
   167  	v, err := convertVerification(source, target, msg)
   168  	if err != nil {
   169  		return errors.Wrap(err, "authVerificationLoop fail on newVerification")
   170  	}
   171  
   172  	c.mu.Lock()
   173  	defer c.mu.Unlock()
   174  	return c.authVerification(v, target)
   175  }
   176  
   177  func (c *Casper) verifyVerification(v *verification) error {
   178  	if err := v.valid(); err != nil {
   179  		return err
   180  	}
   181  
   182  	if err := c.verifySameHeight(v); err != nil {
   183  		return err
   184  	}
   185  
   186  	return c.verifySpanHeight(v)
   187  }
   188  
   189  // a validator must not publish two distinct votes for the same target height
   190  func (c *Casper) verifySameHeight(v *verification) error {
   191  	checkpoints, err := c.store.GetCheckpointsByHeight(v.TargetHeight)
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	for _, checkpoint := range checkpoints {
   197  		for _, supLink := range checkpoint.SupLinks {
   198  			if len(supLink.Signatures[v.order]) != 0 && checkpoint.Hash != v.TargetHash {
   199  				return errSameHeightInVerification
   200  			}
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  // a validator must not vote within the span of its other votes.
   207  func (c *Casper) verifySpanHeight(v *verification) error {
   208  	if c.tree.findOnlyOne(func(checkpoint *state.Checkpoint) bool {
   209  		if checkpoint.Height == v.TargetHeight {
   210  			return false
   211  		}
   212  
   213  		for _, supLink := range checkpoint.SupLinks {
   214  			if len(supLink.Signatures[v.order]) != 0 {
   215  				if (checkpoint.Height < v.TargetHeight && supLink.SourceHeight > v.SourceHeight) ||
   216  					(checkpoint.Height > v.TargetHeight && supLink.SourceHeight < v.SourceHeight) {
   217  					return true
   218  				}
   219  			}
   220  		}
   221  		return false
   222  	}) != nil {
   223  		return errSpanHeightInVerification
   224  	}
   225  	return nil
   226  }
   227  
   228  func verificationCacheKey(blockHash bc.Hash, pubKey string) string {
   229  	return fmt.Sprintf("%s:%s", blockHash.String(), pubKey)
   230  }