github.com/prysmaticlabs/prysm@v1.4.4/slasher/db/kv/indexed_attestations.go (about) 1 package kv 2 3 import ( 4 "bytes" 5 "context" 6 7 "github.com/pkg/errors" 8 types "github.com/prysmaticlabs/eth2-types" 9 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 10 "github.com/prysmaticlabs/prysm/shared/bytesutil" 11 bolt "go.etcd.io/bbolt" 12 "go.opencensus.io/trace" 13 "google.golang.org/protobuf/proto" 14 ) 15 16 func unmarshalIndexedAttestation(ctx context.Context, enc []byte) (*ethpb.IndexedAttestation, error) { 17 ctx, span := trace.StartSpan(ctx, "slasherDB.unmarshalIndexedAttestation") 18 defer span.End() 19 protoIdxAtt := ðpb.IndexedAttestation{} 20 err := proto.Unmarshal(enc, protoIdxAtt) 21 if err != nil { 22 return nil, errors.Wrap(err, "failed to unmarshal encoded indexed attestation") 23 } 24 return protoIdxAtt, nil 25 } 26 27 // IndexedAttestationsForTarget accepts a target epoch and returns a list of 28 // indexed attestations. 29 // Returns nil if the indexed attestation does not exist with that target epoch. 30 func (s *Store) IndexedAttestationsForTarget(ctx context.Context, targetEpoch types.Epoch) ([]*ethpb.IndexedAttestation, error) { 31 ctx, span := trace.StartSpan(ctx, "slasherDB.IndexedAttestationsForTarget") 32 defer span.End() 33 var idxAtts []*ethpb.IndexedAttestation 34 key := bytesutil.Bytes8(uint64(targetEpoch)) 35 err := s.view(func(tx *bolt.Tx) error { 36 c := tx.Bucket(historicIndexedAttestationsBucket).Cursor() 37 for k, enc := c.Seek(key); k != nil && bytes.Equal(k[:8], key); k, enc = c.Next() { 38 idxAtt, err := unmarshalIndexedAttestation(ctx, enc) 39 if err != nil { 40 return err 41 } 42 idxAtts = append(idxAtts, idxAtt) 43 } 44 return nil 45 }) 46 return idxAtts, err 47 } 48 49 // IndexedAttestationsWithPrefix accepts a target epoch and signature bytes to find all attestations with the requested prefix. 50 // Returns nil if the indexed attestation does not exist with that target epoch. 51 func (s *Store) IndexedAttestationsWithPrefix(ctx context.Context, targetEpoch types.Epoch, sigBytes []byte) ([]*ethpb.IndexedAttestation, error) { 52 ctx, span := trace.StartSpan(ctx, "slasherDB.IndexedAttestationsWithPrefix") 53 defer span.End() 54 var idxAtts []*ethpb.IndexedAttestation 55 key := encodeEpochSig(targetEpoch, sigBytes) 56 err := s.view(func(tx *bolt.Tx) error { 57 c := tx.Bucket(historicIndexedAttestationsBucket).Cursor() 58 for k, enc := c.Seek(key); k != nil && bytes.Equal(k[:len(key)], key); k, enc = c.Next() { 59 idxAtt, err := unmarshalIndexedAttestation(ctx, enc) 60 if err != nil { 61 return err 62 } 63 idxAtts = append(idxAtts, idxAtt) 64 } 65 return nil 66 }) 67 return idxAtts, err 68 } 69 70 // HasIndexedAttestation accepts an attestation and returns true if it exists in the DB. 71 func (s *Store) HasIndexedAttestation(ctx context.Context, att *ethpb.IndexedAttestation) (bool, error) { 72 ctx, span := trace.StartSpan(ctx, "slasherDB.HasIndexedAttestation") 73 defer span.End() 74 key := encodeEpochSig(att.Data.Target.Epoch, att.Signature) 75 var hasAttestation bool 76 // #nosec G104 77 err := s.view(func(tx *bolt.Tx) error { 78 bucket := tx.Bucket(historicIndexedAttestationsBucket) 79 enc := bucket.Get(key) 80 if enc == nil { 81 return nil 82 } 83 hasAttestation = true 84 return nil 85 }) 86 87 return hasAttestation, err 88 } 89 90 // SaveIndexedAttestation accepts an indexed attestation and writes it to the DB. 91 func (s *Store) SaveIndexedAttestation(ctx context.Context, idxAttestation *ethpb.IndexedAttestation) error { 92 ctx, span := trace.StartSpan(ctx, "slasherDB.SaveIndexedAttestation") 93 defer span.End() 94 key := encodeEpochSig(idxAttestation.Data.Target.Epoch, idxAttestation.Signature) 95 enc, err := proto.Marshal(idxAttestation) 96 if err != nil { 97 return errors.Wrap(err, "failed to marshal") 98 } 99 err = s.update(func(tx *bolt.Tx) error { 100 bucket := tx.Bucket(historicIndexedAttestationsBucket) 101 // if data is in s skip put and index functions 102 val := bucket.Get(key) 103 if val != nil { 104 return nil 105 } 106 if err := bucket.Put(key, enc); err != nil { 107 return errors.Wrap(err, "failed to save indexed attestation into historical bucket") 108 } 109 110 return err 111 }) 112 return err 113 } 114 115 // SaveIndexedAttestations accepts multiple indexed attestations and writes them to the DB. 116 func (s *Store) SaveIndexedAttestations(ctx context.Context, idxAttestations []*ethpb.IndexedAttestation) error { 117 ctx, span := trace.StartSpan(ctx, "slasherDB.SaveIndexedAttestations") 118 defer span.End() 119 keys := make([][]byte, len(idxAttestations)) 120 marshaledAtts := make([][]byte, len(idxAttestations)) 121 for i, att := range idxAttestations { 122 enc, err := proto.Marshal(att) 123 if err != nil { 124 return errors.Wrap(err, "failed to marshal") 125 } 126 keys[i] = encodeEpochSig(att.Data.Target.Epoch, att.Signature) 127 marshaledAtts[i] = enc 128 } 129 130 err := s.update(func(tx *bolt.Tx) error { 131 bucket := tx.Bucket(historicIndexedAttestationsBucket) 132 for i, key := range keys { 133 // if data is in s skip put and index functions 134 val := bucket.Get(key) 135 if val != nil { 136 continue 137 } 138 if err := bucket.Put(key, marshaledAtts[i]); err != nil { 139 return errors.Wrap(err, "failed to save indexed attestation into historical bucket") 140 } 141 } 142 return nil 143 }) 144 return err 145 } 146 147 // DeleteIndexedAttestation deletes a indexed attestation using the slot and its root as keys in their respective buckets. 148 func (s *Store) DeleteIndexedAttestation(ctx context.Context, idxAttestation *ethpb.IndexedAttestation) error { 149 ctx, span := trace.StartSpan(ctx, "slasherDB.DeleteIndexedAttestation") 150 defer span.End() 151 key := encodeEpochSig(idxAttestation.Data.Target.Epoch, idxAttestation.Signature) 152 return s.update(func(tx *bolt.Tx) error { 153 bucket := tx.Bucket(historicIndexedAttestationsBucket) 154 enc := bucket.Get(key) 155 if enc == nil { 156 return nil 157 } 158 if err := bucket.Delete(key); err != nil { 159 return errors.Wrap(err, "failed to delete indexed attestation from historical bucket") 160 } 161 return nil 162 }) 163 } 164 165 // PruneAttHistory removes all attestations from the DB older than the pruning epoch age. 166 func (s *Store) PruneAttHistory(ctx context.Context, currentEpoch, pruningEpochAge types.Epoch) error { 167 ctx, span := trace.StartSpan(ctx, "slasherDB.pruneAttHistory") 168 defer span.End() 169 pruneFromEpoch := int64(currentEpoch) - int64(pruningEpochAge) 170 if pruneFromEpoch <= 0 { 171 return nil 172 } 173 174 return s.update(func(tx *bolt.Tx) error { 175 attBucket := tx.Bucket(historicIndexedAttestationsBucket) 176 c := tx.Bucket(historicIndexedAttestationsBucket).Cursor() 177 max := bytesutil.Bytes8(uint64(pruneFromEpoch)) 178 for k, _ := c.First(); k != nil && bytes.Compare(k[:8], max) <= 0; k, _ = c.Next() { 179 if err := attBucket.Delete(k); err != nil { 180 return errors.Wrap(err, "failed to delete indexed attestation from historical bucket") 181 } 182 } 183 return nil 184 }) 185 } 186 187 // LatestIndexedAttestationsTargetEpoch returns latest target epoch in db 188 // returns 0 if there is no indexed attestations in db. 189 func (s *Store) LatestIndexedAttestationsTargetEpoch(ctx context.Context) (uint64, error) { 190 ctx, span := trace.StartSpan(ctx, "slasherDB.LatestIndexedAttestationsTargetEpoch") 191 defer span.End() 192 var lt uint64 193 err := s.view(func(tx *bolt.Tx) error { 194 c := tx.Bucket(historicIndexedAttestationsBucket).Cursor() 195 k, _ := c.Last() 196 if k == nil { 197 return nil 198 } 199 lt = bytesutil.FromBytes8(k[:8]) 200 return nil 201 }) 202 return lt, err 203 }