github.com/prysmaticlabs/prysm@v1.4.4/shared/aggregation/sync_contribution/naive.go (about)

     1  package sync_contribution
     2  
     3  import (
     4  	v2 "github.com/prysmaticlabs/prysm/proto/prysm/v2"
     5  	"github.com/prysmaticlabs/prysm/shared/aggregation"
     6  	"github.com/prysmaticlabs/prysm/shared/bls"
     7  	"github.com/prysmaticlabs/prysm/shared/copyutil"
     8  )
     9  
    10  // naiveSyncContributionAggregation aggregates naively, without any complex algorithms or optimizations.
    11  // Note: this is currently a naive implementation to the order of O(mn^2).
    12  func naiveSyncContributionAggregation(contributions []*v2.SyncCommitteeContribution) ([]*v2.SyncCommitteeContribution, error) {
    13  	if len(contributions) <= 1 {
    14  		return contributions, nil
    15  	}
    16  
    17  	// Naive aggregation. O(n^2) time.
    18  	for i, a := range contributions {
    19  		if i >= len(contributions) {
    20  			break
    21  		}
    22  		for j := i + 1; j < len(contributions); j++ {
    23  			b := contributions[j]
    24  			if o, err := a.AggregationBits.Overlaps(b.AggregationBits); err != nil {
    25  				return nil, err
    26  			} else if !o {
    27  				var err error
    28  				a, err = aggregate(a, b)
    29  				if err != nil {
    30  					return nil, err
    31  				}
    32  				// Delete b
    33  				contributions = append(contributions[:j], contributions[j+1:]...)
    34  				j--
    35  				contributions[i] = a
    36  			}
    37  		}
    38  	}
    39  
    40  	// Naive deduplication of identical contributions. O(n^2) time.
    41  	for i, a := range contributions {
    42  		for j := i + 1; j < len(contributions); j++ {
    43  			b := contributions[j]
    44  
    45  			if a.AggregationBits.Len() != b.AggregationBits.Len() {
    46  				continue
    47  			}
    48  
    49  			if c, err := a.AggregationBits.Contains(b.AggregationBits); err != nil {
    50  				return nil, err
    51  			} else if c {
    52  				// If b is fully contained in a, then b can be removed.
    53  				contributions = append(contributions[:j], contributions[j+1:]...)
    54  				j--
    55  			} else if c, err := b.AggregationBits.Contains(a.AggregationBits); err != nil {
    56  				return nil, err
    57  			} else if c {
    58  				// if a is fully contained in b, then a can be removed.
    59  				contributions = append(contributions[:i], contributions[i+1:]...)
    60  				break // Stop the inner loop, advance a.
    61  			}
    62  		}
    63  	}
    64  
    65  	return contributions, nil
    66  }
    67  
    68  // aggregates pair of sync contributions c1 and c2 together.
    69  func aggregate(c1, c2 *v2.SyncCommitteeContribution) (*v2.SyncCommitteeContribution, error) {
    70  	if o, err := c1.AggregationBits.Overlaps(c2.AggregationBits); err != nil {
    71  		return nil, err
    72  	} else if o {
    73  		return nil, aggregation.ErrBitsOverlap
    74  	}
    75  
    76  	baseContribution := copyutil.CopySyncCommitteeContribution(c1)
    77  	newContribution := copyutil.CopySyncCommitteeContribution(c2)
    78  	if newContribution.AggregationBits.Count() > baseContribution.AggregationBits.Count() {
    79  		baseContribution, newContribution = newContribution, baseContribution
    80  	}
    81  
    82  	if c, err := baseContribution.AggregationBits.Contains(newContribution.AggregationBits); err != nil {
    83  		return nil, err
    84  	} else if c {
    85  		return baseContribution, nil
    86  	}
    87  
    88  	newBits, err := baseContribution.AggregationBits.Or(newContribution.AggregationBits)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	newSig, err := bls.SignatureFromBytes(newContribution.Signature)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	baseSig, err := bls.SignatureFromBytes(baseContribution.Signature)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	aggregatedSig := bls.AggregateSignatures([]bls.Signature{baseSig, newSig})
   102  	baseContribution.Signature = aggregatedSig.Marshal()
   103  	baseContribution.AggregationBits = newBits
   104  
   105  	return baseContribution, nil
   106  }