github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_attestations.go (about)

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	"github.com/prysmaticlabs/go-bitfield"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
    10  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    11  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    12  	"github.com/prysmaticlabs/prysm/shared/aggregation"
    13  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    14  	"github.com/prysmaticlabs/prysm/shared/params"
    15  )
    16  
    17  type proposerAtts []*ethpb.Attestation
    18  
    19  // filter separates attestation list into two groups: valid and invalid attestations.
    20  // The first group passes the all the required checks for attestation to be considered for proposing.
    21  // And attestations from the second group should be deleted.
    22  func (a proposerAtts) filter(ctx context.Context, state iface.BeaconState) (proposerAtts, proposerAtts) {
    23  	validAtts := make([]*ethpb.Attestation, 0, len(a))
    24  	invalidAtts := make([]*ethpb.Attestation, 0, len(a))
    25  	for _, att := range a {
    26  		if _, err := blocks.ProcessAttestationNoVerifySignature(ctx, state, att); err == nil {
    27  			validAtts = append(validAtts, att)
    28  			continue
    29  		}
    30  		invalidAtts = append(invalidAtts, att)
    31  	}
    32  	return validAtts, invalidAtts
    33  }
    34  
    35  // sortByProfitability orders attestations by highest slot and by highest aggregation bit count.
    36  func (a proposerAtts) sortByProfitability() (proposerAtts, error) {
    37  	if len(a) < 2 {
    38  		return a, nil
    39  	}
    40  	if featureconfig.Get().ProposerAttsSelectionUsingMaxCover {
    41  		return a.sortByProfitabilityUsingMaxCover()
    42  	}
    43  	sort.Slice(a, func(i, j int) bool {
    44  		if a[i].Data.Slot == a[j].Data.Slot {
    45  			return a[i].AggregationBits.Count() > a[j].AggregationBits.Count()
    46  		}
    47  		return a[i].Data.Slot > a[j].Data.Slot
    48  	})
    49  	return a, nil
    50  }
    51  
    52  // sortByProfitabilityUsingMaxCover orders attestations by highest slot and by highest aggregation bit count.
    53  // Duplicate bits are counted only once, using max-cover algorithm.
    54  func (a proposerAtts) sortByProfitabilityUsingMaxCover() (proposerAtts, error) {
    55  	// Separate attestations by slot, as slot number takes higher precedence when sorting.
    56  	var slots []types.Slot
    57  	attsBySlot := map[types.Slot]proposerAtts{}
    58  	for _, att := range a {
    59  		if _, ok := attsBySlot[att.Data.Slot]; !ok {
    60  			slots = append(slots, att.Data.Slot)
    61  		}
    62  		attsBySlot[att.Data.Slot] = append(attsBySlot[att.Data.Slot], att)
    63  	}
    64  
    65  	selectAtts := func(atts proposerAtts) (proposerAtts, error) {
    66  		if len(atts) < 2 {
    67  			return atts, nil
    68  		}
    69  		candidates := make([]*bitfield.Bitlist64, len(atts))
    70  		for i := 0; i < len(atts); i++ {
    71  			var err error
    72  			candidates[i], err = atts[i].AggregationBits.ToBitlist64()
    73  			if err != nil {
    74  				return nil, err
    75  			}
    76  		}
    77  		// Add selected candidates on top, those that are not selected - append at bottom.
    78  		selectedKeys, _, err := aggregation.MaxCover(candidates, len(candidates), true /* allowOverlaps */)
    79  		if err == nil {
    80  			// Pick selected attestations first, leftover attestations will be appended at the end.
    81  			// Both lists will be sorted by number of bits set.
    82  			selectedAtts := make(proposerAtts, selectedKeys.Count())
    83  			leftoverAtts := make(proposerAtts, selectedKeys.Not().Count())
    84  			for i, key := range selectedKeys.BitIndices() {
    85  				selectedAtts[i] = atts[key]
    86  			}
    87  			for i, key := range selectedKeys.Not().BitIndices() {
    88  				leftoverAtts[i] = atts[key]
    89  			}
    90  			sort.Slice(selectedAtts, func(i, j int) bool {
    91  				return selectedAtts[i].AggregationBits.Count() > selectedAtts[j].AggregationBits.Count()
    92  			})
    93  			sort.Slice(leftoverAtts, func(i, j int) bool {
    94  				return leftoverAtts[i].AggregationBits.Count() > leftoverAtts[j].AggregationBits.Count()
    95  			})
    96  			return append(selectedAtts, leftoverAtts...), nil
    97  		}
    98  		return atts, nil
    99  	}
   100  
   101  	// Select attestations. Slots are sorted from higher to lower at this point. Within slots attestations
   102  	// are sorted to maximize profitability (greedily selected, with previous attestations' bits
   103  	// evaluated before including any new attestation).
   104  	var sortedAtts proposerAtts
   105  	sort.Slice(slots, func(i, j int) bool {
   106  		return slots[i] > slots[j]
   107  	})
   108  	for _, slot := range slots {
   109  		selected, err := selectAtts(attsBySlot[slot])
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  		sortedAtts = append(sortedAtts, selected...)
   114  	}
   115  
   116  	return sortedAtts, nil
   117  }
   118  
   119  // limitToMaxAttestations limits attestations to maximum attestations per block.
   120  func (a proposerAtts) limitToMaxAttestations() proposerAtts {
   121  	if uint64(len(a)) > params.BeaconConfig().MaxAttestations {
   122  		return a[:params.BeaconConfig().MaxAttestations]
   123  	}
   124  	return a
   125  }
   126  
   127  // dedup removes duplicate attestations (ones with the same bits set on).
   128  // Important: not only exact duplicates are removed, but proper subsets are removed too
   129  // (their known bits are redundant and are already contained in their supersets).
   130  func (a proposerAtts) dedup() (proposerAtts, error) {
   131  	if len(a) < 2 {
   132  		return a, nil
   133  	}
   134  	attsByDataRoot := make(map[[32]byte][]*ethpb.Attestation, len(a))
   135  	for _, att := range a {
   136  		attDataRoot, err := att.Data.HashTreeRoot()
   137  		if err != nil {
   138  			continue
   139  		}
   140  		attsByDataRoot[attDataRoot] = append(attsByDataRoot[attDataRoot], att)
   141  	}
   142  
   143  	uniqAtts := make([]*ethpb.Attestation, 0, len(a))
   144  	for _, atts := range attsByDataRoot {
   145  		for i := 0; i < len(atts); i++ {
   146  			a := atts[i]
   147  			for j := i + 1; j < len(atts); j++ {
   148  				b := atts[j]
   149  				if c, err := a.AggregationBits.Contains(b.AggregationBits); err != nil {
   150  					return nil, err
   151  				} else if c {
   152  					// a contains b, b is redundant.
   153  					atts[j] = atts[len(atts)-1]
   154  					atts[len(atts)-1] = nil
   155  					atts = atts[:len(atts)-1]
   156  					j--
   157  				} else if c, err := b.AggregationBits.Contains(a.AggregationBits); err != nil {
   158  					return nil, err
   159  				} else if c {
   160  					// b contains a, a is redundant.
   161  					atts[i] = atts[len(atts)-1]
   162  					atts[len(atts)-1] = nil
   163  					atts = atts[:len(atts)-1]
   164  					i--
   165  					break
   166  				}
   167  			}
   168  		}
   169  		uniqAtts = append(uniqAtts, atts...)
   170  	}
   171  
   172  	return uniqAtts, nil
   173  }