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

     1  package testutil
     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  	v1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
    12  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    13  	"github.com/prysmaticlabs/prysm/shared/bls"
    14  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    15  	"github.com/prysmaticlabs/prysm/shared/params"
    16  	"github.com/prysmaticlabs/prysm/shared/rand"
    17  )
    18  
    19  // BlockGenConfig is used to define the requested conditions
    20  // for block generation.
    21  type BlockGenConfig struct {
    22  	NumProposerSlashings uint64
    23  	NumAttesterSlashings uint64
    24  	NumAttestations      uint64
    25  	NumDeposits          uint64
    26  	NumVoluntaryExits    uint64
    27  }
    28  
    29  // DefaultBlockGenConfig returns the block config that utilizes the
    30  // current params in the beacon config.
    31  func DefaultBlockGenConfig() *BlockGenConfig {
    32  	return &BlockGenConfig{
    33  		NumProposerSlashings: 0,
    34  		NumAttesterSlashings: 0,
    35  		NumAttestations:      1,
    36  		NumDeposits:          0,
    37  		NumVoluntaryExits:    0,
    38  	}
    39  }
    40  
    41  // NewBeaconBlock creates a beacon block with minimum marshalable fields.
    42  func NewBeaconBlock() *ethpb.SignedBeaconBlock {
    43  	return &ethpb.SignedBeaconBlock{
    44  		Block: &ethpb.BeaconBlock{
    45  			ParentRoot: make([]byte, 32),
    46  			StateRoot:  make([]byte, 32),
    47  			Body: &ethpb.BeaconBlockBody{
    48  				RandaoReveal: make([]byte, 96),
    49  				Eth1Data: &ethpb.Eth1Data{
    50  					DepositRoot: make([]byte, 32),
    51  					BlockHash:   make([]byte, 32),
    52  				},
    53  				Graffiti:          make([]byte, 32),
    54  				Attestations:      []*ethpb.Attestation{},
    55  				AttesterSlashings: []*ethpb.AttesterSlashing{},
    56  				Deposits:          []*ethpb.Deposit{},
    57  				ProposerSlashings: []*ethpb.ProposerSlashing{},
    58  				VoluntaryExits:    []*ethpb.SignedVoluntaryExit{},
    59  			},
    60  		},
    61  		Signature: make([]byte, 96),
    62  	}
    63  }
    64  
    65  // GenerateFullBlock generates a fully valid block with the requested parameters.
    66  // Use BlockGenConfig to declare the conditions you would like the block generated under.
    67  func GenerateFullBlock(
    68  	bState iface.BeaconState,
    69  	privs []bls.SecretKey,
    70  	conf *BlockGenConfig,
    71  	slot types.Slot,
    72  ) (*ethpb.SignedBeaconBlock, error) {
    73  	ctx := context.Background()
    74  	currentSlot := bState.Slot()
    75  	if currentSlot > slot {
    76  		return nil, fmt.Errorf("current slot in state is larger than given slot. %d > %d", currentSlot, slot)
    77  	}
    78  	bState = bState.Copy()
    79  
    80  	if conf == nil {
    81  		conf = &BlockGenConfig{}
    82  	}
    83  
    84  	var err error
    85  	var pSlashings []*ethpb.ProposerSlashing
    86  	numToGen := conf.NumProposerSlashings
    87  	if numToGen > 0 {
    88  		pSlashings, err = generateProposerSlashings(bState, privs, numToGen)
    89  		if err != nil {
    90  			return nil, errors.Wrapf(err, "failed generating %d proposer slashings:", numToGen)
    91  		}
    92  	}
    93  
    94  	numToGen = conf.NumAttesterSlashings
    95  	var aSlashings []*ethpb.AttesterSlashing
    96  	if numToGen > 0 {
    97  		aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
    98  		if err != nil {
    99  			return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
   100  		}
   101  	}
   102  
   103  	numToGen = conf.NumAttestations
   104  	var atts []*ethpb.Attestation
   105  	if numToGen > 0 {
   106  		atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
   107  		if err != nil {
   108  			return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
   109  		}
   110  	}
   111  
   112  	numToGen = conf.NumDeposits
   113  	var newDeposits []*ethpb.Deposit
   114  	eth1Data := bState.Eth1Data()
   115  	if numToGen > 0 {
   116  		newDeposits, eth1Data, err = generateDepositsAndEth1Data(bState, numToGen)
   117  		if err != nil {
   118  			return nil, errors.Wrapf(err, "failed generating %d deposits:", numToGen)
   119  		}
   120  	}
   121  
   122  	numToGen = conf.NumVoluntaryExits
   123  	var exits []*ethpb.SignedVoluntaryExit
   124  	if numToGen > 0 {
   125  		exits, err = generateVoluntaryExits(bState, privs, numToGen)
   126  		if err != nil {
   127  			return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
   128  		}
   129  	}
   130  
   131  	newHeader := bState.LatestBlockHeader()
   132  	prevStateRoot, err := bState.HashTreeRoot(ctx)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	newHeader.StateRoot = prevStateRoot[:]
   137  	parentRoot, err := newHeader.HashTreeRoot()
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	if slot == currentSlot {
   143  		slot = currentSlot + 1
   144  	}
   145  
   146  	// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
   147  	// function deterministic on beacon state slot.
   148  	if err := bState.SetSlot(slot); err != nil {
   149  		return nil, err
   150  	}
   151  	reveal, err := RandaoReveal(bState, helpers.CurrentEpoch(bState), privs)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	idx, err := helpers.BeaconProposerIndex(bState)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	block := &ethpb.BeaconBlock{
   162  		Slot:          slot,
   163  		ParentRoot:    parentRoot[:],
   164  		ProposerIndex: idx,
   165  		Body: &ethpb.BeaconBlockBody{
   166  			Eth1Data:          eth1Data,
   167  			RandaoReveal:      reveal,
   168  			ProposerSlashings: pSlashings,
   169  			AttesterSlashings: aSlashings,
   170  			Attestations:      atts,
   171  			VoluntaryExits:    exits,
   172  			Deposits:          newDeposits,
   173  			Graffiti:          make([]byte, 32),
   174  		},
   175  	}
   176  	if err := bState.SetSlot(currentSlot); err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	signature, err := BlockSignature(bState, block, privs)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return &ethpb.SignedBeaconBlock{Block: block, Signature: signature.Marshal()}, nil
   186  }
   187  
   188  // GenerateProposerSlashingForValidator for a specific validator index.
   189  func GenerateProposerSlashingForValidator(
   190  	bState iface.BeaconState,
   191  	priv bls.SecretKey,
   192  	idx types.ValidatorIndex,
   193  ) (*ethpb.ProposerSlashing, error) {
   194  	header1 := HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   195  		Header: &ethpb.BeaconBlockHeader{
   196  			ProposerIndex: idx,
   197  			Slot:          bState.Slot(),
   198  			BodyRoot:      bytesutil.PadTo([]byte{0, 1, 0}, 32),
   199  		},
   200  	})
   201  	currentEpoch := helpers.CurrentEpoch(bState)
   202  	var err error
   203  	header1.Signature, err = helpers.ComputeDomainAndSign(bState, currentEpoch, header1.Header, params.BeaconConfig().DomainBeaconProposer, priv)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	header2 := &ethpb.SignedBeaconBlockHeader{
   209  		Header: &ethpb.BeaconBlockHeader{
   210  			ProposerIndex: idx,
   211  			Slot:          bState.Slot(),
   212  			BodyRoot:      bytesutil.PadTo([]byte{0, 2, 0}, 32),
   213  			StateRoot:     make([]byte, 32),
   214  			ParentRoot:    make([]byte, 32),
   215  		},
   216  	}
   217  	header2.Signature, err = helpers.ComputeDomainAndSign(bState, currentEpoch, header2.Header, params.BeaconConfig().DomainBeaconProposer, priv)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	return &ethpb.ProposerSlashing{
   223  		Header_1: header1,
   224  		Header_2: header2,
   225  	}, nil
   226  }
   227  
   228  func generateProposerSlashings(
   229  	bState iface.BeaconState,
   230  	privs []bls.SecretKey,
   231  	numSlashings uint64,
   232  ) ([]*ethpb.ProposerSlashing, error) {
   233  	proposerSlashings := make([]*ethpb.ProposerSlashing, numSlashings)
   234  	for i := uint64(0); i < numSlashings; i++ {
   235  		proposerIndex, err := randValIndex(bState)
   236  		if err != nil {
   237  			return nil, err
   238  		}
   239  		slashing, err := GenerateProposerSlashingForValidator(bState, privs[proposerIndex], proposerIndex)
   240  		if err != nil {
   241  			return nil, err
   242  		}
   243  		proposerSlashings[i] = slashing
   244  	}
   245  	return proposerSlashings, nil
   246  }
   247  
   248  // GenerateAttesterSlashingForValidator for a specific validator index.
   249  func GenerateAttesterSlashingForValidator(
   250  	bState iface.BeaconState,
   251  	priv bls.SecretKey,
   252  	idx types.ValidatorIndex,
   253  ) (*ethpb.AttesterSlashing, error) {
   254  	currentEpoch := helpers.CurrentEpoch(bState)
   255  
   256  	att1 := &ethpb.IndexedAttestation{
   257  		Data: &ethpb.AttestationData{
   258  			Slot:            bState.Slot(),
   259  			CommitteeIndex:  0,
   260  			BeaconBlockRoot: make([]byte, 32),
   261  			Target: &ethpb.Checkpoint{
   262  				Epoch: currentEpoch,
   263  				Root:  params.BeaconConfig().ZeroHash[:],
   264  			},
   265  			Source: &ethpb.Checkpoint{
   266  				Epoch: currentEpoch + 1,
   267  				Root:  params.BeaconConfig().ZeroHash[:],
   268  			},
   269  		},
   270  		AttestingIndices: []uint64{uint64(idx)},
   271  	}
   272  	var err error
   273  	att1.Signature, err = helpers.ComputeDomainAndSign(bState, currentEpoch, att1.Data, params.BeaconConfig().DomainBeaconAttester, priv)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	att2 := &ethpb.IndexedAttestation{
   279  		Data: &ethpb.AttestationData{
   280  			Slot:            bState.Slot(),
   281  			CommitteeIndex:  0,
   282  			BeaconBlockRoot: make([]byte, 32),
   283  			Target: &ethpb.Checkpoint{
   284  				Epoch: currentEpoch,
   285  				Root:  params.BeaconConfig().ZeroHash[:],
   286  			},
   287  			Source: &ethpb.Checkpoint{
   288  				Epoch: currentEpoch,
   289  				Root:  params.BeaconConfig().ZeroHash[:],
   290  			},
   291  		},
   292  		AttestingIndices: []uint64{uint64(idx)},
   293  	}
   294  	att2.Signature, err = helpers.ComputeDomainAndSign(bState, currentEpoch, att2.Data, params.BeaconConfig().DomainBeaconAttester, priv)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	return &ethpb.AttesterSlashing{
   300  		Attestation_1: att1,
   301  		Attestation_2: att2,
   302  	}, nil
   303  }
   304  
   305  func generateAttesterSlashings(
   306  	bState iface.BeaconState,
   307  	privs []bls.SecretKey,
   308  	numSlashings uint64,
   309  ) ([]*ethpb.AttesterSlashing, error) {
   310  	attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
   311  	randGen := rand.NewDeterministicGenerator()
   312  	for i := uint64(0); i < numSlashings; i++ {
   313  		committeeIndex := randGen.Uint64() % params.BeaconConfig().MaxCommitteesPerSlot
   314  		committee, err := helpers.BeaconCommitteeFromState(bState, bState.Slot(), types.CommitteeIndex(committeeIndex))
   315  		if err != nil {
   316  			return nil, err
   317  		}
   318  		randIndex := randGen.Uint64() % uint64(len(committee))
   319  		valIndex := committee[randIndex]
   320  		slashing, err := GenerateAttesterSlashingForValidator(bState, privs[valIndex], valIndex)
   321  		if err != nil {
   322  			return nil, err
   323  		}
   324  		attesterSlashings[i] = slashing
   325  	}
   326  	return attesterSlashings, nil
   327  }
   328  
   329  func generateDepositsAndEth1Data(
   330  	bState iface.BeaconState,
   331  	numDeposits uint64,
   332  ) (
   333  	[]*ethpb.Deposit,
   334  	*ethpb.Eth1Data,
   335  	error,
   336  ) {
   337  	previousDepsLen := bState.Eth1DepositIndex()
   338  	currentDeposits, _, err := DeterministicDepositsAndKeys(previousDepsLen + numDeposits)
   339  	if err != nil {
   340  		return nil, nil, errors.Wrap(err, "could not get deposits")
   341  	}
   342  	eth1Data, err := DeterministicEth1Data(len(currentDeposits))
   343  	if err != nil {
   344  		return nil, nil, errors.Wrap(err, "could not get eth1data")
   345  	}
   346  	return currentDeposits[previousDepsLen:], eth1Data, nil
   347  }
   348  
   349  func generateVoluntaryExits(
   350  	bState iface.BeaconState,
   351  	privs []bls.SecretKey,
   352  	numExits uint64,
   353  ) ([]*ethpb.SignedVoluntaryExit, error) {
   354  	currentEpoch := helpers.CurrentEpoch(bState)
   355  
   356  	voluntaryExits := make([]*ethpb.SignedVoluntaryExit, numExits)
   357  	for i := 0; i < len(voluntaryExits); i++ {
   358  		valIndex, err := randValIndex(bState)
   359  		if err != nil {
   360  			return nil, err
   361  		}
   362  		exit := &ethpb.SignedVoluntaryExit{
   363  			Exit: &ethpb.VoluntaryExit{
   364  				Epoch:          helpers.PrevEpoch(bState),
   365  				ValidatorIndex: valIndex,
   366  			},
   367  		}
   368  		exit.Signature, err = helpers.ComputeDomainAndSign(bState, currentEpoch, exit.Exit, params.BeaconConfig().DomainVoluntaryExit, privs[valIndex])
   369  		if err != nil {
   370  			return nil, err
   371  		}
   372  		voluntaryExits[i] = exit
   373  	}
   374  	return voluntaryExits, nil
   375  }
   376  
   377  func randValIndex(bState iface.BeaconState) (types.ValidatorIndex, error) {
   378  	activeCount, err := helpers.ActiveValidatorCount(bState, helpers.CurrentEpoch(bState))
   379  	if err != nil {
   380  		return 0, err
   381  	}
   382  	return types.ValidatorIndex(rand.NewGenerator().Uint64() % activeCount), nil
   383  }
   384  
   385  // HydrateSignedBeaconHeader hydrates a signed beacon block header with correct field length sizes
   386  // to comply with fssz marshalling and unmarshalling rules.
   387  func HydrateSignedBeaconHeader(h *ethpb.SignedBeaconBlockHeader) *ethpb.SignedBeaconBlockHeader {
   388  	if h.Signature == nil {
   389  		h.Signature = make([]byte, params.BeaconConfig().BLSSignatureLength)
   390  	}
   391  	h.Header = HydrateBeaconHeader(h.Header)
   392  	return h
   393  }
   394  
   395  // HydrateBeaconHeader hydrates a beacon block header with correct field length sizes
   396  // to comply with fssz marshalling and unmarshalling rules.
   397  func HydrateBeaconHeader(h *ethpb.BeaconBlockHeader) *ethpb.BeaconBlockHeader {
   398  	if h == nil {
   399  		h = &ethpb.BeaconBlockHeader{}
   400  	}
   401  	if h.BodyRoot == nil {
   402  		h.BodyRoot = make([]byte, 32)
   403  	}
   404  	if h.StateRoot == nil {
   405  		h.StateRoot = make([]byte, 32)
   406  	}
   407  	if h.ParentRoot == nil {
   408  		h.ParentRoot = make([]byte, 32)
   409  	}
   410  	return h
   411  }
   412  
   413  // HydrateSignedBeaconBlock hydrates a signed beacon block with correct field length sizes
   414  // to comply with fssz marshalling and unmarshalling rules.
   415  func HydrateSignedBeaconBlock(b *ethpb.SignedBeaconBlock) *ethpb.SignedBeaconBlock {
   416  	if b.Signature == nil {
   417  		b.Signature = make([]byte, params.BeaconConfig().BLSSignatureLength)
   418  	}
   419  	b.Block = HydrateBeaconBlock(b.Block)
   420  	return b
   421  }
   422  
   423  // HydrateBeaconBlock hydrates a beacon block with correct field length sizes
   424  // to comply with fssz marshalling and unmarshalling rules.
   425  func HydrateBeaconBlock(b *ethpb.BeaconBlock) *ethpb.BeaconBlock {
   426  	if b == nil {
   427  		b = &ethpb.BeaconBlock{}
   428  	}
   429  	if b.ParentRoot == nil {
   430  		b.ParentRoot = make([]byte, 32)
   431  	}
   432  	if b.StateRoot == nil {
   433  		b.StateRoot = make([]byte, 32)
   434  	}
   435  	b.Body = HydrateBeaconBlockBody(b.Body)
   436  	return b
   437  }
   438  
   439  // HydrateBeaconBlockBody hydrates a beacon block body with correct field length sizes
   440  // to comply with fssz marshalling and unmarshalling rules.
   441  func HydrateBeaconBlockBody(b *ethpb.BeaconBlockBody) *ethpb.BeaconBlockBody {
   442  	if b == nil {
   443  		b = &ethpb.BeaconBlockBody{}
   444  	}
   445  	if b.RandaoReveal == nil {
   446  		b.RandaoReveal = make([]byte, params.BeaconConfig().BLSSignatureLength)
   447  	}
   448  	if b.Graffiti == nil {
   449  		b.Graffiti = make([]byte, 32)
   450  	}
   451  	if b.Eth1Data == nil {
   452  		b.Eth1Data = &ethpb.Eth1Data{
   453  			DepositRoot: make([]byte, 32),
   454  			BlockHash:   make([]byte, 32),
   455  		}
   456  	}
   457  	return b
   458  }
   459  
   460  // HydrateV1SignedBeaconBlock hydrates a signed beacon block with correct field length sizes
   461  // to comply with fssz marshalling and unmarshalling rules.
   462  func HydrateV1SignedBeaconBlock(b *v1.SignedBeaconBlock) *v1.SignedBeaconBlock {
   463  	if b.Signature == nil {
   464  		b.Signature = make([]byte, params.BeaconConfig().BLSSignatureLength)
   465  	}
   466  	b.Block = HydrateV1BeaconBlock(b.Block)
   467  	return b
   468  }
   469  
   470  // HydrateV1BeaconBlock hydrates a beacon block with correct field length sizes
   471  // to comply with fssz marshalling and unmarshalling rules.
   472  func HydrateV1BeaconBlock(b *v1.BeaconBlock) *v1.BeaconBlock {
   473  	if b == nil {
   474  		b = &v1.BeaconBlock{}
   475  	}
   476  	if b.ParentRoot == nil {
   477  		b.ParentRoot = make([]byte, 32)
   478  	}
   479  	if b.StateRoot == nil {
   480  		b.StateRoot = make([]byte, 32)
   481  	}
   482  	b.Body = HydrateV1BeaconBlockBody(b.Body)
   483  	return b
   484  }
   485  
   486  // HydrateV1BeaconBlockBody hydrates a beacon block body with correct field length sizes
   487  // to comply with fssz marshalling and unmarshalling rules.
   488  func HydrateV1BeaconBlockBody(b *v1.BeaconBlockBody) *v1.BeaconBlockBody {
   489  	if b == nil {
   490  		b = &v1.BeaconBlockBody{}
   491  	}
   492  	if b.RandaoReveal == nil {
   493  		b.RandaoReveal = make([]byte, params.BeaconConfig().BLSSignatureLength)
   494  	}
   495  	if b.Graffiti == nil {
   496  		b.Graffiti = make([]byte, 32)
   497  	}
   498  	if b.Eth1Data == nil {
   499  		b.Eth1Data = &v1.Eth1Data{
   500  			DepositRoot: make([]byte, 32),
   501  			BlockHash:   make([]byte, 32),
   502  		}
   503  	}
   504  	return b
   505  }