github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/baseapp/baseapp_paralled_test.go (about)

     1  package baseapp_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"math/big"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/ethereum/go-ethereum/accounts/abi"
    10  	ethcmn "github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/rlp"
    12  	"github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1"
    13  	types3 "github.com/fibonacci-chain/fbc/app/types"
    14  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/simapp/helpers"
    15  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    16  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    17  	authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
    18  	simapp2 "github.com/fibonacci-chain/fbc/libs/ibc-go/testing/simapp"
    19  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    20  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    21  	"github.com/fibonacci-chain/fbc/x/evm/types"
    22  	types4 "github.com/fibonacci-chain/fbc/x/token/types"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  type Env struct {
    27  	priv []ethsecp256k1.PrivKey
    28  	addr []sdk.AccAddress
    29  }
    30  type Chain struct {
    31  	app          *simapp2.SimApp
    32  	priv         []ethsecp256k1.PrivKey
    33  	addr         []sdk.AccAddress
    34  	acc          []*types3.EthAccount
    35  	seq          []uint64
    36  	num          []uint64
    37  	chainIdStr   string
    38  	chainIdInt   *big.Int
    39  	ContractAddr []byte
    40  }
    41  
    42  func NewChain(env *Env) *Chain {
    43  	types2.UnittestOnlySetMilestoneVenusHeight(-1)
    44  	types2.UnittestOnlySetMilestoneVenus1Height(-1)
    45  	chain := new(Chain)
    46  	chain.acc = make([]*types3.EthAccount, 10)
    47  	chain.priv = make([]ethsecp256k1.PrivKey, 10)
    48  	chain.addr = make([]sdk.AccAddress, 10)
    49  	chain.seq = make([]uint64, 10)
    50  	chain.num = make([]uint64, 10)
    51  	genAccs := []authexported.GenesisAccount{}
    52  	for i := 0; i < 10; i++ {
    53  		chain.acc[i] = &types3.EthAccount{
    54  			BaseAccount: &auth.BaseAccount{
    55  				Address: env.addr[i],
    56  				Coins:   sdk.Coins{sdk.NewInt64Coin("fibo", 1000000)},
    57  			},
    58  			//CodeHash: []byte{1, 2},
    59  		}
    60  		genAccs = append(genAccs, chain.acc[i])
    61  		chain.priv[i] = env.priv[i]
    62  		chain.addr[i] = env.addr[i]
    63  		chain.seq[i] = 0
    64  		chain.num[i] = uint64(i)
    65  	}
    66  	chain.chainIdStr = "ethermint-3"
    67  	chain.chainIdInt = big.NewInt(3)
    68  
    69  	chain.app = simapp2.SetupWithGenesisAccounts(genAccs, sdk.NewDecCoins(sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(1000000, 0))))
    70  	//header := abci.Header{Height: app.LastBlockHeight() + 1, ChainID: chainIdStr}
    71  
    72  	chain.app.BaseApp.Commit(abci.RequestCommit{})
    73  	return chain
    74  }
    75  
    76  func createEthTx(t *testing.T, chain *Chain, i int) []byte {
    77  	amount, gasPrice, gasLimit := int64(1024), int64(2048), uint64(100000)
    78  	addrTo := ethcmn.BytesToAddress(chain.priv[i+1].PubKey().Address().Bytes())
    79  	msg := types.NewMsgEthereumTx(chain.seq[i], &addrTo, big.NewInt(amount), gasLimit, big.NewInt(gasPrice), []byte("test"))
    80  	chain.seq[i]++
    81  	err := msg.Sign(chain.chainIdInt, chain.priv[i].ToECDSA())
    82  	require.NoError(t, err)
    83  	rawtx, err := rlp.EncodeToBytes(&msg)
    84  	require.NoError(t, err)
    85  
    86  	return rawtx
    87  }
    88  
    89  // contract Storage {
    90  // uint256 number;
    91  // /**
    92  // * @dev Store value in variable
    93  // * @param num value to store
    94  // */
    95  // function store(uint256 num) public {
    96  // number = num;
    97  // }
    98  // function add() public {
    99  // number += 1;
   100  // }
   101  // /**
   102  // * @dev Return value
   103  // * @return value of 'number'
   104  // */
   105  // function retrieve() public view returns (uint256){
   106  // return number;
   107  // }
   108  // }
   109  var abiStr = `[{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"retrieve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}]`
   110  
   111  func deployContract(t *testing.T, chain *Chain, i int) []byte {
   112  	// Deploy contract - Owner.sol
   113  	gasLimit := uint64(10000000000000)
   114  	gasPrice := big.NewInt(10000)
   115  
   116  	sender := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String())
   117  
   118  	bytecode := ethcmn.FromHex("608060405234801561001057600080fd5b50610217806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631003e2d2146100465780632e64cec1146100625780636057361d14610080575b600080fd5b610060600480360381019061005b9190610105565b61009c565b005b61006a6100b7565b6040516100779190610141565b60405180910390f35b61009a60048036038101906100959190610105565b6100c0565b005b806000808282546100ad919061018b565b9250508190555050565b60008054905090565b8060008190555050565b600080fd5b6000819050919050565b6100e2816100cf565b81146100ed57600080fd5b50565b6000813590506100ff816100d9565b92915050565b60006020828403121561011b5761011a6100ca565b5b6000610129848285016100f0565b91505092915050565b61013b816100cf565b82525050565b60006020820190506101566000830184610132565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610196826100cf565b91506101a1836100cf565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101d6576101d561015c565b5b82820190509291505056fea2646970667358221220318e29d6b4806f219eedd0cc861e82c13e28eb7f42161f2c780dc539b0e32b4e64736f6c634300080a0033")
   119  	msg := types.NewMsgEthereumTx(chain.seq[i], &sender, big.NewInt(0), gasLimit, gasPrice, bytecode)
   120  	err := msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA())
   121  	require.NoError(t, err)
   122  	chain.seq[i]++
   123  	rawTx, err := rlp.EncodeToBytes(&msg)
   124  	require.NoError(t, err)
   125  	return rawTx
   126  }
   127  
   128  var contractJson = `{"abi":[{"inputs":[],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"retrieve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}],"bin":"608060405234801561001057600080fd5b50610205806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632e64cec1146100465780634f2be91f146100645780636057361d1461006e575b600080fd5b61004e61008a565b60405161005b91906100d1565b60405180910390f35b61006c610093565b005b6100886004803603810190610083919061011d565b6100ae565b005b60008054905090565b60016000808282546100a59190610179565b92505081905550565b8060008190555050565b6000819050919050565b6100cb816100b8565b82525050565b60006020820190506100e660008301846100c2565b92915050565b600080fd5b6100fa816100b8565b811461010557600080fd5b50565b600081359050610117816100f1565b92915050565b600060208284031215610133576101326100ec565b5b600061014184828501610108565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610184826100b8565b915061018f836100b8565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101c4576101c361014a565b5b82820190509291505056fea2646970667358221220742b7232e733bee3592cb9e558bdae3fbd0006bcbdba76abc47b6020744037b364736f6c634300080a0033"}`
   129  
   130  type CompiledContract struct {
   131  	ABI abi.ABI
   132  	Bin string
   133  }
   134  
   135  func UnmarshalContract(t *testing.T) *CompiledContract {
   136  	cc := new(CompiledContract)
   137  	err := json.Unmarshal([]byte(contractJson), cc)
   138  	require.NoError(t, err)
   139  	return cc
   140  }
   141  
   142  func callContract(t *testing.T, chain *Chain, i int) []byte {
   143  	gasLimit := uint64(10000000000000)
   144  	gasPrice := big.NewInt(10000)
   145  	//to := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String())
   146  	to := ethcmn.BytesToAddress(chain.ContractAddr)
   147  	cc := UnmarshalContract(t)
   148  	data, err := cc.ABI.Pack("add")
   149  	require.NoError(t, err)
   150  	msg := types.NewMsgEthereumTx(chain.seq[i], &to, big.NewInt(0), gasLimit, gasPrice, data)
   151  	err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA())
   152  	require.NoError(t, err)
   153  	chain.seq[i]++
   154  	rawTx, err := rlp.EncodeToBytes(&msg)
   155  	require.NoError(t, err)
   156  	return rawTx
   157  }
   158  
   159  func createCosmosTx(t *testing.T, chain *Chain, i int) []byte {
   160  	msg := types4.NewMsgTokenSend(chain.addr[i], chain.addr[i+1], sdk.Coins{sdk.NewInt64Coin("fibo", 10)})
   161  
   162  	tx := helpers.GenTx(
   163  		[]sdk.Msg{msg},
   164  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)},
   165  		helpers.DefaultGenTxGas,
   166  		chain.chainIdStr,
   167  		[]uint64{chain.num[i]},
   168  		[]uint64{chain.seq[i]},
   169  		chain.priv[i],
   170  	)
   171  	chain.seq[i]++
   172  
   173  	txBytes, err := chain.app.Codec().MarshalBinaryLengthPrefixed(tx)
   174  	require.Nil(t, err)
   175  	return txBytes
   176  }
   177  
   178  func runtxs(chain *Chain, rawTxs [][]byte, isParalle bool) []*abci.ResponseDeliverTx {
   179  	header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr}
   180  	chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header})
   181  	ret := []*abci.ResponseDeliverTx{}
   182  	if isParalle {
   183  		ret = chain.app.BaseApp.ParallelTxs(rawTxs, false)
   184  	} else {
   185  		for _, tx := range rawTxs {
   186  			r := chain.app.BaseApp.DeliverTx(abci.RequestDeliverTx{Tx: tx})
   187  			ret = append(ret, &r)
   188  		}
   189  	}
   190  	chain.app.BaseApp.EndBlock(abci.RequestEndBlock{})
   191  	chain.app.BaseApp.Commit(abci.RequestCommit{})
   192  
   193  	return ret
   194  }
   195  
   196  func DeployContractAndGetContractAddress(t *testing.T, chain *Chain) {
   197  	rawTxs := [][]byte{}
   198  	rawTxs = append(rawTxs, deployContract(t, chain, 0))
   199  	r := runtxs(chain, rawTxs, false)
   200  
   201  	for _, e := range r[0].Events {
   202  		for _, v := range e.Attributes {
   203  			if string(v.Key) == "recipient" {
   204  				chain.ContractAddr = v.Value
   205  			}
   206  		}
   207  	}
   208  }
   209  
   210  func TestParalledTxs(t *testing.T) {
   211  	env := new(Env)
   212  	accountNum := 10
   213  	env.priv = make([]ethsecp256k1.PrivKey, 10)
   214  	env.addr = make([]sdk.AccAddress, 10)
   215  	for i := 0; i < accountNum; i++ {
   216  		priv, _ := ethsecp256k1.GenerateKey()
   217  		addr := sdk.AccAddress(priv.PubKey().Address())
   218  		env.priv[i] = priv
   219  		env.addr[i] = addr
   220  	}
   221  
   222  	chainA, chainB := NewChain(env), NewChain(env)
   223  	//deploy contract on chainA and chainB
   224  	DeployContractAndGetContractAddress(t, chainA)
   225  	DeployContractAndGetContractAddress(t, chainB)
   226  
   227  	testCases := []struct {
   228  		name     string
   229  		malleate func(t *testing.T, chain *Chain, isParallel bool) ([]byte, []byte)
   230  	}{
   231  		{
   232  			"five txs one group:a->b b->c c->d d->e e->f",
   233  			func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) {
   234  
   235  				rawTxs := [][]byte{}
   236  				for i := 0; i < 5; i++ {
   237  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   238  				}
   239  
   240  				header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr}
   241  				chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header})
   242  				ret := runtxs(chain, rawTxs, isParalled)
   243  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   244  			},
   245  		},
   246  		{
   247  			"five txs two group, no conflict:a->b b->c / d->e e->f f->g",
   248  			func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) {
   249  				rawTxs := [][]byte{}
   250  				//one group 3txs
   251  				for i := 0; i < 3; i++ {
   252  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   253  				}
   254  				//one group 2txs
   255  				for i := 8; i > 6; i-- {
   256  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   257  				}
   258  				ret := runtxs(chain, rawTxs, isParalled)
   259  
   260  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   261  			},
   262  		},
   263  		{
   264  			"five txs two group, has conflict",
   265  			func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) {
   266  				rawTxs := [][]byte{}
   267  
   268  				//one group 3txs
   269  				for i := 0; i < 3; i++ {
   270  					rawTxs = append(rawTxs, callContract(t, chain, i))
   271  				}
   272  				////one group 2txs
   273  				for i := 8; i > 6; i-- {
   274  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   275  				}
   276  				ret := runtxs(chain, rawTxs, isParalled)
   277  
   278  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   279  			},
   280  		},
   281  		{
   282  			"five txs one group with cosmos tx",
   283  			func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) {
   284  				rawTxs := [][]byte{}
   285  				//one group 3txs
   286  				for i := 0; i < 2; i++ {
   287  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   288  				}
   289  				//cosmostx
   290  				rawTxs = append(rawTxs, createCosmosTx(t, chain, 2))
   291  				//one group 2txs
   292  				for i := 3; i < 5; i++ {
   293  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   294  				}
   295  				ret := runtxs(chain, rawTxs, isParalled)
   296  
   297  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   298  			},
   299  		},
   300  		{
   301  			"five txs two group, no conflict with cosmos tx",
   302  			func(t *testing.T, chain *Chain, isParalle bool) ([]byte, []byte) {
   303  				rawTxs := [][]byte{}
   304  				//one group 3txs(2eth and 1 cosmos)
   305  				for i := 0; i < 2; i++ {
   306  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   307  				}
   308  				//cosmos tx
   309  				rawTxs = append(rawTxs, createCosmosTx(t, chain, 2))
   310  				//one group 2txs
   311  				for i := 8; i > 6; i-- {
   312  					rawTxs = append(rawTxs, createEthTx(t, chain, i))
   313  				}
   314  				ret := runtxs(chain, rawTxs, isParalle)
   315  
   316  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   317  			},
   318  		},
   319  		{
   320  			"five txs two group, has conflict with cosmos tx",
   321  			func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) {
   322  				rawTxs := [][]byte{}
   323  
   324  				//one group 3txs:2 evm tx with conflict, one cosmos tx
   325  				for i := 0; i < 2; i++ {
   326  					rawTxs = append(rawTxs, callContract(t, chain, i))
   327  				}
   328  				rawTxs = append(rawTxs, createCosmosTx(t, chain, 2))
   329  				////one group 2txs
   330  				for i := 8; i > 6; i-- {
   331  					rawTxs = append(rawTxs, createCosmosTx(t, chain, i))
   332  				}
   333  				ret := runtxs(chain, rawTxs, isParalled)
   334  
   335  				return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash
   336  			},
   337  		},
   338  	}
   339  	for _, tc := range testCases {
   340  		resultHashA, appHashA := tc.malleate(t, chainA, true)
   341  		resultHashB, appHashB := tc.malleate(t, chainB, false)
   342  		require.True(t, reflect.DeepEqual(resultHashA, resultHashB))
   343  		require.True(t, reflect.DeepEqual(appHashA, appHashB))
   344  	}
   345  
   346  }
   347  
   348  func resultHash(txs []*abci.ResponseDeliverTx) []byte {
   349  	results := types2.NewResults(txs)
   350  	return results.Hash()
   351  }