github.com/prysmaticlabs/prysm@v1.4.4/shared/testutil/attestation.go (about)

     1  package testutil
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/go-bitfield"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
    12  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    14  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    15  	"github.com/prysmaticlabs/prysm/shared/bls"
    16  	"github.com/prysmaticlabs/prysm/shared/params"
    17  	"github.com/prysmaticlabs/prysm/shared/rand"
    18  	log "github.com/sirupsen/logrus"
    19  )
    20  
    21  // NewAttestation creates an attestation block with minimum marshalable fields.
    22  func NewAttestation() *ethpb.Attestation {
    23  	return &ethpb.Attestation{
    24  		AggregationBits: bitfield.Bitlist{0b1101},
    25  		Data: &ethpb.AttestationData{
    26  			BeaconBlockRoot: make([]byte, 32),
    27  			Source: &ethpb.Checkpoint{
    28  				Root: make([]byte, 32),
    29  			},
    30  			Target: &ethpb.Checkpoint{
    31  				Root: make([]byte, 32),
    32  			},
    33  		},
    34  		Signature: make([]byte, 96),
    35  	}
    36  }
    37  
    38  // GenerateAttestations creates attestations that are entirely valid, for all
    39  // the committees of the current state slot. This function expects attestations
    40  // requested to be cleanly divisible by committees per slot. If there is 1 committee
    41  // in the slot, and numToGen is set to 4, then it will return 4 attestations
    42  // for the same data with their aggregation bits split uniformly.
    43  //
    44  // If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations.
    45  func GenerateAttestations(
    46  	bState iface.BeaconState, privs []bls.SecretKey, numToGen uint64, slot types.Slot, randomRoot bool,
    47  ) ([]*ethpb.Attestation, error) {
    48  	var attestations []*ethpb.Attestation
    49  	generateHeadState := false
    50  	bState = bState.Copy()
    51  	if slot > bState.Slot() {
    52  		// Going back a slot here so there's no inclusion delay issues.
    53  		slot--
    54  		generateHeadState = true
    55  	}
    56  	currentEpoch := helpers.SlotToEpoch(slot)
    57  
    58  	targetRoot := make([]byte, 32)
    59  	var headRoot []byte
    60  	var err error
    61  	// Only calculate head state if its an attestation for the current slot or future slot.
    62  	if generateHeadState || slot == bState.Slot() {
    63  		pbState, err := v1.ProtobufBeaconState(bState.CloneInnerState())
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  		genState, err := v1.InitializeFromProtoUnsafe(pbState)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		headState := iface.BeaconState(genState)
    72  		headState, err = state.ProcessSlots(context.Background(), headState, slot+1)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		headRoot, err = helpers.BlockRootAtSlot(headState, slot)
    77  		if err != nil {
    78  			return nil, err
    79  		}
    80  		targetRoot, err = helpers.BlockRoot(headState, currentEpoch)
    81  		if err != nil {
    82  			return nil, err
    83  		}
    84  	} else {
    85  		headRoot, err = helpers.BlockRootAtSlot(bState, slot)
    86  		if err != nil {
    87  			return nil, err
    88  		}
    89  	}
    90  	if randomRoot {
    91  		randGen := rand.NewDeterministicGenerator()
    92  		b := make([]byte, 32)
    93  		_, err := randGen.Read(b)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		headRoot = b
    98  	}
    99  
   100  	activeValidatorCount, err := helpers.ActiveValidatorCount(bState, currentEpoch)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	committeesPerSlot := helpers.SlotCommitteeCount(activeValidatorCount)
   105  
   106  	if numToGen < committeesPerSlot {
   107  		log.Printf(
   108  			"Warning: %d attestations requested is less than %d committees in current slot, not all validators will be attesting.",
   109  			numToGen,
   110  			committeesPerSlot,
   111  		)
   112  	} else if numToGen > committeesPerSlot {
   113  		log.Printf(
   114  			"Warning: %d attestations requested are more than %d committees in current slot, attestations will not be perfectly efficient.",
   115  			numToGen,
   116  			committeesPerSlot,
   117  		)
   118  	}
   119  
   120  	attsPerCommittee := math.Max(float64(numToGen/committeesPerSlot), 1)
   121  	if math.Trunc(attsPerCommittee) != attsPerCommittee {
   122  		return nil, fmt.Errorf(
   123  			"requested attestations %d must be easily divisible by committees in slot %d, calculated %f",
   124  			numToGen,
   125  			committeesPerSlot,
   126  			attsPerCommittee,
   127  		)
   128  	}
   129  
   130  	domain, err := helpers.Domain(bState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconAttester, bState.GenesisValidatorRoot())
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	for c := types.CommitteeIndex(0); uint64(c) < committeesPerSlot && uint64(c) < numToGen; c++ {
   135  		committee, err := helpers.BeaconCommitteeFromState(bState, slot, c)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  
   140  		attData := &ethpb.AttestationData{
   141  			Slot:            slot,
   142  			CommitteeIndex:  c,
   143  			BeaconBlockRoot: headRoot,
   144  			Source:          bState.CurrentJustifiedCheckpoint(),
   145  			Target: &ethpb.Checkpoint{
   146  				Epoch: currentEpoch,
   147  				Root:  targetRoot,
   148  			},
   149  		}
   150  
   151  		dataRoot, err := helpers.ComputeSigningRoot(attData, domain)
   152  		if err != nil {
   153  			return nil, err
   154  		}
   155  
   156  		committeeSize := uint64(len(committee))
   157  		bitsPerAtt := committeeSize / uint64(attsPerCommittee)
   158  		for i := uint64(0); i < committeeSize; i += bitsPerAtt {
   159  			aggregationBits := bitfield.NewBitlist(committeeSize)
   160  			var sigs []bls.Signature
   161  			for b := i; b < i+bitsPerAtt; b++ {
   162  				aggregationBits.SetBitAt(b, true)
   163  				sigs = append(sigs, privs[committee[b]].Sign(dataRoot[:]))
   164  			}
   165  
   166  			// bls.AggregateSignatures will return nil if sigs is 0.
   167  			if len(sigs) == 0 {
   168  				continue
   169  			}
   170  
   171  			att := &ethpb.Attestation{
   172  				Data:            attData,
   173  				AggregationBits: aggregationBits,
   174  				Signature:       bls.AggregateSignatures(sigs).Marshal(),
   175  			}
   176  			attestations = append(attestations, att)
   177  		}
   178  	}
   179  	return attestations, nil
   180  }
   181  
   182  // HydrateAttestation hydrates an attestation object with correct field length sizes
   183  // to comply with fssz marshalling and unmarshalling rules.
   184  func HydrateAttestation(a *ethpb.Attestation) *ethpb.Attestation {
   185  	if a.Signature == nil {
   186  		a.Signature = make([]byte, 96)
   187  	}
   188  	if a.AggregationBits == nil {
   189  		a.AggregationBits = make([]byte, 1)
   190  	}
   191  	if a.Data == nil {
   192  		a.Data = &ethpb.AttestationData{}
   193  	}
   194  	a.Data = HydrateAttestationData(a.Data)
   195  	return a
   196  }
   197  
   198  // HydrateAttestationData hydrates an attestation data object with correct field length sizes
   199  // to comply with fssz marshalling and unmarshalling rules.
   200  func HydrateAttestationData(d *ethpb.AttestationData) *ethpb.AttestationData {
   201  	if d.BeaconBlockRoot == nil {
   202  		d.BeaconBlockRoot = make([]byte, 32)
   203  	}
   204  	if d.Target == nil {
   205  		d.Target = &ethpb.Checkpoint{}
   206  	}
   207  	if d.Target.Root == nil {
   208  		d.Target.Root = make([]byte, 32)
   209  	}
   210  	if d.Source == nil {
   211  		d.Source = &ethpb.Checkpoint{}
   212  	}
   213  	if d.Source.Root == nil {
   214  		d.Source.Root = make([]byte, 32)
   215  	}
   216  	return d
   217  }
   218  
   219  // HydrateIndexedAttestation hydrates an indexed attestation with correct field length sizes
   220  // to comply with fssz marshalling and unmarshalling rules.
   221  func HydrateIndexedAttestation(a *ethpb.IndexedAttestation) *ethpb.IndexedAttestation {
   222  	if a.Signature == nil {
   223  		a.Signature = make([]byte, 96)
   224  	}
   225  	if a.Data == nil {
   226  		a.Data = &ethpb.AttestationData{}
   227  	}
   228  	a.Data = HydrateAttestationData(a.Data)
   229  	return a
   230  }