Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* [2538](https://github.com/zeta-chain/node/pull/2538) - add background worker routines to shutdown zetaclientd when needed for tss migration
* [2681](https://github.com/zeta-chain/node/pull/2681) - implement `MsgUpdateERC20CustodyPauseStatus` to pause or unpause ERC20 Custody contract (to be used for the migration process for smart contract V2)
* [2644](https://github.com/zeta-chain/node/pull/2644) - add created_timestamp to cctx status
* [2673](https://github.com/zeta-chain/node/pull/2673) - add relayer key importer, encryption and decryption

### Refactor

Expand Down
22 changes: 0 additions & 22 deletions cmd/zetaclientd-supervisor/lib.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"bufio"
"context"
"encoding/json"
"errors"
Expand All @@ -10,7 +9,6 @@ import (
"os"
"path"
"runtime"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -256,23 +254,3 @@ func (s *zetaclientdSupervisor) downloadZetaclientd(ctx context.Context, plan *u
}
return nil
}

func promptPasswords() (string, string, error) {
reader := bufio.NewReader(os.Stdin)
fmt.Print("HotKey Password: ")
hotKeyPass, err := reader.ReadString('\n')
if err != nil {
return "", "", err
}
fmt.Print("TSS Password: ")
tssKeyPass, err := reader.ReadString('\n')
if err != nil {
return "", "", err
}

//trim delimiters
hotKeyPass = strings.TrimSuffix(hotKeyPass, "\n")
tssKeyPass = strings.TrimSuffix(tssKeyPass, "\n")

return hotKeyPass, tssKeyPass, err
}
8 changes: 6 additions & 2 deletions cmd/zetaclientd-supervisor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"time"

"cosmossdk.io/errors"
"golang.org/x/sync/errgroup"

"github.com/zeta-chain/zetacore/app"
zetaos "github.com/zeta-chain/zetacore/pkg/os"
"github.com/zeta-chain/zetacore/zetaclient/config"
)

Expand All @@ -37,7 +39,9 @@ func main() {
shutdownChan := make(chan os.Signal, 1)
signal.Notify(shutdownChan, syscall.SIGINT, syscall.SIGTERM)

hotkeyPassword, tssPassword, err := promptPasswords()
// prompt for all necessary passwords
titles := []string{"HotKey", "TSS", "Solana Relayer Key"}
passwords, err := zetaos.PromptPasswords(titles)
if err != nil {
logger.Error().Err(err).Msg("unable to get passwords")
os.Exit(1)
Expand All @@ -64,7 +68,7 @@ func main() {
cmd.Stderr = os.Stderr
// must reset the passwordInputBuffer every iteration because reads are stateful (seek to end)
passwordInputBuffer := bytes.Buffer{}
passwordInputBuffer.Write([]byte(hotkeyPassword + "\n" + tssPassword + "\n"))
passwordInputBuffer.Write([]byte(strings.Join(passwords, "\n") + "\n"))
cmd.Stdin = &passwordInputBuffer

eg, ctx := errgroup.WithContext(ctx)
Expand Down
2 changes: 1 addition & 1 deletion cmd/zetaclientd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func debugCmd(_ *cobra.Command, args []string) error {
return err
}

appContext := zctx.New(cfg, zerolog.Nop())
appContext := zctx.New(cfg, nil, zerolog.Nop())
ctx := zctx.WithAppContext(context.Background(), appContext)

if err := client.UpdateAppContext(ctx, appContext, zerolog.Nop()); err != nil {
Expand Down
36 changes: 8 additions & 28 deletions cmd/zetaclientd/encrypt_tss.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package main

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/json"
"errors"
"io"
"os"
"path/filepath"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/zeta-chain/zetacore/pkg/crypto"
)

var encTssCmd = &cobra.Command{
Expand All @@ -25,9 +22,10 @@ func init() {
RootCmd.AddCommand(encTssCmd)
}

// EncryptTSSFile encrypts the given file with the given secret key
func EncryptTSSFile(_ *cobra.Command, args []string) error {
filePath := args[0]
secretKey := args[1]
password := args[1]

filePath = filepath.Clean(filePath)
data, err := os.ReadFile(filePath)
Expand All @@ -39,29 +37,11 @@ func EncryptTSSFile(_ *cobra.Command, args []string) error {
return errors.New("file does not contain valid json, may already be encrypted")
}

block, err := aes.NewCipher(getFragmentSeed(secretKey))
if err != nil {
return err
}

// Creating GCM mode
gcm, err := cipher.NewGCM(block)
// encrypt the data
cipherText, err := crypto.EncryptAES256GCM(data, password)
if err != nil {
return err
}
// Generating random nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return err
return errors.Wrap(err, "failed to encrypt data")
}

cipherText := gcm.Seal(nonce, nonce, data, nil)
return os.WriteFile(filePath, cipherText, 0o600)
}

func getFragmentSeed(password string) []byte {
h := sha256.New()
h.Write([]byte(password))
seed := h.Sum(nil)
return seed
}
153 changes: 153 additions & 0 deletions cmd/zetaclientd/import_relayer_keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package main

import (
"fmt"
"os"
"path/filepath"

"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"

"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/pkg/crypto"
zetaos "github.com/zeta-chain/zetacore/pkg/os"
"github.com/zeta-chain/zetacore/zetaclient/keys"
)

var CmdImportRelayerKey = &cobra.Command{
Use: "import-relayer-key --network=<network> --private-key=<private-key> --password=<password> --relayer-key-path=<relayer-key-path>",
Short: "Import a relayer private key",
Example: `zetaclientd import-relayer-key --network=7 --private-key=<your_private_key> --password=<your_password>`,
RunE: ImportRelayerKey,
}

var CmdRelayerAddress = &cobra.Command{
Use: "relayer-address --network=<network> --password=<password> --relayer-key-path=<relayer-key-path>",
Short: "Show the relayer address",
Example: `zetaclientd relayer-address --network=7 --password=my_password`,
RunE: ShowRelayerAddress,
}

var importArgs = importRelayerKeyArguments{}
var addressArgs = relayerAddressArguments{}

// importRelayerKeyArguments is the struct that holds the arguments for the import command
type importRelayerKeyArguments struct {
network int32
privateKey string
password string
relayerKeyPath string
}

// relayerAddressArguments is the struct that holds the arguments for the show command
type relayerAddressArguments struct {
network int32
password string
relayerKeyPath string
}

func init() {
RootCmd.AddCommand(CmdImportRelayerKey)
RootCmd.AddCommand(CmdRelayerAddress)

// resolve default relayer key path
defaultRelayerKeyPath := "~/.zetacored/relayer-keys"
defaultRelayerKeyPath, err := zetaos.ExpandHomeDir(defaultRelayerKeyPath)
if err != nil {
log.Fatal().Err(err).Msg("failed to resolve default relayer key path")
}

CmdImportRelayerKey.Flags().Int32Var(&importArgs.network, "network", 7, "network id, (7: solana)")
CmdImportRelayerKey.Flags().
StringVar(&importArgs.privateKey, "private-key", "", "the relayer private key to import")
CmdImportRelayerKey.Flags().
StringVar(&importArgs.password, "password", "", "the password to encrypt the relayer private key")
CmdImportRelayerKey.Flags().
StringVar(&importArgs.relayerKeyPath, "relayer-key-path", defaultRelayerKeyPath, "path to relayer keys")

CmdRelayerAddress.Flags().Int32Var(&addressArgs.network, "network", 7, "network id, (7:solana)")
CmdRelayerAddress.Flags().
StringVar(&addressArgs.password, "password", "", "the password to decrypt the relayer private key")
CmdRelayerAddress.Flags().
StringVar(&addressArgs.relayerKeyPath, "relayer-key-path", defaultRelayerKeyPath, "path to relayer keys")
}

// ImportRelayerKey imports a relayer private key
func ImportRelayerKey(_ *cobra.Command, _ []string) error {
// validate private key and password
if importArgs.privateKey == "" {
return errors.New("must provide a private key")
}
if importArgs.password == "" {
return errors.New("must provide a password")
}
if !keys.IsRelayerPrivateKeyValid(importArgs.privateKey, chains.Network(importArgs.network)) {
return errors.New("invalid private key")
}

// resolve the relayer key file path
fileName, err := keys.ResolveRelayerKeyFile(importArgs.relayerKeyPath, chains.Network(importArgs.network))
if err != nil {
return errors.Wrap(err, "failed to resolve relayer key file path")
}

// create path (owner `rwx` permissions) if it does not exist
keyPath := filepath.Dir(fileName)
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
if err := os.MkdirAll(keyPath, 0o700); err != nil {
return errors.Wrapf(err, "failed to create relayer key path: %s", keyPath)
}
}

// avoid overwriting existing key file
if zetaos.FileExists(fileName) {
return errors.Errorf(
"relayer key %s already exists, please backup and remove it before importing a new key",
fileName,
)
}

// encrypt the private key
ciphertext, err := crypto.EncryptAES256GCMBase64(importArgs.privateKey, importArgs.password)
if err != nil {
return errors.Wrap(err, "private key encryption failed")
}

// create the relayer key file
err = keys.WriteRelayerKeyToFile(fileName, keys.RelayerKey{PrivateKey: ciphertext})
if err != nil {
return errors.Wrapf(err, "failed to create relayer key file: %s", fileName)
}
fmt.Printf("successfully imported relayer key: %s\n", fileName)

return nil
}

// ShowRelayerAddress shows the relayer address
func ShowRelayerAddress(_ *cobra.Command, _ []string) error {
// try loading the relayer key if present
network := chains.Network(addressArgs.network)
relayerKey, err := keys.LoadRelayerKey(addressArgs.relayerKeyPath, network, addressArgs.password)
if err != nil {
return errors.Wrap(err, "failed to load relayer key")
}

// relayer key does not exist, return error
if relayerKey == nil {
return fmt.Errorf(
"relayer key not found for network %d in path: %s",
addressArgs.network,
addressArgs.relayerKeyPath,
)
}

// resolve the relayer address
networkName, address, err := relayerKey.ResolveAddress(network)
if err != nil {
return errors.Wrap(err, "failed to resolve relayer address")
}
fmt.Printf("relayer address (%s): %s\n", networkName, address)

return nil
}
16 changes: 4 additions & 12 deletions cmd/zetaclientd/init.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main

import (
"path"

"github.com/rs/zerolog"
"github.com/spf13/cobra"

Expand Down Expand Up @@ -38,7 +36,7 @@ type initArguments struct {
KeyringBackend string
HsmMode bool
HsmHotKey string
SolanaKey string
RelayerKeyPath string
}

func init() {
Expand Down Expand Up @@ -72,7 +70,8 @@ func init() {
InitCmd.Flags().BoolVar(&initArgs.HsmMode, "hsm-mode", false, "enable hsm signer, default disabled")
InitCmd.Flags().
StringVar(&initArgs.HsmHotKey, "hsm-hotkey", "hsm-hotkey", "name of hotkey associated with hardware security module")
InitCmd.Flags().StringVar(&initArgs.SolanaKey, "solana-key", "solana-key.json", "solana key file name")
InitCmd.Flags().
StringVar(&initArgs.RelayerKeyPath, "relayer-key-path", "~/.zetacored/relayer-keys", "path to relayer keys")
}

func Initialize(_ *cobra.Command, _ []string) error {
Expand Down Expand Up @@ -110,16 +109,9 @@ func Initialize(_ *cobra.Command, _ []string) error {
configData.KeyringBackend = config.KeyringBackend(initArgs.KeyringBackend)
configData.HsmMode = initArgs.HsmMode
configData.HsmHotKey = initArgs.HsmHotKey
configData.SolanaKeyFile = initArgs.SolanaKey
configData.RelayerKeyPath = initArgs.RelayerKeyPath
configData.ComplianceConfig = testutils.ComplianceConfigTest()

// Save solana test fee payer key file
keyFile := path.Join(rootArgs.zetaCoreHome, initArgs.SolanaKey)
err = createSolanaTestKeyFile(keyFile)
if err != nil {
return err
}

// Save config file
return config.Save(&configData, rootArgs.zetaCoreHome)
}
37 changes: 0 additions & 37 deletions cmd/zetaclientd/solana_test_key.go

This file was deleted.

Loading