github.com/prysmaticlabs/prysm@v1.4.4/slasher/db/kv/highest_attestation.go (about) 1 package kv 2 3 import ( 4 "context" 5 "encoding/json" 6 7 "github.com/pkg/errors" 8 slashpb "github.com/prysmaticlabs/prysm/proto/slashing" 9 "github.com/prysmaticlabs/prysm/shared/bytesutil" 10 bolt "go.etcd.io/bbolt" 11 "go.opencensus.io/trace" 12 ) 13 14 func persistHighestAttestationCacheOnEviction(db *Store) func(key interface{}, value interface{}) { 15 // We use a closure here so we can access the database itself 16 // on the eviction of a span map from the cache. The function has the signature 17 // required by the ristretto cache OnEvict method. 18 // See https://godoc.org/github.com/dgraph-io/ristretto#Config. 19 return func(key interface{}, value interface{}) { 20 log.Tracef("Evicting highest attestation for validator: %d", key.(uint64)) 21 err := db.update(func(tx *bolt.Tx) error { 22 enc, err := json.Marshal(value.(map[uint64]*slashpb.HighestAttestation)) 23 if err != nil { 24 return errors.Wrap(err, "failed to marshal") 25 } 26 dbKey := highestAttSetkeyBytes(key.(uint64)) 27 bucket := tx.Bucket(highestAttestationBucket) 28 if err := bucket.Put(dbKey, enc); err != nil { 29 return errors.Wrap(err, "failed to add highest attestation to slasher db.") 30 } 31 return nil 32 }) 33 if err != nil { 34 log.Errorf("Failed to save highest attestation to db on cache eviction: %v", err) 35 } 36 } 37 } 38 39 // EnableHighestAttestationCache used to enable or disable highest attestation cache in tests. 40 func (s *Store) EnableHighestAttestationCache(enable bool) { 41 s.highestAttCacheEnabled = enable 42 } 43 44 // HighestAttestation returns the highest calculated attestation for a validatorID 45 func (s *Store) HighestAttestation(ctx context.Context, validatorID uint64) (*slashpb.HighestAttestation, error) { 46 ctx, span := trace.StartSpan(ctx, "SlasherDB.HighestAttestation") 47 defer span.End() 48 49 if s.highestAttCacheEnabled { 50 h, ok := s.highestAttestationCache.Get(highestAttSetkey(validatorID)) 51 if ok && h[validatorID] != nil { 52 return h[validatorID], nil 53 } 54 } 55 56 key := highestAttSetkeyBytes(validatorID) 57 var highestAtt *slashpb.HighestAttestation 58 err := s.view(func(tx *bolt.Tx) error { 59 b := tx.Bucket(highestAttestationBucket) 60 if enc := b.Get(key); enc != nil { 61 set := map[uint64]*slashpb.HighestAttestation{} 62 err := json.Unmarshal(enc, &set) 63 if err != nil { 64 return err 65 } 66 highestAtt = set[validatorID] 67 } 68 return nil 69 }) 70 71 return highestAtt, err 72 } 73 74 // SaveHighestAttestation saves highest attestation for a validatorID. 75 func (s *Store) SaveHighestAttestation(ctx context.Context, highest *slashpb.HighestAttestation) error { 76 ctx, span := trace.StartSpan(ctx, "SlasherDB.SaveHighestAttestation") 77 defer span.End() 78 79 if s.highestAttCacheEnabled { 80 s.highestAttestationCache.Set(highestAttSetkey(highest.ValidatorId), highest) 81 return nil 82 } 83 84 key := highestAttSetkeyBytes(highest.ValidatorId) 85 set := map[uint64]*slashpb.HighestAttestation{} 86 err := s.view(func(tx *bolt.Tx) error { 87 b := tx.Bucket(highestAttestationBucket) 88 if enc := b.Get(key); enc != nil { 89 err := json.Unmarshal(enc, &set) 90 if err != nil { 91 return err 92 } 93 } 94 return nil 95 }) 96 if err != nil { 97 return err 98 } 99 100 set[highest.ValidatorId] = highest 101 enc, err := json.Marshal(set) 102 if err != nil { 103 return errors.Wrap(err, "failed to marshal") 104 } 105 err = s.update(func(tx *bolt.Tx) error { 106 bucket := tx.Bucket(highestAttestationBucket) 107 if err := bucket.Put(key, enc); err != nil { 108 return errors.Wrap(err, "failed to add highest attestation to slasher s.") 109 } 110 return nil 111 }) 112 if err != nil { 113 return err 114 } 115 116 return nil 117 } 118 119 func highestAttSetkeyBytes(validatorID uint64) []byte { 120 return bytesutil.Uint64ToBytesBigEndian(highestAttSetkey(validatorID)) 121 } 122 123 // divide validators by id into 1k-ish buckets (0-1000,1001-1999, etc). 124 func highestAttSetkey(validatorID uint64) uint64 { 125 return validatorID / 1000 126 }