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  }