-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: native core SDK command support #892
Changes from all commits
1526481
421b08c
5342317
069779d
c57a3c5
46c1c39
f20e1e8
c1d1d0d
32e08ba
e6ea937
2fb0a4f
720d1cd
d36acc8
7d0bfe9
809d695
c2a4a6c
4317009
59bf214
d5bee5e
f1c330e
264939e
fe405d2
03e390c
c6cdd0c
8648f3c
059a87e
b21efd0
4341133
609856d
8d920bd
60c69d0
2dd180b
8c603c0
8c6cb9a
79d8959
7e076dc
2b43cb4
e127b6f
eecbc6d
7cef1a9
7953959
c9a62ef
7c9f8fd
2544c5f
3af2926
99c1ff2
42d7856
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ import ( | |
"context" | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"math" | ||
|
@@ -22,10 +21,8 @@ import ( | |
"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||
"github.com/cosmos/cosmos-sdk/types" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" | ||
paramsutils "github.com/cosmos/cosmos-sdk/x/params/client/utils" | ||
cosmosproto "github.com/cosmos/gogoproto/proto" | ||
chanTypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" | ||
dockertypes "github.com/docker/docker/api/types" | ||
volumetypes "github.com/docker/docker/api/types/volume" | ||
|
@@ -38,8 +35,6 @@ import ( | |
"github.com/strangelove-ventures/interchaintest/v8/testutil" | ||
"go.uber.org/zap" | ||
"golang.org/x/sync/errgroup" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials/insecure" | ||
) | ||
|
||
// CosmosChain is a local docker testnet for a Cosmos SDK chain. | ||
|
@@ -55,6 +50,7 @@ type CosmosChain struct { | |
// Additional processes that need to be run on a per-chain basis. | ||
Sidecars SidecarProcesses | ||
|
||
cdc *codec.ProtoCodec | ||
log *zap.Logger | ||
keyring keyring.Keyring | ||
findTxMu sync.Mutex | ||
|
@@ -104,10 +100,16 @@ func NewCosmosChain(testName string, chainConfig ibc.ChainConfig, numValidators | |
numValidators: numValidators, | ||
numFullNodes: numFullNodes, | ||
log: log, | ||
cdc: cdc, | ||
keyring: kr, | ||
} | ||
} | ||
|
||
// GetCodec returns the codec for the chain. | ||
func (c *CosmosChain) GetCodec() *codec.ProtoCodec { | ||
return c.cdc | ||
} | ||
|
||
// Nodes returns all nodes, including validators and fullnodes. | ||
func (c *CosmosChain) Nodes() ChainNodes { | ||
return append(c.Validators, c.FullNodes...) | ||
|
@@ -184,14 +186,7 @@ func (c *CosmosChain) Initialize(ctx context.Context, testName string, cli *clie | |
} | ||
|
||
func (c *CosmosChain) getFullNode() *ChainNode { | ||
c.findTxMu.Lock() | ||
defer c.findTxMu.Unlock() | ||
if len(c.FullNodes) > 0 { | ||
// use first full node | ||
return c.FullNodes[0] | ||
} | ||
// use first validator | ||
return c.Validators[0] | ||
return c.GetNode() | ||
} | ||
Comment on lines
188
to
190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When a test adds or removes a full node, this then switches which node the user was original acting on. This results in a NPE and causes a lot of confusion (including for myself). This uses GetNode() (validator[0]) now so commands always happen on the same machine as a user expects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great catch!! |
||
|
||
func (c *CosmosChain) GetNode() *ChainNode { | ||
|
@@ -319,7 +314,7 @@ func (c *CosmosChain) BuildRelayerWallet(ctx context.Context, keyName string) (i | |
|
||
// Implements Chain interface | ||
func (c *CosmosChain) SendFunds(ctx context.Context, keyName string, amount ibc.WalletAmount) error { | ||
return c.getFullNode().SendFunds(ctx, keyName, amount) | ||
return c.getFullNode().BankSend(ctx, keyName, amount) | ||
} | ||
|
||
// Implements Chain interface | ||
|
@@ -381,26 +376,6 @@ func (c *CosmosChain) SendIBCTransfer( | |
return tx, nil | ||
} | ||
|
||
// GetGovernanceAddress performs a query to get the address of the chain's x/gov module | ||
func (c *CosmosChain) GetGovernanceAddress(ctx context.Context) (string, error) { | ||
return c.GetModuleAddress(ctx, govtypes.ModuleName) | ||
} | ||
|
||
// GetModuleAddress performs a query to get the address of the specified chain module | ||
func (c *CosmosChain) GetModuleAddress(ctx context.Context, moduleName string) (string, error) { | ||
return c.getFullNode().GetModuleAddress(ctx, moduleName) | ||
} | ||
|
||
// QueryProposal returns the state and details of a governance proposal. | ||
func (c *CosmosChain) QueryProposal(ctx context.Context, proposalID string) (*ProposalResponse, error) { | ||
return c.getFullNode().QueryProposal(ctx, proposalID) | ||
} | ||
|
||
// QueryProposal returns the state and details of an IBC-Go v8 / SDK v50 governance proposal. | ||
func (c *CosmosChain) QueryProposalV8(ctx context.Context, proposalID string) (*ProposalResponseV8, error) { | ||
return c.getFullNode().QueryProposalV8(ctx, proposalID) | ||
} | ||
|
||
// PushNewWasmClientProposal submits a new wasm client governance proposal to the chain | ||
func (c *CosmosChain) PushNewWasmClientProposal(ctx context.Context, keyName string, fileName string, prop TxProposalv1) (TxProposal, string, error) { | ||
tx := TxProposal{} | ||
|
@@ -449,38 +424,6 @@ func (c *CosmosChain) SubmitProposal(ctx context.Context, keyName string, prop T | |
return c.txProposal(txHash) | ||
} | ||
|
||
// Build a gov v1 proposal type. | ||
// | ||
// The proposer field should only be set for IBC-Go v8 / SDK v50 chains. | ||
func (c *CosmosChain) BuildProposal(messages []cosmosproto.Message, title, summary, metadata, depositStr, proposer string, expedited bool) (TxProposalv1, error) { | ||
var propType TxProposalv1 | ||
rawMsgs := make([]json.RawMessage, len(messages)) | ||
|
||
for i, msg := range messages { | ||
msg, err := c.Config().EncodingConfig.Codec.MarshalInterfaceJSON(msg) | ||
if err != nil { | ||
return propType, err | ||
} | ||
rawMsgs[i] = msg | ||
} | ||
|
||
propType = TxProposalv1{ | ||
Messages: rawMsgs, | ||
Metadata: metadata, | ||
Deposit: depositStr, | ||
Title: title, | ||
Summary: summary, | ||
} | ||
|
||
// SDK v50 only | ||
if proposer != "" { | ||
propType.Proposer = proposer | ||
propType.Expedited = expedited | ||
} | ||
|
||
return propType, nil | ||
} | ||
|
||
// TextProposal submits a text governance proposal to the chain. | ||
func (c *CosmosChain) TextProposal(ctx context.Context, keyName string, prop TextProposal) (tx TxProposal, _ error) { | ||
txHash, err := c.getFullNode().TextProposal(ctx, keyName, prop) | ||
|
@@ -571,47 +514,6 @@ func (c *CosmosChain) ExportState(ctx context.Context, height int64) (string, er | |
return c.getFullNode().ExportState(ctx, height) | ||
} | ||
|
||
// GetBalance fetches the current balance for a specific account address and denom. | ||
// Implements Chain interface | ||
func (c *CosmosChain) GetBalance(ctx context.Context, address string, denom string) (sdkmath.Int, error) { | ||
params := &bankTypes.QueryBalanceRequest{Address: address, Denom: denom} | ||
grpcAddress := c.getFullNode().hostGRPCPort | ||
conn, err := grpc.Dial(grpcAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
return sdkmath.Int{}, err | ||
} | ||
defer conn.Close() | ||
|
||
queryClient := bankTypes.NewQueryClient(conn) | ||
res, err := queryClient.Balance(ctx, params) | ||
|
||
if err != nil { | ||
return sdkmath.Int{}, err | ||
} | ||
|
||
return res.Balance.Amount, nil | ||
} | ||
|
||
// AllBalances fetches an account address's balance for all denoms it holds | ||
func (c *CosmosChain) AllBalances(ctx context.Context, address string) (types.Coins, error) { | ||
params := bankTypes.QueryAllBalancesRequest{Address: address} | ||
grpcAddress := c.getFullNode().hostGRPCPort | ||
conn, err := grpc.Dial(grpcAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer conn.Close() | ||
|
||
queryClient := bankTypes.NewQueryClient(conn) | ||
res, err := queryClient.AllBalances(ctx, ¶ms) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return res.GetBalances(), nil | ||
} | ||
|
||
func (c *CosmosChain) GetTransaction(txhash string) (*types.TxResponse, error) { | ||
fn := c.getFullNode() | ||
return fn.GetTransaction(fn.CliContext(), txhash) | ||
|
@@ -1264,12 +1166,17 @@ func (c *CosmosChain) StartAllValSidecars(ctx context.Context) error { | |
} | ||
|
||
func (c *CosmosChain) VoteOnProposalAllValidators(ctx context.Context, proposalID string, vote string) error { | ||
propID, err := strconv.ParseUint(proposalID, 10, 64) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse proposalID %s: %w", proposalID, err) | ||
} | ||
|
||
var eg errgroup.Group | ||
for _, n := range c.Nodes() { | ||
if n.Validator { | ||
n := n | ||
eg.Go(func() error { | ||
return n.VoteOnProposal(ctx, valKey, proposalID, vote) | ||
return n.VoteOnProposal(ctx, valKey, propID, vote) | ||
}) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package cosmos | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" | ||
|
||
cdctypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
) | ||
|
||
// AuthQueryAccount performs a query to get the account details of the specified address | ||
func (c *CosmosChain) AuthQueryAccount(ctx context.Context, addr string) (*cdctypes.Any, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).Account(ctx, &authtypes.QueryAccountRequest{ | ||
Address: addr, | ||
}) | ||
return res.Account, err | ||
} | ||
|
||
// AuthQueryParams performs a query to get the auth module parameters | ||
func (c *CosmosChain) AuthQueryParams(ctx context.Context) (*authtypes.Params, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).Params(ctx, &authtypes.QueryParamsRequest{}) | ||
return &res.Params, err | ||
} | ||
|
||
// AuthQueryModuleAccounts performs a query to get the account details of all the chain modules | ||
func (c *CosmosChain) AuthQueryModuleAccounts(ctx context.Context) ([]authtypes.ModuleAccount, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).ModuleAccounts(ctx, &authtypes.QueryModuleAccountsRequest{}) | ||
|
||
maccs := make([]authtypes.ModuleAccount, len(res.Accounts)) | ||
|
||
for i, acc := range res.Accounts { | ||
var macc authtypes.ModuleAccount | ||
err := c.GetCodec().Unmarshal(acc.Value, &macc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
maccs[i] = macc | ||
} | ||
|
||
return maccs, err | ||
} | ||
|
||
// AuthGetModuleAccount performs a query to get the account details of the specified chain module | ||
func (c *CosmosChain) AuthQueryModuleAccount(ctx context.Context, moduleName string) (authtypes.ModuleAccount, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).ModuleAccountByName(ctx, &authtypes.QueryModuleAccountByNameRequest{ | ||
Name: moduleName, | ||
}) | ||
if err != nil { | ||
return authtypes.ModuleAccount{}, err | ||
} | ||
|
||
var modAcc authtypes.ModuleAccount | ||
err = c.GetCodec().Unmarshal(res.Account.Value, &modAcc) | ||
|
||
return modAcc, err | ||
} | ||
|
||
// GetModuleAddress performs a query to get the address of the specified chain module | ||
func (c *CosmosChain) AuthQueryModuleAddress(ctx context.Context, moduleName string) (string, error) { | ||
queryRes, err := c.AuthQueryModuleAccount(ctx, moduleName) | ||
if err != nil { | ||
return "", err | ||
} | ||
return queryRes.BaseAccount.Address, nil | ||
} | ||
|
||
// Deprecated: use AuthQueryModuleAddress instead | ||
func (c *CosmosChain) GetModuleAddress(ctx context.Context, moduleName string) (string, error) { | ||
return c.AuthQueryModuleAddress(ctx, moduleName) | ||
} | ||
|
||
// GetGovernanceAddress performs a query to get the address of the chain's x/gov module | ||
// Deprecated: use AuthQueryModuleAddress(ctx, "gov") instead | ||
func (c *CosmosChain) GetGovernanceAddress(ctx context.Context) (string, error) { | ||
return c.GetModuleAddress(ctx, "gov") | ||
} | ||
|
||
func (c *CosmosChain) AuthQueryBech32Prefix(ctx context.Context) (string, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).Bech32Prefix(ctx, &authtypes.Bech32PrefixRequest{}) | ||
return res.Bech32Prefix, err | ||
} | ||
|
||
// AddressBytesToString converts a byte array address to a string | ||
func (c *CosmosChain) AuthAddressBytesToString(ctx context.Context, addrBz []byte) (string, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).AddressBytesToString(ctx, &authtypes.AddressBytesToStringRequest{ | ||
AddressBytes: addrBz, | ||
}) | ||
return res.AddressString, err | ||
} | ||
|
||
// AddressStringToBytes converts a string address to a byte array | ||
func (c *CosmosChain) AuthAddressStringToBytes(ctx context.Context, addr string) ([]byte, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).AddressStringToBytes(ctx, &authtypes.AddressStringToBytesRequest{ | ||
AddressString: addr, | ||
}) | ||
return res.AddressBytes, err | ||
} | ||
|
||
// AccountInfo queries the account information of the given address | ||
func (c *CosmosChain) AuthQueryAccountInfo(ctx context.Context, addr string) (*authtypes.BaseAccount, error) { | ||
res, err := authtypes.NewQueryClient(c.GetNode().GrpcConn).AccountInfo(ctx, &authtypes.QueryAccountInfoRequest{ | ||
Address: addr, | ||
}) | ||
return res.Info, err | ||
} | ||
|
||
func (c *CosmosChain) AuthPrintAccountInfo(chain *CosmosChain, res *cdctypes.Any) error { | ||
switch res.TypeUrl { | ||
case "/cosmos.auth.v1beta1.ModuleAccount": | ||
var modAcc authtypes.ModuleAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &modAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("ModuleAccount: %+v\n", modAcc) | ||
return nil | ||
|
||
case "/cosmos.vesting.v1beta1.VestingAccount": | ||
var vestingAcc vestingtypes.BaseVestingAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &vestingAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("BaseVestingAccount: %+v\n", vestingAcc) | ||
return nil | ||
|
||
case "/cosmos.vesting.v1beta1.PeriodicVestingAccount": | ||
var vestingAcc vestingtypes.PeriodicVestingAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &vestingAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("PeriodicVestingAccount: %+v\n", vestingAcc) | ||
return nil | ||
|
||
case "/cosmos.vesting.v1beta1.ContinuousVestingAccount": | ||
var vestingAcc vestingtypes.ContinuousVestingAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &vestingAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("ContinuousVestingAccount: %+v\n", vestingAcc) | ||
return nil | ||
|
||
case "/cosmos.vesting.v1beta1.DelayedVestingAccount": | ||
var vestingAcc vestingtypes.DelayedVestingAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &vestingAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("DelayedVestingAccount: %+v\n", vestingAcc) | ||
return nil | ||
|
||
case "/cosmos.vesting.v1beta1.PermanentLockedAccount": | ||
var vestingAcc vestingtypes.PermanentLockedAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &vestingAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("PermanentLockedAccount: %+v\n", vestingAcc) | ||
return nil | ||
|
||
default: | ||
var baseAcc authtypes.BaseAccount | ||
if err := chain.GetCodec().Unmarshal(res.Value, &baseAcc); err != nil { | ||
return err | ||
} | ||
fmt.Printf("BaseAccount: %+v\n", baseAcc) | ||
return nil | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Required for module_auth.go (converting the any types -> accounts)