Skip to content

Commit

Permalink
Merge pull request ethereum-optimism#18 from babylonchain/initial-eve…
Browse files Browse the repository at this point in the history
…nt-loop

Initial event loop
  • Loading branch information
KonradStaniec authored Jul 19, 2023
2 parents 8b50fdd + 9500968 commit 7de0a07
Show file tree
Hide file tree
Showing 8 changed files with 405 additions and 163 deletions.
44 changes: 42 additions & 2 deletions cmd/valcli/daemoncmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ var daemonCommands = []cli.Command{
Usage: "More advanced commands which require validator daemon to be running.",
Category: "Daemon commands",
Subcommands: []cli.Command{
getDaemonInfo,
getDaemonInfoCmd,
createValCmd,
},
},
}
Expand All @@ -30,7 +31,7 @@ var (
defaultValdDaemonAddress = "127.0.0.1:" + strconv.Itoa(valcfg.DefaultRPCPort)
)

var getDaemonInfo = cli.Command{
var getDaemonInfoCmd = cli.Command{
Name: "get-info",
ShortName: "gi",
Usage: "Get information of the running daemon.",
Expand Down Expand Up @@ -62,3 +63,42 @@ func getInfo(ctx *cli.Context) error {

return nil
}

var createValCmd = cli.Command{
Name: "create-validator",
ShortName: "cv",
Usage: "Get information of the running daemon.",
Flags: []cli.Flag{
cli.StringFlag{
Name: valdDaemonAddressFlag,
Usage: "Full address of the validator daemon in format tcp://<host>:<port>",
Value: defaultValdDaemonAddress,
},
cli.StringFlag{
Name: keyNameFlag,
Usage: "The unique name of the validator key",
Required: true,
},
},
Action: createValDaemon,
}

func createValDaemon(ctx *cli.Context) error {
daemonAddress := ctx.String(valdDaemonAddressFlag)
keyName := ctx.String(keyNameFlag)
client, cleanUp, err := dc.NewValidatorServiceGRpcClient(daemonAddress)
if err != nil {
return err
}
defer cleanUp()

info, err := client.CreateValidator(context.Background(), keyName)

if err != nil {
return err
}

printRespJSON(info)

return nil
}
5 changes: 3 additions & 2 deletions cmd/valcli/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/hex"
"fmt"

"github.com/urfave/cli"
Expand Down Expand Up @@ -105,8 +106,8 @@ func createVal(ctx *cli.Context) error {
}

printRespJSON(&proto.CreateValidatorResponse{
BabylonPk: validator.BabylonPk,
BtcPk: validator.BtcPk,
BabylonPk: hex.EncodeToString(validator.BabylonPk),
BtcPk: hex.EncodeToString(validator.BtcPk),
})

return err
Expand Down
59 changes: 57 additions & 2 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,34 @@ package e2etest

import (
"os"
"path/filepath"
"testing"
"time"

babylonclient "github.com/babylonchain/btc-validator/bbnclient"
"github.com/babylonchain/btc-validator/service"
"github.com/babylonchain/btc-validator/valcfg"
cfg "github.com/babylonchain/btc-validator/valcfg"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
)

func TempDirWithName(name string) (string, error) {
tempPath := os.TempDir()

tempName, err := os.MkdirTemp(tempPath, name)
if err != nil {
return "", err
}

err = os.Chmod(tempName, 0755)

if err != nil {
return "", err
}

return tempName, nil
}

func TestPoller(t *testing.T) {
handler, err := NewBabylonNodeHandler()
require.NoError(t, err)
Expand All @@ -31,7 +48,7 @@ func TestPoller(t *testing.T) {
logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)
logger.Out = os.Stdout
defaultPollerConfig := cfg.DefaulPollerConfig()
defaultPollerConfig := valcfg.DefaulPollerConfig()

bc, err := babylonclient.NewBabylonController(&defaultConfig, logger)
require.NoError(t, err)
Expand Down Expand Up @@ -68,3 +85,41 @@ func TestPoller(t *testing.T) {
t.Fatalf("Failed to get block info")
}
}

func TestCreateValidator(t *testing.T) {
tDir, err := TempDirWithName("valtest")
require.NoError(t, err)
defer func() {
err = os.RemoveAll(tDir)
require.NoError(t, err)
}()

defaultConfig := valcfg.DefaultConfig()
defaultConfig.KeyringDir = tDir
defaultConfig.BabylonConfig.KeyDirectory = tDir
defaultConfig.DatabaseConfig.Path = filepath.Join(tDir, "valtest.db")

logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)
logger.Out = os.Stdout

bc, err := babylonclient.NewBabylonController(defaultConfig.BabylonConfig, logger)
require.NoError(t, err)

app, err := service.NewValidatorAppFromConfig(&defaultConfig, logger, bc)
require.NoError(t, err)

err = app.Start()
require.NoError(t, err)
defer app.Stop()

newValName := "testingValidator"
valResult, err := app.CreateValidator(newValName)
require.NoError(t, err)

validator, err := app.GetValidator(valResult.BabylonValidatorPk.Key)
require.NoError(t, err)

require.Equal(t, newValName, validator.KeyName)

}
305 changes: 158 additions & 147 deletions proto/validators.pb.go

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions proto/validators.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ message GetInfoResponse {
}

message CreateValidatorRequest {
// key_name is the identifier key in keyring
string key_name = 1;
}

message CreateValidatorResponse {
// babylon_pk is the Babylon secp256k1 PK of this BTC validator
bytes babylon_pk = 1;
string babylon_pk = 1;
// btc_pk is the BTC secp256k1 PK of the validator encoded in BIP-340 spec
bytes btc_pk = 2;
string btc_pk = 2;
}

message RegisterValidatorRequest {
Expand Down
123 changes: 116 additions & 7 deletions service/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"github.com/babylonchain/babylon/types"
bstypes "github.com/babylonchain/babylon/x/btcstaking/types"
ftypes "github.com/babylonchain/babylon/x/finality/types"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/sirupsen/logrus"
Expand All @@ -29,6 +32,8 @@ type ValidatorApp struct {
vs *val.ValidatorStore
config *valcfg.Config
logger *logrus.Logger

createValidatorRequestChan chan *createValidatorRequest
}

func NewValidatorAppFromConfig(
Expand All @@ -52,15 +57,31 @@ func NewValidatorAppFromConfig(
}

return &ValidatorApp{
bc: bc,
vs: valStore,
kr: kr,
config: config,
logger: logger,
quit: make(chan struct{}),
bc: bc,
vs: valStore,
kr: kr,
config: config,
logger: logger,
quit: make(chan struct{}),
createValidatorRequestChan: make(chan *createValidatorRequest),
}, nil
}

type createValidatorResponse struct {
BtcValidatorPk btcec.PublicKey
BabylonValidatorPk secp256k1.PubKey
}
type createValidatorRequest struct {
keyName string
errResponse chan error
successResponse chan *createValidatorResponse
}

type CreateValidatorResult struct {
BtcValidatorPk btcec.PublicKey
BabylonValidatorPk secp256k1.PubKey
}

func (app *ValidatorApp) GetValidatorStore() *val.ValidatorStore {
return app.vs
}
Expand Down Expand Up @@ -217,7 +238,95 @@ func (app *ValidatorApp) Stop() error {
return stopErr
}

func (app *ValidatorApp) CreateValidator(keyName string) (*CreateValidatorResult, error) {
req := &createValidatorRequest{
keyName: keyName,
errResponse: make(chan error),
successResponse: make(chan *createValidatorResponse),
}

app.createValidatorRequestChan <- req

select {
case err := <-req.errResponse:
return nil, err
case successResponse := <-req.successResponse:
return &CreateValidatorResult{
BtcValidatorPk: successResponse.BtcValidatorPk,
BabylonValidatorPk: successResponse.BabylonValidatorPk,
}, nil
case <-app.quit:
return nil, fmt.Errorf("validator app is shutting down")
}
}

func (app *ValidatorApp) GetValidator(pkBytes []byte) (*proto.Validator, error) {
return app.vs.GetValidator(pkBytes)
}

func (app *ValidatorApp) handleCreateValidatorRequest(req *createValidatorRequest) (*createValidatorResponse, error) {

kr, err := val.NewKeyringControllerWithKeyring(app.kr, req.keyName)

if err != nil {
return nil, fmt.Errorf("failed to create keyring controller: %w", err)
}

if kr.KeyNameTaken() {
return nil, fmt.Errorf("the key name %s is taken", kr.GetKeyName())
}

// TODO should not expose direct proto here, as this is internal db representation
// conected to serialization
validator, err := kr.CreateBTCValidator()
if err != nil {
return nil, fmt.Errorf("failed to create validator: %w", err)
}

if err := app.vs.SaveValidator(validator); err != nil {
return nil, fmt.Errorf("failed to save validator: %w", err)
}

btcPubKey, err := schnorr.ParsePubKey(validator.BtcPk)

if err != nil {
app.logger.WithFields(logrus.Fields{
"err": err,
}).Fatal("failed to parse created btc public key")
}

babylonPubKey := secp256k1.PubKey{
Key: validator.BabylonPk,
}

return &createValidatorResponse{
BtcValidatorPk: *btcPubKey,
BabylonValidatorPk: babylonPubKey,
}, nil
}

// main event loop for the validator app
func (app *ValidatorApp) eventLoop() {
panic("implement me")
defer app.wg.Done()

for {
select {
case req := <-app.createValidatorRequestChan:
resp, err := app.handleCreateValidatorRequest(req)

if err != nil {
req.errResponse <- err
continue
}

app.logger.WithFields(logrus.Fields{
"btc_pub_key": resp.BtcValidatorPk,
"babylon_pub_key": resp.BabylonValidatorPk,
}).Info("Successfully created validator")

req.successResponse <- resp
case <-app.quit:
return
}
}
}
10 changes: 10 additions & 0 deletions service/client/rpcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,13 @@ func (c *ValidatorServiceGRpcClient) CommitPubRandList(ctx context.Context, bbnP

return res, nil
}

func (c *ValidatorServiceGRpcClient) CreateValidator(ctx context.Context, keyName string) (*proto.CreateValidatorResponse, error) {
req := &proto.CreateValidatorRequest{KeyName: keyName}
res, err := c.client.CreateValidator(ctx, req)
if err != nil {
return nil, err
}

return res, nil
}
16 changes: 15 additions & 1 deletion service/rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package service

import (
"context"
"encoding/hex"
"fmt"
"sync"
"sync/atomic"

"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/lightningnetwork/lnd/signal"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
Expand Down Expand Up @@ -98,7 +100,19 @@ func (r *rpcServer) GetInfo(context.Context, *proto.GetInfoRequest) (*proto.GetI
// CreateValidator generates a validator object and saves it in the database
func (r *rpcServer) CreateValidator(ctx context.Context, req *proto.CreateValidatorRequest) (
*proto.CreateValidatorResponse, error) {
panic("implement me")
result, err := r.app.CreateValidator(req.KeyName)

if err != nil {
return nil, err
}

btcPk := schnorr.SerializePubKey(&result.BtcValidatorPk)

return &proto.CreateValidatorResponse{
BtcPk: hex.EncodeToString(btcPk),
BabylonPk: hex.EncodeToString(result.BabylonValidatorPk.Key),
}, nil

}

// RegisterValidator sends a transactions to Babylon to register a BTC validator
Expand Down

0 comments on commit 7de0a07

Please sign in to comment.