Skip to content

Commit

Permalink
feat: list all keys in store (#234)
Browse files Browse the repository at this point in the history
Adds `eotsd ls` command which prints all keys from DB

[closes](#229)
  • Loading branch information
Lazar955 authored Dec 19, 2024
1 parent e995884 commit 70df36f
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* [#228](https://github.com/babylonlabs-io/finality-provider/pull/228) Save key name mapping in eotsd import commands
* [#227](https://github.com/babylonlabs-io/finality-provider/pull/227) Fix FP submission loop
* [#226](https://github.com/babylonlabs-io/finality-provider/pull/226) Update local fp before register
* [#234](https://github.com/babylonlabs-io/finality-provider/pull/234) eotsd ls command

## v0.13.1

Expand Down
74 changes: 74 additions & 0 deletions eotsmanager/cmd/eotsd/daemon/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"io"

"github.com/babylonlabs-io/babylon/types"
Expand Down Expand Up @@ -124,6 +125,79 @@ 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,
}

cmd.Flags().String(flags.FlagHome, config.DefaultEOTSDir, "The path to the eotsd home directory")

return cmd
}

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

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())
}

return nil
}

func getAllEOTSKeys(cmd *cobra.Command) (map[string][]byte, error) {
homePath, err := getHomePath(cmd)
if err != nil {
return nil, err
}

// Load configuration
cfg, err := config.LoadConfig(homePath)
if err != nil {
return nil, fmt.Errorf("failed to load config: %w", err)
}

// Setup logger
logger, err := log.NewRootLoggerWithFile(config.LogFile(homePath), cfg.LogLevel)
if err != nil {
return nil, fmt.Errorf("failed to load the logger: %w", err)
}

// Get database backend
dbBackend, err := cfg.DatabaseConfig.GetDBBackend()
if err != nil {
return nil, fmt.Errorf("failed to create db backend: %w", err)
}
defer dbBackend.Close()

// Create EOTS manager
eotsManager, err := eotsmanager.NewLocalEOTSManager(homePath, cfg.KeyringBackend, dbBackend, logger)
if err != nil {
return nil, fmt.Errorf("failed to create EOTS manager: %w", err)
}

res, err := eotsManager.ListEOTSKeys()
if err != nil {
return nil, fmt.Errorf("failed to get keys from db: %w", err)
}

return res, nil
}

func printFromKey(cmd *cobra.Command, keyName string, eotsPk *types.BIP340PubKey) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions eotsmanager/cmd/eotsd/daemon/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func NewRootCmd() *cobra.Command {
NewKeysCmd(),
NewStartCmd(),
version.CommandVersion("eotsd"),
CommandPrintAllKeys(),
)

return rootCmd
Expand Down
4 changes: 4 additions & 0 deletions eotsmanager/localmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,7 @@ func (lm *LocalEOTSManager) keyExists(name string) bool {
_, err := lm.kr.Key(name)
return err == nil
}

func (lm *LocalEOTSManager) ListEOTSKeys() (map[string][]byte, error) {
return lm.es.GetAllEOTSKeyNames()
}
28 changes: 28 additions & 0 deletions eotsmanager/store/eotsstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,34 @@ func (s *EOTSStore) GetEOTSKeyName(pk []byte) (string, error) {
return keyName, nil
}

// GetAllEOTSKeyNames retrieves all keys and values.
// Returns keyName -> btcPK
func (s *EOTSStore) GetAllEOTSKeyNames() (map[string][]byte, error) {
result := make(map[string][]byte)

err := s.db.View(func(tx kvdb.RTx) error {
eotsBucket := tx.ReadBucket(eotsBucketName)
if eotsBucket == nil {
return ErrCorruptedEOTSDb
}

return eotsBucket.ForEach(func(k, v []byte) error {
if k == nil || v == nil {
return fmt.Errorf("encountered invalid key or value in bucket")
}
result[string(v)] = k

return nil
})
}, func() {})

if err != nil {
return nil, err
}

return result, nil
}

func (s *EOTSStore) SaveSignRecord(
height uint64,
chainID []byte,
Expand Down
51 changes: 51 additions & 0 deletions eotsmanager/store/eotsstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,54 @@ func FuzzSignStore(f *testing.F) {
require.False(t, found)
})
}

// FuzzListKeysEOTSStore tests getting all keys from store
func FuzzListKeysEOTSStore(f *testing.F) {
testutil.AddRandomSeedsToFuzzer(f, 10)
f.Fuzz(func(t *testing.T, seed int64) {
t.Parallel()
r := rand.New(rand.NewSource(seed))

homePath := t.TempDir()
cfg := config.DefaultDBConfigWithHomePath(homePath)

dbBackend, err := cfg.GetDBBackend()
require.NoError(t, err)

vs, err := store.NewEOTSStore(dbBackend)
require.NoError(t, err)

defer func() {
dbBackend.Close()
}()

expected := make(map[string][]byte)
for i := 0; i < r.Intn(10); i++ {
expectedKeyName := testutil.GenRandomHexStr(r, 10)
_, btcPk, err := datagen.GenRandomBTCKeyPair(r)
require.NoError(t, err)
expected[expectedKeyName] = schnorr.SerializePubKey(btcPk)

err = vs.AddEOTSKeyName(
btcPk,
expectedKeyName,
)
require.NoError(t, err)
}

keys, err := vs.GetAllEOTSKeyNames()
require.NoError(t, err)

for keyName, btcPk := range expected {
gotBtcPk, ok := keys[keyName]
require.True(t, ok)

parsedGot, err := schnorr.ParsePubKey(gotBtcPk)
require.NoError(t, err)
parsedExpected, err := schnorr.ParsePubKey(btcPk)
require.NoError(t, err)

require.Equal(t, parsedExpected, parsedGot)
}
})
}
49 changes: 49 additions & 0 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package e2etest

import (
"bytes"
"encoding/json"
"errors"
"fmt"
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/store"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/jessevdk/go-flags"
"log"
"math/rand"
"os"
Expand Down Expand Up @@ -352,3 +357,47 @@ func TestRemoveMerkleProofsCmd(t *testing.T) {
return errors.Is(err, store.ErrPubRandProofNotFound)
}, eventuallyWaitTimeOut, eventuallyPollTime)
}

func TestPrintEotsCmd(t *testing.T) {
tm := StartManager(t)
r := rand.New(rand.NewSource(time.Now().Unix()))
defer tm.Stop(t)

expected := make(map[string]string)
for i := 0; i < r.Intn(10); i++ {
eotsKeyName := fmt.Sprintf("eots-key-%s", datagen.GenRandomHexStr(r, 4))
ekey, err := tm.EOTSClient.CreateKey(eotsKeyName, passphrase, hdPath)
require.NoError(t, err)
pk, err := schnorr.ParsePubKey(ekey)
require.NoError(t, err)
expected[eotsKeyName] = bbntypes.NewBIP340PubKeyFromBTCPK(pk).MarshalHex()
}

tm.EOTSServerHandler.Stop()

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.SetArgs([]string{
"--home=" + tm.EOTSHomeDir,
})

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

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

output := outputBuffer.String()
t.Logf("Captured output: %s", output)

for keyName, eotsPK := range expected {
require.Contains(t, output, keyName)
require.Contains(t, output, eotsPK)
}
}
2 changes: 2 additions & 0 deletions itest/test_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ var (
type TestManager struct {
Wg sync.WaitGroup
EOTSServerHandler *EOTSServerHandler
EOTSHomeDir string
FpConfig *fpcfg.Config
Fps []*service.FinalityProviderApp
EOTSClient *client.EOTSManagerGRpcClient
Expand Down Expand Up @@ -138,6 +139,7 @@ func StartManager(t *testing.T) *TestManager {

tm := &TestManager{
EOTSServerHandler: eh,
EOTSHomeDir: eotsHomeDir,
FpConfig: cfg,
EOTSClient: eotsCli,
BBNClient: bc,
Expand Down

0 comments on commit 70df36f

Please sign in to comment.