From 81c9e37335dbb035a13313289c7a66446fed0f67 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 2 Sep 2024 18:15:27 -0500 Subject: [PATCH 01/13] feat: `ConsensusClient` interface & comet integration --- ...ent_wrapper.go => cmbft_client_wrapper.go} | 40 ++-- client/cmbft_consensus.go | 173 ++++++++++++++++++ client/consensus.go | 112 ++++++++++++ 3 files changed, 305 insertions(+), 20 deletions(-) rename client/{client_wrapper.go => cmbft_client_wrapper.go} (90%) create mode 100644 client/cmbft_consensus.go create mode 100644 client/consensus.go diff --git a/client/client_wrapper.go b/client/cmbft_client_wrapper.go similarity index 90% rename from client/client_wrapper.go rename to client/cmbft_client_wrapper.go index 9825dffae..3aae0e2f3 100644 --- a/client/client_wrapper.go +++ b/client/cmbft_client_wrapper.go @@ -28,17 +28,17 @@ import ( 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. +// CometRPCClient 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 { +type CometRPCClient struct { c *client.Client } -func NewRPCClient(c *client.Client) RPCClient { - return RPCClient{c: c} +func NewRPCClient(c *client.Client) CometRPCClient { + return CometRPCClient{c: c} } -func (r RPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { +func (r CometRPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { res, err := r.c.ABCIInfo(ctx) if err != nil { return nil, err @@ -55,7 +55,7 @@ func (r RPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, err }, nil } -func (r RPCClient) ABCIQuery( +func (r CometRPCClient) ABCIQuery( ctx context.Context, path string, data bytes.HexBytes, @@ -68,7 +68,7 @@ func (r RPCClient) ABCIQuery( return convertResultABCIQuery(res), nil } -func (r RPCClient) ABCIQueryWithOptions( +func (r CometRPCClient) ABCIQueryWithOptions( ctx context.Context, path string, data bytes.HexBytes, @@ -87,7 +87,7 @@ func (r RPCClient) ABCIQueryWithOptions( return convertResultABCIQuery(res), nil } -func (r RPCClient) BroadcastTxCommit(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { +func (r CometRPCClient) 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 @@ -119,7 +119,7 @@ func (r RPCClient) BroadcastTxCommit(ctx context.Context, tx tmtypes.Tx) (*coret }, nil } -func (r RPCClient) BroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { +func (r CometRPCClient) 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 @@ -134,7 +134,7 @@ func (r RPCClient) BroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*corety }, nil } -func (r RPCClient) BroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { +func (r CometRPCClient) 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 @@ -149,7 +149,7 @@ func (r RPCClient) BroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*coretyp }, nil } -func (r RPCClient) Validators( +func (r CometRPCClient) Validators( ctx context.Context, height *int64, page, perPage *int, @@ -177,7 +177,7 @@ func (r RPCClient) Validators( }, nil } -func (r RPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { +func (r CometRPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { res, err := r.c.Status(ctx) if err != nil { return nil, err @@ -220,7 +220,7 @@ func (r RPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) }, nil } -func (r RPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { +func (r CometRPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { res, err := r.c.Block(ctx, height) if err != nil { return nil, err @@ -232,7 +232,7 @@ func (r RPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultB }, nil } -func (r RPCClient) BlockByHash(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) { +func (r CometRPCClient) BlockByHash(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) { res, err := r.c.BlockByHash(ctx, hash) if err != nil { return nil, err @@ -244,7 +244,7 @@ func (r RPCClient) BlockByHash(ctx context.Context, hash []byte) (*coretypes.Res }, nil } -func (r RPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { +func (r CometRPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { res, err := r.c.BlockResults(ctx, height) if err != nil { return nil, err @@ -274,7 +274,7 @@ func (r RPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes. }, nil } -func (r RPCClient) BlockchainInfo( +func (r CometRPCClient) BlockchainInfo( ctx context.Context, minHeight, maxHeight int64, ) (*coretypes.ResultBlockchainInfo, error) { @@ -305,7 +305,7 @@ func (r RPCClient) BlockchainInfo( }, nil } -func (r RPCClient) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { +func (r CometRPCClient) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { res, err := r.c.Commit(ctx, height) if err != nil { return nil, err @@ -336,7 +336,7 @@ func (r RPCClient) Commit(ctx context.Context, height *int64) (*coretypes.Result }, nil } -func (r RPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { +func (r CometRPCClient) 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 @@ -345,7 +345,7 @@ func (r RPCClient) Tx(ctx context.Context, hash []byte, prove bool) (*coretypes. return convertResultTx(res), nil } -func (r RPCClient) TxSearch( +func (r CometRPCClient) TxSearch( ctx context.Context, query string, prove bool, @@ -368,7 +368,7 @@ func (r RPCClient) TxSearch( }, nil } -func (r RPCClient) BlockSearch( +func (r CometRPCClient) BlockSearch( ctx context.Context, query string, page, perPage *int, diff --git a/client/cmbft_consensus.go b/client/cmbft_consensus.go new file mode 100644 index 000000000..365557932 --- /dev/null +++ b/client/cmbft_consensus.go @@ -0,0 +1,173 @@ +package client + +import ( + "context" + "fmt" + "time" + + "github.com/cometbft/cometbft/libs/bytes" + rpcclient "github.com/cometbft/cometbft/rpc/client" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" + rbytes "github.com/cosmos/relayer/v2/client/bytes" +) + +// ConsensusRelayerI is the itnerface we will use across the relayer so we can swap out the underlying consensus engine client. +var _ ConsensusClient = (*CometRPCClient)(nil) + +// GetBlock implements ConsensusRelayerI. +func (r CometRPCClient) GetBlockTime(ctx context.Context, height uint64) (time.Time, error) { + h := int64(height) + + b, err := r.Block(ctx, &h) + if err != nil { + return time.Time{}, fmt.Errorf("failed to get block: %w", err) + } + + return b.Block.Header.Time, nil +} + +// GetBlockResults implements ConsensusRelayerI. +func (r CometRPCClient) GetBlockResults(ctx context.Context, height uint64) (*BlockResults, error) { + h := int64(height) + br, err := r.BlockResults(ctx, &h) + if err != nil { + return nil, fmt.Errorf("failed to get block results: %w", err) + } + return &BlockResults{ + TxsResults: br.TxsResults, + FinalizeBlockEvents: br.FinalizeBlockEvents, + }, nil +} + +// GetABCIQuery implements ConsensusRelayerI. +func (r CometRPCClient) GetABCIQuery(ctx context.Context, queryPath string, data bytes.HexBytes) (*ABCIQueryResponse, error) { + resp, err := r.ABCIQuery(ctx, queryPath, data) + if err != nil { + return nil, fmt.Errorf("failed to get ABCI query: %w", err) + } + return &ABCIQueryResponse{ + Code: resp.Response.Code, + Value: resp.Response.Value, + }, nil +} + +// GetTx implements ConsensusRelayerI. +func (r CometRPCClient) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { + resp, err := r.Tx(ctx, hash, prove) + if err != nil { + return nil, fmt.Errorf("failed to get tx: %w", err) + } + // return &Transaction{ + // Height: uint64(resp.Height), + // TxHash: resp.Hash, + // Code: resp.TxResult.Code, + // Data: string(resp.TxResult.Data), + // Events: resp.TxResult.Events, + // }, nil + return resp, nil +} + +// GetTxSearch implements ConsensusRelayerI. +func (r CometRPCClient) GetTxSearch(ctx context.Context, query string, prove bool, page *int, perPage *int, orderBy string) (*ResultTxSearch, error) { + resp, err := r.TxSearch(ctx, query, prove, page, perPage, orderBy) + if err != nil { + return nil, fmt.Errorf("failed to get tx search: %w", err) + } + return &ResultTxSearch{ + Txs: resp.Txs, + TotalCount: resp.TotalCount, + }, nil +} + +// GetBlockSearch implements ConsensusRelayerI. +func (r CometRPCClient) GetBlockSearch(ctx context.Context, query string, page *int, perPage *int, orderBy string) (*coretypes.ResultBlockSearch, error) { + resp, err := r.BlockSearch(ctx, query, page, perPage, orderBy) + if err != nil { + return nil, fmt.Errorf("failed to get block search: %w", err) + } + return resp, nil +} + +// GetCommit implements ConsensusRelayerI. +func (r CometRPCClient) GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) { + h := int64(height) + c, err := r.Commit(ctx, &h) + if err != nil { + return nil, fmt.Errorf("failed to get commit: %w", err) + } + return c, nil +} + +// GetValidators implements ConsensusRelayerI. +func (r CometRPCClient) GetValidators(ctx context.Context, height *int64, page *int, perPage *int) (*ResultValidators, error) { + v, err := r.Validators(ctx, height, page, perPage) + if err != nil { + return nil, fmt.Errorf("failed to get validators: %w", err) + } + + vals := make([]*tmtypes.Validator, len(v.Validators)) + for i, val := range v.Validators { + vals[i] = &tmtypes.Validator{ + Address: val.Address, + PubKey: val.PubKey, + VotingPower: val.VotingPower, + ProposerPriority: val.ProposerPriority, + } + } + + return &ResultValidators{ + Validators: vals, + }, nil +} + +// DoBroadcastTxAsync implements ConsensusRelayerI. +func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { + b, err := r.BroadcastTxAsync(ctx, tx) + if err != nil { + return nil, fmt.Errorf("failed to broadcast tx async: %w", err) + } + return &ResultBroadcastTx{ + Code: b.Code, + Data: rbytes.ConvertCometBFTToHexBytes(b.Data), + Log: b.Log, + Codespace: b.Codespace, + Hash: rbytes.ConvertCometBFTToHexBytes(b.Hash), + }, nil +} + +// DoBroadcastTxSync implements ConsensusRelayerI. +func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { + b, err := r.BroadcastTxSync(ctx, tx) + if err != nil { + return nil, fmt.Errorf("failed to broadcast tx sync: %w", err) + } + return &ResultBroadcastTx{ + Code: b.Code, + Data: rbytes.ConvertCometBFTToHexBytes(b.Data), + Log: b.Log, + Codespace: b.Codespace, + Hash: rbytes.ConvertCometBFTToHexBytes(b.Hash), + }, nil +} + +// GetABCIQueryWithOptions implements ConsensusRelayerI. +func (r CometRPCClient) GetABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { + q, err := r.ABCIQueryWithOptions(ctx, path, data, opts) + if err != nil { + return nil, fmt.Errorf("failed to get ABCI query with options: %w", err) + } + return q, nil +} + +// GetStatus implements ConsensusRelayerI. +func (r CometRPCClient) GetStatus(ctx context.Context) (*Status, error) { + s, err := r.Status(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get status: %w", err) + } + return &Status{ + CatchingUp: s.SyncInfo.CatchingUp, + LatestBlockHeight: uint64(s.SyncInfo.LatestBlockHeight), + }, nil +} diff --git a/client/consensus.go b/client/consensus.go new file mode 100644 index 000000000..21e565af5 --- /dev/null +++ b/client/consensus.go @@ -0,0 +1,112 @@ +package client + +import ( + "context" + "strings" + "time" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto" + rpcclient "github.com/cometbft/cometbft/rpc/client" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" + + bytes "github.com/cometbft/cometbft/libs/bytes" + rbytes "github.com/cosmos/relayer/v2/client/bytes" +) + +type ConsensusClient interface { + GetBlockTime(ctx context.Context, height uint64) (time.Time, error) + GetStatus(ctx context.Context) (*Status, error) + GetBlockResults(ctx context.Context, height uint64) (*BlockResults, error) + GetABCIQuery(ctx context.Context, queryPath string, data bytes.HexBytes) (*ABCIQueryResponse, error) + GetValidators( + ctx context.Context, + height *int64, + page, perPage *int, + ) (*ResultValidators, error) + GetTxSearch( + ctx context.Context, + query string, + prove bool, + page, perPage *int, + orderBy string, + ) (*ResultTxSearch, error) + DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) + DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) + + // TODO: migrate with v2 + GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) // resp (Events), err != nil - does this need its own tm store? or does the manager have context to this + + GetBlockSearch( + ctx context.Context, + query string, + page, perPage *int, + orderBy string, + ) (*coretypes.ResultBlockSearch, error) + + GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) + GetABCIQueryWithOptions( + ctx context.Context, + path string, + data bytes.HexBytes, + opts rpcclient.ABCIQueryOptions, + ) (*coretypes.ResultABCIQuery, error) +} + +type Status struct { + CatchingUp bool + LatestBlockHeight uint64 +} + +type BlockResults struct { + // TODO: ideally we get off of this into our own internal type. Then the ConsensusRelayerI can have methods to convert + FinalizeBlockEvents []abci.Event `json:"finalize_block_events"` + TxsResults []*abci.ExecTxResult `json:"txs_results"` +} + +type ABCIQueryResponse struct { + Code uint32 `json:"code,omitempty"` + Value []byte `json:"value,omitempty"` +} + +// The response value contains the data link escape control character which must be removed before parsing. +func (q ABCIQueryResponse) ValueCleaned() string { + return strings.ReplaceAll(strings.TrimSpace(string(q.Value)), "\u0010", "") +} + +// TODO: can't do this yet as the cosmos-sdk side in v0.50 is tied to cometbft +// type Transaction struct { +// Height uint64 +// TxHash []byte +// Code uint32 +// Data string +// Events []abci.Event // TODO: []provider.RelayerEvent +// Tx cmtypes.Tx `json:"tx"` +// } + +// coretypes.ResultTxSearch +type ResultTxSearch struct { + Txs []*coretypes.ResultTx `json:"txs"` + TotalCount int `json:"total_count"` +} + +type ResultValidators struct { + Validators []*tmtypes.Validator `json:"validators"` + // Validators []Validator // TODO: requires some helper methods on the gordian side for the query to update set +} + +type Validator struct { + Address crypto.Address `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + VotingPower int64 `json:"voting_power"` + ProposerPriority int64 `json:"proposer_priority"` +} + +type ResultBroadcastTx struct { + Code uint32 `json:"code"` + Data rbytes.HexBytes `json:"data"` + Log string `json:"log"` + Codespace string `json:"codespace"` + Hash rbytes.HexBytes `json:"hash"` +} From 966c6acd0342fdb0189ded3a9dc00da0eb646e26 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 2 Sep 2024 18:15:43 -0500 Subject: [PATCH 02/13] chore: cometbft bytes lib --- client/bytes/bytes.go | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 client/bytes/bytes.go diff --git a/client/bytes/bytes.go b/client/bytes/bytes.go new file mode 100644 index 000000000..eb9ba787d --- /dev/null +++ b/client/bytes/bytes.go @@ -0,0 +1,75 @@ +// FROM: COMETBFT +// IBC-Go also uses this package. Maybe the SDK in v2 upstreams this? + +package bytes + +import ( + "encoding/hex" + "fmt" + "strings" + + "github.com/cometbft/cometbft/libs/bytes" +) + +// HexBytes enables HEX-encoding for json/encoding. +type HexBytes []byte + +// Marshal needed for protobuf compatibility +func (bz HexBytes) Marshal() ([]byte, error) { + return bz, nil +} + +// Unmarshal needed for protobuf compatibility +func (bz *HexBytes) Unmarshal(data []byte) error { + *bz = data + return nil +} + +// This is the point of Bytes. +func (bz HexBytes) MarshalJSON() ([]byte, error) { + s := strings.ToUpper(hex.EncodeToString(bz)) + jbz := make([]byte, len(s)+2) + jbz[0] = '"' + copy(jbz[1:], s) + jbz[len(jbz)-1] = '"' + return jbz, nil +} + +// This is the point of Bytes. +func (bz *HexBytes) UnmarshalJSON(data []byte) error { + if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { + return fmt.Errorf("invalid hex string: %s", data) + } + bz2, err := hex.DecodeString(string(data[1 : len(data)-1])) + if err != nil { + return err + } + *bz = bz2 + return nil +} + +// Bytes fulfills various interfaces in light-client, etc... +func (bz HexBytes) Bytes() []byte { + return bz +} + +func (bz HexBytes) String() string { + return strings.ToUpper(hex.EncodeToString(bz)) +} + +// Format writes either address of 0th element in a slice in base 16 notation, +// with leading 0x (%p), or casts HexBytes to bytes and writes as hexadecimal +// string to s. +func (bz HexBytes) Format(s fmt.State, verb rune) { + switch verb { + case 'p': + s.Write([]byte(fmt.Sprintf("%p", bz))) + default: + s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) + } +} + +// ConvertCometBFTToHexBytes converts a cometbft bytes.HexBytes to relayer HexBytes. +func ConvertCometBFTToHexBytes(cbft bytes.HexBytes) HexBytes { + return HexBytes(cbft) +} From 1509ba6c062a35452a713a9af888df2540167843 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 2 Sep 2024 18:16:10 -0500 Subject: [PATCH 03/13] refactor: migrate to ConsensusClient --- interchaintest/feegrant_test.go | 8 ++-- .../chains/cosmos/cosmos_chain_processor.go | 12 +++--- relayer/chains/cosmos/fee_market.go | 10 ++--- relayer/chains/cosmos/feegrant.go | 3 +- relayer/chains/cosmos/provider.go | 40 +++++++++---------- relayer/chains/cosmos/query.go | 27 +++++++------ relayer/chains/cosmos/tx.go | 20 +++++----- relayer/chains/penumbra/provider.go | 2 +- 8 files changed, 61 insertions(+), 61 deletions(-) diff --git a/interchaintest/feegrant_test.go b/interchaintest/feegrant_test.go index 9b9cbf951..9cdf8bc46 100644 --- a/interchaintest/feegrant_test.go +++ b/interchaintest/feegrant_test.go @@ -396,7 +396,7 @@ func TestRelayerFeeGrant(t *testing.T) { hash, err := hex.DecodeString(curr.Response.TxHash) require.Nil(t, err) - txResp, err := TxWithRetry(ctx, cProv.RPCClient, hash) + txResp, err := TxWithRetry(ctx, cProv.ConsensusClient, hash) require.Nil(t, err) require.Nil(t, err) @@ -538,11 +538,11 @@ func TestRelayerFeeGrant(t *testing.T) { } } -func TxWithRetry(ctx context.Context, client client.RPCClient, hash []byte) (*coretypes.ResultTx, error) { +func TxWithRetry(ctx context.Context, client client.ConsensusClient, hash []byte) (*coretypes.ResultTx, error) { var err error var res *coretypes.ResultTx if err = retry.Do(func() error { - res, err = client.Tx(ctx, hash, true) + res, err = client.GetTx(ctx, hash, true) return err }, retry.Context(ctx), relayer.RtyAtt, relayer.RtyDel, relayer.RtyErr); err != nil { return res, err @@ -870,7 +870,7 @@ func TestRelayerFeeGrantExternal(t *testing.T) { hash, err := hex.DecodeString(curr.Response.TxHash) require.Nil(t, err) - txResp, err := TxWithRetry(ctx, cProv.RPCClient, hash) + txResp, err := TxWithRetry(ctx, cProv.ConsensusClient, hash) require.Nil(t, err) require.Nil(t, err) diff --git a/relayer/chains/cosmos/cosmos_chain_processor.go b/relayer/chains/cosmos/cosmos_chain_processor.go index 13746ef81..0d8e9486f 100644 --- a/relayer/chains/cosmos/cosmos_chain_processor.go +++ b/relayer/chains/cosmos/cosmos_chain_processor.go @@ -8,12 +8,12 @@ import ( "time" "github.com/avast/retry-go/v4" - coretypes "github.com/cometbft/cometbft/rpc/core/types" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + rclient "github.com/cosmos/relayer/v2/client" "github.com/cosmos/relayer/v2/relayer/chains" "github.com/cosmos/relayer/v2/relayer/processor" "github.com/cosmos/relayer/v2/relayer/provider" @@ -149,7 +149,7 @@ func (ccp *CosmosChainProcessor) latestHeightWithRetry(ctx context.Context) (lat // nodeStatusWithRetry will query for the latest node status, retrying in case of failure. // It will delay by latestHeightQueryRetryDelay between attempts, up to latestHeightQueryRetries. -func (ccp *CosmosChainProcessor) nodeStatusWithRetry(ctx context.Context) (status *coretypes.ResultStatus, err error) { +func (ccp *CosmosChainProcessor) nodeStatusWithRetry(ctx context.Context) (status *rclient.Status, err error) { return status, retry.Do(func() error { latestHeightQueryCtx, cancelLatestHeightQueryCtx := context.WithTimeout(ctx, queryTimeout) defer cancelLatestHeightQueryCtx() @@ -239,7 +239,7 @@ func (ccp *CosmosChainProcessor) Run(ctx context.Context, initialBlockHistory ui } continue } - persistence.latestHeight = status.SyncInfo.LatestBlockHeight + persistence.latestHeight = int64(status.LatestBlockHeight) break } @@ -351,7 +351,7 @@ func (ccp *CosmosChainProcessor) queryCycle(ctx context.Context, persistence *qu return nil } - persistence.latestHeight = status.SyncInfo.LatestBlockHeight + persistence.latestHeight = int64(status.LatestBlockHeight) // This debug log is very noisy, but is helpful when debugging new chains. // ccp.log.Debug("Queried latest height", @@ -393,7 +393,7 @@ func (ccp *CosmosChainProcessor) queryCycle(ctx context.Context, persistence *qu for i := persistence.latestQueriedBlock + 1; i <= persistence.latestHeight; i++ { var ( eg errgroup.Group - blockRes *coretypes.ResultBlockResults + blockRes *rclient.BlockResults ibcHeader provider.IBCHeader ) @@ -403,7 +403,7 @@ func (ccp *CosmosChainProcessor) queryCycle(ctx context.Context, persistence *qu queryCtx, cancelQueryCtx := context.WithTimeout(ctx, blockResultsQueryTimeout) defer cancelQueryCtx() - blockRes, err = ccp.chainProvider.RPCClient.BlockResults(queryCtx, &sI) + blockRes, err = ccp.chainProvider.ConsensusClient.GetBlockResults(queryCtx, uint64(i)) if err != nil && ccp.metrics != nil { ccp.metrics.IncBlockQueryFailure(chainID, "RPC Client") } diff --git a/relayer/chains/cosmos/fee_market.go b/relayer/chains/cosmos/fee_market.go index bc4cb85f1..d2e96bb50 100644 --- a/relayer/chains/cosmos/fee_market.go +++ b/relayer/chains/cosmos/fee_market.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "regexp" - "strings" sdkmath "cosmossdk.io/math" "go.uber.org/zap" @@ -32,15 +31,12 @@ func (cc *CosmosProvider) DynamicFee(ctx context.Context) string { // QueryBaseFee attempts to make an ABCI query to retrieve the base fee on chains using the Osmosis EIP-1559 implementation. // This is currently hardcoded to only work on Osmosis. func (cc *CosmosProvider) QueryBaseFee(ctx context.Context) (string, error) { - resp, err := cc.RPCClient.ABCIQuery(ctx, queryPath, nil) - if err != nil || resp.Response.Code != 0 { + resp, err := cc.ConsensusClient.GetABCIQuery(ctx, queryPath, nil) + if err != nil || resp.Code != 0 { return "", err } - // The response value contains the data link escape control character which must be removed before parsing. - cleanedString := strings.ReplaceAll(strings.TrimSpace(string(resp.Response.Value)), "\u0010", "") - - decFee, err := sdkmath.LegacyNewDecFromStr(cleanedString) + decFee, err := sdkmath.LegacyNewDecFromStr(resp.ValueCleaned()) if err != nil { return "", err } diff --git a/relayer/chains/cosmos/feegrant.go b/relayer/chains/cosmos/feegrant.go index f74027290..1ecd442c8 100644 --- a/relayer/chains/cosmos/feegrant.go +++ b/relayer/chains/cosmos/feegrant.go @@ -332,7 +332,8 @@ func (cc *CosmosProvider) EnsureBasicGrants(ctx context.Context, memo string, ga } if len(msgs) > 0 { - cliCtx := client.Context{}.WithClient(cc.RPCClient). + cliCtx := client.Context{}. + // WithClient(cc.RPCClient). // TODO(reece): how does server/v2 handle this? WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). WithCodec(cc.Cdc.Marshaler). diff --git a/relayer/chains/cosmos/provider.go b/relayer/chains/cosmos/provider.go index 61d9a7a86..75c458d00 100644 --- a/relayer/chains/cosmos/provider.go +++ b/relayer/chains/cosmos/provider.go @@ -19,7 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/gogoproto/proto" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - cwrapper "github.com/cosmos/relayer/v2/client" + rclient "github.com/cosmos/relayer/v2/client" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/cosmos/relayer/v2/relayer/processor" "github.com/cosmos/relayer/v2/relayer/provider" @@ -124,14 +124,14 @@ func (pc CosmosProviderConfig) NewProvider(log *zap.Logger, homepath string, deb type CosmosProvider struct { log *zap.Logger - PCfg CosmosProviderConfig - Keybase keyring.Keyring - KeyringOptions []keyring.Option - RPCClient cwrapper.RPCClient - LightProvider provtypes.Provider - Input io.Reader - Output io.Writer - Cdc Codec + PCfg CosmosProviderConfig + Keybase keyring.Keyring + KeyringOptions []keyring.Option + ConsensusClient rclient.ConsensusClient + LightProvider provtypes.Provider + Input io.Reader + Output io.Writer + Cdc Codec // TODO: GRPC Client type? //nextAccountSeq uint64 @@ -350,7 +350,7 @@ func (cc *CosmosProvider) startLivelinessChecks(ctx context.Context, timeout tim case <-ctx.Done(): return case <-ticker.C: - _, err := cc.RPCClient.Status(ctx) + _, err := cc.ConsensusClient.GetStatus(ctx) if err != nil { cc.log.Error("RPC client disconnected", zap.String("chain", cc.ChainName()), zap.Error(err)) @@ -401,13 +401,13 @@ func (cc *CosmosProvider) setRpcClient(onStartup bool, rpcAddr string, timeout t return err } - cc.RPCClient = cwrapper.NewRPCClient(c) + cc.ConsensusClient = rclient.NewRPCClient(c) // Only check status if not on startup, to ensure the relayer will not block on startup. // All subsequent calls will perform the status check to ensure RPC endpoints are rotated // as necessary. if !onStartup { - if _, err = cc.RPCClient.Status(context.Background()); err != nil { + if _, err = cc.ConsensusClient.GetStatus(context.Background()); err != nil { return err } } @@ -428,21 +428,21 @@ func (cc *CosmosProvider) setLightProvider(rpcAddr string) error { // 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) + var initial uint64 + h, err := cc.ConsensusClient.GetStatus(ctx) if err != nil { return err } - if h.SyncInfo.CatchingUp { + if h.CatchingUp { return errors.New("chain catching up") } - initial = h.SyncInfo.LatestBlockHeight + initial = h.LatestBlockHeight for { - h, err = cc.RPCClient.Status(ctx) + h, err = cc.ConsensusClient.GetStatus(ctx) if err != nil { return err } - if h.SyncInfo.LatestBlockHeight > initial+n { + if h.LatestBlockHeight > initial+uint64(n) { return nil } select { @@ -455,11 +455,11 @@ func (cc *CosmosProvider) WaitForNBlocks(ctx context.Context, n int64) error { } func (cc *CosmosProvider) BlockTime(ctx context.Context, height int64) (time.Time, error) { - resultBlock, err := cc.RPCClient.Block(ctx, &height) + bt, err := cc.ConsensusClient.GetBlockTime(ctx, uint64(height)) if err != nil { return time.Time{}, err } - return resultBlock.Block.Time, nil + return bt, nil } func (cc *CosmosProvider) SetMetrics(m *processor.PrometheusMetrics) { diff --git a/relayer/chains/cosmos/query.go b/relayer/chains/cosmos/query.go index 188635934..5be04f88a 100644 --- a/relayer/chains/cosmos/query.go +++ b/relayer/chains/cosmos/query.go @@ -16,7 +16,6 @@ import ( "cosmossdk.io/x/feegrant" upgradetypes "cosmossdk.io/x/upgrade/types" abci "github.com/cometbft/cometbft/abci/types" - coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -33,6 +32,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + rclient "github.com/cosmos/relayer/v2/client" "github.com/cosmos/relayer/v2/relayer/chains" "github.com/cosmos/relayer/v2/relayer/provider" "go.uber.org/zap" @@ -67,7 +67,7 @@ func (cc *CosmosProvider) queryIBCMessages(ctx context.Context, log *zap.Logger, ) eg.Go(func() error { - res, err := cc.RPCClient.BlockSearch(ctx, query, &page, &limit, "") + res, err := cc.ConsensusClient.GetBlockSearch(ctx, query, &page, &limit, "") if err != nil { return err } @@ -77,7 +77,7 @@ func (cc *CosmosProvider) queryIBCMessages(ctx context.Context, log *zap.Logger, for _, b := range res.Blocks { b := b nestedEg.Go(func() error { - block, err := cc.RPCClient.BlockResults(ctx, &b.Block.Height) + block, err := cc.ConsensusClient.GetBlockResults(ctx, uint64(b.Block.Height)) if err != nil { return err } @@ -93,7 +93,7 @@ func (cc *CosmosProvider) queryIBCMessages(ctx context.Context, log *zap.Logger, }) eg.Go(func() error { - res, err := cc.RPCClient.TxSearch(ctx, query, true, &page, &limit, "") + res, err := cc.ConsensusClient.GetTxSearch(ctx, query, true, &page, &limit, "") if err != nil { return err } @@ -121,7 +121,8 @@ func (cc *CosmosProvider) QueryTx(ctx context.Context, hashHex string) (*provide return nil, err } - resp, err := cc.RPCClient.Tx(ctx, hash, true) + // TODO(reece): Why is this true when we do not use the proof? + resp, err := cc.ConsensusClient.GetTx(ctx, hash, true) if err != nil { return nil, err } @@ -151,7 +152,7 @@ func (cc *CosmosProvider) QueryTxs(ctx context.Context, page, limit int, events return nil, errors.New("limit must greater than 0") } - res, err := cc.RPCClient.TxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") + res, err := cc.ConsensusClient.GetTxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") if err != nil { return nil, err } @@ -604,7 +605,7 @@ func (cc *CosmosProvider) QueryUpgradedConsState(ctx context.Context, height int // QueryConsensusState returns a consensus state for a given chain to be used as a // client in another chain, fetches latest height when passed 0 as arg func (cc *CosmosProvider) QueryConsensusState(ctx context.Context, height int64) (ibcexported.ConsensusState, int64, error) { - commit, err := cc.RPCClient.Commit(ctx, &height) + commit, err := cc.ConsensusClient.GetCommit(ctx, uint64(height)) if err != nil { return &tmclient.ConsensusState{}, 0, err } @@ -613,7 +614,7 @@ func (cc *CosmosProvider) QueryConsensusState(ctx context.Context, height int64) count := 10_000 nextHeight := height + 1 - nextVals, err := cc.RPCClient.Validators(ctx, &nextHeight, &page, &count) + nextVals, err := cc.ConsensusClient.GetValidators(ctx, &nextHeight, &page, &count) if err != nil { return &tmclient.ConsensusState{}, 0, err } @@ -1201,18 +1202,18 @@ func (cc *CosmosProvider) QueryPacketReceipt(ctx context.Context, height int64, } func (cc *CosmosProvider) QueryLatestHeight(ctx context.Context) (int64, error) { - stat, err := cc.RPCClient.Status(ctx) + stat, err := cc.ConsensusClient.GetStatus(ctx) if err != nil { return -1, err - } else if stat.SyncInfo.CatchingUp { + } else if stat.CatchingUp { return -1, fmt.Errorf("node at %s running chain %s not caught up", cc.PCfg.RPCAddr, cc.PCfg.ChainID) } - return stat.SyncInfo.LatestBlockHeight, nil + return int64(stat.LatestBlockHeight), nil } // Query current node status -func (cc *CosmosProvider) QueryStatus(ctx context.Context) (*coretypes.ResultStatus, error) { - status, err := cc.RPCClient.Status(ctx) +func (cc *CosmosProvider) QueryStatus(ctx context.Context) (*rclient.Status, error) { + status, err := cc.ConsensusClient.GetStatus(ctx) if err != nil { return nil, fmt.Errorf("failed to query node status: %w", err) } diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index bf5750969..ea03a9dce 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -18,7 +18,6 @@ import ( "cosmossdk.io/store/rootmulti" "github.com/avast/retry-go/v4" abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/libs/bytes" "github.com/cometbft/cometbft/light" client2 "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" @@ -43,6 +42,8 @@ import ( ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" + rclient "github.com/cosmos/relayer/v2/client" + rbytes "github.com/cosmos/relayer/v2/client/bytes" strideicqtypes "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" "github.com/cosmos/relayer/v2/relayer/ethermint" "github.com/cosmos/relayer/v2/relayer/provider" @@ -233,7 +234,7 @@ func (cc *CosmosProvider) SubmitTxAwaitResponse(ctx context.Context, msgs []sdk. } // Get the TX by hash, waiting for it to be included in a block -func (cc *CosmosProvider) AwaitTx(txHash bytes.HexBytes, timeout time.Duration) (*txtypes.GetTxResponse, error) { +func (cc *CosmosProvider) AwaitTx(txHash rbytes.HexBytes, timeout time.Duration) (*txtypes.GetTxResponse, error) { var txByHash *txtypes.GetTxResponse var txLookupErr error startTime := time.Now() @@ -265,7 +266,7 @@ func (cc *CosmosProvider) AwaitTx(txHash bytes.HexBytes, timeout time.Duration) // sent and executed successfully is returned. // // feegranterKey - key name of the address set as the feegranter, empty string will not feegrant -func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo string, gas uint64, signingKey string, feegranterKey string) (*coretypes.ResultBroadcastTx, error) { +func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo string, gas uint64, signingKey string, feegranterKey string) (*rclient.ResultBroadcastTx, error) { sdkConfigMutex.Lock() sdkConf := sdk.GetConfig() sdkConf.SetBech32PrefixForAccount(cc.PCfg.AccountPrefix, cc.PCfg.AccountPrefix+"pub") @@ -343,7 +344,7 @@ func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo return nil, err } - res, err := cc.RPCClient.BroadcastTxAsync(ctx, txBytes) + res, err := cc.ConsensusClient.DoBroadcastTxAsync(ctx, txBytes) if res != nil { fmt.Printf("TX hash: %s\n", res.Hash) } @@ -386,7 +387,7 @@ func (cc *CosmosProvider) broadcastTx( asyncCallbacks []func(*provider.RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion dynamicFee string, ) error { - res, err := cc.RPCClient.BroadcastTxSync(ctx, tx) + res, err := cc.ConsensusClient.DoBroadcastTxSync(ctx, tx) isErr := err != nil isFailed := res != nil && res.Code != 0 if isErr || isFailed { @@ -497,7 +498,7 @@ func (cc *CosmosProvider) waitForBlockInclusion( 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) + res, err := cc.ConsensusClient.GetTx(ctx, txHash, false) if err == nil { return cc.mkTxResult(res) } @@ -1668,7 +1669,8 @@ func (cc *CosmosProvider) PrepareFactory(txf tx.Factory, signingKey string) (tx. return tx.Factory{}, err } - cliCtx := client.Context{}.WithClient(cc.RPCClient). + cliCtx := client.Context{}. + // WithClient(cc.RPCClient). // TODO(reece): will this break gordian? hwo does server/v2 handle this? WithInterfaceRegistry(cc.Cdc.InterfaceRegistry). WithChainID(cc.PCfg.ChainID). WithCodec(cc.Cdc.Marshaler). @@ -1746,7 +1748,7 @@ func (cc *CosmosProvider) SetWithExtensionOptions(txf tx.Factory) (tx.Factory, e for _, opt := range cc.PCfg.ExtensionOptions { max, ok := sdkmath.NewIntFromString(opt.Value) if !ok { - return txf,errors.New("invalid opt value") + return txf, errors.New("invalid opt value") } extensionOption := ethermint.ExtensionOptionDynamicFeeTx{ MaxPriorityPrice: max, @@ -1845,7 +1847,7 @@ func (cc *CosmosProvider) QueryABCI(ctx context.Context, req abci.RequestQuery) Prove: req.Prove, } - result, err := cc.RPCClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts) + result, err := cc.ConsensusClient.GetABCIQueryWithOptions(ctx, req.Path, req.Data, opts) if err != nil { return abci.ResponseQuery{}, err } diff --git a/relayer/chains/penumbra/provider.go b/relayer/chains/penumbra/provider.go index 9145302af..4324740d2 100644 --- a/relayer/chains/penumbra/provider.go +++ b/relayer/chains/penumbra/provider.go @@ -142,7 +142,7 @@ type PenumbraProvider struct { PCfg PenumbraProviderConfig Keybase keyring.Keyring KeyringOptions []keyring.Option - RPCClient cwrapper.RPCClient + RPCClient cwrapper.CometRPCClient LightProvider provtypes.Provider Input io.Reader Output io.Writer From f7f7f246a76f40cec30e31d1367b70af72329c41 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 2 Sep 2024 18:32:21 -0500 Subject: [PATCH 04/13] rename --- client/cmbft_client_wrapper.go | 2 +- client/cmbft_consensus.go | 34 +++++++++++------------------ client/consensus.go | 20 +++-------------- interchaintest/feegrant_test.go | 4 ++-- relayer/chains/penumbra/provider.go | 6 ++--- 5 files changed, 22 insertions(+), 44 deletions(-) diff --git a/client/cmbft_client_wrapper.go b/client/cmbft_client_wrapper.go index 3aae0e2f3..4f4c95f98 100644 --- a/client/cmbft_client_wrapper.go +++ b/client/cmbft_client_wrapper.go @@ -1,4 +1,4 @@ -package client +package rclient import ( "context" diff --git a/client/cmbft_consensus.go b/client/cmbft_consensus.go index 365557932..15aa5fe3d 100644 --- a/client/cmbft_consensus.go +++ b/client/cmbft_consensus.go @@ -1,4 +1,4 @@ -package client +package rclient import ( "context" @@ -12,10 +12,9 @@ import ( rbytes "github.com/cosmos/relayer/v2/client/bytes" ) -// ConsensusRelayerI is the itnerface we will use across the relayer so we can swap out the underlying consensus engine client. var _ ConsensusClient = (*CometRPCClient)(nil) -// GetBlock implements ConsensusRelayerI. +// GetBlock implements ConsensusClient. func (r CometRPCClient) GetBlockTime(ctx context.Context, height uint64) (time.Time, error) { h := int64(height) @@ -27,7 +26,7 @@ func (r CometRPCClient) GetBlockTime(ctx context.Context, height uint64) (time.T return b.Block.Header.Time, nil } -// GetBlockResults implements ConsensusRelayerI. +// GetBlockResults implements ConsensusClient. func (r CometRPCClient) GetBlockResults(ctx context.Context, height uint64) (*BlockResults, error) { h := int64(height) br, err := r.BlockResults(ctx, &h) @@ -40,7 +39,7 @@ func (r CometRPCClient) GetBlockResults(ctx context.Context, height uint64) (*Bl }, nil } -// GetABCIQuery implements ConsensusRelayerI. +// GetABCIQuery implements ConsensusClient. func (r CometRPCClient) GetABCIQuery(ctx context.Context, queryPath string, data bytes.HexBytes) (*ABCIQueryResponse, error) { resp, err := r.ABCIQuery(ctx, queryPath, data) if err != nil { @@ -52,23 +51,16 @@ func (r CometRPCClient) GetABCIQuery(ctx context.Context, queryPath string, data }, nil } -// GetTx implements ConsensusRelayerI. +// GetTx implements ConsensusClient. func (r CometRPCClient) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { resp, err := r.Tx(ctx, hash, prove) if err != nil { return nil, fmt.Errorf("failed to get tx: %w", err) } - // return &Transaction{ - // Height: uint64(resp.Height), - // TxHash: resp.Hash, - // Code: resp.TxResult.Code, - // Data: string(resp.TxResult.Data), - // Events: resp.TxResult.Events, - // }, nil return resp, nil } -// GetTxSearch implements ConsensusRelayerI. +// GetTxSearch implements ConsensusClient. func (r CometRPCClient) GetTxSearch(ctx context.Context, query string, prove bool, page *int, perPage *int, orderBy string) (*ResultTxSearch, error) { resp, err := r.TxSearch(ctx, query, prove, page, perPage, orderBy) if err != nil { @@ -80,7 +72,7 @@ func (r CometRPCClient) GetTxSearch(ctx context.Context, query string, prove boo }, nil } -// GetBlockSearch implements ConsensusRelayerI. +// GetBlockSearch implements ConsensusClient. func (r CometRPCClient) GetBlockSearch(ctx context.Context, query string, page *int, perPage *int, orderBy string) (*coretypes.ResultBlockSearch, error) { resp, err := r.BlockSearch(ctx, query, page, perPage, orderBy) if err != nil { @@ -89,7 +81,7 @@ func (r CometRPCClient) GetBlockSearch(ctx context.Context, query string, page * return resp, nil } -// GetCommit implements ConsensusRelayerI. +// GetCommit implements ConsensusClient. func (r CometRPCClient) GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) { h := int64(height) c, err := r.Commit(ctx, &h) @@ -99,7 +91,7 @@ func (r CometRPCClient) GetCommit(ctx context.Context, height uint64) (*coretype return c, nil } -// GetValidators implements ConsensusRelayerI. +// GetValidators implements ConsensusClient. func (r CometRPCClient) GetValidators(ctx context.Context, height *int64, page *int, perPage *int) (*ResultValidators, error) { v, err := r.Validators(ctx, height, page, perPage) if err != nil { @@ -121,7 +113,7 @@ func (r CometRPCClient) GetValidators(ctx context.Context, height *int64, page * }, nil } -// DoBroadcastTxAsync implements ConsensusRelayerI. +// DoBroadcastTxAsync implements ConsensusClient. func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { b, err := r.BroadcastTxAsync(ctx, tx) if err != nil { @@ -136,7 +128,7 @@ func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) ( }, nil } -// DoBroadcastTxSync implements ConsensusRelayerI. +// DoBroadcastTxSync implements ConsensusClient. func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { b, err := r.BroadcastTxSync(ctx, tx) if err != nil { @@ -151,7 +143,7 @@ func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (* }, nil } -// GetABCIQueryWithOptions implements ConsensusRelayerI. +// GetABCIQueryWithOptions implements ConsensusClient. func (r CometRPCClient) GetABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { q, err := r.ABCIQueryWithOptions(ctx, path, data, opts) if err != nil { @@ -160,7 +152,7 @@ func (r CometRPCClient) GetABCIQueryWithOptions(ctx context.Context, path string return q, nil } -// GetStatus implements ConsensusRelayerI. +// GetStatus implements ConsensusClient. func (r CometRPCClient) GetStatus(ctx context.Context) (*Status, error) { s, err := r.Status(ctx) if err != nil { diff --git a/client/consensus.go b/client/consensus.go index 21e565af5..e680052a5 100644 --- a/client/consensus.go +++ b/client/consensus.go @@ -1,4 +1,4 @@ -package client +package rclient import ( "context" @@ -15,6 +15,7 @@ import ( rbytes "github.com/cosmos/relayer/v2/client/bytes" ) +// TODO(reece): get off CometBFT types into internal relayer. type ConsensusClient interface { GetBlockTime(ctx context.Context, height uint64) (time.Time, error) GetStatus(ctx context.Context) (*Status, error) @@ -34,17 +35,13 @@ type ConsensusClient interface { ) (*ResultTxSearch, error) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) - - // TODO: migrate with v2 - GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) // resp (Events), err != nil - does this need its own tm store? or does the manager have context to this - + GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) GetBlockSearch( ctx context.Context, query string, page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) - GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) GetABCIQueryWithOptions( ctx context.Context, @@ -60,7 +57,6 @@ type Status struct { } type BlockResults struct { - // TODO: ideally we get off of this into our own internal type. Then the ConsensusRelayerI can have methods to convert FinalizeBlockEvents []abci.Event `json:"finalize_block_events"` TxsResults []*abci.ExecTxResult `json:"txs_results"` } @@ -75,16 +71,6 @@ func (q ABCIQueryResponse) ValueCleaned() string { return strings.ReplaceAll(strings.TrimSpace(string(q.Value)), "\u0010", "") } -// TODO: can't do this yet as the cosmos-sdk side in v0.50 is tied to cometbft -// type Transaction struct { -// Height uint64 -// TxHash []byte -// Code uint32 -// Data string -// Events []abci.Event // TODO: []provider.RelayerEvent -// Tx cmtypes.Tx `json:"tx"` -// } - // coretypes.ResultTxSearch type ResultTxSearch struct { Txs []*coretypes.ResultTx `json:"txs"` diff --git a/interchaintest/feegrant_test.go b/interchaintest/feegrant_test.go index 9cdf8bc46..584df4b64 100644 --- a/interchaintest/feegrant_test.go +++ b/interchaintest/feegrant_test.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/go-bip39" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - "github.com/cosmos/relayer/v2/client" + rclient "github.com/cosmos/relayer/v2/client" "github.com/cosmos/relayer/v2/relayer" "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "github.com/cosmos/relayer/v2/relayer/processor" @@ -538,7 +538,7 @@ func TestRelayerFeeGrant(t *testing.T) { } } -func TxWithRetry(ctx context.Context, client client.ConsensusClient, hash []byte) (*coretypes.ResultTx, error) { +func TxWithRetry(ctx context.Context, client rclient.ConsensusClient, hash []byte) (*coretypes.ResultTx, error) { var err error var res *coretypes.ResultTx if err = retry.Do(func() error { diff --git a/relayer/chains/penumbra/provider.go b/relayer/chains/penumbra/provider.go index 4324740d2..cb1c4299c 100644 --- a/relayer/chains/penumbra/provider.go +++ b/relayer/chains/penumbra/provider.go @@ -22,7 +22,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - cwrapper "github.com/cosmos/relayer/v2/client" + rclient "github.com/cosmos/relayer/v2/client" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/cosmos/relayer/v2/relayer/provider" "github.com/strangelove-ventures/cometbft-client/client" @@ -142,7 +142,7 @@ type PenumbraProvider struct { PCfg PenumbraProviderConfig Keybase keyring.Keyring KeyringOptions []keyring.Option - RPCClient cwrapper.CometRPCClient + RPCClient rclient.CometRPCClient LightProvider provtypes.Provider Input io.Reader Output io.Writer @@ -354,7 +354,7 @@ func (cc *PenumbraProvider) setRpcClient(onStartup bool, rpcAddr string, timeout return err } - cc.RPCClient = cwrapper.NewRPCClient(c) + cc.RPCClient = rclient.NewRPCClient(c) // Only check status if not on startup, to ensure the relayer will not block on startup. // All subsequent calls will perform the status check to ensure RPC endpoints are rotated From 12b9bf7f000d2d46563d48f812dbe84939b5a3ba Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 2 Sep 2024 18:34:08 -0500 Subject: [PATCH 05/13] simplify --- client/cmbft_consensus.go | 12 +----------- client/consensus.go | 3 +-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/client/cmbft_consensus.go b/client/cmbft_consensus.go index 15aa5fe3d..a33339105 100644 --- a/client/cmbft_consensus.go +++ b/client/cmbft_consensus.go @@ -98,18 +98,8 @@ func (r CometRPCClient) GetValidators(ctx context.Context, height *int64, page * return nil, fmt.Errorf("failed to get validators: %w", err) } - vals := make([]*tmtypes.Validator, len(v.Validators)) - for i, val := range v.Validators { - vals[i] = &tmtypes.Validator{ - Address: val.Address, - PubKey: val.PubKey, - VotingPower: val.VotingPower, - ProposerPriority: val.ProposerPriority, - } - } - return &ResultValidators{ - Validators: vals, + Validators: v.Validators, }, nil } diff --git a/client/consensus.go b/client/consensus.go index e680052a5..f552445e3 100644 --- a/client/consensus.go +++ b/client/consensus.go @@ -15,7 +15,7 @@ import ( rbytes "github.com/cosmos/relayer/v2/client/bytes" ) -// TODO(reece): get off CometBFT types into internal relayer. +// TODO(reece): get off cometbft types into internal relayer. type ConsensusClient interface { GetBlockTime(ctx context.Context, height uint64) (time.Time, error) GetStatus(ctx context.Context) (*Status, error) @@ -79,7 +79,6 @@ type ResultTxSearch struct { type ResultValidators struct { Validators []*tmtypes.Validator `json:"validators"` - // Validators []Validator // TODO: requires some helper methods on the gordian side for the query to update set } type Validator struct { From 7e8f01268e31348c8a55e422902b30a3c59793fb Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 3 Sep 2024 09:07:50 -0500 Subject: [PATCH 06/13] refactor: just use cometbft bytes. helper lib for now --- client/bytes/bytes.go | 75 ------------------------------------- client/cmbft_consensus.go | 9 ++--- client/consensus.go | 14 +++---- relayer/chains/cosmos/tx.go | 4 +- 4 files changed, 12 insertions(+), 90 deletions(-) delete mode 100644 client/bytes/bytes.go diff --git a/client/bytes/bytes.go b/client/bytes/bytes.go deleted file mode 100644 index eb9ba787d..000000000 --- a/client/bytes/bytes.go +++ /dev/null @@ -1,75 +0,0 @@ -// FROM: COMETBFT -// IBC-Go also uses this package. Maybe the SDK in v2 upstreams this? - -package bytes - -import ( - "encoding/hex" - "fmt" - "strings" - - "github.com/cometbft/cometbft/libs/bytes" -) - -// HexBytes enables HEX-encoding for json/encoding. -type HexBytes []byte - -// Marshal needed for protobuf compatibility -func (bz HexBytes) Marshal() ([]byte, error) { - return bz, nil -} - -// Unmarshal needed for protobuf compatibility -func (bz *HexBytes) Unmarshal(data []byte) error { - *bz = data - return nil -} - -// This is the point of Bytes. -func (bz HexBytes) MarshalJSON() ([]byte, error) { - s := strings.ToUpper(hex.EncodeToString(bz)) - jbz := make([]byte, len(s)+2) - jbz[0] = '"' - copy(jbz[1:], s) - jbz[len(jbz)-1] = '"' - return jbz, nil -} - -// This is the point of Bytes. -func (bz *HexBytes) UnmarshalJSON(data []byte) error { - if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { - return fmt.Errorf("invalid hex string: %s", data) - } - bz2, err := hex.DecodeString(string(data[1 : len(data)-1])) - if err != nil { - return err - } - *bz = bz2 - return nil -} - -// Bytes fulfills various interfaces in light-client, etc... -func (bz HexBytes) Bytes() []byte { - return bz -} - -func (bz HexBytes) String() string { - return strings.ToUpper(hex.EncodeToString(bz)) -} - -// Format writes either address of 0th element in a slice in base 16 notation, -// with leading 0x (%p), or casts HexBytes to bytes and writes as hexadecimal -// string to s. -func (bz HexBytes) Format(s fmt.State, verb rune) { - switch verb { - case 'p': - s.Write([]byte(fmt.Sprintf("%p", bz))) - default: - s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) - } -} - -// ConvertCometBFTToHexBytes converts a cometbft bytes.HexBytes to relayer HexBytes. -func ConvertCometBFTToHexBytes(cbft bytes.HexBytes) HexBytes { - return HexBytes(cbft) -} diff --git a/client/cmbft_consensus.go b/client/cmbft_consensus.go index a33339105..b449af8c6 100644 --- a/client/cmbft_consensus.go +++ b/client/cmbft_consensus.go @@ -9,7 +9,6 @@ import ( rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" - rbytes "github.com/cosmos/relayer/v2/client/bytes" ) var _ ConsensusClient = (*CometRPCClient)(nil) @@ -111,10 +110,10 @@ func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) ( } return &ResultBroadcastTx{ Code: b.Code, - Data: rbytes.ConvertCometBFTToHexBytes(b.Data), + Data: b.Data, Log: b.Log, Codespace: b.Codespace, - Hash: rbytes.ConvertCometBFTToHexBytes(b.Hash), + Hash: b.Hash, }, nil } @@ -126,10 +125,10 @@ func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (* } return &ResultBroadcastTx{ Code: b.Code, - Data: rbytes.ConvertCometBFTToHexBytes(b.Data), + Data: b.Data, Log: b.Log, Codespace: b.Codespace, - Hash: rbytes.ConvertCometBFTToHexBytes(b.Hash), + Hash: b.Hash, }, nil } diff --git a/client/consensus.go b/client/consensus.go index f552445e3..1226799ce 100644 --- a/client/consensus.go +++ b/client/consensus.go @@ -7,12 +7,10 @@ import ( abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto" + bytes "github.com/cometbft/cometbft/libs/bytes" rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" - - bytes "github.com/cometbft/cometbft/libs/bytes" - rbytes "github.com/cosmos/relayer/v2/client/bytes" ) // TODO(reece): get off cometbft types into internal relayer. @@ -89,9 +87,9 @@ type Validator struct { } type ResultBroadcastTx struct { - Code uint32 `json:"code"` - Data rbytes.HexBytes `json:"data"` - Log string `json:"log"` - Codespace string `json:"codespace"` - Hash rbytes.HexBytes `json:"hash"` + Code uint32 `json:"code"` + Data bytes.HexBytes `json:"data"` + Log string `json:"log"` + Codespace string `json:"codespace"` + Hash bytes.HexBytes `json:"hash"` } diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index ea03a9dce..70f239878 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -18,6 +18,7 @@ import ( "cosmossdk.io/store/rootmulti" "github.com/avast/retry-go/v4" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/bytes" "github.com/cometbft/cometbft/light" client2 "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" @@ -43,7 +44,6 @@ import ( tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" rclient "github.com/cosmos/relayer/v2/client" - rbytes "github.com/cosmos/relayer/v2/client/bytes" strideicqtypes "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" "github.com/cosmos/relayer/v2/relayer/ethermint" "github.com/cosmos/relayer/v2/relayer/provider" @@ -234,7 +234,7 @@ func (cc *CosmosProvider) SubmitTxAwaitResponse(ctx context.Context, msgs []sdk. } // Get the TX by hash, waiting for it to be included in a block -func (cc *CosmosProvider) AwaitTx(txHash rbytes.HexBytes, timeout time.Duration) (*txtypes.GetTxResponse, error) { +func (cc *CosmosProvider) AwaitTx(txHash bytes.HexBytes, timeout time.Duration) (*txtypes.GetTxResponse, error) { var txByHash *txtypes.GetTxResponse var txLookupErr error startTime := time.Now() From 5f7a8b3b59b98ba31df01f59bb793deda3a4c682 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 3 Sep 2024 09:13:58 -0500 Subject: [PATCH 07/13] refactor: rename rclient -> cclient (consensus client) --- {client => cclient}/cmbft_client_wrapper.go | 7 ++-- {client => cclient}/cmbft_consensus.go | 5 ++- {client => cclient}/consensus.go | 5 ++- interchaintest/feegrant_test.go | 4 +-- .../chains/cosmos/cosmos_chain_processor.go | 6 ++-- relayer/chains/cosmos/provider.go | 6 ++-- relayer/chains/cosmos/query.go | 4 +-- relayer/chains/cosmos/tx.go | 4 +-- .../penumbra/penumbra_chain_processor.go | 2 +- relayer/chains/penumbra/provider.go | 32 +++++++++---------- relayer/chains/penumbra/query.go | 18 +++++------ relayer/chains/penumbra/tx.go | 14 ++++---- 12 files changed, 52 insertions(+), 55 deletions(-) rename {client => cclient}/cmbft_client_wrapper.go (99%) rename {client => cclient}/cmbft_consensus.go (98%) rename {client => cclient}/consensus.go (95%) diff --git a/client/cmbft_client_wrapper.go b/cclient/cmbft_client_wrapper.go similarity index 99% rename from client/cmbft_client_wrapper.go rename to cclient/cmbft_client_wrapper.go index 4f4c95f98..9338060f8 100644 --- a/client/cmbft_client_wrapper.go +++ b/cclient/cmbft_client_wrapper.go @@ -1,4 +1,4 @@ -package rclient +package cclient import ( "context" @@ -34,7 +34,7 @@ type CometRPCClient struct { c *client.Client } -func NewRPCClient(c *client.Client) CometRPCClient { +func NewCometRPCClient(c *client.Client) CometRPCClient { return CometRPCClient{c: c} } @@ -388,8 +388,7 @@ func (r CometRPCClient) BlockSearch( } return &coretypes.ResultBlockSearch{ - Blocks: blocks, - TotalCount: res.TotalCount, + Blocks: blocks, }, nil } diff --git a/client/cmbft_consensus.go b/cclient/cmbft_consensus.go similarity index 98% rename from client/cmbft_consensus.go rename to cclient/cmbft_consensus.go index b449af8c6..7a0a40e99 100644 --- a/client/cmbft_consensus.go +++ b/cclient/cmbft_consensus.go @@ -1,4 +1,4 @@ -package rclient +package cclient import ( "context" @@ -66,8 +66,7 @@ func (r CometRPCClient) GetTxSearch(ctx context.Context, query string, prove boo return nil, fmt.Errorf("failed to get tx search: %w", err) } return &ResultTxSearch{ - Txs: resp.Txs, - TotalCount: resp.TotalCount, + Txs: resp.Txs, }, nil } diff --git a/client/consensus.go b/cclient/consensus.go similarity index 95% rename from client/consensus.go rename to cclient/consensus.go index 1226799ce..b185d34af 100644 --- a/client/consensus.go +++ b/cclient/consensus.go @@ -1,4 +1,4 @@ -package rclient +package cclient import ( "context" @@ -71,8 +71,7 @@ func (q ABCIQueryResponse) ValueCleaned() string { // coretypes.ResultTxSearch type ResultTxSearch struct { - Txs []*coretypes.ResultTx `json:"txs"` - TotalCount int `json:"total_count"` + Txs []*coretypes.ResultTx `json:"txs"` } type ResultValidators struct { diff --git a/interchaintest/feegrant_test.go b/interchaintest/feegrant_test.go index 584df4b64..977bd792e 100644 --- a/interchaintest/feegrant_test.go +++ b/interchaintest/feegrant_test.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/go-bip39" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" "github.com/cosmos/relayer/v2/relayer" "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "github.com/cosmos/relayer/v2/relayer/processor" @@ -538,7 +538,7 @@ func TestRelayerFeeGrant(t *testing.T) { } } -func TxWithRetry(ctx context.Context, client rclient.ConsensusClient, hash []byte) (*coretypes.ResultTx, error) { +func TxWithRetry(ctx context.Context, client cclient.ConsensusClient, hash []byte) (*coretypes.ResultTx, error) { var err error var res *coretypes.ResultTx if err = retry.Do(func() error { diff --git a/relayer/chains/cosmos/cosmos_chain_processor.go b/relayer/chains/cosmos/cosmos_chain_processor.go index 0d8e9486f..dea00a435 100644 --- a/relayer/chains/cosmos/cosmos_chain_processor.go +++ b/relayer/chains/cosmos/cosmos_chain_processor.go @@ -13,7 +13,7 @@ import ( conntypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" "github.com/cosmos/relayer/v2/relayer/chains" "github.com/cosmos/relayer/v2/relayer/processor" "github.com/cosmos/relayer/v2/relayer/provider" @@ -149,7 +149,7 @@ func (ccp *CosmosChainProcessor) latestHeightWithRetry(ctx context.Context) (lat // nodeStatusWithRetry will query for the latest node status, retrying in case of failure. // It will delay by latestHeightQueryRetryDelay between attempts, up to latestHeightQueryRetries. -func (ccp *CosmosChainProcessor) nodeStatusWithRetry(ctx context.Context) (status *rclient.Status, err error) { +func (ccp *CosmosChainProcessor) nodeStatusWithRetry(ctx context.Context) (status *cclient.Status, err error) { return status, retry.Do(func() error { latestHeightQueryCtx, cancelLatestHeightQueryCtx := context.WithTimeout(ctx, queryTimeout) defer cancelLatestHeightQueryCtx() @@ -393,7 +393,7 @@ func (ccp *CosmosChainProcessor) queryCycle(ctx context.Context, persistence *qu for i := persistence.latestQueriedBlock + 1; i <= persistence.latestHeight; i++ { var ( eg errgroup.Group - blockRes *rclient.BlockResults + blockRes *cclient.BlockResults ibcHeader provider.IBCHeader ) diff --git a/relayer/chains/cosmos/provider.go b/relayer/chains/cosmos/provider.go index 75c458d00..11491be8c 100644 --- a/relayer/chains/cosmos/provider.go +++ b/relayer/chains/cosmos/provider.go @@ -19,7 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/gogoproto/proto" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/cosmos/relayer/v2/relayer/processor" "github.com/cosmos/relayer/v2/relayer/provider" @@ -127,7 +127,7 @@ type CosmosProvider struct { PCfg CosmosProviderConfig Keybase keyring.Keyring KeyringOptions []keyring.Option - ConsensusClient rclient.ConsensusClient + ConsensusClient cclient.ConsensusClient LightProvider provtypes.Provider Input io.Reader Output io.Writer @@ -401,7 +401,7 @@ func (cc *CosmosProvider) setRpcClient(onStartup bool, rpcAddr string, timeout t return err } - cc.ConsensusClient = rclient.NewRPCClient(c) + cc.ConsensusClient = cclient.NewCometRPCClient(c) // Only check status if not on startup, to ensure the relayer will not block on startup. // All subsequent calls will perform the status check to ensure RPC endpoints are rotated diff --git a/relayer/chains/cosmos/query.go b/relayer/chains/cosmos/query.go index 5be04f88a..0bce53f42 100644 --- a/relayer/chains/cosmos/query.go +++ b/relayer/chains/cosmos/query.go @@ -32,7 +32,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" "github.com/cosmos/relayer/v2/relayer/chains" "github.com/cosmos/relayer/v2/relayer/provider" "go.uber.org/zap" @@ -1212,7 +1212,7 @@ func (cc *CosmosProvider) QueryLatestHeight(ctx context.Context) (int64, error) } // Query current node status -func (cc *CosmosProvider) QueryStatus(ctx context.Context) (*rclient.Status, error) { +func (cc *CosmosProvider) QueryStatus(ctx context.Context) (*cclient.Status, error) { status, err := cc.ConsensusClient.GetStatus(ctx) if err != nil { return nil, fmt.Errorf("failed to query node status: %w", err) diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index 70f239878..06081995f 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -43,7 +43,7 @@ import ( ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" strideicqtypes "github.com/cosmos/relayer/v2/relayer/chains/cosmos/stride" "github.com/cosmos/relayer/v2/relayer/ethermint" "github.com/cosmos/relayer/v2/relayer/provider" @@ -266,7 +266,7 @@ func (cc *CosmosProvider) AwaitTx(txHash bytes.HexBytes, timeout time.Duration) // sent and executed successfully is returned. // // feegranterKey - key name of the address set as the feegranter, empty string will not feegrant -func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo string, gas uint64, signingKey string, feegranterKey string) (*rclient.ResultBroadcastTx, error) { +func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo string, gas uint64, signingKey string, feegranterKey string) (*cclient.ResultBroadcastTx, error) { sdkConfigMutex.Lock() sdkConf := sdk.GetConfig() sdkConf.SetBech32PrefixForAccount(cc.PCfg.AccountPrefix, cc.PCfg.AccountPrefix+"pub") diff --git a/relayer/chains/penumbra/penumbra_chain_processor.go b/relayer/chains/penumbra/penumbra_chain_processor.go index 2944a4570..7bea56b33 100644 --- a/relayer/chains/penumbra/penumbra_chain_processor.go +++ b/relayer/chains/penumbra/penumbra_chain_processor.go @@ -337,7 +337,7 @@ func (pcp *PenumbraChainProcessor) queryCycle(ctx context.Context, persistence * queryCtx, cancelQueryCtx := context.WithTimeout(ctx, blockResultsQueryTimeout) defer cancelQueryCtx() - blockRes, err = pcp.chainProvider.RPCClient.BlockResults(queryCtx, &i) + blockRes, err = pcp.chainProvider.ConsensusClient.BlockResults(queryCtx, &i) return err }) diff --git a/relayer/chains/penumbra/provider.go b/relayer/chains/penumbra/provider.go index cb1c4299c..c4ef95f96 100644 --- a/relayer/chains/penumbra/provider.go +++ b/relayer/chains/penumbra/provider.go @@ -22,7 +22,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - rclient "github.com/cosmos/relayer/v2/client" + "github.com/cosmos/relayer/v2/cclient" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/cosmos/relayer/v2/relayer/provider" "github.com/strangelove-ventures/cometbft-client/client" @@ -139,15 +139,15 @@ func (h PenumbraIBCHeader) NextValidatorsHash() []byte { type PenumbraProvider struct { log *zap.Logger - PCfg PenumbraProviderConfig - Keybase keyring.Keyring - KeyringOptions []keyring.Option - RPCClient rclient.CometRPCClient - LightProvider provtypes.Provider - Input io.Reader - Output io.Writer - Codec Codec - RPCCaller jsonrpcclient.Caller + PCfg PenumbraProviderConfig + Keybase keyring.Keyring + KeyringOptions []keyring.Option + ConsensusClient cclient.CometRPCClient + LightProvider provtypes.Provider + Input io.Reader + Output io.Writer + Codec Codec + RPCCaller jsonrpcclient.Caller } func (cc *PenumbraProvider) ProviderConfig() provider.ProviderConfig { @@ -303,7 +303,7 @@ func (cc *PenumbraProvider) startLivelinessChecks(ctx context.Context, timeout t case <-ctx.Done(): return case <-ticker.C: - _, err := cc.RPCClient.Status(ctx) + _, err := cc.ConsensusClient.Status(ctx) if err != nil { cc.log.Error("RPC client disconnected", zap.String("chain", cc.ChainName()), zap.Error(err)) @@ -354,13 +354,13 @@ func (cc *PenumbraProvider) setRpcClient(onStartup bool, rpcAddr string, timeout return err } - cc.RPCClient = rclient.NewRPCClient(c) + cc.ConsensusClient = cclient.NewCometRPCClient(c) // Only check status if not on startup, to ensure the relayer will not block on startup. // All subsequent calls will perform the status check to ensure RPC endpoints are rotated // as necessary. if !onStartup { - if _, err = cc.RPCClient.Status(context.Background()); err != nil { + if _, err = cc.ConsensusClient.Status(context.Background()); err != nil { return err } } @@ -382,7 +382,7 @@ func (cc *PenumbraProvider) setLightProvider(rpcAddr string) error { // WaitForNBlocks blocks until the next block on a given chain func (cc *PenumbraProvider) WaitForNBlocks(ctx context.Context, n int64) error { var initial int64 - h, err := cc.RPCClient.Status(ctx) + h, err := cc.ConsensusClient.Status(ctx) if err != nil { return err } @@ -391,7 +391,7 @@ func (cc *PenumbraProvider) WaitForNBlocks(ctx context.Context, n int64) error { } initial = h.SyncInfo.LatestBlockHeight for { - h, err = cc.RPCClient.Status(ctx) + h, err = cc.ConsensusClient.Status(ctx) if err != nil { return err } @@ -408,7 +408,7 @@ func (cc *PenumbraProvider) WaitForNBlocks(ctx context.Context, n int64) error { } func (cc *PenumbraProvider) BlockTime(ctx context.Context, height int64) (time.Time, error) { - resultBlock, err := cc.RPCClient.Block(ctx, &height) + resultBlock, err := cc.ConsensusClient.Block(ctx, &height) if err != nil { return time.Time{}, err } diff --git a/relayer/chains/penumbra/query.go b/relayer/chains/penumbra/query.go index 615428799..518aa0764 100644 --- a/relayer/chains/penumbra/query.go +++ b/relayer/chains/penumbra/query.go @@ -42,7 +42,7 @@ func (cc *PenumbraProvider) QueryTx(ctx context.Context, hashHex string) (*provi return nil, err } - resp, err := cc.RPCClient.Tx(ctx, hash, true) + resp, err := cc.ConsensusClient.Tx(ctx, hash, true) if err != nil { return nil, err } @@ -72,7 +72,7 @@ func (cc *PenumbraProvider) QueryTxs(ctx context.Context, page, limit int, event return nil, errors.New("limit must greater than 0") } - res, err := cc.RPCClient.TxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") + res, err := cc.ConsensusClient.TxSearch(ctx, strings.Join(events, " AND "), true, &page, &limit, "") if err != nil { return nil, err } @@ -380,7 +380,7 @@ func (cc *PenumbraProvider) QueryUpgradedConsState(ctx context.Context, height i // QueryConsensusState returns a consensus state for a given chain to be used as a // client in another chain, fetches latest height when passed 0 as arg func (cc *PenumbraProvider) QueryConsensusState(ctx context.Context, height int64) (ibcexported.ConsensusState, int64, error) { - commit, err := cc.RPCClient.Commit(ctx, &height) + commit, err := cc.ConsensusClient.Commit(ctx, &height) if err != nil { return &tmclient.ConsensusState{}, 0, err } @@ -389,7 +389,7 @@ func (cc *PenumbraProvider) QueryConsensusState(ctx context.Context, height int6 count := 10_000 nextHeight := height + 1 - nextVals, err := cc.RPCClient.Validators(ctx, &nextHeight, &page, &count) + nextVals, err := cc.ConsensusClient.Validators(ctx, &nextHeight, &page, &count) if err != nil { return &tmclient.ConsensusState{}, 0, err } @@ -787,7 +787,7 @@ func (cc *PenumbraProvider) QueryPacketReceipt(ctx context.Context, height int64 } func (cc *PenumbraProvider) QueryLatestHeight(ctx context.Context) (int64, error) { - stat, err := cc.RPCClient.Status(ctx) + stat, err := cc.ConsensusClient.Status(ctx) if err != nil { return -1, err } else if stat.SyncInfo.CatchingUp { @@ -806,12 +806,12 @@ func (cc *PenumbraProvider) QueryHeaderAtHeight(ctx context.Context, height int6 return nil, fmt.Errorf("must pass in valid height, %d not valid", height) } - res, err := cc.RPCClient.Commit(ctx, &height) + res, err := cc.ConsensusClient.Commit(ctx, &height) if err != nil { return nil, err } - val, err := cc.RPCClient.Validators(ctx, &height, &page, &perPage) + val, err := cc.ConsensusClient.Validators(ctx, &height, &page, &perPage) if err != nil { return nil, err } @@ -922,7 +922,7 @@ func (cc *PenumbraProvider) queryIBCMessages(ctx context.Context, log *zap.Logge return nil, errors.New("limit must greater than 0") } - res, err := cc.RPCClient.TxSearch(ctx, query, true, &page, &limit, "") + res, err := cc.ConsensusClient.TxSearch(ctx, query, true, &page, &limit, "") if err != nil { return nil, err } @@ -1004,7 +1004,7 @@ func (cc *PenumbraProvider) QueryRecvPacket( // QueryStatus queries the current node status. func (cc *PenumbraProvider) QueryStatus(ctx context.Context) (*coretypes.ResultStatus, error) { - status, err := cc.RPCClient.Status(ctx) + status, err := cc.ConsensusClient.Status(ctx) if err != nil { return nil, fmt.Errorf("failed to query node status: %w", err) } diff --git a/relayer/chains/penumbra/tx.go b/relayer/chains/penumbra/tx.go index dbf8a2547..5ce21696a 100644 --- a/relayer/chains/penumbra/tx.go +++ b/relayer/chains/penumbra/tx.go @@ -248,7 +248,7 @@ type ValidatorUpdate struct { } func (cc *PenumbraProvider) getAnchor(ctx context.Context) (*penumbracrypto.MerkleRoot, error) { - status, err := cc.RPCClient.Status(ctx) + status, err := cc.ConsensusClient.Status(ctx) if err != nil { return nil, err } @@ -345,7 +345,7 @@ func (cc *PenumbraProvider) sendMessagesInner(ctx context.Context, msgs []provid return nil, err } - return cc.RPCClient.BroadcastTxSync(ctx, txBytes) + return cc.ConsensusClient.BroadcastTxSync(ctx, txBytes) } // SendMessages attempts to sign, encode, & send a slice of RelayerMessages @@ -372,7 +372,7 @@ func (cc *PenumbraProvider) SendMessages(ctx context.Context, msgs []provider.Re ctx, cancel := context.WithTimeout(ctx, 40*time.Second) defer cancel() - res, err := cc.RPCClient.Tx(ctx, syncRes.Hash, false) + res, err := cc.ConsensusClient.Tx(ctx, syncRes.Hash, false) if err != nil { return err } @@ -2078,7 +2078,7 @@ func (cc *PenumbraProvider) QueryABCI(ctx context.Context, req abci.RequestQuery Prove: req.Prove, } - result, err := cc.RPCClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts) + result, err := cc.ConsensusClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts) if err != nil { return abci.ResponseQuery{}, err } @@ -2153,7 +2153,7 @@ func (cc *PenumbraProvider) broadcastTx( asyncTimeout time.Duration, // timeout for waiting for block inclusion asyncCallback func(*provider.RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion ) error { - res, err := cc.RPCClient.BroadcastTxSync(ctx, tx) + res, err := cc.ConsensusClient.BroadcastTxSync(ctx, tx) isErr := err != nil isFailed := res != nil && res.Code != 0 if isErr || isFailed { @@ -2249,12 +2249,12 @@ func (cc *PenumbraProvider) waitForBlockInclusion( 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) + res, err := cc.ConsensusClient.Tx(ctx, txHash, false) if err == nil { return cc.mkTxResult(res) } if strings.Contains(err.Error(), "transaction indexing is disabled") { - return nil,errors.New("cannot determine success/failure of tx because transaction indexing is disabled on rpc url") + return nil, errors.New("cannot determine success/failure of tx because transaction indexing is disabled on rpc url") } case <-ctx.Done(): return nil, ctx.Err() From b3b4006ab1b9fbc5c4ae68d3ec106e84664133ac Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 4 Sep 2024 21:03:06 -0500 Subject: [PATCH 08/13] `GordianConsensus` base --- ...{cmbft_consensus.go => consensus_cmbft.go} | 0 cclient/consensus_gordian.go | 105 ++++++++++++++++++ cclient/gordian_test.go | 21 ++++ 3 files changed, 126 insertions(+) rename cclient/{cmbft_consensus.go => consensus_cmbft.go} (100%) create mode 100644 cclient/consensus_gordian.go create mode 100644 cclient/gordian_test.go diff --git a/cclient/cmbft_consensus.go b/cclient/consensus_cmbft.go similarity index 100% rename from cclient/cmbft_consensus.go rename to cclient/consensus_cmbft.go diff --git a/cclient/consensus_gordian.go b/cclient/consensus_gordian.go new file mode 100644 index 000000000..c80569190 --- /dev/null +++ b/cclient/consensus_gordian.go @@ -0,0 +1,105 @@ +package cclient + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "os" + "time" + + "github.com/cometbft/cometbft/libs/bytes" + "github.com/cometbft/cometbft/rpc/client" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cometbft/cometbft/types" +) + +var _ ConsensusClient = (*GordianConsensus)(nil) + +type GordianConsensus struct { + // temp until IBC-Go is updated so we can import & use gRPC + addr string +} + +func NewGordianConsensus(addr string) *GordianConsensus { + return &GordianConsensus{ + addr: addr, + } +} + +// DoBroadcastTxAsync implements ConsensusClient. +func (g *GordianConsensus) DoBroadcastTxAsync(ctx context.Context, tx types.Tx) (*ResultBroadcastTx, error) { + panic("unimplemented") +} + +// DoBroadcastTxSync implements ConsensusClient. +func (g *GordianConsensus) DoBroadcastTxSync(ctx context.Context, tx types.Tx) (*ResultBroadcastTx, error) { + panic("unimplemented") +} + +// GetABCIQuery implements ConsensusClient. +func (g *GordianConsensus) GetABCIQuery(ctx context.Context, queryPath string, data bytes.HexBytes) (*ABCIQueryResponse, error) { + panic("unimplemented") +} + +// GetABCIQueryWithOptions implements ConsensusClient. +func (g *GordianConsensus) GetABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { + panic("unimplemented") +} + +// GetBlockResults implements ConsensusClient. +func (g *GordianConsensus) GetBlockResults(ctx context.Context, height uint64) (*BlockResults, error) { + panic("unimplemented") +} + +// GetBlockSearch implements ConsensusClient. +func (g *GordianConsensus) GetBlockSearch(ctx context.Context, query string, page *int, perPage *int, orderBy string) (*coretypes.ResultBlockSearch, error) { + panic("unimplemented") +} + +// GetBlockTime implements ConsensusClient. +func (g *GordianConsensus) GetBlockTime(ctx context.Context, height uint64) (time.Time, error) { + res, err := http.Get(fmt.Sprintf("%s/block/%d", g.addr, height)) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + // decode into type (copy pasted from gserver/internal/ggrpc + type GetBlockResponse struct { + Time uint64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"` // nanoseconds + } + + var resp GetBlockResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + os.Exit(1) + } + + return time.Unix(int64(resp.Time), 0), nil +} + +// GetCommit implements ConsensusClient. +func (g *GordianConsensus) GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) { + panic("unimplemented") +} + +// GetStatus implements ConsensusClient. +func (g *GordianConsensus) GetStatus(ctx context.Context) (*Status, error) { + panic("unimplemented") +} + +// GetTx implements ConsensusClient. +func (g *GordianConsensus) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { + panic("unimplemented") +} + +// GetTxSearch implements ConsensusClient. +func (g *GordianConsensus) GetTxSearch(ctx context.Context, query string, prove bool, page *int, perPage *int, orderBy string) (*ResultTxSearch, error) { + panic("unimplemented") +} + +// GetValidators implements ConsensusClient. +func (g *GordianConsensus) GetValidators(ctx context.Context, height *int64, page *int, perPage *int) (*ResultValidators, error) { + panic("unimplemented") +} diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go new file mode 100644 index 000000000..b079d5134 --- /dev/null +++ b/cclient/gordian_test.go @@ -0,0 +1,21 @@ +package cclient_test + +import ( + "context" + "testing" + "time" + + "github.com/cosmos/relayer/v2/cclient" +) + +func TestGordian(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + gc := cclient.NewGordianConsensus("http://127.0.0.1:26657") + bt, err := gc.GetBlockTime(ctx, 2) + if err != nil { + t.Error(err) + } + t.Log(bt) +} From 92b4c038ed9bbff79f091e500af363f84a91f257 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 4 Sep 2024 22:34:41 -0500 Subject: [PATCH 09/13] gordian: ec9423087caf49 (reece/ibc-slop-backup) --- cclient/consensus.go | 15 ++- cclient/consensus_cmbft.go | 6 +- cclient/consensus_gordian.go | 200 +++++++++++++++++++++++++++++++++-- cclient/gordian_test.go | 31 +++++- relayer/chains/cosmos/tx.go | 6 +- 5 files changed, 234 insertions(+), 24 deletions(-) diff --git a/cclient/consensus.go b/cclient/consensus.go index b185d34af..37a9d1701 100644 --- a/cclient/consensus.go +++ b/cclient/consensus.go @@ -6,7 +6,6 @@ import ( "time" abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto" bytes "github.com/cometbft/cometbft/libs/bytes" rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" @@ -31,7 +30,7 @@ type ConsensusClient interface { page, perPage *int, orderBy string, ) (*ResultTxSearch, error) - DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) + DoBroadcastTxSync(ctx context.Context, tx []byte) (*TxResultResponse, error) // TODO: is tx []byte fine or does it need to be tx tmtypes.Tx? DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) GetBlockSearch( @@ -78,12 +77,12 @@ type ResultValidators struct { Validators []*tmtypes.Validator `json:"validators"` } -type Validator struct { - Address crypto.Address `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` - VotingPower int64 `json:"voting_power"` - ProposerPriority int64 `json:"proposer_priority"` -} +// type Validator struct { +// Address crypto.Address `json:"address"` +// PubKey crypto.PubKey `json:"pub_key"` +// VotingPower int64 `json:"voting_power"` +// ProposerPriority int64 `json:"proposer_priority"` +// } type ResultBroadcastTx struct { Code uint32 `json:"code"` diff --git a/cclient/consensus_cmbft.go b/cclient/consensus_cmbft.go index 7a0a40e99..ca28020df 100644 --- a/cclient/consensus_cmbft.go +++ b/cclient/consensus_cmbft.go @@ -117,17 +117,17 @@ func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) ( } // DoBroadcastTxSync implements ConsensusClient. -func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { +func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx []byte) (*TxResultResponse, error) { b, err := r.BroadcastTxSync(ctx, tx) if err != nil { return nil, fmt.Errorf("failed to broadcast tx sync: %w", err) } - return &ResultBroadcastTx{ + return &TxResultResponse{ Code: b.Code, Data: b.Data, Log: b.Log, Codespace: b.Codespace, - Hash: b.Hash, + TxHash: string(b.Hash), }, nil } diff --git a/cclient/consensus_gordian.go b/cclient/consensus_gordian.go index c80569190..e1876bc43 100644 --- a/cclient/consensus_gordian.go +++ b/cclient/consensus_gordian.go @@ -1,17 +1,22 @@ package cclient import ( + "bytes" "context" "encoding/json" "fmt" + "io" "net/http" "os" "time" - "github.com/cometbft/cometbft/libs/bytes" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto" + cmtbytes "github.com/cometbft/cometbft/libs/bytes" "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cometbft/cometbft/types" + tmtypes "github.com/cometbft/cometbft/types" ) var _ ConsensusClient = (*GordianConsensus)(nil) @@ -27,23 +32,87 @@ func NewGordianConsensus(addr string) *GordianConsensus { } } +type TxResultResponse struct { + Events []*Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` + // bytes resp = 2; // []transaction.Msg + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + Code uint32 `protobuf:"varint,4,opt,name=code,proto3" json:"code,omitempty"` + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + Log string `protobuf:"bytes,6,opt,name=log,proto3" json:"log,omitempty"` + Info string `protobuf:"bytes,7,opt,name=info,proto3" json:"info,omitempty"` + GasWanted uint64 `protobuf:"varint,8,opt,name=gas_wanted,proto3" json:"gas_wanted,omitempty"` + GasUsed uint64 `protobuf:"varint,9,opt,name=gas_used,proto3" json:"gas_used,omitempty"` + Codespace string `protobuf:"bytes,10,opt,name=codespace,proto3" json:"codespace,omitempty"` + TxHash string `protobuf:"bytes,11,opt,name=tx_hash,proto3" json:"tx_hash,omitempty"` +} +type Event struct { + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Attributes []*EventAttribute `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"` +} + +func convertConsensusEvents(e []*Event) []abci.Event { + events := make([]abci.Event, len(e)) + for _, ev := range e { + attributes := make([]abci.EventAttribute, len(ev.Attributes)) + for idx, attr := range ev.Attributes { + attributes[idx] = abci.EventAttribute{ + Key: attr.Key, + Value: attr.Value, + } + } + + events = append(events, abci.Event{ + Type: ev.Type, + Attributes: attributes, + }) + } + return events +} + +type EventAttribute struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +// ----- + // DoBroadcastTxAsync implements ConsensusClient. func (g *GordianConsensus) DoBroadcastTxAsync(ctx context.Context, tx types.Tx) (*ResultBroadcastTx, error) { panic("unimplemented") } // DoBroadcastTxSync implements ConsensusClient. -func (g *GordianConsensus) DoBroadcastTxSync(ctx context.Context, tx types.Tx) (*ResultBroadcastTx, error) { - panic("unimplemented") +func (g *GordianConsensus) DoBroadcastTxSync(ctx context.Context, tx []byte) (*TxResultResponse, error) { + var body io.Reader + if tx != nil { + body = bytes.NewReader(tx) + } else { + return nil, fmt.Errorf("DoBroadcastTxSync tx is nil") + } + + res, err := http.Post(fmt.Sprintf("%s/debug/submit_tx", g.addr), "application/json", body) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + var resp TxResultResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + return nil, err + } + + return &resp, nil + } // GetABCIQuery implements ConsensusClient. -func (g *GordianConsensus) GetABCIQuery(ctx context.Context, queryPath string, data bytes.HexBytes) (*ABCIQueryResponse, error) { +func (g *GordianConsensus) GetABCIQuery(ctx context.Context, queryPath string, data cmtbytes.HexBytes) (*ABCIQueryResponse, error) { panic("unimplemented") } // GetABCIQueryWithOptions implements ConsensusClient. -func (g *GordianConsensus) GetABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { +func (g *GordianConsensus) GetABCIQueryWithOptions(ctx context.Context, path string, data cmtbytes.HexBytes, opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { panic("unimplemented") } @@ -86,12 +155,58 @@ func (g *GordianConsensus) GetCommit(ctx context.Context, height uint64) (*coret // GetStatus implements ConsensusClient. func (g *GordianConsensus) GetStatus(ctx context.Context) (*Status, error) { - panic("unimplemented") + res, err := http.Get(fmt.Sprintf("%s/status", g.addr)) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + // decode into type (copy pasted from gserver/internal/ggrpc + type GetStatusResponse struct { + CatchingUp bool `protobuf:"varint,1,opt,name=catching_up,json=catchingUp,proto3" json:"catching_up,omitempty"` + LatestBlockHeight uint64 `protobuf:"varint,2,opt,name=latest_block_height,json=latestBlockHeight,proto3" json:"latest_block_height,omitempty"` + } + + var resp GetStatusResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + os.Exit(1) + } + + return &Status{ + CatchingUp: resp.CatchingUp, + LatestBlockHeight: resp.LatestBlockHeight, + }, nil } // GetTx implements ConsensusClient. func (g *GordianConsensus) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { - panic("unimplemented") + res, err := http.Get(fmt.Sprintf("%s/tx/%s", g.addr, hash)) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + var resp TxResultResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + os.Exit(1) + } + + return &coretypes.ResultTx{ + Hash: cmtbytes.HexBytes(resp.TxHash), + Height: 999, // TODO: debugging + TxResult: abci.ExecTxResult{ + Code: resp.Code, + Data: resp.Data, + Log: resp.Log, + Info: resp.Info, + GasWanted: int64(resp.GasWanted), + GasUsed: int64(resp.GasUsed), + Events: convertConsensusEvents(resp.Events), + Codespace: resp.Codespace, + }, + }, nil } // GetTxSearch implements ConsensusClient. @@ -99,7 +214,78 @@ func (g *GordianConsensus) GetTxSearch(ctx context.Context, query string, prove panic("unimplemented") } +// TODO: GetValidators needs pubkey -> address conversions // GetValidators implements ConsensusClient. func (g *GordianConsensus) GetValidators(ctx context.Context, height *int64, page *int, perPage *int) (*ResultValidators, error) { + // coppied & modified namespace to GordianValidator + type GordianValidator struct { + EncodedPubKey []byte `protobuf:"bytes,1,opt,name=encoded_pub_key,json=encodedPubKey,proto3" json:"encoded_pub_key,omitempty"` + Power uint64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` + } + type GetValidatorsResponse struct { + FinalizationHeight *uint64 `protobuf:"varint,1,opt,name=finalization_height,json=finalizationHeight,proto3,oneof" json:"finalization_height,omitempty"` + Validators []*GordianValidator `protobuf:"bytes,2,rep,name=validators,proto3" json:"validators,omitempty"` + } + + res, err := http.Get(fmt.Sprintf("%s/validators", g.addr)) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + var resp GetValidatorsResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + os.Exit(1) + } + + converted := make([]*tmtypes.Validator, len(resp.Validators)) + + for i, v := range resp.Validators { + tmk := &tmPubKeyHack{pubKey: v.EncodedPubKey} + + converted[i] = &tmtypes.Validator{ + Address: tmk.Address(), + PubKey: tmk, + VotingPower: int64(v.Power), + ProposerPriority: -1, // TODO: do we need this for any reason? + } + } + + return &ResultValidators{ + Validators: converted, + }, nil +} + +var _ crypto.PubKey = (*tmPubKeyHack)(nil) + +// tmPubKeyHack is a temp workaround to make pubkeys happy. In the future we can build a better interface wrapper +// or struct using the gordian crypto lib. +type tmPubKeyHack struct { + pubKey []byte +} + +// Address implements crypto.PubKey. +func (t *tmPubKeyHack) Address() cmtbytes.HexBytes { + return t.pubKey +} + +// Bytes implements crypto.PubKey. +func (t *tmPubKeyHack) Bytes() []byte { + return t.pubKey +} + +// Equals implements crypto.PubKey. +func (t *tmPubKeyHack) Equals(pk crypto.PubKey) bool { + return bytes.Equal(t.pubKey, pk.Bytes()) +} + +// Type implements crypto.PubKey. +func (t *tmPubKeyHack) Type() string { + return "ed25519" +} + +// VerifySignature implements crypto.PubKey. +func (t *tmPubKeyHack) VerifySignature(msg []byte, sig []byte) bool { panic("unimplemented") } diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go index b079d5134..3c80053d6 100644 --- a/cclient/gordian_test.go +++ b/cclient/gordian_test.go @@ -2,20 +2,45 @@ package cclient_test import ( "context" + "fmt" "testing" "time" "github.com/cosmos/relayer/v2/cclient" + "github.com/stretchr/testify/require" ) +// cat example-tx-signed.json +const tx = `{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","to_address":"cosmos10r39fueph9fq7a6lgswu4zdsg8t3gxlqvvvyvn","amount":[{"denom":"stake","amount":"1"}]}],"memo":"","timeout_height":"0","unordered":false,"timeout_timestamp":"0001-01-01T00:00:00Z","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArpmqEz3g5rxcqE+f8n15wCMuLyhWF+PO6+zA57aPB/d"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"1"}],"fee":{"amount":[],"gas_limit":"200000","payer":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","granter":""},"tip":null},"signatures":["CeyHZH8itZikoY8mWtfCzM46qZfOLkncHRe8CxludOUpgvxklTcy4+EetVN++OzBgxxXUMG/B5DIuJAFQ4G6cg=="]}` + +// const tx = `{"tx":"eyJib2R5Ijp7Im1lc3NhZ2VzIjpbeyJAdHlwZSI6Ii9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQiLCJmcm9tX2FkZHJlc3MiOiJjb3Ntb3MxcjV2NXNyZGE3eGZ0aDNobjJzMjZ0eHZyY3JudGxkanVtdDhtaGwiLCJ0b19hZGRyZXNzIjoiY29zbW9zMTByMzlmdWVwaDlmcTdhNmxnc3d1NHpkc2c4dDNneGxxdnZ2eXZuIiwiYW1vdW50IjpbeyJkZW5vbSI6InN0YWtlIiwiYW1vdW50IjoiMSJ9XX1dLCJtZW1vIjoiIiwidGltZW91dF9oZWlnaHQiOiIwIiwidW5vcmRlcmVkIjpmYWxzZSwidGltZW91dF90aW1lc3RhbXAiOiIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsImV4dGVuc2lvbl9vcHRpb25zIjpbXSwibm9uX2NyaXRpY2FsX2V4dGVuc2lvbl9vcHRpb25zIjpbXX0sImF1dGhfaW5mbyI6eyJzaWduZXJfaW5mb3MiOlt7InB1YmxpY19rZXkiOnsiQHR5cGUiOiIvY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5Iiwia2V5IjoiQXJwbXFFejNnNXJ4Y3FFK2Y4bjE1d0NNdUx5aFdGK1BPNit6QTU3YVBCL2QifSwibW9kZV9pbmZvIjp7InNpbmdsZSI6eyJtb2RlIjoiU0lHTl9NT0RFX0RJUkVDVCJ9fSwic2VxdWVuY2UiOiIxIn1dLCJmZWUiOnsiYW1vdW50IjpbXSwiZ2FzX2xpbWl0IjoiMjAwMDAwIiwicGF5ZXIiOiJjb3Ntb3MxcjV2NXNyZGE3eGZ0aDNobjJzMjZ0eHZyY3JudGxkanVtdDhtaGwiLCJncmFudGVyIjoiIn0sInRpcCI6bnVsbH0sInNpZ25hdHVyZXMiOlsiQ2V5SFpIOGl0Wmlrb1k4bVd0ZkN6TTQ2cVpmT0xrbmNIUmU4Q3hsdWRPVXBndnhrbFRjeTQrRWV0Vk4rK096Qmd4eFhVTUcvQjVESXVKQUZRNEc2Y2c9PSJdfQo="}` + func TestGordian(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() gc := cclient.NewGordianConsensus("http://127.0.0.1:26657") + + s, err := gc.GetStatus(ctx) + require.NoError(t, err) + t.Log(s) + bt, err := gc.GetBlockTime(ctx, 2) - if err != nil { - t.Error(err) - } + require.NoError(t, err) t.Log(bt) + + resp, err := gc.DoBroadcastTxSync(ctx, []byte(tx)) + fmt.Println("resp", resp) + require.NoError(t, err) + t.Log(resp) + + tx, err := gc.GetTx(ctx, []byte("D8FF0A405957A3D090A485CA3C997A25E2964F2E7840DDBCBFE805EC97192651"), false) + require.NoError(t, err, "tx hash not found, make sure to submit one.") + t.Log(tx) + + bh := int64(s.LatestBlockHeight) + vals, err := gc.GetValidators(ctx, &bh, nil, nil) + require.NoError(t, err) + t.Log("vals", vals) + } diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index 06081995f..2592814cb 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -397,10 +397,10 @@ func (cc *CosmosProvider) broadcastTx( return err } rlyResp := &provider.RelayerTxResponse{ - TxHash: res.Hash.String(), + TxHash: res.TxHash, Codespace: res.Codespace, Code: res.Code, - Data: res.Data.String(), + Data: string(res.Data), } if isFailed { err = cc.sdkError(res.Codespace, res.Code) @@ -421,7 +421,7 @@ func (cc *CosmosProvider) broadcastTx( // 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, []byte(res.TxHash), msgs, asyncTimeout, asyncCallbacks) return nil } From d8db9dbfe936499f3db8c4f467c838a36c69d526 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Thu, 5 Sep 2024 15:37:11 -0500 Subject: [PATCH 10/13] use TxResultResponse for Async --- cclient/consensus.go | 2 +- cclient/consensus_cmbft.go | 6 +++--- cclient/consensus_gordian.go | 8 ++++---- cclient/gordian_test.go | 2 -- relayer/chains/cosmos/tx.go | 14 +++++++++++--- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/cclient/consensus.go b/cclient/consensus.go index 37a9d1701..631178ade 100644 --- a/cclient/consensus.go +++ b/cclient/consensus.go @@ -31,7 +31,7 @@ type ConsensusClient interface { orderBy string, ) (*ResultTxSearch, error) DoBroadcastTxSync(ctx context.Context, tx []byte) (*TxResultResponse, error) // TODO: is tx []byte fine or does it need to be tx tmtypes.Tx? - DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) + DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*TxResultResponse, error) GetTx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) GetBlockSearch( ctx context.Context, diff --git a/cclient/consensus_cmbft.go b/cclient/consensus_cmbft.go index ca28020df..5ba50492f 100644 --- a/cclient/consensus_cmbft.go +++ b/cclient/consensus_cmbft.go @@ -102,17 +102,17 @@ func (r CometRPCClient) GetValidators(ctx context.Context, height *int64, page * } // DoBroadcastTxAsync implements ConsensusClient. -func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*ResultBroadcastTx, error) { +func (r CometRPCClient) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*TxResultResponse, error) { b, err := r.BroadcastTxAsync(ctx, tx) if err != nil { return nil, fmt.Errorf("failed to broadcast tx async: %w", err) } - return &ResultBroadcastTx{ + return &TxResultResponse{ Code: b.Code, Data: b.Data, Log: b.Log, Codespace: b.Codespace, - Hash: b.Hash, + TxHash: string(b.Hash), }, nil } diff --git a/cclient/consensus_gordian.go b/cclient/consensus_gordian.go index e1876bc43..10dd0b420 100644 --- a/cclient/consensus_gordian.go +++ b/cclient/consensus_gordian.go @@ -15,7 +15,6 @@ import ( cmtbytes "github.com/cometbft/cometbft/libs/bytes" "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" - "github.com/cometbft/cometbft/types" tmtypes "github.com/cometbft/cometbft/types" ) @@ -77,8 +76,10 @@ type EventAttribute struct { // ----- // DoBroadcastTxAsync implements ConsensusClient. -func (g *GordianConsensus) DoBroadcastTxAsync(ctx context.Context, tx types.Tx) (*ResultBroadcastTx, error) { - panic("unimplemented") +func (g *GordianConsensus) DoBroadcastTxAsync(ctx context.Context, tx tmtypes.Tx) (*TxResultResponse, error) { + // TODO: fix me to be async + // panic("unimplemented") + return g.DoBroadcastTxSync(ctx, tx) } // DoBroadcastTxSync implements ConsensusClient. @@ -103,7 +104,6 @@ func (g *GordianConsensus) DoBroadcastTxSync(ctx context.Context, tx []byte) (*T } return &resp, nil - } // GetABCIQuery implements ConsensusClient. diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go index 3c80053d6..08d1c030c 100644 --- a/cclient/gordian_test.go +++ b/cclient/gordian_test.go @@ -13,8 +13,6 @@ import ( // cat example-tx-signed.json const tx = `{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","to_address":"cosmos10r39fueph9fq7a6lgswu4zdsg8t3gxlqvvvyvn","amount":[{"denom":"stake","amount":"1"}]}],"memo":"","timeout_height":"0","unordered":false,"timeout_timestamp":"0001-01-01T00:00:00Z","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArpmqEz3g5rxcqE+f8n15wCMuLyhWF+PO6+zA57aPB/d"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"1"}],"fee":{"amount":[],"gas_limit":"200000","payer":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","granter":""},"tip":null},"signatures":["CeyHZH8itZikoY8mWtfCzM46qZfOLkncHRe8CxludOUpgvxklTcy4+EetVN++OzBgxxXUMG/B5DIuJAFQ4G6cg=="]}` -// const tx = `{"tx":"eyJib2R5Ijp7Im1lc3NhZ2VzIjpbeyJAdHlwZSI6Ii9jb3Ntb3MuYmFuay52MWJldGExLk1zZ1NlbmQiLCJmcm9tX2FkZHJlc3MiOiJjb3Ntb3MxcjV2NXNyZGE3eGZ0aDNobjJzMjZ0eHZyY3JudGxkanVtdDhtaGwiLCJ0b19hZGRyZXNzIjoiY29zbW9zMTByMzlmdWVwaDlmcTdhNmxnc3d1NHpkc2c4dDNneGxxdnZ2eXZuIiwiYW1vdW50IjpbeyJkZW5vbSI6InN0YWtlIiwiYW1vdW50IjoiMSJ9XX1dLCJtZW1vIjoiIiwidGltZW91dF9oZWlnaHQiOiIwIiwidW5vcmRlcmVkIjpmYWxzZSwidGltZW91dF90aW1lc3RhbXAiOiIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsImV4dGVuc2lvbl9vcHRpb25zIjpbXSwibm9uX2NyaXRpY2FsX2V4dGVuc2lvbl9vcHRpb25zIjpbXX0sImF1dGhfaW5mbyI6eyJzaWduZXJfaW5mb3MiOlt7InB1YmxpY19rZXkiOnsiQHR5cGUiOiIvY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5Iiwia2V5IjoiQXJwbXFFejNnNXJ4Y3FFK2Y4bjE1d0NNdUx5aFdGK1BPNit6QTU3YVBCL2QifSwibW9kZV9pbmZvIjp7InNpbmdsZSI6eyJtb2RlIjoiU0lHTl9NT0RFX0RJUkVDVCJ9fSwic2VxdWVuY2UiOiIxIn1dLCJmZWUiOnsiYW1vdW50IjpbXSwiZ2FzX2xpbWl0IjoiMjAwMDAwIiwicGF5ZXIiOiJjb3Ntb3MxcjV2NXNyZGE3eGZ0aDNobjJzMjZ0eHZyY3JudGxkanVtdDhtaGwiLCJncmFudGVyIjoiIn0sInRpcCI6bnVsbH0sInNpZ25hdHVyZXMiOlsiQ2V5SFpIOGl0Wmlrb1k4bVd0ZkN6TTQ2cVpmT0xrbmNIUmU4Q3hsdWRPVXBndnhrbFRjeTQrRWV0Vk4rK096Qmd4eFhVTUcvQjVESXVKQUZRNEc2Y2c9PSJdfQo="}` - func TestGordian(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index 2592814cb..a8aaf833b 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -346,20 +346,28 @@ func (cc *CosmosProvider) SendMsgsWith(ctx context.Context, msgs []sdk.Msg, memo res, err := cc.ConsensusClient.DoBroadcastTxAsync(ctx, txBytes) if res != nil { - fmt.Printf("TX hash: %s\n", res.Hash) + fmt.Printf("TX hash: %s\n", res.TxHash) } if err != nil { return nil, err } + resp := &cclient.ResultBroadcastTx{ + Code: res.Code, + Data: res.Data, + Log: res.Log, + Codespace: res.Codespace, + Hash: bytes.HexBytes([]byte(res.TxHash)), + } + // 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 { - return res, fmt.Errorf("transaction failed with code: %d", res.Code) + return resp, fmt.Errorf("transaction failed with code: %d", res.Code) } - return res, nil + return resp, nil } // sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil. From cc84847ff826820f719634c4faaf9e7d2c4b8d06 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Fri, 6 Sep 2024 17:01:02 -0500 Subject: [PATCH 11/13] `SimulateTransaction` to reduce ABCI requirement for GasInfo --- cclient/consensus.go | 51 +++++++++++++++++++++++ cclient/consensus_cmbft.go | 46 +++++++++++++++++++++ cclient/consensus_gordian.go | 79 +++++++++++++++++------------------- cclient/gordian_test.go | 5 +++ relayer/chains/cosmos/tx.go | 29 ++++--------- 5 files changed, 147 insertions(+), 63 deletions(-) diff --git a/cclient/consensus.go b/cclient/consensus.go index 631178ade..66ca3f63c 100644 --- a/cclient/consensus.go +++ b/cclient/consensus.go @@ -10,6 +10,7 @@ import ( rpcclient "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" + types "github.com/cosmos/cosmos-sdk/types" ) // TODO(reece): get off cometbft types into internal relayer. @@ -46,6 +47,13 @@ type ConsensusClient interface { data bytes.HexBytes, opts rpcclient.ABCIQueryOptions, ) (*coretypes.ResultABCIQuery, error) + + SimulateTransaction(ctx context.Context, tx []byte, cfg *SimTxConfig) (types.GasInfo, error) +} + +type SimTxConfig struct { + // CometBFT only function (QueryABCI). + QueryABCIFunc func(ctx context.Context, req abci.RequestQuery) (abci.ResponseQuery, error) } type Status struct { @@ -91,3 +99,46 @@ type ResultBroadcastTx struct { Codespace string `json:"codespace"` Hash bytes.HexBytes `json:"hash"` } + +type TxResultResponse struct { + Events []*Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` + // bytes resp = 2; // []transaction.Msg + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + Code uint32 `protobuf:"varint,4,opt,name=code,proto3" json:"code,omitempty"` + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + Log string `protobuf:"bytes,6,opt,name=log,proto3" json:"log,omitempty"` + Info string `protobuf:"bytes,7,opt,name=info,proto3" json:"info,omitempty"` + GasWanted uint64 `protobuf:"varint,8,opt,name=gas_wanted,proto3" json:"gas_wanted,omitempty"` + GasUsed uint64 `protobuf:"varint,9,opt,name=gas_used,proto3" json:"gas_used,omitempty"` + Codespace string `protobuf:"bytes,10,opt,name=codespace,proto3" json:"codespace,omitempty"` + TxHash string `protobuf:"bytes,11,opt,name=tx_hash,proto3" json:"tx_hash,omitempty"` +} + +type Event struct { + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Attributes []*EventAttribute `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"` +} + +func convertConsensusEvents(e []*Event) []abci.Event { + events := make([]abci.Event, len(e)) + for _, ev := range e { + attributes := make([]abci.EventAttribute, len(ev.Attributes)) + for idx, attr := range ev.Attributes { + attributes[idx] = abci.EventAttribute{ + Key: attr.Key, + Value: attr.Value, + } + } + + events = append(events, abci.Event{ + Type: ev.Type, + Attributes: attributes, + }) + } + return events +} + +type EventAttribute struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} diff --git a/cclient/consensus_cmbft.go b/cclient/consensus_cmbft.go index 5ba50492f..2537c0425 100644 --- a/cclient/consensus_cmbft.go +++ b/cclient/consensus_cmbft.go @@ -5,14 +5,26 @@ import ( "fmt" "time" + "github.com/avast/retry-go/v4" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/bytes" 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" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" ) var _ ConsensusClient = (*CometRPCClient)(nil) +var ( + // originally from relayer/chains/cosmos/tx.go + rtyAttNum = uint(5) + rtyAtt = retry.Attempts(rtyAttNum) + rtyDel = retry.Delay(time.Millisecond * 400) + rtyErr = retry.LastErrorOnly(true) +) + // GetBlock implements ConsensusClient. func (r CometRPCClient) GetBlockTime(ctx context.Context, height uint64) (time.Time, error) { h := int64(height) @@ -131,6 +143,40 @@ func (r CometRPCClient) DoBroadcastTxSync(ctx context.Context, tx []byte) (*TxRe }, nil } +// SimulateTransaction implements ConsensusClient. +func (r CometRPCClient) SimulateTransaction(ctx context.Context, tx []byte, cfg *SimTxConfig) (sdk.GasInfo, error) { + simQuery := abci.RequestQuery{ + Path: "/cosmos.tx.v1beta1.Service/Simulate", + Data: tx, + } + + if cfg == nil { + return sdk.GasInfo{}, fmt.Errorf("BUG: SimulateTransaction cfg is nil, cfg.QueryABCIFunc is required for CometRPCClient") + } + + var res abci.ResponseQuery + if err := retry.Do(func() error { + var err error + res, err = cfg.QueryABCIFunc(ctx, simQuery) + if err != nil { + return err + } + return nil + }, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil { + return sdk.GasInfo{}, err + } + + var simRes txtypes.SimulateResponse + if err := simRes.Unmarshal(res.Value); err != nil { + return sdk.GasInfo{}, err + } + + return sdk.GasInfo{ + GasWanted: simRes.GasInfo.GasWanted, + GasUsed: simRes.GasInfo.GasUsed, + }, nil +} + // GetABCIQueryWithOptions implements ConsensusClient. func (r CometRPCClient) GetABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { q, err := r.ABCIQueryWithOptions(ctx, path, data, opts) diff --git a/cclient/consensus_gordian.go b/cclient/consensus_gordian.go index 10dd0b420..416a08bd3 100644 --- a/cclient/consensus_gordian.go +++ b/cclient/consensus_gordian.go @@ -16,6 +16,7 @@ import ( "github.com/cometbft/cometbft/rpc/client" coretypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/types" ) var _ ConsensusClient = (*GordianConsensus)(nil) @@ -31,48 +32,6 @@ func NewGordianConsensus(addr string) *GordianConsensus { } } -type TxResultResponse struct { - Events []*Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` - // bytes resp = 2; // []transaction.Msg - Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` - Code uint32 `protobuf:"varint,4,opt,name=code,proto3" json:"code,omitempty"` - Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` - Log string `protobuf:"bytes,6,opt,name=log,proto3" json:"log,omitempty"` - Info string `protobuf:"bytes,7,opt,name=info,proto3" json:"info,omitempty"` - GasWanted uint64 `protobuf:"varint,8,opt,name=gas_wanted,proto3" json:"gas_wanted,omitempty"` - GasUsed uint64 `protobuf:"varint,9,opt,name=gas_used,proto3" json:"gas_used,omitempty"` - Codespace string `protobuf:"bytes,10,opt,name=codespace,proto3" json:"codespace,omitempty"` - TxHash string `protobuf:"bytes,11,opt,name=tx_hash,proto3" json:"tx_hash,omitempty"` -} -type Event struct { - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - Attributes []*EventAttribute `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"` -} - -func convertConsensusEvents(e []*Event) []abci.Event { - events := make([]abci.Event, len(e)) - for _, ev := range e { - attributes := make([]abci.EventAttribute, len(ev.Attributes)) - for idx, attr := range ev.Attributes { - attributes[idx] = abci.EventAttribute{ - Key: attr.Key, - Value: attr.Value, - } - } - - events = append(events, abci.Event{ - Type: ev.Type, - Attributes: attributes, - }) - } - return events -} - -type EventAttribute struct { - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` -} - // ----- // DoBroadcastTxAsync implements ConsensusClient. @@ -106,8 +65,44 @@ func (g *GordianConsensus) DoBroadcastTxSync(ctx context.Context, tx []byte) (*T return &resp, nil } +// SimulateTransaction implements ConsensusClient. +func (g *GordianConsensus) SimulateTransaction(ctx context.Context, tx []byte, cfg *SimTxConfig) (types.GasInfo, error) { + var body io.Reader + if tx != nil { + body = bytes.NewReader(tx) + } else { + return types.GasInfo{}, fmt.Errorf("SimulateTransaction tx is nil") + } + + res, err := http.Post(fmt.Sprintf("%s/debug/simulate_tx", g.addr), "application/json", body) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + var resp TxResultResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + return types.GasInfo{}, err + } + + return types.GasInfo{ + GasWanted: resp.GasWanted, + GasUsed: resp.GasUsed, + }, nil +} + // GetABCIQuery implements ConsensusClient. func (g *GordianConsensus) GetABCIQuery(ctx context.Context, queryPath string, data cmtbytes.HexBytes) (*ABCIQueryResponse, error) { + // res, err := cc.QueryABCI(ctx, abci.RequestQuery{ + // Path: "store/upgrade/key", + // Height: int64(height - 1), + // Data: key, + // Prove: true, + // }) + // if err != nil { + // return nil, clienttypes.Height{}, err + // } panic("unimplemented") } diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go index 08d1c030c..3230405c3 100644 --- a/cclient/gordian_test.go +++ b/cclient/gordian_test.go @@ -27,6 +27,11 @@ func TestGordian(t *testing.T) { require.NoError(t, err) t.Log(bt) + gasInfo, err := gc.SimulateTransaction(ctx, []byte(tx), nil) + require.NoError(t, err) + require.GreaterOrEqual(t, gasInfo.GasUsed, uint64(1)) + t.Log(gasInfo) + resp, err := gc.DoBroadcastTxSync(ctx, []byte(tx)) fmt.Println("resp", resp) require.NoError(t, err) diff --git a/relayer/chains/cosmos/tx.go b/relayer/chains/cosmos/tx.go index a8aaf833b..87d8ae4a3 100644 --- a/relayer/chains/cosmos/tx.go +++ b/relayer/chains/cosmos/tx.go @@ -1792,30 +1792,17 @@ func (cc *CosmosProvider) CalculateGas(ctx context.Context, txf tx.Factory, sign 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 { + gasInfo, err := cc.ConsensusClient.SimulateTransaction(ctx, txBytes, &cclient.SimTxConfig{ + QueryABCIFunc: cc.QueryABCI, + }) + if err != nil { return txtypes.SimulateResponse{}, 0, err } - gas, err := cc.AdjustEstimatedGas(simRes.GasInfo.GasUsed) - return simRes, gas, err + gas, err := cc.AdjustEstimatedGas(gasInfo.GasUsed) + return txtypes.SimulateResponse{ + GasInfo: &gasInfo, + }, gas, err } // TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain. From f2ae8db63720c2347d4cfcbb28e4d9dbe41f5310 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Fri, 6 Sep 2024 17:07:33 -0500 Subject: [PATCH 12/13] fix: only run gordian test locally --- cclient/gordian_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go index 3230405c3..fa77ec9ac 100644 --- a/cclient/gordian_test.go +++ b/cclient/gordian_test.go @@ -3,6 +3,7 @@ package cclient_test import ( "context" "fmt" + "os" "testing" "time" @@ -13,7 +14,13 @@ import ( // cat example-tx-signed.json const tx = `{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","to_address":"cosmos10r39fueph9fq7a6lgswu4zdsg8t3gxlqvvvyvn","amount":[{"denom":"stake","amount":"1"}]}],"memo":"","timeout_height":"0","unordered":false,"timeout_timestamp":"0001-01-01T00:00:00Z","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArpmqEz3g5rxcqE+f8n15wCMuLyhWF+PO6+zA57aPB/d"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"1"}],"fee":{"amount":[],"gas_limit":"200000","payer":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","granter":""},"tip":null},"signatures":["CeyHZH8itZikoY8mWtfCzM46qZfOLkncHRe8CxludOUpgvxklTcy4+EetVN++OzBgxxXUMG/B5DIuJAFQ4G6cg=="]}` +// go test -timeout 3000s -run ^TestGordian$ github.com/cosmos/relayer/v2/cclient -v func TestGordian(t *testing.T) { + // TODO: this test is only local for now. Will add CI in the future + if os.Getenv("IS_LOCAL_TESTING_GORDIAN") == "" { + t.Skip("skipping test; set IS_LOCAL_TESTING_GORDIAN to run this test") + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() From c99e78d35b83e57081c0d15fb511118a7d7c9203 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Fri, 6 Sep 2024 17:53:07 -0500 Subject: [PATCH 13/13] `GetCommit` with just Time & AppHash returns --- cclient/consensus.go | 7 +++++- cclient/consensus_cmbft.go | 7 ++++-- cclient/consensus_gordian.go | 44 +++++++++++++++++++++++++++++++++--- cclient/gordian_test.go | 6 ++++- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/cclient/consensus.go b/cclient/consensus.go index 66ca3f63c..b8b0f082d 100644 --- a/cclient/consensus.go +++ b/cclient/consensus.go @@ -40,7 +40,7 @@ type ConsensusClient interface { page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) - GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) + GetCommit(ctx context.Context, height uint64) (*ResultCommit, error) GetABCIQueryWithOptions( ctx context.Context, path string, @@ -51,6 +51,11 @@ type ConsensusClient interface { SimulateTransaction(ctx context.Context, tx []byte, cfg *SimTxConfig) (types.GasInfo, error) } +type ResultCommit struct { + Time time.Time `json:"time"` + AppHash []byte `json:"app_hash"` +} + type SimTxConfig struct { // CometBFT only function (QueryABCI). QueryABCIFunc func(ctx context.Context, req abci.RequestQuery) (abci.ResponseQuery, error) diff --git a/cclient/consensus_cmbft.go b/cclient/consensus_cmbft.go index 2537c0425..e353defaa 100644 --- a/cclient/consensus_cmbft.go +++ b/cclient/consensus_cmbft.go @@ -92,13 +92,16 @@ func (r CometRPCClient) GetBlockSearch(ctx context.Context, query string, page * } // GetCommit implements ConsensusClient. -func (r CometRPCClient) GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) { +func (r CometRPCClient) GetCommit(ctx context.Context, height uint64) (*ResultCommit, error) { h := int64(height) c, err := r.Commit(ctx, &h) if err != nil { return nil, fmt.Errorf("failed to get commit: %w", err) } - return c, nil + return &ResultCommit{ + AppHash: c.AppHash, + Time: c.Time, + }, nil } // GetValidators implements ConsensusClient. diff --git a/cclient/consensus_gordian.go b/cclient/consensus_gordian.go index 416a08bd3..c8874db76 100644 --- a/cclient/consensus_gordian.go +++ b/cclient/consensus_gordian.go @@ -144,8 +144,45 @@ func (g *GordianConsensus) GetBlockTime(ctx context.Context, height uint64) (tim } // GetCommit implements ConsensusClient. -func (g *GordianConsensus) GetCommit(ctx context.Context, height uint64) (*coretypes.ResultCommit, error) { - panic("unimplemented") +func (g *GordianConsensus) GetCommit(ctx context.Context, height uint64) (*ResultCommit, error) { + // looks like we just need the apphash. returning just this for gordian to see how it goes. + // get latest header from the network + + res, err := http.Get(fmt.Sprintf("%s/commit", g.addr)) + if err != nil { + fmt.Printf("error making http request: %s\n", err) + os.Exit(1) + } + + // tmconsensus.CommittedBlock + type GetCommitResponse struct { + BlockHash []byte `protobuf:"bytes,1,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + BlockHashPrevious []byte `protobuf:"bytes,2,opt,name=block_hash_previous,json=blockHashPrevious,proto3" json:"block_hash_previous,omitempty"` + Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + // PreviousCommitProof *CommitProof `protobuf:"bytes,4,opt,name=previous_commit_proof,json=previousCommitProof,proto3" json:"previous_commit_proof,omitempty"` + // ValidatorSet *ValidatorSet `protobuf:"bytes,5,opt,name=validator_set,json=validatorSet,proto3" json:"validator_set,omitempty"` + // ValidatorSetNext *ValidatorSet `protobuf:"bytes,6,opt,name=validator_set_next,json=validatorSetNext,proto3" json:"validator_set_next,omitempty"` + DataId []byte `protobuf:"bytes,7,opt,name=data_id,json=dataId,proto3" json:"data_id,omitempty"` + AppStatePrevHash []byte `protobuf:"bytes,8,opt,name=app_state_prev_hash,json=appStatePrevHash,proto3" json:"app_state_prev_hash,omitempty"` // annotations + } + + var resp GetCommitResponse + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + fmt.Printf("error decoding response: %s\n", err) + os.Exit(1) + } + + // Get this from the header annotation directly? + bt, err := g.GetBlockTime(ctx, resp.Height) + if err != nil { + return nil, fmt.Errorf("failed to get block time: %w", err) + } + + // TODO: do we need the full coretypes.NewResultCommit ? Does not seem like it + return &ResultCommit{ + AppHash: resp.AppStatePrevHash, + Time: bt, + }, nil } // GetStatus implements ConsensusClient. @@ -206,7 +243,8 @@ func (g *GordianConsensus) GetTx(ctx context.Context, hash []byte, prove bool) ( // GetTxSearch implements ConsensusClient. func (g *GordianConsensus) GetTxSearch(ctx context.Context, query string, prove bool, page *int, perPage *int, orderBy string) (*ResultTxSearch, error) { - panic("unimplemented") + // TODO: + return nil, nil } // TODO: GetValidators needs pubkey -> address conversions diff --git a/cclient/gordian_test.go b/cclient/gordian_test.go index fa77ec9ac..5f4db0dbb 100644 --- a/cclient/gordian_test.go +++ b/cclient/gordian_test.go @@ -14,7 +14,7 @@ import ( // cat example-tx-signed.json const tx = `{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","to_address":"cosmos10r39fueph9fq7a6lgswu4zdsg8t3gxlqvvvyvn","amount":[{"denom":"stake","amount":"1"}]}],"memo":"","timeout_height":"0","unordered":false,"timeout_timestamp":"0001-01-01T00:00:00Z","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"ArpmqEz3g5rxcqE+f8n15wCMuLyhWF+PO6+zA57aPB/d"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"1"}],"fee":{"amount":[],"gas_limit":"200000","payer":"cosmos1r5v5srda7xfth3hn2s26txvrcrntldjumt8mhl","granter":""},"tip":null},"signatures":["CeyHZH8itZikoY8mWtfCzM46qZfOLkncHRe8CxludOUpgvxklTcy4+EetVN++OzBgxxXUMG/B5DIuJAFQ4G6cg=="]}` -// go test -timeout 3000s -run ^TestGordian$ github.com/cosmos/relayer/v2/cclient -v +// go test -timeout 3000s -run ^TestGordian$ github.com/cosmos/relayer/v2/cclient -v -count 1 func TestGordian(t *testing.T) { // TODO: this test is only local for now. Will add CI in the future if os.Getenv("IS_LOCAL_TESTING_GORDIAN") == "" { @@ -53,4 +53,8 @@ func TestGordian(t *testing.T) { require.NoError(t, err) t.Log("vals", vals) + c, err := gc.GetCommit(ctx, uint64(s.LatestBlockHeight)) + require.NoError(t, err) + t.Logf("commit: %+v", c) + }