Skip to content

Commit

Permalink
integrate relayer key into E2E and Solana signer
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Aug 12, 2024
1 parent 5da629e commit 6a64051
Show file tree
Hide file tree
Showing 16 changed files with 628 additions and 253 deletions.
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"
"syscall"
"time"
Expand Down Expand Up @@ -383,23 +381,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,12 +7,14 @@ import (
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"time"

"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 @@ -36,7 +38,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 Down Expand Up @@ -65,7 +69,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
68 changes: 20 additions & 48 deletions cmd/zetaclientd/import_relayer_keys.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand All @@ -10,6 +9,7 @@ import (
"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"
Expand Down Expand Up @@ -62,13 +62,13 @@ func init() {
CmdImportRelayerKey.Flags().
StringVar(&importArgs.privateKey, "private-key", "", "the relayer private key to import")
CmdImportRelayerKey.Flags().
StringVar(&importArgs.password, "password", "", "the password to encrypt the private key")
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 private key")
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")
}
Expand All @@ -84,12 +84,13 @@ func ImportRelayerKey(_ *cobra.Command, _ []string) error {
}

// resolve the relayer key file path
keyPath, fileName, err := resolveRelayerKeyPath(importArgs.network, importArgs.relayerKeyPath)
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)
Expand All @@ -110,14 +111,8 @@ func ImportRelayerKey(_ *cobra.Command, _ []string) error {
return errors.Wrap(err, "private key encryption failed")
}

// construct the relayer key struct and write to file as json
keyData, err := json.Marshal(keys.RelayerKey{PrivateKey: ciphertext})
if err != nil {
return errors.Wrap(err, "failed to marshal relayer key")
}

// create relay key file (owner `rw` permissions)
err = os.WriteFile(fileName, keyData, 0o600)
// 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)
}
Expand All @@ -128,51 +123,28 @@ func ImportRelayerKey(_ *cobra.Command, _ []string) error {

// ShowRelayerAddress shows the relayer address
func ShowRelayerAddress(_ *cobra.Command, _ []string) error {
// resolve the relayer key file path
_, fileName, err := resolveRelayerKeyPath(addressArgs.network, addressArgs.relayerKeyPath)
if err != nil {
return errors.Wrap(err, "failed to resolve relayer key file path")
}

// read the relayer key file
relayerKey, err := keys.ReadRelayerKeyFromFile(fileName)
// 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 err
return errors.Wrap(err, "failed to load relayer key")
}

// decrypt the private key
privateKey, err := crypto.DecryptAES256GCMBase64(relayerKey.PrivateKey, addressArgs.password)
if err != nil {
return errors.Wrap(err, "private key decryption failed")
// 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,
)
}
relayerKey.PrivateKey = privateKey

// resolve the address
networkName, address, err := relayerKey.ResolveAddress(addressArgs.network)
// 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
}

// resolveRelayerKeyPath is a helper function to resolve the relayer key file path and name
func resolveRelayerKeyPath(network int32, relayerKeyPath string) (string, string, error) {
// get relayer key file name by network
name, err := keys.GetRelayerKeyFileByNetwork(network)
if err != nil {
return "", "", errors.Wrap(err, "failed to get relayer key file name")
}

// resolve relayer key path if it contains a tilde
keyPath, err := zetaos.ExpandHomeDir(relayerKeyPath)
if err != nil {
return "", "", errors.Wrap(err, "failed to resolve relayer key path")
}

// build file name
fileName := filepath.Join(keyPath, name)

return keyPath, fileName, err
}
38 changes: 11 additions & 27 deletions cmd/zetaclientd/start.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"bufio"
"context"
"encoding/json"
"fmt"
Expand All @@ -21,7 +20,9 @@ import (
"github.com/spf13/cobra"

"github.com/zeta-chain/zetacore/pkg/authz"
"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/pkg/constant"
zetaos "github.com/zeta-chain/zetacore/pkg/os"
observerTypes "github.com/zeta-chain/zetacore/x/observer/types"
"github.com/zeta-chain/zetacore/zetaclient/chains/base"
"github.com/zeta-chain/zetacore/zetaclient/config"
Expand Down Expand Up @@ -49,10 +50,15 @@ func start(_ *cobra.Command, _ []string) error {

SetupConfigForTest()

//Prompt for Hotkey and TSS key-share passwords
hotkeyPass, tssKeyPass, err := promptPasswords()
// Prompt for Hotkey, TSS key-share and relayer key passwords
titles := []string{"HotKey", "TSS", "Solana Relayer Key"}
passwords, err := zetaos.PromptPasswords(titles)
if err != nil {
return err
return errors.Wrap(err, "unable to get passwords")
}
hotkeyPass, tssKeyPass, solanaKeyPass := passwords[0], passwords[1], passwords[2]
relayerKeyPasswords := map[chains.Network]string{
chains.Network_solana: solanaKeyPass,
}

//Load Config file given path
Expand All @@ -77,6 +83,7 @@ func start(_ *cobra.Command, _ []string) error {
startLogger := logger.Std.With().Str("module", "startup").Logger()

appContext := zctx.New(cfg, masterLogger)
appContext.SetRelayerKeyPasswords(relayerKeyPasswords)
ctx := zctx.WithAppContext(context.Background(), appContext)

// Wait until zetacore is up
Expand Down Expand Up @@ -397,29 +404,6 @@ func initPreParams(path string) {
}
}

// promptPasswords() This function will prompt for passwords which will be used to decrypt two key files:
// 1. HotKey
// 2. TSS key-share
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
}

// isObserverNode checks whether THIS node is an observer node.
func isObserverNode(ctx context.Context, client *zetacore.Client) (bool, error) {
observers, err := client.GetObserverList(ctx)
Expand Down
1 change: 1 addition & 0 deletions contrib/localnet/scripts/password.file
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
password
pass2
pass_relayerkey
21 changes: 9 additions & 12 deletions contrib/localnet/scripts/start-zetaclientd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@ set_sepolia_endpoint() {
jq '.EVMChainConfigs."11155111".Endpoint = "http://eth2:8545"' /root/.zetacored/config/zetaclient_config.json > tmp.json && mv tmp.json /root/.zetacored/config/zetaclient_config.json
}

# creates a file that contains a relayer private key (e.g. Solana relayer key)
create_relayer_key_file() {
# import a relayer private key (e.g. Solana relayer key)
import_relayer_key() {
local num="$1"
local file="$2"

# read observer relayer private key from config
privkey_relayer=$(yq -r ".observer_relayer_accounts.relayer_account_${num}.solana_private_key" /root/config.yml)

# create the key file that contains the private key
jq -n --arg privkey_relayer "$privkey_relayer" '{"private_key": $privkey_relayer}' > "${file}"
# import solana (network=7) relayer private key
privkey_solana=$(yq -r ".observer_relayer_accounts.relayer_account_${num}.solana_private_key" /root/config.yml)
zetaclientd import-relayer-key --network=7 --private-key="$privkey_solana" --password=pass_relayerkey
}

PREPARAMS_PATH="/root/preparams/${HOSTNAME}.json"
Expand Down Expand Up @@ -78,8 +75,8 @@ then
MYIP=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
zetaclientd init --zetacore-url zetacore0 --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH"

# create relayer key file for solana
create_relayer_key_file 0 "${RELAYER_KEY_PATH}/solana.json"
# import relayer private key for zetaclient0
import_relayer_key 0

# if eth2 is enabled, set the endpoint in the zetaclient_config.json
# in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545)
Expand All @@ -101,8 +98,8 @@ then
done
zetaclientd init --peer "/ip4/172.20.0.21/tcp/6668/p2p/${SEED}" --zetacore-url "$node" --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --log-level 1 --keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH"

# create relayer key file for solana
create_relayer_key_file "${num}" "${RELAYER_KEY_PATH}/solana.json"
# import relayer private key for zetaclient{$num}
import_relayer_key "${num}"

# check if the option is additional-evm
# in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545)
Expand Down
29 changes: 29 additions & 0 deletions pkg/os/console.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package os

import (
"bufio"
"fmt"
"os"
"strings"
)

// PromptPasswords prompts the user for passwords with the given titles
func PromptPasswords(passwordTitles []string) ([]string, error) {
reader := bufio.NewReader(os.Stdin)
passwords := make([]string, len(passwordTitles))

// iterate over password titles and prompt for each
for i, title := range passwordTitles {
fmt.Printf("%s Password: ", title)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

Sensitive data returned by an access to passwordTitles
flows to a logging call.
password, err := reader.ReadString('\n')
if err != nil {
return nil, err
}

// trim delimiters
password = strings.TrimSuffix(password, "\n")
passwords[i] = password
}

return passwords, nil
}
Loading

0 comments on commit 6a64051

Please sign in to comment.