github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/params/proposal_handler_test.go (about)

     1  package params
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store"
     9  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt"
    10  	storetypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    11  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/bank"
    14  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    15  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1"
    16  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    17  	tmdb "github.com/fibonacci-chain/fbc/libs/tm-db"
    18  	govtypes "github.com/fibonacci-chain/fbc/x/gov/types"
    19  	"github.com/fibonacci-chain/fbc/x/params/types"
    20  	"github.com/stretchr/testify/suite"
    21  )
    22  
    23  type mockStakingKeeper struct {
    24  	vals map[string]struct{}
    25  }
    26  
    27  func newMockStakingKeeper(vals ...sdk.AccAddress) *mockStakingKeeper {
    28  	valsMap := make(map[string]struct{})
    29  	for _, val := range vals {
    30  		valsMap[val.String()] = struct{}{}
    31  	}
    32  	return &mockStakingKeeper{valsMap}
    33  }
    34  
    35  func (sk *mockStakingKeeper) IsValidator(_ sdk.Context, addr sdk.AccAddress) bool {
    36  	_, ok := sk.vals[addr.String()]
    37  	return ok
    38  }
    39  
    40  func makeTestCodec() *codec.Codec {
    41  	var cdc = codec.New()
    42  	auth.RegisterCodec(cdc)
    43  	RegisterCodec(cdc)
    44  	codec.RegisterCrypto(cdc)
    45  
    46  	return cdc
    47  }
    48  
    49  type ProposalHandlerSuite struct {
    50  	suite.Suite
    51  	ms           storetypes.CommitMultiStore
    52  	paramsKeeper Keeper
    53  	bankKeeper   bank.BaseKeeper
    54  
    55  	validatorPriv secp256k1.PrivKeySecp256k1
    56  	regularPriv   secp256k1.PrivKeySecp256k1
    57  }
    58  
    59  func TestProposalHandler(t *testing.T) {
    60  	suite.Run(t, new(ProposalHandlerSuite))
    61  }
    62  
    63  func (suite *ProposalHandlerSuite) SetupTest() {
    64  	db := tmdb.NewMemDB()
    65  	storeKey := sdk.NewKVStoreKey(StoreKey)
    66  	tstoreKey := sdk.NewTransientStoreKey(TStoreKey)
    67  	keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
    68  	keyMpt := sdk.NewKVStoreKey(mpt.StoreKey)
    69  
    70  	suite.ms = store.NewCommitMultiStore(tmdb.NewMemDB())
    71  	suite.ms.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db)
    72  	suite.ms.MountStoreWithDB(tstoreKey, sdk.StoreTypeTransient, db)
    73  	suite.ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
    74  	suite.ms.MountStoreWithDB(keyMpt, sdk.StoreTypeMPT, db)
    75  	err := suite.ms.LoadLatestVersion()
    76  	suite.NoError(err)
    77  
    78  	cdc := makeTestCodec()
    79  
    80  	suite.paramsKeeper = NewKeeper(cdc, storeKey, tstoreKey, log.NewNopLogger())
    81  
    82  	accountKeeper := auth.NewAccountKeeper(
    83  		cdc,
    84  		keyAcc,
    85  		keyMpt,
    86  		suite.paramsKeeper.Subspace(auth.DefaultParamspace),
    87  		auth.ProtoBaseAccount, // prototype
    88  	)
    89  	suite.bankKeeper = bank.NewBaseKeeper(
    90  		accountKeeper,
    91  		suite.paramsKeeper.Subspace(bank.DefaultParamspace),
    92  		make(map[string]bool),
    93  	)
    94  
    95  	suite.validatorPriv = secp256k1.GenPrivKeySecp256k1([]byte("private key to validator"))
    96  	suite.regularPriv = secp256k1.GenPrivKeySecp256k1([]byte("private key to regular"))
    97  
    98  	suite.paramsKeeper.SetStakingKeeper(newMockStakingKeeper(sdk.AccAddress(suite.validatorPriv.PubKey().Address())))
    99  	suite.paramsKeeper.SetBankKeeper(suite.bankKeeper)
   100  }
   101  
   102  func (suite *ProposalHandlerSuite) Context(height int64) sdk.Context {
   103  	return sdk.NewContext(suite.ms, abci.Header{Height: height}, false, log.NewNopLogger())
   104  }
   105  
   106  func (suite *ProposalHandlerSuite) TestCheckUpgradeProposal() {
   107  	minDeposit := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)))
   108  
   109  	tests := []struct {
   110  		proposer            sdk.AccAddress
   111  		proposerCoins       sdk.SysCoins
   112  		proposalInitDeposit sdk.SysCoins
   113  		expectHeight        uint64
   114  		currentHeight       int64
   115  		maxBlockHeight      uint64
   116  		nameHasExist        bool
   117  		expectError         bool
   118  	}{
   119  		{ // proposer is not a validator
   120  			proposer:            sdk.AccAddress(suite.regularPriv.PubKey().Address()),
   121  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   122  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   123  			expectHeight:        20,
   124  			currentHeight:       10,
   125  			maxBlockHeight:      100,
   126  			expectError:         true,
   127  		},
   128  		{ // proposer has no enough coins
   129  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   130  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(1, 0)),
   131  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   132  			expectHeight:        20,
   133  			currentHeight:       10,
   134  			maxBlockHeight:      100,
   135  			expectError:         true,
   136  		},
   137  		{ // proposal init coin is too small
   138  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   139  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   140  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(1, 2)),
   141  			expectHeight:        20,
   142  			currentHeight:       10,
   143  			maxBlockHeight:      100,
   144  			expectError:         true,
   145  		},
   146  		{ // expectHeight is not zero and smaller than current height
   147  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   148  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   149  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   150  			expectHeight:        10,
   151  			currentHeight:       11,
   152  			maxBlockHeight:      100,
   153  			expectError:         true,
   154  		},
   155  		{ // expectHeight is not zero and equal current height
   156  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   157  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   158  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   159  			expectHeight:        11,
   160  			currentHeight:       11,
   161  			maxBlockHeight:      100,
   162  			expectError:         true,
   163  		},
   164  		{ // expectHeight is not zero but too far away from current height
   165  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   166  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   167  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   168  			expectHeight:        22,
   169  			currentHeight:       11,
   170  			maxBlockHeight:      10,
   171  			expectError:         true,
   172  		},
   173  		{ // expectHeight is 0
   174  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   175  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   176  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   177  			expectHeight:        0,
   178  			currentHeight:       11,
   179  			maxBlockHeight:      10,
   180  			expectError:         false,
   181  		},
   182  		{ // expectHeight is not zero but name has been exist
   183  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   184  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   185  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   186  			expectHeight:        12,
   187  			currentHeight:       11,
   188  			maxBlockHeight:      10,
   189  			nameHasExist:        true,
   190  			expectError:         true,
   191  		},
   192  
   193  		{ // expectHeight is not zero and every thing is ok
   194  			proposer:            sdk.AccAddress(suite.validatorPriv.PubKey().Address()),
   195  			proposerCoins:       minDeposit.MulDec(sdk.NewDecWithPrec(3, 0)),
   196  			proposalInitDeposit: minDeposit.MulDec(sdk.NewDecWithPrec(2, 0)),
   197  			expectHeight:        12,
   198  			currentHeight:       11,
   199  			maxBlockHeight:      10,
   200  			expectError:         false,
   201  		},
   202  	}
   203  
   204  	for i, tt := range tests {
   205  		ctx := suite.Context(tt.currentHeight)
   206  		err := suite.bankKeeper.SetCoins(ctx, tt.proposer, tt.proposerCoins)
   207  		suite.NoError(err)
   208  		param := types.DefaultParams()
   209  		param.MaxBlockHeight = tt.maxBlockHeight
   210  		param.MinDeposit = minDeposit
   211  		suite.paramsKeeper.SetParams(ctx, param)
   212  
   213  		upgradeProposal := types.NewUpgradeProposal("title", "desc", fmt.Sprintf("upgrade-name-%d", i), tt.expectHeight, "")
   214  		msg := govtypes.NewMsgSubmitProposal(upgradeProposal, tt.proposalInitDeposit, tt.proposer)
   215  		if tt.nameHasExist {
   216  			info := types.UpgradeInfo{
   217  				Name:            upgradeProposal.Name,
   218  				ExpectHeight:    upgradeProposal.ExpectHeight,
   219  				Config:          upgradeProposal.Config,
   220  				EffectiveHeight: 0,
   221  				Status:          0,
   222  			}
   223  			suite.NoError(suite.paramsKeeper.writeUpgradeInfo(ctx, info, false))
   224  		}
   225  
   226  		err = suite.paramsKeeper.CheckMsgSubmitProposal(ctx, msg)
   227  		if tt.expectError {
   228  			suite.Error(err)
   229  			continue
   230  		}
   231  
   232  		suite.NoError(err)
   233  		if !tt.nameHasExist {
   234  			_, err := suite.paramsKeeper.readUpgradeInfo(ctx, upgradeProposal.Name)
   235  			suite.Error(err)
   236  		}
   237  	}
   238  
   239  }
   240  
   241  func (suite *ProposalHandlerSuite) TestCheckUpgradeVote() {
   242  	tests := []struct {
   243  		expectHeight  uint64
   244  		currentHeight int64
   245  		expectError   bool
   246  	}{
   247  		{0, 10, false},
   248  		{0, 1111, false},
   249  		{10, 11, true},
   250  		{10, 10, true},
   251  		{10, 9, false},
   252  	}
   253  
   254  	for i, tt := range tests {
   255  		ctx := suite.Context(tt.currentHeight)
   256  		content := types.UpgradeProposal{ExpectHeight: tt.expectHeight}
   257  		proposal := govtypes.Proposal{Content: content, ProposalID: uint64(i)}
   258  		vote := govtypes.Vote{}
   259  
   260  		_, err := suite.paramsKeeper.VoteHandler(ctx, proposal, vote)
   261  		if tt.expectError {
   262  			suite.Error(err)
   263  		} else {
   264  			suite.NoError(err)
   265  		}
   266  	}
   267  }
   268  
   269  func (suite *ProposalHandlerSuite) TestAfterSubmitProposalHandler() {
   270  	ctx := suite.Context(10)
   271  	expectInfo := types.UpgradeInfo{
   272  		Name:            "name1",
   273  		EffectiveHeight: 0,
   274  		Status:          types.UpgradeStatusEffective,
   275  	}
   276  	proposal := govtypes.Proposal{
   277  		Content: types.UpgradeProposal{
   278  			Name:         expectInfo.Name,
   279  			ExpectHeight: expectInfo.ExpectHeight,
   280  			Config:       expectInfo.Config,
   281  		},
   282  		ProposalID: 1,
   283  	}
   284  
   285  	suite.paramsKeeper.AfterSubmitProposalHandler(ctx, proposal)
   286  
   287  	expectInfo.Status = types.UpgradeStatusPreparing
   288  	info, err := suite.paramsKeeper.readUpgradeInfo(ctx, expectInfo.Name)
   289  	suite.NoError(err)
   290  	suite.Equal(expectInfo, info)
   291  }