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

add command to generate pop #111

Merged
merged 8 commits into from
Jan 8, 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## Unreleased

- [#111](https://github.com/babylonlabs-io/btc-staker/pull/111) Add CLI command
to create phase-1/phase-2 PoP payload

## v0.14.0

* [#108](https://github.com/babylonlabs-io/btc-staker/pull/108) Bump babylon to v1.0.0-rc.1

## v0.13.0
Expand Down
16 changes: 16 additions & 0 deletions babylonclient/keyringcontroller/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package keyringcontroller

import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
)

func MakeCodec() *codec.ProtoCodec {
ir := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(ir)

cryptocodec.RegisterInterfaces(ir)

return cdc
}
43 changes: 43 additions & 0 deletions babylonclient/keyringcontroller/keyring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package keyringcontroller

import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)

func CreateKeyring(keyringDir string, chainID string, backend string, input *strings.Reader) (keyring.Keyring, error) {
ctx, err := CreateClientCtx(keyringDir, chainID)
if err != nil {
return nil, err
}

if backend == "" {
return nil, fmt.Errorf("the keyring backend should not be empty")
}

kr, err := keyring.New(
ctx.ChainID,
backend,
ctx.KeyringDir,
input,
ctx.Codec,
ctx.KeyringOptions...)
if err != nil {
return nil, fmt.Errorf("failed to create keyring: %w", err)
}

return kr, nil
}

func CreateClientCtx(keyringDir string, chainID string) (client.Context, error) {
if keyringDir == "" {
return client.Context{}, fmt.Errorf("the keyring directory should not be empty")
}
return client.Context{}.
WithChainID(chainID).
WithCodec(MakeCodec()).
WithKeyringDir(keyringDir), nil
}
136 changes: 136 additions & 0 deletions babylonclient/keyringcontroller/keyringcontroller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package keyringcontroller

import (
"fmt"
"strings"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdksecp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/go-bip39"
)

const (
secp256k1Type = "secp256k1"
mnemonicEntropySize = 256
)

type ChainKeyInfo struct {
Name string
Mnemonic string
PublicKey *btcec.PublicKey
PrivateKey *btcec.PrivateKey
}

type ChainKeyringController struct {
kr keyring.Keyring
keyName string
// input is to send passphrase to kr
input *strings.Reader
}

func NewChainKeyringController(ctx client.Context, name, keyringBackend string) (*ChainKeyringController, error) {
if name == "" {
return nil, fmt.Errorf("the key name should not be empty")
}

if keyringBackend == "" {
return nil, fmt.Errorf("the keyring backend should not be empty")
}

inputReader := strings.NewReader("")
kr, err := keyring.New(
ctx.ChainID,
keyringBackend,
ctx.KeyringDir,
inputReader,
ctx.Codec,
ctx.KeyringOptions...)
if err != nil {
return nil, fmt.Errorf("failed to create keyring: %w", err)
}

return &ChainKeyringController{
keyName: name,
kr: kr,
input: inputReader,
}, nil
}

func NewChainKeyringControllerWithKeyring(kr keyring.Keyring, name string, input *strings.Reader) (*ChainKeyringController, error) {
if name == "" {
return nil, fmt.Errorf("the key name should not be empty")
}

return &ChainKeyringController{
kr: kr,
keyName: name,
input: input,
}, nil
}

func (kc *ChainKeyringController) GetKeyring() keyring.Keyring {
return kc.kr
}

func (kc *ChainKeyringController) CreateChainKey(passphrase, hdPath string) (*ChainKeyInfo, error) {
keyringAlgos, _ := kc.kr.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(secp256k1Type, keyringAlgos)
if err != nil {
return nil, err
}
// read entropy seed straight from tmcrypto.Rand and convert to mnemonic
entropySeed, err := bip39.NewEntropy(mnemonicEntropySize)
if err != nil {
return nil, err
}

mnemonic, err := bip39.NewMnemonic(entropySeed)
if err != nil {
return nil, err
}

// we need to repeat the passphrase to mock the reentry
kc.input.Reset(passphrase + "\n" + passphrase)
record, err := kc.kr.NewAccount(kc.keyName, mnemonic, passphrase, hdPath, algo)
if err != nil {
return nil, err
}

privKey := record.GetLocal().PrivKey.GetCachedValue()

switch v := privKey.(type) {
case *sdksecp256k1.PrivKey:
sk, pk := btcec.PrivKeyFromBytes(v.Key)
return &ChainKeyInfo{
Name: kc.keyName,
PublicKey: pk,
PrivateKey: sk,
Mnemonic: mnemonic,
}, nil
default:
return nil, fmt.Errorf("unsupported key type in keyring")
}
}

func (kc *ChainKeyringController) GetChainPrivKey(passphrase string) (*sdksecp256k1.PrivKey, error) {
kc.input.Reset(passphrase)
k, err := kc.kr.Key(kc.keyName)
if err != nil {
return nil, fmt.Errorf("failed to get private key: %w", err)
}

privKeyCached := k.GetLocal().PrivKey.GetCachedValue()

switch v := privKeyCached.(type) {
case *sdksecp256k1.PrivKey:
return v, nil
default:
return nil, fmt.Errorf("unsupported key type in keyring")
}
}

func (kc *ChainKeyringController) KeyRecord() (*keyring.Record, error) {
return kc.GetKeyring().Key(kc.keyName)
}
8 changes: 2 additions & 6 deletions cmd/stakercli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

cmdadmin "github.com/babylonlabs-io/btc-staker/cmd/stakercli/admin"
cmddaemon "github.com/babylonlabs-io/btc-staker/cmd/stakercli/daemon"
cmdpop "github.com/babylonlabs-io/btc-staker/cmd/stakercli/pop"
cmdtx "github.com/babylonlabs-io/btc-staker/cmd/stakercli/transaction"
"github.com/urfave/cli"
)
Expand All @@ -21,7 +22,6 @@ const (
btcWalletRPCUserFlag = "btc-wallet-rpc-user"
btcWalletRPCPassFlag = "btc-wallet-rpc-pass"
btcWalletPassphraseFlag = "btc-wallet-passphrase"
btcWalletBackendFlag = "btc-wallet-backend"
)

func main() {
Expand Down Expand Up @@ -53,16 +53,12 @@ func main() {
Name: btcWalletPassphraseFlag,
Usage: "Bitcoin wallet passphrase",
},
cli.StringFlag{
Name: btcWalletBackendFlag,
Usage: "Bitcoin backend (btcwallet|bitcoind)",
Value: "btcd",
},
}

app.Commands = append(app.Commands, cmddaemon.DaemonCommands...)
app.Commands = append(app.Commands, cmdadmin.AdminCommands...)
app.Commands = append(app.Commands, cmdtx.TransactionCommands...)
app.Commands = append(app.Commands, cmdpop.PopCommands...)

if err := app.Run(os.Args); err != nil {
fatal(err)
Expand Down
Loading
Loading