prysm-pulse/shared/aggregation/attestations/attestations.go

110 lines
3.8 KiB
Go
Raw Normal View History

package attestations
import (
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/aggregation"
"github.com/prysmaticlabs/prysm/shared/bls"
2021-05-26 18:33:46 +00:00
"github.com/prysmaticlabs/prysm/shared/copyutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/sirupsen/logrus"
)
const (
// NaiveAggregation is an aggregation strategy without any optimizations.
NaiveAggregation AttestationAggregationStrategy = "naive"
// MaxCoverAggregation is a strategy based on Maximum Coverage greedy algorithm.
MaxCoverAggregation AttestationAggregationStrategy = "max_cover"
Attestation aggregation: optimizations and benchmarks (#7938) * profitablity tests * cleanup benchmark * fix deduplication function * dedup: move method to atts list * proper substring handling * refactor validate method * update benchmarks * prepare proposer test * remove redundant code * reset test * remove dedup from maxcover - moved to proposer * remove redundant test * remove lower level check for bit length * optimize candidate validation on att aggregation * restore test * fix test * fix test * remove dedup functionality * add benchmark * optimize list usage * Attestation aggregration: remove redundant dedup routine * fix func call * experiment with bitset based cover * add benchmark * samplem implementation using Bilist64 * add tests * remove redundant code * remove tmp comments * unskip test * update benchmarks * gazelle * process err * optimized max-cover * Max-cover: optimized implementation based on Bitlist64 * gazelle * re-arrange overlaps check * minor comments * add Bitlists64WithMultipleBitSet * update benchmarks * gazelle * add TestAggregateAttestations_rearrangeProcessedAttestations * minor updates to rearrange method * add link to design doc * remove redundant methods * simplify test * add TestAggregateAttestations_aggregateAttestations * fix issues * fix assignment * use ToBitlist(), ToBitlist64() * fixes test * benchmarks * fix typo * allow opt_max_cover opt-int flag * update benchmarks * reset e2e * fix test * enable opt_max_cover in e2e tests Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2021-02-04 00:58:33 +00:00
// OptMaxCoverAggregation is a strategy based on Maximum Coverage greedy algorithm.
// This new variant is optimized and relies on Bitlist64 (once fully tested, `max_cover`
// strategy will be replaced with this one).
OptMaxCoverAggregation AttestationAggregationStrategy = "opt_max_cover"
)
// AttestationAggregationStrategy defines attestation aggregation strategy.
type AttestationAggregationStrategy string
// attList represents list of attestations, defined for easier en masse operations (filtering, sorting).
type attList []*ethpb.Attestation
// BLS aggregate signature aliases for testing / benchmark substitution. These methods are
// significantly more expensive than the inner logic of AggregateAttestations so they must be
// substituted for benchmarks which analyze AggregateAttestations.
var aggregateSignatures = bls.AggregateSignatures
var signatureFromBytes = bls.SignatureFromBytes
var _ = logrus.WithField("prefix", "aggregation.attestations")
// ErrInvalidAttestationCount is returned when insufficient number
// of attestations is provided for aggregation.
var ErrInvalidAttestationCount = errors.New("invalid number of attestations")
// Aggregate aggregates attestations. The minimal number of attestations is returned.
Attestation aggregation: optimizations and benchmarks (#7938) * profitablity tests * cleanup benchmark * fix deduplication function * dedup: move method to atts list * proper substring handling * refactor validate method * update benchmarks * prepare proposer test * remove redundant code * reset test * remove dedup from maxcover - moved to proposer * remove redundant test * remove lower level check for bit length * optimize candidate validation on att aggregation * restore test * fix test * fix test * remove dedup functionality * add benchmark * optimize list usage * Attestation aggregration: remove redundant dedup routine * fix func call * experiment with bitset based cover * add benchmark * samplem implementation using Bilist64 * add tests * remove redundant code * remove tmp comments * unskip test * update benchmarks * gazelle * process err * optimized max-cover * Max-cover: optimized implementation based on Bitlist64 * gazelle * re-arrange overlaps check * minor comments * add Bitlists64WithMultipleBitSet * update benchmarks * gazelle * add TestAggregateAttestations_rearrangeProcessedAttestations * minor updates to rearrange method * add link to design doc * remove redundant methods * simplify test * add TestAggregateAttestations_aggregateAttestations * fix issues * fix assignment * use ToBitlist(), ToBitlist64() * fixes test * benchmarks * fix typo * allow opt_max_cover opt-int flag * update benchmarks * reset e2e * fix test * enable opt_max_cover in e2e tests Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2021-02-04 00:58:33 +00:00
// Aggregation occurs in-place i.e. contents of input array will be modified. Should you need to
// preserve input attestations, clone them before aggregating:
//
// clonedAtts := make([]*ethpb.Attestation, len(atts))
// for i, a := range atts {
// clonedAtts[i] = stateTrie.CopyAttestation(a)
// }
// aggregatedAtts, err := attaggregation.Aggregate(clonedAtts)
func Aggregate(atts []*ethpb.Attestation) ([]*ethpb.Attestation, error) {
strategy := AttestationAggregationStrategy(featureconfig.Get().AttestationAggregationStrategy)
switch strategy {
case "", NaiveAggregation:
return NaiveAttestationAggregation(atts)
case MaxCoverAggregation:
return MaxCoverAttestationAggregation(atts)
Attestation aggregation: optimizations and benchmarks (#7938) * profitablity tests * cleanup benchmark * fix deduplication function * dedup: move method to atts list * proper substring handling * refactor validate method * update benchmarks * prepare proposer test * remove redundant code * reset test * remove dedup from maxcover - moved to proposer * remove redundant test * remove lower level check for bit length * optimize candidate validation on att aggregation * restore test * fix test * fix test * remove dedup functionality * add benchmark * optimize list usage * Attestation aggregration: remove redundant dedup routine * fix func call * experiment with bitset based cover * add benchmark * samplem implementation using Bilist64 * add tests * remove redundant code * remove tmp comments * unskip test * update benchmarks * gazelle * process err * optimized max-cover * Max-cover: optimized implementation based on Bitlist64 * gazelle * re-arrange overlaps check * minor comments * add Bitlists64WithMultipleBitSet * update benchmarks * gazelle * add TestAggregateAttestations_rearrangeProcessedAttestations * minor updates to rearrange method * add link to design doc * remove redundant methods * simplify test * add TestAggregateAttestations_aggregateAttestations * fix issues * fix assignment * use ToBitlist(), ToBitlist64() * fixes test * benchmarks * fix typo * allow opt_max_cover opt-int flag * update benchmarks * reset e2e * fix test * enable opt_max_cover in e2e tests Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2021-02-04 00:58:33 +00:00
case OptMaxCoverAggregation:
return optMaxCoverAttestationAggregation(atts)
default:
return nil, errors.Wrapf(aggregation.ErrInvalidStrategy, "%q", strategy)
}
}
// AggregatePair aggregates pair of attestations a1 and a2 together.
func AggregatePair(a1, a2 *ethpb.Attestation) (*ethpb.Attestation, error) {
2021-07-08 15:31:40 +00:00
o, err := a1.AggregationBits.Overlaps(a2.AggregationBits)
if err != nil {
return nil, err
}
2021-07-08 15:31:40 +00:00
if o {
return nil, aggregation.ErrBitsOverlap
}
2021-05-26 18:33:46 +00:00
baseAtt := copyutil.CopyAttestation(a1)
newAtt := copyutil.CopyAttestation(a2)
if newAtt.AggregationBits.Count() > baseAtt.AggregationBits.Count() {
baseAtt, newAtt = newAtt, baseAtt
}
2021-07-08 15:31:40 +00:00
c, err := baseAtt.AggregationBits.Contains(newAtt.AggregationBits)
if err != nil {
return nil, err
}
if c {
return baseAtt, nil
}
2021-07-08 15:31:40 +00:00
newBits, err := baseAtt.AggregationBits.Or(newAtt.AggregationBits)
if err != nil {
return nil, err
}
newSig, err := signatureFromBytes(newAtt.Signature)
if err != nil {
return nil, err
}
baseSig, err := signatureFromBytes(baseAtt.Signature)
if err != nil {
return nil, err
}
aggregatedSig := aggregateSignatures([]bls.Signature{baseSig, newSig})
baseAtt.Signature = aggregatedSig.Marshal()
baseAtt.AggregationBits = newBits
return baseAtt, nil
}