From 56df3aa52ca6fe6d5b4ca42c4325b142c6663c0f Mon Sep 17 00:00:00 2001 From: Lazar Date: Mon, 20 Jan 2025 15:38:06 +0100 Subject: [PATCH 01/21] moving relayer code --- client/client/client.go | 9 +- client/client/tx.go | 33 +- client/config/babylon_config.go | 6 +- client/config/babylon_query_config.go | 2 +- client/relayer/account.go | 75 +++ client/relayer/bech32_hack.go | 28 + client/relayer/broadcast.go | 18 + client/relayer/chain_provider.go | 223 ++++++++ client/relayer/client_wrapper.go | 580 +++++++++++++++++++ client/relayer/codec.go | 117 ++++ client/relayer/feegrant.go | 37 ++ client/relayer/grpc_query.go | 216 ++++++++ client/relayer/keys.go | 266 +++++++++ client/relayer/log.go | 189 +++++++ client/relayer/msg.go | 65 +++ client/relayer/provider.go | 310 +++++++++++ client/relayer/query.go | 143 +++++ client/relayer/tx.go | 770 ++++++++++++++++++++++++++ 18 files changed, 3061 insertions(+), 26 deletions(-) create mode 100644 client/relayer/account.go create mode 100644 client/relayer/bech32_hack.go create mode 100644 client/relayer/broadcast.go create mode 100644 client/relayer/chain_provider.go create mode 100644 client/relayer/client_wrapper.go create mode 100644 client/relayer/codec.go create mode 100644 client/relayer/feegrant.go create mode 100644 client/relayer/grpc_query.go create mode 100644 client/relayer/keys.go create mode 100644 client/relayer/log.go create mode 100644 client/relayer/msg.go create mode 100644 client/relayer/provider.go create mode 100644 client/relayer/query.go create mode 100644 client/relayer/tx.go diff --git a/client/client/client.go b/client/client/client.go index e641c96bc..964915493 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -2,20 +2,20 @@ package client import ( "context" + relayerclient "github.com/babylonlabs-io/babylon/client/relayer" "time" bbn "github.com/babylonlabs-io/babylon/app" "github.com/babylonlabs-io/babylon/client/config" "github.com/babylonlabs-io/babylon/client/query" rpchttp "github.com/cometbft/cometbft/rpc/client/http" - "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "go.uber.org/zap" ) type Client struct { *query.QueryClient - provider *cosmos.CosmosProvider + provider *relayerclient.CosmosProvider timeout time.Duration logger *zap.Logger cfg *config.BabylonConfig @@ -44,20 +44,19 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { provider, err := cfg.ToCosmosProviderConfig().NewProvider( zapLogger, "", // TODO: set home path - true, "babylon", ) if err != nil { return nil, err } - cp := provider.(*cosmos.CosmosProvider) + cp := provider.(*relayerclient.CosmosProvider) cp.PCfg.KeyDirectory = cfg.KeyDirectory // Create tmp Babylon app to retrieve and register codecs // Need to override this manually as otherwise option from config is ignored encCfg := bbn.GetEncodingConfig() - cp.Cdc = cosmos.Codec{ + cp.Cdc = relayerclient.Codec{ InterfaceRegistry: encCfg.InterfaceRegistry, Marshaler: encCfg.Codec, TxConfig: encCfg.TxConfig, diff --git a/client/client/tx.go b/client/client/tx.go index 891738002..f00822f89 100644 --- a/client/client/tx.go +++ b/client/client/tx.go @@ -3,6 +3,7 @@ package client import ( "context" "fmt" + relayerclient "github.com/babylonlabs-io/babylon/client/relayer" "sync" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" @@ -21,16 +22,14 @@ import ( txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/cosmos/relayer/v2/relayer/chains/cosmos" - pv "github.com/cosmos/relayer/v2/relayer/provider" "go.uber.org/zap" ) // ToProviderMsgs converts a list of sdk.Msg to a list of provider.RelayerMessage -func ToProviderMsgs(msgs []sdk.Msg) []pv.RelayerMessage { - relayerMsgs := []pv.RelayerMessage{} +func ToProviderMsgs(msgs []sdk.Msg) []relayerclient.RelayerMessage { + relayerMsgs := make([]relayerclient.RelayerMessage, 0, len(msgs)) for _, m := range msgs { - relayerMsgs = append(relayerMsgs, cosmos.NewCosmosMessage(m, func(signer string) {})) + relayerMsgs = append(relayerMsgs, relayerclient.NewCosmosMessage(m, func(signer string) {})) } return relayerMsgs } @@ -48,7 +47,7 @@ func (c *Client) SendMsgsToMempool(ctx context.Context, msgs []sdk.Msg) error { if err := retry.Do(func() error { var sendMsgErr error krErr := c.accessKeyWithLock(func() { - sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*pv.RelayerTxResponse, error){}) + sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*relayerclient.RelayerTxResponse, error){}) }) if krErr != nil { c.logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr)) @@ -67,21 +66,21 @@ func (c *Client) SendMsgsToMempool(ctx context.Context, msgs []sdk.Msg) error { // ReliablySendMsg reliable sends a message to the chain. // It utilizes a file lock as well as a keyring lock to ensure atomic access. // TODO: needs tests -func (c *Client) ReliablySendMsg(ctx context.Context, msg sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*pv.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsg(ctx context.Context, msg sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { return c.ReliablySendMsgs(ctx, []sdk.Msg{msg}, expectedErrors, unrecoverableErrors) } // ReliablySendMsgs reliably sends a list of messages to the chain. // It utilizes a file lock as well as a keyring lock to ensure atomic access. // TODO: needs tests -func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*pv.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { var ( - rlyResp *pv.RelayerTxResponse + rlyResp *relayerclient.RelayerTxResponse callbackErr error wg sync.WaitGroup ) - callback := func(rtr *pv.RelayerTxResponse, err error) { + callback := func(rtr *relayerclient.RelayerTxResponse, err error) { rlyResp = rtr callbackErr = err wg.Done() @@ -96,7 +95,7 @@ func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedE if err := retry.Do(func() error { var sendMsgErr error krErr := c.accessKeyWithLock(func() { - sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*pv.RelayerTxResponse, error){callback}) + sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*relayerclient.RelayerTxResponse, error){callback}) }) if krErr != nil { c.logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr)) @@ -147,9 +146,9 @@ func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedE // ReliablySendMsgsWithSigner reliably sends a list of messages to the chain. // It utilizes the signer private key to sign all msgs -func (c *Client) ReliablySendMsgsWithSigner(ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*pv.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsgsWithSigner(ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { var ( - rlyResp *pv.RelayerTxResponse + rlyResp *relayerclient.RelayerTxResponse callbackErr error wg sync.WaitGroup ) @@ -209,9 +208,9 @@ func (c *Client) SendMessageWithSigner( ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, - relayerMsgs []pv.RelayerMessage, + relayerMsgs []relayerclient.RelayerMessage, ) (result *coretypes.ResultBroadcastTx, err error) { - cMsgs := cosmos.CosmosMsgs(relayerMsgs...) + cMsgs := relayerclient.CosmosMsgs(relayerMsgs...) var ( num, seq uint64 ) @@ -486,11 +485,11 @@ func Sign( // - we do not support cancellation of submitting messages // - the only timeout is the block inclusion timeout i.e block-timeout // TODO: To properly support cancellation we need to expose ctx in our client calls -func (c *Client) InsertBTCSpvProof(ctx context.Context, msg *btcctypes.MsgInsertBTCSpvProof) (*pv.RelayerTxResponse, error) { +func (c *Client) InsertBTCSpvProof(ctx context.Context, msg *btcctypes.MsgInsertBTCSpvProof) (*relayerclient.RelayerTxResponse, error) { return c.ReliablySendMsg(ctx, msg, []*errors.Error{}, []*errors.Error{}) } -func (c *Client) InsertHeaders(ctx context.Context, msg *btclctypes.MsgInsertHeaders) (*pv.RelayerTxResponse, error) { +func (c *Client) InsertHeaders(ctx context.Context, msg *btclctypes.MsgInsertHeaders) (*relayerclient.RelayerTxResponse, error) { return c.ReliablySendMsg(ctx, msg, []*errors.Error{}, []*errors.Error{}) } diff --git a/client/config/babylon_config.go b/client/config/babylon_config.go index 680e5fb1a..e903d9780 100644 --- a/client/config/babylon_config.go +++ b/client/config/babylon_config.go @@ -2,7 +2,7 @@ package config import ( "fmt" - "github.com/cosmos/relayer/v2/relayer/chains/cosmos" + relayerclient "github.com/babylonlabs-io/babylon/client/relayer" "net/url" "os" "path/filepath" @@ -42,8 +42,8 @@ func (cfg *BabylonConfig) Validate() error { return nil } -func (cfg *BabylonConfig) ToCosmosProviderConfig() cosmos.CosmosProviderConfig { - return cosmos.CosmosProviderConfig{ +func (cfg *BabylonConfig) ToCosmosProviderConfig() relayerclient.CosmosProviderConfig { + return relayerclient.CosmosProviderConfig{ Key: cfg.Key, ChainID: cfg.ChainID, RPCAddr: cfg.RPCAddr, diff --git a/client/config/babylon_query_config.go b/client/config/babylon_query_config.go index 5a378f221..ff4026cb4 100644 --- a/client/config/babylon_query_config.go +++ b/client/config/babylon_query_config.go @@ -6,7 +6,7 @@ import ( "time" ) -// BabylonConfig defines configuration for the Babylon query client +// BabylonQueryConfig defines configuration for the Babylon query client type BabylonQueryConfig struct { RPCAddr string `mapstructure:"rpc-addr"` Timeout time.Duration `mapstructure:"timeout"` diff --git a/client/relayer/account.go b/client/relayer/account.go new file mode 100644 index 000000000..b9ca8caba --- /dev/null +++ b/client/relayer/account.go @@ -0,0 +1,75 @@ +package relayerclient + +import ( + "context" + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +var _ client.AccountRetriever = &CosmosProvider{} + +// GetAccount queries for an account given an address and a block height. An +// error is returned if the query or decoding fails. +func (cc *CosmosProvider) GetAccount(clientCtx client.Context, addr sdk.AccAddress) (client.Account, error) { + account, _, err := cc.GetAccountWithHeight(clientCtx, addr) + return account, err +} + +// GetAccountWithHeight queries for an account given an address. Returns the +// height of the query with the account. An error is returned if the query +// or decoding fails. +func (cc *CosmosProvider) GetAccountWithHeight(_ client.Context, addr sdk.AccAddress) (client.Account, int64, error) { + var header metadata.MD + address, err := cc.EncodeBech32AccAddr(addr) + if err != nil { + return nil, 0, err + } + + queryClient := authtypes.NewQueryClient(cc) + res, err := queryClient.Account(context.Background(), &authtypes.QueryAccountRequest{Address: address}, grpc.Header(&header)) + if err != nil { + return nil, 0, err + } + + blockHeight := header.Get(grpctypes.GRPCBlockHeightHeader) + if l := len(blockHeight); l != 1 { + return nil, 0, fmt.Errorf("unexpected '%s' header length; got %d, expected: %d", grpctypes.GRPCBlockHeightHeader, l, 1) + } + + nBlockHeight, err := strconv.Atoi(blockHeight[0]) + if err != nil { + return nil, 0, fmt.Errorf("failed to parse block height: %w", err) + } + + var acc authtypes.AccountI + if err := cc.Cdc.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { + return nil, 0, err + } + + return acc, int64(nBlockHeight), nil +} + +// EnsureExists returns an error if no account exists for the given address else nil. +func (cc *CosmosProvider) EnsureExists(clientCtx client.Context, addr sdk.AccAddress) error { + if _, err := cc.GetAccount(clientCtx, addr); err != nil { + return err + } + return nil +} + +// GetAccountNumberSequence returns sequence and account number for the given address. +// It returns an error if the account couldn't be retrieved from the state. +func (cc *CosmosProvider) GetAccountNumberSequence(clientCtx client.Context, addr sdk.AccAddress) (uint64, uint64, error) { + acc, err := cc.GetAccount(clientCtx, addr) + if err != nil { + return 0, 0, err + } + return acc.GetAccountNumber(), acc.GetSequence(), nil +} diff --git a/client/relayer/bech32_hack.go b/client/relayer/bech32_hack.go new file mode 100644 index 000000000..a888690a9 --- /dev/null +++ b/client/relayer/bech32_hack.go @@ -0,0 +1,28 @@ +package relayerclient + +import ( + "sync" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// This file is cursed and this mutex is too +// you don't want none of this dewey cox. +var sdkConfigMutex sync.Mutex + +// SetSDKContext sets the SDK config to the proper bech32 prefixes. +// Don't use this unless you know what you're doing. +// TODO: :dagger: :knife: :chainsaw: remove this function +func (cc *CosmosProvider) SetSDKContext() func() { + return SetSDKConfigContext(cc.PCfg.AccountPrefix) +} + +// SetSDKConfigContext sets the SDK config to the given bech32 prefixes +func SetSDKConfigContext(prefix string) func() { + sdkConfigMutex.Lock() + sdkConf := sdk.GetConfig() + sdkConf.SetBech32PrefixForAccount(prefix, prefix+"pub") + sdkConf.SetBech32PrefixForValidator(prefix+"valoper", prefix+"valoperpub") + sdkConf.SetBech32PrefixForConsensusNode(prefix+"valcons", prefix+"valconspub") + return sdkConfigMutex.Unlock +} diff --git a/client/relayer/broadcast.go b/client/relayer/broadcast.go new file mode 100644 index 000000000..42605d0e8 --- /dev/null +++ b/client/relayer/broadcast.go @@ -0,0 +1,18 @@ +package relayerclient + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" +) + +const ( + ErrTimeoutAfterWaitingForTxBroadcast _err = "timed out after waiting for tx to get included in the block" +) + +type _err string + +func (e _err) Error() string { return string(e) } + +// todo(lazar) remove this +type intoAny interface { + AsAny() *codectypes.Any +} diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go new file mode 100644 index 000000000..a6725ae99 --- /dev/null +++ b/client/relayer/chain_provider.go @@ -0,0 +1,223 @@ +package relayerclient + +import ( + "context" + "fmt" + "time" + + "github.com/cometbft/cometbft/types" + "github.com/cosmos/gogoproto/proto" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +type BroadcastMode string + +const ( + BroadcastModeSingle BroadcastMode = "single" + BroadcastModeBatch BroadcastMode = "batch" +) + +type ProviderConfig interface { + NewProvider(log *zap.Logger, homepath string, chainName string) (ChainProvider, error) + Validate() error + BroadcastMode() BroadcastMode +} + +type RelayerMessage interface { + Type() string + MsgBytes() ([]byte, error) +} + +type RelayerTxResponse struct { + Height int64 + TxHash string + Codespace string + Code uint32 + Data string + Events []RelayerEvent +} + +type RelayerEvent struct { + EventType string + Attributes map[string]string +} + +// loggableEvents is an unexported wrapper type for a slice of RelayerEvent, +// to satisfy the zapcore.ArrayMarshaler interface. +type loggableEvents []RelayerEvent + +// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface. +func (e RelayerEvent) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddString("event_type", e.EventType) + for k, v := range e.Attributes { + enc.AddString("event_attr: "+k, v) + } + return nil +} + +// MarshalLogArray satisfies the zapcore.ArrayMarshaler interface. +func (es loggableEvents) MarshalLogArray(enc zapcore.ArrayEncoder) error { + for _, e := range es { + enc.AppendObject(e) + } + return nil +} + +// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface. +func (r RelayerTxResponse) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddInt64("height", r.Height) + enc.AddString("tx_hash", r.TxHash) + enc.AddString("codespace", r.Codespace) + enc.AddUint32("code", r.Code) + enc.AddString("data", r.Data) + enc.AddArray("events", loggableEvents(r.Events)) + return nil +} + +type KeyProvider interface { + CreateKeystore(path string) error + KeystoreCreated(path string) bool + AddKey(name string, coinType uint32, signingAlgorithm string) (output *KeyOutput, err error) + UseKey(key string) error + RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) + ShowAddress(name string) (address string, err error) + ListAddresses() (map[string]string, error) + DeleteKey(name string) error + KeyExists(name string) bool + ExportPrivKeyArmor(keyName string) (armor string, err error) +} + +type ChainProvider interface { + QueryProvider + KeyProvider + + Init(ctx context.Context) error + + SendMessagesToMempool( + ctx context.Context, + msgs []RelayerMessage, + memo string, + asyncCtx context.Context, + asyncCallbacks []func(*RelayerTxResponse, error), + ) error + + ChainName() string + ChainId() string + Type() string + ProviderConfig() ProviderConfig + Key() string + Address() (string, error) + Timeout() string + WaitForNBlocks(ctx context.Context, n int64) error + Sprint(toPrint proto.Message) (string, error) + + SetRpcAddr(rpcAddr string) error +} + +type QueryProvider interface { + BlockTime(ctx context.Context, height int64) (time.Time, error) + QueryTx(ctx context.Context, hashHex string) (*RelayerTxResponse, error) + QueryTxs(ctx context.Context, page, limit int, events []string) ([]*RelayerTxResponse, error) +} + +// KeyOutput contains mnemonic and address of key +type KeyOutput struct { + Mnemonic string `json:"mnemonic" yaml:"mnemonic"` + Address string `json:"address" yaml:"address"` +} + +// TimeoutHeightError is used during packet validation to inform the PathProcessor +// that the current chain height has exceeded the packet height timeout so that +// a MsgTimeout can be assembled for the counterparty chain. +type TimeoutHeightError struct { + latestHeight uint64 + timeoutHeight uint64 +} + +func (t *TimeoutHeightError) Error() string { + return fmt.Sprintf("latest height %d is greater than expiration height: %d", t.latestHeight, t.timeoutHeight) +} + +func NewTimeoutHeightError(latestHeight, timeoutHeight uint64) *TimeoutHeightError { + return &TimeoutHeightError{latestHeight, timeoutHeight} +} + +// TimeoutTimestampError is used during packet validation to inform the PathProcessor +// that current block timestamp has exceeded the packet timestamp timeout so that +// a MsgTimeout can be assembled for the counterparty chain. +type TimeoutTimestampError struct { + latestTimestamp uint64 + timeoutTimestamp uint64 +} + +func (t *TimeoutTimestampError) Error() string { + return fmt.Sprintf("latest block timestamp %d is greater than expiration timestamp: %d", t.latestTimestamp, t.timeoutTimestamp) +} + +func NewTimeoutTimestampError(latestTimestamp, timeoutTimestamp uint64) *TimeoutTimestampError { + return &TimeoutTimestampError{latestTimestamp, timeoutTimestamp} +} + +type TimeoutOnCloseError struct { + msg string +} + +func (t *TimeoutOnCloseError) Error() string { + return fmt.Sprintf("packet timeout on close error: %s", t.msg) +} + +func NewTimeoutOnCloseError(msg string) *TimeoutOnCloseError { + return &TimeoutOnCloseError{msg} +} + +type TendermintIBCHeader struct { + SignedHeader *types.SignedHeader + ValidatorSet *types.ValidatorSet + TrustedValidators *types.ValidatorSet + TrustedHeight clienttypes.Height +} + +func (h TendermintIBCHeader) Height() uint64 { + return uint64(h.SignedHeader.Height) +} + +func (h TendermintIBCHeader) ConsensusState() ibcexported.ConsensusState { + return &tendermint.ConsensusState{ + Timestamp: h.SignedHeader.Time, + Root: commitmenttypes.NewMerkleRoot(h.SignedHeader.AppHash), + NextValidatorsHash: h.SignedHeader.NextValidatorsHash, + } +} + +func (h TendermintIBCHeader) NextValidatorsHash() []byte { + return h.SignedHeader.NextValidatorsHash +} + +func (h TendermintIBCHeader) TMHeader() (*tendermint.Header, error) { + valSet, err := h.ValidatorSet.ToProto() + if err != nil { + return nil, err + } + + trustedVals, err := h.TrustedValidators.ToProto() + if err != nil { + return nil, err + } + + return &tendermint.Header{ + SignedHeader: h.SignedHeader.ToProto(), + ValidatorSet: valSet, + TrustedHeight: h.TrustedHeight, + TrustedValidators: trustedVals, + }, nil +} + +type ExtensionOption struct { + Type string `json:"type"` + Value string `json:"value"` +} diff --git a/client/relayer/client_wrapper.go b/client/relayer/client_wrapper.go new file mode 100644 index 000000000..d350cebc4 --- /dev/null +++ b/client/relayer/client_wrapper.go @@ -0,0 +1,580 @@ +package relayerclient + +import ( + "context" + + "github.com/cometbft/cometbft/abci/types" + cometcrypto "github.com/cometbft/cometbft/crypto" + ced25519 "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/cometbft/cometbft/crypto/merkle" + csecp256k1 "github.com/cometbft/cometbft/crypto/secp256k1" + csr25519 "github.com/cometbft/cometbft/crypto/sr25519" + "github.com/cometbft/cometbft/libs/bytes" + "github.com/cometbft/cometbft/p2p" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + rpcclient "github.com/cometbft/cometbft/rpc/client" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sltypes "github.com/strangelove-ventures/cometbft-client/abci/types" + "github.com/strangelove-ventures/cometbft-client/client" + slcrypto "github.com/strangelove-ventures/cometbft-client/crypto" + "github.com/strangelove-ventures/cometbft-client/crypto/ed25519" + "github.com/strangelove-ventures/cometbft-client/crypto/secp256k1" + "github.com/strangelove-ventures/cometbft-client/crypto/sr25519" + slbytes "github.com/strangelove-ventures/cometbft-client/libs/bytes" + slclient "github.com/strangelove-ventures/cometbft-client/rpc/client" + coretypes2 "github.com/strangelove-ventures/cometbft-client/rpc/core/types" + types2 "github.com/strangelove-ventures/cometbft-client/types" +) + +// RPCClient wraps our slimmed down CometBFT client and converts the returned types to the upstream CometBFT types. +// This is useful so that it can be used in any function calls that expect the upstream types. +type RPCClient struct { + c *client.Client +} + +func NewRPCClient(c *client.Client) RPCClient { + return RPCClient{c: c} +} + +func (r RPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { + res, err := r.c.ABCIInfo(ctx) + if err != nil { + return nil, err + } + + return &coretypes.ResultABCIInfo{ + Response: types.ResponseInfo{ + Data: res.Response.Data, + Version: res.Response.Version, + AppVersion: res.Response.AppVersion, + LastBlockHeight: res.Response.LastBlockHeight, + LastBlockAppHash: res.Response.LastBlockAppHash, + }, + }, nil +} + +func (r RPCClient) ABCIQuery( + ctx context.Context, + path string, + data bytes.HexBytes, +) (*coretypes.ResultABCIQuery, error) { + res, err := r.c.ABCIQuery(ctx, path, slbytes.HexBytes(data)) + if err != nil { + return nil, err + } + + return convertResultABCIQuery(res), nil +} + +func (r RPCClient) ABCIQueryWithOptions( + ctx context.Context, + path string, + data bytes.HexBytes, + opts rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + o := slclient.ABCIQueryOptions{ + Height: opts.Height, + Prove: opts.Prove, + } + + res, err := r.c.ABCIQueryWithOptions(ctx, path, slbytes.HexBytes(data), o) + if err != nil { + return nil, err + } + + return convertResultABCIQuery(res), nil +} + +func (r RPCClient) BroadcastTxCommit(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + res, err := r.c.BroadcastTxCommit(ctx, types2.Tx(tx)) + if err != nil { + return nil, err + } + + return &coretypes.ResultBroadcastTxCommit{ + CheckTx: types.ResponseCheckTx{ + Code: res.CheckTx.Code, + Data: res.CheckTx.Data, + Log: res.CheckTx.Log, + Info: res.CheckTx.Info, + GasWanted: res.CheckTx.GasWanted, + GasUsed: res.CheckTx.GasUsed, + Events: convertEvents(res.CheckTx.Events), + Codespace: res.CheckTx.Codespace, + }, + TxResult: types.ExecTxResult{ + Code: res.TxResult.Code, + Data: res.TxResult.Data, + Log: res.TxResult.Log, + Info: res.TxResult.Info, + GasWanted: res.TxResult.GasWanted, + GasUsed: res.TxResult.GasUsed, + Events: convertEvents(res.TxResult.Events), + Codespace: res.TxResult.Codespace, + }, + Hash: bytes.HexBytes(res.Hash), + Height: res.Height, + }, nil +} + +func (r RPCClient) BroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { + res, err := r.c.BroadcastTxAsync(ctx, types2.Tx(tx)) + if err != nil { + return nil, err + } + + return &coretypes.ResultBroadcastTx{ + Code: res.Code, + Data: bytes.HexBytes(res.Data), + Log: res.Log, + Codespace: res.Codespace, + Hash: bytes.HexBytes(res.Hash), + }, nil +} + +func (r RPCClient) BroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { + res, err := r.c.BroadcastTxSync(ctx, types2.Tx(tx)) + if err != nil { + return nil, err + } + + return &coretypes.ResultBroadcastTx{ + Code: res.Code, + Data: bytes.HexBytes(res.Data), + Log: res.Log, + Codespace: res.Codespace, + Hash: bytes.HexBytes(res.Hash), + }, nil +} + +func (r RPCClient) Validators( + ctx context.Context, + height *int64, + page, perPage *int, +) (*coretypes.ResultValidators, error) { + res, err := r.c.Validators(ctx, height, page, perPage) + if err != nil { + return nil, err + } + + vals := make([]*tmtypes.Validator, len(res.Validators)) + for i, val := range res.Validators { + vals[i] = &tmtypes.Validator{ + Address: tmtypes.Address(val.Address), + PubKey: convertPubKey(val.PubKey), + VotingPower: val.VotingPower, + ProposerPriority: val.ProposerPriority, + } + } + + return &coretypes.ResultValidators{ + BlockHeight: res.BlockHeight, + Validators: vals, + Count: res.Count, + Total: res.Total, + }, nil +} + +func (r RPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { + res, err := r.c.Status(ctx) + if err != nil { + return nil, err + } + + return &coretypes.ResultStatus{ + NodeInfo: p2p.DefaultNodeInfo{ + ProtocolVersion: p2p.ProtocolVersion{ + P2P: res.NodeInfo.ProtocolVersion.P2P, + Block: res.NodeInfo.ProtocolVersion.Block, + App: res.NodeInfo.ProtocolVersion.App, + }, + DefaultNodeID: p2p.ID(res.NodeInfo.DefaultNodeID), + ListenAddr: res.NodeInfo.ListenAddr, + Network: res.NodeInfo.Network, + Version: res.NodeInfo.Version, + Channels: bytes.HexBytes(res.NodeInfo.Channels), + Moniker: res.NodeInfo.Moniker, + Other: p2p.DefaultNodeInfoOther{ + TxIndex: res.NodeInfo.Other.TxIndex, + RPCAddress: res.NodeInfo.Other.RPCAddress, + }, + }, + SyncInfo: coretypes.SyncInfo{ + LatestBlockHash: bytes.HexBytes(res.SyncInfo.LatestBlockHash), + LatestAppHash: bytes.HexBytes(res.SyncInfo.LatestAppHash), + LatestBlockHeight: res.SyncInfo.LatestBlockHeight, + LatestBlockTime: res.SyncInfo.LatestBlockTime, + EarliestBlockHash: bytes.HexBytes(res.SyncInfo.EarliestBlockHash), + EarliestAppHash: bytes.HexBytes(res.SyncInfo.EarliestAppHash), + EarliestBlockHeight: res.SyncInfo.EarliestBlockHeight, + EarliestBlockTime: res.SyncInfo.EarliestBlockTime, + CatchingUp: res.SyncInfo.CatchingUp, + }, + ValidatorInfo: coretypes.ValidatorInfo{ + Address: bytes.HexBytes(res.ValidatorInfo.Address), + PubKey: convertPubKey(res.ValidatorInfo.PubKey), + VotingPower: res.ValidatorInfo.VotingPower, + }, + }, nil +} + +func (r RPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { + res, err := r.c.Block(ctx, height) + if err != nil { + return nil, err + } + + return &coretypes.ResultBlock{ + BlockID: convertBlockID(res.BlockID), + Block: convertBlock(res.Block), + }, nil +} + +func (r RPCClient) BlockByHash(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) { + res, err := r.c.BlockByHash(ctx, hash) + if err != nil { + return nil, err + } + + return &coretypes.ResultBlock{ + BlockID: convertBlockID(res.BlockID), + Block: convertBlock(res.Block), + }, nil +} + +func (r RPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { + res, err := r.c.BlockResults(ctx, height) + if err != nil { + return nil, err + } + + txs := make([]*types.ExecTxResult, len(res.TxResponses)) + for i, tx := range res.TxResponses { + txs[i] = &types.ExecTxResult{ + Code: tx.Code, + Data: tx.Data, + Log: tx.Log, + Info: tx.Info, + GasWanted: tx.GasWanted, + GasUsed: tx.GasUsed, + Events: converStringEvents(tx.Events), + Codespace: tx.Codespace, + } + } + + return &coretypes.ResultBlockResults{ + Height: res.Height, + TxsResults: txs, + FinalizeBlockEvents: converStringEvents(res.Events), + ValidatorUpdates: nil, + ConsensusParamUpdates: nil, + AppHash: res.AppHash, + }, nil +} + +func (r RPCClient) BlockchainInfo( + ctx context.Context, + minHeight, maxHeight int64, +) (*coretypes.ResultBlockchainInfo, error) { + res, err := r.c.BlockchainInfo(ctx, minHeight, maxHeight) + if err != nil { + return nil, err + } + + meta := make([]*tmtypes.BlockMeta, len(res.BlockMetas)) + for i, m := range res.BlockMetas { + meta[i] = &tmtypes.BlockMeta{ + BlockID: tmtypes.BlockID{ + Hash: bytes.HexBytes(m.BlockID.Hash), + PartSetHeader: tmtypes.PartSetHeader{ + Total: m.BlockID.PartSetHeader.Total, + Hash: bytes.HexBytes(m.BlockID.PartSetHeader.Hash), + }, + }, + BlockSize: m.BlockSize, + Header: convertHeader(m.Header), + NumTxs: m.NumTxs, + } + } + + return &coretypes.ResultBlockchainInfo{ + LastHeight: res.LastHeight, + BlockMetas: meta, + }, nil +} + +func (r RPCClient) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { + res, err := r.c.Commit(ctx, height) + if err != nil { + return nil, err + } + + signatures := make([]tmtypes.CommitSig, len(res.Commit.Signatures)) + for i, sig := range res.Commit.Signatures { + signatures[i] = tmtypes.CommitSig{ + BlockIDFlag: tmtypes.BlockIDFlag(sig.BlockIDFlag), + ValidatorAddress: tmtypes.Address(sig.ValidatorAddress), + Timestamp: sig.Timestamp, + Signature: sig.Signature, + } + } + + header := convertHeader(*res.SignedHeader.Header) + return &coretypes.ResultCommit{ + SignedHeader: tmtypes.SignedHeader{ + Header: &header, + Commit: &tmtypes.Commit{ + Height: res.Commit.Height, + Round: res.Commit.Round, + BlockID: convertBlockID(res.Commit.BlockID), + Signatures: signatures, + }, + }, + CanonicalCommit: res.CanonicalCommit, + }, nil +} + +func (r RPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { + res, err := r.c.Tx(ctx, hash, prove) + if err != nil { + return nil, err + } + + return convertResultTx(res), nil +} + +func (r RPCClient) TxSearch( + ctx context.Context, + query string, + prove bool, + page, perPage *int, + orderBy string, +) (*coretypes.ResultTxSearch, error) { + res, err := r.c.TxSearch(ctx, query, prove, page, perPage, orderBy) + if err != nil { + return nil, err + } + + txs := make([]*coretypes.ResultTx, len(res)) + for i, tx := range res { + txs[i] = convertResultTx(tx) + } + + return &coretypes.ResultTxSearch{ + Txs: txs, + TotalCount: len(txs), + }, nil +} + +func (r RPCClient) BlockSearch( + ctx context.Context, + query string, + page, perPage *int, + orderBy string, +) (*coretypes.ResultBlockSearch, error) { + res, err := r.c.BlockSearch(ctx, query, page, perPage, orderBy) + if err != nil { + return nil, err + } + + blocks := make([]*coretypes.ResultBlock, len(res.Blocks)) + for i, block := range res.Blocks { + blocks[i] = &coretypes.ResultBlock{ + BlockID: convertBlockID(block.BlockID), + Block: convertBlock(block.Block), + } + } + + return &coretypes.ResultBlockSearch{ + Blocks: blocks, + TotalCount: res.TotalCount, + }, nil +} + +func convertProofOps(proofOps *sltypes.ProofOps) *crypto.ProofOps { + ops := make([]crypto.ProofOp, len(proofOps.Ops)) + for i, op := range proofOps.Ops { + ops[i] = crypto.ProofOp{ + Type: op.Type, + Key: op.Key, + Data: op.Data, + } + } + + return &crypto.ProofOps{Ops: ops} +} + +func convertEvents(events []sltypes.Event) []types.Event { + evts := make([]types.Event, len(events)) + + for i, evt := range events { + attributes := make([]types.EventAttribute, len(evt.Attributes)) + + for j, attr := range evt.Attributes { + attributes[j] = types.EventAttribute{ + Key: attr.Key, + Value: attr.Value, + Index: attr.Index, + } + } + + evts[i] = types.Event{ + Type: evt.Type, + Attributes: attributes, + } + } + + return evts +} + +func converStringEvents(events sdk.StringEvents) []types.Event { + evts := make([]types.Event, len(events)) + + for i, evt := range events { + attributes := make([]types.EventAttribute, len(evt.Attributes)) + + for j, attr := range evt.Attributes { + attributes[j] = types.EventAttribute{ + Key: attr.Key, + Value: attr.Value, + } + } + + evts[i] = types.Event{ + Type: evt.Type, + Attributes: attributes, + } + } + + return evts +} + +func convertHeader(header types2.Header) tmtypes.Header { + return tmtypes.Header{ + ChainID: header.ChainID, + Height: header.Height, + Time: header.Time, + LastBlockID: tmtypes.BlockID{ + Hash: bytes.HexBytes(header.LastBlockID.Hash), + PartSetHeader: tmtypes.PartSetHeader{ + Total: header.LastBlockID.PartSetHeader.Total, + Hash: bytes.HexBytes(header.LastBlockID.PartSetHeader.Hash), + }, + }, + LastCommitHash: bytes.HexBytes(header.LastCommitHash), + DataHash: bytes.HexBytes(header.DataHash), + ValidatorsHash: bytes.HexBytes(header.ValidatorsHash), + NextValidatorsHash: bytes.HexBytes(header.NextValidatorsHash), + ConsensusHash: bytes.HexBytes(header.ConsensusHash), + AppHash: bytes.HexBytes(header.AppHash), + LastResultsHash: bytes.HexBytes(header.LastResultsHash), + EvidenceHash: bytes.HexBytes(header.EvidenceHash), + ProposerAddress: tmtypes.Address(header.ProposerAddress), + } +} + +func convertBlockID(id types2.BlockID) tmtypes.BlockID { + return tmtypes.BlockID{ + Hash: bytes.HexBytes(id.Hash), + PartSetHeader: tmtypes.PartSetHeader{ + Total: id.PartSetHeader.Total, + Hash: bytes.HexBytes(id.PartSetHeader.Hash), + }, + } +} + +func convertBlock(block *types2.Block) *tmtypes.Block { + signatures := make([]tmtypes.CommitSig, len(block.LastCommit.Signatures)) + for i, sig := range block.LastCommit.Signatures { + signatures[i] = tmtypes.CommitSig{ + BlockIDFlag: tmtypes.BlockIDFlag(sig.BlockIDFlag), + ValidatorAddress: tmtypes.Address(sig.ValidatorAddress), + Timestamp: sig.Timestamp, + Signature: sig.Signature, + } + } + + txs := make([]tmtypes.Tx, len(block.Data.Txs)) + for i, tx := range block.Data.Txs { + txs[i] = tmtypes.Tx(tx) + } + + return &tmtypes.Block{ + Header: convertHeader(block.Header), + Data: tmtypes.Data{ + Txs: txs, + }, + Evidence: tmtypes.EvidenceData{}, + LastCommit: &tmtypes.Commit{ + Height: block.LastCommit.Height, + Round: block.LastCommit.Round, + BlockID: convertBlockID(block.LastCommit.BlockID), + Signatures: signatures, + }, + } +} + +func convertResultABCIQuery(res *coretypes2.ResultABCIQuery) *coretypes.ResultABCIQuery { + var ops *crypto.ProofOps + if res.Response.ProofOps != nil { + ops = convertProofOps(res.Response.ProofOps) + } + + return &coretypes.ResultABCIQuery{ + Response: types.ResponseQuery{ + Code: res.Response.Code, + Log: res.Response.Log, + Info: res.Response.Info, + Index: res.Response.Index, + Key: res.Response.Key, + Value: res.Response.Value, + ProofOps: ops, + Height: res.Response.Height, + Codespace: res.Response.Codespace, + }, + } +} + +func convertResultTx(res *client.TxResponse) *coretypes.ResultTx { + return &coretypes.ResultTx{ + Hash: bytes.HexBytes(res.Hash), + Height: res.Height, + Index: res.Index, + TxResult: types.ExecTxResult{ + Code: res.ExecTx.Code, + Data: res.ExecTx.Data, + Log: res.ExecTx.Log, + Info: res.ExecTx.Info, + GasWanted: res.ExecTx.GasWanted, + GasUsed: res.ExecTx.GasUsed, + Events: converStringEvents(res.ExecTx.Events), + Codespace: res.ExecTx.Codespace, + }, + Tx: tmtypes.Tx(res.Tx), + Proof: tmtypes.TxProof{ + RootHash: bytes.HexBytes(res.Proof.RootHash), + Data: tmtypes.Tx(res.Proof.Data), + Proof: merkle.Proof{ + Total: res.Proof.Proof.Total, + Index: res.Proof.Proof.Index, + LeafHash: res.Proof.Proof.LeafHash, + Aunts: res.Proof.Proof.Aunts, + }, + }, + } +} + +func convertPubKey(pk slcrypto.PubKey) cometcrypto.PubKey { + switch key := pk.(type) { + case ed25519.PubKey: + return ced25519.PubKey(key) + case secp256k1.PubKey: + return csecp256k1.PubKey(key) + case sr25519.PubKey: + return csr25519.PubKey(key) + default: + return nil + } +} diff --git a/client/relayer/codec.go b/client/relayer/codec.go new file mode 100644 index 000000000..60ffc2eb5 --- /dev/null +++ b/client/relayer/codec.go @@ -0,0 +1,117 @@ +package relayerclient + +import ( + feegrant "cosmossdk.io/x/feegrant/module" + "cosmossdk.io/x/tx/signing" + "cosmossdk.io/x/upgrade" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + authz "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/crisis" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + "github.com/cosmos/cosmos-sdk/x/slashing" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/ibc-go/modules/capability" + ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer" + ibc "github.com/cosmos/ibc-go/v8/modules/core" + + cosmosmodule "github.com/cosmos/relayer/v2/relayer/chains/cosmos/module" + "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" + ethermintcodecs "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" + injectivecodecs "github.com/cosmos/relayer/v2/relayer/codecs/injective" +) + +var ModuleBasics = []module.AppModuleBasic{ + auth.AppModuleBasic{}, + authz.AppModuleBasic{}, + bank.AppModuleBasic{}, + capability.AppModuleBasic{}, + // TODO: add osmosis governance proposal types here + // TODO: add other proposal types here + gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + }, + ), + crisis.AppModuleBasic{}, + distribution.AppModuleBasic{}, + feegrant.AppModuleBasic{}, + mint.AppModuleBasic{}, + params.AppModuleBasic{}, + slashing.AppModuleBasic{}, + staking.AppModuleBasic{}, + upgrade.AppModuleBasic{}, + transfer.AppModuleBasic{}, + ibc.AppModuleBasic{}, + cosmosmodule.AppModuleBasic{}, + stride.AppModuleBasic{}, + ibcfee.AppModuleBasic{}, +} + +type Codec struct { + InterfaceRegistry types.InterfaceRegistry + Marshaler codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino +} + +func MakeCodec(moduleBasics []module.AppModuleBasic, extraCodecs []string, accBech32Prefix, valBech32Prefix string) Codec { + modBasic := module.NewBasicManager(moduleBasics...) + encodingConfig := MakeCodecConfig(accBech32Prefix, valBech32Prefix) + std.RegisterLegacyAminoCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + modBasic.RegisterLegacyAminoCodec(encodingConfig.Amino) + modBasic.RegisterInterfaces(encodingConfig.InterfaceRegistry) + for _, c := range extraCodecs { + switch c { + case "ethermint": + ethermintcodecs.RegisterInterfaces(encodingConfig.InterfaceRegistry) + encodingConfig.Amino.RegisterConcrete(ðermintcodecs.PubKey{}, ethermintcodecs.PubKeyName, nil) + encodingConfig.Amino.RegisterConcrete(ðermintcodecs.PrivKey{}, ethermintcodecs.PrivKeyName, nil) + case "injective": + injectivecodecs.RegisterInterfaces(encodingConfig.InterfaceRegistry) + encodingConfig.Amino.RegisterConcrete(&injectivecodecs.PubKey{}, injectivecodecs.PubKeyName, nil) + encodingConfig.Amino.RegisterConcrete(&injectivecodecs.PrivKey{}, injectivecodecs.PrivKeyName, nil) + } + } + + return encodingConfig +} + +func MakeCodecConfig(accBech32Prefix, valBech32Prefix string) Codec { + interfaceRegistry, err := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ + ProtoFiles: proto.HybridResolver, + SigningOptions: signing.Options{ + AddressCodec: address.NewBech32Codec(accBech32Prefix), + ValidatorAddressCodec: address.NewBech32Codec(valBech32Prefix), + }, + }) + if err != nil { + panic(err) + } + marshaler := codec.NewProtoCodec(interfaceRegistry) + + done := SetSDKConfigContext(accBech32Prefix) + defer done() + + return Codec{ + InterfaceRegistry: interfaceRegistry, + Marshaler: marshaler, + TxConfig: tx.NewTxConfig(marshaler, tx.DefaultSignModes), + Amino: codec.NewLegacyAmino(), + } +} diff --git a/client/relayer/feegrant.go b/client/relayer/feegrant.go new file mode 100644 index 000000000..758bea17b --- /dev/null +++ b/client/relayer/feegrant.go @@ -0,0 +1,37 @@ +package relayerclient + +// GetTxFeeGrant Get the feegrant params to use for the next TX. If feegrants are not configured for the chain client, the default key will be used for TX signing. +// Otherwise, a configured feegrantee will be chosen for TX signing in round-robin fashion. +func (cc *CosmosProvider) GetTxFeeGrant() (txSignerKey string, feeGranterKeyOrAddr string) { + // By default, we should sign TXs with the ChainClient's default key + txSignerKey = cc.PCfg.Key + + if cc.PCfg.FeeGrants == nil { + return + } + + // Use the ChainClient's configured Feegranter key for the next TX. + feeGranterKeyOrAddr = cc.PCfg.FeeGrants.GranterKeyOrAddr + + // The ChainClient Feegrant configuration has never been verified on chain. + // Don't use Feegrants as it could cause the TX to fail on chain. + if feeGranterKeyOrAddr == "" || cc.PCfg.FeeGrants.BlockHeightVerified <= 0 { + feeGranterKeyOrAddr = "" + return + } + + // Pick the next managed grantee in the list as the TX signer + lastGranteeIdx := cc.PCfg.FeeGrants.GranteeLastSignerIndex + + if lastGranteeIdx >= 0 && lastGranteeIdx <= len(cc.PCfg.FeeGrants.ManagedGrantees)-1 { + txSignerKey = cc.PCfg.FeeGrants.ManagedGrantees[lastGranteeIdx] + cc.PCfg.FeeGrants.GranteeLastSignerIndex = cc.PCfg.FeeGrants.GranteeLastSignerIndex + 1 + + // Restart the round robin at 0 if we reached the end of the list of grantees + if cc.PCfg.FeeGrants.GranteeLastSignerIndex == len(cc.PCfg.FeeGrants.ManagedGrantees) { + cc.PCfg.FeeGrants.GranteeLastSignerIndex = 0 + } + } + + return +} diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go new file mode 100644 index 000000000..3a426ab50 --- /dev/null +++ b/client/relayer/grpc_query.go @@ -0,0 +1,216 @@ +package relayerclient + +import ( + "context" + "fmt" + "reflect" + "strconv" + "sync" + "time" + + sdkerrors "cosmossdk.io/errors" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/tx" + gogogrpc "github.com/cosmos/gogoproto/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/encoding" + "google.golang.org/grpc/encoding/proto" + "google.golang.org/grpc/mem" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +var _ gogogrpc.ClientConn = &CosmosProvider{} + +var protoCodec = encoding.GetCodecV2(proto.Name) + +// Invoke implements the grpc ClientConn.Invoke method +func (cc *CosmosProvider) Invoke(ctx context.Context, method string, req, reply interface{}, opts ...grpc.CallOption) (err error) { + // Two things can happen here: + // 1. either we're broadcasting a Tx, in which call we call Tendermint's broadcast endpoint directly, + // 2. or we are querying for state, in which case we call ABCI's Querier. + + // In both cases, we don't allow empty request req (it will panic unexpectedly). + if reflect.ValueOf(req).IsNil() { + return sdkerrors.Wrap(legacyerrors.ErrInvalidRequest, "request cannot be nil") + } + + // Case 1. Broadcasting a Tx. + if reqProto, ok := req.(*tx.BroadcastTxRequest); ok { + if !ok { + return sdkerrors.Wrapf(legacyerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req) + } + resProto, ok := reply.(*tx.BroadcastTxResponse) + if !ok { + return sdkerrors.Wrapf(legacyerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), req) + } + + broadcastRes, err := cc.TxServiceBroadcast(ctx, reqProto) + if err != nil { + return err + } + *resProto = *broadcastRes + return err + } + + // Case 2. Querying state. + inMd, _ := metadata.FromOutgoingContext(ctx) + abciRes, outMd, err := cc.RunGRPCQuery(ctx, method, req, inMd) + if err != nil { + return err + } + + if err = protoCodec.Unmarshal([]mem.Buffer{mem.NewBuffer(&abciRes.Value, nil)}, reply); err != nil { + return err + } + + for _, callOpt := range opts { + header, ok := callOpt.(grpc.HeaderCallOption) + if !ok { + continue + } + + *header.HeaderAddr = outMd + } + + if cc.Cdc.InterfaceRegistry != nil { + return types.UnpackInterfaces(reply, cc.Cdc.Marshaler) + } + + return nil +} + +// NewStream implements the grpc ClientConn.NewStream method +func (cc *CosmosProvider) NewStream(context.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, fmt.Errorf("streaming rpc not supported") +} + +// RunGRPCQuery runs a gRPC query from the clientCtx, given all necessary +// arguments for the gRPC method, and returns the ABCI response. It is used +// to factorize code between client (Invoke) and server (RegisterGRPCServer) +// gRPC handlers. +func (cc *CosmosProvider) RunGRPCQuery(ctx context.Context, method string, req interface{}, md metadata.MD) (abci.ResponseQuery, metadata.MD, error) { + reqBz, err := protoCodec.Marshal(req) + if err != nil { + return abci.ResponseQuery{}, nil, err + } + + // parse height header + if heights := md.Get(grpctypes.GRPCBlockHeightHeader); len(heights) > 0 { + height, err := strconv.ParseInt(heights[0], 10, 64) + if err != nil { + return abci.ResponseQuery{}, nil, err + } + if height < 0 { + return abci.ResponseQuery{}, nil, sdkerrors.Wrapf( + legacyerrors.ErrInvalidRequest, + "client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader) + } + + } + + height, err := GetHeightFromMetadata(md) + if err != nil { + return abci.ResponseQuery{}, nil, err + } + + prove, err := GetProveFromMetadata(md) + if err != nil { + return abci.ResponseQuery{}, nil, err + } + + abciReq := abci.RequestQuery{ + Path: method, + Data: reqBz.Materialize(), + Height: height, + Prove: prove, + } + + abciRes, err := cc.QueryABCI(ctx, abciReq) + if err != nil { + return abci.ResponseQuery{}, nil, err + } + + // Create header metadata. For now the headers contain: + // - block height + // We then parse all the call options, if the call option is a + // HeaderCallOption, then we manually set the value of that header to the + // metadata. + md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(abciRes.Height, 10)) + + return abciRes, md, nil +} + +// TxServiceBroadcast is a helper function to broadcast a Tx with the correct gRPC types +// from the tx service. Calls `clientCtx.BroadcastTx` under the hood. +func (cc *CosmosProvider) TxServiceBroadcast(ctx context.Context, req *tx.BroadcastTxRequest) (*tx.BroadcastTxResponse, error) { + if req == nil || req.TxBytes == nil { + return nil, status.Error(codes.InvalidArgument, "invalid empty tx") + } + + var ( + blockTimeout = defaultBroadcastWaitTimeout + err error + rlyResp *RelayerTxResponse + callbackErr error + wg sync.WaitGroup + ) + + if cc.PCfg.BlockTimeout != "" { + blockTimeout, err = time.ParseDuration(cc.PCfg.BlockTimeout) + if err != nil { + // Did you call Validate() method on CosmosProviderConfig struct + // before coming here? + return nil, err + } + } + + callback := func(rtr *RelayerTxResponse, err error) { + rlyResp = rtr + callbackErr = err + wg.Done() + } + + wg.Add(1) + + if err := cc.broadcastTx(ctx, req.TxBytes, nil, nil, ctx, blockTimeout, []func(*RelayerTxResponse, error){callback}); err != nil { + return nil, err + } + + wg.Wait() + + if callbackErr != nil { + return nil, callbackErr + } + + return &tx.BroadcastTxResponse{ + TxResponse: &sdk.TxResponse{ + Height: rlyResp.Height, + TxHash: rlyResp.TxHash, + Codespace: rlyResp.Codespace, + Code: rlyResp.Code, + Data: rlyResp.Data, + }, + }, nil +} + +func GetHeightFromMetadata(md metadata.MD) (int64, error) { + height := md.Get(grpctypes.GRPCBlockHeightHeader) + if len(height) == 1 { + return strconv.ParseInt(height[0], 10, 64) + } + return 0, nil +} + +func GetProveFromMetadata(md metadata.MD) (bool, error) { + prove := md.Get("x-cosmos-query-prove") + if len(prove) == 1 { + return strconv.ParseBool(prove[0]) + } + return false, nil +} diff --git a/client/relayer/keys.go b/client/relayer/keys.go new file mode 100644 index 000000000..2f92df685 --- /dev/null +++ b/client/relayer/keys.go @@ -0,0 +1,266 @@ +package relayerclient + +import ( + "errors" + "os" + + ckeys "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" + "github.com/cosmos/relayer/v2/relayer/chains/cosmos/keys/sr25519" + "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" + "github.com/cosmos/relayer/v2/relayer/codecs/injective" +) + +const ethereumCoinType = uint32(60) + +var ( + // SupportedAlgorithms defines the list of signing algorithms used on Evmos: + // - secp256k1 (Cosmos) + // - sr25519 (Cosmos) + // - eth_secp256k1 (Ethereum, Injective) + SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} + // SupportedAlgorithmsLedger defines the list of signing algorithms used on Evmos for the Ledger device: + // - secp256k1 (Cosmos) + // - sr25519 (Cosmos) + // - eth_secp256k1 (Ethereum, Injective) + SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} +) + +// KeyringAlgoOptions defines a function keys options for the ethereum Secp256k1 curve. +// It supports secp256k1 and eth_secp256k1 keys for accounts. +func KeyringAlgoOptions() keyring.Option { + return func(options *keyring.Options) { + options.SupportedAlgos = SupportedAlgorithms + options.SupportedAlgosLedger = SupportedAlgorithmsLedger + } +} + +// CreateKeystore initializes a new instance of a keyring at the specified path in the local filesystem. +func (cc *CosmosProvider) CreateKeystore(path string) error { + keybase, err := keyring.New(cc.PCfg.ChainID, cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, cc.Cdc.Marshaler, KeyringAlgoOptions()) + if err != nil { + return err + } + cc.Keybase = keybase + return nil +} + +// KeystoreCreated returns true if there is an existing keystore instance at the specified path, it returns false otherwise. +func (cc *CosmosProvider) KeystoreCreated(path string) bool { + if _, err := os.Stat(cc.PCfg.KeyDirectory); errors.Is(err, os.ErrNotExist) { + return false + } else if cc.Keybase == nil { + return false + } + return true +} + +// AddKey generates a new mnemonic which is then converted to a private key and BIP-39 HD Path and persists it to the keystore. +// It fails if there is an existing key with the same address. +func (cc *CosmosProvider) AddKey(name string, coinType uint32, signingAlgorithm string) (output *KeyOutput, err error) { + ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm) + if err != nil { + return nil, err + } + return ko, nil +} + +// UseKey Updates config.yaml chain with the specified key. +// It fails config is already using the same key or if the key does not exist +func (cc *CosmosProvider) UseKey(key string) error { + cc.PCfg.Key = key + return nil +} + +// RestoreKey converts a mnemonic to a private key and BIP-39 HD Path and persists it to the keystore. +// It fails if there is an existing key with the same address. +func (cc *CosmosProvider) RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) { + ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm, mnemonic) + if err != nil { + return "", err + } + return ko.Address, nil +} + +// KeyAddOrRestore either generates a new mnemonic or uses the specified mnemonic and converts it to a private key +// and BIP-39 HD Path which is then persisted to the keystore. It fails if there is an existing key with the same address. +func (cc *CosmosProvider) KeyAddOrRestore(keyName string, coinType uint32, signingAlgorithm string, mnemonic ...string) (*KeyOutput, error) { + var mnemonicStr string + var err error + + var algo keyring.SignatureAlgo + switch signingAlgorithm { + case string(hd.Sr25519Type): + algo = sr25519.Sr25519 + default: + algo = hd.Secp256k1 + } + + if len(mnemonic) > 0 { + mnemonicStr = mnemonic[0] + } else { + mnemonicStr, err = CreateMnemonic() + if err != nil { + return nil, err + } + } + + if coinType == ethereumCoinType { + algo = keyring.SignatureAlgo(ethermint.EthSecp256k1) + for _, codec := range cc.PCfg.ExtraCodecs { + if codec == "injective" { + algo = keyring.SignatureAlgo(injective.EthSecp256k1) + } + } + } + + done := SetSDKConfigContext(cc.PCfg.AccountPrefix) + + info, err := cc.Keybase.NewAccount(keyName, mnemonicStr, "", hd.CreateHDPath(coinType, 0, 0).String(), algo) + if err != nil { + return nil, err + } + + done() + + acc, err := info.GetAddress() + if err != nil { + return nil, err + } + + out, err := cc.EncodeBech32AccAddr(acc) + if err != nil { + return nil, err + } + return &KeyOutput{Mnemonic: mnemonicStr, Address: out}, nil +} + +// ShowAddress retrieves a key by name from the keystore and returns the bech32 encoded string representation of that key. +func (cc *CosmosProvider) ShowAddress(name string) (address string, err error) { + info, err := cc.Keybase.Key(name) + if err != nil { + return "", err + } + acc, err := info.GetAddress() + if err != nil { + return "", nil + } + out, err := cc.EncodeBech32AccAddr(acc) + if err != nil { + return "", err + } + return out, nil +} + +// ListAddresses returns a map of bech32 encoded strings representing all keys currently in the keystore. +func (cc *CosmosProvider) ListAddresses() (map[string]string, error) { + out := map[string]string{} + info, err := cc.Keybase.List() + if err != nil { + return nil, err + } + for _, k := range info { + acc, err := k.GetAddress() + if err != nil { + return nil, err + } + addr, err := cc.EncodeBech32AccAddr(acc) + if err != nil { + return nil, err + } + out[k.Name] = addr + } + return out, nil +} + +// DeleteKey removes a key from the keystore for the specified name. +func (cc *CosmosProvider) DeleteKey(name string) error { + if err := cc.Keybase.Delete(name); err != nil { + return err + } + return nil +} + +// KeyExists returns true if a key with the specified name exists in the keystore, it returns false otherwise. +func (cc *CosmosProvider) KeyExists(name string) bool { + k, err := cc.Keybase.Key(name) + if err != nil { + return false + } + + return k.Name == name + +} + +// ExportPrivKeyArmor returns a private key in ASCII armored format. +// It returns an error if the key does not exist or a wrong encryption passphrase is supplied. +func (cc *CosmosProvider) ExportPrivKeyArmor(keyName string) (armor string, err error) { + return cc.Keybase.ExportPrivKeyArmor(keyName, ckeys.DefaultKeyPass) +} + +// GetKeyAddress returns the account address representation for the currently configured key. +func (cc *CosmosProvider) GetKeyAddress(key string) (sdk.AccAddress, error) { + info, err := cc.Keybase.Key(key) + if err != nil { + return nil, err + } + return info.GetAddress() +} + +// CreateMnemonic generates a new mnemonic. +func CreateMnemonic() (string, error) { + entropySeed, err := bip39.NewEntropy(256) + if err != nil { + return "", err + } + mnemonic, err := bip39.NewMnemonic(entropySeed) + if err != nil { + return "", err + } + return mnemonic, nil +} + +// EncodeBech32AccAddr returns the string bech32 representation for the specified account address. +// It returns an empty sting if the byte slice is 0-length. +// It returns an error if the bech32 conversion fails or the prefix is empty. +func (cc *CosmosProvider) EncodeBech32AccAddr(addr sdk.AccAddress) (string, error) { + return sdk.Bech32ifyAddressBytes(cc.PCfg.AccountPrefix, addr) +} + +func (cc *CosmosProvider) DecodeBech32AccAddr(addr string) (sdk.AccAddress, error) { + return sdk.GetFromBech32(addr, cc.PCfg.AccountPrefix) +} + +func (cc *CosmosProvider) GetKeyAddressForKey(key string) (sdk.AccAddress, error) { + info, err := cc.Keybase.Key(key) + if err != nil { + return nil, err + } + return info.GetAddress() +} + +func (cc *CosmosProvider) KeyFromKeyOrAddress(keyOrAddress string) (string, error) { + switch { + case keyOrAddress == "": + return cc.PCfg.Key, nil + case cc.KeyExists(keyOrAddress): + return keyOrAddress, nil + default: + acc, err := cc.DecodeBech32AccAddr(keyOrAddress) + if err != nil { + return "", err + } + + done := SetSDKConfigContext(cc.PCfg.AccountPrefix) + defer done() + + kr, err := cc.Keybase.KeyByAddress(acc) + if err != nil { + return "", err + } + return kr.Name, nil + } +} diff --git a/client/relayer/log.go b/client/relayer/log.go new file mode 100644 index 000000000..12483e1f8 --- /dev/null +++ b/client/relayer/log.go @@ -0,0 +1,189 @@ +package relayerclient + +import ( + "errors" + "reflect" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + typestx "github.com/cosmos/cosmos-sdk/types/tx" + feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// getChannelsIfPresent scans the events for channel tags +func getChannelsIfPresent(events []RelayerEvent) []zapcore.Field { + channelTags := []string{srcChanTag, dstChanTag} + var fields []zap.Field + + // While a transaction may have multiple messages, we just need to first + // a pair of channels + foundTag := map[string]struct{}{} + + for _, event := range events { + for _, tag := range channelTags { + for attributeKey, attributeValue := range event.Attributes { + if attributeKey == tag { + // Only append the tag once + // TODO: what if they are different? + if _, ok := foundTag[tag]; !ok { + fields = append(fields, zap.String(tag, attributeValue)) + foundTag[tag] = struct{}{} + } + } + } + } + } + return fields +} + +// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data +func (cc *CosmosProvider) LogFailedTx(res *RelayerTxResponse, err error, msgs []RelayerMessage) { + // Include the chain_id + fields := []zapcore.Field{zap.String("chain_id", cc.ChainId())} + + // Extract the channels from the events, if present + if res != nil { + channels := getChannelsIfPresent(res.Events) + fields = append(fields, channels...) + } + fields = append(fields, msgTypesField(msgs)) + + if err != nil { + + if errors.Is(err, chantypes.ErrRedundantTx) { + cc.log.Debug("Redundant message(s)", fields...) + return + } + + // Make a copy since we may continue to the warning + errorFields := append(fields, zap.Error(err)) + cc.log.Error( + "Failed sending cosmos transaction", + errorFields..., + ) + + if res == nil { + return + } + } + + if res.Code != 0 { + if sdkErr := cc.sdkError(res.Codespace, res.Code); err != nil { + fields = append(fields, zap.NamedError("sdk_error", sdkErr)) + } + fields = append(fields, zap.Object("response", res)) + cc.log.Warn( + "Sent transaction but received failure response", + fields..., + ) + } +} + +// LogSuccessTx take the transaction and the messages to create it and logs the appropriate data +func (cc *CosmosProvider) LogSuccessTx(res *sdk.TxResponse, msgs []RelayerMessage) { + // Include the chain_id + fields := []zapcore.Field{zap.String("chain_id", cc.ChainId())} + + // Extract the channels from the events, if present + if res != nil { + events := parseEventsFromTxResponse(res) + fields = append(fields, getChannelsIfPresent(events)...) + } + + // Include the gas used + fields = append(fields, zap.Int64("gas_used", res.GasUsed)) + + // Extract fees and fee_payer if present + cdc := codec.NewProtoCodec(cc.Cdc.InterfaceRegistry) + + var m sdk.Msg + if err := cc.Cdc.InterfaceRegistry.UnpackAny(res.Tx, &m); err == nil { + if tx, ok := m.(*typestx.Tx); ok { + fields = append(fields, zap.Stringer("fees", tx.GetFee())) + if feePayer := getFeePayer(cc.log, cdc, tx); feePayer != "" { + fields = append(fields, zap.String("fee_payer", feePayer)) + } + } else { + cc.log.Debug( + "Failed to convert message to Tx type", + zap.Stringer("type", reflect.TypeOf(m)), + ) + } + } else { + cc.log.Debug("Failed to unpack response Tx into sdk.Msg", zap.Error(err)) + } + + // Include the height, msgType, and tx_hash + fields = append(fields, + zap.Int64("height", res.Height), + msgTypesField(msgs), + zap.String("tx_hash", res.TxHash), + ) + + // Log the successful transaction with fields + cc.log.Info( + "Successful transaction", + fields..., + ) +} + +func msgTypesField(msgs []RelayerMessage) zap.Field { + msgTypes := make([]string, len(msgs)) + for i, m := range msgs { + msgTypes[i] = m.Type() + } + return zap.Strings("msg_types", msgTypes) +} + +// getFeePayer returns the bech32 address of the fee payer of a transaction. +// This uses the fee payer field if set, +// otherwise falls back to the address of whoever signed the first message. +func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string { + payer := tx.AuthInfo.Fee.Payer + if payer != "" { + return payer + } + + switch firstMsg := tx.GetMsgs()[0].(type) { + case *transfertypes.MsgTransfer: + // There is a possible data race around concurrent map access + // in the cosmos sdk when it converts the address from bech32. + // We don't need the address conversion; just the sender is all that + // GetSigners is doing under the hood anyway. + return firstMsg.Sender + case *clienttypes.MsgCreateClient: + // Without this particular special case, there is a panic in ibc-go + // due to the sdk config singleton expecting one bech32 prefix but seeing another. + return firstMsg.Signer + case *clienttypes.MsgUpdateClient: + // Same failure mode as MsgCreateClient. + return firstMsg.Signer + case *clienttypes.MsgUpgradeClient: + return firstMsg.Signer + case *clienttypes.MsgSubmitMisbehaviour: + // Same failure mode as MsgCreateClient. + return firstMsg.Signer + case *feetypes.MsgRegisterPayee: + return firstMsg.Relayer + case *feetypes.MsgRegisterCounterpartyPayee: + return firstMsg.Relayer + case *feetypes.MsgPayPacketFee: + return firstMsg.Signer + case *feetypes.MsgPayPacketFeeAsync: + return firstMsg.PacketFee.RefundAddress + default: + signers, _, err := cdc.GetMsgV1Signers(firstMsg) + if err != nil { + log.Info("Could not get signers for msg when attempting to get the fee payer", zap.Error(err)) + return "" + } + + return string(signers[0]) + } +} diff --git a/client/relayer/msg.go b/client/relayer/msg.go new file mode 100644 index 000000000..eec3259f3 --- /dev/null +++ b/client/relayer/msg.go @@ -0,0 +1,65 @@ +package relayerclient + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + "go.uber.org/zap/zapcore" +) + +type CosmosMessage struct { + Msg sdk.Msg + SetSigner func(string) //callback to update the Msg Signer field + FeegrantDisabled bool //marks whether this message type should ALWAYS disable feegranting (use the default signer) +} + +func NewCosmosMessage(msg sdk.Msg, optionalSetSigner func(string)) RelayerMessage { + return CosmosMessage{ + Msg: msg, + SetSigner: optionalSetSigner, + } +} + +func CosmosMsg(rm RelayerMessage) sdk.Msg { + if val, ok := rm.(CosmosMessage); !ok { + fmt.Printf("got data of type %T but wanted provider.CosmosMessage \n", val) + return nil + } else { + return val.Msg + } +} + +func CosmosMsgs(rm ...RelayerMessage) []sdk.Msg { + sdkMsgs := make([]sdk.Msg, 0) + for _, rMsg := range rm { + if val, ok := rMsg.(CosmosMessage); !ok { + fmt.Printf("got data of type %T but wanted CosmosMessage \n", rMsg) + return nil + } else { + sdkMsgs = append(sdkMsgs, val.Msg) + } + } + return sdkMsgs +} + +func (cm CosmosMessage) Type() string { + return sdk.MsgTypeURL(cm.Msg) +} + +func (cm CosmosMessage) MsgBytes() ([]byte, error) { + return proto.Marshal(cm.Msg) +} + +// MarshalLogObject is used to encode cm to a zap logger with the zap.Object field type. +func (cm CosmosMessage) MarshalLogObject(enc zapcore.ObjectEncoder) error { + // Using plain json.Marshal or calling cm.Msg.String() both fail miserably here. + // There is probably a better way to encode the message than this. + j, err := codec.NewLegacyAmino().MarshalJSON(cm.Msg) + if err != nil { + return err + } + enc.AddByteString("msg_json", j) + return nil +} diff --git a/client/relayer/provider.go b/client/relayer/provider.go new file mode 100644 index 000000000..596080751 --- /dev/null +++ b/client/relayer/provider.go @@ -0,0 +1,310 @@ +package relayerclient + +import ( + "context" + "fmt" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/gogoproto/proto" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" + "github.com/strangelove-ventures/cometbft-client/client" + "go.uber.org/zap" + "io" + "os" + "path" + "sync" + "time" +) + +type CosmosProviderConfig struct { + KeyDirectory string `json:"key-directory" yaml:"key-directory"` + Key string `json:"key" yaml:"key"` + ChainName string `json:"-" yaml:"-"` + ChainID string `json:"chain-id" yaml:"chain-id"` + RPCAddr string `json:"rpc-addr" yaml:"rpc-addr"` + AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` + KeyringBackend string `json:"keyring-backend" yaml:"keyring-backend"` + GasAdjustment float64 `json:"gas-adjustment" yaml:"gas-adjustment"` + GasPrices string `json:"gas-prices" yaml:"gas-prices"` + MinGasAmount uint64 `json:"min-gas-amount" yaml:"min-gas-amount"` + MaxGasAmount uint64 `json:"max-gas-amount" yaml:"max-gas-amount"` + Debug bool `json:"debug" yaml:"debug"` + Timeout string `json:"timeout" yaml:"timeout"` + BlockTimeout string `json:"block-timeout" yaml:"block-timeout"` + OutputFormat string `json:"output-format" yaml:"output-format"` + SignModeStr string `json:"sign-mode" yaml:"sign-mode"` + ExtraCodecs []string `json:"extra-codecs" yaml:"extra-codecs"` + Modules []module.AppModuleBasic `json:"-" yaml:"-"` + Slip44 *int `json:"coin-type" yaml:"coin-type"` + SigningAlgorithm string `json:"signing-algorithm" yaml:"signing-algorithm"` + Broadcast BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` + MinLoopDuration time.Duration `json:"min-loop-duration" yaml:"min-loop-duration"` + ExtensionOptions []ExtensionOption `json:"extension-options" yaml:"extension-options"` + + // If FeeGrantConfiguration is set, TXs submitted by the ChainClient will be signed by the FeeGrantees in a round-robin fashion by default. + FeeGrants *FeeGrantConfiguration `json:"feegrants" yaml:"feegrants"` +} + +// FeeGrantConfiguration By default, TXs will be signed by the feegrantees 'ManagedGrantees' keys in a round robin fashion. +// Clients can use other signing keys by invoking 'tx.SendMsgsWith' and specifying the signing key. +type FeeGrantConfiguration struct { + GranteesWanted int `json:"num_grantees" yaml:"num_grantees"` + // Normally this is the default ChainClient key + GranterKeyOrAddr string `json:"granter" yaml:"granter"` + // Whether we control the granter private key (if not, someone else must authorize our feegrants) + IsExternalGranter bool `json:"external_granter" yaml:"external_granter"` + // List of keys (by name) that this FeeGranter manages + ManagedGrantees []string `json:"grantees" yaml:"grantees"` + // Last checked on chain (0 means grants never checked and may not exist) + BlockHeightVerified int64 `json:"block_last_verified" yaml:"block_last_verified"` + // Index of the last ManagedGrantee used as a TX signer + GranteeLastSignerIndex int +} + +type CosmosProvider struct { + log *zap.Logger + + PCfg CosmosProviderConfig + Keybase keyring.Keyring + KeyringOptions []keyring.Option + RPCClient RPCClient + //LightProvider provtypes.Provider + Input io.Reader + Output io.Writer + Cdc Codec + + //nextAccountSeq uint64 + feegrantMu sync.Mutex + + // the map key is the TX signer, which can either be 'default' (provider key) or a feegrantee + // the purpose of the map is to lock on the signer from TX creation through submission, + // thus making TX sequencing errors less likely. + walletStateMap map[string]*WalletState + + // metrics to monitor the provider + TotalFees sdk.Coins + totalFeesMu sync.Mutex + + // for comet < v0.37, decode tm events as base64 todo remove this + cometLegacyEncoding bool + + // for comet < v0.38, use legacy RPC client for ResultsBlockResults todo remove this + cometLegacyBlockResults bool +} + +func (pc CosmosProviderConfig) BroadcastMode() BroadcastMode { + return pc.Broadcast +} + +type WalletState struct { + NextAccountSequence uint64 + Mu sync.Mutex +} + +// NewProvider validates the CosmosProviderConfig, instantiates a ChainClient and then instantiates a CosmosProvider +func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, chainName string) (ChainProvider, error) { + if err := pc.Validate(); err != nil { + return nil, err + } + + pc.KeyDirectory = keysDir(homepath, pc.ChainID) + + pc.ChainName = chainName + pc.Modules = append([]module.AppModuleBasic{}, ModuleBasics...) + + if pc.Broadcast == "" { + pc.Broadcast = BroadcastModeBatch + } + + cp := &CosmosProvider{ + log: log, + PCfg: pc, + KeyringOptions: []keyring.Option{ethermint.EthSecp256k1Option()}, + Input: os.Stdin, + Output: os.Stdout, + walletStateMap: map[string]*WalletState{}, + + // TODO: this is a bit of a hack, we should probably have a better way to inject modules + Cdc: MakeCodec(pc.Modules, pc.ExtraCodecs, pc.AccountPrefix, pc.AccountPrefix+"valoper"), + } + + return cp, nil +} + +func (pc CosmosProviderConfig) Validate() error { + if _, err := time.ParseDuration(pc.Timeout); err != nil { + return fmt.Errorf("invalid Timeout: %w", err) + } + return nil +} + +// keysDir returns a string representing the path on the local filesystem where the keystore will be initialized. +func keysDir(home, chainID string) string { + return path.Join(home, "keys", chainID) +} + +func (cc *CosmosProvider) ProviderConfig() ProviderConfig { + return cc.PCfg +} + +func (cc *CosmosProvider) ChainId() string { + return cc.PCfg.ChainID +} + +func (cc *CosmosProvider) ChainName() string { + return cc.PCfg.ChainName +} + +func (cc *CosmosProvider) Type() string { + return "cosmos" +} + +func (cc *CosmosProvider) Key() string { + return cc.PCfg.Key +} + +func (cc *CosmosProvider) Timeout() string { + return cc.PCfg.Timeout +} + +// CommitmentPrefix returns the commitment prefix for Cosmos +func (cc *CosmosProvider) CommitmentPrefix() commitmenttypes.MerklePrefix { + return defaultChainPrefix +} + +// Address returns the chains configured address as a string +func (cc *CosmosProvider) Address() (string, error) { + info, err := cc.Keybase.Key(cc.PCfg.Key) + if err != nil { + return "", err + } + + acc, err := info.GetAddress() + if err != nil { + return "", err + } + + out, err := cc.EncodeBech32AccAddr(acc) + if err != nil { + return "", err + } + + return out, err +} + +func (cc *CosmosProvider) MustEncodeAccAddr(addr sdk.AccAddress) string { + enc, err := cc.EncodeBech32AccAddr(addr) + if err != nil { + panic(err) + } + return enc +} + +// AccountFromKeyOrAddress returns an account from either a key or an address. +// If 'keyOrAddress' is the empty string, this returns the default key's address. +func (cc *CosmosProvider) AccountFromKeyOrAddress(keyOrAddress string) (out sdk.AccAddress, err error) { + switch { + case keyOrAddress == "": + out, err = cc.GetKeyAddress(cc.PCfg.Key) + case cc.KeyExists(keyOrAddress): + out, err = cc.GetKeyAddress(keyOrAddress) + default: + out, err = sdk.GetFromBech32(keyOrAddress, cc.PCfg.AccountPrefix) + } + return +} + +// Sprint returns the json representation of the specified proto message. +func (cc *CosmosProvider) Sprint(toPrint proto.Message) (string, error) { + out, err := cc.Cdc.Marshaler.MarshalJSON(toPrint) + if err != nil { + return "", err + } + return string(out), nil +} + +// SetPCAddr sets the rpc-addr for the chain. +// It will fail if the rpcAddr is invalid(not a url). +func (cc *CosmosProvider) SetRpcAddr(rpcAddr string) error { + cc.PCfg.RPCAddr = rpcAddr + return nil +} + +// Init initializes the keystore, RPC client, amd light client provider. +// Once initialization is complete an attempt to query the underlying node's tendermint version is performed. +// NOTE: Init must be called after creating a new instance of CosmosProvider. +func (cc *CosmosProvider) Init(ctx context.Context) error { + keybase, err := keyring.New( + cc.PCfg.ChainID, + cc.PCfg.KeyringBackend, + cc.PCfg.KeyDirectory, + cc.Input, + cc.Cdc.Marshaler, + cc.KeyringOptions..., + ) + if err != nil { + return err + } + // TODO: figure out how to deal with input or maybe just make all keyring backends test? + + timeout, err := time.ParseDuration(cc.PCfg.Timeout) + if err != nil { + return err + } + + c, err := client.NewClient(cc.PCfg.RPCAddr, timeout) + if err != nil { + return err + } + + //lightprovider, err := prov.New(cc.PCfg.ChainID, cc.PCfg.RPCAddr) todo check if needed + //if err != nil { + // return err + //} + + rpcClient := NewRPCClient(c) + + cc.RPCClient = rpcClient + //cc.LightProvider = lightprovider + cc.Keybase = keybase + + return nil +} + +// WaitForNBlocks blocks until the next block on a given chain +func (cc *CosmosProvider) WaitForNBlocks(ctx context.Context, n int64) error { + var initial int64 + h, err := cc.RPCClient.Status(ctx) + if err != nil { + return err + } + if h.SyncInfo.CatchingUp { + return fmt.Errorf("chain catching up") + } + initial = h.SyncInfo.LatestBlockHeight + for { + h, err = cc.RPCClient.Status(ctx) + if err != nil { + return err + } + if h.SyncInfo.LatestBlockHeight > initial+n { + return nil + } + select { + case <-time.After(10 * time.Millisecond): + // Nothing to do. + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func (cc *CosmosProvider) BlockTime(ctx context.Context, height int64) (time.Time, error) { + resultBlock, err := cc.RPCClient.Block(ctx, &height) + if err != nil { + return time.Time{}, err + } + return resultBlock.Block.Time, nil +} diff --git a/client/relayer/query.go b/client/relayer/query.go new file mode 100644 index 000000000..2459ef28e --- /dev/null +++ b/client/relayer/query.go @@ -0,0 +1,143 @@ +package relayerclient + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "strconv" + "strings" + "time" +) + +func (cc *CosmosProvider) queryParamsSubspaceTime(ctx context.Context, subspace string, key string) (time.Duration, error) { + queryClient := proposal.NewQueryClient(cc) + + params := proposal.QueryParamsRequest{Subspace: subspace, Key: key} + + res, err := queryClient.Params(ctx, ¶ms) + + if err != nil { + return 0, fmt.Errorf("failed to make %s params request: %w", subspace, err) + } + + if res.Param.Value == "" { + return 0, fmt.Errorf("%s %s is empty", subspace, key) + } + + unbondingValue, err := strconv.ParseUint(strings.ReplaceAll(res.Param.Value, `"`, ""), 10, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse %s from %s param: %w", key, subspace, err) + } + + return time.Duration(unbondingValue), nil +} + +// QueryUnbondingPeriod returns the unbonding period of the chain +func (cc *CosmosProvider) QueryUnbondingPeriod(ctx context.Context) (time.Duration, error) { + + // Attempt ICS query + consumerUnbondingPeriod, consumerErr := cc.queryParamsSubspaceTime(ctx, "ccvconsumer", "UnbondingPeriod") + if consumerErr == nil { + return consumerUnbondingPeriod, nil + } + + //Attempt Staking query. + unbondingPeriod, stakingParamsErr := cc.queryParamsSubspaceTime(ctx, "staking", "UnbondingTime") + if stakingParamsErr == nil { + return unbondingPeriod, nil + } + + // Fallback + req := stakingtypes.QueryParamsRequest{} + queryClient := stakingtypes.NewQueryClient(cc) + res, err := queryClient.Params(ctx, &req) + if err == nil { + return res.Params.UnbondingTime, nil + + } + + return 0, + fmt.Errorf("failed to query unbonding period from ccvconsumer, staking & fallback : %w: %s : %s", consumerErr, stakingParamsErr.Error(), err.Error()) +} + +// QueryTx takes a transaction hash and returns the transaction +func (cc *CosmosProvider) QueryTx(ctx context.Context, hashHex string) (*RelayerTxResponse, error) { + hash, err := hex.DecodeString(hashHex) + if err != nil { + return nil, err + } + + resp, err := cc.RPCClient.Tx(ctx, hash, true) + if err != nil { + return nil, err + } + + events := parseEventsFromResponseDeliverTx(resp.TxResult.Events) + + return &RelayerTxResponse{ + Height: resp.Height, + TxHash: string(hash), + Code: resp.TxResult.Code, + Data: string(resp.TxResult.Data), + Events: events, + }, nil +} + +// QueryTxs returns an array of transactions given a tag +func (cc *CosmosProvider) QueryTxs(ctx context.Context, page, limit int, events []string) ([]*RelayerTxResponse, error) { + if len(events) == 0 { + return nil, errors.New("must declare at least one event to search") + } + + if page <= 0 { + return nil, errors.New("page must greater than 0") + } + + if limit <= 0 { + return nil, errors.New("limit must greater than 0") + } + + res, err := cc.RPCClient.TxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") + if err != nil { + return nil, err + } + + // Currently, we only call QueryTxs() in two spots and in both of them we are expecting there to only be, + // at most, one tx in the response. Because of this we don't want to initialize the slice with an initial size. + var txResps []*RelayerTxResponse + for _, tx := range res.Txs { + relayerEvents := parseEventsFromResponseDeliverTx(tx.TxResult.Events) + txResps = append(txResps, &RelayerTxResponse{ + Height: tx.Height, + TxHash: string(tx.Hash), + Code: tx.TxResult.Code, + Data: string(tx.TxResult.Data), + Events: relayerEvents, + }) + } + return txResps, nil +} + +// parseEventsFromResponseDeliverTx parses the events from a ResponseDeliverTx and builds a slice +// of provider.RelayerEvent's. +func parseEventsFromResponseDeliverTx(events []abci.Event) []RelayerEvent { + var rlyEvents []RelayerEvent + + for _, event := range events { + attributes := make(map[string]string) + for _, attribute := range event.Attributes { + attributes[attribute.Key] = attribute.Value + } + + rlyEvents = append(rlyEvents, RelayerEvent{ + EventType: event.Type, + Attributes: attributes, + }) + } + + return rlyEvents +} diff --git a/client/relayer/tx.go b/client/relayer/tx.go new file mode 100644 index 000000000..4deea7c72 --- /dev/null +++ b/client/relayer/tx.go @@ -0,0 +1,770 @@ +package relayerclient + +import ( + "context" + sdkerrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + "cosmossdk.io/store/rootmulti" + "errors" + "fmt" + abci "github.com/cometbft/cometbft/abci/types" + client2 "github.com/cometbft/cometbft/rpc/client" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/relayer/v2/relayer/ethermint" + "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "math" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "github.com/avast/retry-go/v4" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" +) + +// Variables used for retries +var ( + rtyAttNum = uint(5) + rtyAtt = retry.Attempts(rtyAttNum) + rtyDel = retry.Delay(time.Millisecond * 400) + rtyErr = retry.LastErrorOnly(true) + accountSeqRegex = regexp.MustCompile("account sequence mismatch, expected ([0-9]+), got ([0-9]+)") + defaultBroadcastWaitTimeout = 10 * time.Minute + errUnknown = "unknown" +) + +// Default IBC settings +var ( + defaultChainPrefix = commitmenttypes.NewMerklePrefix([]byte("ibc")) +) + +// Strings for parsing events +var ( + spTag = "send_packet" + waTag = "write_acknowledgement" + srcChanTag = "packet_src_channel" + dstChanTag = "packet_dst_channel" +) + +var seqGuardSingleton sync.Mutex + +// Gets the sequence guard. If it doesn't exist, initialized and returns it. +func ensureSequenceGuard(cc *CosmosProvider, key string) *WalletState { + seqGuardSingleton.Lock() + defer seqGuardSingleton.Unlock() + + if cc.walletStateMap == nil { + cc.walletStateMap = map[string]*WalletState{} + } + + sequenceGuard, ok := cc.walletStateMap[key] + if !ok { + cc.walletStateMap[key] = &WalletState{} + return cc.walletStateMap[key] + } + + return sequenceGuard +} + +// QueryABCI performs an ABCI query and returns the appropriate response and error sdk error code. +func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) (abci.ResponseQuery, error) { + opts := client2.ABCIQueryOptions{ + Height: req.Height, + Prove: req.Prove, + } + + result, err := cc.RPCClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts) + if err != nil { + return abci.ResponseQuery{}, err + } + + if !result.Response.IsOK() { + return abci.ResponseQuery{}, sdkErrorToGRPCError(result.Response) + } + + // data from trusted node or subspace query doesn't need verification + if !opts.Prove || !isQueryStoreWithProof(req.Path) { + return result.Response, nil + } + + return result.Response, nil +} + +// broadcastTx broadcasts a transaction with the given raw bytes and then, in an async goroutine, waits for the tx to be included in the block. +// The wait will end after either the asyncTimeout has run out or the asyncCtx exits. +// If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion. +func (cc *CosmosProvider) broadcastTx( + ctx context.Context, // context for tx broadcast + tx []byte, // raw tx to be broadcasted + msgs []RelayerMessage, // used for logging only + fees sdk.Coins, // used for metrics + + asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast + asyncTimeout time.Duration, // timeout for waiting for block inclusion + asyncCallbacks []func(*RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion +) error { + res, err := cc.RPCClient.BroadcastTxSync(ctx, tx) + isErr := err != nil + isFailed := res != nil && res.Code != 0 + if isErr || isFailed { + if isErr && res == nil { + // There are some cases where BroadcastTxSync will return an error but the associated + // ResultBroadcastTx will be nil. + return err + } + rlyResp := &RelayerTxResponse{ + TxHash: res.Hash.String(), + Codespace: res.Codespace, + Code: res.Code, + Data: res.Data.String(), + } + if isFailed { + err = cc.sdkError(res.Codespace, res.Code) + if err == nil { + err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.Log) + } + } + cc.LogFailedTx(rlyResp, err, msgs) + return err + } + + // TODO: maybe we need to check if the node has tx indexing enabled? + // if not, we need to find a new way to block until inclusion in a block + + go cc.waitForTx(asyncCtx, res.Hash, msgs, asyncTimeout, asyncCallbacks) + + return nil +} + +// waitForTx waits for a transaction to be included in a block, logs success/fail, then invokes callback. +// This is intended to be called as an async goroutine. +func (cc *CosmosProvider) waitForTx( + ctx context.Context, + txHash []byte, + msgs []RelayerMessage, // used for logging only + waitTimeout time.Duration, + callbacks []func(*RelayerTxResponse, error), +) { + res, err := cc.waitForBlockInclusion(ctx, txHash, waitTimeout) + if err != nil { + cc.log.Error("Failed to wait for block inclusion", zap.Error(err)) + if len(callbacks) > 0 { + for _, cb := range callbacks { + // Call each callback in order since waitForTx is already invoked asynchronously + cb(nil, err) + } + } + return + } + + rlyResp := &RelayerTxResponse{ + Height: res.Height, + TxHash: res.TxHash, + Codespace: res.Codespace, + Code: res.Code, + Data: res.Data, + Events: parseEventsFromTxResponse(res), + } + + // transaction was executed, log the success or failure using the tx response code + // NOTE: error is nil, logic should use the returned error to determine if the + // transaction was successfully executed. + + if res.Code != 0 { + // Check for any registered SDK errors + err := cc.sdkError(res.Codespace, res.Code) + if err == nil { + err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.RawLog) + } + if len(callbacks) > 0 { + for _, cb := range callbacks { + // Call each callback in order since waitForTx is already invoked asynchronously + cb(nil, err) + } + } + cc.LogFailedTx(rlyResp, nil, msgs) + return + } + + if len(callbacks) > 0 { + for _, cb := range callbacks { + //Call each callback in order since waitForTx is already invoked asyncronously + cb(rlyResp, nil) + } + } + cc.LogSuccessTx(res, msgs) +} + +// waitForBlockInclusion will wait for a transaction to be included in a block, up to waitTimeout or context cancellation. +func (cc *CosmosProvider) waitForBlockInclusion( + ctx context.Context, + txHash []byte, + waitTimeout time.Duration, +) (*sdk.TxResponse, error) { + exitAfter := time.After(waitTimeout) + for { + select { + case <-exitAfter: + return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, ErrTimeoutAfterWaitingForTxBroadcast) + // This fixed poll is fine because it's only for logging and updating prometheus metrics currently. + case <-time.After(time.Millisecond * 100): + res, err := cc.RPCClient.Tx(ctx, txHash, false) + if err == nil { + return cc.mkTxResult(res) + } + if strings.Contains(err.Error(), "transaction indexing is disabled") { + return nil, fmt.Errorf("cannot determine success/failure of tx because transaction indexing is disabled on rpc url") + } + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// mkTxResult decodes a comet transaction into an SDK TxResponse. +func (cc *CosmosProvider) mkTxResult(resTx *coretypes.ResultTx) (*sdk.TxResponse, error) { + txbz, err := cc.Cdc.TxConfig.TxDecoder()(resTx.Tx) + if err != nil { + return nil, err + } + + p, ok := txbz.(intoAny) + if !ok { + return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txbz) + } + + any := p.AsAny() + return sdk.NewResponseResultTx(resTx, any, ""), nil +} + +func sdkErrorToGRPCError(resp abci.ResponseQuery) error { + switch resp.Code { + case legacyerrors.ErrInvalidRequest.ABCICode(): + return status.Error(codes.InvalidArgument, resp.Log) + case legacyerrors.ErrUnauthorized.ABCICode(): + return status.Error(codes.Unauthenticated, resp.Log) + case legacyerrors.ErrKeyNotFound.ABCICode(): + return status.Error(codes.NotFound, resp.Log) + default: + return status.Error(codes.Unknown, resp.Log) + } +} + +// isQueryStoreWithProof expects a format like /// +// queryType must be "store" and subpath must be "key" to require a proof. +func isQueryStoreWithProof(path string) bool { + if !strings.HasPrefix(path, "/") { + return false + } + + paths := strings.SplitN(path[1:], "/", 3) + + switch { + case len(paths) != 3: + return false + case paths[0] != "store": + return false + case rootmulti.RequireProof("/" + paths[2]): + return true + } + + return false +} + +// sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil. +func (cc *CosmosProvider) sdkError(codespace string, code uint32) error { + // ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace + // This catches all of the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go + err := errors.Unwrap(sdkerrors.ABCIError(codespace, code, "error broadcasting transaction")) + if err.Error() != errUnknown { + return err + } + return nil +} + +func parseEventsFromTxResponse(resp *sdk.TxResponse) []RelayerEvent { + var events []RelayerEvent + + if resp == nil { + return events + } + + for _, logs := range resp.Logs { + for _, event := range logs.Events { + attributes := make(map[string]string) + for _, attribute := range event.Attributes { + attributes[attribute.Key] = attribute.Value + } + events = append(events, RelayerEvent{ + EventType: event.Type, + Attributes: attributes, + }) + } + } + + // After SDK v0.50, indexed events are no longer provided in the logs on + // transaction execution, the response events can be directly used + if len(events) == 0 { + for _, event := range resp.Events { + attributes := make(map[string]string) + for _, attribute := range event.Attributes { + attributes[attribute.Key] = attribute.Value + } + events = append(events, RelayerEvent{ + EventType: event.Type, + Attributes: attributes, + }) + } + } + + return events +} + +// handleAccountSequenceMismatchError will parse the error string, e.g.: +// "account sequence mismatch, expected 10, got 9: incorrect account sequence" +// and update the next account sequence with the expected value. +func (cc *CosmosProvider) handleAccountSequenceMismatchError(sequenceGuard *WalletState, err error) { + if sequenceGuard == nil { + panic("sequence guard not configured") + } + + matches := accountSeqRegex.FindStringSubmatch(err.Error()) + if len(matches) == 0 { + return + } + nextSeq, err := strconv.ParseUint(matches[1], 10, 64) + if err != nil { + return + } + sequenceGuard.NextAccountSequence = nextSeq +} + +// SendMessagesToMempool simulates and broadcasts a transaction with the given msgs and memo. +// This method will return once the transaction has entered the mempool. +// In an async goroutine, will wait for the tx to be included in the block unless asyncCtx exits. +// If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion. +func (cc *CosmosProvider) SendMessagesToMempool( + ctx context.Context, + msgs []RelayerMessage, + memo string, + + asyncCtx context.Context, + asyncCallbacks []func(*RelayerTxResponse, error), +) error { + txSignerKey, feegranterKeyOrAddr, err := cc.buildSignerConfig(msgs) + if err != nil { + return err + } + + sequenceGuard := ensureSequenceGuard(cc, txSignerKey) + sequenceGuard.Mu.Lock() + defer sequenceGuard.Mu.Unlock() + + txBytes, sequence, fees, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feegranterKeyOrAddr, sequenceGuard) + if err != nil { + // Account sequence mismatch errors can happen on the simulated transaction also. + if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { + cc.handleAccountSequenceMismatchError(sequenceGuard, err) + } + + return err + } + + if err := cc.broadcastTx(ctx, txBytes, msgs, fees, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil { + if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { + cc.handleAccountSequenceMismatchError(sequenceGuard, err) + } + + return err + } + + // we had a successful tx broadcast with this sequence, so update it to the next + cc.updateNextAccountSequence(sequenceGuard, sequence+1) + return nil +} + +func (cc *CosmosProvider) updateNextAccountSequence(sequenceGuard *WalletState, seq uint64) { + if seq > sequenceGuard.NextAccountSequence { + sequenceGuard.NextAccountSequence = seq + } +} + +func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) ( + txSignerKey string, + feegranterKeyOrAddr string, + err error, +) { + // Guard against race conditions when choosing a signer/feegranter + cc.feegrantMu.Lock() + defer cc.feegrantMu.Unlock() + + // Some messages have feegranting disabled. If any message in the TX disables feegrants, then the TX will not be feegranted. + isFeegrantEligible := cc.PCfg.FeeGrants != nil + + for _, curr := range msgs { + if cMsg, ok := curr.(CosmosMessage); ok { + if cMsg.FeegrantDisabled { + isFeegrantEligible = false + } + } + } + + // By default, we should sign TXs with the provider's default key + txSignerKey = cc.PCfg.Key + + if isFeegrantEligible { + txSignerKey, feegranterKeyOrAddr = cc.GetTxFeeGrant() + signerAcc, addrErr := cc.GetKeyAddressForKey(txSignerKey) + if addrErr != nil { + err = addrErr + return + } + + signerAccAddr, encodeErr := cc.EncodeBech32AccAddr(signerAcc) + if encodeErr != nil { + err = encodeErr + return + } + + // Overwrite the 'Signer' field in any Msgs that provide an 'optionalSetSigner' callback + for _, curr := range msgs { + if cMsg, ok := curr.(CosmosMessage); ok { + if cMsg.SetSigner != nil { + cMsg.SetSigner(signerAccAddr) + } + } + } + } + + return +} + +func (cc *CosmosProvider) buildMessages( + ctx context.Context, + msgs []RelayerMessage, + memo string, + gas uint64, + txSignerKey string, + feegranterKeyOrAddr string, + sequenceGuard *WalletState, +) ( + txBytes []byte, + sequence uint64, + fees sdk.Coins, + err error, +) { + done := cc.SetSDKContext() + defer done() + + cMsgs := CosmosMsgs(msgs...) + + txf, err := cc.PrepareFactory(cc.TxFactory(), txSignerKey) + if err != nil { + return nil, 0, sdk.Coins{}, err + } + + if memo != "" { + txf = txf.WithMemo(memo) + } + + sequence = txf.Sequence() + cc.updateNextAccountSequence(sequenceGuard, sequence) + if sequence < sequenceGuard.NextAccountSequence { + sequence = sequenceGuard.NextAccountSequence + txf = txf.WithSequence(sequence) + } + + // Cannot feegrant your own TX + if txSignerKey != feegranterKeyOrAddr && feegranterKeyOrAddr != "" { + var granterAddr sdk.AccAddress + if cc.PCfg.FeeGrants != nil && cc.PCfg.FeeGrants.IsExternalGranter { + granterAddr, err = cc.DecodeBech32AccAddr(feegranterKeyOrAddr) + if err != nil { + return nil, 0, sdk.Coins{}, err + } + } else { + granterAddr, err = cc.GetKeyAddressForKey(feegranterKeyOrAddr) + if err != nil { + return nil, 0, sdk.Coins{}, err + } + } + + txf = txf.WithFeeGranter(granterAddr) + } + + adjusted := gas + + if gas == 0 { + _, adjusted, err = cc.CalculateGas(ctx, txf, txSignerKey, cMsgs...) + + if err != nil { + return nil, 0, sdk.Coins{}, err + } + } + + // Set the gas amount on the transaction factory + txf = txf.WithGas(adjusted) + + // Build the transaction builder + txb, err := txf.BuildUnsignedTx(cMsgs...) + if err != nil { + return nil, 0, sdk.Coins{}, err + } + + if err = tx.Sign(ctx, txf, txSignerKey, txb, false); err != nil { + return nil, 0, sdk.Coins{}, err + } + + tx := txb.GetTx() + fees = tx.GetFee() + + // Generate the transaction bytes + txBytes, err = cc.Cdc.TxConfig.TxEncoder()(tx) + if err != nil { + return nil, 0, sdk.Coins{}, err + } + + return txBytes, txf.Sequence(), fees, nil +} + +// PrepareFactory mutates the tx factory with the appropriate account number, sequence number, and min gas settings. +func (cc *CosmosProvider) PrepareFactory(txf tx.Factory, signingKey string) (tx.Factory, error) { + var ( + err error + from sdk.AccAddress + num, seq uint64 + ) + + // Get key address and retry if fail + if err = retry.Do(func() error { + from, err = cc.GetKeyAddressForKey(signingKey) + if err != nil { + return err + } + return err + }, rtyAtt, rtyDel, rtyErr); err != nil { + return tx.Factory{}, err + } + + cliCtx := client.Context{}.WithClient(cc.RPCClient). + WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). + WithChainID(cc.PCfg.ChainID). + WithCodec(cc.Cdc.Marshaler). + WithFromAddress(from) + + // Set the account number and sequence on the transaction factory and retry if fail + if err = retry.Do(func() error { + if err = txf.AccountRetriever().EnsureExists(cliCtx, from); err != nil { + return err + } + return err + }, rtyAtt, rtyDel, rtyErr); err != nil { + return txf, err + } + + // TODO: why this code? this may potentially require another query when we don't want one + initNum, initSeq := txf.AccountNumber(), txf.Sequence() + if initNum == 0 || initSeq == 0 { + if err = retry.Do(func() error { + num, seq, err = txf.AccountRetriever().GetAccountNumberSequence(cliCtx, from) + if err != nil { + return err + } + return err + }, rtyAtt, rtyDel, rtyErr); err != nil { + return txf, err + } + + if initNum == 0 { + txf = txf.WithAccountNumber(num) + } + + if initSeq == 0 { + txf = txf.WithSequence(seq) + } + } + + if cc.PCfg.MinGasAmount != 0 { + txf = txf.WithGas(cc.PCfg.MinGasAmount) + } + + if cc.PCfg.MaxGasAmount != 0 { + txf = txf.WithGas(cc.PCfg.MaxGasAmount) + } + txf, err = cc.SetWithExtensionOptions(txf) + if err != nil { + return tx.Factory{}, err + } + return txf, nil +} + +// SetWithExtensionOptions sets the dynamic fee extension options on the given +// transaction factory using the configuration options from the CosmosProvider. +// The function creates an extension option for each configuration option and +// serializes it into a byte slice before adding it to the list of extension +// options. The function returns the updated transaction factory with the new +// extension options or an error if the serialization fails or an invalid option +// value is encountered. +func (cc *CosmosProvider) SetWithExtensionOptions(txf tx.Factory) (tx.Factory, error) { + extOpts := make([]*types.Any, 0, len(cc.PCfg.ExtensionOptions)) + for _, opt := range cc.PCfg.ExtensionOptions { + max, ok := sdkmath.NewIntFromString(opt.Value) + if !ok { + return txf, fmt.Errorf("invalid opt value") + } + extensionOption := ethermint.ExtensionOptionDynamicFeeTx{ + MaxPriorityPrice: max, + } + extBytes, err := extensionOption.Marshal() + if err != nil { + return txf, err + } + extOpts = append(extOpts, &types.Any{ + TypeUrl: "/ethermint.types.v1.ExtensionOptionDynamicFeeTx", + Value: extBytes, + }) + } + return txf.WithExtensionOptions(extOpts...), nil +} + +// TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain. +func (cc *CosmosProvider) TxFactory() tx.Factory { + return tx.Factory{}. + WithAccountRetriever(cc). + WithChainID(cc.PCfg.ChainID). + WithTxConfig(cc.Cdc.TxConfig). + WithGasAdjustment(cc.PCfg.GasAdjustment). + WithGasPrices(cc.PCfg.GasPrices). + WithKeybase(cc.Keybase). + WithSignMode(cc.PCfg.SignMode()) +} + +// SignMode returns the SDK sign mode type reflective of the specified sign mode in the config file. +func (pc CosmosProviderConfig) SignMode() signing.SignMode { + signMode := signing.SignMode_SIGN_MODE_UNSPECIFIED + switch pc.SignModeStr { + case "direct": + signMode = signing.SignMode_SIGN_MODE_DIRECT + case "amino-json": + signMode = signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON + } + return signMode +} + +// CalculateGas simulates a tx to generate the appropriate gas settings before broadcasting a tx. +func (cc *CosmosProvider) CalculateGas(ctx context.Context, txf tx.Factory, signingKey string, msgs ...sdk.Msg) (txtypes.SimulateResponse, uint64, error) { + keyInfo, err := cc.Keybase.Key(signingKey) + if err != nil { + return txtypes.SimulateResponse{}, 0, err + } + + var txBytes []byte + if err := retry.Do(func() error { + var err error + txBytes, err = BuildSimTx(keyInfo, txf, msgs...) + if err != nil { + return err + } + return nil + }, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil { + return txtypes.SimulateResponse{}, 0, err + } + + simQuery := abci.RequestQuery{ + Path: "/cosmos.tx.v1beta1.Service/Simulate", + Data: txBytes, + } + + var res abci.ResponseQuery + if err := retry.Do(func() error { + var err error + res, err = cc.QueryABCI(ctx, simQuery) + if err != nil { + return err + } + return nil + }, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil { + return txtypes.SimulateResponse{}, 0, err + } + + var simRes txtypes.SimulateResponse + if err := simRes.Unmarshal(res.Value); err != nil { + return txtypes.SimulateResponse{}, 0, err + } + + gas, err := cc.AdjustEstimatedGas(simRes.GasInfo.GasUsed) + return simRes, gas, err +} + +// BuildSimTx creates an unsigned tx with an empty single signature and returns +// the encoded transaction or an error if the unsigned transaction cannot be built. +func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte, error) { + txb, err := txf.BuildUnsignedTx(msgs...) + if err != nil { + return nil, err + } + + var pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type + + pk, err = info.GetPubKey() + if err != nil { + return nil, err + } + + // Create an empty signature literal as the ante handler will populate with a + // sentinel pubkey. + sig := signing.SignatureV2{ + PubKey: pk, + Data: &signing.SingleSignatureData{ + SignMode: txf.SignMode(), + }, + Sequence: txf.Sequence(), + } + if err := txb.SetSignatures(sig); err != nil { + return nil, err + } + + protoProvider, ok := txb.(protoTxProvider) + if !ok { + return nil, fmt.Errorf("cannot simulate amino tx") + } + + simReq := txtypes.SimulateRequest{Tx: protoProvider.GetProtoTx()} + return simReq.Marshal() +} + +// AdjustEstimatedGas adjusts the estimated gas usage by multiplying it by the gas adjustment factor +// and return estimated gas is higher than max gas error. If the gas usage is zero, the adjusted gas +// is also zero. +func (cc *CosmosProvider) AdjustEstimatedGas(gasUsed uint64) (uint64, error) { + if gasUsed == 0 { + return gasUsed, nil + } + if cc.PCfg.MaxGasAmount > 0 && gasUsed > cc.PCfg.MaxGasAmount { + return 0, fmt.Errorf("estimated gas %d is higher than max gas %d", gasUsed, cc.PCfg.MaxGasAmount) + } + gas := cc.PCfg.GasAdjustment * float64(gasUsed) + if math.IsInf(gas, 1) { + return 0, fmt.Errorf("infinite gas used") + } + return uint64(gas), nil +} + +// protoTxProvider is a type which can provide a proto transaction. It is a +// workaround to get access to the wrapper TxBuilder's method GetProtoTx(). +type protoTxProvider interface { + GetProtoTx() *txtypes.Tx +} From ed114fbc6ea923771aa0488ddae53969d8deb88e Mon Sep 17 00:00:00 2001 From: Lazar Date: Mon, 20 Jan 2025 15:53:56 +0100 Subject: [PATCH 02/21] moves tests and rm excess --- client/relayer/chain_provider.go | 19 ------ client/relayer/feegrant.go | 2 +- client/relayer/keys_test.go | 103 +++++++++++++++++++++++++++++++ client/relayer/tx_test.go | 77 +++++++++++++++++++++++ 4 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 client/relayer/keys_test.go create mode 100644 client/relayer/tx_test.go diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index a6725ae99..1058e349b 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -198,25 +198,6 @@ func (h TendermintIBCHeader) NextValidatorsHash() []byte { return h.SignedHeader.NextValidatorsHash } -func (h TendermintIBCHeader) TMHeader() (*tendermint.Header, error) { - valSet, err := h.ValidatorSet.ToProto() - if err != nil { - return nil, err - } - - trustedVals, err := h.TrustedValidators.ToProto() - if err != nil { - return nil, err - } - - return &tendermint.Header{ - SignedHeader: h.SignedHeader.ToProto(), - ValidatorSet: valSet, - TrustedHeight: h.TrustedHeight, - TrustedValidators: trustedVals, - }, nil -} - type ExtensionOption struct { Type string `json:"type"` Value string `json:"value"` diff --git a/client/relayer/feegrant.go b/client/relayer/feegrant.go index 758bea17b..8d81698a3 100644 --- a/client/relayer/feegrant.go +++ b/client/relayer/feegrant.go @@ -27,7 +27,7 @@ func (cc *CosmosProvider) GetTxFeeGrant() (txSignerKey string, feeGranterKeyOrAd txSignerKey = cc.PCfg.FeeGrants.ManagedGrantees[lastGranteeIdx] cc.PCfg.FeeGrants.GranteeLastSignerIndex = cc.PCfg.FeeGrants.GranteeLastSignerIndex + 1 - // Restart the round robin at 0 if we reached the end of the list of grantees + // Restart the round-robin at 0 if we reached the end of the list of grantees if cc.PCfg.FeeGrants.GranteeLastSignerIndex == len(cc.PCfg.FeeGrants.ManagedGrantees) { cc.PCfg.FeeGrants.GranteeLastSignerIndex = 0 } diff --git a/client/relayer/keys_test.go b/client/relayer/keys_test.go new file mode 100644 index 000000000..2c1b70c0d --- /dev/null +++ b/client/relayer/keys_test.go @@ -0,0 +1,103 @@ +package relayerclient_test + +import ( + relayerclient "github.com/babylonlabs-io/babylon/client/relayer" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func testProviderWithKeystore(t *testing.T, accountPrefix string, extraCodecs []string) relayerclient.ChainProvider { + homePath := t.TempDir() + cfg := relayerclient.CosmosProviderConfig{ + ChainID: "test", + KeyDirectory: filepath.Join(homePath, "keys"), + KeyringBackend: "test", + Timeout: "10s", + AccountPrefix: accountPrefix, + ExtraCodecs: extraCodecs, + } + p, err := cfg.NewProvider(zap.NewNop(), homePath, "test_chain") + if err != nil { + t.Fatalf("Error creating provider: %v", err) + } + err = p.CreateKeystore(homePath) + if err != nil { + t.Fatalf("Error creating keystore: %v", err) + } + return p +} + +// TestKeyRestore restores a test mnemonic +func TestKeyRestore(t *testing.T) { + const ( + keyName = "test_key" + signatureAlgorithm = "secp256k1" + mnemonic = "blind master acoustic speak victory lend kiss grab glad help demand hood roast zone lend sponsor level cheap truck kingdom apology token hover reunion" + accountPrefix = "cosmos" + expectedAddress = "cosmos15cw268ckjj2hgq8q3jf68slwjjcjlvxy57je2u" + coinType = uint32(118) + ) + + p := testProviderWithKeystore(t, accountPrefix, nil) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreEth restores a test mnemonic +func TestKeyRestoreEth(t *testing.T) { + const ( + keyName = "test_key" + signatureAlgorithm = "secp256k1" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "evmos" + expectedAddress = "evmos1dea7vlekr9e34vugwkvesulglt8fx4e457vk9z" + coinType = uint32(60) + ) + + p := testProviderWithKeystore(t, accountPrefix, []string{"ethermint"}) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreInj restores a test mnemonic +func TestKeyRestoreInj(t *testing.T) { + const ( + keyName = "inj_key" + signatureAlgorithm = "secp256k1" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "inj" + expectedAddress = "inj1dea7vlekr9e34vugwkvesulglt8fx4e4uk2udj" + coinType = uint32(60) + ) + + p := testProviderWithKeystore(t, accountPrefix, []string{"injective"}) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreSr25519 restores a test mnemonic +func TestKeyRestoreSr25519(t *testing.T) { + const ( + keyName = "sei_key" + signatureAlgorithm = "sr25519" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "sei" + expectedAddress = "sei1th80nzvgkzg7reehtyp4xm39xerqg6z77ymcnx" + coinType = uint32(118) + ) + + p := testProviderWithKeystore(t, accountPrefix, nil) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} diff --git a/client/relayer/tx_test.go b/client/relayer/tx_test.go new file mode 100644 index 000000000..275c391d0 --- /dev/null +++ b/client/relayer/tx_test.go @@ -0,0 +1,77 @@ +package relayerclient + +import ( + "fmt" + "math" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCosmosProvider_AdjustEstimatedGas(t *testing.T) { + testCases := []struct { + name string + gasUsed uint64 + gasAdjustment float64 + maxGasAmount uint64 + expectedGas uint64 + expectedErr error + }{ + { + name: "gas used is zero", + gasUsed: 0, + gasAdjustment: 1.0, + maxGasAmount: 0, + expectedGas: 0, + expectedErr: nil, + }, + { + name: "gas used is non-zero", + gasUsed: 50000, + gasAdjustment: 1.5, + maxGasAmount: 100000, + expectedGas: 75000, + expectedErr: nil, + }, + { + name: "gas used is infinite", + gasUsed: 10000, + gasAdjustment: math.Inf(1), + maxGasAmount: 0, + expectedGas: 0, + expectedErr: fmt.Errorf("infinite gas used"), + }, + { + name: "gas used is non-zero with zero max gas amount as default", + gasUsed: 50000, + gasAdjustment: 1.5, + maxGasAmount: 0, + expectedGas: 75000, + expectedErr: nil, + }, + { + name: "estimated gas is higher than max gas", + gasUsed: 50000, + gasAdjustment: 1.5, + maxGasAmount: 70000, + expectedGas: 75000, + expectedErr: fmt.Errorf("estimated gas 75000 is higher than max gas 70000"), + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + cc := &CosmosProvider{PCfg: CosmosProviderConfig{ + GasAdjustment: tc.gasAdjustment, + MaxGasAmount: tc.maxGasAmount, + }} + adjustedGas, err := cc.AdjustEstimatedGas(tc.gasUsed) + if err != nil { + require.EqualError(t, err, tc.expectedErr.Error()) + } else { + require.Equal(t, adjustedGas, tc.expectedGas) + } + }) + } +} From 51990199a39a1237c2d8a6b7d147924c449e99c1 Mon Sep 17 00:00:00 2001 From: Lazar Date: Mon, 20 Jan 2025 16:34:43 +0100 Subject: [PATCH 03/21] rm excess --- client/relayer/chain_provider.go | 73 -------------------------------- client/relayer/grpc_query.go | 2 +- client/relayer/tx.go | 10 ++--- 3 files changed, 5 insertions(+), 80 deletions(-) diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index 1058e349b..611c15e42 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -2,15 +2,9 @@ package relayerclient import ( "context" - "fmt" "time" - "github.com/cometbft/cometbft/types" "github.com/cosmos/gogoproto/proto" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -131,73 +125,6 @@ type KeyOutput struct { Address string `json:"address" yaml:"address"` } -// TimeoutHeightError is used during packet validation to inform the PathProcessor -// that the current chain height has exceeded the packet height timeout so that -// a MsgTimeout can be assembled for the counterparty chain. -type TimeoutHeightError struct { - latestHeight uint64 - timeoutHeight uint64 -} - -func (t *TimeoutHeightError) Error() string { - return fmt.Sprintf("latest height %d is greater than expiration height: %d", t.latestHeight, t.timeoutHeight) -} - -func NewTimeoutHeightError(latestHeight, timeoutHeight uint64) *TimeoutHeightError { - return &TimeoutHeightError{latestHeight, timeoutHeight} -} - -// TimeoutTimestampError is used during packet validation to inform the PathProcessor -// that current block timestamp has exceeded the packet timestamp timeout so that -// a MsgTimeout can be assembled for the counterparty chain. -type TimeoutTimestampError struct { - latestTimestamp uint64 - timeoutTimestamp uint64 -} - -func (t *TimeoutTimestampError) Error() string { - return fmt.Sprintf("latest block timestamp %d is greater than expiration timestamp: %d", t.latestTimestamp, t.timeoutTimestamp) -} - -func NewTimeoutTimestampError(latestTimestamp, timeoutTimestamp uint64) *TimeoutTimestampError { - return &TimeoutTimestampError{latestTimestamp, timeoutTimestamp} -} - -type TimeoutOnCloseError struct { - msg string -} - -func (t *TimeoutOnCloseError) Error() string { - return fmt.Sprintf("packet timeout on close error: %s", t.msg) -} - -func NewTimeoutOnCloseError(msg string) *TimeoutOnCloseError { - return &TimeoutOnCloseError{msg} -} - -type TendermintIBCHeader struct { - SignedHeader *types.SignedHeader - ValidatorSet *types.ValidatorSet - TrustedValidators *types.ValidatorSet - TrustedHeight clienttypes.Height -} - -func (h TendermintIBCHeader) Height() uint64 { - return uint64(h.SignedHeader.Height) -} - -func (h TendermintIBCHeader) ConsensusState() ibcexported.ConsensusState { - return &tendermint.ConsensusState{ - Timestamp: h.SignedHeader.Time, - Root: commitmenttypes.NewMerkleRoot(h.SignedHeader.AppHash), - NextValidatorsHash: h.SignedHeader.NextValidatorsHash, - } -} - -func (h TendermintIBCHeader) NextValidatorsHash() []byte { - return h.SignedHeader.NextValidatorsHash -} - type ExtensionOption struct { Type string `json:"type"` Value string `json:"value"` diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go index 3a426ab50..568a46ff9 100644 --- a/client/relayer/grpc_query.go +++ b/client/relayer/grpc_query.go @@ -178,7 +178,7 @@ func (cc *CosmosProvider) TxServiceBroadcast(ctx context.Context, req *tx.Broadc wg.Add(1) - if err := cc.broadcastTx(ctx, req.TxBytes, nil, nil, ctx, blockTimeout, []func(*RelayerTxResponse, error){callback}); err != nil { + if err := cc.broadcastTx(ctx, req.TxBytes, nil, ctx, blockTimeout, []func(*RelayerTxResponse, error){callback}); err != nil { return nil, err } diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 4deea7c72..8c75711e8 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -108,10 +108,8 @@ func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) // If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion. func (cc *CosmosProvider) broadcastTx( ctx context.Context, // context for tx broadcast - tx []byte, // raw tx to be broadcasted + tx []byte, // raw tx to be broadcast msgs []RelayerMessage, // used for logging only - fees sdk.Coins, // used for metrics - asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast asyncTimeout time.Duration, // timeout for waiting for block inclusion asyncCallbacks []func(*RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion @@ -287,7 +285,7 @@ func isQueryStoreWithProof(path string) bool { // sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil. func (cc *CosmosProvider) sdkError(codespace string, code uint32) error { // ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace - // This catches all of the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go + // This catches all the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go err := errors.Unwrap(sdkerrors.ABCIError(codespace, code, "error broadcasting transaction")) if err.Error() != errUnknown { return err @@ -373,7 +371,7 @@ func (cc *CosmosProvider) SendMessagesToMempool( sequenceGuard.Mu.Lock() defer sequenceGuard.Mu.Unlock() - txBytes, sequence, fees, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feegranterKeyOrAddr, sequenceGuard) + txBytes, sequence, _, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feegranterKeyOrAddr, sequenceGuard) if err != nil { // Account sequence mismatch errors can happen on the simulated transaction also. if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { @@ -383,7 +381,7 @@ func (cc *CosmosProvider) SendMessagesToMempool( return err } - if err := cc.broadcastTx(ctx, txBytes, msgs, fees, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil { + if err := cc.broadcastTx(ctx, txBytes, msgs, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil { if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { cc.handleAccountSequenceMismatchError(sequenceGuard, err) } From 9f5fe6c2d389442d8a9edc72bdcfc762d6e26bc7 Mon Sep 17 00:00:00 2001 From: Lazar Date: Mon, 20 Jan 2025 17:22:58 +0100 Subject: [PATCH 04/21] cleanup --- client/client/client.go | 2 +- client/client/tx.go | 8 ++----- client/relayer/app_module.go | 46 ++++++++++++++++++++++++++++++++++++ client/relayer/codec.go | 27 ++++----------------- client/relayer/grpc_query.go | 2 +- client/relayer/keys.go | 21 +++------------- client/relayer/provider.go | 6 ++--- client/relayer/tx.go | 39 ++---------------------------- 8 files changed, 63 insertions(+), 88 deletions(-) create mode 100644 client/relayer/app_module.go diff --git a/client/client/client.go b/client/client/client.go index 964915493..ebbcdfd2a 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -58,7 +58,7 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { encCfg := bbn.GetEncodingConfig() cp.Cdc = relayerclient.Codec{ InterfaceRegistry: encCfg.InterfaceRegistry, - Marshaler: encCfg.Codec, + Marshaller: encCfg.Codec, TxConfig: encCfg.TxConfig, Amino: encCfg.Amino, } diff --git a/client/client/tx.go b/client/client/tx.go index f00822f89..669bc718d 100644 --- a/client/client/tx.go +++ b/client/client/tx.go @@ -219,7 +219,7 @@ func (c *Client) SendMessageWithSigner( cliCtx := client.Context{}.WithClient(cc.RPCClient). WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). - WithCodec(cc.Cdc.Marshaler). + WithCodec(cc.Cdc.Marshaller). WithFromAddress(signerAddr) txf := cc.TxFactory() @@ -260,10 +260,6 @@ func (c *Client) SendMessageWithSigner( if cc.PCfg.MaxGasAmount != 0 { txf = txf.WithGas(cc.PCfg.MaxGasAmount) } - txf, err = cc.SetWithExtensionOptions(txf) - if err != nil { - return nil, err - } // txf ready _, adjusted, err := c.CalculateGas(ctx, txf, signerPvKey.PubKey(), cMsgs...) @@ -284,7 +280,7 @@ func (c *Client) SendMessageWithSigner( // c.LogFailedTx(nil, err, msgs) // Force encoding in the chain specific address for _, msg := range cMsgs { - cc.Cdc.Marshaler.MustMarshalJSON(msg) + cc.Cdc.Marshaller.MustMarshalJSON(msg) } if err := Sign(ctx, txf, signerPvKey, txb, cc.Cdc.TxConfig.SignModeHandler(), false); err != nil { return nil, err diff --git a/client/relayer/app_module.go b/client/relayer/app_module.go new file mode 100644 index 000000000..163082047 --- /dev/null +++ b/client/relayer/app_module.go @@ -0,0 +1,46 @@ +package relayerclient + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" + localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + tmlightclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" +) + +// AppModuleBasic defines the basic application module used by the module. +type AppModuleBasic struct{} + +// Name returns the module's name. +func (AppModuleBasic) Name() string { + return "cosmos_chain_provider" +} + +// RegisterLegacyAminoCodec does nothing. IBC does not support amino. +func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} + +// RegisterInterfaces registers module concrete types into protobuf Any. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + tmlightclient.RegisterInterfaces(registry) + solomachine.RegisterInterfaces(registry) + localhost.RegisterInterfaces(registry) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + panic("not implemented") +} + +// GetTxCmd returns the root tx command for the ibc module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + panic("not implemented") +} + +// GetQueryCmd returns no root query command for the ibc module. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + panic("not implemented") +} diff --git a/client/relayer/codec.go b/client/relayer/codec.go index 60ffc2eb5..86a32f1d1 100644 --- a/client/relayer/codec.go +++ b/client/relayer/codec.go @@ -29,10 +29,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer" ibc "github.com/cosmos/ibc-go/v8/modules/core" - cosmosmodule "github.com/cosmos/relayer/v2/relayer/chains/cosmos/module" "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" - ethermintcodecs "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" - injectivecodecs "github.com/cosmos/relayer/v2/relayer/codecs/injective" ) var ModuleBasics = []module.AppModuleBasic{ @@ -40,8 +37,6 @@ var ModuleBasics = []module.AppModuleBasic{ authz.AppModuleBasic{}, bank.AppModuleBasic{}, capability.AppModuleBasic{}, - // TODO: add osmosis governance proposal types here - // TODO: add other proposal types here gov.NewAppModuleBasic( []govclient.ProposalHandler{ paramsclient.ProposalHandler, @@ -57,14 +52,14 @@ var ModuleBasics = []module.AppModuleBasic{ upgrade.AppModuleBasic{}, transfer.AppModuleBasic{}, ibc.AppModuleBasic{}, - cosmosmodule.AppModuleBasic{}, + AppModuleBasic{}, stride.AppModuleBasic{}, ibcfee.AppModuleBasic{}, } type Codec struct { InterfaceRegistry types.InterfaceRegistry - Marshaler codec.Codec + Marshaller codec.Codec TxConfig client.TxConfig Amino *codec.LegacyAmino } @@ -76,18 +71,6 @@ func MakeCodec(moduleBasics []module.AppModuleBasic, extraCodecs []string, accBe std.RegisterInterfaces(encodingConfig.InterfaceRegistry) modBasic.RegisterLegacyAminoCodec(encodingConfig.Amino) modBasic.RegisterInterfaces(encodingConfig.InterfaceRegistry) - for _, c := range extraCodecs { - switch c { - case "ethermint": - ethermintcodecs.RegisterInterfaces(encodingConfig.InterfaceRegistry) - encodingConfig.Amino.RegisterConcrete(ðermintcodecs.PubKey{}, ethermintcodecs.PubKeyName, nil) - encodingConfig.Amino.RegisterConcrete(ðermintcodecs.PrivKey{}, ethermintcodecs.PrivKeyName, nil) - case "injective": - injectivecodecs.RegisterInterfaces(encodingConfig.InterfaceRegistry) - encodingConfig.Amino.RegisterConcrete(&injectivecodecs.PubKey{}, injectivecodecs.PubKeyName, nil) - encodingConfig.Amino.RegisterConcrete(&injectivecodecs.PrivKey{}, injectivecodecs.PrivKeyName, nil) - } - } return encodingConfig } @@ -103,15 +86,15 @@ func MakeCodecConfig(accBech32Prefix, valBech32Prefix string) Codec { if err != nil { panic(err) } - marshaler := codec.NewProtoCodec(interfaceRegistry) + marshaller := codec.NewProtoCodec(interfaceRegistry) done := SetSDKConfigContext(accBech32Prefix) defer done() return Codec{ InterfaceRegistry: interfaceRegistry, - Marshaler: marshaler, - TxConfig: tx.NewTxConfig(marshaler, tx.DefaultSignModes), + Marshaller: marshaller, + TxConfig: tx.NewTxConfig(marshaller, tx.DefaultSignModes), Amino: codec.NewLegacyAmino(), } } diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go index 568a46ff9..eb8fc5ac9 100644 --- a/client/relayer/grpc_query.go +++ b/client/relayer/grpc_query.go @@ -79,7 +79,7 @@ func (cc *CosmosProvider) Invoke(ctx context.Context, method string, req, reply } if cc.Cdc.InterfaceRegistry != nil { - return types.UnpackInterfaces(reply, cc.Cdc.Marshaler) + return types.UnpackInterfaces(reply, cc.Cdc.Marshaller) } return nil diff --git a/client/relayer/keys.go b/client/relayer/keys.go index 2f92df685..8df509182 100644 --- a/client/relayer/keys.go +++ b/client/relayer/keys.go @@ -10,23 +10,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/go-bip39" "github.com/cosmos/relayer/v2/relayer/chains/cosmos/keys/sr25519" - "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" - "github.com/cosmos/relayer/v2/relayer/codecs/injective" ) -const ethereumCoinType = uint32(60) - var ( // SupportedAlgorithms defines the list of signing algorithms used on Evmos: // - secp256k1 (Cosmos) // - sr25519 (Cosmos) - // - eth_secp256k1 (Ethereum, Injective) - SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} + SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519} // SupportedAlgorithmsLedger defines the list of signing algorithms used on Evmos for the Ledger device: // - secp256k1 (Cosmos) // - sr25519 (Cosmos) - // - eth_secp256k1 (Ethereum, Injective) - SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} + SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519} ) // KeyringAlgoOptions defines a function keys options for the ethereum Secp256k1 curve. @@ -40,7 +34,7 @@ func KeyringAlgoOptions() keyring.Option { // CreateKeystore initializes a new instance of a keyring at the specified path in the local filesystem. func (cc *CosmosProvider) CreateKeystore(path string) error { - keybase, err := keyring.New(cc.PCfg.ChainID, cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, cc.Cdc.Marshaler, KeyringAlgoOptions()) + keybase, err := keyring.New(cc.PCfg.ChainID, cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, cc.Cdc.Marshaller, KeyringAlgoOptions()) if err != nil { return err } @@ -108,15 +102,6 @@ func (cc *CosmosProvider) KeyAddOrRestore(keyName string, coinType uint32, signi } } - if coinType == ethereumCoinType { - algo = keyring.SignatureAlgo(ethermint.EthSecp256k1) - for _, codec := range cc.PCfg.ExtraCodecs { - if codec == "injective" { - algo = keyring.SignatureAlgo(injective.EthSecp256k1) - } - } - } - done := SetSDKConfigContext(cc.PCfg.AccountPrefix) info, err := cc.Keybase.NewAccount(keyName, mnemonicStr, "", hd.CreateHDPath(coinType, 0, 0).String(), algo) diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 596080751..7d8c47065 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -218,14 +218,14 @@ func (cc *CosmosProvider) AccountFromKeyOrAddress(keyOrAddress string) (out sdk. // Sprint returns the json representation of the specified proto message. func (cc *CosmosProvider) Sprint(toPrint proto.Message) (string, error) { - out, err := cc.Cdc.Marshaler.MarshalJSON(toPrint) + out, err := cc.Cdc.Marshaller.MarshalJSON(toPrint) if err != nil { return "", err } return string(out), nil } -// SetPCAddr sets the rpc-addr for the chain. +// SetRpcAddr sets the rpc-addr for the chain. // It will fail if the rpcAddr is invalid(not a url). func (cc *CosmosProvider) SetRpcAddr(rpcAddr string) error { cc.PCfg.RPCAddr = rpcAddr @@ -241,7 +241,7 @@ func (cc *CosmosProvider) Init(ctx context.Context) error { cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, - cc.Cdc.Marshaler, + cc.Cdc.Marshaller, cc.KeyringOptions..., ) if err != nil { diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 8c75711e8..ebb63f7dc 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -3,7 +3,6 @@ package relayerclient import ( "context" sdkerrors "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" "cosmossdk.io/store/rootmulti" "errors" "fmt" @@ -12,7 +11,6 @@ import ( coretypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -20,7 +18,6 @@ import ( legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/relayer/v2/relayer/ethermint" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -560,7 +557,7 @@ func (cc *CosmosProvider) PrepareFactory(txf tx.Factory, signingKey string) (tx. cliCtx := client.Context{}.WithClient(cc.RPCClient). WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). - WithCodec(cc.Cdc.Marshaler). + WithCodec(cc.Cdc.Marshaller). WithFromAddress(from) // Set the account number and sequence on the transaction factory and retry if fail @@ -602,40 +599,8 @@ func (cc *CosmosProvider) PrepareFactory(txf tx.Factory, signingKey string) (tx. if cc.PCfg.MaxGasAmount != 0 { txf = txf.WithGas(cc.PCfg.MaxGasAmount) } - txf, err = cc.SetWithExtensionOptions(txf) - if err != nil { - return tx.Factory{}, err - } - return txf, nil -} -// SetWithExtensionOptions sets the dynamic fee extension options on the given -// transaction factory using the configuration options from the CosmosProvider. -// The function creates an extension option for each configuration option and -// serializes it into a byte slice before adding it to the list of extension -// options. The function returns the updated transaction factory with the new -// extension options or an error if the serialization fails or an invalid option -// value is encountered. -func (cc *CosmosProvider) SetWithExtensionOptions(txf tx.Factory) (tx.Factory, error) { - extOpts := make([]*types.Any, 0, len(cc.PCfg.ExtensionOptions)) - for _, opt := range cc.PCfg.ExtensionOptions { - max, ok := sdkmath.NewIntFromString(opt.Value) - if !ok { - return txf, fmt.Errorf("invalid opt value") - } - extensionOption := ethermint.ExtensionOptionDynamicFeeTx{ - MaxPriorityPrice: max, - } - extBytes, err := extensionOption.Marshal() - if err != nil { - return txf, err - } - extOpts = append(extOpts, &types.Any{ - TypeUrl: "/ethermint.types.v1.ExtensionOptionDynamicFeeTx", - Value: extBytes, - }) - } - return txf.WithExtensionOptions(extOpts...), nil + return txf, nil } // TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain. From 7433cfdfabc6ef22ee7d611f268202ba74a5278c Mon Sep 17 00:00:00 2001 From: Lazar Date: Mon, 20 Jan 2025 17:50:26 +0100 Subject: [PATCH 05/21] cleanup --- client/relayer/chain_provider.go | 34 ----- client/relayer/keys.go | 207 ------------------------------- client/relayer/keys_test.go | 103 --------------- client/relayer/provider.go | 47 ------- client/relayer/query.go | 60 --------- 5 files changed, 451 deletions(-) delete mode 100644 client/relayer/keys_test.go diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index 611c15e42..e42d84647 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -2,9 +2,6 @@ package relayerclient import ( "context" - "time" - - "github.com/cosmos/gogoproto/proto" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -74,24 +71,13 @@ func (r RelayerTxResponse) MarshalLogObject(enc zapcore.ObjectEncoder) error { } type KeyProvider interface { - CreateKeystore(path string) error - KeystoreCreated(path string) bool - AddKey(name string, coinType uint32, signingAlgorithm string) (output *KeyOutput, err error) - UseKey(key string) error - RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) - ShowAddress(name string) (address string, err error) - ListAddresses() (map[string]string, error) - DeleteKey(name string) error KeyExists(name string) bool - ExportPrivKeyArmor(keyName string) (armor string, err error) } type ChainProvider interface { - QueryProvider KeyProvider Init(ctx context.Context) error - SendMessagesToMempool( ctx context.Context, msgs []RelayerMessage, @@ -107,25 +93,5 @@ type ChainProvider interface { Key() string Address() (string, error) Timeout() string - WaitForNBlocks(ctx context.Context, n int64) error - Sprint(toPrint proto.Message) (string, error) - SetRpcAddr(rpcAddr string) error } - -type QueryProvider interface { - BlockTime(ctx context.Context, height int64) (time.Time, error) - QueryTx(ctx context.Context, hashHex string) (*RelayerTxResponse, error) - QueryTxs(ctx context.Context, page, limit int, events []string) ([]*RelayerTxResponse, error) -} - -// KeyOutput contains mnemonic and address of key -type KeyOutput struct { - Mnemonic string `json:"mnemonic" yaml:"mnemonic"` - Address string `json:"address" yaml:"address"` -} - -type ExtensionOption struct { - Type string `json:"type"` - Value string `json:"value"` -} diff --git a/client/relayer/keys.go b/client/relayer/keys.go index 8df509182..8d9c172fd 100644 --- a/client/relayer/keys.go +++ b/client/relayer/keys.go @@ -1,174 +1,9 @@ package relayerclient import ( - "errors" - "os" - - ckeys "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/crypto/hd" - "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/go-bip39" - "github.com/cosmos/relayer/v2/relayer/chains/cosmos/keys/sr25519" -) - -var ( - // SupportedAlgorithms defines the list of signing algorithms used on Evmos: - // - secp256k1 (Cosmos) - // - sr25519 (Cosmos) - SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519} - // SupportedAlgorithmsLedger defines the list of signing algorithms used on Evmos for the Ledger device: - // - secp256k1 (Cosmos) - // - sr25519 (Cosmos) - SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519} ) -// KeyringAlgoOptions defines a function keys options for the ethereum Secp256k1 curve. -// It supports secp256k1 and eth_secp256k1 keys for accounts. -func KeyringAlgoOptions() keyring.Option { - return func(options *keyring.Options) { - options.SupportedAlgos = SupportedAlgorithms - options.SupportedAlgosLedger = SupportedAlgorithmsLedger - } -} - -// CreateKeystore initializes a new instance of a keyring at the specified path in the local filesystem. -func (cc *CosmosProvider) CreateKeystore(path string) error { - keybase, err := keyring.New(cc.PCfg.ChainID, cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, cc.Cdc.Marshaller, KeyringAlgoOptions()) - if err != nil { - return err - } - cc.Keybase = keybase - return nil -} - -// KeystoreCreated returns true if there is an existing keystore instance at the specified path, it returns false otherwise. -func (cc *CosmosProvider) KeystoreCreated(path string) bool { - if _, err := os.Stat(cc.PCfg.KeyDirectory); errors.Is(err, os.ErrNotExist) { - return false - } else if cc.Keybase == nil { - return false - } - return true -} - -// AddKey generates a new mnemonic which is then converted to a private key and BIP-39 HD Path and persists it to the keystore. -// It fails if there is an existing key with the same address. -func (cc *CosmosProvider) AddKey(name string, coinType uint32, signingAlgorithm string) (output *KeyOutput, err error) { - ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm) - if err != nil { - return nil, err - } - return ko, nil -} - -// UseKey Updates config.yaml chain with the specified key. -// It fails config is already using the same key or if the key does not exist -func (cc *CosmosProvider) UseKey(key string) error { - cc.PCfg.Key = key - return nil -} - -// RestoreKey converts a mnemonic to a private key and BIP-39 HD Path and persists it to the keystore. -// It fails if there is an existing key with the same address. -func (cc *CosmosProvider) RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) { - ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm, mnemonic) - if err != nil { - return "", err - } - return ko.Address, nil -} - -// KeyAddOrRestore either generates a new mnemonic or uses the specified mnemonic and converts it to a private key -// and BIP-39 HD Path which is then persisted to the keystore. It fails if there is an existing key with the same address. -func (cc *CosmosProvider) KeyAddOrRestore(keyName string, coinType uint32, signingAlgorithm string, mnemonic ...string) (*KeyOutput, error) { - var mnemonicStr string - var err error - - var algo keyring.SignatureAlgo - switch signingAlgorithm { - case string(hd.Sr25519Type): - algo = sr25519.Sr25519 - default: - algo = hd.Secp256k1 - } - - if len(mnemonic) > 0 { - mnemonicStr = mnemonic[0] - } else { - mnemonicStr, err = CreateMnemonic() - if err != nil { - return nil, err - } - } - - done := SetSDKConfigContext(cc.PCfg.AccountPrefix) - - info, err := cc.Keybase.NewAccount(keyName, mnemonicStr, "", hd.CreateHDPath(coinType, 0, 0).String(), algo) - if err != nil { - return nil, err - } - - done() - - acc, err := info.GetAddress() - if err != nil { - return nil, err - } - - out, err := cc.EncodeBech32AccAddr(acc) - if err != nil { - return nil, err - } - return &KeyOutput{Mnemonic: mnemonicStr, Address: out}, nil -} - -// ShowAddress retrieves a key by name from the keystore and returns the bech32 encoded string representation of that key. -func (cc *CosmosProvider) ShowAddress(name string) (address string, err error) { - info, err := cc.Keybase.Key(name) - if err != nil { - return "", err - } - acc, err := info.GetAddress() - if err != nil { - return "", nil - } - out, err := cc.EncodeBech32AccAddr(acc) - if err != nil { - return "", err - } - return out, nil -} - -// ListAddresses returns a map of bech32 encoded strings representing all keys currently in the keystore. -func (cc *CosmosProvider) ListAddresses() (map[string]string, error) { - out := map[string]string{} - info, err := cc.Keybase.List() - if err != nil { - return nil, err - } - for _, k := range info { - acc, err := k.GetAddress() - if err != nil { - return nil, err - } - addr, err := cc.EncodeBech32AccAddr(acc) - if err != nil { - return nil, err - } - out[k.Name] = addr - } - return out, nil -} - -// DeleteKey removes a key from the keystore for the specified name. -func (cc *CosmosProvider) DeleteKey(name string) error { - if err := cc.Keybase.Delete(name); err != nil { - return err - } - return nil -} - // KeyExists returns true if a key with the specified name exists in the keystore, it returns false otherwise. func (cc *CosmosProvider) KeyExists(name string) bool { k, err := cc.Keybase.Key(name) @@ -180,12 +15,6 @@ func (cc *CosmosProvider) KeyExists(name string) bool { } -// ExportPrivKeyArmor returns a private key in ASCII armored format. -// It returns an error if the key does not exist or a wrong encryption passphrase is supplied. -func (cc *CosmosProvider) ExportPrivKeyArmor(keyName string) (armor string, err error) { - return cc.Keybase.ExportPrivKeyArmor(keyName, ckeys.DefaultKeyPass) -} - // GetKeyAddress returns the account address representation for the currently configured key. func (cc *CosmosProvider) GetKeyAddress(key string) (sdk.AccAddress, error) { info, err := cc.Keybase.Key(key) @@ -195,19 +24,6 @@ func (cc *CosmosProvider) GetKeyAddress(key string) (sdk.AccAddress, error) { return info.GetAddress() } -// CreateMnemonic generates a new mnemonic. -func CreateMnemonic() (string, error) { - entropySeed, err := bip39.NewEntropy(256) - if err != nil { - return "", err - } - mnemonic, err := bip39.NewMnemonic(entropySeed) - if err != nil { - return "", err - } - return mnemonic, nil -} - // EncodeBech32AccAddr returns the string bech32 representation for the specified account address. // It returns an empty sting if the byte slice is 0-length. // It returns an error if the bech32 conversion fails or the prefix is empty. @@ -226,26 +42,3 @@ func (cc *CosmosProvider) GetKeyAddressForKey(key string) (sdk.AccAddress, error } return info.GetAddress() } - -func (cc *CosmosProvider) KeyFromKeyOrAddress(keyOrAddress string) (string, error) { - switch { - case keyOrAddress == "": - return cc.PCfg.Key, nil - case cc.KeyExists(keyOrAddress): - return keyOrAddress, nil - default: - acc, err := cc.DecodeBech32AccAddr(keyOrAddress) - if err != nil { - return "", err - } - - done := SetSDKConfigContext(cc.PCfg.AccountPrefix) - defer done() - - kr, err := cc.Keybase.KeyByAddress(acc) - if err != nil { - return "", err - } - return kr.Name, nil - } -} diff --git a/client/relayer/keys_test.go b/client/relayer/keys_test.go deleted file mode 100644 index 2c1b70c0d..000000000 --- a/client/relayer/keys_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package relayerclient_test - -import ( - relayerclient "github.com/babylonlabs-io/babylon/client/relayer" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/zap" -) - -func testProviderWithKeystore(t *testing.T, accountPrefix string, extraCodecs []string) relayerclient.ChainProvider { - homePath := t.TempDir() - cfg := relayerclient.CosmosProviderConfig{ - ChainID: "test", - KeyDirectory: filepath.Join(homePath, "keys"), - KeyringBackend: "test", - Timeout: "10s", - AccountPrefix: accountPrefix, - ExtraCodecs: extraCodecs, - } - p, err := cfg.NewProvider(zap.NewNop(), homePath, "test_chain") - if err != nil { - t.Fatalf("Error creating provider: %v", err) - } - err = p.CreateKeystore(homePath) - if err != nil { - t.Fatalf("Error creating keystore: %v", err) - } - return p -} - -// TestKeyRestore restores a test mnemonic -func TestKeyRestore(t *testing.T) { - const ( - keyName = "test_key" - signatureAlgorithm = "secp256k1" - mnemonic = "blind master acoustic speak victory lend kiss grab glad help demand hood roast zone lend sponsor level cheap truck kingdom apology token hover reunion" - accountPrefix = "cosmos" - expectedAddress = "cosmos15cw268ckjj2hgq8q3jf68slwjjcjlvxy57je2u" - coinType = uint32(118) - ) - - p := testProviderWithKeystore(t, accountPrefix, nil) - - address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) - require.NoError(t, err) - require.Equal(t, expectedAddress, address) -} - -// TestKeyRestoreEth restores a test mnemonic -func TestKeyRestoreEth(t *testing.T) { - const ( - keyName = "test_key" - signatureAlgorithm = "secp256k1" - mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" - accountPrefix = "evmos" - expectedAddress = "evmos1dea7vlekr9e34vugwkvesulglt8fx4e457vk9z" - coinType = uint32(60) - ) - - p := testProviderWithKeystore(t, accountPrefix, []string{"ethermint"}) - - address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) - require.NoError(t, err) - require.Equal(t, expectedAddress, address) -} - -// TestKeyRestoreInj restores a test mnemonic -func TestKeyRestoreInj(t *testing.T) { - const ( - keyName = "inj_key" - signatureAlgorithm = "secp256k1" - mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" - accountPrefix = "inj" - expectedAddress = "inj1dea7vlekr9e34vugwkvesulglt8fx4e4uk2udj" - coinType = uint32(60) - ) - - p := testProviderWithKeystore(t, accountPrefix, []string{"injective"}) - - address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) - require.NoError(t, err) - require.Equal(t, expectedAddress, address) -} - -// TestKeyRestoreSr25519 restores a test mnemonic -func TestKeyRestoreSr25519(t *testing.T) { - const ( - keyName = "sei_key" - signatureAlgorithm = "sr25519" - mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" - accountPrefix = "sei" - expectedAddress = "sei1th80nzvgkzg7reehtyp4xm39xerqg6z77ymcnx" - coinType = uint32(118) - ) - - p := testProviderWithKeystore(t, accountPrefix, nil) - - address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) - require.NoError(t, err) - require.Equal(t, expectedAddress, address) -} diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 7d8c47065..633372937 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/gogoproto/proto" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/strangelove-ventures/cometbft-client/client" @@ -41,7 +40,6 @@ type CosmosProviderConfig struct { SigningAlgorithm string `json:"signing-algorithm" yaml:"signing-algorithm"` Broadcast BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` MinLoopDuration time.Duration `json:"min-loop-duration" yaml:"min-loop-duration"` - ExtensionOptions []ExtensionOption `json:"extension-options" yaml:"extension-options"` // If FeeGrantConfiguration is set, TXs submitted by the ChainClient will be signed by the FeeGrantees in a round-robin fashion by default. FeeGrants *FeeGrantConfiguration `json:"feegrants" yaml:"feegrants"` @@ -216,15 +214,6 @@ func (cc *CosmosProvider) AccountFromKeyOrAddress(keyOrAddress string) (out sdk. return } -// Sprint returns the json representation of the specified proto message. -func (cc *CosmosProvider) Sprint(toPrint proto.Message) (string, error) { - out, err := cc.Cdc.Marshaller.MarshalJSON(toPrint) - if err != nil { - return "", err - } - return string(out), nil -} - // SetRpcAddr sets the rpc-addr for the chain. // It will fail if the rpcAddr is invalid(not a url). func (cc *CosmosProvider) SetRpcAddr(rpcAddr string) error { @@ -272,39 +261,3 @@ func (cc *CosmosProvider) Init(ctx context.Context) error { return nil } - -// WaitForNBlocks blocks until the next block on a given chain -func (cc *CosmosProvider) WaitForNBlocks(ctx context.Context, n int64) error { - var initial int64 - h, err := cc.RPCClient.Status(ctx) - if err != nil { - return err - } - if h.SyncInfo.CatchingUp { - return fmt.Errorf("chain catching up") - } - initial = h.SyncInfo.LatestBlockHeight - for { - h, err = cc.RPCClient.Status(ctx) - if err != nil { - return err - } - if h.SyncInfo.LatestBlockHeight > initial+n { - return nil - } - select { - case <-time.After(10 * time.Millisecond): - // Nothing to do. - case <-ctx.Done(): - return ctx.Err() - } - } -} - -func (cc *CosmosProvider) BlockTime(ctx context.Context, height int64) (time.Time, error) { - resultBlock, err := cc.RPCClient.Block(ctx, &height) - if err != nil { - return time.Time{}, err - } - return resultBlock.Block.Time, nil -} diff --git a/client/relayer/query.go b/client/relayer/query.go index 2459ef28e..e5abb7bde 100644 --- a/client/relayer/query.go +++ b/client/relayer/query.go @@ -2,8 +2,6 @@ package relayerclient import ( "context" - "encoding/hex" - "errors" "fmt" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" @@ -64,64 +62,6 @@ func (cc *CosmosProvider) QueryUnbondingPeriod(ctx context.Context) (time.Durati fmt.Errorf("failed to query unbonding period from ccvconsumer, staking & fallback : %w: %s : %s", consumerErr, stakingParamsErr.Error(), err.Error()) } -// QueryTx takes a transaction hash and returns the transaction -func (cc *CosmosProvider) QueryTx(ctx context.Context, hashHex string) (*RelayerTxResponse, error) { - hash, err := hex.DecodeString(hashHex) - if err != nil { - return nil, err - } - - resp, err := cc.RPCClient.Tx(ctx, hash, true) - if err != nil { - return nil, err - } - - events := parseEventsFromResponseDeliverTx(resp.TxResult.Events) - - return &RelayerTxResponse{ - Height: resp.Height, - TxHash: string(hash), - Code: resp.TxResult.Code, - Data: string(resp.TxResult.Data), - Events: events, - }, nil -} - -// QueryTxs returns an array of transactions given a tag -func (cc *CosmosProvider) QueryTxs(ctx context.Context, page, limit int, events []string) ([]*RelayerTxResponse, error) { - if len(events) == 0 { - return nil, errors.New("must declare at least one event to search") - } - - if page <= 0 { - return nil, errors.New("page must greater than 0") - } - - if limit <= 0 { - return nil, errors.New("limit must greater than 0") - } - - res, err := cc.RPCClient.TxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") - if err != nil { - return nil, err - } - - // Currently, we only call QueryTxs() in two spots and in both of them we are expecting there to only be, - // at most, one tx in the response. Because of this we don't want to initialize the slice with an initial size. - var txResps []*RelayerTxResponse - for _, tx := range res.Txs { - relayerEvents := parseEventsFromResponseDeliverTx(tx.TxResult.Events) - txResps = append(txResps, &RelayerTxResponse{ - Height: tx.Height, - TxHash: string(tx.Hash), - Code: tx.TxResult.Code, - Data: string(tx.TxResult.Data), - Events: relayerEvents, - }) - } - return txResps, nil -} - // parseEventsFromResponseDeliverTx parses the events from a ResponseDeliverTx and builds a slice // of provider.RelayerEvent's. func parseEventsFromResponseDeliverTx(events []abci.Event) []RelayerEvent { From 28b7931a922c61e71c3f7cfb04f510b5c4a56e27 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 09:37:38 +0100 Subject: [PATCH 06/21] cleanup more --- client/relayer/app_module.go | 46 --------------------------------- client/relayer/codec.go | 3 +-- client/relayer/provider.go | 49 ++++-------------------------------- client/relayer/query.go | 21 ---------------- client/relayer/tx.go | 8 ------ 5 files changed, 6 insertions(+), 121 deletions(-) delete mode 100644 client/relayer/app_module.go diff --git a/client/relayer/app_module.go b/client/relayer/app_module.go deleted file mode 100644 index 163082047..000000000 --- a/client/relayer/app_module.go +++ /dev/null @@ -1,46 +0,0 @@ -package relayerclient - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" - localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" - - tmlightclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" -) - -// AppModuleBasic defines the basic application module used by the module. -type AppModuleBasic struct{} - -// Name returns the module's name. -func (AppModuleBasic) Name() string { - return "cosmos_chain_provider" -} - -// RegisterLegacyAminoCodec does nothing. IBC does not support amino. -func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} - -// RegisterInterfaces registers module concrete types into protobuf Any. -func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { - tmlightclient.RegisterInterfaces(registry) - solomachine.RegisterInterfaces(registry) - localhost.RegisterInterfaces(registry) -} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - panic("not implemented") -} - -// GetTxCmd returns the root tx command for the ibc module. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - panic("not implemented") -} - -// GetQueryCmd returns no root query command for the ibc module. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - panic("not implemented") -} diff --git a/client/relayer/codec.go b/client/relayer/codec.go index 86a32f1d1..58d8b90a9 100644 --- a/client/relayer/codec.go +++ b/client/relayer/codec.go @@ -52,7 +52,6 @@ var ModuleBasics = []module.AppModuleBasic{ upgrade.AppModuleBasic{}, transfer.AppModuleBasic{}, ibc.AppModuleBasic{}, - AppModuleBasic{}, stride.AppModuleBasic{}, ibcfee.AppModuleBasic{}, } @@ -64,7 +63,7 @@ type Codec struct { Amino *codec.LegacyAmino } -func MakeCodec(moduleBasics []module.AppModuleBasic, extraCodecs []string, accBech32Prefix, valBech32Prefix string) Codec { +func MakeCodec(moduleBasics []module.AppModuleBasic, accBech32Prefix, valBech32Prefix string) Codec { modBasic := module.NewBasicManager(moduleBasics...) encodingConfig := MakeCodecConfig(accBech32Prefix, valBech32Prefix) std.RegisterLegacyAminoCodec(encodingConfig.Amino) diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 633372937..60d0919ef 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/strangelove-ventures/cometbft-client/client" "go.uber.org/zap" @@ -68,28 +67,15 @@ type CosmosProvider struct { Keybase keyring.Keyring KeyringOptions []keyring.Option RPCClient RPCClient - //LightProvider provtypes.Provider - Input io.Reader - Output io.Writer - Cdc Codec - - //nextAccountSeq uint64 - feegrantMu sync.Mutex + Input io.Reader + Output io.Writer + Cdc Codec + feegrantMu sync.Mutex // the map key is the TX signer, which can either be 'default' (provider key) or a feegrantee // the purpose of the map is to lock on the signer from TX creation through submission, // thus making TX sequencing errors less likely. walletStateMap map[string]*WalletState - - // metrics to monitor the provider - TotalFees sdk.Coins - totalFeesMu sync.Mutex - - // for comet < v0.37, decode tm events as base64 todo remove this - cometLegacyEncoding bool - - // for comet < v0.38, use legacy RPC client for ResultsBlockResults todo remove this - cometLegacyBlockResults bool } func (pc CosmosProviderConfig) BroadcastMode() BroadcastMode { @@ -125,7 +111,7 @@ func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, cha walletStateMap: map[string]*WalletState{}, // TODO: this is a bit of a hack, we should probably have a better way to inject modules - Cdc: MakeCodec(pc.Modules, pc.ExtraCodecs, pc.AccountPrefix, pc.AccountPrefix+"valoper"), + Cdc: MakeCodec(pc.Modules, pc.AccountPrefix, pc.AccountPrefix+"valoper"), } return cp, nil @@ -167,11 +153,6 @@ func (cc *CosmosProvider) Timeout() string { return cc.PCfg.Timeout } -// CommitmentPrefix returns the commitment prefix for Cosmos -func (cc *CosmosProvider) CommitmentPrefix() commitmenttypes.MerklePrefix { - return defaultChainPrefix -} - // Address returns the chains configured address as a string func (cc *CosmosProvider) Address() (string, error) { info, err := cc.Keybase.Key(cc.PCfg.Key) @@ -200,20 +181,6 @@ func (cc *CosmosProvider) MustEncodeAccAddr(addr sdk.AccAddress) string { return enc } -// AccountFromKeyOrAddress returns an account from either a key or an address. -// If 'keyOrAddress' is the empty string, this returns the default key's address. -func (cc *CosmosProvider) AccountFromKeyOrAddress(keyOrAddress string) (out sdk.AccAddress, err error) { - switch { - case keyOrAddress == "": - out, err = cc.GetKeyAddress(cc.PCfg.Key) - case cc.KeyExists(keyOrAddress): - out, err = cc.GetKeyAddress(keyOrAddress) - default: - out, err = sdk.GetFromBech32(keyOrAddress, cc.PCfg.AccountPrefix) - } - return -} - // SetRpcAddr sets the rpc-addr for the chain. // It will fail if the rpcAddr is invalid(not a url). func (cc *CosmosProvider) SetRpcAddr(rpcAddr string) error { @@ -248,15 +215,9 @@ func (cc *CosmosProvider) Init(ctx context.Context) error { return err } - //lightprovider, err := prov.New(cc.PCfg.ChainID, cc.PCfg.RPCAddr) todo check if needed - //if err != nil { - // return err - //} - rpcClient := NewRPCClient(c) cc.RPCClient = rpcClient - //cc.LightProvider = lightprovider cc.Keybase = keybase return nil diff --git a/client/relayer/query.go b/client/relayer/query.go index e5abb7bde..032f395dd 100644 --- a/client/relayer/query.go +++ b/client/relayer/query.go @@ -3,7 +3,6 @@ package relayerclient import ( "context" "fmt" - abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "strconv" @@ -61,23 +60,3 @@ func (cc *CosmosProvider) QueryUnbondingPeriod(ctx context.Context) (time.Durati return 0, fmt.Errorf("failed to query unbonding period from ccvconsumer, staking & fallback : %w: %s : %s", consumerErr, stakingParamsErr.Error(), err.Error()) } - -// parseEventsFromResponseDeliverTx parses the events from a ResponseDeliverTx and builds a slice -// of provider.RelayerEvent's. -func parseEventsFromResponseDeliverTx(events []abci.Event) []RelayerEvent { - var rlyEvents []RelayerEvent - - for _, event := range events { - attributes := make(map[string]string) - for _, attribute := range event.Attributes { - attributes[attribute.Key] = attribute.Value - } - - rlyEvents = append(rlyEvents, RelayerEvent{ - EventType: event.Type, - Attributes: attributes, - }) - } - - return rlyEvents -} diff --git a/client/relayer/tx.go b/client/relayer/tx.go index ebb63f7dc..07e3dd962 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -29,7 +29,6 @@ import ( "time" "github.com/avast/retry-go/v4" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" ) // Variables used for retries @@ -43,15 +42,8 @@ var ( errUnknown = "unknown" ) -// Default IBC settings -var ( - defaultChainPrefix = commitmenttypes.NewMerklePrefix([]byte("ibc")) -) - // Strings for parsing events var ( - spTag = "send_packet" - waTag = "write_acknowledgement" srcChanTag = "packet_src_channel" dstChanTag = "packet_dst_channel" ) From 095b25e3ccc88f1b92277f8b1c47ceddf4d307bf Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 09:50:53 +0100 Subject: [PATCH 07/21] cleanup more --- client/relayer/broadcast.go | 1 - client/relayer/chain_provider.go | 33 ------ client/relayer/grpc_query.go | 2 +- client/relayer/log.go | 189 ------------------------------- client/relayer/msg.go | 9 -- client/relayer/provider.go | 3 - client/relayer/tx.go | 17 +-- 7 files changed, 3 insertions(+), 251 deletions(-) delete mode 100644 client/relayer/log.go diff --git a/client/relayer/broadcast.go b/client/relayer/broadcast.go index 42605d0e8..4dd2e52f4 100644 --- a/client/relayer/broadcast.go +++ b/client/relayer/broadcast.go @@ -12,7 +12,6 @@ type _err string func (e _err) Error() string { return string(e) } -// todo(lazar) remove this type intoAny interface { AsAny() *codectypes.Any } diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index e42d84647..a7322ad46 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -3,7 +3,6 @@ package relayerclient import ( "context" "go.uber.org/zap" - "go.uber.org/zap/zapcore" ) type BroadcastMode string @@ -38,38 +37,6 @@ type RelayerEvent struct { Attributes map[string]string } -// loggableEvents is an unexported wrapper type for a slice of RelayerEvent, -// to satisfy the zapcore.ArrayMarshaler interface. -type loggableEvents []RelayerEvent - -// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface. -func (e RelayerEvent) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("event_type", e.EventType) - for k, v := range e.Attributes { - enc.AddString("event_attr: "+k, v) - } - return nil -} - -// MarshalLogArray satisfies the zapcore.ArrayMarshaler interface. -func (es loggableEvents) MarshalLogArray(enc zapcore.ArrayEncoder) error { - for _, e := range es { - enc.AppendObject(e) - } - return nil -} - -// MarshalLogObject satisfies the zapcore.ObjectMarshaler interface. -func (r RelayerTxResponse) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddInt64("height", r.Height) - enc.AddString("tx_hash", r.TxHash) - enc.AddString("codespace", r.Codespace) - enc.AddUint32("code", r.Code) - enc.AddString("data", r.Data) - enc.AddArray("events", loggableEvents(r.Events)) - return nil -} - type KeyProvider interface { KeyExists(name string) bool } diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go index eb8fc5ac9..e2c551e13 100644 --- a/client/relayer/grpc_query.go +++ b/client/relayer/grpc_query.go @@ -178,7 +178,7 @@ func (cc *CosmosProvider) TxServiceBroadcast(ctx context.Context, req *tx.Broadc wg.Add(1) - if err := cc.broadcastTx(ctx, req.TxBytes, nil, ctx, blockTimeout, []func(*RelayerTxResponse, error){callback}); err != nil { + if err := cc.broadcastTx(ctx, req.TxBytes, ctx, blockTimeout, []func(*RelayerTxResponse, error){callback}); err != nil { return nil, err } diff --git a/client/relayer/log.go b/client/relayer/log.go deleted file mode 100644 index 12483e1f8..000000000 --- a/client/relayer/log.go +++ /dev/null @@ -1,189 +0,0 @@ -package relayerclient - -import ( - "errors" - "reflect" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - typestx "github.com/cosmos/cosmos-sdk/types/tx" - feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// getChannelsIfPresent scans the events for channel tags -func getChannelsIfPresent(events []RelayerEvent) []zapcore.Field { - channelTags := []string{srcChanTag, dstChanTag} - var fields []zap.Field - - // While a transaction may have multiple messages, we just need to first - // a pair of channels - foundTag := map[string]struct{}{} - - for _, event := range events { - for _, tag := range channelTags { - for attributeKey, attributeValue := range event.Attributes { - if attributeKey == tag { - // Only append the tag once - // TODO: what if they are different? - if _, ok := foundTag[tag]; !ok { - fields = append(fields, zap.String(tag, attributeValue)) - foundTag[tag] = struct{}{} - } - } - } - } - } - return fields -} - -// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data -func (cc *CosmosProvider) LogFailedTx(res *RelayerTxResponse, err error, msgs []RelayerMessage) { - // Include the chain_id - fields := []zapcore.Field{zap.String("chain_id", cc.ChainId())} - - // Extract the channels from the events, if present - if res != nil { - channels := getChannelsIfPresent(res.Events) - fields = append(fields, channels...) - } - fields = append(fields, msgTypesField(msgs)) - - if err != nil { - - if errors.Is(err, chantypes.ErrRedundantTx) { - cc.log.Debug("Redundant message(s)", fields...) - return - } - - // Make a copy since we may continue to the warning - errorFields := append(fields, zap.Error(err)) - cc.log.Error( - "Failed sending cosmos transaction", - errorFields..., - ) - - if res == nil { - return - } - } - - if res.Code != 0 { - if sdkErr := cc.sdkError(res.Codespace, res.Code); err != nil { - fields = append(fields, zap.NamedError("sdk_error", sdkErr)) - } - fields = append(fields, zap.Object("response", res)) - cc.log.Warn( - "Sent transaction but received failure response", - fields..., - ) - } -} - -// LogSuccessTx take the transaction and the messages to create it and logs the appropriate data -func (cc *CosmosProvider) LogSuccessTx(res *sdk.TxResponse, msgs []RelayerMessage) { - // Include the chain_id - fields := []zapcore.Field{zap.String("chain_id", cc.ChainId())} - - // Extract the channels from the events, if present - if res != nil { - events := parseEventsFromTxResponse(res) - fields = append(fields, getChannelsIfPresent(events)...) - } - - // Include the gas used - fields = append(fields, zap.Int64("gas_used", res.GasUsed)) - - // Extract fees and fee_payer if present - cdc := codec.NewProtoCodec(cc.Cdc.InterfaceRegistry) - - var m sdk.Msg - if err := cc.Cdc.InterfaceRegistry.UnpackAny(res.Tx, &m); err == nil { - if tx, ok := m.(*typestx.Tx); ok { - fields = append(fields, zap.Stringer("fees", tx.GetFee())) - if feePayer := getFeePayer(cc.log, cdc, tx); feePayer != "" { - fields = append(fields, zap.String("fee_payer", feePayer)) - } - } else { - cc.log.Debug( - "Failed to convert message to Tx type", - zap.Stringer("type", reflect.TypeOf(m)), - ) - } - } else { - cc.log.Debug("Failed to unpack response Tx into sdk.Msg", zap.Error(err)) - } - - // Include the height, msgType, and tx_hash - fields = append(fields, - zap.Int64("height", res.Height), - msgTypesField(msgs), - zap.String("tx_hash", res.TxHash), - ) - - // Log the successful transaction with fields - cc.log.Info( - "Successful transaction", - fields..., - ) -} - -func msgTypesField(msgs []RelayerMessage) zap.Field { - msgTypes := make([]string, len(msgs)) - for i, m := range msgs { - msgTypes[i] = m.Type() - } - return zap.Strings("msg_types", msgTypes) -} - -// getFeePayer returns the bech32 address of the fee payer of a transaction. -// This uses the fee payer field if set, -// otherwise falls back to the address of whoever signed the first message. -func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string { - payer := tx.AuthInfo.Fee.Payer - if payer != "" { - return payer - } - - switch firstMsg := tx.GetMsgs()[0].(type) { - case *transfertypes.MsgTransfer: - // There is a possible data race around concurrent map access - // in the cosmos sdk when it converts the address from bech32. - // We don't need the address conversion; just the sender is all that - // GetSigners is doing under the hood anyway. - return firstMsg.Sender - case *clienttypes.MsgCreateClient: - // Without this particular special case, there is a panic in ibc-go - // due to the sdk config singleton expecting one bech32 prefix but seeing another. - return firstMsg.Signer - case *clienttypes.MsgUpdateClient: - // Same failure mode as MsgCreateClient. - return firstMsg.Signer - case *clienttypes.MsgUpgradeClient: - return firstMsg.Signer - case *clienttypes.MsgSubmitMisbehaviour: - // Same failure mode as MsgCreateClient. - return firstMsg.Signer - case *feetypes.MsgRegisterPayee: - return firstMsg.Relayer - case *feetypes.MsgRegisterCounterpartyPayee: - return firstMsg.Relayer - case *feetypes.MsgPayPacketFee: - return firstMsg.Signer - case *feetypes.MsgPayPacketFeeAsync: - return firstMsg.PacketFee.RefundAddress - default: - signers, _, err := cdc.GetMsgV1Signers(firstMsg) - if err != nil { - log.Info("Could not get signers for msg when attempting to get the fee payer", zap.Error(err)) - return "" - } - - return string(signers[0]) - } -} diff --git a/client/relayer/msg.go b/client/relayer/msg.go index eec3259f3..bd621e69f 100644 --- a/client/relayer/msg.go +++ b/client/relayer/msg.go @@ -22,15 +22,6 @@ func NewCosmosMessage(msg sdk.Msg, optionalSetSigner func(string)) RelayerMessag } } -func CosmosMsg(rm RelayerMessage) sdk.Msg { - if val, ok := rm.(CosmosMessage); !ok { - fmt.Printf("got data of type %T but wanted provider.CosmosMessage \n", val) - return nil - } else { - return val.Msg - } -} - func CosmosMsgs(rm ...RelayerMessage) []sdk.Msg { sdkMsgs := make([]sdk.Msg, 0) for _, rMsg := range rm { diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 60d0919ef..758808c0b 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -61,8 +61,6 @@ type FeeGrantConfiguration struct { } type CosmosProvider struct { - log *zap.Logger - PCfg CosmosProviderConfig Keybase keyring.Keyring KeyringOptions []keyring.Option @@ -103,7 +101,6 @@ func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, cha } cp := &CosmosProvider{ - log: log, PCfg: pc, KeyringOptions: []keyring.Option{ethermint.EthSecp256k1Option()}, Input: os.Stdin, diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 07e3dd962..d7eea2b88 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -18,7 +18,6 @@ import ( legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" - "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "math" @@ -98,7 +97,6 @@ func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) func (cc *CosmosProvider) broadcastTx( ctx context.Context, // context for tx broadcast tx []byte, // raw tx to be broadcast - msgs []RelayerMessage, // used for logging only asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast asyncTimeout time.Duration, // timeout for waiting for block inclusion asyncCallbacks []func(*RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion @@ -112,26 +110,19 @@ func (cc *CosmosProvider) broadcastTx( // ResultBroadcastTx will be nil. return err } - rlyResp := &RelayerTxResponse{ - TxHash: res.Hash.String(), - Codespace: res.Codespace, - Code: res.Code, - Data: res.Data.String(), - } if isFailed { err = cc.sdkError(res.Codespace, res.Code) if err == nil { err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.Log) } } - cc.LogFailedTx(rlyResp, err, msgs) return err } // TODO: maybe we need to check if the node has tx indexing enabled? // if not, we need to find a new way to block until inclusion in a block - go cc.waitForTx(asyncCtx, res.Hash, msgs, asyncTimeout, asyncCallbacks) + go cc.waitForTx(asyncCtx, res.Hash, asyncTimeout, asyncCallbacks) return nil } @@ -141,13 +132,11 @@ func (cc *CosmosProvider) broadcastTx( func (cc *CosmosProvider) waitForTx( ctx context.Context, txHash []byte, - msgs []RelayerMessage, // used for logging only waitTimeout time.Duration, callbacks []func(*RelayerTxResponse, error), ) { res, err := cc.waitForBlockInclusion(ctx, txHash, waitTimeout) if err != nil { - cc.log.Error("Failed to wait for block inclusion", zap.Error(err)) if len(callbacks) > 0 { for _, cb := range callbacks { // Call each callback in order since waitForTx is already invoked asynchronously @@ -182,7 +171,6 @@ func (cc *CosmosProvider) waitForTx( cb(nil, err) } } - cc.LogFailedTx(rlyResp, nil, msgs) return } @@ -192,7 +180,6 @@ func (cc *CosmosProvider) waitForTx( cb(rlyResp, nil) } } - cc.LogSuccessTx(res, msgs) } // waitForBlockInclusion will wait for a transaction to be included in a block, up to waitTimeout or context cancellation. @@ -370,7 +357,7 @@ func (cc *CosmosProvider) SendMessagesToMempool( return err } - if err := cc.broadcastTx(ctx, txBytes, msgs, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil { + if err := cc.broadcastTx(ctx, txBytes, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil { if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { cc.handleAccountSequenceMismatchError(sequenceGuard, err) } From d1985b89112a1386d6e74130987c1b8b34529675 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 11:15:17 +0100 Subject: [PATCH 08/21] moar cleanup --- client/client/client.go | 4 +- client/relayer/broadcast.go | 17 ------- client/relayer/chain_provider.go | 12 +---- client/relayer/codec.go | 85 -------------------------------- client/relayer/keys.go | 11 ----- client/relayer/provider.go | 20 ++------ client/relayer/query.go | 62 ----------------------- client/relayer/tx.go | 16 ++++-- 8 files changed, 19 insertions(+), 208 deletions(-) delete mode 100644 client/relayer/broadcast.go delete mode 100644 client/relayer/query.go diff --git a/client/client/client.go b/client/client/client.go index ebbcdfd2a..a2657efe9 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -1,7 +1,6 @@ package client import ( - "context" relayerclient "github.com/babylonlabs-io/babylon/client/relayer" "time" @@ -42,7 +41,6 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { } provider, err := cfg.ToCosmosProviderConfig().NewProvider( - zapLogger, "", // TODO: set home path "babylon", ) @@ -67,7 +65,7 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { // NOTE: this will create a RPC client. The RPC client will be used for // submitting txs and making ad hoc queries. It won't create WebSocket // connection with Babylon node - err = cp.Init(context.Background()) + err = cp.Init() if err != nil { return nil, err } diff --git a/client/relayer/broadcast.go b/client/relayer/broadcast.go deleted file mode 100644 index 4dd2e52f4..000000000 --- a/client/relayer/broadcast.go +++ /dev/null @@ -1,17 +0,0 @@ -package relayerclient - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" -) - -const ( - ErrTimeoutAfterWaitingForTxBroadcast _err = "timed out after waiting for tx to get included in the block" -) - -type _err string - -func (e _err) Error() string { return string(e) } - -type intoAny interface { - AsAny() *codectypes.Any -} diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index a7322ad46..bd51999e0 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -2,7 +2,6 @@ package relayerclient import ( "context" - "go.uber.org/zap" ) type BroadcastMode string @@ -13,7 +12,7 @@ const ( ) type ProviderConfig interface { - NewProvider(log *zap.Logger, homepath string, chainName string) (ChainProvider, error) + NewProvider(homepath string, chainName string) (ChainProvider, error) Validate() error BroadcastMode() BroadcastMode } @@ -37,14 +36,8 @@ type RelayerEvent struct { Attributes map[string]string } -type KeyProvider interface { - KeyExists(name string) bool -} - type ChainProvider interface { - KeyProvider - - Init(ctx context.Context) error + Init() error SendMessagesToMempool( ctx context.Context, msgs []RelayerMessage, @@ -52,7 +45,6 @@ type ChainProvider interface { asyncCtx context.Context, asyncCallbacks []func(*RelayerTxResponse, error), ) error - ChainName() string ChainId() string Type() string diff --git a/client/relayer/codec.go b/client/relayer/codec.go index 58d8b90a9..9f1434b18 100644 --- a/client/relayer/codec.go +++ b/client/relayer/codec.go @@ -1,99 +1,14 @@ package relayerclient import ( - feegrant "cosmossdk.io/x/feegrant/module" - "cosmossdk.io/x/tx/signing" - "cosmossdk.io/x/upgrade" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/std" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - authz "github.com/cosmos/cosmos-sdk/x/authz/module" - "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/cosmos/cosmos-sdk/x/crisis" - "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/cosmos/cosmos-sdk/x/gov" - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - "github.com/cosmos/cosmos-sdk/x/mint" - "github.com/cosmos/cosmos-sdk/x/params" - paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" - "github.com/cosmos/cosmos-sdk/x/slashing" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/ibc-go/modules/capability" - ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer" - ibc "github.com/cosmos/ibc-go/v8/modules/core" - - "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" ) -var ModuleBasics = []module.AppModuleBasic{ - auth.AppModuleBasic{}, - authz.AppModuleBasic{}, - bank.AppModuleBasic{}, - capability.AppModuleBasic{}, - gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, - }, - ), - crisis.AppModuleBasic{}, - distribution.AppModuleBasic{}, - feegrant.AppModuleBasic{}, - mint.AppModuleBasic{}, - params.AppModuleBasic{}, - slashing.AppModuleBasic{}, - staking.AppModuleBasic{}, - upgrade.AppModuleBasic{}, - transfer.AppModuleBasic{}, - ibc.AppModuleBasic{}, - stride.AppModuleBasic{}, - ibcfee.AppModuleBasic{}, -} - type Codec struct { InterfaceRegistry types.InterfaceRegistry Marshaller codec.Codec TxConfig client.TxConfig Amino *codec.LegacyAmino } - -func MakeCodec(moduleBasics []module.AppModuleBasic, accBech32Prefix, valBech32Prefix string) Codec { - modBasic := module.NewBasicManager(moduleBasics...) - encodingConfig := MakeCodecConfig(accBech32Prefix, valBech32Prefix) - std.RegisterLegacyAminoCodec(encodingConfig.Amino) - std.RegisterInterfaces(encodingConfig.InterfaceRegistry) - modBasic.RegisterLegacyAminoCodec(encodingConfig.Amino) - modBasic.RegisterInterfaces(encodingConfig.InterfaceRegistry) - - return encodingConfig -} - -func MakeCodecConfig(accBech32Prefix, valBech32Prefix string) Codec { - interfaceRegistry, err := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ - ProtoFiles: proto.HybridResolver, - SigningOptions: signing.Options{ - AddressCodec: address.NewBech32Codec(accBech32Prefix), - ValidatorAddressCodec: address.NewBech32Codec(valBech32Prefix), - }, - }) - if err != nil { - panic(err) - } - marshaller := codec.NewProtoCodec(interfaceRegistry) - - done := SetSDKConfigContext(accBech32Prefix) - defer done() - - return Codec{ - InterfaceRegistry: interfaceRegistry, - Marshaller: marshaller, - TxConfig: tx.NewTxConfig(marshaller, tx.DefaultSignModes), - Amino: codec.NewLegacyAmino(), - } -} diff --git a/client/relayer/keys.go b/client/relayer/keys.go index 8d9c172fd..1a552b137 100644 --- a/client/relayer/keys.go +++ b/client/relayer/keys.go @@ -4,17 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// KeyExists returns true if a key with the specified name exists in the keystore, it returns false otherwise. -func (cc *CosmosProvider) KeyExists(name string) bool { - k, err := cc.Keybase.Key(name) - if err != nil { - return false - } - - return k.Name == name - -} - // GetKeyAddress returns the account address representation for the currently configured key. func (cc *CosmosProvider) GetKeyAddress(key string) (sdk.AccAddress, error) { info, err := cc.Keybase.Key(key) diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 758808c0b..1f5778581 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -1,14 +1,11 @@ package relayerclient import ( - "context" "fmt" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/strangelove-ventures/cometbft-client/client" - "go.uber.org/zap" "io" "os" "path" @@ -44,7 +41,7 @@ type CosmosProviderConfig struct { FeeGrants *FeeGrantConfiguration `json:"feegrants" yaml:"feegrants"` } -// FeeGrantConfiguration By default, TXs will be signed by the feegrantees 'ManagedGrantees' keys in a round robin fashion. +// FeeGrantConfiguration By default, TXs will be signed by the feegrantees 'ManagedGrantees' keys in a round-robin fashion. // Clients can use other signing keys by invoking 'tx.SendMsgsWith' and specifying the signing key. type FeeGrantConfiguration struct { GranteesWanted int `json:"num_grantees" yaml:"num_grantees"` @@ -86,15 +83,13 @@ type WalletState struct { } // NewProvider validates the CosmosProviderConfig, instantiates a ChainClient and then instantiates a CosmosProvider -func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, chainName string) (ChainProvider, error) { +func (pc CosmosProviderConfig) NewProvider(homepath string, chainName string) (ChainProvider, error) { if err := pc.Validate(); err != nil { return nil, err } pc.KeyDirectory = keysDir(homepath, pc.ChainID) - pc.ChainName = chainName - pc.Modules = append([]module.AppModuleBasic{}, ModuleBasics...) if pc.Broadcast == "" { pc.Broadcast = BroadcastModeBatch @@ -102,13 +97,10 @@ func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, cha cp := &CosmosProvider{ PCfg: pc, - KeyringOptions: []keyring.Option{ethermint.EthSecp256k1Option()}, + KeyringOptions: []keyring.Option{}, Input: os.Stdin, Output: os.Stdout, walletStateMap: map[string]*WalletState{}, - - // TODO: this is a bit of a hack, we should probably have a better way to inject modules - Cdc: MakeCodec(pc.Modules, pc.AccountPrefix, pc.AccountPrefix+"valoper"), } return cp, nil @@ -188,7 +180,7 @@ func (cc *CosmosProvider) SetRpcAddr(rpcAddr string) error { // Init initializes the keystore, RPC client, amd light client provider. // Once initialization is complete an attempt to query the underlying node's tendermint version is performed. // NOTE: Init must be called after creating a new instance of CosmosProvider. -func (cc *CosmosProvider) Init(ctx context.Context) error { +func (cc *CosmosProvider) Init() error { keybase, err := keyring.New( cc.PCfg.ChainID, cc.PCfg.KeyringBackend, @@ -212,9 +204,7 @@ func (cc *CosmosProvider) Init(ctx context.Context) error { return err } - rpcClient := NewRPCClient(c) - - cc.RPCClient = rpcClient + cc.RPCClient = NewRPCClient(c) cc.Keybase = keybase return nil diff --git a/client/relayer/query.go b/client/relayer/query.go deleted file mode 100644 index 032f395dd..000000000 --- a/client/relayer/query.go +++ /dev/null @@ -1,62 +0,0 @@ -package relayerclient - -import ( - "context" - "fmt" - "github.com/cosmos/cosmos-sdk/x/params/types/proposal" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "strconv" - "strings" - "time" -) - -func (cc *CosmosProvider) queryParamsSubspaceTime(ctx context.Context, subspace string, key string) (time.Duration, error) { - queryClient := proposal.NewQueryClient(cc) - - params := proposal.QueryParamsRequest{Subspace: subspace, Key: key} - - res, err := queryClient.Params(ctx, ¶ms) - - if err != nil { - return 0, fmt.Errorf("failed to make %s params request: %w", subspace, err) - } - - if res.Param.Value == "" { - return 0, fmt.Errorf("%s %s is empty", subspace, key) - } - - unbondingValue, err := strconv.ParseUint(strings.ReplaceAll(res.Param.Value, `"`, ""), 10, 64) - if err != nil { - return 0, fmt.Errorf("failed to parse %s from %s param: %w", key, subspace, err) - } - - return time.Duration(unbondingValue), nil -} - -// QueryUnbondingPeriod returns the unbonding period of the chain -func (cc *CosmosProvider) QueryUnbondingPeriod(ctx context.Context) (time.Duration, error) { - - // Attempt ICS query - consumerUnbondingPeriod, consumerErr := cc.queryParamsSubspaceTime(ctx, "ccvconsumer", "UnbondingPeriod") - if consumerErr == nil { - return consumerUnbondingPeriod, nil - } - - //Attempt Staking query. - unbondingPeriod, stakingParamsErr := cc.queryParamsSubspaceTime(ctx, "staking", "UnbondingTime") - if stakingParamsErr == nil { - return unbondingPeriod, nil - } - - // Fallback - req := stakingtypes.QueryParamsRequest{} - queryClient := stakingtypes.NewQueryClient(cc) - res, err := queryClient.Params(ctx, &req) - if err == nil { - return res.Params.UnbondingTime, nil - - } - - return 0, - fmt.Errorf("failed to query unbonding period from ccvconsumer, staking & fallback : %w: %s : %s", consumerErr, stakingParamsErr.Error(), err.Error()) -} diff --git a/client/relayer/tx.go b/client/relayer/tx.go index d7eea2b88..fddb4938e 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -11,6 +11,7 @@ import ( coretypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -30,7 +31,6 @@ import ( "github.com/avast/retry-go/v4" ) -// Variables used for retries var ( rtyAttNum = uint(5) rtyAtt = retry.Attempts(rtyAttNum) @@ -41,12 +41,18 @@ var ( errUnknown = "unknown" ) -// Strings for parsing events -var ( - srcChanTag = "packet_src_channel" - dstChanTag = "packet_dst_channel" +const ( + ErrTimeoutAfterWaitingForTxBroadcast _err = "timed out after waiting for tx to get included in the block" ) +type _err string + +func (e _err) Error() string { return string(e) } + +type intoAny interface { + AsAny() *codectypes.Any +} + var seqGuardSingleton sync.Mutex // Gets the sequence guard. If it doesn't exist, initialized and returns it. From 9aca0d2f6c1755cfec5117969fdd1513c3a4b5d5 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 12:01:15 +0100 Subject: [PATCH 09/21] lint fixes --- client/relayer/account.go | 2 +- client/relayer/feegrant.go | 29 ++++++++++++++--------------- client/relayer/grpc_query.go | 1 - client/relayer/msg.go | 4 ++-- client/relayer/tx.go | 36 ++++++++++++++---------------------- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/client/relayer/account.go b/client/relayer/account.go index b9ca8caba..5ff1cc18c 100644 --- a/client/relayer/account.go +++ b/client/relayer/account.go @@ -48,7 +48,7 @@ func (cc *CosmosProvider) GetAccountWithHeight(_ client.Context, addr sdk.AccAdd return nil, 0, fmt.Errorf("failed to parse block height: %w", err) } - var acc authtypes.AccountI + var acc sdk.AccountI if err := cc.Cdc.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { return nil, 0, err } diff --git a/client/relayer/feegrant.go b/client/relayer/feegrant.go index 8d81698a3..0c20bbc59 100644 --- a/client/relayer/feegrant.go +++ b/client/relayer/feegrant.go @@ -2,36 +2,35 @@ package relayerclient // GetTxFeeGrant Get the feegrant params to use for the next TX. If feegrants are not configured for the chain client, the default key will be used for TX signing. // Otherwise, a configured feegrantee will be chosen for TX signing in round-robin fashion. -func (cc *CosmosProvider) GetTxFeeGrant() (txSignerKey string, feeGranterKeyOrAddr string) { - // By default, we should sign TXs with the ChainClient's default key - txSignerKey = cc.PCfg.Key +func (cc *CosmosProvider) GetTxFeeGrant() (string, string) { + // Default values + txSignerKey := cc.PCfg.Key + feeGranterKeyOrAddr := "" if cc.PCfg.FeeGrants == nil { - return + // Fee grants are not configured; use the default key. + return txSignerKey, feeGranterKeyOrAddr } - // Use the ChainClient's configured Feegranter key for the next TX. + // Use the configured Feegranter key for the next TX feeGranterKeyOrAddr = cc.PCfg.FeeGrants.GranterKeyOrAddr - // The ChainClient Feegrant configuration has never been verified on chain. - // Don't use Feegrants as it could cause the TX to fail on chain. + // If the Feegrant configuration has never been verified on chain, avoid using Feegrants. if feeGranterKeyOrAddr == "" || cc.PCfg.FeeGrants.BlockHeightVerified <= 0 { - feeGranterKeyOrAddr = "" - return + return txSignerKey, "" } // Pick the next managed grantee in the list as the TX signer lastGranteeIdx := cc.PCfg.FeeGrants.GranteeLastSignerIndex - - if lastGranteeIdx >= 0 && lastGranteeIdx <= len(cc.PCfg.FeeGrants.ManagedGrantees)-1 { + if lastGranteeIdx >= 0 && lastGranteeIdx < len(cc.PCfg.FeeGrants.ManagedGrantees) { txSignerKey = cc.PCfg.FeeGrants.ManagedGrantees[lastGranteeIdx] - cc.PCfg.FeeGrants.GranteeLastSignerIndex = cc.PCfg.FeeGrants.GranteeLastSignerIndex + 1 + cc.PCfg.FeeGrants.GranteeLastSignerIndex++ - // Restart the round-robin at 0 if we reached the end of the list of grantees - if cc.PCfg.FeeGrants.GranteeLastSignerIndex == len(cc.PCfg.FeeGrants.ManagedGrantees) { + // Restart the round-robin if we reached the end of the list of grantees + if cc.PCfg.FeeGrants.GranteeLastSignerIndex >= len(cc.PCfg.FeeGrants.ManagedGrantees) { cc.PCfg.FeeGrants.GranteeLastSignerIndex = 0 } } - return + return txSignerKey, feeGranterKeyOrAddr } diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go index e2c551e13..28d8422e2 100644 --- a/client/relayer/grpc_query.go +++ b/client/relayer/grpc_query.go @@ -111,7 +111,6 @@ func (cc *CosmosProvider) RunGRPCQuery(ctx context.Context, method string, req i legacyerrors.ErrInvalidRequest, "client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader) } - } height, err := GetHeightFromMetadata(md) diff --git a/client/relayer/msg.go b/client/relayer/msg.go index bd621e69f..21c143ed7 100644 --- a/client/relayer/msg.go +++ b/client/relayer/msg.go @@ -11,8 +11,8 @@ import ( type CosmosMessage struct { Msg sdk.Msg - SetSigner func(string) //callback to update the Msg Signer field - FeegrantDisabled bool //marks whether this message type should ALWAYS disable feegranting (use the default signer) + SetSigner func(string) // callback to update the Msg Signer field + FeegrantDisabled bool // marks whether this message type should ALWAYS disable feegranting (use the default signer) } func NewCosmosMessage(msg sdk.Msg, optionalSetSigner func(string)) RelayerMessage { diff --git a/client/relayer/tx.go b/client/relayer/tx.go index fddb4938e..dafdf8ce1 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -13,7 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -182,7 +181,7 @@ func (cc *CosmosProvider) waitForTx( if len(callbacks) > 0 { for _, cb := range callbacks { - //Call each callback in order since waitForTx is already invoked asyncronously + // Call each callback in order since waitForTx is already invoked asyncronously cb(rlyResp, nil) } } @@ -382,18 +381,13 @@ func (cc *CosmosProvider) updateNextAccountSequence(sequenceGuard *WalletState, } } -func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) ( - txSignerKey string, - feegranterKeyOrAddr string, - err error, -) { +func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) (string, string, error) { // Guard against race conditions when choosing a signer/feegranter cc.feegrantMu.Lock() defer cc.feegrantMu.Unlock() - // Some messages have feegranting disabled. If any message in the TX disables feegrants, then the TX will not be feegranted. + // Check if fee grants are eligible isFeegrantEligible := cc.PCfg.FeeGrants != nil - for _, curr := range msgs { if cMsg, ok := curr.(CosmosMessage); ok { if cMsg.FeegrantDisabled { @@ -402,34 +396,32 @@ func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) ( } } - // By default, we should sign TXs with the provider's default key - txSignerKey = cc.PCfg.Key + // Default signer key + txSignerKey := cc.PCfg.Key + feegranterKeyOrAddr := "" if isFeegrantEligible { txSignerKey, feegranterKeyOrAddr = cc.GetTxFeeGrant() + signerAcc, addrErr := cc.GetKeyAddressForKey(txSignerKey) if addrErr != nil { - err = addrErr - return + return "", "", addrErr } signerAccAddr, encodeErr := cc.EncodeBech32AccAddr(signerAcc) if encodeErr != nil { - err = encodeErr - return + return "", "", encodeErr } - // Overwrite the 'Signer' field in any Msgs that provide an 'optionalSetSigner' callback + // Update the 'Signer' field in any Msgs that provide an 'optionalSetSigner' callback for _, curr := range msgs { - if cMsg, ok := curr.(CosmosMessage); ok { - if cMsg.SetSigner != nil { - cMsg.SetSigner(signerAccAddr) - } + if cMsg, ok := curr.(CosmosMessage); ok && cMsg.SetSigner != nil { + cMsg.SetSigner(signerAccAddr) } } } - return + return txSignerKey, feegranterKeyOrAddr, nil } func (cc *CosmosProvider) buildMessages( @@ -665,7 +657,7 @@ func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte, return nil, err } - var pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type + var pk cryptotypes.PubKey // use default public key type pk, err = info.GetPubKey() if err != nil { From 44182cdd861753b4d9961d3edd4b74016ab45502 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 12:23:19 +0100 Subject: [PATCH 10/21] handling nil derefs --- client/relayer/tx.go | 75 +++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/client/relayer/tx.go b/client/relayer/tx.go index dafdf8ce1..5409ae6df 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -100,10 +100,10 @@ func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) // The wait will end after either the asyncTimeout has run out or the asyncCtx exits. // If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion. func (cc *CosmosProvider) broadcastTx( - ctx context.Context, // context for tx broadcast - tx []byte, // raw tx to be broadcast - asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast - asyncTimeout time.Duration, // timeout for waiting for block inclusion + ctx context.Context, // context for tx broadcast + tx []byte, // raw tx to be broadcast + asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast + asyncTimeout time.Duration, // timeout for waiting for block inclusion asyncCallbacks []func(*RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion ) error { res, err := cc.RPCClient.BroadcastTxSync(ctx, tx) @@ -116,17 +116,19 @@ func (cc *CosmosProvider) broadcastTx( return err } if isFailed { - err = cc.sdkError(res.Codespace, res.Code) - if err == nil { + if err = cc.sdkError(res.Codespace, res.Code); err == nil { err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.Log) } } return err } + if res == nil { + return fmt.Errorf("unexpected nil response from BroadcastTxSync") + } + // TODO: maybe we need to check if the node has tx indexing enabled? // if not, we need to find a new way to block until inclusion in a block - go cc.waitForTx(asyncCtx, res.Hash, asyncTimeout, asyncCallbacks) return nil @@ -160,10 +162,8 @@ func (cc *CosmosProvider) waitForTx( Events: parseEventsFromTxResponse(res), } - // transaction was executed, log the success or failure using the tx response code // NOTE: error is nil, logic should use the returned error to determine if the // transaction was successfully executed. - if res.Code != 0 { // Check for any registered SDK errors err := cc.sdkError(res.Codespace, res.Code) @@ -181,7 +181,7 @@ func (cc *CosmosProvider) waitForTx( if len(callbacks) > 0 { for _, cb := range callbacks { - // Call each callback in order since waitForTx is already invoked asyncronously + // Call each callback in order since waitForTx is already invoked asynchronously cb(rlyResp, nil) } } @@ -215,18 +215,17 @@ func (cc *CosmosProvider) waitForBlockInclusion( // mkTxResult decodes a comet transaction into an SDK TxResponse. func (cc *CosmosProvider) mkTxResult(resTx *coretypes.ResultTx) (*sdk.TxResponse, error) { - txbz, err := cc.Cdc.TxConfig.TxDecoder()(resTx.Tx) + txBz, err := cc.Cdc.TxConfig.TxDecoder()(resTx.Tx) if err != nil { return nil, err } - p, ok := txbz.(intoAny) + p, ok := txBz.(intoAny) if !ok { - return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txbz) + return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txBz) } - any := p.AsAny() - return sdk.NewResponseResultTx(resTx, any, ""), nil + return sdk.NewResponseResultTx(resTx, p.AsAny(), ""), nil } func sdkErrorToGRPCError(resp abci.ResponseQuery) error { @@ -242,8 +241,8 @@ func sdkErrorToGRPCError(resp abci.ResponseQuery) error { } } -// isQueryStoreWithProof expects a format like /// -// queryType must be "store" and subpath must be "key" to require a proof. +// isQueryStoreWithProof expects a format like /// +// queryType must be "store" and subPath must be "key" to require a proof. func isQueryStoreWithProof(path string) bool { if !strings.HasPrefix(path, "/") { return false @@ -263,11 +262,15 @@ func isQueryStoreWithProof(path string) bool { return false } -// sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil. -func (cc *CosmosProvider) sdkError(codespace string, code uint32) error { - // ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace +// sdkError will return the Cosmos SDK registered error for a given codeSpace/code combo if registered, otherwise nil. +func (cc *CosmosProvider) sdkError(codeSpace string, code uint32) error { + // ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.CodeSpace // This catches all the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go - err := errors.Unwrap(sdkerrors.ABCIError(codespace, code, "error broadcasting transaction")) + err := errors.Unwrap(sdkerrors.ABCIError(codeSpace, code, "error broadcasting transaction")) + if err == nil { + return nil + } + if err.Error() != errUnknown { return err } @@ -343,7 +346,7 @@ func (cc *CosmosProvider) SendMessagesToMempool( asyncCtx context.Context, asyncCallbacks []func(*RelayerTxResponse, error), ) error { - txSignerKey, feegranterKeyOrAddr, err := cc.buildSignerConfig(msgs) + txSignerKey, feeGranterKeyOrAddr, err := cc.buildSignerConfig(msgs) if err != nil { return err } @@ -352,7 +355,7 @@ func (cc *CosmosProvider) SendMessagesToMempool( sequenceGuard.Mu.Lock() defer sequenceGuard.Mu.Unlock() - txBytes, sequence, _, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feegranterKeyOrAddr, sequenceGuard) + txBytes, sequence, _, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feeGranterKeyOrAddr, sequenceGuard) if err != nil { // Account sequence mismatch errors can happen on the simulated transaction also. if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { @@ -382,26 +385,26 @@ func (cc *CosmosProvider) updateNextAccountSequence(sequenceGuard *WalletState, } func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) (string, string, error) { - // Guard against race conditions when choosing a signer/feegranter + // Guard against race conditions when choosing a signer/feeGranter cc.feegrantMu.Lock() defer cc.feegrantMu.Unlock() // Check if fee grants are eligible - isFeegrantEligible := cc.PCfg.FeeGrants != nil + isFeeGrantEligible := cc.PCfg.FeeGrants != nil for _, curr := range msgs { if cMsg, ok := curr.(CosmosMessage); ok { if cMsg.FeegrantDisabled { - isFeegrantEligible = false + isFeeGrantEligible = false } } } // Default signer key txSignerKey := cc.PCfg.Key - feegranterKeyOrAddr := "" + feeGranterKeyOrAddr := "" - if isFeegrantEligible { - txSignerKey, feegranterKeyOrAddr = cc.GetTxFeeGrant() + if isFeeGrantEligible { + txSignerKey, feeGranterKeyOrAddr = cc.GetTxFeeGrant() signerAcc, addrErr := cc.GetKeyAddressForKey(txSignerKey) if addrErr != nil { @@ -421,7 +424,7 @@ func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) (string, stri } } - return txSignerKey, feegranterKeyOrAddr, nil + return txSignerKey, feeGranterKeyOrAddr, nil } func (cc *CosmosProvider) buildMessages( @@ -430,7 +433,7 @@ func (cc *CosmosProvider) buildMessages( memo string, gas uint64, txSignerKey string, - feegranterKeyOrAddr string, + feeGranterKeyOrAddr string, sequenceGuard *WalletState, ) ( txBytes []byte, @@ -459,16 +462,16 @@ func (cc *CosmosProvider) buildMessages( txf = txf.WithSequence(sequence) } - // Cannot feegrant your own TX - if txSignerKey != feegranterKeyOrAddr && feegranterKeyOrAddr != "" { + // Cannot feeGrant your own TX + if txSignerKey != feeGranterKeyOrAddr && feeGranterKeyOrAddr != "" { var granterAddr sdk.AccAddress if cc.PCfg.FeeGrants != nil && cc.PCfg.FeeGrants.IsExternalGranter { - granterAddr, err = cc.DecodeBech32AccAddr(feegranterKeyOrAddr) + granterAddr, err = cc.DecodeBech32AccAddr(feeGranterKeyOrAddr) if err != nil { return nil, 0, sdk.Coins{}, err } } else { - granterAddr, err = cc.GetKeyAddressForKey(feegranterKeyOrAddr) + granterAddr, err = cc.GetKeyAddressForKey(feeGranterKeyOrAddr) if err != nil { return nil, 0, sdk.Coins{}, err } @@ -665,7 +668,7 @@ func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte, } // Create an empty signature literal as the ante handler will populate with a - // sentinel pubkey. + // sentinel pubKey. sig := signing.SignatureV2{ PubKey: pk, Data: &signing.SingleSignatureData{ From 7313371295dae342f3b077e8d08b146dc2f9b7f6 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 12:36:02 +0100 Subject: [PATCH 11/21] changelog --- CHANGELOG.md | 1 + client/relayer/tx.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 640e97b40..6d05b4a36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [#391](https://github.com/babylonlabs-io/babylon/pull/391) Fix e2e `TestBTCRewardsDistribution` flunky check of rewards - [#419](https://github.com/babylonlabs-io/babylon/pull/419) Add new modules to swagger config +- [#429](https://github.com/babylonlabs-io/babylon/pull/429) chore: remove cosmos/relayer dependency ### Bug fixes diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 5409ae6df..8cc91013d 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -100,10 +100,10 @@ func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) // The wait will end after either the asyncTimeout has run out or the asyncCtx exits. // If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion. func (cc *CosmosProvider) broadcastTx( - ctx context.Context, // context for tx broadcast - tx []byte, // raw tx to be broadcast - asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast - asyncTimeout time.Duration, // timeout for waiting for block inclusion + ctx context.Context, // context for tx broadcast + tx []byte, // raw tx to be broadcast + asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast + asyncTimeout time.Duration, // timeout for waiting for block inclusion asyncCallbacks []func(*RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion ) error { res, err := cc.RPCClient.BroadcastTxSync(ctx, tx) From 9bab3f4e4ff1a79d4823721f100d3188b7ae0cc1 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 14:00:42 +0100 Subject: [PATCH 12/21] rm fee grant --- client/relayer/chain_provider.go | 1 - client/relayer/feegrant.go | 36 ---------------- client/relayer/msg.go | 5 +-- client/relayer/provider.go | 6 +-- client/relayer/tx.go | 70 +------------------------------- 5 files changed, 5 insertions(+), 113 deletions(-) delete mode 100644 client/relayer/feegrant.go diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index bd51999e0..6656bc6e8 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -47,7 +47,6 @@ type ChainProvider interface { ) error ChainName() string ChainId() string - Type() string ProviderConfig() ProviderConfig Key() string Address() (string, error) diff --git a/client/relayer/feegrant.go b/client/relayer/feegrant.go deleted file mode 100644 index 0c20bbc59..000000000 --- a/client/relayer/feegrant.go +++ /dev/null @@ -1,36 +0,0 @@ -package relayerclient - -// GetTxFeeGrant Get the feegrant params to use for the next TX. If feegrants are not configured for the chain client, the default key will be used for TX signing. -// Otherwise, a configured feegrantee will be chosen for TX signing in round-robin fashion. -func (cc *CosmosProvider) GetTxFeeGrant() (string, string) { - // Default values - txSignerKey := cc.PCfg.Key - feeGranterKeyOrAddr := "" - - if cc.PCfg.FeeGrants == nil { - // Fee grants are not configured; use the default key. - return txSignerKey, feeGranterKeyOrAddr - } - - // Use the configured Feegranter key for the next TX - feeGranterKeyOrAddr = cc.PCfg.FeeGrants.GranterKeyOrAddr - - // If the Feegrant configuration has never been verified on chain, avoid using Feegrants. - if feeGranterKeyOrAddr == "" || cc.PCfg.FeeGrants.BlockHeightVerified <= 0 { - return txSignerKey, "" - } - - // Pick the next managed grantee in the list as the TX signer - lastGranteeIdx := cc.PCfg.FeeGrants.GranteeLastSignerIndex - if lastGranteeIdx >= 0 && lastGranteeIdx < len(cc.PCfg.FeeGrants.ManagedGrantees) { - txSignerKey = cc.PCfg.FeeGrants.ManagedGrantees[lastGranteeIdx] - cc.PCfg.FeeGrants.GranteeLastSignerIndex++ - - // Restart the round-robin if we reached the end of the list of grantees - if cc.PCfg.FeeGrants.GranteeLastSignerIndex >= len(cc.PCfg.FeeGrants.ManagedGrantees) { - cc.PCfg.FeeGrants.GranteeLastSignerIndex = 0 - } - } - - return txSignerKey, feeGranterKeyOrAddr -} diff --git a/client/relayer/msg.go b/client/relayer/msg.go index 21c143ed7..b73890b88 100644 --- a/client/relayer/msg.go +++ b/client/relayer/msg.go @@ -10,9 +10,8 @@ import ( ) type CosmosMessage struct { - Msg sdk.Msg - SetSigner func(string) // callback to update the Msg Signer field - FeegrantDisabled bool // marks whether this message type should ALWAYS disable feegranting (use the default signer) + Msg sdk.Msg + SetSigner func(string) // callback to update the Msg Signer field } func NewCosmosMessage(msg sdk.Msg, optionalSetSigner func(string)) RelayerMessage { diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 1f5778581..e487d0029 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -67,7 +67,7 @@ type CosmosProvider struct { Cdc Codec feegrantMu sync.Mutex - // the map key is the TX signer, which can either be 'default' (provider key) or a feegrantee + // the map key is the TX signer (provider key) // the purpose of the map is to lock on the signer from TX creation through submission, // thus making TX sequencing errors less likely. walletStateMap map[string]*WalletState @@ -130,10 +130,6 @@ func (cc *CosmosProvider) ChainName() string { return cc.PCfg.ChainName } -func (cc *CosmosProvider) Type() string { - return "cosmos" -} - func (cc *CosmosProvider) Key() string { return cc.PCfg.Key } diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 8cc91013d..3a645e836 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -342,20 +342,16 @@ func (cc *CosmosProvider) SendMessagesToMempool( ctx context.Context, msgs []RelayerMessage, memo string, - asyncCtx context.Context, asyncCallbacks []func(*RelayerTxResponse, error), ) error { - txSignerKey, feeGranterKeyOrAddr, err := cc.buildSignerConfig(msgs) - if err != nil { - return err - } + txSignerKey := cc.PCfg.Key sequenceGuard := ensureSequenceGuard(cc, txSignerKey) sequenceGuard.Mu.Lock() defer sequenceGuard.Mu.Unlock() - txBytes, sequence, _, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, feeGranterKeyOrAddr, sequenceGuard) + txBytes, sequence, _, err := cc.buildMessages(ctx, msgs, memo, 0, txSignerKey, sequenceGuard) if err != nil { // Account sequence mismatch errors can happen on the simulated transaction also. if strings.Contains(err.Error(), legacyerrors.ErrWrongSequence.Error()) { @@ -384,56 +380,12 @@ func (cc *CosmosProvider) updateNextAccountSequence(sequenceGuard *WalletState, } } -func (cc *CosmosProvider) buildSignerConfig(msgs []RelayerMessage) (string, string, error) { - // Guard against race conditions when choosing a signer/feeGranter - cc.feegrantMu.Lock() - defer cc.feegrantMu.Unlock() - - // Check if fee grants are eligible - isFeeGrantEligible := cc.PCfg.FeeGrants != nil - for _, curr := range msgs { - if cMsg, ok := curr.(CosmosMessage); ok { - if cMsg.FeegrantDisabled { - isFeeGrantEligible = false - } - } - } - - // Default signer key - txSignerKey := cc.PCfg.Key - feeGranterKeyOrAddr := "" - - if isFeeGrantEligible { - txSignerKey, feeGranterKeyOrAddr = cc.GetTxFeeGrant() - - signerAcc, addrErr := cc.GetKeyAddressForKey(txSignerKey) - if addrErr != nil { - return "", "", addrErr - } - - signerAccAddr, encodeErr := cc.EncodeBech32AccAddr(signerAcc) - if encodeErr != nil { - return "", "", encodeErr - } - - // Update the 'Signer' field in any Msgs that provide an 'optionalSetSigner' callback - for _, curr := range msgs { - if cMsg, ok := curr.(CosmosMessage); ok && cMsg.SetSigner != nil { - cMsg.SetSigner(signerAccAddr) - } - } - } - - return txSignerKey, feeGranterKeyOrAddr, nil -} - func (cc *CosmosProvider) buildMessages( ctx context.Context, msgs []RelayerMessage, memo string, gas uint64, txSignerKey string, - feeGranterKeyOrAddr string, sequenceGuard *WalletState, ) ( txBytes []byte, @@ -462,24 +414,6 @@ func (cc *CosmosProvider) buildMessages( txf = txf.WithSequence(sequence) } - // Cannot feeGrant your own TX - if txSignerKey != feeGranterKeyOrAddr && feeGranterKeyOrAddr != "" { - var granterAddr sdk.AccAddress - if cc.PCfg.FeeGrants != nil && cc.PCfg.FeeGrants.IsExternalGranter { - granterAddr, err = cc.DecodeBech32AccAddr(feeGranterKeyOrAddr) - if err != nil { - return nil, 0, sdk.Coins{}, err - } - } else { - granterAddr, err = cc.GetKeyAddressForKey(feeGranterKeyOrAddr) - if err != nil { - return nil, 0, sdk.Coins{}, err - } - } - - txf = txf.WithFeeGranter(granterAddr) - } - adjusted := gas if gas == 0 { From 3742371f7c5b53c0f784a1c17c98463e39894bc3 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 14:23:26 +0100 Subject: [PATCH 13/21] lint fixes --- client/relayer/provider.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/relayer/provider.go b/client/relayer/provider.go index e487d0029..54b3dff4c 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -65,7 +65,6 @@ type CosmosProvider struct { Input io.Reader Output io.Writer Cdc Codec - feegrantMu sync.Mutex // the map key is the TX signer (provider key) // the purpose of the map is to lock on the signer from TX creation through submission, From c9ee3bc45031b5767cc0b00e1ac13c6f2893fcee Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 15:47:17 +0100 Subject: [PATCH 14/21] update gomod --- go.mod | 13 ++----------- go.sum | 50 -------------------------------------------------- 2 files changed, 2 insertions(+), 61 deletions(-) diff --git a/go.mod b/go.mod index 4dfae8240..62291ab81 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 github.com/cosmos/cosmos-sdk v0.50.11 github.com/cosmos/ibc-go/modules/light-clients/08-wasm v0.0.0-20240429153234-e1e6da7e4ead - github.com/cosmos/relayer/v2 v2.5.3 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/pkg/errors v0.9.1 @@ -61,6 +60,7 @@ require ( github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b github.com/ory/dockertest/v3 v3.9.1 github.com/otiai10/copy v1.14.0 + github.com/strangelove-ventures/cometbft-client v0.1.1 github.com/vulpine-io/io-test v1.0.0 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 @@ -159,13 +159,10 @@ require ( github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd // indirect github.com/cosmos/ics23/go v0.11.0 // indirect - github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/creachadair/atomicfile v0.3.1 // indirect github.com/creachadair/tomledit v0.0.24 // indirect github.com/danieljoos/wincred v1.1.2 // indirect @@ -177,13 +174,12 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/dot v1.6.2 // indirect - github.com/ethereum/c-kzg-4844 v0.4.0 // indirect - github.com/ethereum/go-ethereum v1.13.14 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -203,7 +199,6 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -215,7 +210,6 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect @@ -231,10 +225,8 @@ require ( github.com/shamaton/msgpack/v2 v2.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/strangelove-ventures/cometbft-client v0.1.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tidwall/btree v1.7.0 // indirect - github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -257,7 +249,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect pgregory.net/rapid v1.1.0 // indirect - rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 26ff7cc0c..1c06b05c5 100644 --- a/go.sum +++ b/go.sum @@ -241,10 +241,6 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= @@ -372,10 +368,6 @@ github.com/cometbft/cometbft v0.38.15 h1:5veFd8k1uXM27PBg9sMO3hAfRJ3vbh4OmmLf6cV github.com/cometbft/cometbft v0.38.15/go.mod h1:+wh6ap6xctVG+JOHwbl8pPKZ0GeqdPYqISu7F4b43cQ= github.com/cometbft/cometbft-db v0.15.0 h1:VLtsRt8udD4jHCyjvrsTBpgz83qne5hnL245AcPJVRk= github.com/cometbft/cometbft-db v0.15.0/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -413,14 +405,8 @@ github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= -github.com/cosmos/relayer/v2 v2.5.3 h1:Cuhp4MZ8OwWtGf4/UU4HqpEdEDkCvd42uHvY5MK5MpE= -github.com/cosmos/relayer/v2 v2.5.3/go.mod h1:4N4Dd42G1sKd7zUqOonrGPC2xgdY59T8KevjKodoLUI= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= -github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= -github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= -github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/atomicfile v0.3.1 h1:yQORkHjSYySh/tv5th1dkKcn02NEW5JleB84sjt+W4Q= github.com/creachadair/atomicfile v0.3.1/go.mod h1:mwfrkRxFKwpNAflYZzytbSwxvbK6fdGRRlp0KEQc0qU= github.com/creachadair/tomledit v0.0.24 h1:5Xjr25R2esu1rKCbQEmjZYlrhFkDspoAbAKb6QKQDhQ= @@ -484,10 +470,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= -github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.14 h1:EwiY3FZP94derMCIam1iW4HFVrSgIcpsu0HwTQtm6CQ= -github.com/ethereum/go-ethereum v1.13.14/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= @@ -504,8 +486,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= -github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -537,8 +517,6 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -566,8 +544,6 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -669,7 +645,6 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -766,10 +741,6 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= -github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -840,8 +811,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -871,8 +840,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= @@ -890,9 +857,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -928,8 +892,6 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -1026,8 +988,6 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1053,8 +1013,6 @@ github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6v github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= -github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -1117,14 +1075,8 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= -github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -1834,8 +1786,6 @@ pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From 0ba6efc2e7c3c0532315d4098be5f26e66e82fb6 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 20:33:43 +0100 Subject: [PATCH 15/21] remove strangelove dep, use cmt client --- client/relayer/client_wrapper.go | 508 ++----------------------------- client/relayer/provider.go | 4 +- go.mod | 1 - 3 files changed, 20 insertions(+), 493 deletions(-) diff --git a/client/relayer/client_wrapper.go b/client/relayer/client_wrapper.go index d350cebc4..48f99ef5b 100644 --- a/client/relayer/client_wrapper.go +++ b/client/relayer/client_wrapper.go @@ -2,57 +2,22 @@ package relayerclient import ( "context" - - "github.com/cometbft/cometbft/abci/types" - cometcrypto "github.com/cometbft/cometbft/crypto" - ced25519 "github.com/cometbft/cometbft/crypto/ed25519" - "github.com/cometbft/cometbft/crypto/merkle" - csecp256k1 "github.com/cometbft/cometbft/crypto/secp256k1" - csr25519 "github.com/cometbft/cometbft/crypto/sr25519" "github.com/cometbft/cometbft/libs/bytes" - "github.com/cometbft/cometbft/p2p" - "github.com/cometbft/cometbft/proto/tendermint/crypto" rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sltypes "github.com/strangelove-ventures/cometbft-client/abci/types" - "github.com/strangelove-ventures/cometbft-client/client" - slcrypto "github.com/strangelove-ventures/cometbft-client/crypto" - "github.com/strangelove-ventures/cometbft-client/crypto/ed25519" - "github.com/strangelove-ventures/cometbft-client/crypto/secp256k1" - "github.com/strangelove-ventures/cometbft-client/crypto/sr25519" - slbytes "github.com/strangelove-ventures/cometbft-client/libs/bytes" - slclient "github.com/strangelove-ventures/cometbft-client/rpc/client" - coretypes2 "github.com/strangelove-ventures/cometbft-client/rpc/core/types" - types2 "github.com/strangelove-ventures/cometbft-client/types" ) -// RPCClient wraps our slimmed down CometBFT client and converts the returned types to the upstream CometBFT types. -// This is useful so that it can be used in any function calls that expect the upstream types. type RPCClient struct { - c *client.Client + c rpcclient.Client } -func NewRPCClient(c *client.Client) RPCClient { +func NewRPCClient(c rpcclient.Client) RPCClient { return RPCClient{c: c} } func (r RPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { - res, err := r.c.ABCIInfo(ctx) - if err != nil { - return nil, err - } - - return &coretypes.ResultABCIInfo{ - Response: types.ResponseInfo{ - Data: res.Response.Data, - Version: res.Response.Version, - AppVersion: res.Response.AppVersion, - LastBlockHeight: res.Response.LastBlockHeight, - LastBlockAppHash: res.Response.LastBlockAppHash, - }, - }, nil + return r.c.ABCIInfo(ctx) } func (r RPCClient) ABCIQuery( @@ -60,12 +25,7 @@ func (r RPCClient) ABCIQuery( path string, data bytes.HexBytes, ) (*coretypes.ResultABCIQuery, error) { - res, err := r.c.ABCIQuery(ctx, path, slbytes.HexBytes(data)) - if err != nil { - return nil, err - } - - return convertResultABCIQuery(res), nil + return r.c.ABCIQuery(ctx, path, (data)) } func (r RPCClient) ABCIQueryWithOptions( @@ -74,79 +34,19 @@ func (r RPCClient) ABCIQueryWithOptions( data bytes.HexBytes, opts rpcclient.ABCIQueryOptions, ) (*coretypes.ResultABCIQuery, error) { - o := slclient.ABCIQueryOptions{ - Height: opts.Height, - Prove: opts.Prove, - } - - res, err := r.c.ABCIQueryWithOptions(ctx, path, slbytes.HexBytes(data), o) - if err != nil { - return nil, err - } - - return convertResultABCIQuery(res), nil + return r.c.ABCIQueryWithOptions(ctx, path, data, opts) } func (r RPCClient) BroadcastTxCommit(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { - res, err := r.c.BroadcastTxCommit(ctx, types2.Tx(tx)) - if err != nil { - return nil, err - } - - return &coretypes.ResultBroadcastTxCommit{ - CheckTx: types.ResponseCheckTx{ - Code: res.CheckTx.Code, - Data: res.CheckTx.Data, - Log: res.CheckTx.Log, - Info: res.CheckTx.Info, - GasWanted: res.CheckTx.GasWanted, - GasUsed: res.CheckTx.GasUsed, - Events: convertEvents(res.CheckTx.Events), - Codespace: res.CheckTx.Codespace, - }, - TxResult: types.ExecTxResult{ - Code: res.TxResult.Code, - Data: res.TxResult.Data, - Log: res.TxResult.Log, - Info: res.TxResult.Info, - GasWanted: res.TxResult.GasWanted, - GasUsed: res.TxResult.GasUsed, - Events: convertEvents(res.TxResult.Events), - Codespace: res.TxResult.Codespace, - }, - Hash: bytes.HexBytes(res.Hash), - Height: res.Height, - }, nil + return r.c.BroadcastTxCommit(ctx, tx) } func (r RPCClient) BroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { - res, err := r.c.BroadcastTxAsync(ctx, types2.Tx(tx)) - if err != nil { - return nil, err - } - - return &coretypes.ResultBroadcastTx{ - Code: res.Code, - Data: bytes.HexBytes(res.Data), - Log: res.Log, - Codespace: res.Codespace, - Hash: bytes.HexBytes(res.Hash), - }, nil + return r.c.BroadcastTxAsync(ctx, tx) } func (r RPCClient) BroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { - res, err := r.c.BroadcastTxSync(ctx, types2.Tx(tx)) - if err != nil { - return nil, err - } - - return &coretypes.ResultBroadcastTx{ - Code: res.Code, - Data: bytes.HexBytes(res.Data), - Log: res.Log, - Codespace: res.Codespace, - Hash: bytes.HexBytes(res.Hash), - }, nil + return r.c.BroadcastTxSync(ctx, tx) } func (r RPCClient) Validators( @@ -154,195 +54,38 @@ func (r RPCClient) Validators( height *int64, page, perPage *int, ) (*coretypes.ResultValidators, error) { - res, err := r.c.Validators(ctx, height, page, perPage) - if err != nil { - return nil, err - } - - vals := make([]*tmtypes.Validator, len(res.Validators)) - for i, val := range res.Validators { - vals[i] = &tmtypes.Validator{ - Address: tmtypes.Address(val.Address), - PubKey: convertPubKey(val.PubKey), - VotingPower: val.VotingPower, - ProposerPriority: val.ProposerPriority, - } - } - - return &coretypes.ResultValidators{ - BlockHeight: res.BlockHeight, - Validators: vals, - Count: res.Count, - Total: res.Total, - }, nil + return r.c.Validators(ctx, height, page, perPage) } func (r RPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { - res, err := r.c.Status(ctx) - if err != nil { - return nil, err - } - - return &coretypes.ResultStatus{ - NodeInfo: p2p.DefaultNodeInfo{ - ProtocolVersion: p2p.ProtocolVersion{ - P2P: res.NodeInfo.ProtocolVersion.P2P, - Block: res.NodeInfo.ProtocolVersion.Block, - App: res.NodeInfo.ProtocolVersion.App, - }, - DefaultNodeID: p2p.ID(res.NodeInfo.DefaultNodeID), - ListenAddr: res.NodeInfo.ListenAddr, - Network: res.NodeInfo.Network, - Version: res.NodeInfo.Version, - Channels: bytes.HexBytes(res.NodeInfo.Channels), - Moniker: res.NodeInfo.Moniker, - Other: p2p.DefaultNodeInfoOther{ - TxIndex: res.NodeInfo.Other.TxIndex, - RPCAddress: res.NodeInfo.Other.RPCAddress, - }, - }, - SyncInfo: coretypes.SyncInfo{ - LatestBlockHash: bytes.HexBytes(res.SyncInfo.LatestBlockHash), - LatestAppHash: bytes.HexBytes(res.SyncInfo.LatestAppHash), - LatestBlockHeight: res.SyncInfo.LatestBlockHeight, - LatestBlockTime: res.SyncInfo.LatestBlockTime, - EarliestBlockHash: bytes.HexBytes(res.SyncInfo.EarliestBlockHash), - EarliestAppHash: bytes.HexBytes(res.SyncInfo.EarliestAppHash), - EarliestBlockHeight: res.SyncInfo.EarliestBlockHeight, - EarliestBlockTime: res.SyncInfo.EarliestBlockTime, - CatchingUp: res.SyncInfo.CatchingUp, - }, - ValidatorInfo: coretypes.ValidatorInfo{ - Address: bytes.HexBytes(res.ValidatorInfo.Address), - PubKey: convertPubKey(res.ValidatorInfo.PubKey), - VotingPower: res.ValidatorInfo.VotingPower, - }, - }, nil + return r.c.Status(ctx) } func (r RPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { - res, err := r.c.Block(ctx, height) - if err != nil { - return nil, err - } - - return &coretypes.ResultBlock{ - BlockID: convertBlockID(res.BlockID), - Block: convertBlock(res.Block), - }, nil + return r.c.Block(ctx, height) } func (r RPCClient) BlockByHash(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) { - res, err := r.c.BlockByHash(ctx, hash) - if err != nil { - return nil, err - } - - return &coretypes.ResultBlock{ - BlockID: convertBlockID(res.BlockID), - Block: convertBlock(res.Block), - }, nil + return r.c.BlockByHash(ctx, hash) } func (r RPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { - res, err := r.c.BlockResults(ctx, height) - if err != nil { - return nil, err - } - - txs := make([]*types.ExecTxResult, len(res.TxResponses)) - for i, tx := range res.TxResponses { - txs[i] = &types.ExecTxResult{ - Code: tx.Code, - Data: tx.Data, - Log: tx.Log, - Info: tx.Info, - GasWanted: tx.GasWanted, - GasUsed: tx.GasUsed, - Events: converStringEvents(tx.Events), - Codespace: tx.Codespace, - } - } - - return &coretypes.ResultBlockResults{ - Height: res.Height, - TxsResults: txs, - FinalizeBlockEvents: converStringEvents(res.Events), - ValidatorUpdates: nil, - ConsensusParamUpdates: nil, - AppHash: res.AppHash, - }, nil + return r.c.BlockResults(ctx, height) } func (r RPCClient) BlockchainInfo( ctx context.Context, minHeight, maxHeight int64, ) (*coretypes.ResultBlockchainInfo, error) { - res, err := r.c.BlockchainInfo(ctx, minHeight, maxHeight) - if err != nil { - return nil, err - } - - meta := make([]*tmtypes.BlockMeta, len(res.BlockMetas)) - for i, m := range res.BlockMetas { - meta[i] = &tmtypes.BlockMeta{ - BlockID: tmtypes.BlockID{ - Hash: bytes.HexBytes(m.BlockID.Hash), - PartSetHeader: tmtypes.PartSetHeader{ - Total: m.BlockID.PartSetHeader.Total, - Hash: bytes.HexBytes(m.BlockID.PartSetHeader.Hash), - }, - }, - BlockSize: m.BlockSize, - Header: convertHeader(m.Header), - NumTxs: m.NumTxs, - } - } - - return &coretypes.ResultBlockchainInfo{ - LastHeight: res.LastHeight, - BlockMetas: meta, - }, nil + return r.c.BlockchainInfo(ctx, minHeight, maxHeight) } func (r RPCClient) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { - res, err := r.c.Commit(ctx, height) - if err != nil { - return nil, err - } - - signatures := make([]tmtypes.CommitSig, len(res.Commit.Signatures)) - for i, sig := range res.Commit.Signatures { - signatures[i] = tmtypes.CommitSig{ - BlockIDFlag: tmtypes.BlockIDFlag(sig.BlockIDFlag), - ValidatorAddress: tmtypes.Address(sig.ValidatorAddress), - Timestamp: sig.Timestamp, - Signature: sig.Signature, - } - } - - header := convertHeader(*res.SignedHeader.Header) - return &coretypes.ResultCommit{ - SignedHeader: tmtypes.SignedHeader{ - Header: &header, - Commit: &tmtypes.Commit{ - Height: res.Commit.Height, - Round: res.Commit.Round, - BlockID: convertBlockID(res.Commit.BlockID), - Signatures: signatures, - }, - }, - CanonicalCommit: res.CanonicalCommit, - }, nil + return r.c.Commit(ctx, height) } func (r RPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { - res, err := r.c.Tx(ctx, hash, prove) - if err != nil { - return nil, err - } - - return convertResultTx(res), nil + return r.c.Tx(ctx, hash, prove) } func (r RPCClient) TxSearch( @@ -352,20 +95,7 @@ func (r RPCClient) TxSearch( page, perPage *int, orderBy string, ) (*coretypes.ResultTxSearch, error) { - res, err := r.c.TxSearch(ctx, query, prove, page, perPage, orderBy) - if err != nil { - return nil, err - } - - txs := make([]*coretypes.ResultTx, len(res)) - for i, tx := range res { - txs[i] = convertResultTx(tx) - } - - return &coretypes.ResultTxSearch{ - Txs: txs, - TotalCount: len(txs), - }, nil + return r.c.TxSearch(ctx, query, prove, page, perPage, orderBy) } func (r RPCClient) BlockSearch( @@ -374,207 +104,5 @@ func (r RPCClient) BlockSearch( page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) { - res, err := r.c.BlockSearch(ctx, query, page, perPage, orderBy) - if err != nil { - return nil, err - } - - blocks := make([]*coretypes.ResultBlock, len(res.Blocks)) - for i, block := range res.Blocks { - blocks[i] = &coretypes.ResultBlock{ - BlockID: convertBlockID(block.BlockID), - Block: convertBlock(block.Block), - } - } - - return &coretypes.ResultBlockSearch{ - Blocks: blocks, - TotalCount: res.TotalCount, - }, nil -} - -func convertProofOps(proofOps *sltypes.ProofOps) *crypto.ProofOps { - ops := make([]crypto.ProofOp, len(proofOps.Ops)) - for i, op := range proofOps.Ops { - ops[i] = crypto.ProofOp{ - Type: op.Type, - Key: op.Key, - Data: op.Data, - } - } - - return &crypto.ProofOps{Ops: ops} -} - -func convertEvents(events []sltypes.Event) []types.Event { - evts := make([]types.Event, len(events)) - - for i, evt := range events { - attributes := make([]types.EventAttribute, len(evt.Attributes)) - - for j, attr := range evt.Attributes { - attributes[j] = types.EventAttribute{ - Key: attr.Key, - Value: attr.Value, - Index: attr.Index, - } - } - - evts[i] = types.Event{ - Type: evt.Type, - Attributes: attributes, - } - } - - return evts -} - -func converStringEvents(events sdk.StringEvents) []types.Event { - evts := make([]types.Event, len(events)) - - for i, evt := range events { - attributes := make([]types.EventAttribute, len(evt.Attributes)) - - for j, attr := range evt.Attributes { - attributes[j] = types.EventAttribute{ - Key: attr.Key, - Value: attr.Value, - } - } - - evts[i] = types.Event{ - Type: evt.Type, - Attributes: attributes, - } - } - - return evts -} - -func convertHeader(header types2.Header) tmtypes.Header { - return tmtypes.Header{ - ChainID: header.ChainID, - Height: header.Height, - Time: header.Time, - LastBlockID: tmtypes.BlockID{ - Hash: bytes.HexBytes(header.LastBlockID.Hash), - PartSetHeader: tmtypes.PartSetHeader{ - Total: header.LastBlockID.PartSetHeader.Total, - Hash: bytes.HexBytes(header.LastBlockID.PartSetHeader.Hash), - }, - }, - LastCommitHash: bytes.HexBytes(header.LastCommitHash), - DataHash: bytes.HexBytes(header.DataHash), - ValidatorsHash: bytes.HexBytes(header.ValidatorsHash), - NextValidatorsHash: bytes.HexBytes(header.NextValidatorsHash), - ConsensusHash: bytes.HexBytes(header.ConsensusHash), - AppHash: bytes.HexBytes(header.AppHash), - LastResultsHash: bytes.HexBytes(header.LastResultsHash), - EvidenceHash: bytes.HexBytes(header.EvidenceHash), - ProposerAddress: tmtypes.Address(header.ProposerAddress), - } -} - -func convertBlockID(id types2.BlockID) tmtypes.BlockID { - return tmtypes.BlockID{ - Hash: bytes.HexBytes(id.Hash), - PartSetHeader: tmtypes.PartSetHeader{ - Total: id.PartSetHeader.Total, - Hash: bytes.HexBytes(id.PartSetHeader.Hash), - }, - } -} - -func convertBlock(block *types2.Block) *tmtypes.Block { - signatures := make([]tmtypes.CommitSig, len(block.LastCommit.Signatures)) - for i, sig := range block.LastCommit.Signatures { - signatures[i] = tmtypes.CommitSig{ - BlockIDFlag: tmtypes.BlockIDFlag(sig.BlockIDFlag), - ValidatorAddress: tmtypes.Address(sig.ValidatorAddress), - Timestamp: sig.Timestamp, - Signature: sig.Signature, - } - } - - txs := make([]tmtypes.Tx, len(block.Data.Txs)) - for i, tx := range block.Data.Txs { - txs[i] = tmtypes.Tx(tx) - } - - return &tmtypes.Block{ - Header: convertHeader(block.Header), - Data: tmtypes.Data{ - Txs: txs, - }, - Evidence: tmtypes.EvidenceData{}, - LastCommit: &tmtypes.Commit{ - Height: block.LastCommit.Height, - Round: block.LastCommit.Round, - BlockID: convertBlockID(block.LastCommit.BlockID), - Signatures: signatures, - }, - } -} - -func convertResultABCIQuery(res *coretypes2.ResultABCIQuery) *coretypes.ResultABCIQuery { - var ops *crypto.ProofOps - if res.Response.ProofOps != nil { - ops = convertProofOps(res.Response.ProofOps) - } - - return &coretypes.ResultABCIQuery{ - Response: types.ResponseQuery{ - Code: res.Response.Code, - Log: res.Response.Log, - Info: res.Response.Info, - Index: res.Response.Index, - Key: res.Response.Key, - Value: res.Response.Value, - ProofOps: ops, - Height: res.Response.Height, - Codespace: res.Response.Codespace, - }, - } -} - -func convertResultTx(res *client.TxResponse) *coretypes.ResultTx { - return &coretypes.ResultTx{ - Hash: bytes.HexBytes(res.Hash), - Height: res.Height, - Index: res.Index, - TxResult: types.ExecTxResult{ - Code: res.ExecTx.Code, - Data: res.ExecTx.Data, - Log: res.ExecTx.Log, - Info: res.ExecTx.Info, - GasWanted: res.ExecTx.GasWanted, - GasUsed: res.ExecTx.GasUsed, - Events: converStringEvents(res.ExecTx.Events), - Codespace: res.ExecTx.Codespace, - }, - Tx: tmtypes.Tx(res.Tx), - Proof: tmtypes.TxProof{ - RootHash: bytes.HexBytes(res.Proof.RootHash), - Data: tmtypes.Tx(res.Proof.Data), - Proof: merkle.Proof{ - Total: res.Proof.Proof.Total, - Index: res.Proof.Proof.Index, - LeafHash: res.Proof.Proof.LeafHash, - Aunts: res.Proof.Proof.Aunts, - }, - }, - } -} - -func convertPubKey(pk slcrypto.PubKey) cometcrypto.PubKey { - switch key := pk.(type) { - case ed25519.PubKey: - return ced25519.PubKey(key) - case secp256k1.PubKey: - return csecp256k1.PubKey(key) - case sr25519.PubKey: - return csr25519.PubKey(key) - default: - return nil - } + return r.c.BlockSearch(ctx, query, page, perPage, orderBy) } diff --git a/client/relayer/provider.go b/client/relayer/provider.go index 54b3dff4c..e05655925 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -2,10 +2,10 @@ package relayerclient import ( "fmt" + "github.com/cometbft/cometbft/rpc/client/http" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/strangelove-ventures/cometbft-client/client" "io" "os" "path" @@ -194,7 +194,7 @@ func (cc *CosmosProvider) Init() error { return err } - c, err := client.NewClient(cc.PCfg.RPCAddr, timeout) + c, err := http.NewWithTimeout(cc.PCfg.RPCAddr, "/websocket", uint(timeout.Seconds())) if err != nil { return err } diff --git a/go.mod b/go.mod index 62291ab81..b4de0f484 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,6 @@ require ( github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b github.com/ory/dockertest/v3 v3.9.1 github.com/otiai10/copy v1.14.0 - github.com/strangelove-ventures/cometbft-client v0.1.1 github.com/vulpine-io/io-test v1.0.0 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 From 561f6810026a90fe29955ddc6cdcf6dcb0882e21 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 20:44:07 +0100 Subject: [PATCH 16/21] remove fee grant leftovers --- client/client/client.go | 3 +- client/relayer/provider.go | 59 +++++++++++--------------------------- 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/client/client/client.go b/client/client/client.go index a2657efe9..b4aaa5c8f 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -65,8 +65,7 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { // NOTE: this will create a RPC client. The RPC client will be used for // submitting txs and making ad hoc queries. It won't create WebSocket // connection with Babylon node - err = cp.Init() - if err != nil { + if err = cp.Init(); err != nil { return nil, err } diff --git a/client/relayer/provider.go b/client/relayer/provider.go index e05655925..cddbb8a06 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -5,7 +5,6 @@ import ( "github.com/cometbft/cometbft/rpc/client/http" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" "io" "os" "path" @@ -14,47 +13,23 @@ import ( ) type CosmosProviderConfig struct { - KeyDirectory string `json:"key-directory" yaml:"key-directory"` - Key string `json:"key" yaml:"key"` - ChainName string `json:"-" yaml:"-"` - ChainID string `json:"chain-id" yaml:"chain-id"` - RPCAddr string `json:"rpc-addr" yaml:"rpc-addr"` - AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` - KeyringBackend string `json:"keyring-backend" yaml:"keyring-backend"` - GasAdjustment float64 `json:"gas-adjustment" yaml:"gas-adjustment"` - GasPrices string `json:"gas-prices" yaml:"gas-prices"` - MinGasAmount uint64 `json:"min-gas-amount" yaml:"min-gas-amount"` - MaxGasAmount uint64 `json:"max-gas-amount" yaml:"max-gas-amount"` - Debug bool `json:"debug" yaml:"debug"` - Timeout string `json:"timeout" yaml:"timeout"` - BlockTimeout string `json:"block-timeout" yaml:"block-timeout"` - OutputFormat string `json:"output-format" yaml:"output-format"` - SignModeStr string `json:"sign-mode" yaml:"sign-mode"` - ExtraCodecs []string `json:"extra-codecs" yaml:"extra-codecs"` - Modules []module.AppModuleBasic `json:"-" yaml:"-"` - Slip44 *int `json:"coin-type" yaml:"coin-type"` - SigningAlgorithm string `json:"signing-algorithm" yaml:"signing-algorithm"` - Broadcast BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` - MinLoopDuration time.Duration `json:"min-loop-duration" yaml:"min-loop-duration"` - - // If FeeGrantConfiguration is set, TXs submitted by the ChainClient will be signed by the FeeGrantees in a round-robin fashion by default. - FeeGrants *FeeGrantConfiguration `json:"feegrants" yaml:"feegrants"` -} - -// FeeGrantConfiguration By default, TXs will be signed by the feegrantees 'ManagedGrantees' keys in a round-robin fashion. -// Clients can use other signing keys by invoking 'tx.SendMsgsWith' and specifying the signing key. -type FeeGrantConfiguration struct { - GranteesWanted int `json:"num_grantees" yaml:"num_grantees"` - // Normally this is the default ChainClient key - GranterKeyOrAddr string `json:"granter" yaml:"granter"` - // Whether we control the granter private key (if not, someone else must authorize our feegrants) - IsExternalGranter bool `json:"external_granter" yaml:"external_granter"` - // List of keys (by name) that this FeeGranter manages - ManagedGrantees []string `json:"grantees" yaml:"grantees"` - // Last checked on chain (0 means grants never checked and may not exist) - BlockHeightVerified int64 `json:"block_last_verified" yaml:"block_last_verified"` - // Index of the last ManagedGrantee used as a TX signer - GranteeLastSignerIndex int + KeyDirectory string `json:"key-directory" yaml:"key-directory"` + Key string `json:"key" yaml:"key"` + ChainName string `json:"-" yaml:"-"` + ChainID string `json:"chain-id" yaml:"chain-id"` + RPCAddr string `json:"rpc-addr" yaml:"rpc-addr"` + AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` + KeyringBackend string `json:"keyring-backend" yaml:"keyring-backend"` + GasAdjustment float64 `json:"gas-adjustment" yaml:"gas-adjustment"` + GasPrices string `json:"gas-prices" yaml:"gas-prices"` + MinGasAmount uint64 `json:"min-gas-amount" yaml:"min-gas-amount"` + MaxGasAmount uint64 `json:"max-gas-amount" yaml:"max-gas-amount"` + Debug bool `json:"debug" yaml:"debug"` + Timeout string `json:"timeout" yaml:"timeout"` + BlockTimeout string `json:"block-timeout" yaml:"block-timeout"` + OutputFormat string `json:"output-format" yaml:"output-format"` + SignModeStr string `json:"sign-mode" yaml:"sign-mode"` + Broadcast BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` } type CosmosProvider struct { From c95b01e63cd05116f3d7795f7ed4031346560db5 Mon Sep 17 00:00:00 2001 From: Lazar Date: Tue, 21 Jan 2025 20:56:52 +0100 Subject: [PATCH 17/21] add notice headers --- client/relayer/account.go | 3 +++ client/relayer/bech32_hack.go | 3 +++ client/relayer/chain_provider.go | 3 +++ client/relayer/client_wrapper.go | 3 +++ client/relayer/codec.go | 3 +++ client/relayer/grpc_query.go | 3 +++ client/relayer/keys.go | 3 +++ client/relayer/msg.go | 3 +++ client/relayer/provider.go | 3 +++ client/relayer/tx.go | 3 +++ client/relayer/tx_test.go | 3 +++ 11 files changed, 33 insertions(+) diff --git a/client/relayer/account.go b/client/relayer/account.go index 5ff1cc18c..eabdd52c0 100644 --- a/client/relayer/account.go +++ b/client/relayer/account.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/bech32_hack.go b/client/relayer/bech32_hack.go index a888690a9..b6b5be775 100644 --- a/client/relayer/bech32_hack.go +++ b/client/relayer/bech32_hack.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/chain_provider.go b/client/relayer/chain_provider.go index 6656bc6e8..b58ce3984 100644 --- a/client/relayer/chain_provider.go +++ b/client/relayer/chain_provider.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/client_wrapper.go b/client/relayer/client_wrapper.go index 48f99ef5b..368667fef 100644 --- a/client/relayer/client_wrapper.go +++ b/client/relayer/client_wrapper.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/codec.go b/client/relayer/codec.go index 9f1434b18..50a5b4709 100644 --- a/client/relayer/codec.go +++ b/client/relayer/codec.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/grpc_query.go b/client/relayer/grpc_query.go index 28d8422e2..5f90fce98 100644 --- a/client/relayer/grpc_query.go +++ b/client/relayer/grpc_query.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/keys.go b/client/relayer/keys.go index 1a552b137..b34ae6185 100644 --- a/client/relayer/keys.go +++ b/client/relayer/keys.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/msg.go b/client/relayer/msg.go index b73890b88..170b41dae 100644 --- a/client/relayer/msg.go +++ b/client/relayer/msg.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/provider.go b/client/relayer/provider.go index cddbb8a06..be42e38c9 100644 --- a/client/relayer/provider.go +++ b/client/relayer/provider.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/tx.go b/client/relayer/tx.go index 3a645e836..29de740bb 100644 --- a/client/relayer/tx.go +++ b/client/relayer/tx.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( diff --git a/client/relayer/tx_test.go b/client/relayer/tx_test.go index 275c391d0..8e631f9d8 100644 --- a/client/relayer/tx_test.go +++ b/client/relayer/tx_test.go @@ -1,3 +1,6 @@ +// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), +// originally licensed under the Apache License, Version 2.0. + package relayerclient import ( From bc5528529c6381276ee82e0a71209302fa5db030 Mon Sep 17 00:00:00 2001 From: Lazar Date: Wed, 22 Jan 2025 09:48:40 +0100 Subject: [PATCH 18/21] rename package --- client/{relayer => babylonclient}/account.go | 2 +- .../{relayer => babylonclient}/bech32_hack.go | 2 +- .../chain_provider.go | 2 +- .../client_wrapper.go | 2 +- client/{relayer => babylonclient}/codec.go | 2 +- .../{relayer => babylonclient}/grpc_query.go | 2 +- client/{relayer => babylonclient}/keys.go | 2 +- client/{relayer => babylonclient}/msg.go | 2 +- client/{relayer => babylonclient}/provider.go | 2 +- client/{relayer => babylonclient}/tx.go | 2 +- client/{relayer => babylonclient}/tx_test.go | 2 +- client/client/client.go | 8 ++--- client/client/tx.go | 32 +++++++++---------- client/config/babylon_config.go | 6 ++-- 14 files changed, 34 insertions(+), 34 deletions(-) rename client/{relayer => babylonclient}/account.go (99%) rename client/{relayer => babylonclient}/bech32_hack.go (97%) rename client/{relayer => babylonclient}/chain_provider.go (98%) rename client/{relayer => babylonclient}/client_wrapper.go (99%) rename client/{relayer => babylonclient}/codec.go (95%) rename client/{relayer => babylonclient}/grpc_query.go (99%) rename client/{relayer => babylonclient}/keys.go (98%) rename client/{relayer => babylonclient}/msg.go (98%) rename client/{relayer => babylonclient}/provider.go (99%) rename client/{relayer => babylonclient}/tx.go (99%) rename client/{relayer => babylonclient}/tx_test.go (98%) diff --git a/client/relayer/account.go b/client/babylonclient/account.go similarity index 99% rename from client/relayer/account.go rename to client/babylonclient/account.go index eabdd52c0..c997cc35b 100644 --- a/client/relayer/account.go +++ b/client/babylonclient/account.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "context" diff --git a/client/relayer/bech32_hack.go b/client/babylonclient/bech32_hack.go similarity index 97% rename from client/relayer/bech32_hack.go rename to client/babylonclient/bech32_hack.go index b6b5be775..cf66ea7c3 100644 --- a/client/relayer/bech32_hack.go +++ b/client/babylonclient/bech32_hack.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "sync" diff --git a/client/relayer/chain_provider.go b/client/babylonclient/chain_provider.go similarity index 98% rename from client/relayer/chain_provider.go rename to client/babylonclient/chain_provider.go index b58ce3984..dbfddb661 100644 --- a/client/relayer/chain_provider.go +++ b/client/babylonclient/chain_provider.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "context" diff --git a/client/relayer/client_wrapper.go b/client/babylonclient/client_wrapper.go similarity index 99% rename from client/relayer/client_wrapper.go rename to client/babylonclient/client_wrapper.go index 368667fef..db5f4aee8 100644 --- a/client/relayer/client_wrapper.go +++ b/client/babylonclient/client_wrapper.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "context" diff --git a/client/relayer/codec.go b/client/babylonclient/codec.go similarity index 95% rename from client/relayer/codec.go rename to client/babylonclient/codec.go index 50a5b4709..cac538869 100644 --- a/client/relayer/codec.go +++ b/client/babylonclient/codec.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "github.com/cosmos/cosmos-sdk/client" diff --git a/client/relayer/grpc_query.go b/client/babylonclient/grpc_query.go similarity index 99% rename from client/relayer/grpc_query.go rename to client/babylonclient/grpc_query.go index 5f90fce98..d3fb91c66 100644 --- a/client/relayer/grpc_query.go +++ b/client/babylonclient/grpc_query.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "context" diff --git a/client/relayer/keys.go b/client/babylonclient/keys.go similarity index 98% rename from client/relayer/keys.go rename to client/babylonclient/keys.go index b34ae6185..9f7a9b064 100644 --- a/client/relayer/keys.go +++ b/client/babylonclient/keys.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/client/relayer/msg.go b/client/babylonclient/msg.go similarity index 98% rename from client/relayer/msg.go rename to client/babylonclient/msg.go index 170b41dae..f7467fb30 100644 --- a/client/relayer/msg.go +++ b/client/babylonclient/msg.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "fmt" diff --git a/client/relayer/provider.go b/client/babylonclient/provider.go similarity index 99% rename from client/relayer/provider.go rename to client/babylonclient/provider.go index be42e38c9..b77e502cb 100644 --- a/client/relayer/provider.go +++ b/client/babylonclient/provider.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "fmt" diff --git a/client/relayer/tx.go b/client/babylonclient/tx.go similarity index 99% rename from client/relayer/tx.go rename to client/babylonclient/tx.go index 29de740bb..1a90db8aa 100644 --- a/client/relayer/tx.go +++ b/client/babylonclient/tx.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "context" diff --git a/client/relayer/tx_test.go b/client/babylonclient/tx_test.go similarity index 98% rename from client/relayer/tx_test.go rename to client/babylonclient/tx_test.go index 8e631f9d8..8fb8a9cb6 100644 --- a/client/relayer/tx_test.go +++ b/client/babylonclient/tx_test.go @@ -1,7 +1,7 @@ // This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), // originally licensed under the Apache License, Version 2.0. -package relayerclient +package babylonclient import ( "fmt" diff --git a/client/client/client.go b/client/client/client.go index b4aaa5c8f..6068bcbff 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -1,7 +1,7 @@ package client import ( - relayerclient "github.com/babylonlabs-io/babylon/client/relayer" + "github.com/babylonlabs-io/babylon/client/babylonclient" "time" bbn "github.com/babylonlabs-io/babylon/app" @@ -14,7 +14,7 @@ import ( type Client struct { *query.QueryClient - provider *relayerclient.CosmosProvider + provider *babylonclient.CosmosProvider timeout time.Duration logger *zap.Logger cfg *config.BabylonConfig @@ -48,13 +48,13 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { return nil, err } - cp := provider.(*relayerclient.CosmosProvider) + cp := provider.(*babylonclient.CosmosProvider) cp.PCfg.KeyDirectory = cfg.KeyDirectory // Create tmp Babylon app to retrieve and register codecs // Need to override this manually as otherwise option from config is ignored encCfg := bbn.GetEncodingConfig() - cp.Cdc = relayerclient.Codec{ + cp.Cdc = babylonclient.Codec{ InterfaceRegistry: encCfg.InterfaceRegistry, Marshaller: encCfg.Codec, TxConfig: encCfg.TxConfig, diff --git a/client/client/tx.go b/client/client/tx.go index 669bc718d..be6bc4a8a 100644 --- a/client/client/tx.go +++ b/client/client/tx.go @@ -3,7 +3,7 @@ package client import ( "context" "fmt" - relayerclient "github.com/babylonlabs-io/babylon/client/relayer" + "github.com/babylonlabs-io/babylon/client/babylonclient" "sync" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" @@ -26,10 +26,10 @@ import ( ) // ToProviderMsgs converts a list of sdk.Msg to a list of provider.RelayerMessage -func ToProviderMsgs(msgs []sdk.Msg) []relayerclient.RelayerMessage { - relayerMsgs := make([]relayerclient.RelayerMessage, 0, len(msgs)) +func ToProviderMsgs(msgs []sdk.Msg) []babylonclient.RelayerMessage { + relayerMsgs := make([]babylonclient.RelayerMessage, 0, len(msgs)) for _, m := range msgs { - relayerMsgs = append(relayerMsgs, relayerclient.NewCosmosMessage(m, func(signer string) {})) + relayerMsgs = append(relayerMsgs, babylonclient.NewCosmosMessage(m, func(signer string) {})) } return relayerMsgs } @@ -47,7 +47,7 @@ func (c *Client) SendMsgsToMempool(ctx context.Context, msgs []sdk.Msg) error { if err := retry.Do(func() error { var sendMsgErr error krErr := c.accessKeyWithLock(func() { - sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*relayerclient.RelayerTxResponse, error){}) + sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*babylonclient.RelayerTxResponse, error){}) }) if krErr != nil { c.logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr)) @@ -66,21 +66,21 @@ func (c *Client) SendMsgsToMempool(ctx context.Context, msgs []sdk.Msg) error { // ReliablySendMsg reliable sends a message to the chain. // It utilizes a file lock as well as a keyring lock to ensure atomic access. // TODO: needs tests -func (c *Client) ReliablySendMsg(ctx context.Context, msg sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsg(ctx context.Context, msg sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*babylonclient.RelayerTxResponse, error) { return c.ReliablySendMsgs(ctx, []sdk.Msg{msg}, expectedErrors, unrecoverableErrors) } // ReliablySendMsgs reliably sends a list of messages to the chain. // It utilizes a file lock as well as a keyring lock to ensure atomic access. // TODO: needs tests -func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*babylonclient.RelayerTxResponse, error) { var ( - rlyResp *relayerclient.RelayerTxResponse + rlyResp *babylonclient.RelayerTxResponse callbackErr error wg sync.WaitGroup ) - callback := func(rtr *relayerclient.RelayerTxResponse, err error) { + callback := func(rtr *babylonclient.RelayerTxResponse, err error) { rlyResp = rtr callbackErr = err wg.Done() @@ -95,7 +95,7 @@ func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedE if err := retry.Do(func() error { var sendMsgErr error krErr := c.accessKeyWithLock(func() { - sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*relayerclient.RelayerTxResponse, error){callback}) + sendMsgErr = c.provider.SendMessagesToMempool(ctx, relayerMsgs, "", ctx, []func(*babylonclient.RelayerTxResponse, error){callback}) }) if krErr != nil { c.logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr)) @@ -146,9 +146,9 @@ func (c *Client) ReliablySendMsgs(ctx context.Context, msgs []sdk.Msg, expectedE // ReliablySendMsgsWithSigner reliably sends a list of messages to the chain. // It utilizes the signer private key to sign all msgs -func (c *Client) ReliablySendMsgsWithSigner(ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*relayerclient.RelayerTxResponse, error) { +func (c *Client) ReliablySendMsgsWithSigner(ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, msgs []sdk.Msg, expectedErrors []*errors.Error, unrecoverableErrors []*errors.Error) (*babylonclient.RelayerTxResponse, error) { var ( - rlyResp *relayerclient.RelayerTxResponse + rlyResp *babylonclient.RelayerTxResponse callbackErr error wg sync.WaitGroup ) @@ -208,9 +208,9 @@ func (c *Client) SendMessageWithSigner( ctx context.Context, signerAddr sdk.AccAddress, signerPvKey *secp256k1.PrivKey, - relayerMsgs []relayerclient.RelayerMessage, + relayerMsgs []babylonclient.RelayerMessage, ) (result *coretypes.ResultBroadcastTx, err error) { - cMsgs := relayerclient.CosmosMsgs(relayerMsgs...) + cMsgs := babylonclient.CosmosMsgs(relayerMsgs...) var ( num, seq uint64 ) @@ -481,11 +481,11 @@ func Sign( // - we do not support cancellation of submitting messages // - the only timeout is the block inclusion timeout i.e block-timeout // TODO: To properly support cancellation we need to expose ctx in our client calls -func (c *Client) InsertBTCSpvProof(ctx context.Context, msg *btcctypes.MsgInsertBTCSpvProof) (*relayerclient.RelayerTxResponse, error) { +func (c *Client) InsertBTCSpvProof(ctx context.Context, msg *btcctypes.MsgInsertBTCSpvProof) (*babylonclient.RelayerTxResponse, error) { return c.ReliablySendMsg(ctx, msg, []*errors.Error{}, []*errors.Error{}) } -func (c *Client) InsertHeaders(ctx context.Context, msg *btclctypes.MsgInsertHeaders) (*relayerclient.RelayerTxResponse, error) { +func (c *Client) InsertHeaders(ctx context.Context, msg *btclctypes.MsgInsertHeaders) (*babylonclient.RelayerTxResponse, error) { return c.ReliablySendMsg(ctx, msg, []*errors.Error{}, []*errors.Error{}) } diff --git a/client/config/babylon_config.go b/client/config/babylon_config.go index e903d9780..39597dde5 100644 --- a/client/config/babylon_config.go +++ b/client/config/babylon_config.go @@ -2,7 +2,7 @@ package config import ( "fmt" - relayerclient "github.com/babylonlabs-io/babylon/client/relayer" + "github.com/babylonlabs-io/babylon/client/babylonclient" "net/url" "os" "path/filepath" @@ -42,8 +42,8 @@ func (cfg *BabylonConfig) Validate() error { return nil } -func (cfg *BabylonConfig) ToCosmosProviderConfig() relayerclient.CosmosProviderConfig { - return relayerclient.CosmosProviderConfig{ +func (cfg *BabylonConfig) ToCosmosProviderConfig() babylonclient.CosmosProviderConfig { + return babylonclient.CosmosProviderConfig{ Key: cfg.Key, ChainID: cfg.ChainID, RPCAddr: cfg.RPCAddr, From fc55f54f9fc5909f9974ed088518273c9d8ac335 Mon Sep 17 00:00:00 2001 From: Lazar Date: Wed, 22 Jan 2025 11:37:12 +0100 Subject: [PATCH 19/21] cleanup more --- client/babylonclient/msg.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/client/babylonclient/msg.go b/client/babylonclient/msg.go index f7467fb30..3bc30c24a 100644 --- a/client/babylonclient/msg.go +++ b/client/babylonclient/msg.go @@ -6,10 +6,8 @@ package babylonclient import ( "fmt" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/gogoproto/proto" - "go.uber.org/zap/zapcore" ) type CosmosMessage struct { @@ -44,15 +42,3 @@ func (cm CosmosMessage) Type() string { func (cm CosmosMessage) MsgBytes() ([]byte, error) { return proto.Marshal(cm.Msg) } - -// MarshalLogObject is used to encode cm to a zap logger with the zap.Object field type. -func (cm CosmosMessage) MarshalLogObject(enc zapcore.ObjectEncoder) error { - // Using plain json.Marshal or calling cm.Msg.String() both fail miserably here. - // There is probably a better way to encode the message than this. - j, err := codec.NewLegacyAmino().MarshalJSON(cm.Msg) - if err != nil { - return err - } - enc.AddByteString("msg_json", j) - return nil -} From 0a1e13e89d00758bf24d67eb245082f5daac64dd Mon Sep 17 00:00:00 2001 From: Lazar Date: Thu, 23 Jan 2025 13:05:52 +0100 Subject: [PATCH 20/21] pr comments --- client/babylonclient/codec.go | 17 ----------------- client/babylonclient/grpc_query.go | 2 +- client/babylonclient/provider.go | 6 +++--- client/babylonclient/tx.go | 2 +- client/client/client.go | 29 +++++------------------------ 5 files changed, 10 insertions(+), 46 deletions(-) delete mode 100644 client/babylonclient/codec.go diff --git a/client/babylonclient/codec.go b/client/babylonclient/codec.go deleted file mode 100644 index cac538869..000000000 --- a/client/babylonclient/codec.go +++ /dev/null @@ -1,17 +0,0 @@ -// This file is derived from the Cosmos Relayer repository (https://github.com/cosmos/relayer), -// originally licensed under the Apache License, Version 2.0. - -package babylonclient - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" -) - -type Codec struct { - InterfaceRegistry types.InterfaceRegistry - Marshaller codec.Codec - TxConfig client.TxConfig - Amino *codec.LegacyAmino -} diff --git a/client/babylonclient/grpc_query.go b/client/babylonclient/grpc_query.go index d3fb91c66..4ba264871 100644 --- a/client/babylonclient/grpc_query.go +++ b/client/babylonclient/grpc_query.go @@ -82,7 +82,7 @@ func (cc *CosmosProvider) Invoke(ctx context.Context, method string, req, reply } if cc.Cdc.InterfaceRegistry != nil { - return types.UnpackInterfaces(reply, cc.Cdc.Marshaller) + return types.UnpackInterfaces(reply, cc.Cdc.Codec) } return nil diff --git a/client/babylonclient/provider.go b/client/babylonclient/provider.go index b77e502cb..fde82657e 100644 --- a/client/babylonclient/provider.go +++ b/client/babylonclient/provider.go @@ -5,6 +5,7 @@ package babylonclient import ( "fmt" + "github.com/babylonlabs-io/babylon/app/params" "github.com/cometbft/cometbft/rpc/client/http" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" @@ -42,7 +43,7 @@ type CosmosProvider struct { RPCClient RPCClient Input io.Reader Output io.Writer - Cdc Codec + Cdc *params.EncodingConfig // the map key is the TX signer (provider key) // the purpose of the map is to lock on the signer from TX creation through submission, @@ -159,14 +160,13 @@ func (cc *CosmosProvider) Init() error { cc.PCfg.KeyringBackend, cc.PCfg.KeyDirectory, cc.Input, - cc.Cdc.Marshaller, + cc.Cdc.Codec, cc.KeyringOptions..., ) if err != nil { return err } // TODO: figure out how to deal with input or maybe just make all keyring backends test? - timeout, err := time.ParseDuration(cc.PCfg.Timeout) if err != nil { return err diff --git a/client/babylonclient/tx.go b/client/babylonclient/tx.go index 1a90db8aa..7d208e4c1 100644 --- a/client/babylonclient/tx.go +++ b/client/babylonclient/tx.go @@ -474,7 +474,7 @@ func (cc *CosmosProvider) PrepareFactory(txf tx.Factory, signingKey string) (tx. cliCtx := client.Context{}.WithClient(cc.RPCClient). WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). - WithCodec(cc.Cdc.Marshaller). + WithCodec(cc.Cdc.Codec). WithFromAddress(from) // Set the account number and sequence on the transaction factory and retry if fail diff --git a/client/client/client.go b/client/client/client.go index 6068bcbff..33ee75d56 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -8,7 +8,6 @@ import ( "github.com/babylonlabs-io/babylon/client/config" "github.com/babylonlabs-io/babylon/client/query" rpchttp "github.com/cometbft/cometbft/rpc/client/http" - "go.uber.org/zap" ) type Client struct { @@ -16,30 +15,19 @@ type Client struct { provider *babylonclient.CosmosProvider timeout time.Duration - logger *zap.Logger cfg *config.BabylonConfig } -func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { - var ( - zapLogger *zap.Logger - err error - ) +func (c *Client) Provider() *babylonclient.CosmosProvider { + return c.provider +} +func New(cfg *config.BabylonConfig) (*Client, error) { // ensure cfg is valid if err := cfg.Validate(); err != nil { return nil, err } - // use the existing logger or create a new one if not given - zapLogger = logger - if zapLogger == nil { - zapLogger, err = newRootLogger("console", true) - if err != nil { - return nil, err - } - } - provider, err := cfg.ToCosmosProviderConfig().NewProvider( "", // TODO: set home path "babylon", @@ -53,13 +41,7 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { // Create tmp Babylon app to retrieve and register codecs // Need to override this manually as otherwise option from config is ignored - encCfg := bbn.GetEncodingConfig() - cp.Cdc = babylonclient.Codec{ - InterfaceRegistry: encCfg.InterfaceRegistry, - Marshaller: encCfg.Codec, - TxConfig: encCfg.TxConfig, - Amino: encCfg.Amino, - } + cp.Cdc = bbn.GetEncodingConfig() // initialise Cosmos provider // NOTE: this will create a RPC client. The RPC client will be used for @@ -86,7 +68,6 @@ func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { queryClient, cp, cfg.Timeout, - zapLogger, cfg, }, nil } From 9c8e50ff2be7e19bbadcb09d86b8d04173172ef7 Mon Sep 17 00:00:00 2001 From: Lazar Date: Thu, 23 Jan 2025 13:13:08 +0100 Subject: [PATCH 21/21] revert logger --- client/client/client.go | 19 ++++++++++++++++++- client/client/tx.go | 4 ++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/client/client/client.go b/client/client/client.go index 33ee75d56..bf1df9444 100644 --- a/client/client/client.go +++ b/client/client/client.go @@ -8,6 +8,7 @@ import ( "github.com/babylonlabs-io/babylon/client/config" "github.com/babylonlabs-io/babylon/client/query" rpchttp "github.com/cometbft/cometbft/rpc/client/http" + "go.uber.org/zap" ) type Client struct { @@ -15,6 +16,7 @@ type Client struct { provider *babylonclient.CosmosProvider timeout time.Duration + logger *zap.Logger cfg *config.BabylonConfig } @@ -22,12 +24,26 @@ func (c *Client) Provider() *babylonclient.CosmosProvider { return c.provider } -func New(cfg *config.BabylonConfig) (*Client, error) { +func New(cfg *config.BabylonConfig, logger *zap.Logger) (*Client, error) { + var ( + zapLogger *zap.Logger + err error + ) + // ensure cfg is valid if err := cfg.Validate(); err != nil { return nil, err } + // use the existing logger or create a new one if not given + zapLogger = logger + if zapLogger == nil { + zapLogger, err = newRootLogger("console", true) + if err != nil { + return nil, err + } + } + provider, err := cfg.ToCosmosProviderConfig().NewProvider( "", // TODO: set home path "babylon", @@ -68,6 +84,7 @@ func New(cfg *config.BabylonConfig) (*Client, error) { queryClient, cp, cfg.Timeout, + zapLogger, cfg, }, nil } diff --git a/client/client/tx.go b/client/client/tx.go index be6bc4a8a..c2ce56936 100644 --- a/client/client/tx.go +++ b/client/client/tx.go @@ -219,7 +219,7 @@ func (c *Client) SendMessageWithSigner( cliCtx := client.Context{}.WithClient(cc.RPCClient). WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). - WithCodec(cc.Cdc.Marshaller). + WithCodec(cc.Cdc.Codec). WithFromAddress(signerAddr) txf := cc.TxFactory() @@ -280,7 +280,7 @@ func (c *Client) SendMessageWithSigner( // c.LogFailedTx(nil, err, msgs) // Force encoding in the chain specific address for _, msg := range cMsgs { - cc.Cdc.Marshaller.MustMarshalJSON(msg) + cc.Cdc.Codec.MustMarshalJSON(msg) } if err := Sign(ctx, txf, signerPvKey, txb, cc.Cdc.TxConfig.SignModeHandler(), false); err != nil { return nil, err