Skip to content

Commit

Permalink
test: Proposal msg execution test
Browse files Browse the repository at this point in the history
  • Loading branch information
dudong2 committed Jul 4, 2024
1 parent 4ef4878 commit 39dfb33
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 16 deletions.
95 changes: 89 additions & 6 deletions x/govshuttle/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,33 @@ import (
"encoding/json"
"math/big"
"testing"
"time"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/Canto-Network/Canto/v7/app"
"github.com/Canto-Network/Canto/v7/x/govshuttle/types"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/crypto/tmhash"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmversion "github.com/cometbft/cometbft/proto/tendermint/version"
"github.com/cometbft/cometbft/version"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/evmos/ethermint/server/config"
evm "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
"github.com/stretchr/testify/require"

//used for deploying contracts
"github.com/Canto-Network/Canto/v7/contracts"
"github.com/Canto-Network/Canto/v7/x/erc20/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)

Expand All @@ -34,6 +44,7 @@ type KeeperTestSuite struct {
queryClient types.QueryClient
queryClientEvm evm.QueryClient
signer keyring.Signer
validator stakingtypes.Validator
}

var s *KeeperTestSuite
Expand All @@ -45,14 +56,63 @@ func TestKeeperTestSuite(t *testing.T) {

// Test Helpers
func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false

feemarketGenesis := feemarkettypes.DefaultGenesisState()
feemarketGenesis.Params.EnableHeight = 1
feemarketGenesis.Params.NoBaseFee = false

//init app
suite.app = app.Setup(checkTx, feemarketGenesis)
// init app
suite.app = app.Setup(false, feemarketGenesis)

// consensus key
pubKey := ed25519.GenPrivKey().PubKey()
consAddress := sdk.ConsAddress(pubKey.Address())

suite.ctx = suite.app.BaseApp.NewContextLegacy(false, tmproto.Header{
Height: 1,
ChainID: "canto_9001-1",
Time: time.Now().UTC(),
ProposerAddress: consAddress.Bytes(),

Version: tmversion.Consensus{
Block: version.BlockProtocol,
},
LastBlockId: tmproto.BlockID{
Hash: tmhash.Sum([]byte("block_id")),
PartSetHeader: tmproto.PartSetHeader{
Total: 11,
Hash: tmhash.Sum([]byte("partset_header")),
},
},
AppHash: tmhash.Sum([]byte("app")),
DataHash: tmhash.Sum([]byte("data")),
EvidenceHash: tmhash.Sum([]byte("evidence")),
ValidatorsHash: tmhash.Sum([]byte("validators")),
NextValidatorsHash: tmhash.Sum([]byte("next_validators")),
ConsensusHash: tmhash.Sum([]byte("consensus")),
LastResultsHash: tmhash.Sum([]byte("last_result")),
})

queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.GovshuttleKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)

// Set Validator
valAddr := sdk.ValAddress(pubKey.Address().Bytes())
validator, err := stakingtypes.NewValidator(valAddr.String(), pubKey, stakingtypes.Description{})
suite.NoError(err)

validator = stakingkeeper.TestingUpdateValidator(suite.app.StakingKeeper, suite.ctx, validator, true)
valbz, err := suite.app.StakingKeeper.ValidatorAddressCodec().StringToBytes(validator.GetOperator())
suite.NoError(err)
suite.app.StakingKeeper.Hooks().AfterValidatorCreated(suite.ctx, valbz)
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
suite.NoError(err)
suite.validator = validator

stakingParams, err := suite.app.StakingKeeper.GetParams(suite.ctx)
suite.NoError(err)
stakingParams.BondDenom = "acanto"
suite.app.StakingKeeper.SetParams(suite.ctx, stakingParams)
}

func (suite *KeeperTestSuite) SetupTest() {
Expand Down Expand Up @@ -119,3 +179,26 @@ func (suite *KeeperTestSuite) DeployCaller() (common.Address, error) {
func (suite *KeeperTestSuite) DeployCallee() {

}

func (suite *KeeperTestSuite) Commit() {
suite.CommitAfter(time.Nanosecond)
}

func (suite *KeeperTestSuite) CommitAfter(t time.Duration) {
header := suite.ctx.BlockHeader()
header.Time = header.Time.Add(t)
suite.app.FinalizeBlock(&abci.RequestFinalizeBlock{
Height: header.Height,
Time: header.Time,
ProposerAddress: suite.ctx.BlockHeader().ProposerAddress,
})
suite.app.Commit()

// update ctx
header.Height += 1
suite.ctx = suite.app.BaseApp.NewUncachedContext(false, header)

queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
evm.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClientEvm = evm.NewQueryClient(queryHelper)
}
240 changes: 230 additions & 10 deletions x/govshuttle/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,237 @@
package keeper_test

import (
"context"
"testing"
"encoding/hex"
"encoding/json"
"fmt"
"math"
"math/big"

//sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/Canto-Network/Canto/v7/x/govshuttle/types"
//"github.com/Canto-Network/Canto/v2/x/govshuttle/keeper"
//keepertest "github.com/Canto-Network/Canto/v2/testutil/keeper"
"github.com/ethereum/go-ethereum/common"

sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/server/config"
evmtypes "github.com/evmos/ethermint/x/evm/types"

"github.com/Canto-Network/Canto/v7/contracts"
"github.com/Canto-Network/Canto/v7/testutil"
govshuttletypes "github.com/Canto-Network/Canto/v7/x/govshuttle/types"
)

func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) {
//k, ctx := keepertest.govshuttleKeeper(t)
//return keeper.NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx)
return nil, nil
type ProposalResult struct {
Id *big.Int `json:"id"`
Title string `json:"title"`
Desc string `json:"desc"`
Targets []common.Address `json:"targets"`
Values []*big.Int `json:"values"`
Signatures []string `json:"signatures"`
Calldatas [][]byte `json:"calldatas"`
}

func (suite *KeeperTestSuite) TestMsgExecutionByProposal() {
suite.SetupTest()

// get denom
stakingParams, err := suite.app.StakingKeeper.GetParams(suite.ctx)
suite.Require().NoError(err)
denom := stakingParams.BondDenom

// change mindeposit for denom
govParams, err := suite.app.GovKeeper.Params.Get(suite.ctx)
suite.Require().NoError(err)
govParams.MinDeposit = []sdk.Coin{sdk.NewCoin(denom, sdkmath.NewInt(1))}
err = suite.app.GovKeeper.Params.Set(suite.ctx, govParams)
suite.Require().NoError(err)

// create account
privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
proposer := sdk.AccAddress(privKey.PubKey().Address().Bytes())

// deligate to validator
initAmount := sdkmath.NewInt(int64(math.Pow10(18)) * 2)
initBalance := sdk.NewCoins(sdk.NewCoin(denom, initAmount))
testutil.FundAccount(suite.app.BankKeeper, suite.ctx, proposer, initBalance)
shares, err := suite.app.StakingKeeper.Delegate(suite.ctx, proposer, sdk.DefaultPowerReduction, stakingtypes.Unbonded, suite.validator, true)
suite.Require().NoError(err)
suite.Require().True(shares.GT(sdkmath.LegacyNewDec(0)))

testCases := []struct {
name string
msg sdk.Msg
checkFunc func(uint64)
expectErr bool
}{
{
"fail - MsgLendingMarketProposal - authority check",
&govshuttletypes.MsgLendingMarketProposal{
Authority: "canto1yrmjye0zyfvr0lthc6fwq7qlwg9e8muftxa630",
Title: "lending market proposal test",
Description: "lending market proposal test description",
Metadata: &govshuttletypes.LendingMarketMetadata{
Account: []string{"0x20F72265e2225837fd77C692e0781f720B93eF89", "0xf6Db2570A2417188a5788D6d5Fd9faAa5B1fE555"},
PropId: 1,
Values: []uint64{1234, 5678},
Calldatas: []string{hex.EncodeToString([]byte("calldata1")), hex.EncodeToString([]byte("calldata2"))},
Signatures: []string{"sig1", "sig2"},
},
},
func(proposalId uint64) {},
true,
},
{
"ok - MsgLendingMarketProposal",
&govshuttletypes.MsgLendingMarketProposal{
Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Title: "lending market proposal test",
Description: "lending market proposal test description",
Metadata: &govshuttletypes.LendingMarketMetadata{
Account: []string{"0x20F72265e2225837fd77C692e0781f720B93eF89", "0xf6Db2570A2417188a5788D6d5Fd9faAa5B1fE555"},
PropId: 1,
Values: []uint64{1234, 5678},
Calldatas: []string{hex.EncodeToString([]byte("calldata1")), hex.EncodeToString([]byte("calldata2"))},
Signatures: []string{"sig1", "sig2"},
},
},
func(proposalId uint64) {
proposal, err := suite.app.GovKeeper.Proposals.Get(suite.ctx, proposalId)
suite.Require().NoError(err)
suite.Require().Equal(govtypesv1.ProposalStatus_PROPOSAL_STATUS_PASSED, proposal.Status)

suite.checkQueryPropResult(
proposalId,
ProposalResult{
Id: big.NewInt(1),
Title: "lending market proposal test",
Desc: "lending market proposal test description",
Targets: []common.Address{common.HexToAddress("0x20F72265e2225837fd77C692e0781f720B93eF89"), common.HexToAddress("0xf6Db2570A2417188a5788D6d5Fd9faAa5B1fE555")},
Values: []*big.Int{big.NewInt(1234), big.NewInt(5678)},
Signatures: []string{"sig1", "sig2"},
Calldatas: [][]byte{[]byte("calldata1"), []byte("calldata2")},
},
)
},
false,
},
{
"fail - MsgTreasuryProposal - authority check",
&govshuttletypes.MsgTreasuryProposal{
Authority: "canto1yrmjye0zyfvr0lthc6fwq7qlwg9e8muftxa630",
Title: "treasury proposal test",
Description: "treasury proposal test description",
Metadata: &govshuttletypes.TreasuryProposalMetadata{
PropID: 2,
Recipient: "0x20F72265e2225837fd77C692e0781f720B93eF89",
Amount: 1234,
Denom: "acanto",
},
},
func(proposalId uint64) {},
true,
},
{
"ok - MsgTreasuryProposal",
&govshuttletypes.MsgTreasuryProposal{
Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Title: "treasury proposal test",
Description: "treasury proposal test description",
Metadata: &govshuttletypes.TreasuryProposalMetadata{
PropID: 2,
Recipient: "0x20F72265e2225837fd77C692e0781f720B93eF89",
Amount: 1234,
Denom: "acanto",
},
},
func(proposalId uint64) {
proposal, err := suite.app.GovKeeper.Proposals.Get(suite.ctx, proposalId)
suite.Require().NoError(err)
suite.Require().Equal(govtypesv1.ProposalStatus_PROPOSAL_STATUS_PASSED, proposal.Status)

suite.checkQueryPropResult(
proposalId,
ProposalResult{
Id: big.NewInt(2),
Title: "treasury proposal test",
Desc: "treasury proposal test description",
Targets: []common.Address{common.HexToAddress("0x20F72265e2225837fd77C692e0781f720B93eF89")},
Values: []*big.Int{big.NewInt(1234)},
Signatures: []string{"acanto"},
Calldatas: [][]byte{},
},
)
},
false,
},
}

for _, tc := range testCases {
suite.Run(tc.name, func() {
// submit proposal
proposal, err := suite.app.GovKeeper.SubmitProposal(suite.ctx, []sdk.Msg{tc.msg}, "", "test", "description", proposer, false)
if tc.expectErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
suite.Commit()

ok, err := suite.app.GovKeeper.AddDeposit(suite.ctx, proposal.Id, proposer, govParams.MinDeposit)
suite.Require().NoError(err)
suite.Require().True(ok)
suite.Commit()

err = suite.app.GovKeeper.AddVote(suite.ctx, proposal.Id, proposer, govtypesv1.NewNonSplitVoteOption(govtypesv1.OptionYes), "")
suite.Require().NoError(err)
suite.CommitAfter(*govParams.VotingPeriod)

// check proposal result
tc.checkFunc(proposal.Id)
}
})
}
}

func (suite *KeeperTestSuite) checkQueryPropResult(propId uint64, expectedResult ProposalResult) {
// make calldata
data, err := contracts.ProposalStoreContract.ABI.Pack("QueryProp", big.NewInt(int64(propId)))
suite.Require().NoError(err)

// get port contract address
portAddr, ok := suite.app.GovshuttleKeeper.GetPort(suite.ctx)
suite.Require().True(ok)

txArgs := map[string]interface{}{
"to": portAddr,
"data": fmt.Sprintf("0x%x", data),
}
txArgsJson, err := json.Marshal(txArgs)
suite.Require().NoError(err)

// query to contract
req := &evmtypes.EthCallRequest{
Args: txArgsJson,
GasCap: config.DefaultGasCap,
}
rpcRes, err := suite.app.EvmKeeper.EthCall(suite.ctx, req)
suite.Require().NoError(err)

queryRes, err := contracts.ProposalStoreContract.ABI.Unpack("QueryProp", rpcRes.Ret)
suite.Require().NoError(err)

// marshal and unmarshal to get ProposalResult
var res ProposalResult
b, err := json.Marshal(queryRes[0])
suite.Require().NoError(err)
json.Unmarshal(b, &res)

suite.Require().Equal(
expectedResult,
res,
)
}

0 comments on commit 39dfb33

Please sign in to comment.