x/community events and e2e test improvements (#1766)

* Initial e2e setup

* Fix inflation disable tests

* Add upgrade handler

* Add param tests for after upgrade

* Replace deprecated grpc creds

* Remove upgrade for e2e test

* Update upgrade handler to set x/community params

* Remove params check in upgrade

* Update tests for switchover time and params check

* wip inflation

* Add attribute to disable inflation event

* Add before/after switchover mint and dist checks

* Add missing attribute to disable inflation test check

* Check mint events are 0

* Check total supply doesn't change

* Check inflation and events before switchover

* Check staking reward payouts from x/community

* move events funcs to util

* Add keyring to chain, fetch keys from kvtool and test withdrawal

* Remove duplicate KavaHomePath

* Update subtest names to specify before/after switchover

Co-authored-by: Draco <draco@dracoli.com>

* Use blocktime for InflationStop event DisableTime

* Test 5 blocks for staking rewards payout

* Remove logging and unused lines

* Check val claimed balance with queried

* Enable and update consolidation tests

* Update test for modified EventTypeInflationStop time attr

* Test x/distribution community tax

* Fix test names

* Update e2e tests for better live network test support (#1749)

* Update e2e tests to support mirrornet

* Skip claim rewards on live network, require no errors for existing tests

* Update readme with upgrade height

* Update .env example with usdt contract address

* Restore .env file to original local e2e

* Log community params when set

* Make AttributeKeyInflationDisableTime more precise

* Add mainnet and testnet community params (#1753)

* Re-enable ibc tests

* Remove duplicate types.EventTypeInflationStop emit

* feat: set validator minimum commissions to at least 5% in upgrade handler (#1761)

* Update validator min commission in upgrade

* Add min commission upgrade test

* Update changelog

* Set validator MaxRate, call BeforeValidatorModified hook

* Check max commission and update time in tests

* Update e2e test for max rate

* Test val update time

* Use SdkBlock instead of Block

* Remove upgrade related handlers and tests

Preserve any module and test util changes

* Update e2e x/community params proposal test to work without upgrade handler

---------

Co-authored-by: Draco <draco@dracoli.com>
This commit is contained in:
drklee3 2023-10-31 16:37:40 -07:00 committed by GitHub
parent 84f84c4eec
commit 6998196461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 307 additions and 57 deletions

View File

@ -54,7 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (community) [#1729] Consolidate community funds from `x/distribution` and `x/kavadist` to `x/community` - (community) [#1729] Consolidate community funds from `x/distribution` and `x/kavadist` to `x/community`
- (community) [#1752] Set `x/distribution` CommunityTax to zero on inflation disable upgrade - (community) [#1752] Set `x/distribution` CommunityTax to zero on inflation disable upgrade
- (community) [#1755] Keep funds in `x/community` in `CommunityPoolLendWithdrawProposal` handler - (community) [#1755] Keep funds in `x/community` in `CommunityPoolLendWithdrawProposal` handler
- (staking) [#1761] Set validator minimum commission to 5% for all validators under 5%
## [v0.24.1](https://github.com/Kava-Labs/kava/releases/tag/v0.24.1) ## [v0.24.1](https://github.com/Kava-Labs/kava/releases/tag/v0.24.1)
@ -303,6 +303,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
large-scale simulations remotely using aws-batch large-scale simulations remotely using aws-batch
[#1755]: https://github.com/Kava-Labs/kava/pull/1755 [#1755]: https://github.com/Kava-Labs/kava/pull/1755
[#1761]: https://github.com/Kava-Labs/kava/pull/1761
[#1752]: https://github.com/Kava-Labs/kava/pull/1752 [#1752]: https://github.com/Kava-Labs/kava/pull/1752
[#1751]: https://github.com/Kava-Labs/kava/pull/1751 [#1751]: https://github.com/Kava-Labs/kava/pull/1751
[#1745]: https://github.com/Kava-Labs/kava/pull/1745 [#1745]: https://github.com/Kava-Labs/kava/pull/1745

View File

@ -20,4 +20,5 @@ E2E_INCLUDE_IBC_TESTS=false
# - the evmutil params must support conversion & deposits to mint in eip712 messages # - the evmutil params must support conversion & deposits to mint in eip712 messages
# #
# These requirements are verified on test startup in ./testutil/init_evm.go # These requirements are verified on test startup in ./testutil/init_evm.go
E2E_KAVA_ERC20_ADDRESS=0xeA7100edA2f805356291B0E55DaD448599a72C6d # This address is a USDT contract
E2E_KAVA_ERC20_ADDRESS=0x919c1c267bc06a7039e03fcc2ef738525769109c

View File

@ -72,15 +72,38 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
gasLimit := int64(2e5) gasLimit := int64(2e5)
fee := ukava(200) fee := ukava(200)
upgradeTime := time.Now().Add(24 * time.Hour).UTC() // Wait until switchover actually happens - When testing without the upgrade
// handler that sets a relative switchover time, the switchover time in
// genesis should be set in the past so it runs immediately.
suite.Require().Eventually(
func() bool {
params, err := suite.Kava.Community.Params(
context.Background(),
&communitytypes.QueryParamsRequest{},
)
suite.Require().NoError(err)
return params.Params.UpgradeTimeDisableInflation.Equal(time.Time{})
},
20*time.Second,
1*time.Second,
"switchover should happen",
)
// Add 1 to the staking rewards per second
newStakingRewardsPerSecond := communityParamsResInitial.Params.
StakingRewardsPerSecond.
Add(sdkmath.LegacyNewDec(1))
// 1. Proposal // 1. Proposal
// Only modify stakingRewardsPerSecond, as to not re-run the switchover and
// to not influence other tests
updateParamsMsg := communitytypes.NewMsgUpdateParams( updateParamsMsg := communitytypes.NewMsgUpdateParams(
authtypes.NewModuleAddress(govtypes.ModuleName), // authority authtypes.NewModuleAddress(govtypes.ModuleName), // authority
communitytypes.NewParams( communitytypes.NewParams(
upgradeTime, time.Time{}, // after switchover, is empty
sdkmath.LegacyNewDec(1111), // stakingRewardsPerSecond newStakingRewardsPerSecond, // only modify stakingRewardsPerSecond
sdkmath.LegacyNewDec(2222), // upgradeTimeSetstakingRewardsPerSecond communityParamsResInitial.Params.UpgradeTimeSetStakingRewardsPerSecond,
), ),
) )

View File

@ -198,8 +198,8 @@ func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
suite.NoError(err) suite.NoError(err)
suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code) suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second) _, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 12*time.Second)
suite.NoError(err) suite.Require().NoError(err)
// query for the deployed contract // query for the deployed contract
deployedContracts, err := suite.Kava.Evmutil.DeployedCosmosCoinContracts( deployedContracts, err := suite.Kava.Evmutil.DeployedCosmosCoinContracts(
@ -394,7 +394,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
Data: "bob transfers alice's funds, allowed because he's approved", Data: "bob transfers alice's funds, allowed because he's approved",
} }
res = bob.SignAndBroadcastEvmTx(transferJustRightTx) res = bob.SignAndBroadcastEvmTx(transferJustRightTx)
suite.NoError(res.Err) suite.Require().NoError(res.Err)
// alice should have amount deducted // alice should have amount deducted
erc20Balance := suite.Kava.GetErc20Balance(contractAddress.Address, alice.EvmAddress) erc20Balance := suite.Kava.GetErc20Balance(contractAddress.Address, alice.EvmAddress)

View File

@ -17,8 +17,10 @@ import (
) )
func (suite *IntegrationTestSuite) TestEthGasPriceReturnsMinFee() { func (suite *IntegrationTestSuite) TestEthGasPriceReturnsMinFee() {
suite.SkipIfKvtoolDisabled()
// read expected min fee from app.toml // read expected min fee from app.toml
minGasPrices, err := getMinFeeFromAppToml(suite.KavaHomePath()) minGasPrices, err := getMinFeeFromAppToml(util.KavaHomePath())
suite.NoError(err) suite.NoError(err)
// evm uses akava, get akava min fee // evm uses akava, get akava min fee
@ -32,12 +34,14 @@ func (suite *IntegrationTestSuite) TestEthGasPriceReturnsMinFee() {
} }
func (suite *IntegrationTestSuite) TestEvmRespectsMinFee() { func (suite *IntegrationTestSuite) TestEvmRespectsMinFee() {
suite.SkipIfKvtoolDisabled()
// setup sender & receiver // setup sender & receiver
sender := suite.Kava.NewFundedAccount("evm-min-fee-test-sender", sdk.NewCoins(ukava(1e3))) sender := suite.Kava.NewFundedAccount("evm-min-fee-test-sender", sdk.NewCoins(ukava(1e3)))
randoReceiver := util.SdkToEvmAddress(app.RandomAddress()) randoReceiver := util.SdkToEvmAddress(app.RandomAddress())
// get min gas price for evm (from app.toml) // get min gas price for evm (from app.toml)
minFees, err := getMinFeeFromAppToml(suite.KavaHomePath()) minFees, err := getMinFeeFromAppToml(util.KavaHomePath())
suite.NoError(err) suite.NoError(err)
minGasPrice := minFees.AmountOf("akava").TruncateInt() minGasPrice := minFees.AmountOf("akava").TruncateInt()

View File

@ -41,7 +41,7 @@ func TestIntegrationTestSuite(t *testing.T) {
// example test that queries kava via SDK and EVM // example test that queries kava via SDK and EVM
func (suite *IntegrationTestSuite) TestChainID() { func (suite *IntegrationTestSuite) TestChainID() {
expectedEvmNetworkId, err := emtypes.ParseChainID(suite.Kava.ChainId) expectedEvmNetworkId, err := emtypes.ParseChainID(suite.Kava.ChainID)
suite.NoError(err) suite.NoError(err)
// EVM query // EVM query
@ -52,7 +52,7 @@ func (suite *IntegrationTestSuite) TestChainID() {
// SDK query // SDK query
nodeInfo, err := suite.Kava.Tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{}) nodeInfo, err := suite.Kava.Tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
suite.NoError(err) suite.NoError(err)
suite.Equal(suite.Kava.ChainId, nodeInfo.DefaultNodeInfo.Network) suite.Equal(suite.Kava.ChainID, nodeInfo.DefaultNodeInfo.Network)
} }
// example test that funds a new account & queries its balance // example test that funds a new account & queries its balance
@ -99,7 +99,7 @@ func (suite *IntegrationTestSuite) TestTransferOverEVM() {
Data: "any ol' data to track this through the system", Data: "any ol' data to track this through the system",
} }
res := acc.SignAndBroadcastEvmTx(req) res := acc.SignAndBroadcastEvmTx(req)
suite.NoError(res.Err) suite.Require().NoError(res.Err)
suite.Equal(ethtypes.ReceiptStatusSuccessful, res.Receipt.Status) suite.Equal(ethtypes.ReceiptStatusSuccessful, res.Receipt.Status)
// evm txs refund unused gas. so to know the expected balance we need to know how much gas was used. // evm txs refund unused gas. so to know the expected balance we need to know how much gas was used.

@ -1 +1 @@
Subproject commit 6184dc56e9b8ee94a2fe9a1e0c165d6c1129fa42 Subproject commit e1085562d203fd81c5dd8576170b29715b2de9ef

View File

@ -27,12 +27,17 @@ The end-to-end tests support being run on a live network. The primary toggle for
* `E2E_KAVA_RPC_URL` * `E2E_KAVA_RPC_URL`
* `E2E_KAVA_GRPC_URL` * `E2E_KAVA_GRPC_URL`
* `E2E_KAVA_EVM_RPC_URL` * `E2E_KAVA_EVM_RPC_URL`
* `E2E_KAVA_UPGRADE_HEIGHT` - the height at which an existing upgrade was run
See an example environment configuration with full description of all supported configurations in [`.env.live-network-example`](./.env.live-network-example). This example expects a local kvtool network to be running: `kvtool testnet bootstrap`. See an example environment configuration with full description of all supported configurations in [`.env.live-network-example`](./.env.live-network-example). This example expects a local kvtool network to be running: `kvtool testnet bootstrap`.
When run against a live network, the suite will automatically return all the sdk funds sent to `SigningAccount`s on the chain, and will return any ERC20 balance from those accounts if the ERC20 is registered via `Chain.RegisterERC20`. The pre-deployed ERC20 that is required for the tests is registered on setup. When run against a live network, the suite will automatically return all the sdk funds sent to `SigningAccount`s on the chain, and will return any ERC20 balance from those accounts if the ERC20 is registered via `Chain.RegisterERC20`. The pre-deployed ERC20 that is required for the tests is registered on setup.
At this time, live-network tests do not support `E2E_INCLUDE_IBC_TESTS=true` and they do not support automated upgrades. At this time, live-network tests do not support `E2E_INCLUDE_IBC_TESTS=true`.
`E2E_KAVA_UPGRADE_HEIGHT` is supported for an existing upgrade height, and can
be used to verify before / after upgrade state. This doesn't run automatically
any upgrades.
## `Chain`s ## `Chain`s

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
rpchttpclient "github.com/tendermint/tendermint/rpc/client/http"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/kava-labs/kava/tests/util" "github.com/kava-labs/kava/tests/util"
@ -34,6 +35,11 @@ func (c ChainDetails) GrpcConn() (*grpc.ClientConn, error) {
return util.NewGrpcConnection(c.GrpcUrl) return util.NewGrpcConnection(c.GrpcUrl)
} }
// RpcConn creates a new connection to the underlying Rpc url.
func (c ChainDetails) RpcConn() (*rpchttpclient.HTTP, error) {
return rpchttpclient.New(c.RpcUrl, "/websocket")
}
// Chains wraps a map of name -> details about how to connect to a chain. // Chains wraps a map of name -> details about how to connect to a chain.
// It prevents registering multiple chains with the same name & encapsulates // It prevents registering multiple chains with the same name & encapsulates
// panicking if attempting to access a chain that does not exist. // panicking if attempting to access a chain that does not exist.

View File

@ -14,6 +14,8 @@ type LiveNodeRunnerConfig struct {
KavaRpcUrl string KavaRpcUrl string
KavaGrpcUrl string KavaGrpcUrl string
KavaEvmRpcUrl string KavaEvmRpcUrl string
UpgradeHeight int64
} }
// LiveNodeRunner implements NodeRunner for an already-running chain. // LiveNodeRunner implements NodeRunner for an already-running chain.

View File

@ -14,6 +14,7 @@ import (
sdkmath "cosmossdk.io/math" sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/go-bip39" "github.com/cosmos/go-bip39"
@ -37,7 +38,7 @@ type SigningAccount struct {
name string name string
mnemonic string mnemonic string
evmPrivKey *ethsecp256k1.PrivKey evmPrivKey cryptotypes.PrivKey
evmSigner *util.EvmSigner evmSigner *util.EvmSigner
evmReqChan chan<- util.EvmTxRequest evmReqChan chan<- util.EvmTxRequest
evmResChan <-chan util.EvmTxResponse evmResChan <-chan util.EvmTxResponse
@ -76,6 +77,27 @@ func (chain *Chain) AddNewSigningAccount(name string, hdPath *hd.BIP44Params, ch
require.NoErrorf(chain.t, err, "failed to derive private key from mnemonic for %s: %s", name, err) require.NoErrorf(chain.t, err, "failed to derive private key from mnemonic for %s: %s", name, err)
privKey := &ethsecp256k1.PrivKey{Key: privKeyBytes} privKey := &ethsecp256k1.PrivKey{Key: privKeyBytes}
return chain.AddNewSigningAccountFromPrivKey(
name,
privKey,
mnemonic,
chainId,
)
}
// AddNewSigningAccountFromPrivKey sets up a new account with a signer for SDK and EVM transactions,
// using the given private key.
func (chain *Chain) AddNewSigningAccountFromPrivKey(
name string,
privKey cryptotypes.PrivKey,
mnemonic string, // optional
chainId string,
) *SigningAccount {
if _, found := chain.accounts[name]; found {
chain.t.Fatalf("account with name %s already exists", name)
}
// Kava signing account for SDK side
kavaSigner := util.NewKavaSigner( kavaSigner := util.NewKavaSigner(
chainId, chainId,
chain.EncodingConfig, chain.EncodingConfig,
@ -92,7 +114,7 @@ func (chain *Chain) AddNewSigningAccount(name string, hdPath *hd.BIP44Params, ch
// Kava signing account for EVM side // Kava signing account for EVM side
evmChainId, err := emtypes.ParseChainID(chainId) evmChainId, err := emtypes.ParseChainID(chainId)
require.NoErrorf(chain.t, err, "unable to parse ethermint-compatible chain id from %s", chainId) require.NoErrorf(chain.t, err, "unable to parse ethermint-compatible chain id from %s", chainId)
ecdsaPrivKey, err := crypto.HexToECDSA(hex.EncodeToString(privKeyBytes)) ecdsaPrivKey, err := crypto.HexToECDSA(hex.EncodeToString(privKey.Bytes()))
require.NoError(chain.t, err, "failed to generate ECDSA private key from bytes") require.NoError(chain.t, err, "failed to generate ECDSA private key from bytes")
evmSigner, err := util.NewEvmSigner( evmSigner, err := util.NewEvmSigner(
@ -201,7 +223,7 @@ func (chain *Chain) NewFundedAccount(name string, funds sdk.Coins) *SigningAccou
acc := chain.AddNewSigningAccount( acc := chain.AddNewSigningAccount(
name, name,
hd.CreateHDPath(app.Bip44CoinType, 0, 0), hd.CreateHDPath(app.Bip44CoinType, 0, 0),
chain.ChainId, chain.ChainID,
mnemonic, mnemonic,
) )

View File

@ -10,12 +10,19 @@ import (
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx" txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
evmhd "github.com/evmos/ethermint/crypto/hd"
tmclient "github.com/tendermint/tendermint/rpc/client"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -32,6 +39,7 @@ import (
communitytypes "github.com/kava-labs/kava/x/community/types" communitytypes "github.com/kava-labs/kava/x/community/types"
earntypes "github.com/kava-labs/kava/x/earn/types" earntypes "github.com/kava-labs/kava/x/earn/types"
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types" evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
) )
// Chain wraps query clients & accounts for a network // Chain wraps query clients & accounts for a network
@ -40,7 +48,8 @@ type Chain struct {
t *testing.T t *testing.T
StakingDenom string StakingDenom string
ChainId string ChainID string
Keyring keyring.Keyring
EvmClient *ethclient.Client EvmClient *ethclient.Client
ContractAddrs map[string]common.Address ContractAddrs map[string]common.Address
@ -48,18 +57,24 @@ type Chain struct {
EncodingConfig kavaparams.EncodingConfig EncodingConfig kavaparams.EncodingConfig
Auth authtypes.QueryClient Auth authtypes.QueryClient
Bank banktypes.QueryClient Bank banktypes.QueryClient
Cdp cdptypes.QueryClient Cdp cdptypes.QueryClient
Committee committeetypes.QueryClient Committee committeetypes.QueryClient
Community communitytypes.QueryClient Community communitytypes.QueryClient
Earn earntypes.QueryClient Distribution distrtypes.QueryClient
Evm evmtypes.QueryClient Kavadist kavadisttypes.QueryClient
Evmutil evmutiltypes.QueryClient Earn earntypes.QueryClient
Gov govv1types.QueryClient Evm evmtypes.QueryClient
Tm tmservice.ServiceClient Evmutil evmutiltypes.QueryClient
Tx txtypes.ServiceClient Gov govv1types.QueryClient
Upgrade upgradetypes.QueryClient Mint minttypes.QueryClient
Staking stakingtypes.QueryClient
Tm tmservice.ServiceClient
Tx txtypes.ServiceClient
Upgrade upgradetypes.QueryClient
TmSignClient tmclient.SignClient
} }
// NewChain creates the query clients & signing account management for a chain run on a set of ports. // NewChain creates the query clients & signing account management for a chain run on a set of ports.
@ -69,12 +84,26 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
chain := &Chain{ chain := &Chain{
t: t, t: t,
StakingDenom: details.StakingDenom, StakingDenom: details.StakingDenom,
ChainId: details.ChainId, ChainID: details.ChainId,
ContractAddrs: make(map[string]common.Address), ContractAddrs: make(map[string]common.Address),
erc20s: make(map[common.Address]struct{}), erc20s: make(map[common.Address]struct{}),
} }
chain.EncodingConfig = app.MakeEncodingConfig() chain.EncodingConfig = app.MakeEncodingConfig()
// setup keyring
kr, err := keyring.New(
sdk.KeyringServiceName(),
keyring.BackendTest,
util.KavaHomePath(),
nil,
chain.EncodingConfig.Marshaler,
evmhd.EthSecp256k1Option(),
)
if err != nil {
return nil, err
}
chain.Keyring = kr
grpcConn, err := details.GrpcConn() grpcConn, err := details.GrpcConn()
if err != nil { if err != nil {
return chain, err return chain, err
@ -85,15 +114,24 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
return chain, err return chain, err
} }
chain.TmSignClient, err = details.RpcConn()
if err != nil {
return chain, err
}
chain.Auth = authtypes.NewQueryClient(grpcConn) chain.Auth = authtypes.NewQueryClient(grpcConn)
chain.Bank = banktypes.NewQueryClient(grpcConn) chain.Bank = banktypes.NewQueryClient(grpcConn)
chain.Cdp = cdptypes.NewQueryClient(grpcConn) chain.Cdp = cdptypes.NewQueryClient(grpcConn)
chain.Committee = committeetypes.NewQueryClient(grpcConn) chain.Committee = committeetypes.NewQueryClient(grpcConn)
chain.Community = communitytypes.NewQueryClient(grpcConn) chain.Community = communitytypes.NewQueryClient(grpcConn)
chain.Distribution = distrtypes.NewQueryClient(grpcConn)
chain.Kavadist = kavadisttypes.NewQueryClient(grpcConn)
chain.Earn = earntypes.NewQueryClient(grpcConn) chain.Earn = earntypes.NewQueryClient(grpcConn)
chain.Evm = evmtypes.NewQueryClient(grpcConn) chain.Evm = evmtypes.NewQueryClient(grpcConn)
chain.Evmutil = evmutiltypes.NewQueryClient(grpcConn) chain.Evmutil = evmutiltypes.NewQueryClient(grpcConn)
chain.Gov = govv1types.NewQueryClient(grpcConn) chain.Gov = govv1types.NewQueryClient(grpcConn)
chain.Mint = minttypes.NewQueryClient(grpcConn)
chain.Staking = stakingtypes.NewQueryClient(grpcConn)
chain.Tm = tmservice.NewServiceClient(grpcConn) chain.Tm = tmservice.NewServiceClient(grpcConn)
chain.Tx = txtypes.NewServiceClient(grpcConn) chain.Tx = txtypes.NewServiceClient(grpcConn)
chain.Upgrade = upgradetypes.NewQueryClient(grpcConn) chain.Upgrade = upgradetypes.NewQueryClient(grpcConn)
@ -104,12 +142,12 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
whale := chain.AddNewSigningAccount( whale := chain.AddNewSigningAccount(
FundedAccountName, FundedAccountName,
hd.CreateHDPath(Bip44CoinType, 0, 0), hd.CreateHDPath(Bip44CoinType, 0, 0),
chain.ChainId, chain.ChainID,
fundedAccountMnemonic, fundedAccountMnemonic,
) )
// check that funded account is actually funded. // check that funded account is actually funded.
fmt.Printf("[%s] account used for funding (%s) address: %s\n", chain.ChainId, FundedAccountName, whale.SdkAddress) fmt.Printf("[%s] account used for funding (%s) address: %s\n", chain.ChainID, FundedAccountName, whale.SdkAddress)
whaleFunds := chain.QuerySdkForBalances(whale.SdkAddress) whaleFunds := chain.QuerySdkForBalances(whale.SdkAddress)
if whaleFunds.IsZero() { if whaleFunds.IsZero() {
chain.t.Fatal("funded account mnemonic is for account with no funds") chain.t.Fatal("funded account mnemonic is for account with no funds")
@ -202,3 +240,64 @@ func (chain *Chain) GetErc20Balance(contract, address common.Address) *big.Int {
return new(big.Int).SetBytes(resData) return new(big.Int).SetBytes(resData)
} }
func (chain *Chain) GetBeginBlockEventsFromQuery(
ctx context.Context,
query string,
) (sdk.StringEvents, int64, error) {
// 1) Block search to find auction_start event and corresponding height
// https://rpc.kava.io/block_search?query=%22auction_start.auction_id=16837%22
blocks, err := chain.QueryBlock(ctx, query)
if err != nil {
return nil, 0, err
}
if len(blocks) == 0 {
return nil, 0, fmt.Errorf("no blocks found")
}
// 2) Block results to query events from height
// https://rpc.kava.io/block_results?height=3146803
events, err := chain.GetBeginBlockEvents(ctx, blocks[0].Block.Height)
return events, blocks[0].Block.Height, err
}
func (chain *Chain) QueryBlock(ctx context.Context, query string) ([]*coretypes.ResultBlock, error) {
page := 1
perPage := 100
res, err := chain.TmSignClient.BlockSearch(
ctx,
query,
&page,
&perPage,
"desc",
)
if err != nil {
return nil, fmt.Errorf("failed BlockSearch: %w", err)
}
return res.Blocks, nil
}
func (chain *Chain) GetBeginBlockEvents(ctx context.Context, height int64) (sdk.StringEvents, error) {
res, err := chain.TmSignClient.BlockResults(
ctx,
&height,
)
if err != nil {
return nil, fmt.Errorf("failed BlockResults: %w", err)
}
// Do not use sdk.StringifyEvents as it flattens events which makes it
// more difficult to parse.
strEvents := make(sdk.StringEvents, 0, len(res.BeginBlockEvents))
for _, e := range res.BeginBlockEvents {
strEvents = append(strEvents, sdk.StringifyEvent(e))
}
return strEvents, nil
}

View File

@ -56,6 +56,8 @@ type LiveNetworkConfig struct {
KavaRpcUrl string KavaRpcUrl string
KavaGrpcUrl string KavaGrpcUrl string
KavaEvmRpcUrl string KavaEvmRpcUrl string
UpgradeHeight int64
} }
// ParseSuiteConfig builds a SuiteConfig from environment variables. // ParseSuiteConfig builds a SuiteConfig from environment variables.
@ -107,11 +109,23 @@ func ParseKvtoolConfig() KvtoolConfig {
// ParseLiveNetworkConfig builds a LiveNetworkConfig from environment variables. // ParseLiveNetworkConfig builds a LiveNetworkConfig from environment variables.
func ParseLiveNetworkConfig() LiveNetworkConfig { func ParseLiveNetworkConfig() LiveNetworkConfig {
return LiveNetworkConfig{ config := LiveNetworkConfig{
KavaRpcUrl: nonemptyStringEnv("E2E_KAVA_RPC_URL"), KavaRpcUrl: nonemptyStringEnv("E2E_KAVA_RPC_URL"),
KavaGrpcUrl: nonemptyStringEnv("E2E_KAVA_GRPC_URL"), KavaGrpcUrl: nonemptyStringEnv("E2E_KAVA_GRPC_URL"),
KavaEvmRpcUrl: nonemptyStringEnv("E2E_KAVA_EVM_RPC_URL"), KavaEvmRpcUrl: nonemptyStringEnv("E2E_KAVA_EVM_RPC_URL"),
} }
upgradeHeight := os.Getenv("E2E_KAVA_UPGRADE_HEIGHT")
if upgradeHeight != "" {
parsedHeight, err := strconv.ParseInt(upgradeHeight, 10, 64)
if err != nil {
panic(fmt.Sprintf("E2E_KAVA_UPGRADE_HEIGHT must be a number: %s", err))
}
config.UpgradeHeight = parsedHeight
}
return config
} }
// mustParseBool is a helper method that panics if the env variable `name` // mustParseBool is a helper method that panics if the env variable `name`

View File

@ -35,7 +35,7 @@ func (suite *E2eTestSuite) NewEip712TxBuilder(
accNumber := accDetails.GetAccountNumber() accNumber := accDetails.GetAccountNumber()
// get chain id // get chain id
pc, err := emtypes.ParseChainID(chain.ChainId) pc, err := emtypes.ParseChainID(chain.ChainID)
suite.NoError(err) suite.NoError(err)
ethChainId := pc.Uint64() ethChainId := pc.Uint64()
@ -47,7 +47,7 @@ func (suite *E2eTestSuite) NewEip712TxBuilder(
// build EIP712 tx // build EIP712 tx
// -- untyped data // -- untyped data
untypedData := eip712.ConstructUntypedEIP712Data( untypedData := eip712.ConstructUntypedEIP712Data(
chain.ChainId, chain.ChainID,
accNumber, accNumber,
nonce, nonce,
0, // no timeout 0, // no timeout

View File

@ -20,7 +20,11 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
// ensure funded account has nonzero erc20 balance // ensure funded account has nonzero erc20 balance
balance := suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, whale.EvmAddress) balance := suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, whale.EvmAddress)
if balance.Cmp(big.NewInt(0)) != 1 { if balance.Cmp(big.NewInt(0)) != 1 {
panic(fmt.Sprintf("expected funded account (%s) to have erc20 balance", whale.EvmAddress.Hex())) panic(fmt.Sprintf(
"expected funded account (%s) to have erc20 balance of token %s",
whale.EvmAddress.Hex(),
suite.DeployedErc20.Address.Hex(),
))
} }
// expect the erc20 to be enabled for conversion to sdk.Coin // expect the erc20 to be enabled for conversion to sdk.Coin

View File

@ -3,7 +3,6 @@ package testutil
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"path/filepath"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -194,12 +193,16 @@ func (suite *E2eTestSuite) SetupLiveNetworkNodeRunner() *runner.LiveNodeRunner {
if suite.config.IncludeIbcTests { if suite.config.IncludeIbcTests {
panic("ibc tests not supported for live network configuration") panic("ibc tests not supported for live network configuration")
} }
// Manually set upgrade height for live networks
suite.UpgradeHeight = suite.config.LiveNetwork.UpgradeHeight
suite.enableRefunds = true suite.enableRefunds = true
runnerConfig := runner.LiveNodeRunnerConfig{ runnerConfig := runner.LiveNodeRunnerConfig{
KavaRpcUrl: suite.config.LiveNetwork.KavaRpcUrl, KavaRpcUrl: suite.config.LiveNetwork.KavaRpcUrl,
KavaGrpcUrl: suite.config.LiveNetwork.KavaGrpcUrl, KavaGrpcUrl: suite.config.LiveNetwork.KavaGrpcUrl,
KavaEvmRpcUrl: suite.config.LiveNetwork.KavaEvmRpcUrl, KavaEvmRpcUrl: suite.config.LiveNetwork.KavaEvmRpcUrl,
UpgradeHeight: suite.config.LiveNetwork.UpgradeHeight,
} }
return runner.NewLiveNodeRunner(runnerConfig) return runner.NewLiveNodeRunner(runnerConfig)
@ -217,15 +220,23 @@ func (suite *E2eTestSuite) SkipIfIbcDisabled() {
// It gracefully skips the current test if upgrades are dissabled. // It gracefully skips the current test if upgrades are dissabled.
// Note: automated upgrade tests are currently only enabled for Kvtool suite runs. // Note: automated upgrade tests are currently only enabled for Kvtool suite runs.
func (suite *E2eTestSuite) SkipIfUpgradeDisabled() { func (suite *E2eTestSuite) SkipIfUpgradeDisabled() {
if suite.config.Kvtool != nil && suite.config.Kvtool.IncludeAutomatedUpgrade { if suite.config.Kvtool != nil && !suite.config.Kvtool.IncludeAutomatedUpgrade {
fmt.Println("skipping upgrade test, kvtool automated upgrade is disabled")
suite.T().SkipNow()
}
// If there isn't a manual upgrade height set in the config, skip the test
if suite.config.LiveNetwork != nil && suite.config.LiveNetwork.UpgradeHeight == 0 {
fmt.Println("skipping upgrade test, live network upgrade height is not set")
suite.T().SkipNow() suite.T().SkipNow()
} }
} }
// KavaHomePath returns the OS-specific filepath for the kava home directory // SkipIfKvtoolDisabled should be called at the start of tests that require kvtool.
// Assumes network is running with kvtool installed from the sub-repository in tests/e2e/kvtool func (suite *E2eTestSuite) SkipIfKvtoolDisabled() {
func (suite *E2eTestSuite) KavaHomePath() string { if suite.config.Kvtool == nil {
return filepath.Join("kvtool", "full_configs", "generated", "kava", "initstate", ".kava") suite.T().SkipNow()
}
} }
// BigIntsEqual is a helper method for comparing the equality of two big ints // BigIntsEqual is a helper method for comparing the equality of two big ints

31
tests/util/events.go Normal file
View File

@ -0,0 +1,31 @@
package util
import (
abci "github.com/tendermint/tendermint/abci/types"
)
// FilterEventsByType returns a slice of events that match the given type.
func FilterEventsByType(events []abci.Event, eventType string) []abci.Event {
filteredEvents := []abci.Event{}
for _, event := range events {
if event.Type == eventType {
filteredEvents = append(filteredEvents, event)
}
}
return filteredEvents
}
// FilterTxEventsByType returns a slice of events that match the given type
// from any and all txs in a slice of ResponseDeliverTx.
func FilterTxEventsByType(txs []*abci.ResponseDeliverTx, eventType string) []abci.Event {
filteredEvents := []abci.Event{}
for _, tx := range txs {
events := FilterEventsByType(tx.Events, eventType)
filteredEvents = append(filteredEvents, events...)
}
return filteredEvents
}

View File

@ -9,6 +9,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
@ -21,17 +22,17 @@ func NewGrpcConnection(endpoint string) (*grpc.ClientConn, error) {
return nil, err return nil, err
} }
var secureOpt grpc.DialOption var creds credentials.TransportCredentials
switch grpcUrl.Scheme { switch grpcUrl.Scheme {
case "http": case "http":
secureOpt = grpc.WithInsecure() creds = insecure.NewCredentials()
case "https": case "https":
creds := credentials.NewTLS(&tls.Config{}) creds = credentials.NewTLS(&tls.Config{})
secureOpt = grpc.WithTransportCredentials(creds)
default: default:
return nil, fmt.Errorf("unknown grpc url scheme: %s", grpcUrl.Scheme) return nil, fmt.Errorf("unknown grpc url scheme: %s", grpcUrl.Scheme)
} }
secureOpt := grpc.WithTransportCredentials(creds)
grpcConn, err := grpc.Dial(grpcUrl.Host, secureOpt) grpcConn, err := grpc.Dial(grpcUrl.Host, secureOpt)
if err != nil { if err != nil {
return nil, err return nil, err

11
tests/util/kvtool.go Normal file
View File

@ -0,0 +1,11 @@
package util
import (
"path/filepath"
)
// KavaHomePath returns the OS-specific filepath for the kava home directory
// Assumes network is running with kvtool installed from the sub-repository in tests/e2e/kvtool
func KavaHomePath() string {
return filepath.Join("kvtool", "full_configs", "generated", "kava", "initstate", ".kava")
}

View File

@ -28,18 +28,22 @@ func (k Keeper) CheckAndDisableMintAndKavaDistInflation(ctx sdk.Context) {
logger.Info("disable inflation upgrade finished successfully!") logger.Info("disable inflation upgrade finished successfully!")
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeInflationStop,
),
)
// reset disable inflation time to ensure next call is a no-op // reset disable inflation time to ensure next call is a no-op
params.UpgradeTimeDisableInflation = time.Time{} params.UpgradeTimeDisableInflation = time.Time{}
// set staking rewards to provided intial value // set staking rewards to provided intial value
params.StakingRewardsPerSecond = params.UpgradeTimeSetStakingRewardsPerSecond params.StakingRewardsPerSecond = params.UpgradeTimeSetStakingRewardsPerSecond
k.SetParams(ctx, params) k.SetParams(ctx, params)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeInflationStop,
sdk.NewAttribute(
types.AttributeKeyInflationDisableTime,
ctx.BlockTime().Format(time.RFC3339),
),
),
)
if err := k.StartCommunityFundConsolidation(ctx); err != nil { if err := k.StartCommunityFundConsolidation(ctx); err != nil {
panic(err) panic(err)
} }

View File

@ -106,7 +106,17 @@ func (suite *disableInflationTestSuite) TestDisableInflation() {
msgSuffix = "after upgrade" msgSuffix = "after upgrade"
suite.Require().NoError(app.EventsContains(suite.Ctx.EventManager().Events(), sdk.NewEvent(types.EventTypeInflationStop))) suite.Require().NoError(
app.EventsContains(
suite.Ctx.EventManager().Events(),
sdk.NewEvent(
types.EventTypeInflationStop,
sdk.NewAttribute(
types.AttributeKeyInflationDisableTime,
suite.Ctx.BlockTime().Format(time.RFC3339),
),
),
))
} }
suite.Require().Equal(expectedMintState.Params.InflationMin, mintParams.InflationMin, msg+": expected mint inflation min to match state "+msgSuffix) suite.Require().Equal(expectedMintState.Params.InflationMin, mintParams.InflationMin, msg+": expected mint inflation min to match state "+msgSuffix)

View File

@ -5,7 +5,8 @@ const (
EventTypeInflationStop = "inflation_stop" EventTypeInflationStop = "inflation_stop"
EventTypeStakingRewardsPaid = "staking_rewards_paid" EventTypeStakingRewardsPaid = "staking_rewards_paid"
AttributeKeyStakingRewardAmount = "staking_reward_amount" AttributeKeyStakingRewardAmount = "staking_reward_amount"
AttributeKeyInflationDisableTime = "inflation_disable_time"
AttributeValueFundCommunityPool = "fund_community_pool" AttributeValueFundCommunityPool = "fund_community_pool"
AttributeValueCategory = ModuleName AttributeValueCategory = ModuleName