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