-
Notifications
You must be signed in to change notification settings - Fork 1
feat: vanilla implementation #1
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[url "ssh://[email protected]/"] | ||
insteadOf = https://github.com/ | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
MOCKS_DIR=$(CURDIR)/testutil/mocks/ | ||
MOCKGEN_REPO=github.com/golang/mock/mockgen | ||
MOCKGEN_VERSION=v1.6.0 | ||
MOCKGEN_CMD=go run ${MOCKGEN_REPO}@${MOCKGEN_VERSION} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rules for building would also be useful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, is there a usecase in which someone uses this client directly from this repository without anything else? Currently, I do not think we have such a usecase so a In the future, I can envision this client also providing a CLI interface in which someone can interact with a remote Babylon node (although the same can be accomplished through There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. We should implement it as a command line tool just like lens did. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good! An issue for that would be appreciated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
test: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this depend on the mocks getting generated by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying we should re-generate mock files every time before we run tests? Not sure about that. It seems we can manually generate mock files once and upload them in the repo so that others do not need to generate them again, just like the protobuf files. |
||
go test ./... | ||
|
||
mock-gen: | ||
mkdir -p $(MOCKS_DIR) | ||
$(MOCKGEN_CMD) -source=client/interface.go -package mocks -destination $(MOCKS_DIR)/client.go |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package client | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/babylonchain/vigilante/config" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the vigilante depends on the babylon client and the client depends on the vigilante, this might introduce a cyclic dependency. |
||
lensclient "github.com/strangelove-ventures/lens/client" | ||
) | ||
|
||
var _ BabylonClient = &Client{} | ||
|
||
type Client struct { | ||
*lensclient.ChainClient | ||
cfg *config.BabylonConfig | ||
|
||
// retry attributes | ||
retrySleepTime time.Duration | ||
maxRetrySleepTime time.Duration | ||
} | ||
|
||
func New(cfg *config.BabylonConfig, retrySleepTime, maxRetrySleepTime time.Duration) (*Client, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest that we do not depend on Overall, since the RPC client is extracted from the vigilante, the vigilante should aim to have as little knowledge of the workings of the RPC client as possible. This includes configuration, which should be managed here. |
||
// create a Tendermint/Cosmos client for Babylon | ||
cc, err := newLensClient(cfg.Unwrap()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// show addresses in the key ring | ||
// TODO: specify multiple addresses in config | ||
addrs, err := cc.ListAddresses() | ||
if err != nil { | ||
return nil, err | ||
} | ||
log.Debugf("Babylon key directory: %v", cfg.KeyDirectory) | ||
log.Debugf("All Babylon addresses: %v", addrs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we retrieve the Babylon addresses? Is this some kind of sanity check? As they are not used anywhere else in this function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like a sanity check. Any thoughts @SebastianElvis? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reporter uses this address to submit txs to Babylon. The logs and thus retrieving addresses can be omitted though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just making sure: Do we need to execute There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need, the accounts are retrieved just for logging. |
||
|
||
// wrap to our type | ||
client := &Client{cc, cfg, retrySleepTime, maxRetrySleepTime} | ||
log.Infof("Successfully created the Babylon client") | ||
|
||
return client, nil | ||
} | ||
|
||
func (c *Client) GetConfig() *config.BabylonConfig { | ||
return c.cfg | ||
} | ||
|
||
func (c *Client) GetTagIdx() uint8 { | ||
tagIdxStr := c.cfg.TagIdx | ||
if len(tagIdxStr) != 1 { | ||
panic(fmt.Errorf("tag index should be one byte")) | ||
} | ||
// convert tagIdx from string to its ascii value | ||
return uint8(rune(tagIdxStr[0])) | ||
} | ||
|
||
func (c *Client) Stop() { | ||
if c.RPCClient != nil && c.RPCClient.IsRunning() { | ||
<-c.RPCClient.Quit() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package client | ||
|
||
import ( | ||
btcctypes "github.com/babylonchain/babylon/x/btccheckpoint/types" | ||
btclctypes "github.com/babylonchain/babylon/x/btclightclient/types" | ||
checkpointingtypes "github.com/babylonchain/babylon/x/checkpointing/types" | ||
epochingtypes "github.com/babylonchain/babylon/x/epoching/types" | ||
"github.com/babylonchain/vigilante/config" | ||
"github.com/btcsuite/btcd/chaincfg/chainhash" | ||
"github.com/btcsuite/btcd/wire" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
) | ||
|
||
type BabylonClient interface { | ||
Stop() | ||
GetConfig() *config.BabylonConfig | ||
GetTagIdx() uint8 | ||
GetAddr() (sdk.AccAddress, error) | ||
MustGetAddr() sdk.AccAddress | ||
QueryStakingParams() (*stakingtypes.Params, error) | ||
QueryEpochingParams() (*epochingtypes.Params, error) | ||
QueryBTCLightclientParams() (*btclctypes.Params, error) | ||
QueryBTCCheckpointParams() (*btcctypes.Params, error) | ||
MustQueryBTCCheckpointParams() *btcctypes.Params | ||
QueryHeaderChainTip() (*chainhash.Hash, uint64, error) | ||
QueryRawCheckpoint(epochNumber uint64) (*checkpointingtypes.RawCheckpointWithMeta, error) | ||
QueryRawCheckpointList(status checkpointingtypes.CheckpointStatus) ([]*checkpointingtypes.RawCheckpointWithMeta, error) | ||
QueryBaseHeader() (*wire.BlockHeader, uint64, error) | ||
QueryContainsBlock(blockHash *chainhash.Hash) (bool, error) | ||
InsertBTCSpvProof(msg *btcctypes.MsgInsertBTCSpvProof) (*sdk.TxResponse, error) | ||
InsertHeader(msg *btclctypes.MsgInsertHeader) (*sdk.TxResponse, error) | ||
InsertHeaders(msgs []*btclctypes.MsgInsertHeader) (*sdk.TxResponse, error) | ||
MustInsertBTCSpvProof(msg *btcctypes.MsgInsertBTCSpvProof) *sdk.TxResponse | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package client | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
func (c *Client) GetAddr() (sdk.AccAddress, error) { | ||
return c.ChainClient.GetKeyAddress() | ||
} | ||
|
||
func (c *Client) MustGetAddr() sdk.AccAddress { | ||
addr, err := c.ChainClient.GetKeyAddress() | ||
if err != nil { | ||
panic(fmt.Errorf("Failed to get signer: %v", err)) | ||
} | ||
return addr | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package client_test | ||
|
||
import ( | ||
"math/rand" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
bbn "github.com/babylonchain/babylon/app" | ||
"github.com/babylonchain/babylon/testutil/datagen" | ||
"github.com/babylonchain/vigilante/babylonclient" | ||
"github.com/babylonchain/vigilante/config" | ||
"github.com/cosmos/cosmos-sdk/crypto/hd" | ||
"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func FuzzKeys(f *testing.F) { | ||
datagen.AddRandomSeedsToFuzzer(f, 10) | ||
|
||
f.Fuzz(func(t *testing.T, seed int64) { | ||
rand.Seed(seed) | ||
|
||
// create a keyring | ||
keyringName := datagen.GenRandomHexStr(10) | ||
dir := t.TempDir() | ||
mockIn := strings.NewReader("") | ||
cdc := bbn.MakeTestEncodingConfig() | ||
kr, err := keyring.New(keyringName, "test", dir, mockIn, cdc.Marshaler) | ||
require.NoError(t, err) | ||
|
||
// create a random key pair in this keyring | ||
keyName := datagen.GenRandomHexStr(10) | ||
kr.NewMnemonic( | ||
keyName, | ||
keyring.English, | ||
hd.CreateHDPath(118, 0, 0).String(), | ||
keyring.DefaultBIP39Passphrase, | ||
hd.Secp256k1, | ||
) | ||
|
||
// create a Babylon client with this random keyring | ||
cfg := config.DefaultBabylonConfig() | ||
cfg.KeyDirectory = dir | ||
cfg.Key = keyName | ||
cl, err := babylonclient.New(&cfg, 1*time.Minute, 5*time.Minute) | ||
require.NoError(t, err) | ||
|
||
// retrieve the key info from key ring | ||
keys, err := kr.List() | ||
require.NoError(t, err) | ||
require.Equal(t, 1, len(keys)) | ||
|
||
// test if the key is consistent in Babylon client and keyring | ||
bbnAddr := cl.MustGetAddr() | ||
addr, _ := keys[0].GetAddress() | ||
require.Equal(t, addr, bbnAddr) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package client | ||
|
||
import ( | ||
vlog "github.com/babylonchain/vigilante/log" | ||
) | ||
|
||
var log = vlog.Logger.WithField("module", "babylonclient") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package client | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/crypto/hd" | ||
"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||
lensclient "github.com/strangelove-ventures/lens/client" | ||
) | ||
|
||
// adapted from https://github.com/strangelove-ventures/lens/blob/v0.5.1/client/chain_client.go#L48-L63 | ||
// The notable difference is parsing the key directory | ||
// TODO: key directory support for different types of keyring backend | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can add a Github issue for that for easier tracking. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SebastianElvis Not sure about this description. Could you please revisit this TODO and create an issue for tracking if it is needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, created #2 |
||
func newLensClient(ccc *lensclient.ChainClientConfig, kro ...keyring.Option) (*lensclient.ChainClient, error) { | ||
// attach the supported algorithms to the keyring options | ||
keyringOptions := []keyring.Option{} | ||
keyringOptions = append(keyringOptions, func(options *keyring.Options) { | ||
options.SupportedAlgos = keyring.SigningAlgoList{hd.Secp256k1} | ||
options.SupportedAlgosLedger = keyring.SigningAlgoList{hd.Secp256k1} | ||
}) | ||
keyringOptions = append(keyringOptions, kro...) | ||
|
||
cc := &lensclient.ChainClient{ | ||
KeyringOptions: keyringOptions, | ||
Config: ccc, | ||
Codec: lensclient.MakeCodec(ccc.Modules), | ||
} | ||
if err := cc.Init(); err != nil { | ||
return nil, err | ||
} | ||
return cc, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say this does not have a place in this repository. If someone wants to use this replacement rule, we can add instructions on how this can happen on the repository
README
.