github.com/prysmaticlabs/prysm@v1.4.4/shared/interop/generate_genesis_state.go (about)

     1  // Package interop contains deterministic utilities for generating
     2  // genesis states and keys.
     3  package interop
     4  
     5  import (
     6  	"context"
     7  	"sync"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    11  	coreState "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    13  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    14  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    15  	"github.com/prysmaticlabs/prysm/shared/bls"
    16  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    17  	"github.com/prysmaticlabs/prysm/shared/mputil"
    18  	"github.com/prysmaticlabs/prysm/shared/params"
    19  	"github.com/prysmaticlabs/prysm/shared/timeutils"
    20  	"github.com/prysmaticlabs/prysm/shared/trieutil"
    21  )
    22  
    23  var (
    24  	// This is the recommended mock eth1 block hash according to the Ethereum consensus interop guidelines.
    25  	// https://github.com/ethereum/eth2.0-pm/blob/a085c9870f3956d6228ed2a40cd37f0c6580ecd7/interop/mocked_start/README.md
    26  	mockEth1BlockHash = []byte{66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66}
    27  )
    28  
    29  // GenerateGenesisState deterministically given a genesis time and number of validators.
    30  // If a genesis time of 0 is supplied it is set to the current time.
    31  func GenerateGenesisState(ctx context.Context, genesisTime, numValidators uint64) (*pb.BeaconState, []*ethpb.Deposit, error) {
    32  	privKeys, pubKeys, err := DeterministicallyGenerateKeys(0 /*startIndex*/, numValidators)
    33  	if err != nil {
    34  		return nil, nil, errors.Wrapf(err, "could not deterministically generate keys for %d validators", numValidators)
    35  	}
    36  	depositDataItems, depositDataRoots, err := DepositDataFromKeys(privKeys, pubKeys)
    37  	if err != nil {
    38  		return nil, nil, errors.Wrap(err, "could not generate deposit data from keys")
    39  	}
    40  	return GenerateGenesisStateFromDepositData(ctx, genesisTime, depositDataItems, depositDataRoots)
    41  }
    42  
    43  // GenerateGenesisStateFromDepositData creates a genesis state given a list of
    44  // deposit data items and their corresponding roots.
    45  func GenerateGenesisStateFromDepositData(
    46  	ctx context.Context, genesisTime uint64, depositData []*ethpb.Deposit_Data, depositDataRoots [][]byte,
    47  ) (*pb.BeaconState, []*ethpb.Deposit, error) {
    48  	trie, err := trieutil.GenerateTrieFromItems(depositDataRoots, params.BeaconConfig().DepositContractTreeDepth)
    49  	if err != nil {
    50  		return nil, nil, errors.Wrap(err, "could not generate Merkle trie for deposit proofs")
    51  	}
    52  	deposits, err := GenerateDepositsFromData(depositData, trie)
    53  	if err != nil {
    54  		return nil, nil, errors.Wrap(err, "could not generate deposits from the deposit data provided")
    55  	}
    56  	root := trie.Root()
    57  	if genesisTime == 0 {
    58  		genesisTime = uint64(timeutils.Now().Unix())
    59  	}
    60  	beaconState, err := coreState.GenesisBeaconState(ctx, deposits, genesisTime, &ethpb.Eth1Data{
    61  		DepositRoot:  root[:],
    62  		DepositCount: uint64(len(deposits)),
    63  		BlockHash:    mockEth1BlockHash,
    64  	})
    65  	if err != nil {
    66  		return nil, nil, errors.Wrap(err, "could not generate genesis state")
    67  	}
    68  
    69  	pbState, err := v1.ProtobufBeaconState(beaconState.CloneInnerState())
    70  	if err != nil {
    71  		return nil, nil, err
    72  	}
    73  	return pbState, deposits, nil
    74  }
    75  
    76  // GenerateDepositsFromData a list of deposit items by creating proofs for each of them from a sparse Merkle trie.
    77  func GenerateDepositsFromData(depositDataItems []*ethpb.Deposit_Data, trie *trieutil.SparseMerkleTrie) ([]*ethpb.Deposit, error) {
    78  	deposits := make([]*ethpb.Deposit, len(depositDataItems))
    79  	results, err := mputil.Scatter(len(depositDataItems), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) {
    80  		return generateDepositsFromData(depositDataItems[offset:offset+entries], offset, trie)
    81  	})
    82  	if err != nil {
    83  		return nil, errors.Wrap(err, "failed to generate deposits from data")
    84  	}
    85  	for _, result := range results {
    86  		if depositExtent, ok := result.Extent.([]*ethpb.Deposit); ok {
    87  			copy(deposits[result.Offset:], depositExtent)
    88  		} else {
    89  			return nil, errors.New("extent not of expected type")
    90  		}
    91  	}
    92  	return deposits, nil
    93  }
    94  
    95  // generateDepositsFromData a list of deposit items by creating proofs for each of them from a sparse Merkle trie.
    96  func generateDepositsFromData(depositDataItems []*ethpb.Deposit_Data, offset int, trie *trieutil.SparseMerkleTrie) ([]*ethpb.Deposit, error) {
    97  	deposits := make([]*ethpb.Deposit, len(depositDataItems))
    98  	for i, item := range depositDataItems {
    99  		proof, err := trie.MerkleProof(i + offset)
   100  		if err != nil {
   101  			return nil, errors.Wrapf(err, "could not generate proof for deposit %d", i+offset)
   102  		}
   103  		deposits[i] = &ethpb.Deposit{
   104  			Proof: proof,
   105  			Data:  item,
   106  		}
   107  	}
   108  	return deposits, nil
   109  }
   110  
   111  // DepositDataFromKeys generates a list of deposit data items from a set of BLS validator keys.
   112  func DepositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
   113  	type depositData struct {
   114  		items []*ethpb.Deposit_Data
   115  		roots [][]byte
   116  	}
   117  	depositDataItems := make([]*ethpb.Deposit_Data, len(privKeys))
   118  	depositDataRoots := make([][]byte, len(privKeys))
   119  	results, err := mputil.Scatter(len(privKeys), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) {
   120  		items, roots, err := depositDataFromKeys(privKeys[offset:offset+entries], pubKeys[offset:offset+entries])
   121  		return &depositData{items: items, roots: roots}, err
   122  	})
   123  	if err != nil {
   124  		return nil, nil, errors.Wrap(err, "failed to generate deposit data from keys")
   125  	}
   126  	for _, result := range results {
   127  		if depositDataExtent, ok := result.Extent.(*depositData); ok {
   128  			copy(depositDataItems[result.Offset:], depositDataExtent.items)
   129  			copy(depositDataRoots[result.Offset:], depositDataExtent.roots)
   130  		} else {
   131  			return nil, nil, errors.New("extent not of expected type")
   132  		}
   133  	}
   134  	return depositDataItems, depositDataRoots, nil
   135  }
   136  
   137  func depositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) {
   138  	dataRoots := make([][]byte, len(privKeys))
   139  	depositDataItems := make([]*ethpb.Deposit_Data, len(privKeys))
   140  	for i := 0; i < len(privKeys); i++ {
   141  		data, err := createDepositData(privKeys[i], pubKeys[i])
   142  		if err != nil {
   143  			return nil, nil, errors.Wrapf(err, "could not create deposit data for key: %#x", privKeys[i].Marshal())
   144  		}
   145  		hash, err := data.HashTreeRoot()
   146  		if err != nil {
   147  			return nil, nil, errors.Wrap(err, "could not hash tree root deposit data item")
   148  		}
   149  		dataRoots[i] = hash[:]
   150  		depositDataItems[i] = data
   151  	}
   152  	return depositDataItems, dataRoots, nil
   153  }
   154  
   155  // Generates a deposit data item from BLS keys and signs the hash tree root of the data.
   156  func createDepositData(privKey bls.SecretKey, pubKey bls.PublicKey) (*ethpb.Deposit_Data, error) {
   157  	depositMessage := &pb.DepositMessage{
   158  		PublicKey:             pubKey.Marshal(),
   159  		WithdrawalCredentials: withdrawalCredentialsHash(pubKey.Marshal()),
   160  		Amount:                params.BeaconConfig().MaxEffectiveBalance,
   161  	}
   162  	sr, err := depositMessage.HashTreeRoot()
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	root, err := (&pb.SigningData{ObjectRoot: sr[:], Domain: domain}).HashTreeRoot()
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	di := &ethpb.Deposit_Data{
   175  		PublicKey:             depositMessage.PublicKey,
   176  		WithdrawalCredentials: depositMessage.WithdrawalCredentials,
   177  		Amount:                depositMessage.Amount,
   178  		Signature:             privKey.Sign(root[:]).Marshal(),
   179  	}
   180  	return di, nil
   181  }
   182  
   183  // withdrawalCredentialsHash forms a 32 byte hash of the withdrawal public
   184  // address.
   185  //
   186  // The specification is as follows:
   187  //   withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE
   188  //   withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]
   189  // where withdrawal_credentials is of type bytes32.
   190  func withdrawalCredentialsHash(pubKey []byte) []byte {
   191  	h := hashutil.Hash(pubKey)
   192  	return append([]byte{blsWithdrawalPrefixByte}, h[1:]...)[:32]
   193  }