2023-11-02 00:22:38 +00:00
|
|
|
package e2e_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2024-05-01 05:53:58 +00:00
|
|
|
"math/big"
|
2023-11-02 00:22:38 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
query "github.com/cosmos/cosmos-sdk/types/query"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
|
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
|
|
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
|
|
|
|
2024-05-01 03:17:24 +00:00
|
|
|
"github.com/0glabs/0g-chain/tests/e2e/testutil"
|
|
|
|
"github.com/0glabs/0g-chain/tests/util"
|
2023-11-02 00:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2024-05-01 05:53:58 +00:00
|
|
|
govModuleAcc = "0g10d07y265gmmuvt4z0w9aw880jnsr700jxh8cq5"
|
|
|
|
communityModuleAcc = "0g17d2wax0zhjrrecvaszuyxdf5wcu5a0p4qlx3t5"
|
|
|
|
zgChainDistModuleAcc = "0g1cj7njkw2g9fqx4e768zc75dp9sks8u9znxrf0w"
|
2023-11-02 00:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (suite *IntegrationTestSuite) TestGovParamChanges() {
|
|
|
|
suite.SkipIfUpgradeDisabled()
|
|
|
|
|
|
|
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
|
|
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
|
|
|
|
|
|
|
// fetch gov parameters before upgrade
|
2024-05-01 05:53:58 +00:00
|
|
|
govBeforeParams, err := suite.ZgChain.Gov.Params(beforeUpgradeCtx, &govv1.QueryParamsRequest{ParamsType: "tallying"})
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
// assert expected gov quorum before upgrade
|
|
|
|
suite.NotEqual(govBeforeParams.TallyParams.Quorum, "0.200000000000000000")
|
|
|
|
|
2024-05-01 05:53:58 +00:00
|
|
|
govAfterParams, err := suite.ZgChain.Gov.Params(afterUpgradeCtx, &govv1.QueryParamsRequest{ParamsType: "tallying"})
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
// assert expected gov quorum after upgrade
|
|
|
|
suite.Equal(govAfterParams.TallyParams.Quorum, "0.200000000000000000")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTestSuite) TestAuthzParamChanges() {
|
|
|
|
suite.SkipIfUpgradeDisabled()
|
|
|
|
|
|
|
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
|
|
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
|
|
|
|
|
|
|
// fetch authz grants before upgrade
|
2024-05-01 05:53:58 +00:00
|
|
|
authzBeforeGrants, err := suite.ZgChain.Authz.Grants(beforeUpgradeCtx, &authz.QueryGrantsRequest{Granter: zgChainDistModuleAcc, Grantee: govModuleAcc, Pagination: &query.PageRequest{Limit: 1000, CountTotal: true}})
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
suite.Require().Equal(authzBeforeGrants.Pagination.Total, uint64(len(authzBeforeGrants.Grants)), "expected all grants to have been requested")
|
|
|
|
|
|
|
|
// no kavadist -> gov grants
|
|
|
|
suite.Equal(0, len(authzBeforeGrants.Grants))
|
|
|
|
|
|
|
|
// fetch authz grants after upgrade
|
2024-05-01 05:53:58 +00:00
|
|
|
authzAfterGrants, err := suite.ZgChain.Authz.Grants(afterUpgradeCtx, &authz.QueryGrantsRequest{Granter: zgChainDistModuleAcc, Grantee: govModuleAcc, Pagination: &query.PageRequest{Limit: 1000, CountTotal: true}})
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
suite.Require().Equal(authzAfterGrants.Pagination.Total, uint64(len(authzAfterGrants.Grants)), "expected all grants to have been requested")
|
|
|
|
|
|
|
|
// one kavadist -> gov grants
|
|
|
|
suite.Require().Equal(1, len(authzAfterGrants.Grants))
|
|
|
|
|
|
|
|
grant := authzAfterGrants.Grants[0]
|
|
|
|
|
|
|
|
var authorization authz.Authorization
|
2024-05-01 05:53:58 +00:00
|
|
|
suite.ZgChain.EncodingConfig.Marshaler.UnpackAny(grant.Authorization, &authorization)
|
2023-11-02 00:22:38 +00:00
|
|
|
|
|
|
|
genericAuthorization, ok := authorization.(*authz.GenericAuthorization)
|
|
|
|
suite.Require().True(ok, "expected generic authorization")
|
|
|
|
|
|
|
|
// kavadist allows gov to MsgSend it's funds
|
|
|
|
suite.Equal(sdk.MsgTypeURL(&banktypes.MsgSend{}), genericAuthorization.Msg)
|
|
|
|
// no expiration
|
|
|
|
var expectedExpiration *time.Time
|
|
|
|
suite.Equal(expectedExpiration, grant.Expiration)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTestSuite) TestModuleAccountGovTransfers() {
|
|
|
|
suite.SkipIfUpgradeDisabled()
|
|
|
|
suite.SkipIfKvtoolDisabled()
|
|
|
|
|
|
|
|
// the module account (authority) that executes the transfers
|
|
|
|
govAcc := sdk.MustAccAddressFromBech32(govModuleAcc)
|
|
|
|
|
|
|
|
// module accounts for gov transfer test cases
|
|
|
|
communityAcc := sdk.MustAccAddressFromBech32(communityModuleAcc)
|
2024-05-01 05:53:58 +00:00
|
|
|
zgChainDistAcc := sdk.MustAccAddressFromBech32(zgChainDistModuleAcc)
|
2023-11-02 00:22:38 +00:00
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
sender sdk.AccAddress
|
|
|
|
receiver sdk.AccAddress
|
|
|
|
amount sdk.Coin
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "transfer from community to kavadist for incentive rewards",
|
|
|
|
sender: communityAcc,
|
2024-05-01 05:53:58 +00:00
|
|
|
receiver: zgChainDistAcc,
|
|
|
|
amount: a0gi(big.NewInt(100)),
|
2023-11-02 00:22:38 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "transfer from kavadist to community",
|
2024-05-01 05:53:58 +00:00
|
|
|
sender: zgChainDistAcc,
|
2023-11-02 00:22:38 +00:00
|
|
|
receiver: communityAcc,
|
2024-05-01 05:53:58 +00:00
|
|
|
amount: a0gi(big.NewInt(50)),
|
2023-11-02 00:22:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
suite.Run(tc.name, func() {
|
|
|
|
// create msg exec for transfer between modules
|
|
|
|
msg := banktypes.NewMsgSend(
|
|
|
|
tc.sender,
|
|
|
|
tc.receiver,
|
|
|
|
sdk.NewCoins(tc.amount),
|
|
|
|
)
|
|
|
|
execMsg := authz.NewMsgExec(govAcc, []sdk.Msg{msg})
|
|
|
|
|
|
|
|
// ensure proposal passes
|
|
|
|
passBlock := suite.submitAndPassProposal([]sdk.Msg{&execMsg})
|
|
|
|
transfers := suite.getBankTransferAmountAtBlock(passBlock, tc.sender, tc.receiver)
|
|
|
|
|
|
|
|
suite.Require().Containsf(
|
|
|
|
transfers,
|
|
|
|
tc.amount,
|
|
|
|
"expected transfer of %s to be included in bank transfer events: %s",
|
|
|
|
tc.amount,
|
|
|
|
transfers,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *IntegrationTestSuite) submitAndPassProposal(msgs []sdk.Msg) int64 {
|
2024-05-01 05:53:58 +00:00
|
|
|
govParamsRes, err := suite.ZgChain.Gov.Params(context.Background(), &govv1.QueryParamsRequest{
|
2023-11-02 00:22:38 +00:00
|
|
|
ParamsType: govv1.ParamDeposit,
|
|
|
|
})
|
|
|
|
suite.NoError(err)
|
|
|
|
|
2024-05-01 05:53:58 +00:00
|
|
|
zgChainAcc := suite.ZgChain.GetAccount(testutil.FundedAccountName)
|
2023-11-02 00:22:38 +00:00
|
|
|
|
|
|
|
proposalMsg, err := govv1.NewMsgSubmitProposal(
|
|
|
|
msgs,
|
|
|
|
govParamsRes.DepositParams.MinDeposit,
|
2024-05-01 05:53:58 +00:00
|
|
|
zgChainAcc.SdkAddress.String(),
|
2023-11-02 00:22:38 +00:00
|
|
|
"",
|
|
|
|
)
|
|
|
|
suite.NoError(err)
|
|
|
|
|
|
|
|
gasLimit := 1e6
|
2024-05-05 07:00:03 +00:00
|
|
|
fee := sdk.NewCoin("neuron", sdk.NewInt(1e15))
|
2023-11-02 00:22:38 +00:00
|
|
|
|
2024-05-01 05:53:58 +00:00
|
|
|
req := util.ZgChainMsgRequest{
|
2023-11-02 00:22:38 +00:00
|
|
|
Msgs: []sdk.Msg{proposalMsg},
|
|
|
|
GasLimit: uint64(gasLimit),
|
|
|
|
FeeAmount: sdk.NewCoins(fee),
|
|
|
|
Memo: "this is a proposal please accept me",
|
|
|
|
}
|
2024-05-01 05:53:58 +00:00
|
|
|
res := zgChainAcc.SignAndBroadcastZgChainTx(req)
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(res.Err)
|
|
|
|
|
|
|
|
// Wait for proposal to be submitted
|
2024-05-01 05:53:58 +00:00
|
|
|
txRes, err := util.WaitForSdkTxCommit(suite.ZgChain.Tx, res.Result.TxHash, 6*time.Second)
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
var govRes govv1.MsgSubmitProposalResponse
|
|
|
|
suite.decodeTxMsgResponse(txRes, &govRes)
|
|
|
|
|
|
|
|
// 2. Vote for proposal from whale account
|
2024-05-01 05:53:58 +00:00
|
|
|
whale := suite.ZgChain.GetAccount(testutil.FundedAccountName)
|
2023-11-02 00:22:38 +00:00
|
|
|
voteMsg := govv1.NewMsgVote(
|
|
|
|
whale.SdkAddress,
|
|
|
|
govRes.ProposalId,
|
|
|
|
govv1.OptionYes,
|
|
|
|
"",
|
|
|
|
)
|
|
|
|
|
2024-05-01 05:53:58 +00:00
|
|
|
voteReq := util.ZgChainMsgRequest{
|
2023-11-02 00:22:38 +00:00
|
|
|
Msgs: []sdk.Msg{voteMsg},
|
|
|
|
GasLimit: uint64(gasLimit),
|
|
|
|
FeeAmount: sdk.NewCoins(fee),
|
|
|
|
Memo: "voting",
|
|
|
|
}
|
2024-05-01 05:53:58 +00:00
|
|
|
voteRes := whale.SignAndBroadcastZgChainTx(voteReq)
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(voteRes.Err)
|
|
|
|
|
2024-05-01 05:53:58 +00:00
|
|
|
_, err = util.WaitForSdkTxCommit(suite.ZgChain.Tx, voteRes.Result.TxHash, 6*time.Second)
|
2023-11-02 00:22:38 +00:00
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
// 3. Wait until proposal passes
|
|
|
|
suite.Require().Eventually(func() bool {
|
2024-05-01 05:53:58 +00:00
|
|
|
proposalRes, err := suite.ZgChain.Gov.Proposal(context.Background(), &govv1.QueryProposalRequest{
|
2023-11-02 00:22:38 +00:00
|
|
|
ProposalId: govRes.ProposalId,
|
|
|
|
})
|
|
|
|
suite.NoError(err)
|
|
|
|
|
|
|
|
switch status := proposalRes.Proposal.Status; status {
|
|
|
|
case govv1.StatusDepositPeriod, govv1.StatusVotingPeriod:
|
|
|
|
return false
|
|
|
|
case govv1.StatusPassed:
|
|
|
|
return true
|
|
|
|
case govv1.StatusFailed, govv1.StatusRejected:
|
|
|
|
suite.Failf("proposal failed", "proposal failed with status %s", status.String())
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}, 60*time.Second, 1*time.Second)
|
|
|
|
|
|
|
|
page := 1
|
|
|
|
perPage := 100
|
|
|
|
|
|
|
|
// Get the block the proposal was passed in
|
2024-05-01 05:53:58 +00:00
|
|
|
passBlock, err := suite.ZgChain.TmSignClient.BlockSearch(
|
2023-11-02 00:22:38 +00:00
|
|
|
context.Background(),
|
|
|
|
fmt.Sprintf(
|
|
|
|
"active_proposal.proposal_result = 'proposal_passed' AND active_proposal.proposal_id = %d",
|
|
|
|
govRes.ProposalId,
|
|
|
|
),
|
|
|
|
&page,
|
|
|
|
&perPage,
|
|
|
|
"asc",
|
|
|
|
)
|
|
|
|
suite.Require().NoError(err)
|
|
|
|
suite.Require().Equal(1, len(passBlock.Blocks), "passed proposal should be searchable")
|
|
|
|
|
|
|
|
return passBlock.Blocks[len(passBlock.Blocks)-1].Block.Height
|
|
|
|
}
|
|
|
|
|
|
|
|
// getBankTransferAmountAtBlock returns the amount of coins transferred between
|
|
|
|
// the given accounts in the block at the given height. Note that this returns
|
|
|
|
// a slice of sdk.Coin that can contain multiple coins of the SAME denom -- ie. NOT sdk.Coins
|
|
|
|
func (suite *IntegrationTestSuite) getBankTransferAmountAtBlock(
|
|
|
|
blockHeight int64,
|
|
|
|
sender sdk.AccAddress,
|
|
|
|
receiver sdk.AccAddress,
|
|
|
|
) []sdk.Coin {
|
|
|
|
// Fetch block results for paid staking rewards in the block
|
2024-05-01 05:53:58 +00:00
|
|
|
blockRes, err := suite.ZgChain.TmSignClient.BlockResults(
|
2023-11-02 00:22:38 +00:00
|
|
|
context.Background(),
|
|
|
|
&blockHeight,
|
|
|
|
)
|
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
transferEvents := util.FilterEventsByType(
|
|
|
|
blockRes.EndBlockEvents, // gov proposals applied in EndBlocker
|
|
|
|
banktypes.EventTypeTransfer,
|
|
|
|
)
|
|
|
|
suite.Require().NotEmpty(transferEvents, "there should be at least 1 bank transfer event")
|
|
|
|
|
|
|
|
transfers := []sdk.Coin{}
|
|
|
|
|
|
|
|
event:
|
|
|
|
for _, event := range transferEvents {
|
|
|
|
if event.Type != banktypes.EventTypeTransfer {
|
|
|
|
suite.FailNowf(
|
|
|
|
"unexpected event type %s in block results",
|
|
|
|
event.Type,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, attr := range event.Attributes {
|
|
|
|
suite.T().Logf("event attr: %s = %s", string(attr.Key), string(attr.Value))
|
|
|
|
|
|
|
|
if string(attr.Key) == banktypes.AttributeKeyRecipient {
|
|
|
|
if string(attr.Value) != receiver.String() {
|
|
|
|
continue event
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(attr.Key) == banktypes.AttributeKeySender {
|
|
|
|
if string(attr.Value) != sender.String() {
|
|
|
|
continue event
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(attr.Key) == sdk.AttributeKeyAmount {
|
|
|
|
amount, err := sdk.ParseCoinNormalized(string(attr.Value))
|
|
|
|
suite.Require().NoError(err)
|
|
|
|
|
|
|
|
transfers = append(transfers, amount)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return transfers
|
|
|
|
}
|