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 := &ethermint.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 := &ethermint.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 := &ethermint.EthAccount{
   401  		BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1),
   402  		CodeHash:    ethcrypto.Keccak256(nil),
   403  	}
   404  	a11 := &ethermint.EthAccount{
   405  		BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 2),
   406  		CodeHash:    ethcrypto.Keccak256(nil),
   407  	}
   408  	a111 := &ethermint.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  }