github.com/prysmaticlabs/prysm@v1.4.4/shared/depositutil/deposit.go (about)

     1  // Package depositutil contains useful functions for dealing
     2  // with Ethereum deposit inputs.
     3  package depositutil
     4  
     5  import (
     6  	"github.com/pkg/errors"
     7  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
     8  	p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
     9  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    10  	"github.com/prysmaticlabs/prysm/shared/bls"
    11  	"github.com/prysmaticlabs/prysm/shared/copyutil"
    12  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    13  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    14  	"github.com/prysmaticlabs/prysm/shared/params"
    15  )
    16  
    17  // DepositInput for a given key. This input data can be used to when making a
    18  // validator deposit. The input data includes a proof of possession field
    19  // signed by the deposit key.
    20  //
    21  // Spec details about general deposit workflow:
    22  //   To submit a deposit:
    23  //
    24  //   - Pack the validator's initialization parameters into deposit_data, a Deposit_Data SSZ object.
    25  //   - Let amount be the amount in Gwei to be deposited by the validator where MIN_DEPOSIT_AMOUNT <= amount <= MAX_EFFECTIVE_BALANCE.
    26  //   - Set deposit_data.amount = amount.
    27  //   - Let signature be the result of bls_sign of the signing_root(deposit_data) with domain=compute_domain(DOMAIN_DEPOSIT). (Deposits are valid regardless of fork version, compute_domain will default to zeroes there).
    28  //   - Send a transaction on the Ethereum 1.0 chain to DEPOSIT_CONTRACT_ADDRESS executing `deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96])` along with a deposit of amount Gwei.
    29  //
    30  // See: https://github.com/ethereum/eth2.0-specs/blob/master/specs/validator/0_beacon-chain-validator.md#submit-deposit
    31  func DepositInput(depositKey, withdrawalKey bls.SecretKey, amountInGwei uint64) (*ethpb.Deposit_Data, [32]byte, error) {
    32  	depositMessage := &p2ppb.DepositMessage{
    33  		PublicKey:             depositKey.PublicKey().Marshal(),
    34  		WithdrawalCredentials: WithdrawalCredentialsHash(withdrawalKey),
    35  		Amount:                amountInGwei,
    36  	}
    37  
    38  	sr, err := depositMessage.HashTreeRoot()
    39  	if err != nil {
    40  		return nil, [32]byte{}, err
    41  	}
    42  
    43  	domain, err := helpers.ComputeDomain(
    44  		params.BeaconConfig().DomainDeposit,
    45  		nil, /*forkVersion*/
    46  		nil, /*genesisValidatorsRoot*/
    47  	)
    48  	if err != nil {
    49  		return nil, [32]byte{}, err
    50  	}
    51  	root, err := (&p2ppb.SigningData{ObjectRoot: sr[:], Domain: domain}).HashTreeRoot()
    52  	if err != nil {
    53  		return nil, [32]byte{}, err
    54  	}
    55  	di := &ethpb.Deposit_Data{
    56  		PublicKey:             depositMessage.PublicKey,
    57  		WithdrawalCredentials: depositMessage.WithdrawalCredentials,
    58  		Amount:                depositMessage.Amount,
    59  		Signature:             depositKey.Sign(root[:]).Marshal(),
    60  	}
    61  
    62  	dr, err := di.HashTreeRoot()
    63  	if err != nil {
    64  		return nil, [32]byte{}, err
    65  	}
    66  
    67  	return di, dr, nil
    68  }
    69  
    70  // WithdrawalCredentialsHash forms a 32 byte hash of the withdrawal public
    71  // address.
    72  //
    73  // The specification is as follows:
    74  //   withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE
    75  //   withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]
    76  // where withdrawal_credentials is of type bytes32.
    77  func WithdrawalCredentialsHash(withdrawalKey bls.SecretKey) []byte {
    78  	h := hashutil.Hash(withdrawalKey.PublicKey().Marshal())
    79  	return append([]byte{params.BeaconConfig().BLSWithdrawalPrefixByte}, h[1:]...)[:32]
    80  }
    81  
    82  // VerifyDepositSignature verifies the correctness of Eth1 deposit BLS signature
    83  func VerifyDepositSignature(dd *ethpb.Deposit_Data, domain []byte) error {
    84  	if featureconfig.Get().SkipBLSVerify {
    85  		return nil
    86  	}
    87  	ddCopy := copyutil.CopyDepositData(dd)
    88  	publicKey, err := bls.PublicKeyFromBytes(ddCopy.PublicKey)
    89  	if err != nil {
    90  		return errors.Wrap(err, "could not convert bytes to public key")
    91  	}
    92  	sig, err := bls.SignatureFromBytes(ddCopy.Signature)
    93  	if err != nil {
    94  		return errors.Wrap(err, "could not convert bytes to signature")
    95  	}
    96  	di := &p2ppb.DepositMessage{
    97  		PublicKey:             ddCopy.PublicKey,
    98  		WithdrawalCredentials: ddCopy.WithdrawalCredentials,
    99  		Amount:                ddCopy.Amount,
   100  	}
   101  	root, err := di.HashTreeRoot()
   102  	if err != nil {
   103  		return errors.Wrap(err, "could not get signing root")
   104  	}
   105  	signingData := &p2ppb.SigningData{
   106  		ObjectRoot: root[:],
   107  		Domain:     domain,
   108  	}
   109  	ctrRoot, err := signingData.HashTreeRoot()
   110  	if err != nil {
   111  		return errors.Wrap(err, "could not get container root")
   112  	}
   113  	if !sig.Verify(publicKey, ctrRoot[:]) {
   114  		return helpers.ErrSigFailedToVerify
   115  	}
   116  	return nil
   117  }