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  }