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 }