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, ðpb.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] = ðpb.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 := ðpb.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 }