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 }