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 }