github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/stateutil/validator_root.go (about) 1 package stateutil 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 7 "github.com/pkg/errors" 8 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 9 "github.com/prysmaticlabs/prysm/shared/bytesutil" 10 "github.com/prysmaticlabs/prysm/shared/hashutil" 11 "github.com/prysmaticlabs/prysm/shared/htrutils" 12 "github.com/prysmaticlabs/prysm/shared/params" 13 ) 14 15 // ValidatorRootWithHasher describes a method from which the hash tree root 16 // of a validator is returned. 17 func ValidatorRootWithHasher(hasher htrutils.HashFn, validator *ethpb.Validator) ([32]byte, error) { 18 var fieldRoots [][32]byte 19 if validator != nil { 20 pubkey := bytesutil.ToBytes48(validator.PublicKey) 21 withdrawCreds := bytesutil.ToBytes32(validator.WithdrawalCredentials) 22 effectiveBalanceBuf := [32]byte{} 23 binary.LittleEndian.PutUint64(effectiveBalanceBuf[:8], validator.EffectiveBalance) 24 // Slashed. 25 slashBuf := [32]byte{} 26 if validator.Slashed { 27 slashBuf[0] = uint8(1) 28 } else { 29 slashBuf[0] = uint8(0) 30 } 31 activationEligibilityBuf := [32]byte{} 32 binary.LittleEndian.PutUint64(activationEligibilityBuf[:8], uint64(validator.ActivationEligibilityEpoch)) 33 34 activationBuf := [32]byte{} 35 binary.LittleEndian.PutUint64(activationBuf[:8], uint64(validator.ActivationEpoch)) 36 37 exitBuf := [32]byte{} 38 binary.LittleEndian.PutUint64(exitBuf[:8], uint64(validator.ExitEpoch)) 39 40 withdrawalBuf := [32]byte{} 41 binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch)) 42 43 // Public key. 44 pubKeyChunks, err := htrutils.Pack([][]byte{pubkey[:]}) 45 if err != nil { 46 return [32]byte{}, err 47 } 48 pubKeyRoot, err := htrutils.BitwiseMerkleize(hasher, pubKeyChunks, uint64(len(pubKeyChunks)), uint64(len(pubKeyChunks))) 49 if err != nil { 50 return [32]byte{}, err 51 } 52 fieldRoots = [][32]byte{pubKeyRoot, withdrawCreds, effectiveBalanceBuf, slashBuf, activationEligibilityBuf, 53 activationBuf, exitBuf, withdrawalBuf} 54 } 55 return htrutils.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots))) 56 } 57 58 // Uint64ListRootWithRegistryLimit computes the HashTreeRoot Merkleization of 59 // a list of uint64 and mixed with registry limit. 60 func Uint64ListRootWithRegistryLimit(balances []uint64) ([32]byte, error) { 61 hasher := hashutil.CustomSHA256Hasher() 62 balancesMarshaling := make([][]byte, 0) 63 for i := 0; i < len(balances); i++ { 64 balanceBuf := make([]byte, 8) 65 binary.LittleEndian.PutUint64(balanceBuf, balances[i]) 66 balancesMarshaling = append(balancesMarshaling, balanceBuf) 67 } 68 balancesChunks, err := htrutils.Pack(balancesMarshaling) 69 if err != nil { 70 return [32]byte{}, errors.Wrap(err, "could not pack balances into chunks") 71 } 72 maxBalCap := params.BeaconConfig().ValidatorRegistryLimit 73 elemSize := uint64(8) 74 balLimit := (maxBalCap*elemSize + 31) / 32 75 if balLimit == 0 { 76 if len(balances) == 0 { 77 balLimit = 1 78 } else { 79 balLimit = uint64(len(balances)) 80 } 81 } 82 balancesRootsRoot, err := htrutils.BitwiseMerkleize(hasher, balancesChunks, uint64(len(balancesChunks)), balLimit) 83 if err != nil { 84 return [32]byte{}, errors.Wrap(err, "could not compute balances merkleization") 85 } 86 87 balancesLengthRoot := make([]byte, 32) 88 binary.LittleEndian.PutUint64(balancesLengthRoot, uint64(len(balances))) 89 return htrutils.MixInLength(balancesRootsRoot, balancesLengthRoot), nil 90 } 91 92 // ValidatorEncKey returns the encoded key in bytes of input `validator`, 93 // the returned key bytes can be used for caching purposes. 94 func ValidatorEncKey(validator *ethpb.Validator) []byte { 95 if validator == nil { 96 return nil 97 } 98 99 enc := make([]byte, 122) 100 pubkey := bytesutil.ToBytes48(validator.PublicKey) 101 copy(enc[0:48], pubkey[:]) 102 withdrawCreds := bytesutil.ToBytes32(validator.WithdrawalCredentials) 103 copy(enc[48:80], withdrawCreds[:]) 104 effectiveBalanceBuf := [32]byte{} 105 binary.LittleEndian.PutUint64(effectiveBalanceBuf[:8], validator.EffectiveBalance) 106 copy(enc[80:88], effectiveBalanceBuf[:8]) 107 if validator.Slashed { 108 enc[88] = uint8(1) 109 } else { 110 enc[88] = uint8(0) 111 } 112 activationEligibilityBuf := [32]byte{} 113 binary.LittleEndian.PutUint64(activationEligibilityBuf[:8], uint64(validator.ActivationEligibilityEpoch)) 114 copy(enc[89:97], activationEligibilityBuf[:8]) 115 116 activationBuf := [32]byte{} 117 binary.LittleEndian.PutUint64(activationBuf[:8], uint64(validator.ActivationEpoch)) 118 copy(enc[97:105], activationBuf[:8]) 119 120 exitBuf := [32]byte{} 121 binary.LittleEndian.PutUint64(exitBuf[:8], uint64(validator.ExitEpoch)) 122 copy(enc[105:113], exitBuf[:8]) 123 124 withdrawalBuf := [32]byte{} 125 binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch)) 126 copy(enc[113:121], withdrawalBuf[:8]) 127 128 return enc 129 } 130 131 // HandleValidatorSlice returns the validator indices in a slice of root format. 132 func HandleValidatorSlice(val []*ethpb.Validator, indices []uint64, convertAll bool) ([][32]byte, error) { 133 length := len(indices) 134 if convertAll { 135 length = len(val) 136 } 137 roots := make([][32]byte, 0, length) 138 hasher := hashutil.CustomSHA256Hasher() 139 rootCreator := func(input *ethpb.Validator) error { 140 newRoot, err := ValidatorRootWithHasher(hasher, input) 141 if err != nil { 142 return err 143 } 144 roots = append(roots, newRoot) 145 return nil 146 } 147 if convertAll { 148 for i := range val { 149 err := rootCreator(val[i]) 150 if err != nil { 151 return nil, err 152 } 153 } 154 return roots, nil 155 } 156 if len(val) > 0 { 157 for _, idx := range indices { 158 if idx > uint64(len(val))-1 { 159 return nil, fmt.Errorf("index %d greater than number of validators %d", idx, len(val)) 160 } 161 err := rootCreator(val[idx]) 162 if err != nil { 163 return nil, err 164 } 165 } 166 } 167 return roots, nil 168 }