From 9d0a116539c5e43687e70e5957e693b9d5d8adf8 Mon Sep 17 00:00:00 2001 From: buddh0 Date: Thu, 30 Nov 2023 10:22:03 +0800 Subject: [PATCH] cmd/geth: standardize the action of importing bls account --- cmd/geth/blsaccountcmd.go | 116 +++++++++----------- cmd/geth/testdata/bls-account-usage-demo.sh | 33 ++++++ cmd/utils/flags.go | 9 +- 3 files changed, 88 insertions(+), 70 deletions(-) create mode 100644 cmd/geth/testdata/bls-account-usage-demo.sh diff --git a/cmd/geth/blsaccountcmd.go b/cmd/geth/blsaccountcmd.go index 1eeb5ee884..237203730e 100644 --- a/cmd/geth/blsaccountcmd.go +++ b/cmd/geth/blsaccountcmd.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/signer/core" ) @@ -35,19 +36,16 @@ const ( ) var ( - au = aurora.NewAurora(true) - privateKeyFlag = &cli.StringFlag{ - Name: "private-key", - Usage: "Hex string for the BLS12-381 private key you wish encrypt into a keystore file", - Value: "", - } + au = aurora.NewAurora(true) showPrivateKeyFlag = &cli.BoolFlag{ - Name: "show-private-key", - Usage: "Show the BLS12-381 private key you will encrypt into a keystore file", + Name: "show-private-key", + Usage: "Show the BLS12-381 private key you will encrypt into a keystore file", + Category: flags.AccountCategory, } - BLSAccountPasswordFileFlag = &cli.StringFlag{ - Name: "blsaccountpassword", - Usage: "File path for the BLS account password, which contains the password to encrypt private key into keystore file for managing votes in fast_finality feature", + bLSAccountPasswordFileFlag = &cli.StringFlag{ + Name: "blsaccountpassword", + Usage: "File path for the BLS account password, which contains the password to encrypt private key into keystore file for managing votes in fast_finality feature", + Category: flags.AccountCategory, } ) @@ -130,10 +128,9 @@ Make sure you backup your BLS keys regularly.`, Category: "BLS ACCOUNT COMMANDS", Flags: []cli.Flag{ utils.DataDirFlag, - privateKeyFlag, showPrivateKeyFlag, utils.BLSPasswordFileFlag, - BLSAccountPasswordFileFlag, + bLSAccountPasswordFileFlag, }, Description: ` geth bls account new @@ -149,17 +146,17 @@ You must remember this password to unlock your account in the future.`, Name: "import", Usage: "Import a BLS account", Action: blsAccountImport, - ArgsUsage: "", + ArgsUsage: "", Category: "BLS ACCOUNT COMMANDS", Flags: []cli.Flag{ utils.DataDirFlag, utils.BLSPasswordFileFlag, - BLSAccountPasswordFileFlag, + bLSAccountPasswordFileFlag, }, Description: ` geth bls account import -Import a encrypted BLS account from keystore file into the BLS wallet. +Import a encrypted BLS account or a BLS12-381 private key from file into the BLS wallet. If the BLS wallet not created yet, it will try to create BLS wallet first.`, }, @@ -219,8 +216,7 @@ func blsWalletCreate(ctx *cli.Context) error { utils.Fatalf("BLS wallet already exists in /bls/wallet.") } - password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx)) - + password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) opts := []accounts.Option{} opts = append(opts, accounts.WithWalletDir(dir)) opts = append(opts, accounts.WithWalletPassword(password)) @@ -249,8 +245,7 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e } if !dirExists { fmt.Println("BLS wallet not exists, creating BLS wallet...") - password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx)) - + password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) opts := []accounts.Option{} opts = append(opts, accounts.WithWalletDir(walletDir)) opts = append(opts, accounts.WithWalletPassword(password)) @@ -269,7 +264,7 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e return w, nil } - walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx)) + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) w, err = wallet.OpenWallet(context.Background(), &wallet.Config{ WalletDir: walletDir, WalletPassword: walletPassword, @@ -309,27 +304,14 @@ func blsAccountCreate(ctx *cli.Context) error { if err := os.MkdirAll(keystoreDir, 0755); err != nil { utils.Fatalf("Could not access keystore dir: %v.", err) } - accountPassword := utils.GetPassPhraseWithList("Your new BLS account will be encrypted with a password. Please give a password. Do not forget this password.", true, 0, GetBLSAccountPassword(ctx)) + accountPassword := utils.GetPassPhraseWithList("Your new BLS account will be encrypted with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordListFromPath(ctx.String(bLSAccountPasswordFileFlag.Name))) if err := core.ValidatePasswordFormat(accountPassword); err != nil { utils.Fatalf("Password invalid: %v.", err) } encryptor := keystorev4.New() secretKey, err := bls.RandKey() - privateKeyString := ctx.String(privateKeyFlag.Name) - if privateKeyString != "" { - if len(privateKeyString) > 2 && strings.Contains(privateKeyString, "0x") { - privateKeyString = privateKeyString[2:] // Strip the 0x prefix, if any. - } - bytesValue, err := hex.DecodeString(privateKeyString) - if err != nil { - utils.Fatalf("could not decode as hex string: %s", privateKeyString) - } - secretKey, err = bls.SecretKeyFromBytes(bytesValue) - if err != nil { - utils.Fatalf("not a valid BLS12-381 private key") - } - } else if err != nil { + if err != nil { utils.Fatalf("Could not generate BLS secret key: %v.", err) } @@ -387,13 +369,35 @@ func blsAccountImport(ctx *cli.Context) error { if len(keyfile) == 0 { utils.Fatalf("The keystore file must be given as argument.") } - keyJSON, err := os.ReadFile(keyfile) + keyInfo, err := os.ReadFile(keyfile) if err != nil { utils.Fatalf("Could not read keystore file: %v", err) } keystore := &keymanager.Keystore{} - if err := json.Unmarshal(keyJSON, keystore); err != nil { - utils.Fatalf("Could not decode keystore file: %v.", err) + var accountPassword string + if err := json.Unmarshal(keyInfo, keystore); err != nil { + secretKey, err := bls.SecretKeyFromBytes(common.FromHex(strings.TrimRight(string(keyInfo), "\r\n"))) + if err != nil { + utils.Fatalf("keyFile is neither a keystore file or include a valid BLS12-381 private key: %v.", err) + } + pubKeyBytes := secretKey.PublicKey().Marshal() + encryptor := keystorev4.New() + accountPassword = "1234567890" // no security issue, it's only used to create keystore in memory from secretKey. + cryptoFields, err := encryptor.Encrypt(secretKey.Marshal(), accountPassword) + if err != nil { + utils.Fatalf("Could not encrypt secret key: %v.", err) + } + id, err := uuid.NewRandom() + if err != nil { + utils.Fatalf("Could not generate uuid: %v.", err) + } + keystore = &keymanager.Keystore{ + Crypto: cryptoFields, + ID: id.String(), + Pubkey: fmt.Sprintf("%x", pubKeyBytes), + Version: encryptor.Version(), + Name: encryptor.Name(), + } } if keystore.Pubkey == "" { utils.Fatalf(" Missing public key, wrong keystore file.") @@ -421,13 +425,15 @@ func blsAccountImport(ctx *cli.Context) error { utils.Fatalf("The BLS keymanager cannot import keystores") } - password := utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, GetBLSAccountPassword(ctx)) + if accountPassword == "" { + accountPassword = utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, utils.MakePasswordListFromPath(ctx.String(bLSAccountPasswordFileFlag.Name))) + } fmt.Println("Importing BLS account, this may take a while...") statuses, err := accounts.ImportAccounts(context.Background(), &accounts.ImportAccountsConfig{ Importer: k, Keystores: []*keymanager.Keystore{keystore}, - AccountPassword: password, + AccountPassword: accountPassword, }) if err != nil { utils.Fatalf("Import BLS account failed: %v.", err) @@ -458,7 +464,7 @@ func blsAccountList(ctx *cli.Context) error { utils.Fatalf("BLS wallet not exists.") } - walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx)) + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ WalletDir: walletDir, WalletPassword: walletPassword, @@ -537,7 +543,7 @@ func blsAccountDelete(ctx *cli.Context) error { utils.Fatalf("BLS wallet not exists.") } - walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx)) + walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, utils.MakePasswordListFromPath(ctx.String(utils.BLSPasswordFileFlag.Name))) w, err := wallet.OpenWallet(context.Background(), &wallet.Config{ WalletDir: walletDir, WalletPassword: walletPassword, @@ -598,27 +604,3 @@ func blsAccountDelete(ctx *cli.Context) error { return nil } - -func GetBLSPassword(ctx *cli.Context) []string { - path := ctx.String(utils.BLSPasswordFileFlag.Name) - if path == "" { - return nil - } - text, err := os.ReadFile(path) - if err != nil { - utils.Fatalf("Failed to read wallet password file: %v", err) - } - return []string{string(text)} -} - -func GetBLSAccountPassword(ctx *cli.Context) []string { - path := ctx.String(BLSAccountPasswordFileFlag.Name) - if path == "" { - return nil - } - text, err := os.ReadFile(path) - if err != nil { - utils.Fatalf("Failed to read account password file: %v", err) - } - return []string{string(text)} -} diff --git a/cmd/geth/testdata/bls-account-usage-demo.sh b/cmd/geth/testdata/bls-account-usage-demo.sh new file mode 100644 index 0000000000..c1654c7dc1 --- /dev/null +++ b/cmd/geth/testdata/bls-account-usage-demo.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +echo "0. prepare---------------------------------------------------------------------------------\n\n" +echo 123abc >bls-password.txt +echo 123abc7890 > bls-account-password.txt +basedir=$(cd `dirname $0`; pwd) +workspace=${basedir}/../../../ + +echo "1. create a bls account--------------------------------------------------------------------\n\n" +${workspace}/build/bin/geth bls account new --blsaccountpassword ./bls-account-password.txt --blspassword ./bls-password.txt --datadir ./bls +${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls + +echo "2. import a bls account by passing file including a private key-----------------------------\n\n" +secretKey=`${workspace}/build/bin/geth bls account new --show-private-key --blsaccountpassword ./bls-account-password.txt --blspassword ./bls-password.txt --datadir ./bls1 | grep private | awk '{print $NF}'` +echo ${secretKey} > ./bls1/secretKey +${workspace}/build/bin/geth bls account import --blspassword ./bls-password.txt --datadir ./bls ./bls1/secretKey +${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls + +echo "3. delete the imported account above--------------------------------------------------------\n\n" +publicKey=`${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls |grep public | tail -1 | awk '{print $NF}'` +${workspace}/build/bin/geth bls account delete --blspassword ./bls-password.txt --datadir ./bls ${publicKey} +${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls + +echo "4. import a bls account by passing a keystore file------------------------------------------\n\n" +keystoreFile=`ls bls1/bls/keystore` +${workspace}/build/bin/geth bls account import --blsaccountpassword ./bls-account-password.txt --blspassword ./bls-password.txt --datadir ./bls ./bls1/bls/keystore/${keystoreFile} +${workspace}/build/bin/geth bls account list --blspassword ./bls-password.txt --datadir ./bls + +echo "5. clearup----------------------------------------------------------------------------------\n\n" +rm -rf bls +rm -rf bls1 +rm -rf bls-password.txt +rm -rf bls-account-password.txt \ No newline at end of file diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 406c5f7072..9c143fc17c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1093,13 +1093,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. BLSPasswordFileFlag = &cli.StringFlag{ Name: "blspassword", Usage: "File path for the BLS password, which contains the password to unlock BLS wallet for managing votes in fast_finality feature", - Category: flags.FastFinalityCategory, + Category: flags.AccountCategory, } BLSWalletDirFlag = &flags.DirectoryFlag{ Name: "blswallet", Usage: "Path for the blsWallet dir in fast finality feature (default = inside the datadir)", - Category: flags.FastFinalityCategory, + Category: flags.AccountCategory, } VoteJournalDirFlag = &flags.DirectoryFlag{ @@ -1462,7 +1462,10 @@ func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { // MakePasswordList reads password lines from the file specified by the global --password flag. func MakePasswordList(ctx *cli.Context) []string { - path := ctx.Path(PasswordFileFlag.Name) + return MakePasswordListFromPath(ctx.Path(PasswordFileFlag.Name)) +} + +func MakePasswordListFromPath(path string) []string { if path == "" { return nil }