code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/nodewallet/import.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package nodewallet
    17  
    18  import (
    19  	"encoding/base64"
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"code.vegaprotocol.io/vega/core/config"
    25  	"code.vegaprotocol.io/vega/core/nodewallets"
    26  	vgfmt "code.vegaprotocol.io/vega/libs/fmt"
    27  	vgfs "code.vegaprotocol.io/vega/libs/fs"
    28  	vgjson "code.vegaprotocol.io/vega/libs/json"
    29  	"code.vegaprotocol.io/vega/logging"
    30  	"code.vegaprotocol.io/vega/paths"
    31  
    32  	tmconfig "github.com/cometbft/cometbft/config"
    33  	"github.com/jessevdk/go-flags"
    34  )
    35  
    36  var (
    37  	ErrOneOfTendermintFlagIsRequired       = errors.New("one of --tendermint-home or --tendermint-pubkey flag is required")
    38  	ErrTendermintFlagsAreMutuallyExclusive = errors.New("--tendermint-home and --tendermint-pubkey are mutually exclusive")
    39  	ErrClefOptionMissing                   = errors.New("--clef-account and --clef-address must both be set to import a clef wallet")
    40  )
    41  
    42  type importCmd struct {
    43  	config.OutputFlag
    44  
    45  	Config nodewallets.Config
    46  
    47  	WalletPassphrase config.Passphrase `long:"wallet-passphrase-file"`
    48  
    49  	Chain      string              `choice:"vega"                                                                      choice:"ethereum"  choice:"tendermint" description:"The chain to be imported" long:"chain" required:"true" short:"c"`
    50  	WalletPath config.PromptString `description:"The path to the wallet file to import"                                long:"wallet-path"`
    51  	Force      bool                `description:"Should the command re-write an existing nodewallet file if it exists" long:"force"`
    52  
    53  	// clef flags
    54  	EthereumClefAddress string `description:"The URL to the clef instance that Vega will use."               long:"ethereum-clef-address"`
    55  	EthereumClefAccount string `description:"The Ethereum account to be imported by Vega from Clef. In hex." long:"ethereum-clef-account"`
    56  
    57  	// tendermint flags
    58  	TendermintPubkey string `description:"The tendermint pubkey of the tendermint validator node"    long:"tendermint-pubkey"`
    59  	TendermintHome   string `description:"The tendermint home from which to look the for the pubkey" long:"tendermint-home"`
    60  }
    61  
    62  func (opts *importCmd) Execute(_ []string) error {
    63  	output, err := opts.GetOutput()
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	log := logging.NewLoggerFromConfig(logging.NewDefaultConfig())
    69  	defer log.AtExit()
    70  
    71  	if (opts.EthereumClefAccount != "") != (opts.EthereumClefAddress != "") {
    72  		return ErrClefOptionMissing
    73  	}
    74  
    75  	registryPass, err := rootCmd.PassphraseFile.Get("node wallet", false)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	vegaPaths := paths.New(rootCmd.VegaHome)
    81  
    82  	_, conf, err := config.EnsureNodeConfig(vegaPaths)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	opts.Config = conf.NodeWallet
    88  
    89  	if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil {
    90  		return err
    91  	}
    92  
    93  	var walletPass, walletPath string
    94  	if opts.Chain == vegaChain || (opts.Chain == ethereumChain && opts.EthereumClefAddress == "") {
    95  		walletPass, err = opts.WalletPassphrase.Get("blockchain wallet", false)
    96  		if err != nil {
    97  			return err
    98  		}
    99  		walletPath, err = opts.WalletPath.Get("wallet path", "wallet-path")
   100  		if err != nil {
   101  			return err
   102  		}
   103  	}
   104  
   105  	var data map[string]string
   106  	switch opts.Chain {
   107  	case ethereumChain:
   108  		data, err = nodewallets.ImportEthereumWallet(
   109  			vegaPaths,
   110  			registryPass,
   111  			walletPass,
   112  			opts.EthereumClefAccount,
   113  			opts.EthereumClefAddress,
   114  			walletPath,
   115  			opts.Force,
   116  		)
   117  		if err != nil {
   118  			return fmt.Errorf("couldn't import Ethereum node wallet: %w", err)
   119  		}
   120  	case vegaChain:
   121  		data, err = nodewallets.ImportVegaWallet(vegaPaths, registryPass, walletPass, walletPath, opts.Force)
   122  		if err != nil {
   123  			return fmt.Errorf("couldn't import Vega node wallet: %w", err)
   124  		}
   125  	case tendermintChain:
   126  		if len(opts.TendermintHome) == 0 && len(opts.TendermintPubkey) == 0 {
   127  			return ErrOneOfTendermintFlagIsRequired
   128  		}
   129  		if len(opts.TendermintHome) > 0 && len(opts.TendermintPubkey) > 0 {
   130  			return ErrTendermintFlagsAreMutuallyExclusive
   131  		}
   132  
   133  		tendermintPubkey := opts.TendermintPubkey
   134  		if len(opts.TendermintHome) > 0 {
   135  			tendermintPubkey, err = getLocalTendermintPubkey(opts.TendermintHome)
   136  			if err != nil {
   137  				return fmt.Errorf("couldn't retrieve tendermint public key: %w", err)
   138  			}
   139  		}
   140  
   141  		// validate the key is base64
   142  		_, err := base64.StdEncoding.DecodeString(tendermintPubkey)
   143  		if err != nil {
   144  			return fmt.Errorf("tendermint pubkey must be base64 encoded: %w", err)
   145  		}
   146  
   147  		data, err = nodewallets.ImportTendermintPubkey(vegaPaths, registryPass, tendermintPubkey, opts.Force)
   148  		if err != nil {
   149  			return fmt.Errorf("couldn't import Tendermint pubkey: %w", err)
   150  		}
   151  	}
   152  
   153  	if output.IsHuman() {
   154  		fmt.Println(green("import successful:"))
   155  		vgfmt.PrettyPrint(data)
   156  	} else if output.IsJSON() {
   157  		if err := vgjson.Print(data); err != nil {
   158  			return err
   159  		}
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func getLocalTendermintPubkey(tendermintHome string) (string, error) {
   166  	tmConfig := tmconfig.DefaultConfig()
   167  	tmConfig.SetRoot(tendermintHome)
   168  	genesisFilePath := tmConfig.PrivValidatorKeyFile()
   169  
   170  	data, err := vgfs.ReadFile(genesisFilePath)
   171  	if err != nil {
   172  		return "", err
   173  	}
   174  
   175  	privValidatorKey := struct {
   176  		PubKey struct {
   177  			Value string `json:"value"`
   178  		} `json:"pub_key"`
   179  	}{}
   180  
   181  	if err = json.Unmarshal(data, &privValidatorKey); err != nil {
   182  		return "", fmt.Errorf("could not read priv_validator_key.json: %w", err)
   183  	}
   184  
   185  	return privValidatorKey.PubKey.Value, nil
   186  }