github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/watcher/watcher_test.go (about) 1 package watcher_test 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "math/big" 7 "os" 8 "strings" 9 "testing" 10 "time" 11 12 ethcommon "github.com/ethereum/go-ethereum/common" 13 fbexchaincodec "github.com/fibonacci-chain/fbc/app/codec" 14 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/module" 15 16 ethcrypto "github.com/ethereum/go-ethereum/crypto" 17 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth" 19 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 20 21 "github.com/ethereum/go-ethereum/common" 22 ethcmn "github.com/ethereum/go-ethereum/common" 23 "github.com/fibonacci-chain/fbc/app" 24 "github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1" 25 ethermint "github.com/fibonacci-chain/fbc/app/types" 26 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 27 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 28 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1" 29 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/tmhash" 30 "github.com/fibonacci-chain/fbc/x/evm" 31 "github.com/fibonacci-chain/fbc/x/evm/types" 32 evmtypes "github.com/fibonacci-chain/fbc/x/evm/types" 33 "github.com/fibonacci-chain/fbc/x/evm/watcher" 34 jsoniter "github.com/json-iterator/go" 35 "github.com/spf13/viper" 36 "github.com/status-im/keycard-go/hexutils" 37 "github.com/stretchr/testify/require" 38 ) 39 40 var json = jsoniter.ConfigCompatibleWithStandardLibrary 41 42 type KV struct { 43 k []byte 44 v []byte 45 } 46 47 func calcHash(kvs []KV) []byte { 48 ha := tmhash.New() 49 // calc a hash 50 for _, kv := range kvs { 51 ha.Write(kv.k) 52 ha.Write(kv.v) 53 } 54 return ha.Sum(nil) 55 } 56 57 type WatcherTestSt struct { 58 ctx sdk.Context 59 app *app.FBChainApp 60 handler sdk.Handler 61 } 62 63 func setupTest() *WatcherTestSt { 64 w := &WatcherTestSt{} 65 checkTx := false 66 chain_id := "ethermint-3" 67 viper.Set(watcher.FlagFastQuery, true) 68 viper.Set(sdk.FlagDBBackend, "memdb") 69 viper.Set(watcher.FlagCheckWd, true) 70 71 w.app = app.Setup(checkTx) 72 w.ctx = w.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: chain_id, Time: time.Now().UTC()}) 73 w.ctx.SetDeliver() 74 w.handler = evm.NewHandler(w.app.EvmKeeper) 75 76 ethermint.SetChainId(chain_id) 77 78 params := types.DefaultParams() 79 params.EnableCreate = true 80 params.EnableCall = true 81 w.app.EvmKeeper.SetParams(w.ctx, params) 82 return w 83 } 84 85 func getDBKV(db *watcher.WatchStore) []KV { 86 var kvs []KV 87 it := db.Iterator(nil, nil) 88 for it.Valid() { 89 kvs = append(kvs, KV{it.Key(), it.Value()}) 90 it.Next() 91 } 92 return kvs 93 } 94 95 func flushDB(db *watcher.WatchStore) { 96 it := db.Iterator(nil, nil) 97 for it.Valid() { 98 db.Delete(it.Key()) 99 it.Next() 100 } 101 } 102 103 func checkWD(wdBytes []byte, w *WatcherTestSt) { 104 wd := watcher.WatchData{} 105 if err := wd.UnmarshalFromAmino(nil, wdBytes); err != nil { 106 return 107 } 108 keys := make([][]byte, len(wd.Batches)) 109 for i, b := range wd.Batches { 110 keys[i] = b.Key 111 } 112 w.app.EvmKeeper.Watcher.CheckWatchDB(keys, "producer--test") 113 } 114 115 func testWatchData(t *testing.T, w *WatcherTestSt) { 116 // produce WatchData 117 w.app.EvmKeeper.Watcher.Commit() 118 time.Sleep(time.Millisecond) 119 120 // get WatchData 121 wdFunc := w.app.EvmKeeper.Watcher.CreateWatchDataGenerator() 122 wd, err := wdFunc() 123 require.Nil(t, err) 124 require.NotEmpty(t, wd) 125 126 store := watcher.InstanceOfWatchStore() 127 pWd := getDBKV(store) 128 checkWD(wd, w) 129 flushDB(store) 130 131 // use WatchData 132 wData, err := w.app.EvmKeeper.Watcher.UnmarshalWatchData(wd) 133 require.Nil(t, err) 134 w.app.EvmKeeper.Watcher.ApplyWatchData(wData) 135 time.Sleep(time.Millisecond) 136 137 cWd := getDBKV(store) 138 139 // compare db_kv of producer and consumer 140 require.Equal(t, pWd, cWd, "compare len:", "pwd:", len(pWd), "cwd", len(cWd)) 141 pHash := calcHash(pWd) 142 cHash := calcHash(cWd) 143 require.NotEmpty(t, pHash) 144 require.NotEmpty(t, cHash) 145 require.Equal(t, pHash, cHash) 146 147 flushDB(store) 148 } 149 150 func TestHandleMsgEthereumTx(t *testing.T) { 151 w := setupTest() 152 privkey, err := ethsecp256k1.GenerateKey() 153 require.NoError(t, err) 154 sender := ethcmn.HexToAddress(privkey.PubKey().Address().String()) 155 156 var tx *types.MsgEthereumTx 157 158 testCases := []struct { 159 msg string 160 malleate func() 161 expPass bool 162 }{ 163 { 164 "passed", 165 func() { 166 w.app.EvmKeeper.SetBalance(w.ctx, sender, big.NewInt(100)) 167 tx = types.NewMsgEthereumTx(0, &sender, big.NewInt(100), 3000000, big.NewInt(1), nil) 168 169 // parse context chain ID to big.Int 170 chainID, err := ethermint.ParseChainID(w.ctx.ChainID()) 171 require.NoError(t, err) 172 173 // sign transaction 174 err = tx.Sign(chainID, privkey.ToECDSA()) 175 require.NoError(t, err) 176 }, 177 true, 178 }, 179 } 180 181 for _, tc := range testCases { 182 t.Run(tc.msg, func(t *testing.T) { 183 w = setupTest() // reset 184 //nolint 185 tc.malleate() 186 w.ctx.SetGasMeter(sdk.NewInfiniteGasMeter()) 187 res, err := w.handler(w.ctx, tx) 188 189 //nolint 190 if tc.expPass { 191 require.NoError(t, err) 192 require.NotNil(t, res) 193 var expectedConsumedGas uint64 = 21000 194 require.EqualValues(t, expectedConsumedGas, w.ctx.GasMeter().GasConsumed()) 195 } else { 196 require.Error(t, err) 197 require.Nil(t, res) 198 } 199 200 testWatchData(t, w) 201 }) 202 } 203 } 204 205 func TestMsgEthereumTxByWatcher(t *testing.T) { 206 var ( 207 tx *types.MsgEthereumTx 208 from = ethcmn.BytesToAddress(secp256k1.GenPrivKey().PubKey().Address()) 209 to = ethcmn.BytesToAddress(secp256k1.GenPrivKey().PubKey().Address()) 210 ) 211 w := setupTest() 212 testCases := []struct { 213 msg string 214 malleate func() 215 expPass bool 216 }{ 217 { 218 "passed", 219 func() { 220 tx = types.NewMsgEthereumTx(0, &to, big.NewInt(1), 100000, big.NewInt(2), []byte("test")) 221 w.app.EvmKeeper.SetBalance(w.ctx, ethcmn.BytesToAddress(from.Bytes()), big.NewInt(100)) 222 }, 223 true, 224 }, 225 } 226 227 for _, tc := range testCases { 228 t.Run("", func(t *testing.T) { 229 w = setupTest() // reset 230 //nolint 231 tc.malleate() 232 w.ctx.SetIsCheckTx(true) 233 w.ctx.SetGasMeter(sdk.NewInfiniteGasMeter()) 234 w.ctx.SetFrom(from.String()) 235 res, err := w.handler(w.ctx, tx) 236 237 //nolint 238 if tc.expPass { 239 require.NoError(t, err) 240 require.NotNil(t, res) 241 var expectedConsumedGas uint64 = 21064 242 require.EqualValues(t, expectedConsumedGas, w.ctx.GasMeter().GasConsumed()) 243 } else { 244 require.Error(t, err) 245 require.Nil(t, res) 246 } 247 248 testWatchData(t, w) 249 }) 250 } 251 } 252 253 func TestDeployAndCallContract(t *testing.T) { 254 w := setupTest() 255 256 // Deploy contract - Owner.sol 257 gasLimit := uint64(100000000) 258 gasPrice := big.NewInt(10000) 259 260 priv, err := ethsecp256k1.GenerateKey() 261 require.NoError(t, err, "failed to create key") 262 263 sender := ethcmn.HexToAddress(priv.PubKey().Address().String()) 264 w.app.EvmKeeper.SetBalance(w.ctx, sender, big.NewInt(100)) 265 266 bytecode := common.FromHex("0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a36102c4806100dc6000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063893d20e814610058578063a6f9dae1146100a2575b600080fd5b6100606100e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e4600480360360208110156100b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061010f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f397f2733a89198bc7fed0764083694c5b828791f39ebcbc9e414bccef14b48064736f6c63430005100032") 267 tx := types.NewMsgEthereumTx(1, &sender, big.NewInt(0), gasLimit, gasPrice, bytecode) 268 tx.Sign(big.NewInt(3), priv.ToECDSA()) 269 require.NoError(t, err) 270 271 result, err := w.handler(w.ctx, tx) 272 require.NoError(t, err, "failed to handle eth tx msg") 273 274 resultData, err := types.DecodeResultData(result.Data) 275 require.NoError(t, err, "failed to decode result data") 276 277 testWatchData(t, w) 278 279 // store - changeOwner 280 gasLimit = uint64(100000000000) 281 gasPrice = big.NewInt(100) 282 receiver := common.HexToAddress(resultData.ContractAddress.String()) 283 284 storeAddr := "0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424" 285 bytecode = common.FromHex(storeAddr) 286 tx = types.NewMsgEthereumTx(2, &receiver, big.NewInt(0), gasLimit, gasPrice, bytecode) 287 tx.Sign(big.NewInt(3), priv.ToECDSA()) 288 require.NoError(t, err) 289 290 result, err = w.handler(w.ctx, tx) 291 require.NoError(t, err, "failed to handle eth tx msg") 292 293 resultData, err = types.DecodeResultData(result.Data) 294 require.NoError(t, err, "failed to decode result data") 295 296 testWatchData(t, w) 297 298 // query - getOwner 299 bytecode = common.FromHex("0x893d20e8") 300 tx = types.NewMsgEthereumTx(2, &receiver, big.NewInt(0), gasLimit, gasPrice, bytecode) 301 tx.Sign(big.NewInt(3), priv.ToECDSA()) 302 require.NoError(t, err) 303 304 result, err = w.handler(w.ctx, tx) 305 require.NoError(t, err, "failed to handle eth tx msg") 306 307 resultData, err = types.DecodeResultData(result.Data) 308 require.NoError(t, err, "failed to decode result data") 309 310 getAddr := strings.ToLower(hexutils.BytesToHex(resultData.Ret)) 311 require.Equal(t, true, strings.HasSuffix(storeAddr, getAddr), "Fail to query the address") 312 313 testWatchData(t, w) 314 } 315 316 type mockDuplicateAccount struct { 317 *auth.BaseAccount 318 Addr byte 319 Seq byte 320 } 321 322 func (a *mockDuplicateAccount) GetAddress() sdk.AccAddress { 323 return []byte{a.Addr} 324 } 325 326 func newMockAccount(byteAddr, seq byte) *mockDuplicateAccount { 327 ret := &mockDuplicateAccount{Addr: byteAddr, Seq: seq} 328 pubkey := secp256k1.GenPrivKey().PubKey() 329 addr := sdk.AccAddress(pubkey.Address()) 330 baseAcc := auth.NewBaseAccount(addr, nil, pubkey, 0, 0) 331 ret.BaseAccount = baseAcc 332 return ret 333 } 334 335 func TestDuplicateAddress(t *testing.T) { 336 accAdds := make([]*sdk.AccAddress, 0) 337 for i := 0; i < 10; i++ { 338 adds := hex.EncodeToString([]byte(fmt.Sprintf("addr-%d", i))) 339 a, _ := sdk.AccAddressFromHex(adds) 340 accAdds = append(accAdds, &a) 341 } 342 adds := hex.EncodeToString([]byte(fmt.Sprintf("addr-%d", 1))) 343 a, _ := sdk.AccAddressFromHex(adds) 344 accAdds = append(accAdds, &a) 345 filterM := make(map[string]struct{}) 346 count := 0 347 for _, add := range accAdds { 348 _, exist := filterM[string(add.Bytes())] 349 if exist { 350 count++ 351 continue 352 } 353 filterM[string(add.Bytes())] = struct{}{} 354 } 355 require.Equal(t, 1, count) 356 } 357 358 func TestDuplicateWatchMessage(t *testing.T) { 359 w := setupTest() 360 w.app.EvmKeeper.Watcher.NewHeight(1, common.Hash{}, abci.Header{Height: 1}) 361 // init store 362 store := watcher.InstanceOfWatchStore() 363 flushDB(store) 364 privKey := secp256k1.GenPrivKey() 365 pubKey := privKey.PubKey() 366 addr := sdk.AccAddress(pubKey.Address()) 367 368 balance := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))) 369 a1 := ðermint.EthAccount{ 370 BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1), 371 CodeHash: ethcrypto.Keccak256(nil), 372 } 373 w.app.EvmKeeper.Watcher.SaveAccount(a1) 374 a2 := ðermint.EthAccount{ 375 BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 2), 376 CodeHash: ethcrypto.Keccak256(nil), 377 } 378 w.app.EvmKeeper.Watcher.SaveAccount(a2) 379 w.app.EvmKeeper.Watcher.Commit() 380 time.Sleep(time.Millisecond) 381 pWd := getDBKV(store) 382 require.Equal(t, 1, len(pWd)) 383 } 384 385 func TestWriteLatestMsg(t *testing.T) { 386 viper.Set(watcher.FlagFastQuery, true) 387 viper.Set(sdk.FlagDBBackend, "memdb") 388 w := watcher.NewWatcher(log.NewTMLogger(os.Stdout)) 389 w.SetWatchDataManager() 390 w.NewHeight(1, common.Hash{}, abci.Header{Height: 1}) 391 // init store 392 store := watcher.InstanceOfWatchStore() 393 flushDB(store) 394 395 privKey := secp256k1.GenPrivKey() 396 pubKey := privKey.PubKey() 397 addr := sdk.AccAddress(pubKey.Address()) 398 399 balance := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))) 400 a1 := ðermint.EthAccount{ 401 BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1), 402 CodeHash: ethcrypto.Keccak256(nil), 403 } 404 a11 := ðermint.EthAccount{ 405 BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 2), 406 CodeHash: ethcrypto.Keccak256(nil), 407 } 408 a111 := ðermint.EthAccount{ 409 BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 3), 410 CodeHash: ethcrypto.Keccak256(nil), 411 } 412 413 w.SaveAccount(a1) 414 w.SaveAccount(a11) 415 w.SaveAccount(a111) 416 // waiting 1 second for initializing jobChan 417 time.Sleep(time.Millisecond) 418 w.Commit() 419 time.Sleep(time.Millisecond) 420 pWd := getDBKV(store) 421 require.Equal(t, 1, len(pWd)) 422 423 m := watcher.NewMsgAccount(a1) 424 v, err := store.Get(m.GetKey()) 425 require.NoError(t, err) 426 has := store.Has(m.GetKey()) 427 require.Equal(t, has, true) 428 ethAccount, err := watcher.DecodeAccount(v) 429 require.NoError(t, err) 430 //test decode error 431 vv := v[:1] 432 _, err = watcher.DecodeAccount(vv) 433 require.Error(t, err) 434 require.Equal(t, uint64(3), ethAccount.GetSequence()) 435 p := store.GetEvmParams() 436 expectedParams := evmtypes.Params{ 437 EnableCreate: false, 438 EnableCall: false, 439 EnableContractDeploymentWhitelist: false, 440 EnableContractBlockedList: false, 441 MaxGasLimitPerTx: 30000000, 442 } 443 err = ParamsDeepEqual(expectedParams, p) 444 require.NoError(t, err) 445 expectedParams2 := evmtypes.Params{ 446 EnableCreate: true, 447 EnableCall: true, 448 EnableContractDeploymentWhitelist: true, 449 EnableContractBlockedList: true, 450 MaxGasLimitPerTx: 20000000, 451 } 452 store.SetEvmParams(expectedParams2) 453 p = store.GetEvmParams() 454 err = ParamsDeepEqual(p, expectedParams2) 455 require.NoError(t, err) 456 } 457 458 func ParamsDeepEqual(src, dst evmtypes.Params) error { 459 if src.EnableCreate != dst.EnableCreate || 460 src.EnableCall != dst.EnableCall || 461 src.EnableContractDeploymentWhitelist != dst.EnableContractDeploymentWhitelist || 462 src.EnableContractBlockedList != dst.EnableContractBlockedList { 463 return fmt.Errorf("params not fit") 464 } 465 return nil 466 } 467 468 func TestDeliverRealTx(t *testing.T) { 469 w := setupTest() 470 bytecode := ethcommon.FromHex("0x12") 471 tx := evmtypes.NewMsgEthereumTx(0, nil, big.NewInt(0), uint64(1000000), big.NewInt(10000), bytecode) 472 privKey, _ := ethsecp256k1.GenerateKey() 473 err := tx.Sign(big.NewInt(3), privKey.ToECDSA()) 474 require.NoError(t, err) 475 codecProxy, _ := fbexchaincodec.MakeCodecSuit(module.NewBasicManager()) 476 w.app.EvmKeeper.Watcher.RecordTxAndFailedReceipt(tx, nil, evm.TxDecoder(codecProxy)) 477 } 478 479 func TestBaiscDBOpt(t *testing.T) { 480 viper.Set(watcher.FlagFastQuery, true) 481 viper.Set(sdk.FlagDBBackend, "memdb") 482 store := watcher.InstanceOfWatchStore() 483 store.Set([]byte("test01"), []byte("value01")) 484 v, err := store.Get([]byte("test01")) 485 require.NoError(t, err) 486 require.Equal(t, v, []byte("value01")) 487 v, err = store.Get([]byte("test no key")) 488 require.Equal(t, v, []byte(nil)) 489 require.NoError(t, err) 490 r, err := store.GetUnsafe([]byte("test01"), func(value []byte) (interface{}, error) { 491 return nil, nil 492 }) 493 require.Equal(t, r, nil) 494 require.NoError(t, err) 495 }