7 log "github.com/sirupsen/logrus"
9 "github.com/bytom/bytom/protocol/bc"
10 "github.com/bytom/bytom/protocol/state"
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(v *Verification) error {
18 if err := validate(v); err != nil {
25 // root of tree is the last finalized checkpoint
26 if v.TargetHeight < c.tree.checkpoint.Height {
27 // discard the verification message which height of target less than height of last finalized checkpoint
28 // is for simplify check the vote within the span of its other votes
32 targetNode, err := c.tree.nodeByHash(v.TargetHash)
34 c.verificationCache.Add(verificationCacheKey(v.TargetHash, v.PubKey), v)
38 validators, err := c.Validators(&v.TargetHash)
43 if _, ok := validators[v.PubKey]; !ok {
44 return errPubKeyIsNotValidator
47 if targetNode.checkpoint.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
51 _, oldBestHash := c.bestChain()
52 if err := c.authVerification(v, targetNode.checkpoint, validators); err != nil {
56 return c.tryRollback(oldBestHash)
59 func (c *Casper) authVerification(v *Verification, target *state.Checkpoint, validators map[string]*state.Validator) error {
60 validator := validators[v.PubKey]
61 if err := c.verifyVerification(v, validator.Order, true); err != nil {
65 checkpoints, err := c.addVerificationToCheckpoint(target, validators, v)
70 if err := c.store.SaveCheckpoints(checkpoints); err != nil {
74 return c.saveVerificationToHeader(v, validator.Order)
77 func (c *Casper) addVerificationToCheckpoint(target *state.Checkpoint, validators map[string]*state.Validator, verifications ...*Verification) ([]*state.Checkpoint, error) {
78 affectedCheckpoints := []*state.Checkpoint{target}
79 for _, v := range verifications {
80 source, err := c.store.GetCheckpoint(&v.SourceHash)
85 supLink := target.AddVerification(v.SourceHash, v.SourceHeight, validators[v.PubKey].Order, v.Signature)
86 if target.Status != state.Unjustified || !supLink.IsMajority(len(validators)) || source.Status == state.Finalized {
90 c.setJustified(source, target)
91 affectedCheckpoints = append(affectedCheckpoints, source)
93 return affectedCheckpoints, nil
96 func (c *Casper) saveVerificationToHeader(v *Verification, validatorOrder int) error {
97 blockHeader, err := c.store.GetBlockHeader(&v.TargetHash)
102 signature, err := hex.DecodeString(v.Signature)
107 blockHeader.SupLinks.AddSupLink(v.SourceHeight, v.SourceHash, signature, validatorOrder)
108 return c.store.SaveBlockHeader(blockHeader)
111 // source status is justified, and exist a super majority link from source to target
112 func (c *Casper) setJustified(source, target *state.Checkpoint) {
113 target.Status = state.Justified
115 if target.ParentHash == source.Hash {
116 c.setFinalized(source)
120 func (c *Casper) setFinalized(checkpoint *state.Checkpoint) {
121 checkpoint.Status = state.Finalized
122 newRoot, err := c.tree.nodeByHash(checkpoint.Hash)
124 log.WithField("err", err).Error("source checkpoint before the last finalized checkpoint")
128 // update the checkpoint state in memory
129 newRoot.checkpoint.Status = state.Finalized
133 func (c *Casper) tryRollback(oldBestHash bc.Hash) error {
134 if _, newBestHash := c.bestChain(); oldBestHash != newBestHash {
135 msg := &rollbackMsg{bestHash: newBestHash}
142 func (c *Casper) authVerificationLoop() {
143 for blockHash := range c.newEpochCh {
144 validators, err := c.Validators(&blockHash)
146 log.WithField("err", err).Error("get validators when auth verification")
150 for _, validator := range validators {
151 key := verificationCacheKey(blockHash, validator.PubKey)
152 verification, ok := c.verificationCache.Get(key)
157 v := verification.(*Verification)
158 target, err := c.store.GetCheckpoint(&v.TargetHash)
160 log.WithField("err", err).Error("get target checkpoint")
161 c.verificationCache.Remove(key)
166 if err := c.authVerification(v, target, validators); err != nil {
167 log.WithField("err", err).Error("auth verification in cache")
171 c.verificationCache.Remove(key)
176 func (c *Casper) verifyVerification(v *Verification, validatorOrder int, trackEvilValidator bool) error {
177 if err := c.verifySameHeight(v, validatorOrder, trackEvilValidator); err != nil {
181 return c.verifySpanHeight(v, validatorOrder, trackEvilValidator)
184 // a validator must not publish two distinct votes for the same target height
185 func (c *Casper) verifySameHeight(v *Verification, validatorOrder int, trackEvilValidator bool) error {
186 checkpoints, err := c.store.GetCheckpointsByHeight(v.TargetHeight)
191 for _, checkpoint := range checkpoints {
192 for _, supLink := range checkpoint.SupLinks {
193 if supLink.Signatures[validatorOrder] != "" && checkpoint.Hash != v.TargetHash {
194 if trackEvilValidator {
195 c.evilValidators[v.PubKey] = []*Verification{v, makeVerification(supLink, checkpoint, v.PubKey, validatorOrder)}
197 return errSameHeightInVerification
204 // a validator must not vote within the span of its other votes.
205 func (c *Casper) verifySpanHeight(v *Verification, validatorOrder int, trackEvilValidator bool) error {
206 if c.tree.findOnlyOne(func(checkpoint *state.Checkpoint) bool {
207 if checkpoint.Height == v.TargetHeight {
211 for _, supLink := range checkpoint.SupLinks {
212 if supLink.Signatures[validatorOrder] != "" {
213 if (checkpoint.Height < v.TargetHeight && supLink.SourceHeight > v.SourceHeight) ||
214 (checkpoint.Height > v.TargetHeight && supLink.SourceHeight < v.SourceHeight) {
215 if trackEvilValidator {
216 c.evilValidators[v.PubKey] = []*Verification{v, makeVerification(supLink, checkpoint, v.PubKey, validatorOrder)}
224 return errSpanHeightInVerification
229 func makeVerification(supLink *state.SupLink, checkpoint *state.Checkpoint, pubKey string, validatorOrder int) *Verification {
230 return &Verification{
231 SourceHash: supLink.SourceHash,
232 TargetHash: checkpoint.Hash,
233 SourceHeight: supLink.SourceHeight,
234 TargetHeight: checkpoint.Height,
235 Signature: supLink.Signatures[validatorOrder],
240 func validate(v *Verification) error {
241 if v.SourceHeight%state.BlocksOfEpoch != 0 || v.TargetHeight%state.BlocksOfEpoch != 0 {
242 return errVoteToGrowingCheckpoint
245 if v.SourceHeight == v.TargetHeight {
246 return errVoteToSameCheckpoint
249 return v.VerifySignature()
252 func verificationCacheKey(blockHash bc.Hash, pubKey string) string {
253 return fmt.Sprintf("%s:%s", blockHash.String(), pubKey)