6 log "github.com/sirupsen/logrus"
8 "github.com/bytom/bytom/consensus"
9 "github.com/bytom/bytom/protocol/bc"
10 "github.com/bytom/bytom/protocol/bc/types"
11 "github.com/bytom/bytom/protocol/state"
14 // AuthVerification verify whether the Verification is legal.
15 // the status of source checkpoint must justified, and an individual validator ν must not publish two distinct Verification
16 // ⟨ν,s1,t1,h(s1),h(t1)⟩ and ⟨ν,s2,t2,h(s2),h(t2)⟩, such that either:
17 // h(t1) = h(t2) OR h(s1) < h(s2) < h(t2) < h(t1)
18 func (c *Casper) AuthVerification(v *Verification) error {
19 if err := validate(v); err != nil {
26 // root of tree is the last finalized checkpoint
27 if v.TargetHeight < c.tree.checkpoint.Height {
28 // discard the verification message which height of target less than height of last finalized checkpoint
29 // is for simplify check the vote within the span of its other votes
33 targetNode, err := c.tree.nodeByHash(v.TargetHash)
35 c.verificationCache.Add(verificationCacheKey(v.TargetHash, v.PubKey), v)
39 validators, err := c.Validators(&v.TargetHash)
44 if _, ok := validators[v.PubKey]; !ok {
45 return errPubKeyIsNotValidator
48 if targetNode.checkpoint.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
52 oldBestHash := c.bestChain()
53 if err := c.authVerification(v, targetNode.checkpoint, validators); err != nil {
57 return c.tryRollback(oldBestHash)
60 func (c *Casper) authVerification(v *Verification, target *state.Checkpoint, validators map[string]*state.Validator) error {
61 validator := validators[v.PubKey]
62 if err := c.verifyVerification(v, validator.Order, true); err != nil {
66 checkpoints, err := c.addVerificationToCheckpoint(target, validators, v)
71 if err := c.store.SaveCheckpoints(checkpoints); err != nil {
75 return c.saveVerificationToHeader(v, validator.Order)
78 func (c *Casper) addVerificationToCheckpoint(target *state.Checkpoint, validators map[string]*state.Validator, verifications ...*Verification) ([]*state.Checkpoint, error) {
79 affectedCheckpoints := []*state.Checkpoint{target}
80 for _, v := range verifications {
81 source, err := c.store.GetCheckpoint(&v.SourceHash)
86 supLink := target.AddVerification(v.SourceHash, v.SourceHeight, validators[v.PubKey].Order, v.Signature)
87 if target.Status != state.Unjustified || !supLink.IsMajority(len(validators)) || source.Status == state.Finalized {
91 c.setJustified(source, target)
92 affectedCheckpoints = append(affectedCheckpoints, source)
94 return affectedCheckpoints, nil
97 func (c *Casper) saveVerificationToHeader(v *Verification, validatorOrder int) error {
98 blockHeader, err := c.store.GetBlockHeader(&v.TargetHash)
103 blockHeader.SupLinks.AddSupLink(v.SourceHeight, v.SourceHash, v.Signature, validatorOrder)
104 return c.store.SaveBlockHeader(blockHeader)
107 // source status is justified, and exist a super majority link from source to target
108 func (c *Casper) setJustified(source, target *state.Checkpoint) {
109 target.Status = state.Justified
111 if target.ParentHash == source.Hash {
112 c.setFinalized(source)
116 func (c *Casper) setFinalized(checkpoint *state.Checkpoint) {
117 checkpoint.Status = state.Finalized
118 newRoot, err := c.tree.nodeByHash(checkpoint.Hash)
120 log.WithField("err", err).Error("source checkpoint before the last finalized checkpoint")
124 // update the checkpoint state in memory
125 newRoot.checkpoint.Status = state.Finalized
129 func (c *Casper) tryRollback(oldBestHash bc.Hash) error {
130 if newBestHash := c.bestChain(); oldBestHash != newBestHash {
131 msg := &rollbackMsg{bestHash: newBestHash, reply: make(chan error)}
138 func (c *Casper) authVerificationLoop() {
139 for blockHash := range c.newEpochCh {
140 validators, err := c.Validators(&blockHash)
142 log.WithField("err", err).Error("get validators when auth verification")
146 for _, validator := range validators {
147 key := verificationCacheKey(blockHash, validator.PubKey)
148 verification, ok := c.verificationCache.Get(key)
153 v := verification.(*Verification)
154 target, err := c.store.GetCheckpoint(&v.TargetHash)
156 log.WithField("err", err).Error("get target checkpoint")
157 c.verificationCache.Remove(key)
162 if err := c.authVerification(v, target, validators); err != nil {
163 log.WithField("err", err).Error("auth verification in cache")
167 c.verificationCache.Remove(key)
172 func (c *Casper) verifyVerification(v *Verification, validatorOrder int, trackEvilValidator bool) error {
173 if err := c.verifySameHeight(v, validatorOrder, trackEvilValidator); err != nil {
177 return c.verifySpanHeight(v, validatorOrder, trackEvilValidator)
180 // a validator must not publish two distinct votes for the same target height
181 func (c *Casper) verifySameHeight(v *Verification, validatorOrder int, trackEvilValidator bool) error {
182 checkpoints, err := c.store.GetCheckpointsByHeight(v.TargetHeight)
187 for _, checkpoint := range checkpoints {
188 for _, supLink := range checkpoint.SupLinks {
189 if len(supLink.Signatures[validatorOrder]) != 0 && checkpoint.Hash != v.TargetHash {
190 if trackEvilValidator {
191 c.evilValidators[v.PubKey] = []*Verification{v, makeVerification(supLink, checkpoint, v.PubKey, validatorOrder)}
193 return errSameHeightInVerification
200 // a validator must not vote within the span of its other votes.
201 func (c *Casper) verifySpanHeight(v *Verification, validatorOrder int, trackEvilValidator bool) error {
202 if c.tree.findOnlyOne(func(checkpoint *state.Checkpoint) bool {
203 if checkpoint.Height == v.TargetHeight {
207 for _, supLink := range checkpoint.SupLinks {
208 if len(supLink.Signatures[validatorOrder]) != 0 {
209 if (checkpoint.Height < v.TargetHeight && supLink.SourceHeight > v.SourceHeight) ||
210 (checkpoint.Height > v.TargetHeight && supLink.SourceHeight < v.SourceHeight) {
211 if trackEvilValidator {
212 c.evilValidators[v.PubKey] = []*Verification{v, makeVerification(supLink, checkpoint, v.PubKey, validatorOrder)}
220 return errSpanHeightInVerification
225 func makeVerification(supLink *types.SupLink, checkpoint *state.Checkpoint, pubKey string, validatorOrder int) *Verification {
226 return &Verification{
227 SourceHash: supLink.SourceHash,
228 TargetHash: checkpoint.Hash,
229 SourceHeight: supLink.SourceHeight,
230 TargetHeight: checkpoint.Height,
231 Signature: supLink.Signatures[validatorOrder],
236 func validate(v *Verification) error {
237 blocksOfEpoch := consensus.ActiveNetParams.BlocksOfEpoch
238 if v.SourceHeight%blocksOfEpoch != 0 || v.TargetHeight%blocksOfEpoch != 0 {
239 return errVoteToGrowingCheckpoint
242 if v.SourceHeight == v.TargetHeight {
243 return errVoteToSameCheckpoint
246 return v.VerifySignature()
249 func verificationCacheKey(blockHash bc.Hash, pubKey string) string {
250 return fmt.Sprintf("%s:%s", blockHash.String(), pubKey)