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  }