code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/rotate_eth_key.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 commands
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"fmt"
    22  
    23  	"code.vegaprotocol.io/vega/core/config"
    24  	"code.vegaprotocol.io/vega/core/nodewallets"
    25  	"code.vegaprotocol.io/vega/core/txn"
    26  	"code.vegaprotocol.io/vega/core/validators"
    27  	"code.vegaprotocol.io/vega/libs/crypto"
    28  	vgjson "code.vegaprotocol.io/vega/libs/json"
    29  	"code.vegaprotocol.io/vega/logging"
    30  	"code.vegaprotocol.io/vega/paths"
    31  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    32  
    33  	"github.com/jessevdk/go-flags"
    34  )
    35  
    36  type RotateEthKeyCmd struct {
    37  	config.VegaHomeFlag
    38  	config.OutputFlag
    39  	config.Passphrase `long:"passphrase-file"`
    40  
    41  	TargetBlock      uint64 `description:"The future block height at which the rotation will take place" long:"target-block"      short:"b"`
    42  	RotateFrom       string `description:"Ethereum address being rotated from"                           long:"rotate-from"       short:"r"`
    43  	SubmitterAddress string `description:"Ethereum address to use as a submitter to contract changes"    long:"submitter-address" short:"s"`
    44  }
    45  
    46  var rotateEthKeyCmd RotateEthKeyCmd
    47  
    48  func (opts *RotateEthKeyCmd) Execute(_ []string) error {
    49  	log := logging.NewLoggerFromConfig(logging.NewDefaultConfig())
    50  	defer log.AtExit()
    51  
    52  	output, err := opts.GetOutput()
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	vegaPaths := paths.New(opts.VegaHome)
    58  
    59  	_, conf, err := config.EnsureNodeConfig(vegaPaths)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	if !conf.IsValidator() {
    65  		return errors.New("node is not a validator")
    66  	}
    67  
    68  	registryPass, err := opts.Get("node wallet", false)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	nodeWallets, err := nodewallets.GetNodeWallets(conf.NodeWallet, vegaPaths, registryPass)
    74  	if err != nil {
    75  		return fmt.Errorf("couldn't get node wallets: %w", err)
    76  	}
    77  
    78  	// ensure the nodewallet is setup properly, if not we could not complete the command
    79  	if err := nodeWallets.Verify(); err != nil {
    80  		return fmt.Errorf("node wallet misconfigured: %w", err)
    81  	}
    82  
    83  	cmd := commandspb.EthereumKeyRotateSubmission{
    84  		CurrentAddress:   crypto.EthereumChecksumAddress(opts.RotateFrom),
    85  		NewAddress:       nodeWallets.Ethereum.PubKey().Hex(),
    86  		TargetBlock:      opts.TargetBlock,
    87  		SubmitterAddress: opts.SubmitterAddress,
    88  	}
    89  
    90  	if len(cmd.SubmitterAddress) != 0 {
    91  		cmd.SubmitterAddress = crypto.EthereumChecksumAddress(cmd.SubmitterAddress)
    92  	}
    93  
    94  	if err := validators.SignEthereumKeyRotation(&cmd, nodeWallets.Ethereum); err != nil {
    95  		return err
    96  	}
    97  
    98  	commander, _, cfunc, err := getNodeWalletCommander(log, registryPass, vegaPaths)
    99  	if err != nil {
   100  		return fmt.Errorf("failed to get commander: %w", err)
   101  	}
   102  	defer cfunc()
   103  
   104  	var txHash string
   105  	ch := make(chan struct{})
   106  	commander.Command(
   107  		context.Background(),
   108  		txn.RotateEthereumKeySubmissionCommand,
   109  		&cmd,
   110  		func(h string, e error) {
   111  			txHash, err = h, e
   112  			close(ch)
   113  		}, nil)
   114  
   115  	<-ch
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	if output.IsHuman() {
   121  		fmt.Printf("ethereum key rotation successfully sent\ntxHash: %s\nethereum signature: %v\nRotating from: %s\nRotating to: %s",
   122  			txHash,
   123  			cmd.EthereumSignature.Value,
   124  			opts.RotateFrom,
   125  			cmd.NewAddress,
   126  		)
   127  	} else if output.IsJSON() {
   128  		return vgjson.Print(struct {
   129  			TxHash            string `json:"txHash"`
   130  			EthereumSignature string `json:"ethereumSignature"`
   131  			RotateFrom        string `json:"rotateFrom"`
   132  			RotateTo          string `json:"rotateTo"`
   133  		}{
   134  			TxHash:            txHash,
   135  			RotateFrom:        opts.RotateFrom,
   136  			RotateTo:          cmd.NewAddress,
   137  			EthereumSignature: cmd.EthereumSignature.Value,
   138  		})
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func RotateEthKey(ctx context.Context, parser *flags.Parser) error {
   145  	announceNodeCmd = AnnounceNodeCmd{}
   146  
   147  	var (
   148  		short = "Send a transaction to rotate to current ethereum key"
   149  		long  = "Send a transaction to rotate to current ethereum key"
   150  	)
   151  	_, err := parser.AddCommand("rotate_eth_key", short, long, &rotateEthKeyCmd)
   152  	return err
   153  }