github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/attestation.go (about) 1 package blocks 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/pkg/errors" 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 10 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 11 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 12 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 13 "github.com/prysmaticlabs/prysm/proto/interfaces" 14 "github.com/prysmaticlabs/prysm/shared/attestationutil" 15 "github.com/prysmaticlabs/prysm/shared/bls" 16 "github.com/prysmaticlabs/prysm/shared/params" 17 "go.opencensus.io/trace" 18 ) 19 20 // ProcessAttestations applies processing operations to a block's inner attestation 21 // records. 22 func ProcessAttestations( 23 ctx context.Context, 24 beaconState iface.BeaconState, 25 b interfaces.SignedBeaconBlock, 26 ) (iface.BeaconState, error) { 27 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 28 return nil, err 29 } 30 31 var err error 32 for idx, attestation := range b.Block().Body().Attestations() { 33 beaconState, err = ProcessAttestation(ctx, beaconState, attestation) 34 if err != nil { 35 return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx) 36 } 37 } 38 return beaconState, nil 39 } 40 41 // ProcessAttestation verifies an input attestation can pass through processing using the given beacon state. 42 // 43 // Spec pseudocode definition: 44 // def process_attestation(state: BeaconState, attestation: Attestation) -> None: 45 // data = attestation.data 46 // assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) 47 // assert data.target.epoch == compute_epoch_at_slot(data.slot) 48 // assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH 49 // assert data.index < get_committee_count_per_slot(state, data.target.epoch) 50 // 51 // committee = get_beacon_committee(state, data.slot, data.index) 52 // assert len(attestation.aggregation_bits) == len(committee) 53 // 54 // pending_attestation = PendingAttestation( 55 // data=data, 56 // aggregation_bits=attestation.aggregation_bits, 57 // inclusion_delay=state.slot - data.slot, 58 // proposer_index=get_beacon_proposer_index(state), 59 // ) 60 // 61 // if data.target.epoch == get_current_epoch(state): 62 // assert data.source == state.current_justified_checkpoint 63 // state.current_epoch_attestations.append(pending_attestation) 64 // else: 65 // assert data.source == state.previous_justified_checkpoint 66 // state.previous_epoch_attestations.append(pending_attestation) 67 // 68 // # Verify signature 69 // assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) 70 func ProcessAttestation( 71 ctx context.Context, 72 beaconState iface.BeaconState, 73 att *ethpb.Attestation, 74 ) (iface.BeaconState, error) { 75 beaconState, err := ProcessAttestationNoVerifySignature(ctx, beaconState, att) 76 if err != nil { 77 return nil, err 78 } 79 return beaconState, VerifyAttestationSignature(ctx, beaconState, att) 80 } 81 82 // ProcessAttestationsNoVerifySignature applies processing operations to a block's inner attestation 83 // records. The only difference would be that the attestation signature would not be verified. 84 func ProcessAttestationsNoVerifySignature( 85 ctx context.Context, 86 beaconState iface.BeaconState, 87 b interfaces.SignedBeaconBlock, 88 ) (iface.BeaconState, error) { 89 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 90 return nil, err 91 } 92 body := b.Block().Body() 93 var err error 94 for idx, attestation := range body.Attestations() { 95 beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, attestation) 96 if err != nil { 97 return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx) 98 } 99 } 100 return beaconState, nil 101 } 102 103 // VerifyAttestationNoVerifySignature verifies the attestation without verifying the attestation signature. This is 104 // used before processing attestation with the beacon state. 105 func VerifyAttestationNoVerifySignature( 106 ctx context.Context, 107 beaconState iface.ReadOnlyBeaconState, 108 att *ethpb.Attestation, 109 ) error { 110 ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationNoVerifySignature") 111 defer span.End() 112 113 if err := helpers.ValidateNilAttestation(att); err != nil { 114 return err 115 } 116 currEpoch := helpers.CurrentEpoch(beaconState) 117 prevEpoch := helpers.PrevEpoch(beaconState) 118 data := att.Data 119 if data.Target.Epoch != prevEpoch && data.Target.Epoch != currEpoch { 120 return fmt.Errorf( 121 "expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)", 122 data.Target.Epoch, 123 prevEpoch, 124 currEpoch, 125 ) 126 } 127 128 if data.Target.Epoch == currEpoch { 129 if !beaconState.MatchCurrentJustifiedCheckpoint(data.Source) { 130 return errors.New("source check point not equal to current justified checkpoint") 131 } 132 } else { 133 if !beaconState.MatchPreviousJustifiedCheckpoint(data.Source) { 134 return errors.New("source check point not equal to previous justified checkpoint") 135 } 136 } 137 138 if err := helpers.ValidateSlotTargetEpoch(att.Data); err != nil { 139 return err 140 } 141 142 s := att.Data.Slot 143 minInclusionCheck := s+params.BeaconConfig().MinAttestationInclusionDelay <= beaconState.Slot() 144 epochInclusionCheck := beaconState.Slot() <= s+params.BeaconConfig().SlotsPerEpoch 145 if !minInclusionCheck { 146 return fmt.Errorf( 147 "attestation slot %d + inclusion delay %d > state slot %d", 148 s, 149 params.BeaconConfig().MinAttestationInclusionDelay, 150 beaconState.Slot(), 151 ) 152 } 153 if !epochInclusionCheck { 154 return fmt.Errorf( 155 "state slot %d > attestation slot %d + SLOTS_PER_EPOCH %d", 156 beaconState.Slot(), 157 s, 158 params.BeaconConfig().SlotsPerEpoch, 159 ) 160 } 161 activeValidatorCount, err := helpers.ActiveValidatorCount(beaconState, att.Data.Target.Epoch) 162 if err != nil { 163 return err 164 } 165 c := helpers.SlotCommitteeCount(activeValidatorCount) 166 if uint64(att.Data.CommitteeIndex) >= c { 167 return fmt.Errorf("committee index %d >= committee count %d", att.Data.CommitteeIndex, c) 168 } 169 170 if err := helpers.VerifyAttestationBitfieldLengths(beaconState, att); err != nil { 171 return errors.Wrap(err, "could not verify attestation bitfields") 172 } 173 174 // Verify attesting indices are correct. 175 committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex) 176 if err != nil { 177 return err 178 } 179 indexedAtt, err := attestationutil.ConvertToIndexed(ctx, att, committee) 180 if err != nil { 181 return err 182 } 183 184 return attestationutil.IsValidAttestationIndices(ctx, indexedAtt) 185 } 186 187 // ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This 188 // method is used to validate attestations whose signatures have already been verified. 189 func ProcessAttestationNoVerifySignature( 190 ctx context.Context, 191 beaconState iface.BeaconState, 192 att *ethpb.Attestation, 193 ) (iface.BeaconState, error) { 194 ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature") 195 defer span.End() 196 197 if err := VerifyAttestationNoVerifySignature(ctx, beaconState, att); err != nil { 198 return nil, err 199 } 200 201 currEpoch := helpers.CurrentEpoch(beaconState) 202 data := att.Data 203 s := att.Data.Slot 204 proposerIndex, err := helpers.BeaconProposerIndex(beaconState) 205 if err != nil { 206 return nil, err 207 } 208 pendingAtt := &pb.PendingAttestation{ 209 Data: data, 210 AggregationBits: att.AggregationBits, 211 InclusionDelay: beaconState.Slot() - s, 212 ProposerIndex: proposerIndex, 213 } 214 215 if data.Target.Epoch == currEpoch { 216 if err := beaconState.AppendCurrentEpochAttestations(pendingAtt); err != nil { 217 return nil, err 218 } 219 } else { 220 if err := beaconState.AppendPreviousEpochAttestations(pendingAtt); err != nil { 221 return nil, err 222 } 223 } 224 225 return beaconState, nil 226 } 227 228 // VerifyAttestationSignature converts and attestation into an indexed attestation and verifies 229 // the signature in that attestation. 230 func VerifyAttestationSignature(ctx context.Context, beaconState iface.ReadOnlyBeaconState, att *ethpb.Attestation) error { 231 if err := helpers.ValidateNilAttestation(att); err != nil { 232 return err 233 } 234 committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex) 235 if err != nil { 236 return err 237 } 238 indexedAtt, err := attestationutil.ConvertToIndexed(ctx, att, committee) 239 if err != nil { 240 return err 241 } 242 return VerifyIndexedAttestation(ctx, beaconState, indexedAtt) 243 } 244 245 // VerifyIndexedAttestation determines the validity of an indexed attestation. 246 // 247 // Spec pseudocode definition: 248 // def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool: 249 // """ 250 // Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature. 251 // """ 252 // # Verify indices are sorted and unique 253 // indices = indexed_attestation.attesting_indices 254 // if len(indices) == 0 or not indices == sorted(set(indices)): 255 // return False 256 // # Verify aggregate signature 257 // pubkeys = [state.validators[i].pubkey for i in indices] 258 // domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) 259 // signing_root = compute_signing_root(indexed_attestation.data, domain) 260 // return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) 261 func VerifyIndexedAttestation(ctx context.Context, beaconState iface.ReadOnlyBeaconState, indexedAtt *ethpb.IndexedAttestation) error { 262 ctx, span := trace.StartSpan(ctx, "core.VerifyIndexedAttestation") 263 defer span.End() 264 265 if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil { 266 return err 267 } 268 domain, err := helpers.Domain( 269 beaconState.Fork(), 270 indexedAtt.Data.Target.Epoch, 271 params.BeaconConfig().DomainBeaconAttester, 272 beaconState.GenesisValidatorRoot(), 273 ) 274 if err != nil { 275 return err 276 } 277 indices := indexedAtt.AttestingIndices 278 var pubkeys []bls.PublicKey 279 for i := 0; i < len(indices); i++ { 280 pubkeyAtIdx := beaconState.PubkeyAtIndex(types.ValidatorIndex(indices[i])) 281 pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:]) 282 if err != nil { 283 return errors.Wrap(err, "could not deserialize validator public key") 284 } 285 pubkeys = append(pubkeys, pk) 286 } 287 return attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain) 288 }