Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: show pubkey_hex at eotsd keys show and list #320

Merged
merged 6 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -58,6 +58,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
This PR contains a series of PRs on BTC staking integration, with support for OP stack chains and
Cosmos chains.
* [#314](https://github.com/babylonlabs-io/finality-provider/pull/314) nit: Dockerfile AS casing
* [#320](https://github.com/babylonlabs-io/finality-provider/pull/320) chore: show `pubkey_hex` at `eotsd keys show` and `eotsd keys list`

### Bug Fixes

Expand Down
153 changes: 134 additions & 19 deletions eotsmanager/cmd/eotsd/daemon/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"strings"

"github.com/btcsuite/btcd/btcec/v2/schnorr"

Expand Down Expand Up @@ -37,6 +38,52 @@ func NewKeysCmd() *cobra.Command {
panic("failed to find keys add command")
}

listCmd := util.GetSubCommand(keysCmd, "list")
if listCmd == nil {
panic("failed to find keys list command")
}

// Add home flag to root command so all subcommands inherit it
keysCmd.PersistentFlags().String(flags.FlagHome, config.DefaultEOTSDir, "The path to the eotsd home directory")

listCmd.RunE = runCommandPrintAllKeys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could also remove CommandPrintAllKeys since now there is a keys ls subcommand

What do you think @Lazar955 ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep makes sense


if showCmd := util.GetSubCommand(keysCmd, "show"); showCmd != nil {
showCmd.RunE = func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
// load eots keys
eotsPk, err := eotsmanager.LoadBIP340PubKeyFromKeyName(clientCtx.Keyring, args[0])
if err != nil {
// try by address
records, err := clientCtx.Keyring.List()
if err != nil {
return err
}
for _, r := range records {
addr, err := r.GetAddress()
if err != nil {
continue
}
if addr.String() == args[0] {
eotsPk, err = eotsmanager.LoadBIP340PubKeyFromKeyName(clientCtx.Keyring, r.Name)
if err != nil {
return err
}

return printFromKey(cmd, r.Name, eotsPk)
}
}

return fmt.Errorf("key not found: %s", args[0])
}

return printFromKey(cmd, args[0], eotsPk)
}
}

addCmd.Flags().String(rpcClientFlag, "", "The RPC address of a running eotsd to connect and save new key")

// Override the original RunE function to run almost the same as
Expand Down Expand Up @@ -160,35 +207,88 @@ func saveKeyNameMapping(cmd *cobra.Command, keyName string) (*types.BIP340PubKey
return eotsPk, nil
}

// CommandPrintAllKeys prints all EOTS keys
func CommandPrintAllKeys() *cobra.Command {
var cmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "Print all EOTS key names and public keys mapping from database.",
Example: `eotsd list --home=/path/to/cfg`,
Args: cobra.NoArgs,
RunE: runCommandPrintAllKeys,
func runCommandPrintAllKeys(cmd *cobra.Command, _ []string) error {
homePath, err := getHomePath(cmd)
if err != nil {
return err
}

cmd.Flags().String(flags.FlagHome, config.DefaultEOTSDir, "The path to the eotsd home directory")
// Initialize keyring
backend, err := cmd.Flags().GetString("keyring-backend")
if err != nil {
return err
}

return cmd
}
kr, err := eotsmanager.InitKeyring(homePath, backend)
if err != nil {
return fmt.Errorf("failed to init keyring: %w", err)
}

func runCommandPrintAllKeys(cmd *cobra.Command, _ []string) error {
eotsKeys, err := getAllEOTSKeys(cmd)
if err != nil {
return err
}

records, err := kr.List()
if err != nil {
return err
}

keyMap := make(map[string]*cryptokeyring.Record)
for _, r := range records {
keyMap[r.Name] = r
}

type keyInfo struct {
Name string `json:"name"`
Address string `json:"address"`
EOTSPK string `json:"eots_pk"`
}

var keys []keyInfo
for keyName, key := range eotsKeys {
pk, err := schnorr.ParsePubKey(key)
if err != nil {
return err
}
eotsPk := types.NewBIP340PubKeyFromBTCPK(pk)
cmd.Printf("Key Name: %s, EOTS PK: %s\n", keyName, eotsPk.MarshalHex())

k, exists := keyMap[keyName]
if !exists {
continue
}

addr, err := k.GetAddress()
if err != nil {
return err
}

keys = append(keys, keyInfo{
Name: keyName,
Address: addr.String(),
EOTSPK: eotsPk.MarshalHex(),
})
}

output, err := cmd.Flags().GetString(flags.FlagOutput)
if err != nil {
return err
}

if strings.EqualFold(output, flags.OutputFormatJSON) {
bz, err := json.MarshalIndent(keys, "", " ")
if err != nil {
return err
}

_, err = fmt.Fprintln(cmd.OutOrStdout(), string(bz))

return err
}

for _, k := range keys {
cmd.Printf("Key Name: %s\nAddress: %s\nEOTS PK: %s\n\n",
k.Name, k.Address, k.EOTSPK)
}

return nil
Expand Down Expand Up @@ -245,8 +345,23 @@ func printFromKey(cmd *cobra.Command, keyName string, eotsPk *types.BIP340PubKey
}

ctx := cmd.Context()
mnemonic := ctx.Value(mnemonicCtxKey).(string) // nolint: forcetypeassert
showMnemonic := ctx.Value(mnemonicShowCtxKey).(bool)
var mnemonic string
var showMnemonic bool

if m := ctx.Value(mnemonicCtxKey); m != nil {
var ok bool
mnemonic, ok = m.(string)
if !ok {
return fmt.Errorf("mnemonic context value is not a string")
}
}
if sm := ctx.Value(mnemonicShowCtxKey); sm != nil {
var ok bool
showMnemonic, ok = sm.(bool)
if !ok {
return fmt.Errorf("show mnemonic context value is not a bool")
}
}

return printCreatePubKeyHex(cmd, k, eotsPk, showMnemonic, mnemonic, clientCtx.OutputFormat)
}
Expand All @@ -256,7 +371,7 @@ func printCreatePubKeyHex(cmd *cobra.Command, k *cryptokeyring.Record, eotsPk *t
if err != nil {
return err
}
keyOutput := newKeyOutputWithPubKeyHex(out, eotsPk)
keyOutput := newKeyOutputWithPubKeyHex(out, eotsPk.MarshalHex())

switch outputFormat {
case flags.OutputFormatText:
Expand Down Expand Up @@ -290,10 +405,10 @@ func printCreatePubKeyHex(cmd *cobra.Command, k *cryptokeyring.Record, eotsPk *t
return nil
}

func newKeyOutputWithPubKeyHex(k keys.KeyOutput, eotsPk *types.BIP340PubKey) KeyOutputWithPubKeyHex {
func newKeyOutputWithPubKeyHex(k keys.KeyOutput, eotsPk string) KeyOutputWithPubKeyHex {
return KeyOutputWithPubKeyHex{
KeyOutput: k,
PubKeyHex: eotsPk.MarshalHex(),
PubKeyHex: eotsPk,
}
}

Expand Down
58 changes: 31 additions & 27 deletions eotsmanager/cmd/eotsd/daemon/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"go.uber.org/zap"

"github.com/babylonlabs-io/finality-provider/eotsmanager"
eotscfg "github.com/babylonlabs-io/finality-provider/eotsmanager/config"
"github.com/babylonlabs-io/finality-provider/eotsmanager/config"
"github.com/babylonlabs-io/finality-provider/testutil"
)

Expand All @@ -30,31 +30,42 @@ func FuzzNewKeysCmd(f *testing.F) {
tDir := t.TempDir()
tempHome := filepath.Join(tDir, "homeeots")
homeFlagFilled := fmt.Sprintf("--%s=%s", sdkflags.FlagHome, tempHome)
rootCmdBuff := new(bytes.Buffer)
keyringBackendFlagFilled := fmt.Sprintf("--%s=%s", sdkflags.FlagKeyringBackend, keyring.BackendTest)

// Create separate buffers for stdout and stderr
stdoutBuf := new(bytes.Buffer)
stderrBuf := new(bytes.Buffer)

root.SetOut(stdoutBuf)
root.SetErr(stderrBuf)

defer func() {
err := os.RemoveAll(tempHome)
require.NoError(t, err)
}()

// Initialize the EOTS manager
_, _ = exec(t, root, rootCmdBuff, "init", homeFlagFilled)
_, _ = exec(t, root, "init", homeFlagFilled)

// Generate a random key name
keyName := testutil.GenRandomHexStr(r, 5)

// Execute the keys add command
keyringBackendFlagFilled := fmt.Sprintf("--%s=%s", sdkflags.FlagKeyringBackend, keyring.BackendTest)
_, _ = exec(t, root, rootCmdBuff, "keys", "add", keyName, homeFlagFilled, keyringBackendFlagFilled)
// Execute the keys add command with keyring backend
_, _ = exec(t, root, "keys", "add", keyName, homeFlagFilled, keyringBackendFlagFilled)

// Execute the keys list command with keyring backend
_, _ = exec(t, root, "keys", "list", homeFlagFilled, keyringBackendFlagFilled)

// Execute the keys list command
_, listOutput := exec(t, root, rootCmdBuff, "keys", "list", homeFlagFilled)
// Log output for debugging
t.Logf("Stdout: %q", stdoutBuf.String())
t.Logf("Stderr: %q", stderrBuf.String())

// Check if the added key is in the list
require.Contains(t, listOutput, keyName)
// Basic check - key name should be in output
require.Contains(t, stdoutBuf.String(), keyName, "List output should contain the key name")

// Load the EOTS manager and verify the key existence
eotsCfg := eotscfg.DefaultConfigWithHomePath(tempHome)
dbBackend, err := eotsCfg.DatabaseConfig.GetDBBackend()
cfg := config.DefaultConfigWithHomePath(tempHome)
dbBackend, err := cfg.DatabaseConfig.GetDBBackend()
require.NoError(t, err)
defer func() {
err := dbBackend.Close()
Expand All @@ -64,29 +75,22 @@ func FuzzNewKeysCmd(f *testing.F) {
eotsManager, err := eotsmanager.NewLocalEOTSManager(tempHome, "test", dbBackend, zap.NewNop())
require.NoError(t, err, "Should be able to create EOTS manager")

// Verify the key exists and has correct BIP340 public key
pubKey, err := eotsManager.LoadBIP340PubKeyFromKeyName(keyName)
require.NoError(t, err, "Should be able to load public key")
require.NotNil(t, pubKey, "Public key should not be nil")

// Verify the public key is in the output
hexPk := pubKey.MarshalHex()
require.Contains(t, stdoutBuf.String(), hexPk, "List output should contain the BIP340 public key hex")
})
}

// exec executes a command based on the cmd passed, the args should only search for subcommands, not parent commands
func exec(t *testing.T, root *cobra.Command, rootCmdBuf *bytes.Buffer, args ...string) (c *cobra.Command, output string) {
buf := new(bytes.Buffer)
root.SetOut(buf)
root.SetErr(buf)
// exec executes a command based on the cmd passed
func exec(t *testing.T, root *cobra.Command, args ...string) (*cobra.Command, error) {
root.SetArgs(args)

c, err := root.ExecuteC()
require.NoError(t, err)

outStr := buf.String()
if len(outStr) > 0 {
return c, outStr
}

_, err = buf.Write(rootCmdBuf.Bytes())
require.NoError(t, err)

return c, buf.String()
return c, err
}
1 change: 0 additions & 1 deletion eotsmanager/cmd/eotsd/daemon/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ func NewRootCmd() *cobra.Command {
NewKeysCmd(),
NewStartCmd(),
version.CommandVersion("eotsd"),
CommandPrintAllKeys(),
NewPopCmd(),
)

Expand Down
14 changes: 4 additions & 10 deletions itest/babylon/babylon_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ import (
"github.com/babylonlabs-io/babylon/testutil/datagen"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/jessevdk/go-flags"
"github.com/stretchr/testify/require"

sdkmath "cosmossdk.io/math"
bbntypes "github.com/babylonlabs-io/babylon/types"
bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"

eotscmd "github.com/babylonlabs-io/finality-provider/eotsmanager/cmd/eotsd/daemon"
eotscfg "github.com/babylonlabs-io/finality-provider/eotsmanager/config"
"github.com/babylonlabs-io/finality-provider/finality-provider/cmd/fpd/daemon"
"github.com/babylonlabs-io/finality-provider/finality-provider/store"
e2eutils "github.com/babylonlabs-io/finality-provider/itest"
Expand Down Expand Up @@ -388,22 +386,18 @@ func TestPrintEotsCmd(t *testing.T) {

cancel()

cmd := eotscmd.CommandPrintAllKeys()

defaultConfig := eotscfg.DefaultConfigWithHomePath(tm.EOTSHomeDir)
fileParser := flags.NewParser(defaultConfig, flags.Default)
err := flags.NewIniParser(fileParser).WriteFile(eotscfg.CfgFile(tm.EOTSHomeDir), flags.IniIncludeDefaults)
require.NoError(t, err)

cmd := eotscmd.NewKeysCmd()
cmd.SetArgs([]string{
"list",
"--home=" + tm.EOTSHomeDir,
"--keyring-backend=test",
})

var outputBuffer bytes.Buffer
cmd.SetOut(&outputBuffer)
cmd.SetErr(&outputBuffer)

err = cmd.Execute()
err := cmd.Execute()
require.NoError(t, err)

output := outputBuffer.String()
Expand Down
Loading