Skip to content

Commit

Permalink
add command to generate pop (#111)
Browse files Browse the repository at this point in the history
* add command to generate pop
  • Loading branch information
KonradStaniec authored Jan 8, 2025
1 parent ddfabe3 commit 0a59e30
Show file tree
Hide file tree
Showing 8 changed files with 620 additions and 6 deletions.
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

0 comments on commit 0a59e30

Please sign in to comment.