github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/operations/attestations/kv/aggregated.go (about) 1 package kv 2 3 import ( 4 "context" 5 6 "github.com/prysmaticlabs/prysm/shared/copyutil" 7 8 "github.com/pkg/errors" 9 types "github.com/prysmaticlabs/eth2-types" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 11 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 12 attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations" 13 log "github.com/sirupsen/logrus" 14 "go.opencensus.io/trace" 15 ) 16 17 // AggregateUnaggregatedAttestations aggregates the unaggregated attestations and saves the 18 // newly aggregated attestations in the pool. 19 // It tracks the unaggregated attestations that weren't able to aggregate to prevent 20 // the deletion of unaggregated attestations in the pool. 21 func (c *AttCaches) AggregateUnaggregatedAttestations(ctx context.Context) error { 22 ctx, span := trace.StartSpan(ctx, "operations.attestations.kv.AggregateUnaggregatedAttestations") 23 defer span.End() 24 unaggregatedAtts, err := c.UnaggregatedAttestations() 25 if err != nil { 26 return err 27 } 28 return c.aggregateUnaggregatedAttestations(ctx, unaggregatedAtts) 29 } 30 31 // AggregateUnaggregatedAttestationsBySlotIndex aggregates the unaggregated attestations and saves 32 // newly aggregated attestations in the pool. Unaggregated attestations are filtered by slot and 33 // committee index. 34 func (c *AttCaches) AggregateUnaggregatedAttestationsBySlotIndex(ctx context.Context, slot types.Slot, committeeIndex types.CommitteeIndex) error { 35 ctx, span := trace.StartSpan(ctx, "operations.attestations.kv.AggregateUnaggregatedAttestationsBySlotIndex") 36 defer span.End() 37 unaggregatedAtts := c.UnaggregatedAttestationsBySlotIndex(ctx, slot, committeeIndex) 38 return c.aggregateUnaggregatedAttestations(ctx, unaggregatedAtts) 39 } 40 41 func (c *AttCaches) aggregateUnaggregatedAttestations(ctx context.Context, unaggregatedAtts []*ethpb.Attestation) error { 42 ctx, span := trace.StartSpan(ctx, "operations.attestations.kv.aggregateUnaggregatedAttestations") 43 defer span.End() 44 45 attsByDataRoot := make(map[[32]byte][]*ethpb.Attestation, len(unaggregatedAtts)) 46 for _, att := range unaggregatedAtts { 47 attDataRoot, err := att.Data.HashTreeRoot() 48 if err != nil { 49 return err 50 } 51 attsByDataRoot[attDataRoot] = append(attsByDataRoot[attDataRoot], att) 52 } 53 54 // Aggregate unaggregated attestations from the pool and save them in the pool. 55 // Track the unaggregated attestations that aren't able to aggregate. 56 leftOverUnaggregatedAtt := make(map[[32]byte]bool) 57 for _, atts := range attsByDataRoot { 58 aggregatedAtts := make([]*ethpb.Attestation, 0, len(atts)) 59 processedAtts, err := attaggregation.Aggregate(atts) 60 if err != nil { 61 return err 62 } 63 for _, att := range processedAtts { 64 if helpers.IsAggregated(att) { 65 aggregatedAtts = append(aggregatedAtts, att) 66 } else { 67 h, err := hashFn(att) 68 if err != nil { 69 return err 70 } 71 leftOverUnaggregatedAtt[h] = true 72 } 73 } 74 if err := c.SaveAggregatedAttestations(aggregatedAtts); err != nil { 75 return err 76 } 77 } 78 79 // Remove the unaggregated attestations from the pool that were successfully aggregated. 80 for _, att := range unaggregatedAtts { 81 h, err := hashFn(att) 82 if err != nil { 83 return err 84 } 85 if leftOverUnaggregatedAtt[h] { 86 continue 87 } 88 if err := c.DeleteUnaggregatedAttestation(att); err != nil { 89 return err 90 } 91 } 92 93 return nil 94 } 95 96 // SaveAggregatedAttestation saves an aggregated attestation in cache. 97 func (c *AttCaches) SaveAggregatedAttestation(att *ethpb.Attestation) error { 98 if err := helpers.ValidateNilAttestation(att); err != nil { 99 return err 100 } 101 if !helpers.IsAggregated(att) { 102 return errors.New("attestation is not aggregated") 103 } 104 has, err := c.HasAggregatedAttestation(att) 105 if err != nil { 106 return err 107 } 108 if has { 109 return nil 110 } 111 112 seen, err := c.hasSeenBit(att) 113 if err != nil { 114 return err 115 } 116 if seen { 117 return nil 118 } 119 120 r, err := hashFn(att.Data) 121 if err != nil { 122 return errors.Wrap(err, "could not tree hash attestation") 123 } 124 copiedAtt := copyutil.CopyAttestation(att) 125 c.aggregatedAttLock.Lock() 126 defer c.aggregatedAttLock.Unlock() 127 atts, ok := c.aggregatedAtt[r] 128 if !ok { 129 atts := []*ethpb.Attestation{copiedAtt} 130 c.aggregatedAtt[r] = atts 131 return nil 132 } 133 134 atts, err = attaggregation.Aggregate(append(atts, copiedAtt)) 135 if err != nil { 136 return err 137 } 138 c.aggregatedAtt[r] = atts 139 140 return nil 141 } 142 143 // SaveAggregatedAttestations saves a list of aggregated attestations in cache. 144 func (c *AttCaches) SaveAggregatedAttestations(atts []*ethpb.Attestation) error { 145 for _, att := range atts { 146 if err := c.SaveAggregatedAttestation(att); err != nil { 147 log.WithError(err).Debug("Could not save aggregated attestation") 148 if err := c.DeleteAggregatedAttestation(att); err != nil { 149 log.WithError(err).Debug("Could not delete aggregated attestation") 150 } 151 } 152 } 153 return nil 154 } 155 156 // AggregatedAttestations returns the aggregated attestations in cache. 157 func (c *AttCaches) AggregatedAttestations() []*ethpb.Attestation { 158 c.aggregatedAttLock.RLock() 159 defer c.aggregatedAttLock.RUnlock() 160 161 atts := make([]*ethpb.Attestation, 0) 162 163 for _, a := range c.aggregatedAtt { 164 atts = append(atts, a...) 165 } 166 167 return atts 168 } 169 170 // AggregatedAttestationsBySlotIndex returns the aggregated attestations in cache, 171 // filtered by committee index and slot. 172 func (c *AttCaches) AggregatedAttestationsBySlotIndex(ctx context.Context, slot types.Slot, committeeIndex types.CommitteeIndex) []*ethpb.Attestation { 173 ctx, span := trace.StartSpan(ctx, "operations.attestations.kv.AggregatedAttestationsBySlotIndex") 174 defer span.End() 175 176 atts := make([]*ethpb.Attestation, 0) 177 178 c.aggregatedAttLock.RLock() 179 defer c.aggregatedAttLock.RUnlock() 180 for _, a := range c.aggregatedAtt { 181 if slot == a[0].Data.Slot && committeeIndex == a[0].Data.CommitteeIndex { 182 atts = append(atts, a...) 183 } 184 } 185 186 return atts 187 } 188 189 // DeleteAggregatedAttestation deletes the aggregated attestations in cache. 190 func (c *AttCaches) DeleteAggregatedAttestation(att *ethpb.Attestation) error { 191 if err := helpers.ValidateNilAttestation(att); err != nil { 192 return err 193 } 194 if !helpers.IsAggregated(att) { 195 return errors.New("attestation is not aggregated") 196 } 197 r, err := hashFn(att.Data) 198 if err != nil { 199 return errors.Wrap(err, "could not tree hash attestation data") 200 } 201 202 if err := c.insertSeenBit(att); err != nil { 203 return err 204 } 205 206 c.aggregatedAttLock.Lock() 207 defer c.aggregatedAttLock.Unlock() 208 attList, ok := c.aggregatedAtt[r] 209 if !ok { 210 return nil 211 } 212 213 filtered := make([]*ethpb.Attestation, 0) 214 for _, a := range attList { 215 if c, err := att.AggregationBits.Contains(a.AggregationBits); err != nil { 216 return err 217 } else if !c { 218 filtered = append(filtered, a) 219 } 220 } 221 if len(filtered) == 0 { 222 delete(c.aggregatedAtt, r) 223 } else { 224 c.aggregatedAtt[r] = filtered 225 } 226 227 return nil 228 } 229 230 // HasAggregatedAttestation checks if the input attestations has already existed in cache. 231 func (c *AttCaches) HasAggregatedAttestation(att *ethpb.Attestation) (bool, error) { 232 if err := helpers.ValidateNilAttestation(att); err != nil { 233 return false, err 234 } 235 r, err := hashFn(att.Data) 236 if err != nil { 237 return false, errors.Wrap(err, "could not tree hash attestation") 238 } 239 240 c.aggregatedAttLock.RLock() 241 defer c.aggregatedAttLock.RUnlock() 242 if atts, ok := c.aggregatedAtt[r]; ok { 243 for _, a := range atts { 244 if c, err := a.AggregationBits.Contains(att.AggregationBits); err != nil { 245 return false, err 246 } else if c { 247 return true, nil 248 } 249 } 250 } 251 252 c.blockAttLock.RLock() 253 defer c.blockAttLock.RUnlock() 254 if atts, ok := c.blockAtt[r]; ok { 255 for _, a := range atts { 256 if c, err := a.AggregationBits.Contains(att.AggregationBits); err != nil { 257 return false, err 258 } else if c { 259 return true, nil 260 } 261 } 262 } 263 264 return false, nil 265 } 266 267 // AggregatedAttestationCount returns the number of aggregated attestations key in the pool. 268 func (c *AttCaches) AggregatedAttestationCount() int { 269 c.aggregatedAttLock.RLock() 270 defer c.aggregatedAttLock.RUnlock() 271 return len(c.aggregatedAtt) 272 }