github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/app_test.go (about)

     1  package app
     2  
     3  import (
     4  	"math/big"
     5  	"os"
     6  	"testing"
     7  
     8  	ethcommon "github.com/ethereum/go-ethereum/common"
     9  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    10  	"github.com/stretchr/testify/suite"
    11  
    12  	"github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1"
    13  	cosmossdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    14  	authclient "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils"
    15  	"github.com/fibonacci-chain/fbc/libs/tendermint/global"
    16  	tendertypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    17  	"github.com/fibonacci-chain/fbc/x/distribution/keeper"
    18  	evmtypes "github.com/fibonacci-chain/fbc/x/evm/types"
    19  
    20  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/upgrade"
    21  	"github.com/fibonacci-chain/fbc/x/dex"
    22  	distr "github.com/fibonacci-chain/fbc/x/distribution"
    23  	"github.com/fibonacci-chain/fbc/x/farm"
    24  	"github.com/fibonacci-chain/fbc/x/params"
    25  
    26  	"github.com/stretchr/testify/require"
    27  
    28  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    29  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    30  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    31  
    32  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    33  
    34  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    35  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    36  	abcitypes "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    37  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    38  	"github.com/fibonacci-chain/fbc/x/gov"
    39  )
    40  
    41  var (
    42  	txCoin10    = cosmossdk.NewInt64Coin(cosmossdk.DefaultBondDenom, 10)
    43  	txCoin1000  = cosmossdk.NewInt64Coin(cosmossdk.DefaultBondDenom, 1000)
    44  	txFees      = auth.NewStdFee(21000, cosmossdk.NewCoins(txCoin10))
    45  	txFeesError = auth.NewStdFee(100000000000000, cosmossdk.NewCoins(cosmossdk.NewInt64Coin(cosmossdk.DefaultBondDenom, 1000000000000000000)))
    46  
    47  	cosmosChainId = "ethermint-3"
    48  	checkTx       = false
    49  	blockHeight   = int64(2)
    50  
    51  	evmAmountZero = big.NewInt(0)
    52  	evmGasLimit   = uint64(1000000)
    53  	evmGasPrice   = big.NewInt(10000)
    54  	evmChainID    = big.NewInt(3)
    55  
    56  	nonce0 = uint64(0)
    57  	nonce1 = uint64(1)
    58  	nonce2 = uint64(2)
    59  	nonce3 = uint64(3)
    60  
    61  	accountNum = uint64(0)
    62  
    63  	sysCoins10 = keeper.NewTestSysCoins(10, 0)
    64  	sysCoins90 = keeper.NewTestSysCoins(90, 0)
    65  	memo       = "hello, memo"
    66  
    67  	govProposalID1 = uint64(1)
    68  	govProposalID2 = uint64(2)
    69  )
    70  
    71  func TestFBChainAppExport(t *testing.T) {
    72  	db := dbm.NewMemDB()
    73  	app := NewFBChainApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
    74  
    75  	genesisState := ModuleBasics.DefaultGenesis()
    76  	stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState)
    77  	require.NoError(t, err)
    78  
    79  	// Initialize the chain
    80  	app.InitChain(
    81  		abci.RequestInitChain{
    82  			Validators:    []abci.ValidatorUpdate{},
    83  			AppStateBytes: stateBytes,
    84  		},
    85  	)
    86  	app.Commit(abci.RequestCommit{})
    87  
    88  	// Making a new app object with the db, so that initchain hasn't been called
    89  	app2 := NewFBChainApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
    90  	_, _, err = app2.ExportAppStateAndValidators(false, []string{})
    91  	require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
    92  }
    93  
    94  func TestModuleManager(t *testing.T) {
    95  	db := dbm.NewMemDB()
    96  	app := NewFBChainApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
    97  
    98  	for moduleName, _ := range ModuleBasics {
    99  		if moduleName == upgrade.ModuleName {
   100  			continue
   101  		}
   102  		_, found := app.mm.Modules[moduleName]
   103  		require.True(t, found)
   104  	}
   105  }
   106  
   107  func TestProposalManager(t *testing.T) {
   108  	db := dbm.NewMemDB()
   109  	app := NewFBChainApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
   110  
   111  	require.True(t, app.GovKeeper.Router().HasRoute(params.RouterKey))
   112  	require.True(t, app.GovKeeper.Router().HasRoute(dex.RouterKey))
   113  	require.True(t, app.GovKeeper.Router().HasRoute(distr.RouterKey))
   114  	require.True(t, app.GovKeeper.Router().HasRoute(farm.RouterKey))
   115  
   116  	require.True(t, app.GovKeeper.ProposalHandlerRouter().HasRoute(params.RouterKey))
   117  	require.True(t, app.GovKeeper.ProposalHandlerRouter().HasRoute(dex.RouterKey))
   118  	require.True(t, app.GovKeeper.ProposalHandlerRouter().HasRoute(farm.RouterKey))
   119  }
   120  
   121  func TestFakeBlockTxSuite(t *testing.T) {
   122  	suite.Run(t, new(FakeBlockTxTestSuite))
   123  }
   124  
   125  type FakeBlockTxTestSuite struct {
   126  	suite.Suite
   127  	app   *FBChainApp
   128  	codec *codec.Codec
   129  
   130  	evmSenderPrivKey   ethsecp256k1.PrivKey
   131  	evmContractAddress ethcommon.Address
   132  
   133  	stdSenderPrivKey    ethsecp256k1.PrivKey
   134  	stdSenderAccAddress cosmossdk.AccAddress
   135  }
   136  
   137  func (suite *FakeBlockTxTestSuite) SetupTest() {
   138  	suite.app = Setup(checkTx, WithChainId(cosmosChainId))
   139  	suite.codec = suite.app.Codec()
   140  	params := evmtypes.DefaultParams()
   141  	params.EnableCreate = true
   142  	params.EnableCall = true
   143  	suite.app.EvmKeeper.SetParams(suite.Ctx(), params)
   144  }
   145  
   146  func (suite *FakeBlockTxTestSuite) Ctx() cosmossdk.Context {
   147  	return suite.app.BaseApp.GetDeliverStateCtx()
   148  }
   149  
   150  func (suite *FakeBlockTxTestSuite) beginFakeBlock() {
   151  	suite.evmSenderPrivKey, _ = ethsecp256k1.GenerateKey()
   152  	suite.evmContractAddress = ethcrypto.CreateAddress(ethcommon.HexToAddress(suite.evmSenderPrivKey.PubKey().Address().String()), 0)
   153  	accountEvm := suite.app.AccountKeeper.NewAccountWithAddress(suite.Ctx(), suite.evmSenderPrivKey.PubKey().Address().Bytes())
   154  	accountEvm.SetAccountNumber(accountNum)
   155  	accountEvm.SetCoins(cosmossdk.NewCoins(txCoin1000))
   156  	suite.app.AccountKeeper.SetAccount(suite.Ctx(), accountEvm)
   157  
   158  	suite.stdSenderPrivKey, _ = ethsecp256k1.GenerateKey()
   159  	suite.stdSenderAccAddress = cosmossdk.AccAddress(suite.stdSenderPrivKey.PubKey().Address())
   160  	accountStd := suite.app.AccountKeeper.NewAccountWithAddress(suite.Ctx(), suite.stdSenderAccAddress.Bytes())
   161  	accountStd.SetAccountNumber(accountNum)
   162  	accountStd.SetCoins(cosmossdk.NewCoins(txCoin1000))
   163  	suite.app.AccountKeeper.SetAccount(suite.Ctx(), accountStd)
   164  	err := suite.app.BankKeeper.SetCoins(suite.Ctx(), suite.stdSenderAccAddress, cosmossdk.NewCoins(txCoin1000))
   165  	suite.Require().NoError(err)
   166  
   167  	tendertypes.UnittestOnlySetMilestoneVenusHeight(blockHeight - 1)
   168  	global.SetGlobalHeight(blockHeight - 1)
   169  	suite.app.BeginBlocker(suite.Ctx(), abcitypes.RequestBeginBlock{Header: abcitypes.Header{Height: blockHeight}})
   170  }
   171  
   172  func (suite *FakeBlockTxTestSuite) endFakeBlock(totalGas int64) {
   173  	suite.app.EndBlocker(suite.Ctx(), abcitypes.RequestEndBlock{})
   174  	ctx := suite.Ctx()
   175  	blockActualGas := ctx.BlockGasMeter().GasConsumed()
   176  	suite.Require().True(cosmossdk.Gas(totalGas) == blockActualGas, "block gas expect %d, but %d ", totalGas, blockActualGas)
   177  	suite.Require().False(ctx.BlockGasMeter().IsPastLimit())
   178  	suite.Require().False(ctx.BlockGasMeter().IsOutOfGas())
   179  }
   180  
   181  func (suite *FakeBlockTxTestSuite) TestFakeBlockTx() {
   182  	testCases := []struct {
   183  		title      string
   184  		buildTx    func() []byte
   185  		expectCode uint32
   186  		expectGas  int64
   187  	}{
   188  		{
   189  			"create evm contract, success",
   190  			func() []byte {
   191  				//Create evm contract - Owner.sol
   192  				bytecode := ethcommon.FromHex("0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a36102c4806100dc6000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063893d20e814610058578063a6f9dae1146100a2575b600080fd5b6100606100e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e4600480360360208110156100b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061010f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f397f2733a89198bc7fed0764083694c5b828791f39ebcbc9e414bccef14b48064736f6c63430005100032")
   193  				tx := evmtypes.NewMsgEthereumTx(nonce0, nil, evmAmountZero, evmGasLimit, evmGasPrice, bytecode)
   194  				tx.Sign(evmChainID, suite.evmSenderPrivKey.ToECDSA())
   195  				txBytes, err := authclient.GetTxEncoder(nil, authclient.WithEthereumTx())(tx)
   196  				suite.Require().NoError(err)
   197  				return txBytes
   198  			},
   199  			0,
   200  			231649,
   201  		},
   202  		{
   203  			"create evm contract, failed",
   204  			func() []byte {
   205  				//Create evm contract - Owner.sol
   206  				bytecode := ethcommon.FromHex("0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424")
   207  				tx := evmtypes.NewMsgEthereumTx(nonce1, nil, evmAmountZero, evmGasLimit, evmGasPrice, bytecode)
   208  				tx.Sign(evmChainID, suite.evmSenderPrivKey.ToECDSA())
   209  				txBytes, err := authclient.GetTxEncoder(nil, authclient.WithEthereumTx())(tx)
   210  				suite.Require().NoError(err)
   211  				return txBytes
   212  			},
   213  			7, //invalid opcode: opcode 0xa6 not defined: failed to execute message; message index: 0
   214  			1000000,
   215  		},
   216  		{
   217  			"call evm contract with function changeOwner, success",
   218  			func() []byte {
   219  				// Call evm contract with function changeOwner, for saving data.
   220  				storeAddr := "0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424"
   221  				bytecode := ethcommon.FromHex(storeAddr)
   222  
   223  				tx := evmtypes.NewMsgEthereumTx(nonce2, &suite.evmContractAddress, evmAmountZero, evmGasLimit, evmGasPrice, bytecode)
   224  				tx.Sign(evmChainID, suite.evmSenderPrivKey.ToECDSA())
   225  
   226  				txEncoder := authclient.GetTxEncoder(nil, authclient.WithEthereumTx())
   227  				txBytes, _ := txEncoder(tx)
   228  				return txBytes
   229  			},
   230  			0,
   231  			30789,
   232  		},
   233  		{
   234  			"call evm contract with function changeOwner, failed",
   235  			func() []byte {
   236  				// call evm contract with function changeOwner, error with function bytecode
   237  				storeAddr := "0x11111111"
   238  				bytecode := ethcommon.FromHex(storeAddr)
   239  				tx := evmtypes.NewMsgEthereumTx(nonce3, &suite.evmContractAddress, evmAmountZero, evmGasLimit, evmGasPrice, bytecode)
   240  				tx.Sign(evmChainID, suite.evmSenderPrivKey.ToECDSA())
   241  				txBytes, _ := authclient.GetTxEncoder(nil, authclient.WithEthereumTx())(tx)
   242  				return txBytes
   243  			},
   244  			7, //execution reverted: failed to execute message; message index: 0
   245  			21195,
   246  		},
   247  		{
   248  			"send std tx for gov, success",
   249  			func() []byte {
   250  				content := gov.NewTextProposal("Test", "description")
   251  				newProposalMsg := gov.NewMsgSubmitProposal(content, sysCoins10, suite.stdSenderAccAddress)
   252  				depositMsg := gov.NewMsgDeposit(suite.stdSenderAccAddress, govProposalID1, sysCoins90)
   253  				msgs := []cosmossdk.Msg{newProposalMsg, depositMsg}
   254  				tx := newTestStdTx(msgs, []crypto.PrivKey{suite.stdSenderPrivKey}, []uint64{accountNum}, []uint64{nonce0}, txFees, memo)
   255  
   256  				txEncoder := authclient.GetTxEncoder(suite.codec)
   257  				txBytes, _ := txEncoder(tx)
   258  				return txBytes
   259  			},
   260  			0,
   261  			160134,
   262  		},
   263  		{
   264  			"send tx for gov with error fee, failed, do not write to block",
   265  			func() []byte {
   266  				content := gov.NewTextProposal("Test", "description")
   267  				newProposalMsg := gov.NewMsgSubmitProposal(content, sysCoins10, suite.stdSenderAccAddress)
   268  				depositMsg := gov.NewMsgDeposit(suite.stdSenderAccAddress, govProposalID1, sysCoins90)
   269  				msgs := []cosmossdk.Msg{newProposalMsg, depositMsg}
   270  				tx := newTestStdTx(msgs, []crypto.PrivKey{suite.stdSenderPrivKey}, []uint64{accountNum}, []uint64{nonce1}, txFeesError, memo)
   271  
   272  				txEncoder := authclient.GetTxEncoder(suite.codec)
   273  				txBytes, _ := txEncoder(tx)
   274  				return txBytes
   275  			},
   276  			5, //insufficient funds: insufficient funds to pay for fees; 890.000000000000000000fibo < 1000000000000000000.000000000000000000fibo
   277  			0,
   278  		},
   279  		{
   280  			"send tx for gov with repeat proposal id, failed",
   281  			func() []byte {
   282  				content := gov.NewTextProposal("Test", "description")
   283  				newProposalMsg := gov.NewMsgSubmitProposal(content, sysCoins10, suite.stdSenderAccAddress)
   284  				depositMsg := gov.NewMsgDeposit(suite.stdSenderAccAddress, govProposalID1, sysCoins90)
   285  				msgs := []cosmossdk.Msg{newProposalMsg, depositMsg}
   286  				tx := newTestStdTx(msgs, []crypto.PrivKey{suite.stdSenderPrivKey}, []uint64{accountNum}, []uint64{nonce1}, txFees, memo)
   287  
   288  				txEncoder := authclient.GetTxEncoder(suite.codec)
   289  				txBytes, _ := txEncoder(tx)
   290  				return txBytes
   291  			},
   292  			68007, //the status of proposal is not for this operation: failed to execute message; message index: 1
   293  			121944,
   294  		},
   295  		{
   296  			"send std tx for gov again with proposal id 2, success",
   297  			func() []byte {
   298  				content := gov.NewTextProposal("Test", "description")
   299  				newProposalMsg := gov.NewMsgSubmitProposal(content, sysCoins10, suite.stdSenderAccAddress)
   300  				depositMsg := gov.NewMsgDeposit(suite.stdSenderAccAddress, govProposalID2, sysCoins90)
   301  				msgs := []cosmossdk.Msg{newProposalMsg, depositMsg}
   302  				tx := newTestStdTx(msgs, []crypto.PrivKey{suite.stdSenderPrivKey}, []uint64{accountNum}, []uint64{nonce2}, txFees, memo)
   303  
   304  				txEncoder := authclient.GetTxEncoder(suite.codec)
   305  				txBytes, _ := txEncoder(tx)
   306  				return txBytes
   307  			},
   308  			0,
   309  			154723,
   310  		},
   311  	}
   312  
   313  	suite.SetupTest()
   314  	suite.beginFakeBlock()
   315  	totalGas := int64(0)
   316  	for _, tc := range testCases {
   317  		suite.Run(tc.title, func() {
   318  			txReal := suite.app.PreDeliverRealTx(tc.buildTx())
   319  			suite.Require().NotNil(txReal)
   320  			resp := suite.app.DeliverRealTx(txReal)
   321  			totalGas += resp.GasUsed
   322  			suite.Require().True(tc.expectCode == resp.Code, "%s, expect code:%d, but %d ", tc.title, tc.expectCode, resp.Code)
   323  			suite.Require().True(tc.expectGas == resp.GasUsed, "%s, expect gas:%d, but %d ", tc.title, tc.expectGas, resp.GasUsed)
   324  		})
   325  	}
   326  	suite.endFakeBlock(totalGas)
   327  }
   328  
   329  func newTestStdTx(msgs []cosmossdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee auth.StdFee, memo string) cosmossdk.Tx {
   330  	sigs := make([]authtypes.StdSignature, len(privs))
   331  	for i, priv := range privs {
   332  		sig, err := priv.Sign(authtypes.StdSignBytes(cosmosChainId, accNums[i], seqs[i], fee, msgs, memo))
   333  		if err != nil {
   334  			panic(err)
   335  		}
   336  		sigs[i] = authtypes.StdSignature{PubKey: priv.PubKey(), Signature: sig}
   337  	}
   338  
   339  	tx := auth.NewStdTx(msgs, fee, sigs, memo)
   340  	return tx
   341  }