diff --git a/Makefile b/Makefile index c377d6117f..42ae24bcbc 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ IGNORE_CHECK_GO=false install_rocksdb_version:=$(ROCKSDB_VERSION) -Version=v1.7.7 +Version=v1.7.9 CosmosSDK=v0.39.2 Tendermint=v0.33.9 Iavl=v0.14.3 diff --git a/app/app.go b/app/app.go index 12b75d29d4..08e09ef0a5 100644 --- a/app/app.go +++ b/app/app.go @@ -2,6 +2,7 @@ package app import ( "fmt" + "github.com/okex/exchain/libs/cosmos-sdk/client/flags" "io" "os" "runtime/debug" @@ -958,6 +959,8 @@ func NewAccNonceHandler(ak auth.AccountKeeper) sdk.AccNonceHandler { } func PreRun(ctx *server.Context, cmd *cobra.Command) error { + prepareSnapshotDataIfNeed(viper.GetString(server.FlagStartFromSnapshot), viper.GetString(flags.FlagHome), ctx.Logger) + // check start flag conflicts err := sanity.CheckStart() if err != nil { diff --git a/app/app_parallel.go b/app/app_parallel.go index 34cd247fa4..eb3bba5337 100644 --- a/app/app_parallel.go +++ b/app/app_parallel.go @@ -117,15 +117,17 @@ func getTxFeeHandler() sdk.GetTxFeeHandler { // getTxFeeAndFromHandler get tx fee and from func getTxFeeAndFromHandler(ek appante.EVMKeeper) sdk.GetTxFeeAndFromHandler { - return func(ctx sdk.Context, tx sdk.Tx) (fee sdk.Coins, isEvm bool, isE2C bool, from string, to string, err error, supportPara bool) { + return func(ctx sdk.Context, tx sdk.Tx) (fee sdk.Coins, isEvm bool, needUpdateTXCounter bool, from string, to string, err error, supportPara bool) { if evmTx, ok := tx.(*evmtypes.MsgEthereumTx); ok { isEvm = true supportPara = true if appante.IsE2CTx(ek, &ctx, evmTx) { - isE2C = true + if tmtypes.HigherThanVenus6(ctx.BlockHeight()) { + needUpdateTXCounter = true + } // E2C will include cosmos Msg in the Payload. // Sometimes, this Msg do not support parallel execution. - if !isParaSupportedE2CMsg(evmTx.Data.Payload) { + if !tmtypes.HigherThanVenus6(ctx.BlockHeight()) || !isParaSupportedE2CMsg(evmTx.Data.Payload) { supportPara = false } } @@ -143,11 +145,18 @@ func getTxFeeAndFromHandler(ek appante.EVMKeeper) sdk.GetTxFeeAndFromHandler { } } else if feeTx, ok := tx.(authante.FeeTx); ok { fee = feeTx.GetFee() - if stdTx, ok := tx.(*auth.StdTx); ok && len(stdTx.Msgs) == 1 { // only support one message - if msg, ok := stdTx.Msgs[0].(interface{ CalFromAndToForPara() (string, string) }); ok { - from, to = msg.CalFromAndToForPara() - if tmtypes.HigherThanVenus6(ctx.BlockHeight()) { - supportPara = true + if tx.GetType() == sdk.StdTxType { + if tmtypes.HigherThanEarth(ctx.BlockHeight()) { + needUpdateTXCounter = true + } + txMsgs := tx.GetMsgs() + // only support one message + if len(txMsgs) == 1 { + if msg, ok := txMsgs[0].(interface{ CalFromAndToForPara() (string, string) }); ok { + from, to = msg.CalFromAndToForPara() + if tmtypes.HigherThanVenus6(ctx.BlockHeight()) { + supportPara = true + } } } } diff --git a/app/app_parallel_test.go b/app/app_parallel_test.go new file mode 100644 index 0000000000..f207579c90 --- /dev/null +++ b/app/app_parallel_test.go @@ -0,0 +1,1218 @@ +package app_test + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "reflect" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + ethcmn "github.com/ethereum/go-ethereum/common" + ethcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/require" + + "github.com/okex/exchain/app" + "github.com/okex/exchain/app/crypto/ethsecp256k1" + apptypes "github.com/okex/exchain/app/types" + "github.com/okex/exchain/libs/cosmos-sdk/codec" + "github.com/okex/exchain/libs/cosmos-sdk/simapp/helpers" + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + "github.com/okex/exchain/libs/cosmos-sdk/x/auth" + authexported "github.com/okex/exchain/libs/cosmos-sdk/x/auth/exported" + abci "github.com/okex/exchain/libs/tendermint/abci/types" + tmtypes "github.com/okex/exchain/libs/tendermint/types" + evmtypes "github.com/okex/exchain/x/evm/types" + tokentypes "github.com/okex/exchain/x/token/types" + wasmtypes "github.com/okex/exchain/x/wasm/types" +) + +var ( + testPrecompileCodeA = "60806040526101006000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561005257600080fd5b50610b76806100626000396000f3fe60806040526004361061004a5760003560e01c80635b3082c21461004f57806363de1b5d1461007f5780636bbb9b13146100af5780638381f58a146100df578063be2b0ac21461010a575b600080fd5b610069600480360381019061006491906106cc565b610147565b60405161007691906108ba565b60405180910390f35b61009960048036038101906100949190610670565b610161565b6040516100a69190610898565b60405180910390f35b6100c960048036038101906100c49190610744565b610314565b6040516100d69190610898565b60405180910390f35b3480156100eb57600080fd5b506100f46104ca565b6040516101019190610913565b60405180910390f35b34801561011657600080fd5b50610131600480360381019061012c91906105de565b6104d0565b60405161013e91906108ba565b60405180910390f35b606060405180602001604052806000815250905092915050565b60606001805461017191906109c7565b60018190555060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1634866040516024016101c391906108ba565b6040516020818303038152906040527fbe2b0ac2000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161024d9190610881565b60006040518083038185875af1925050503d806000811461028a576040519150601f19603f3d011682016040523d82523d6000602084013e61028f565b606091505b509150915083156102f557816102a457600080fd5b6000818060200190518101906102ba9190610627565b90507fe390e3d6b4766bc311796e6b5ce75dd6d51f0cb55cea58be963a5e7972ade65c816040516102eb91906108ba565b60405180910390a1505b6001805461030391906109c7565b600181905550809250505092915050565b60606001805461032491906109c7565b60018190555060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163487876040516024016103789291906108dc565b6040516020818303038152906040527f5b3082c2000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104029190610881565b60006040518083038185875af1925050503d806000811461043f576040519150601f19603f3d011682016040523d82523d6000602084013e610444565b606091505b509150915083156104aa578161045957600080fd5b60008180602001905181019061046f9190610627565b90507fe390e3d6b4766bc311796e6b5ce75dd6d51f0cb55cea58be963a5e7972ade65c816040516104a091906108ba565b60405180910390a1505b600180546104b891906109c7565b60018190555080925050509392505050565b60015481565b6060604051806020016040528060008152509050919050565b60006104fc6104f784610953565b61092e565b90508281526020810184848401111561051857610517610b09565b5b610523848285610a33565b509392505050565b600061053e61053984610953565b61092e565b90508281526020810184848401111561055a57610559610b09565b5b610565848285610a42565b509392505050565b60008135905061057c81610b29565b92915050565b600082601f83011261059757610596610b04565b5b81356105a78482602086016104e9565b91505092915050565b600082601f8301126105c5576105c4610b04565b5b81516105d584826020860161052b565b91505092915050565b6000602082840312156105f4576105f3610b13565b5b600082013567ffffffffffffffff81111561061257610611610b0e565b5b61061e84828501610582565b91505092915050565b60006020828403121561063d5761063c610b13565b5b600082015167ffffffffffffffff81111561065b5761065a610b0e565b5b610667848285016105b0565b91505092915050565b6000806040838503121561068757610686610b13565b5b600083013567ffffffffffffffff8111156106a5576106a4610b0e565b5b6106b185828601610582565b92505060206106c28582860161056d565b9150509250929050565b600080604083850312156106e3576106e2610b13565b5b600083013567ffffffffffffffff81111561070157610700610b0e565b5b61070d85828601610582565b925050602083013567ffffffffffffffff81111561072e5761072d610b0e565b5b61073a85828601610582565b9150509250929050565b60008060006060848603121561075d5761075c610b13565b5b600084013567ffffffffffffffff81111561077b5761077a610b0e565b5b61078786828701610582565b935050602084013567ffffffffffffffff8111156107a8576107a7610b0e565b5b6107b486828701610582565b92505060406107c58682870161056d565b9150509250925092565b60006107da82610984565b6107e4818561099a565b93506107f4818560208601610a42565b6107fd81610b18565b840191505092915050565b600061081382610984565b61081d81856109ab565b935061082d818560208601610a42565b80840191505092915050565b60006108448261098f565b61084e81856109b6565b935061085e818560208601610a42565b61086781610b18565b840191505092915050565b61087b81610a29565b82525050565b600061088d8284610808565b915081905092915050565b600060208201905081810360008301526108b281846107cf565b905092915050565b600060208201905081810360008301526108d48184610839565b905092915050565b600060408201905081810360008301526108f68185610839565b9050818103602083015261090a8184610839565b90509392505050565b60006020820190506109286000830184610872565b92915050565b6000610938610949565b90506109448282610a75565b919050565b6000604051905090565b600067ffffffffffffffff82111561096e5761096d610ad5565b5b61097782610b18565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b60006109d282610a29565b91506109dd83610a29565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610a1257610a11610aa6565b5b828201905092915050565b60008115159050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015610a60578082015181840152602081019050610a45565b83811115610a6f576000848401525b50505050565b610a7e82610b18565b810181811067ffffffffffffffff82111715610a9d57610a9c610ad5565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b610b3281610a1d565b8114610b3d57600080fd5b5056fea264697066735822122099b3fbd7a2bf1822c7f366e7e6685aa6801d09d9932acbf59c0687cae6df69da64736f6c63430008070033" + + 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"}` + + testPrecompileABIAJson = "{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"wasmAddr\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"data\",\"type\":\"string\"}],\"name\":\"callToWasm\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"response\",\"type\":\"string\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"wasmAddr\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"msgData\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"requireASuccess\",\"type\":\"bool\"}],\"name\":\"callWasm\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"data\",\"type\":\"string\"}],\"name\":\"pushLog\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"msgData\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"requireASuccess\",\"type\":\"bool\"}],\"name\":\"queryWasm\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"number\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"data\",\"type\":\"string\"}],\"name\":\"queryToWasm\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"response\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"bin\":\"60806040526101006000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561005257600080fd5b50610b76806100626000396000f3fe60806040526004361061004a5760003560e01c80635b3082c21461004f57806363de1b5d1461007f5780636bbb9b13146100af5780638381f58a146100df578063be2b0ac21461010a575b600080fd5b610069600480360381019061006491906106cc565b610147565b60405161007691906108ba565b60405180910390f35b61009960048036038101906100949190610670565b610161565b6040516100a69190610898565b60405180910390f35b6100c960048036038101906100c49190610744565b610314565b6040516100d69190610898565b60405180910390f35b3480156100eb57600080fd5b506100f46104ca565b6040516101019190610913565b60405180910390f35b34801561011657600080fd5b50610131600480360381019061012c91906105de565b6104d0565b60405161013e91906108ba565b60405180910390f35b606060405180602001604052806000815250905092915050565b60606001805461017191906109c7565b60018190555060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1634866040516024016101c391906108ba565b6040516020818303038152906040527fbe2b0ac2000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161024d9190610881565b60006040518083038185875af1925050503d806000811461028a576040519150601f19603f3d011682016040523d82523d6000602084013e61028f565b606091505b509150915083156102f557816102a457600080fd5b6000818060200190518101906102ba9190610627565b90507fe390e3d6b4766bc311796e6b5ce75dd6d51f0cb55cea58be963a5e7972ade65c816040516102eb91906108ba565b60405180910390a1505b6001805461030391906109c7565b600181905550809250505092915050565b60606001805461032491906109c7565b60018190555060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163487876040516024016103789291906108dc565b6040516020818303038152906040527f5b3082c2000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104029190610881565b60006040518083038185875af1925050503d806000811461043f576040519150601f19603f3d011682016040523d82523d6000602084013e610444565b606091505b509150915083156104aa578161045957600080fd5b60008180602001905181019061046f9190610627565b90507fe390e3d6b4766bc311796e6b5ce75dd6d51f0cb55cea58be963a5e7972ade65c816040516104a091906108ba565b60405180910390a1505b600180546104b891906109c7565b60018190555080925050509392505050565b60015481565b6060604051806020016040528060008152509050919050565b60006104fc6104f784610953565b61092e565b90508281526020810184848401111561051857610517610b09565b5b610523848285610a33565b509392505050565b600061053e61053984610953565b61092e565b90508281526020810184848401111561055a57610559610b09565b5b610565848285610a42565b509392505050565b60008135905061057c81610b29565b92915050565b600082601f83011261059757610596610b04565b5b81356105a78482602086016104e9565b91505092915050565b600082601f8301126105c5576105c4610b04565b5b81516105d584826020860161052b565b91505092915050565b6000602082840312156105f4576105f3610b13565b5b600082013567ffffffffffffffff81111561061257610611610b0e565b5b61061e84828501610582565b91505092915050565b60006020828403121561063d5761063c610b13565b5b600082015167ffffffffffffffff81111561065b5761065a610b0e565b5b610667848285016105b0565b91505092915050565b6000806040838503121561068757610686610b13565b5b600083013567ffffffffffffffff8111156106a5576106a4610b0e565b5b6106b185828601610582565b92505060206106c28582860161056d565b9150509250929050565b600080604083850312156106e3576106e2610b13565b5b600083013567ffffffffffffffff81111561070157610700610b0e565b5b61070d85828601610582565b925050602083013567ffffffffffffffff81111561072e5761072d610b0e565b5b61073a85828601610582565b9150509250929050565b60008060006060848603121561075d5761075c610b13565b5b600084013567ffffffffffffffff81111561077b5761077a610b0e565b5b61078786828701610582565b935050602084013567ffffffffffffffff8111156107a8576107a7610b0e565b5b6107b486828701610582565b92505060406107c58682870161056d565b9150509250925092565b60006107da82610984565b6107e4818561099a565b93506107f4818560208601610a42565b6107fd81610b18565b840191505092915050565b600061081382610984565b61081d81856109ab565b935061082d818560208601610a42565b80840191505092915050565b60006108448261098f565b61084e81856109b6565b935061085e818560208601610a42565b61086781610b18565b840191505092915050565b61087b81610a29565b82525050565b600061088d8284610808565b915081905092915050565b600060208201905081810360008301526108b281846107cf565b905092915050565b600060208201905081810360008301526108d48184610839565b905092915050565b600060408201905081810360008301526108f68185610839565b9050818103602083015261090a8184610839565b90509392505050565b60006020820190506109286000830184610872565b92915050565b6000610938610949565b90506109448282610a75565b919050565b6000604051905090565b600067ffffffffffffffff82111561096e5761096d610ad5565b5b61097782610b18565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b60006109d282610a29565b91506109dd83610a29565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610a1257610a11610aa6565b5b828201905092915050565b60008115159050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015610a60578082015181840152602081019050610a45565b83811115610a6f576000848401525b50505050565b610a7e82610b18565b810181811067ffffffffffffffff82111715610a9d57610a9c610ad5565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b610b3281610a1d565b8114610b3d57600080fd5b5056fea264697066735822122099b3fbd7a2bf1822c7f366e7e6685aa6801d09d9932acbf59c0687cae6df69da64736f6c63430008070033\"}" + callWasmMsgFormat = "{\"transfer\":{\"amount\":\"%d\",\"recipient\":\"%s\"}}" +) + +type Env struct { + priv []ethsecp256k1.PrivKey + addr []sdk.AccAddress +} + +type Chain struct { + app *app.OKExChainApp + codec *codec.Codec + priv []ethsecp256k1.PrivKey + addr []sdk.AccAddress + acc []apptypes.EthAccount + seq []uint64 + num []uint64 + chainIdStr string + chainIdInt *big.Int + ContractAddr []byte + + erc20ABI abi.ABI + //vmb: evm->wasm + VMBContractA ethcmn.Address + VMBWasmContract sdk.WasmAddress + //vmb: wasm->evm + freeCallWasmContract sdk.WasmAddress + freeCallWasmCodeId uint64 + freeCallEvmContract ethcmn.Address + + timeYear int +} + +func NewChain(env *Env) *Chain { + chain := new(Chain) + chain.acc = make([]apptypes.EthAccount, 10) + chain.priv = make([]ethsecp256k1.PrivKey, 10) + chain.addr = make([]sdk.AccAddress, 10) + chain.seq = make([]uint64, 10) + chain.num = make([]uint64, 10) + chain.chainIdStr = "ethermint-3" + chain.chainIdInt = big.NewInt(3) + chain.timeYear = 2022 + // initialize account + genAccs := make([]authexported.GenesisAccount, 0) + for i := 0; i < 10; i++ { + chain.acc[i] = apptypes.EthAccount{ + BaseAccount: &auth.BaseAccount{ + Address: env.addr[i], + Coins: sdk.Coins{sdk.NewInt64Coin("okt", 1000000)}, + }, + CodeHash: ethcrypto.Keccak256(nil), + } + genAccs = append(genAccs, chain.acc[i]) + chain.priv[i] = env.priv[i] + chain.addr[i] = env.addr[i] + chain.seq[i] = 0 + chain.num[i] = uint64(i) + } + + chain.app = app.SetupWithGenesisAccounts(false, genAccs, app.WithChainId(chain.chainIdStr)) + chain.codec = chain.app.Codec() + + chain.app.WasmKeeper.SetParams(chain.Ctx(), wasmtypes.TestParams()) + params := evmtypes.DefaultParams() + params.EnableCreate = true + params.EnableCall = true + chain.app.EvmKeeper.SetParams(chain.Ctx(), params) + + chain.app.BaseApp.Commit(abci.RequestCommit{}) + return chain +} + +func (chain *Chain) Ctx() sdk.Context { + return chain.app.BaseApp.GetDeliverStateCtx() +} + +func DeployContractAndGetContractAddress(t *testing.T, chain *Chain) { + var rawTxs [][]byte + rawTxs = append(rawTxs, deployContract(t, chain, 0)) + r := runTxs(chain, rawTxs, false) + + log := r[0].Log[1 : len(r[0].Log)-1] + logMap := make(map[string]interface{}) + err := json.Unmarshal([]byte(log), &logMap) + require.NoError(t, err) + + logs := strings.Split(logMap["log"].(string), ";") + require.True(t, len(logs) == 3) + contractLog := strings.Split(logs[2], " ") + require.True(t, len(contractLog) == 4) + chain.ContractAddr = []byte(contractLog[3]) +} + +func createEthTx(t *testing.T, chain *Chain, addressIdx int) []byte { + amount, gasPrice, gasLimit := int64(1024), int64(2048), uint64(100000) + addrTo := ethcmn.BytesToAddress(chain.priv[addressIdx+1].PubKey().Address().Bytes()) + msg := evmtypes.NewMsgEthereumTx(chain.seq[addressIdx], &addrTo, big.NewInt(amount), gasLimit, big.NewInt(gasPrice), []byte{}) + chain.seq[addressIdx]++ + err := msg.Sign(chain.chainIdInt, chain.priv[addressIdx].ToECDSA()) + require.NoError(t, err) + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + + return rawTx +} + +func createAnteErrEthTx(t *testing.T, chain *Chain, addressIdx int) []byte { + amount, gasPrice, gasLimit := int64(1024), int64(2048), uint64(100000) + addrTo := ethcmn.BytesToAddress(chain.priv[addressIdx+1].PubKey().Address().Bytes()) + //Note: anteErr occur (invalid nonce) + msg := evmtypes.NewMsgEthereumTx(chain.seq[addressIdx]+1, &addrTo, big.NewInt(amount), gasLimit, big.NewInt(gasPrice), []byte{}) + err := msg.Sign(chain.chainIdInt, chain.priv[addressIdx].ToECDSA()) + require.NoError(t, err) + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + + return rawTx +} + +func createFailedEthTx(t *testing.T, chain *Chain, addressIdx int) []byte { + amount, gasPrice, gasLimit := int64(1024), int64(2048), uint64(1) + addrTo := ethcmn.BytesToAddress(chain.priv[addressIdx+1].PubKey().Address().Bytes()) + msg := evmtypes.NewMsgEthereumTx(chain.seq[addressIdx], &addrTo, big.NewInt(amount), gasLimit, big.NewInt(gasPrice), []byte{}) + chain.seq[addressIdx]++ + err := msg.Sign(chain.chainIdInt, chain.priv[addressIdx].ToECDSA()) + require.NoError(t, err) + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + + return rawTx +} + +func createTokenSendTx(t *testing.T, chain *Chain, i int) []byte { + msg := tokentypes.NewMsgTokenSend(chain.addr[i], chain.addr[i+1], sdk.Coins{sdk.NewInt64Coin("okt", 1)}) + + tx := helpers.GenTx( + []sdk.Msg{msg}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)}, + helpers.DefaultGenTxGas, + chain.chainIdStr, + []uint64{chain.num[i]}, + []uint64{chain.seq[i]}, + chain.priv[i], + ) + chain.seq[i]++ + + txBytes, err := chain.app.Codec().MarshalBinaryLengthPrefixed(tx) + require.Nil(t, err) + return txBytes +} + +func createFailedTokenSendTx(t *testing.T, chain *Chain, i int) []byte { + msg := tokentypes.NewMsgTokenSend(chain.addr[i], chain.addr[i+1], sdk.Coins{sdk.NewInt64Coin("okt", 100000000000)}) + + tx := helpers.GenTx( + []sdk.Msg{msg}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)}, + helpers.DefaultGenTxGas, + chain.chainIdStr, + []uint64{chain.num[i]}, + []uint64{chain.seq[i]}, + chain.priv[i], + ) + chain.seq[i]++ + + txBytes, err := chain.app.Codec().MarshalBinaryLengthPrefixed(tx) + require.Nil(t, err) + return txBytes +} + +func createAnteErrTokenSendTx(t *testing.T, chain *Chain, i int) []byte { + msg := tokentypes.NewMsgTokenSend(chain.addr[i], chain.addr[i+1], sdk.Coins{sdk.NewInt64Coin("okt", 1)}) + + tx := helpers.GenTx( + []sdk.Msg{msg}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000000000)}, + helpers.DefaultGenTxGas, + chain.chainIdStr, + []uint64{chain.num[i]}, + []uint64{chain.seq[i]}, + chain.priv[i], + ) + + txBytes, err := chain.app.Codec().MarshalBinaryLengthPrefixed(tx) + require.Nil(t, err) + return txBytes +} + +func runTxs(chain *Chain, rawTxs [][]byte, isParallel bool) []*abci.ResponseDeliverTx { + timeValue := fmt.Sprintf("%d-04-11 13:33:37", chain.timeYear+1) + testTime, _ := time.Parse("2006-01-02 15:04:05", timeValue) + header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr, Time: testTime} + chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + var ret []*abci.ResponseDeliverTx + if isParallel { + ret = chain.app.BaseApp.ParallelTxs(rawTxs, false) + } else { + for _, tx := range rawTxs { + r := chain.app.BaseApp.DeliverTx(abci.RequestDeliverTx{Tx: tx}) + ret = append(ret, &r) + } + } + chain.app.BaseApp.EndBlock(abci.RequestEndBlock{}) + chain.app.BaseApp.Commit(abci.RequestCommit{}) + + return ret +} + +func TestParallelTxs(t *testing.T) { + + tmtypes.UnittestOnlySetMilestoneVenusHeight(-1) + tmtypes.UnittestOnlySetMilestoneVenus1Height(1) + tmtypes.UnittestOnlySetMilestoneVenus2Height(1) + tmtypes.UnittestOnlySetMilestoneEarthHeight(1) + tmtypes.UnittestOnlySetMilestoneVenus6Height(1) + + env := new(Env) + env.priv = make([]ethsecp256k1.PrivKey, 10) + env.addr = make([]sdk.AccAddress, 10) + for i := 0; i < 10; i++ { + priv, _ := ethsecp256k1.GenerateKey() + addr := sdk.AccAddress(priv.PubKey().Address()) + env.priv[i] = priv + env.addr[i] = addr + } + chainA, chainB := NewChain(env), NewChain(env) + + VMBPrecompileSetup(t, chainA) + VMBPrecompileSetup(t, chainB) + + DeployContractAndGetContractAddress(t, chainA) + DeployContractAndGetContractAddress(t, chainB) + + testCases := []struct { + title string + executeTxs func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) + expectedCodes []uint32 + }{ + // ##################### + // ### only evm txs #### + // ##################### + { + "5 evm txs, 1 group: a->b b->c c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + for i := 0; i < 5; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + { + "4 evm txs and 1 AnteErr evm tx, 1 group: a->b anteErr(a->b) b->c c->d d->e", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + for i := 2; i < 5; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 0, 0, 0}, + }, + { + "4 evm txs and 1 AnteErr evm tx, 2 group: a->b anteErr(a->b) / c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + for i := 3; i < 6; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 0, 0, 0}, + }, + { + "5 failed evm txs, 1 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + for i := 0; i < 5; i++ { + rawTxs = append(rawTxs, createFailedEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{11, 11, 11, 11, 11}, + }, + { + "5 evm txs, 2 group:a->b b->c / d->e e->f f->g", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + //one group 3txs + for i := 0; i < 3; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + //one group 2txs + for i := 8; i > 6; i-- { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + { + "5 failed evm txs, 2 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + //one group 3txs + for i := 0; i < 3; i++ { + rawTxs = append(rawTxs, createFailedEthTx(t, chain, i)) + } + //one group 2txs + for i := 8; i > 6; i-- { + rawTxs = append(rawTxs, createFailedEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{11, 11, 11, 11, 11}, + }, + { + "2 evm txs and 3 failed evm txs, 2 group:a->b b->c / failed(d->e e->f f->g)", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + rawTxs := [][]byte{} + //one group 3txs + for i := 0; i < 3; i++ { + rawTxs = append(rawTxs, createFailedEthTx(t, chain, i)) + } + //one group 2txs + for i := 8; i > 6; i-- { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{11, 11, 11, 0, 0}, + }, + { + "3 evm txs and 2 failed evm txs, 2 group:a->b failed(b->c) / d->e e->f failed(f->g)", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + rawTxs := [][]byte{} + //one group 3txs + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 2)) + //one group 2txs + for i := 8; i > 7; i-- { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 7)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 11, 0, 11}, + }, + { + "3 contract txs and 2 normal evm txs, 2 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + + for i := 0; i < 3; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + for i := 8; i > 6; i-- { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + // ##################### + // ## only cosmos txs ## + // ##################### + { + "5 cosmos txs, 0 group: a->b b->c c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + for i := 0; i < 5; i++ { + rawTxs = append(rawTxs, createTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + { + "4 cosmos txs, 1 Failed cosmos tx, 0 group: a->b failed(b->c) / d->e e->f f->g", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 1)) + for i := 3; i < 6; i++ { + rawTxs = append(rawTxs, createTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 61034, 0, 0, 0}, + }, + { + "4 cosmos txs, 1 AnteErr cosmos tx, 0 group: a->b AnteErr(b->c) c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 1)) + for i := 2; i < 5; i++ { + rawTxs = append(rawTxs, createTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 5, 0, 0, 0}, + }, + { + "4 failed cosmos txs, 1 AnteErr cosmos tx, 0 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 1)) + for i := 2; i < 5; i++ { + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{61034, 5, 61034, 61034, 61034}, + }, + { + "3 cosmos txs, 1 failed cosmos tx, 1 AnteErr cosmos tx, 0 group: a->b b->c c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, createTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 61034, 5, 0, 0}, + }, + { + "5 failed cosmos txs, 0 group: a->b b->c c->d d->e e->f", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + + var rawTxs [][]byte + for i := 0; i < 5; i++ { + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{61034, 61034, 61034, 61034, 61034}, + }, + // ##################### + // ###### mix txs ###### + // ##################### + { + "2 evm txs with 1 cosmos tx and 2 evm contract txs, 2 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + //one group 3txs + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + //cosmos tx + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 4; i < 6; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + { + "2 evm txs, 1 cosmos tx, and 2 evm contract txs, 2 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 3)) + //one group 2txs + for i := 5; i < 7; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 0, 0}, + }, + { + "1 evm tx, 1 AnteErr evm tx, 1 cosmos tx, and 2 evm contract txs, 2 group", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 3)) + //one group 2txs + for i := 5; i < 7; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 0, 0, 0}, + }, + { + "1 evm tx, 1 failed evm tx, 1 cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 0, 0, 0}, + }, + { + "1 evm tx, 1 failed evm tx, 1 cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 0, 0, 0}, + }, + { + "2 evm tx, 1 AnteErr cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 5, 0, 0}, + }, + { + "2 evm tx, 1 failed cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 61034, 0, 0}, + }, + { + "2 evm tx, 1 cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 3, 0}, + }, + { + "2 evm tx, 1 cosmos tx, 1 failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 0, 11, 0}, + }, + { + "2 evm tx, 1 AnteErr cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 5, 0, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 AnteErr cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 5, 0, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 failed cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 61034, 0, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 0, 3, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 cosmos tx, 1 failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 0, 11, 0}, + }, + { + "1 evm tx, 1 failed evm, 1 AnteErr cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 5, 0, 0}, + }, + { + "1 evm tx, 1 failed evm, 1 failed cosmos tx, and 2 evm contract txs", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + for i := 3; i < 5; i++ { + rawTxs = append(rawTxs, callContract(t, chain, i)) + } + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 61034, 0, 0}, + }, + { + "1 evm tx, 1 failed evm, 1 cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 0, 3, 0}, + }, + { + "1 evm tx, 1 failed evm, 1 cosmos tx, 1 failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 0, 11, 0}, + }, + { + "2 evm tx, 1 AnteErr cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 5, 3, 0}, + }, + { + "2 evm tx, 1 AnteErr cosmos tx, 1 failed evm contract tx, and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 5, 11, 0}, + }, + { + "2 evm tx, 1 failed cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 61034, 3, 0}, + }, + { + "2 evm tx, 1 failed cosmos tx, 1 failed evm contract tx, and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + for i := 0; i < 2; i++ { + rawTxs = append(rawTxs, createEthTx(t, chain, i)) + } + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 61034, 11, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 AnteErr cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 5, 3, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 AnteErr cosmos tx, 1 Failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 5, 11, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 Failed cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 61034, 3, 0}, + }, + { + "1 evm tx, 1 Failed evm, 1 AnteErr cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 5, 3, 0}, + }, + { + "1 evm tx, 1 Failed evm, 1 Failed cosmos tx, 1 Failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 61034, 11, 0}, + }, + { + "1 evm tx, 1 Failed evm, 1 Failed cosmos tx, 1 AnteErr evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractAnteErr(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 61034, 3, 0}, + }, + { + "1 evm tx, 1 Failed evm, 1 AnteErr cosmos tx, 1 Failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createFailedEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createAnteErrTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 11, 5, 11, 0}, + }, + { + "1 evm tx, 1 AnteErr evm, 1 Failed cosmos tx, 1 Failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, createAnteErrEthTx(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 3, 61034, 11, 0}, + }, + { + "1 evm tx, 1 callWasm vmb tx, 1 Failed cosmos tx, 1 Failed evm contract txs,and 1 evm contract tx", + func(t *testing.T, chain *Chain, isParallel bool) ([]*abci.ResponseDeliverTx, []byte, []byte) { + var rawTxs [][]byte + rawTxs = append(rawTxs, createEthTx(t, chain, 0)) + rawTxs = append(rawTxs, callWasmAtContractA(t, chain, 1)) + rawTxs = append(rawTxs, createFailedTokenSendTx(t, chain, 2)) + //one group 2txs + rawTxs = append(rawTxs, callContractFailed(t, chain, 3)) + rawTxs = append(rawTxs, callContract(t, chain, 4)) + ret := runTxs(chain, rawTxs, isParallel) + + return ret, resultHash(ret), chain.app.BaseApp.LastCommitID().Hash + }, + []uint32{0, 0, 61034, 11, 0}, + }, + } + + for _, tc := range testCases { + t.Run(tc.title, func(t *testing.T) { + retA, resultHashA, appHashA := tc.executeTxs(t, chainA, true) + retB, resultHashB, appHashB := tc.executeTxs(t, chainB, false) + checkCodes(t, tc.title, retA, tc.expectedCodes) + checkCodes(t, tc.title, retB, tc.expectedCodes) + require.True(t, reflect.DeepEqual(resultHashA, resultHashB)) + require.True(t, reflect.DeepEqual(appHashA, appHashB)) + }) + } +} + +func resultHash(txs []*abci.ResponseDeliverTx) []byte { + results := tmtypes.NewResults(txs) + return results.Hash() +} + +// contract Storage { +// uint256 number; +// /** +// * @dev Store value in variable +// * @param num value to store +// */ +// function store(uint256 num) public { +// number = num; +// } +// function add() public { +// number += 1; +// } +// /** +// * @dev Return value +// * @return value of 'number' +// */ +// function retrieve() public view returns (uint256){ +// return number; +// } +// } +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"}]` + +func deployContract(t *testing.T, chain *Chain, i int) []byte { + // Deploy contract - Owner.sol + gasLimit := uint64(30000000) + gasPrice := big.NewInt(100000000) + + //sender := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) + + bytecode := ethcmn.FromHex("608060405234801561001057600080fd5b50610217806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631003e2d2146100465780632e64cec1146100625780636057361d14610080575b600080fd5b610060600480360381019061005b9190610105565b61009c565b005b61006a6100b7565b6040516100779190610141565b60405180910390f35b61009a60048036038101906100959190610105565b6100c0565b005b806000808282546100ad919061018b565b9250508190555050565b60008054905090565b8060008190555050565b600080fd5b6000819050919050565b6100e2816100cf565b81146100ed57600080fd5b50565b6000813590506100ff816100d9565b92915050565b60006020828403121561011b5761011a6100ca565b5b6000610129848285016100f0565b91505092915050565b61013b816100cf565b82525050565b60006020820190506101566000830184610132565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610196826100cf565b91506101a1836100cf565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101d6576101d561015c565b5b82820190509291505056fea2646970667358221220318e29d6b4806f219eedd0cc861e82c13e28eb7f42161f2c780dc539b0e32b4e64736f6c634300080a0033") + msg := evmtypes.NewMsgEthereumTx(chain.seq[i], nil, big.NewInt(0), gasLimit, gasPrice, bytecode) + err := msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) + require.NoError(t, err) + chain.seq[i]++ + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + return rawTx +} + +type CompiledContract struct { + ABI abi.ABI + Bin string +} + +func UnmarshalContract(t *testing.T, cJson string) *CompiledContract { + cc := new(CompiledContract) + err := json.Unmarshal([]byte(cJson), cc) + require.NoError(t, err) + return cc +} + +func callContract(t *testing.T, chain *Chain, i int) []byte { + gasLimit := uint64(30000000) + gasPrice := big.NewInt(100000000) + //to := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) + to := ethcmn.BytesToAddress(chain.ContractAddr) + cc := UnmarshalContract(t, contractJson) + data, err := cc.ABI.Pack("add") + require.NoError(t, err) + msg := evmtypes.NewMsgEthereumTx(chain.seq[i], &to, big.NewInt(0), gasLimit, gasPrice, data) + err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) + require.NoError(t, err) + chain.seq[i]++ + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + return rawTx +} + +func callWasmAtContractA(t *testing.T, chain *Chain, i int) []byte { + gasLimit := uint64(30000000) + gasPrice := big.NewInt(100000000) + + to := ethcmn.BytesToAddress(chain.VMBWasmContract.Bytes()) + cc := UnmarshalContract(t, testPrecompileABIAJson) + wasmCallData := fmt.Sprintf(callWasmMsgFormat, 10, chain.addr[i].String()) + data, err := cc.ABI.Pack("callWasm", chain.VMBWasmContract.String(), hex.EncodeToString([]byte(wasmCallData)), true) + require.NoError(t, err) + msg := evmtypes.NewMsgEthereumTx(chain.seq[i], &to, big.NewInt(0), gasLimit, gasPrice, data) + err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) + require.NoError(t, err) + chain.seq[i]++ + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + return rawTx +} + +func callContractFailed(t *testing.T, chain *Chain, i int) []byte { + gasLimit := uint64(1) + gasPrice := big.NewInt(100000000) + //to := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) + to := ethcmn.BytesToAddress(chain.ContractAddr) + cc := UnmarshalContract(t, contractJson) + data, err := cc.ABI.Pack("add") + require.NoError(t, err) + msg := evmtypes.NewMsgEthereumTx(chain.seq[i], &to, big.NewInt(0), gasLimit, gasPrice, data) + err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) + require.NoError(t, err) + chain.seq[i]++ + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + return rawTx +} + +func callContractAnteErr(t *testing.T, chain *Chain, i int) []byte { + gasLimit := uint64(30000000) + gasPrice := big.NewInt(100000000) + //to := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) + to := ethcmn.BytesToAddress(chain.ContractAddr) + cc := UnmarshalContract(t, contractJson) + data, err := cc.ABI.Pack("add") + require.NoError(t, err) + msg := evmtypes.NewMsgEthereumTx(chain.seq[i]+1, &to, big.NewInt(0), gasLimit, gasPrice, data) + err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) + require.NoError(t, err) + rawTx, err := rlp.EncodeToBytes(&msg) + require.NoError(t, err) + return rawTx +} + +func checkCodes(t *testing.T, title string, resp []*abci.ResponseDeliverTx, codes []uint32) { + for i, code := range codes { + require.True(t, resp[i].Code == code, "title: %s, expect code: %d, but %d! tx index: %d", title, code, resp[i].Code, i) + } +} + +func VMBPrecompileSetup(t *testing.T, chain *Chain) { + timeValue := fmt.Sprintf("%d-04-11 13:33:37", chain.timeYear+1) + testTime, _ := time.Parse("2006-01-02 15:04:05", timeValue) + header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr, Time: testTime} + chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + chain.VMBContractA = vmbDeployEvmContract(t, chain, testPrecompileCodeA) + initMsg := []byte(fmt.Sprintf("{\"decimals\":10,\"initial_balances\":[{\"address\":\"%s\",\"amount\":\"100000000\"}],\"name\":\"my test token\", \"symbol\":\"MTT\"}", chain.addr[0].String())) + chain.VMBWasmContract = vmbDeployWasmContract(t, chain, "precompile.wasm", initMsg) + + chain.app.BaseApp.EndBlock(abci.RequestEndBlock{}) + chain.app.BaseApp.Commit(abci.RequestCommit{}) +} + +func vmbDeployEvmContract(t *testing.T, chain *Chain, code string) ethcmn.Address { + freeCallBytecode := ethcmn.Hex2Bytes(code) + _, contract, err := chain.app.VMBridgeKeeper.CallEvm(chain.Ctx(), ethcmn.BytesToAddress(chain.addr[0]), nil, big.NewInt(0), freeCallBytecode) + require.NoError(t, err) + chain.seq[0]++ + return contract.ContractAddress +} + +func vmbDeployWasmContract(t *testing.T, chain *Chain, filename string, initMsg []byte) sdk.WasmAddress { + wasmcode, err := ioutil.ReadFile(fmt.Sprintf("./testdata/%s", filename)) + require.NoError(t, err) + codeid, err := chain.app.WasmPermissionKeeper.Create(chain.Ctx(), sdk.AccToAWasmddress(chain.addr[0]), wasmcode, nil) + require.NoError(t, err) + //initMsg := []byte(fmt.Sprintf("{\"decimals\":10,\"initial_balances\":[{\"address\":\"%s\",\"amount\":\"100000000\"}],\"name\":\"my test token\", \"symbol\":\"MTT\"}", suite.addr.String())) + contract, _, err := chain.app.WasmPermissionKeeper.Instantiate(chain.Ctx(), codeid, sdk.AccToAWasmddress(chain.addr[0]), sdk.AccToAWasmddress(chain.addr[0]), initMsg, "label", sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) + require.NoError(t, err) + return contract +} diff --git a/app/app_test.go b/app/app_test.go index cdbc799926..898301b443 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -7,35 +7,30 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/okex/exchain/app/crypto/ethsecp256k1" + "github.com/okex/exchain/libs/cosmos-sdk/codec" cosmossdk "github.com/okex/exchain/libs/cosmos-sdk/types" + "github.com/okex/exchain/libs/cosmos-sdk/x/auth" authclient "github.com/okex/exchain/libs/cosmos-sdk/x/auth/client/utils" + authtypes "github.com/okex/exchain/libs/cosmos-sdk/x/auth/types" + "github.com/okex/exchain/libs/cosmos-sdk/x/upgrade" + abci "github.com/okex/exchain/libs/tendermint/abci/types" + abcitypes "github.com/okex/exchain/libs/tendermint/abci/types" + "github.com/okex/exchain/libs/tendermint/crypto" "github.com/okex/exchain/libs/tendermint/global" + "github.com/okex/exchain/libs/tendermint/libs/log" tendertypes "github.com/okex/exchain/libs/tendermint/types" - "github.com/okex/exchain/x/distribution/keeper" - evmtypes "github.com/okex/exchain/x/evm/types" - - "github.com/okex/exchain/libs/cosmos-sdk/x/upgrade" + dbm "github.com/okex/exchain/libs/tm-db" "github.com/okex/exchain/x/dex" distr "github.com/okex/exchain/x/distribution" + "github.com/okex/exchain/x/distribution/keeper" + evmtypes "github.com/okex/exchain/x/evm/types" "github.com/okex/exchain/x/farm" - "github.com/okex/exchain/x/params" - - "github.com/stretchr/testify/require" - - abci "github.com/okex/exchain/libs/tendermint/abci/types" - "github.com/okex/exchain/libs/tendermint/libs/log" - dbm "github.com/okex/exchain/libs/tm-db" - - "github.com/okex/exchain/libs/cosmos-sdk/codec" - - "github.com/okex/exchain/libs/cosmos-sdk/x/auth" - authtypes "github.com/okex/exchain/libs/cosmos-sdk/x/auth/types" - abcitypes "github.com/okex/exchain/libs/tendermint/abci/types" - "github.com/okex/exchain/libs/tendermint/crypto" "github.com/okex/exchain/x/gov" + "github.com/okex/exchain/x/params" ) var ( diff --git a/app/config/config.go b/app/config/config.go index 15f55a62dd..ac4cfbe88d 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -49,8 +49,14 @@ type OecConfig struct { maxGasUsedPerBlock int64 // mempool.enable-pgu enablePGU bool + // mempool.pgu-percentage-threshold + pguPercentageThreshold int64 + // mempool.pgu-concurrency + pguConcurrency int // mempool.pgu-adjustment pguAdjustment float64 + // mempool.pgu-persist + pguPersist bool // mempool.node_key_whitelist nodeKeyWhitelist []string //mempool.check_tx_cost @@ -141,7 +147,10 @@ const ( FlagMaxTxNumPerBlock = "mempool.max_tx_num_per_block" FlagMaxGasUsedPerBlock = "mempool.max_gas_used_per_block" FlagEnablePGU = "mempool.enable-pgu" + FlagPGUPercentageThreshold = "mempool.pgu-percentage-threshold" + FlagPGUConcurrency = "mempool.pgu-concurrency" FlagPGUAdjustment = "mempool.pgu-adjustment" + FlagPGUPersist = "mempool.pgu-persist" FlagNodeKeyWhitelist = "mempool.node_key_whitelist" FlagMempoolCheckTxCost = "mempool.check_tx_cost" FlagMempoolEnableDeleteMinGPTx = "mempool.enable_delete_min_gp_tx" @@ -287,7 +296,10 @@ func (c *OecConfig) loadFromConfig() { c.SetPendingPoolBlacklist(viper.GetString(FlagPendingPoolBlacklist)) c.SetMaxGasUsedPerBlock(viper.GetInt64(FlagMaxGasUsedPerBlock)) c.SetEnablePGU(viper.GetBool(FlagEnablePGU)) + c.SetPGUPercentageThreshold(viper.GetInt64(FlagPGUPercentageThreshold)) + c.SetPGUConcurrency(viper.GetInt(FlagPGUConcurrency)) c.SetPGUAdjustment(viper.GetFloat64(FlagPGUAdjustment)) + c.SetPGUPersist(viper.GetBool(FlagPGUPersist)) c.SetGasLimitBuffer(viper.GetUint64(FlagGasLimitBuffer)) c.SetEnableDynamicGp(viper.GetBool(FlagEnableDynamicGp)) @@ -504,12 +516,30 @@ func (c *OecConfig) updateFromKVStr(k, v string) { return } c.SetEnablePGU(r) + case FlagPGUPercentageThreshold: + r, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return + } + c.SetPGUPercentageThreshold(r) + case FlagPGUConcurrency: + r, err := strconv.Atoi(v) + if err != nil { + return + } + c.SetPGUConcurrency(r) case FlagPGUAdjustment: r, err := strconv.ParseFloat(v, 64) if err != nil { return } c.SetPGUAdjustment(r) + case FlagPGUPersist: + r, err := strconv.ParseBool(v) + if err != nil { + return + } + c.SetPGUPersist(r) case FlagGasLimitBuffer: r, err := strconv.ParseUint(v, 10, 64) if err != nil { @@ -834,6 +864,22 @@ func (c *OecConfig) SetEnablePGU(value bool) { c.enablePGU = value } +func (c *OecConfig) GetPGUPercentageThreshold() int64 { + return c.pguPercentageThreshold +} + +func (c *OecConfig) SetPGUPercentageThreshold(value int64) { + c.pguPercentageThreshold = value +} + +func (c *OecConfig) GetPGUConcurrency() int { + return c.pguConcurrency +} + +func (c *OecConfig) SetPGUConcurrency(value int) { + c.pguConcurrency = value +} + func (c *OecConfig) GetPGUAdjustment() float64 { return c.pguAdjustment } @@ -842,6 +888,14 @@ func (c *OecConfig) SetPGUAdjustment(value float64) { c.pguAdjustment = value } +func (c *OecConfig) GetPGUPersist() bool { + return c.pguPersist +} + +func (c *OecConfig) SetPGUPersist(value bool) { + c.pguPersist = value +} + func (c *OecConfig) GetGasLimitBuffer() uint64 { return c.gasLimitBuffer } diff --git a/app/start_from_snapshot.go b/app/start_from_snapshot.go new file mode 100644 index 0000000000..2bf4eea660 --- /dev/null +++ b/app/start_from_snapshot.go @@ -0,0 +1,199 @@ +package app + +import ( + "archive/tar" + "bytes" + "fmt" + "github.com/klauspost/pgzip" + "github.com/okex/exchain/libs/cosmos-sdk/types/errors" + "github.com/okex/exchain/libs/tendermint/libs/log" + "io" + "io/ioutil" + "net/url" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "time" +) + +func prepareSnapshotDataIfNeed(snapshotURL string, home string, logger log.Logger) { + if snapshotURL == "" { + return + } + + snapshotHome := filepath.Join(home, ".download_snapshots") + + // check whether the snapshot file has been downloaded + byteData, err := os.ReadFile(filepath.Join(snapshotHome, ".record")) + if err == nil && strings.Contains(string(byteData), snapshotURL) { + return + } + + if _, err := url.Parse(snapshotURL); err != nil { + panic(errors.Wrap(err, "invalid snapshot URL")) + } + + // download snapshot + snapshotFile, err := downloadSnapshot(snapshotURL, snapshotHome, logger) + if err != nil { + panic(err) + } + + // uncompress snapshot + logger.Info("start to uncompress snapshot") + if err := extractTarGz(snapshotFile, snapshotHome); err != nil { + panic(err) + } + + // delete damaged data + logger.Info("start to delete damaged data") + if err := os.RemoveAll(filepath.Join(home, "data")); err != nil { + panic(err) + } + + // move snapshot data + logger.Info("start to move snapshot data") + if err := moveDir(filepath.Join(snapshotHome, "data"), filepath.Join(home, "data")); err != nil { + panic(err) + } + + os.Remove(snapshotFile) + + os.WriteFile(filepath.Join(snapshotHome, ".record"), []byte(snapshotURL+"\n"), 0644) + + logger.Info("snapshot data is ready, start node soon!") +} + +func downloadSnapshot(url, outputPath string, logger log.Logger) (string, error) { + // create dir + _, err := os.Stat(outputPath) + if err != nil { + os.MkdirAll(outputPath, 0755) + } + + fileName := url[strings.LastIndex(url, "/")+1:] + targetFile := filepath.Join(outputPath, fileName) + + // check file exists + if _, err := os.Stat(targetFile); err == nil { + os.Remove(targetFile) + } + + var stdoutProcessStatus bytes.Buffer + + axel := exec.Command("axel", "-n", fmt.Sprintf("%d", runtime.NumCPU()), "-o", targetFile, url) + axel.Stdout = io.MultiWriter(ioutil.Discard, &stdoutProcessStatus) + done := make(chan struct{}) + defer close(done) + + // print download detail + go func() { + tick := time.NewTicker(time.Millisecond * 50) + defer tick.Stop() + for { + select { + case <-done: + return + case <-tick.C: + bts := make([]byte, stdoutProcessStatus.Len()) + stdoutProcessStatus.Read(bts) + logger.Info(string(bts)) + } + } + }() + + // run and wait + err = axel.Run() + if err != nil { + return "", err + } + + return targetFile, nil +} + +func extractTarGz(tarGzFile, destinationDir string) error { + // open .tar.gz + file, err := os.Open(tarGzFile) + if err != nil { + return err + } + defer file.Close() + + // use gzip.Reader + gzReader, err := pgzip.NewReaderN(file, 1<<22, runtime.NumCPU()) + if err != nil { + return err + } + defer gzReader.Close() + + // create tar.Reader + tarReader := tar.NewReader(gzReader) + + // uncompress file back to back + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + if header == nil { + continue + } + target := filepath.Join(destinationDir, header.Name) + + switch header.Typeflag { + case tar.TypeDir: + err = os.MkdirAll(target, 0755) + if err != nil { + return err + } + case tar.TypeReg: + parent := filepath.Dir(target) + err = os.MkdirAll(parent, 0755) + if err != nil { + return err + } + + file, err := os.Create(target) + if err != nil { + return err + } + defer file.Close() + + _, err = io.Copy(file, tarReader) + if err != nil { + return err + } + } + } + + return nil +} + +func moveDir(sourceDir, destinationDir string) error { + sourceInfo, err := os.Stat(sourceDir) + if err != nil { + return err + } + + if !sourceInfo.IsDir() { + return fmt.Errorf("%s isn't dir", sourceDir) + } + + _, err = os.Stat(destinationDir) + if err == nil { + return fmt.Errorf("dest dir %s exists", destinationDir) + } + + // move + err = os.Rename(sourceDir, destinationDir) + if err != nil { + return err + } + + return nil +} diff --git a/app/test_helpers.go b/app/test_helpers.go index 989c903ea7..1603e44f7d 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -1,11 +1,16 @@ package app import ( + "time" + "github.com/spf13/viper" "github.com/okex/exchain/libs/cosmos-sdk/codec" sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + authtypes "github.com/okex/exchain/libs/cosmos-sdk/x/auth" + authexported "github.com/okex/exchain/libs/cosmos-sdk/x/auth/exported" abci "github.com/okex/exchain/libs/tendermint/abci/types" + abcitypes "github.com/okex/exchain/libs/tendermint/abci/types" "github.com/okex/exchain/libs/tendermint/libs/log" "github.com/okex/exchain/libs/tendermint/types" dbm "github.com/okex/exchain/libs/tm-db" @@ -54,3 +59,41 @@ func Setup(isCheckTx bool, options ...Option) *OKExChainApp { return app } + +func SetupWithGenesisAccounts(isCheckTx bool, genAccs []authexported.GenesisAccount, options ...Option) *OKExChainApp { + viper.Set(sdk.FlagDBBackend, string(dbm.MemDBBackend)) + types.DBBackend = string(dbm.MemDBBackend) + db := dbm.NewMemDB() + app := NewOKExChainApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) + + if !isCheckTx { + setupOption := &SetupOption{chainId: ""} + for _, opt := range options { + opt(setupOption) + } + // init chain must be called to stop deliverState from being nil + genesisState := NewDefaultGenesisState() + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = app.Codec().MustMarshalJSON(authGenesis) + stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState) + if err != nil { + panic(err) + } + + // Initialize the chain + testTime, _ := time.Parse("2006-01-02 15:04:05", "2017-04-11 13:33:37") + app.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: stateBytes, + ChainId: setupOption.chainId, + Time: testTime, + }, + ) + + app.Commit(abcitypes.RequestCommit{}) + app.BeginBlock(abci.RequestBeginBlock{Header: abcitypes.Header{Height: app.LastBlockHeight() + 1}}) + } + + return app +} diff --git a/app/testdata/cw20.wasm b/app/testdata/cw20.wasm new file mode 100644 index 0000000000..9ad8edb813 Binary files /dev/null and b/app/testdata/cw20.wasm differ diff --git a/app/testdata/freecall.sol b/app/testdata/freecall.sol new file mode 100644 index 0000000000..dee445d3a6 --- /dev/null +++ b/app/testdata/freecall.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.18; +// pragma solidity >=0.7.0 <0.9.0; + + +contract FreeCall { + address public constant moduleAddress = + address(0x1033796B018B2bf0Fc9CB88c0793b2F275eDB624); + + event __OKCCallToWasm(string wasmAddr, uint256 value, string data); + + function callByWasm(string memory callerWasmAddr,string memory data) public payable returns (string memory response) { + string memory temp1 = strConcat("callByWasm return: ",callerWasmAddr); + string memory temp2 = strConcat(temp1," ---data: "); + string memory temp3 = strConcat(temp2,data); + return temp3; + } + + + function callToWasm(string memory wasmAddr, uint256 value, string memory data) public returns (bool success){ + emit __OKCCallToWasm(wasmAddr,value,data); + return true; + } + + + function strConcat(string memory _a, string memory _b) internal returns (string memory){ + bytes memory _ba = bytes(_a); + bytes memory _bb = bytes(_b); + string memory ret = new string(_ba.length + _bb.length); + bytes memory bret = bytes(ret); + uint k = 0; + for (uint i = 0; i < _ba.length; i++) { + bret[k++] = _ba[i]; + } + for (uint i = 0; i < _bb.length; i++) { + bret[k++] = _bb[i]; + } + return string(ret); + } +} diff --git a/app/testdata/freecall.wasm b/app/testdata/freecall.wasm new file mode 100644 index 0000000000..8cf65f6b87 Binary files /dev/null and b/app/testdata/freecall.wasm differ diff --git a/app/testdata/precompile.sol b/app/testdata/precompile.sol new file mode 100644 index 0000000000..9d8aa653ab --- /dev/null +++ b/app/testdata/precompile.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; + +contract ContractA { + + address precomplieContarct = 0x0000000000000000000000000000000000000100; + uint256 public number; + event pushLog(string data); + + function callWasm(string memory wasmAddr, string memory msgData,bool requireASuccess) public payable returns (bytes memory response){ + number = number + 1; + (bool success, bytes memory data) = precomplieContarct.call{value: msg.value} ( + abi.encodeWithSignature("callToWasm(string,string)", wasmAddr,msgData) + ); + if (requireASuccess) { + require(success); + string memory res = abi.decode(data,(string)); + emit pushLog(res); + } + number = number + 1; + return data; + } + + function queryWasm(string memory msgData,bool requireASuccess) public payable returns (bytes memory response){ + number = number + 1; + (bool success, bytes memory data) = precomplieContarct.call{value: msg.value} ( + abi.encodeWithSignature("queryToWasm(string)",msgData) + ); + if (requireASuccess) { + require(success); + string memory res = abi.decode(data,(string)); + emit pushLog(res); + } + number = number + 1; + return data; + } + + function callToWasm(string memory wasmAddr, string memory data) public payable returns (string memory response) { + return ""; + } + + function queryToWasm(string memory data) public view returns (string memory response) { + return ""; + } +} + +contract ContractB { + uint256 public number; + + function callWasm(address contractA ,string memory wasmAddr, string memory msgData, bool requireASuccess,bool requireBSuccess) public payable returns (bytes memory response){ + number = number + 1; + (bool success, bytes memory data) = contractA.call{value: msg.value} ( + abi.encodeWithSignature("callWasm(string,string,bool)", wasmAddr,msgData,requireASuccess) + ); + number = number + 1; + if (requireBSuccess) { + require(success); + } + return data; + } + + function queryWasm(address contractA , string memory msgData, bool requireASuccess,bool requireBSuccess) public payable returns (bytes memory response){ + number = number + 1; + (bool success, bytes memory data) = contractA.call{value: msg.value} ( + abi.encodeWithSignature("queryWasm(string,bool)",msgData,requireASuccess) + ); + number = number + 1; + if (requireBSuccess) { + require(success); + } + return data; + } +} diff --git a/app/testdata/precompile.wasm b/app/testdata/precompile.wasm new file mode 100644 index 0000000000..c79e6e9f42 Binary files /dev/null and b/app/testdata/precompile.wasm differ diff --git a/app/testdata/testerc20.sol b/app/testdata/testerc20.sol new file mode 100644 index 0000000000..04117671b6 --- /dev/null +++ b/app/testdata/testerc20.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.7; + +contract Exchange is ERC20 { + address public constant moduleAddress = + address(0xc63cf6c8E1f3DF41085E9d8Af49584dae1432b4f); + + string public wasmContractAddress = "ex14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s6fqu27"; + + event __OKCSendToWasm(string wasmAddr, string recipient, uint256 amount); + + function initialize(string memory denom_, uint8 decimals_) public { + __ERC20_init(denom_, denom_, decimals_); + } + + function native_denom() public view returns (string memory) { + return symbol(); + } + + function updatewasmContractAddress(string memory addr) public { + wasmContractAddress = addr; + } + + function mint(address recipient,uint256 amount) public { + _mint(recipient, amount); + } + + + function mintERC20(string calldata caller, address recipient,uint256 amount) public returns (bool) { + require(msg.sender == moduleAddress); + require(keccak256(abi.encodePacked(caller)) == keccak256(abi.encodePacked(wasmContractAddress))); + _mint(recipient, amount); + return true; + } + + + // send an "amount" of the contract token to recipient on wasm + function send_to_wasm(string memory recipient,string memory wasmContract , uint256 amount) public { + _burn(msg.sender, amount); + emit __OKCSendToWasm(wasmContract,recipient, amount); + } +} + +contract ERC20 { + bool private initialized; + + string private _name; + string private _symbol; + uint8 private _decimals; + uint256 private _totalSupply; + + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); + + function __ERC20_init( + string memory name_, + string memory symbol_, + uint8 decimals_ + ) internal { + require(!initialized, "ERC20: already initialized;"); + initialized = true; + + _name = name_; + _symbol = symbol_; + _decimals = decimals_; + } + + function name() public view virtual returns (string memory) { + return _name; + } + + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + function decimals() public view virtual returns (uint8) { + return _decimals; + } + + function totalSupply() public view virtual returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view virtual returns (uint256) { + return _balances[account]; + } + + function transfer(address to, uint256 amount) + public + virtual + returns (bool) + { + address owner = msg.sender; + _transfer(owner, to, amount); + return true; + } + + function allowance(address owner, address spender) + public + view + virtual + returns (uint256) + { + return _allowances[owner][spender]; + } + + function approve(address spender, uint256 amount) + public + virtual + returns (bool) + { + address owner = msg.sender; + _approve(owner, spender, amount); + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual returns (bool) { + address spender = msg.sender; + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + function increaseAllowance(address spender, uint256 addedValue) + public + virtual + returns (bool) + { + address owner = msg.sender; + _approve(owner, spender, _allowances[owner][spender] + addedValue); + return true; + } + + function decreaseAllowance(address spender, uint256 subtractedValue) + public + virtual + returns (bool) + { + address owner = msg.sender; + uint256 currentAllowance = _allowances[owner][spender]; + require( + currentAllowance >= subtractedValue, + "ERC20: decreased allowance below zero" + ); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + function _transfer( + address from, + address to, + uint256 amount + ) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + uint256 fromBalance = _balances[from]; + require( + fromBalance >= amount, + "ERC20: transfer amount exceeds balance" + ); + unchecked { + _balances[from] = fromBalance - amount; + } + _balances[to] += amount; + + emit Transfer(from, to, amount); + } + + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _totalSupply += amount; + _balances[account] += amount; + emit Transfer(address(0), account, amount); + } + + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + } + _totalSupply -= amount; + + emit Transfer(account, address(0), amount); + } + + function _approve( + address owner, + address spender, + uint256 amount + ) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + function _spendAllowance( + address owner, + address spender, + uint256 amount + ) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require( + currentAllowance >= amount, + "ERC20: insufficient allowance" + ); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } +} diff --git a/dev/vmbridge.sh b/dev/vmbridge.sh index 8b3abd2a97..2bd3c753d9 100755 --- a/dev/vmbridge.sh +++ b/dev/vmbridge.sh @@ -1,4 +1,4 @@ -res=$(exchaincli tx wasm store ./wasm/vmbridge-erc20/artifacts/cw_erc20.wasm --fees 0.01okt --from captain --gas=20000000 -b block -y) +res=$(exchaincli tx wasm store ./wasm/erc20/artifacts/cw_erc20.wasm --fees 0.01okt --from captain --gas=20000000 -b block -y) echo "store--------------" echo $res code_id=$(echo "$res" | jq '.logs[0].events[1].attributes[0].value' | sed 's/\"//g') diff --git a/dev/wasm/erc20/src/contract.rs b/dev/wasm/erc20/src/contract.rs index 772ccdac8e..34cca06b54 100644 --- a/dev/wasm/erc20/src/contract.rs +++ b/dev/wasm/erc20/src/contract.rs @@ -86,12 +86,6 @@ pub fn execute( recipient, amount, } => try_send_to_erc20(deps, env,evmContract,recipient,amount,info), - - ExecuteMsg::CallToEvmMsg { - evmaddr, - calldata, - value, - } => try_call_to_evm(deps, env,evmaddr,calldata,value,info), } } @@ -160,29 +154,7 @@ fn try_mint_cw20( .add_attribute("amount", amount.to_string())) } -fn try_call_to_evm( - deps: DepsMut, - _env: Env, - evmaddr: String, - calldata: String, - value: Uint128, - info: MessageInfo, -) -> Result, ContractError> { - let submsg = SendToEvmMsg { - sender: _env.contract.address.to_string(), - evmaddr: evmaddr.to_string(), - calldata: calldata, - value: value, - }; - - Ok(Response::new() - .add_attribute("action", "call to evm") - .add_attribute("evmaddr", evmaddr.to_string()) - .add_attribute("value", value.to_string()) - .add_message(submsg) - .set_data(b"the result data")) -} fn try_send_to_erc20( deps: DepsMut, diff --git a/dev/wasm/erc20/src/msg.rs b/dev/wasm/erc20/src/msg.rs index abcbdd2085..1d85691378 100644 --- a/dev/wasm/erc20/src/msg.rs +++ b/dev/wasm/erc20/src/msg.rs @@ -48,11 +48,6 @@ pub enum ExecuteMsg { recipient: String, amount: Uint128, }, - CallToEvm { - evmContract: String, - calldata: String, - value: Uint128, - } } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -71,21 +66,6 @@ impl Into> for SendToEvmMsg { } impl CustomMsg for SendToEvmMsg {} -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -#[serde(rename_all = "snake_case")] -pub struct CallToEvmMsg { - pub sender: String, - pub evmaddr: String, - pub calldata: String, - pub value: Uint128, - -} -impl Into> for CallToEvmMsg { - fn into(self) -> CosmosMsg { - CosmosMsg::Custom(self) - } -} -impl CustomMsg for CallToEvmMsg {} #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] diff --git a/dev/wasm/vmbridge-erc20/src/contract.rs b/dev/wasm/vmbridge-erc20/src/contract.rs index 475cf5af98..500c4bf507 100644 --- a/dev/wasm/vmbridge-erc20/src/contract.rs +++ b/dev/wasm/vmbridge-erc20/src/contract.rs @@ -157,11 +157,11 @@ fn try_mint_cw20( recipient: String, amount: Uint128, ) -> Result, ContractError> { - if info.sender.to_string() != EVM_CONTRACT_ADDR.to_string() { - return Err(ContractError::ContractERC20Err { - addr:info.sender.to_string() - }); - } + // if info.sender.to_string() != EVM_CONTRACT_ADDR.to_string() { + // return Err(ContractError::ContractERC20Err { + // addr:info.sender.to_string() + // }); + // } let amount_raw = amount.u128(); let recipient_address = deps.api.addr_validate(recipient.as_str())?; let mut account_balance = read_balance(deps.storage, &recipient_address)?; diff --git a/go.mod b/go.mod index 5b72a16c3d..3049513943 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/99designs/keyring v1.1.6 github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d - github.com/CosmWasm/wasmvm v1.2.4 + github.com/CosmWasm/wasmvm v1.3.0 github.com/VictoriaMetrics/fastcache v1.8.0 github.com/Workiva/go-datastructures v1.0.53 github.com/alicebob/miniredis/v2 v2.17.0 @@ -48,6 +48,7 @@ require ( github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/jmhodges/levigo v1.0.0 github.com/json-iterator/go v1.1.12 + github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada github.com/libp2p/go-buffer-pool v0.1.0 github.com/magiconair/properties v1.8.6 github.com/mattn/go-isatty v0.0.14 @@ -129,6 +130,8 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jonboulle/clockwork v0.2.0 // indirect github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect diff --git a/go.sum b/go.sum index 4b7a29e390..30c01c1dfa 100644 --- a/go.sum +++ b/go.sum @@ -499,9 +499,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTjegPdCiOxVOJtRIy7/8RldvMTsyPYH10= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/libs/cosmos-sdk/baseapp/baseapp.go b/libs/cosmos-sdk/baseapp/baseapp.go index 994cc1f679..fc7c7a0600 100644 --- a/libs/cosmos-sdk/baseapp/baseapp.go +++ b/libs/cosmos-sdk/baseapp/baseapp.go @@ -697,10 +697,16 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context ctx.SetGasMeter(sdk.NewInfiniteGasMeter()) } if app.parallelTxManage.isAsyncDeliverTx && mode == runTxModeDeliverInAsync { + app.parallelTxManage.txByteMpCMIndexLock.RLock() ctx.SetParaMsg(&sdk.ParaMsg{ - HaveCosmosTxInBlock: app.parallelTxManage.haveCosmosTxInBlock, + // Concurrency security issues need to be considered here, + // and there is a small probability that NeedUpdateTXCounter() will be wrong + // due to concurrent reading and writing of pm.txIndexMpUpdateTXCounter (slice), + // but such tx will be rerun, so this case can be ignored. + HaveCosmosTxInBlock: app.parallelTxManage.NeedUpdateTXCounter(), CosmosIndexInBlock: app.parallelTxManage.txByteMpCosmosIndex[string(txBytes)], }) + app.parallelTxManage.txByteMpCMIndexLock.RUnlock() ctx.SetTxBytes(txBytes) ctx.ResetWatcher() } @@ -1013,25 +1019,42 @@ func (app *BaseApp) GetRealTxFromRawTx(rawTx tmtypes.Tx) abci.TxEssentials { return nil } -func (app *BaseApp) GetTxHistoryGasUsed(rawTx tmtypes.Tx) int64 { +func (app *BaseApp) GetTxHistoryGasUsed(rawTx tmtypes.Tx, gasLimit int64) (int64, bool) { tx, err := app.txDecoder(rawTx) if err != nil { - return -1 + return -1, false } txFnSig, toDeployContractSize := tx.GetTxFnSignatureInfo() if txFnSig == nil { - return -1 + return -1, false } hgu := InstanceOfHistoryGasUsedRecordDB().GetHgu(txFnSig) + if hgu == nil { + return -1, false + } + precise := true + if hgu.BlockNum < preciseBlockNum || + (hgu.MaxGas-hgu.MovingAverageGas)*100/hgu.MovingAverageGas > cfg.DynamicConfig.GetPGUPercentageThreshold() || + (hgu.MovingAverageGas-hgu.MinGas)*100/hgu.MinGas > cfg.DynamicConfig.GetPGUPercentageThreshold() { + precise = false + } + var gasWanted int64 if toDeployContractSize > 0 { // if deploy contract case, the history gas used value is unit gas used - return hgu*int64(toDeployContractSize) + int64(1000) + gasWanted = hgu.MovingAverageGas*int64(toDeployContractSize) + int64(1000) + } else { + gasWanted = hgu.MovingAverageGas + } + + // hgu gas can not be greater than gasLimit + if gasWanted > gasLimit { + gasWanted = gasLimit } - return hgu + return gasWanted, precise } func (app *BaseApp) MsgServiceRouter() *MsgServiceRouter { return app.msgServiceRouter } diff --git a/libs/cosmos-sdk/baseapp/baseapp_paralled_test.go b/libs/cosmos-sdk/baseapp/baseapp_paralled_test.go deleted file mode 100644 index d2ae3e815b..0000000000 --- a/libs/cosmos-sdk/baseapp/baseapp_paralled_test.go +++ /dev/null @@ -1,352 +0,0 @@ -package baseapp_test - -import ( - "encoding/json" - "math/big" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi" - ethcmn "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" - "github.com/stretchr/testify/require" - - "github.com/okex/exchain/app/crypto/ethsecp256k1" - types3 "github.com/okex/exchain/app/types" - "github.com/okex/exchain/libs/cosmos-sdk/simapp/helpers" - sdk "github.com/okex/exchain/libs/cosmos-sdk/types" - "github.com/okex/exchain/libs/cosmos-sdk/x/auth" - authexported "github.com/okex/exchain/libs/cosmos-sdk/x/auth/exported" - simapp2 "github.com/okex/exchain/libs/ibc-go/testing/simapp" - abci "github.com/okex/exchain/libs/tendermint/abci/types" - types2 "github.com/okex/exchain/libs/tendermint/types" - "github.com/okex/exchain/x/evm/types" - types4 "github.com/okex/exchain/x/token/types" -) - -type Env struct { - priv []ethsecp256k1.PrivKey - addr []sdk.AccAddress -} -type Chain struct { - app *simapp2.SimApp - priv []ethsecp256k1.PrivKey - addr []sdk.AccAddress - acc []*types3.EthAccount - seq []uint64 - num []uint64 - chainIdStr string - chainIdInt *big.Int - ContractAddr []byte -} - -func NewChain(env *Env) *Chain { - types2.UnittestOnlySetMilestoneVenusHeight(-1) - types2.UnittestOnlySetMilestoneVenus1Height(-1) - chain := new(Chain) - chain.acc = make([]*types3.EthAccount, 10) - chain.priv = make([]ethsecp256k1.PrivKey, 10) - chain.addr = make([]sdk.AccAddress, 10) - chain.seq = make([]uint64, 10) - chain.num = make([]uint64, 10) - genAccs := []authexported.GenesisAccount{} - for i := 0; i < 10; i++ { - chain.acc[i] = &types3.EthAccount{ - BaseAccount: &auth.BaseAccount{ - Address: env.addr[i], - Coins: sdk.Coins{sdk.NewInt64Coin("okt", 1000000)}, - }, - //CodeHash: []byte{1, 2}, - } - genAccs = append(genAccs, chain.acc[i]) - chain.priv[i] = env.priv[i] - chain.addr[i] = env.addr[i] - chain.seq[i] = 0 - chain.num[i] = uint64(i) - } - chain.chainIdStr = "ethermint-3" - chain.chainIdInt = big.NewInt(3) - - chain.app = simapp2.SetupWithGenesisAccounts(genAccs, sdk.NewDecCoins(sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(1000000, 0)))) - //header := abci.Header{Height: app.LastBlockHeight() + 1, ChainID: chainIdStr} - - chain.app.BaseApp.Commit(abci.RequestCommit{}) - return chain -} - -func createEthTx(t *testing.T, chain *Chain, i int) []byte { - amount, gasPrice, gasLimit := int64(1024), int64(2048), uint64(100000) - addrTo := ethcmn.BytesToAddress(chain.priv[i+1].PubKey().Address().Bytes()) - msg := types.NewMsgEthereumTx(chain.seq[i], &addrTo, big.NewInt(amount), gasLimit, big.NewInt(gasPrice), []byte("test")) - chain.seq[i]++ - err := msg.Sign(chain.chainIdInt, chain.priv[i].ToECDSA()) - require.NoError(t, err) - rawtx, err := rlp.EncodeToBytes(&msg) - require.NoError(t, err) - - return rawtx -} - -//contract Storage { -//uint256 number; -///** -// * @dev Store value in variable -// * @param num value to store -// */ -//function store(uint256 num) public { -//number = num; -//} -//function add() public { -//number += 1; -//} -///** -// * @dev Return value -// * @return value of 'number' -// */ -//function retrieve() public view returns (uint256){ -//return number; -//} -//} -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"}]` - -func deployContract(t *testing.T, chain *Chain, i int) []byte { - // Deploy contract - Owner.sol - gasLimit := uint64(10000000000000) - gasPrice := big.NewInt(10000) - - sender := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) - - bytecode := ethcmn.FromHex("608060405234801561001057600080fd5b50610217806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631003e2d2146100465780632e64cec1146100625780636057361d14610080575b600080fd5b610060600480360381019061005b9190610105565b61009c565b005b61006a6100b7565b6040516100779190610141565b60405180910390f35b61009a60048036038101906100959190610105565b6100c0565b005b806000808282546100ad919061018b565b9250508190555050565b60008054905090565b8060008190555050565b600080fd5b6000819050919050565b6100e2816100cf565b81146100ed57600080fd5b50565b6000813590506100ff816100d9565b92915050565b60006020828403121561011b5761011a6100ca565b5b6000610129848285016100f0565b91505092915050565b61013b816100cf565b82525050565b60006020820190506101566000830184610132565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610196826100cf565b91506101a1836100cf565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101d6576101d561015c565b5b82820190509291505056fea2646970667358221220318e29d6b4806f219eedd0cc861e82c13e28eb7f42161f2c780dc539b0e32b4e64736f6c634300080a0033") - msg := types.NewMsgEthereumTx(chain.seq[i], &sender, big.NewInt(0), gasLimit, gasPrice, bytecode) - err := msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) - require.NoError(t, err) - chain.seq[i]++ - rawTx, err := rlp.EncodeToBytes(&msg) - require.NoError(t, err) - return rawTx -} - -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"}` - -type CompiledContract struct { - ABI abi.ABI - Bin string -} - -func UnmarshalContract(t *testing.T) *CompiledContract { - cc := new(CompiledContract) - err := json.Unmarshal([]byte(contractJson), cc) - require.NoError(t, err) - return cc -} - -func callContract(t *testing.T, chain *Chain, i int) []byte { - gasLimit := uint64(10000000000000) - gasPrice := big.NewInt(10000) - //to := ethcmn.HexToAddress(chain.priv[i].PubKey().Address().String()) - to := ethcmn.BytesToAddress(chain.ContractAddr) - cc := UnmarshalContract(t) - data, err := cc.ABI.Pack("add") - require.NoError(t, err) - msg := types.NewMsgEthereumTx(chain.seq[i], &to, big.NewInt(0), gasLimit, gasPrice, data) - err = msg.Sign(big.NewInt(3), chain.priv[i].ToECDSA()) - require.NoError(t, err) - chain.seq[i]++ - rawTx, err := rlp.EncodeToBytes(&msg) - require.NoError(t, err) - return rawTx -} - -func createCosmosTx(t *testing.T, chain *Chain, i int) []byte { - msg := types4.NewMsgTokenSend(chain.addr[i], chain.addr[i+1], sdk.Coins{sdk.NewInt64Coin("okt", 10)}) - - tx := helpers.GenTx( - []sdk.Msg{msg}, - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)}, - helpers.DefaultGenTxGas, - chain.chainIdStr, - []uint64{chain.num[i]}, - []uint64{chain.seq[i]}, - chain.priv[i], - ) - chain.seq[i]++ - - txBytes, err := chain.app.Codec().MarshalBinaryLengthPrefixed(tx) - require.Nil(t, err) - return txBytes -} - -func runtxs(chain *Chain, rawTxs [][]byte, isParalle bool) []*abci.ResponseDeliverTx { - header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr} - chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) - ret := []*abci.ResponseDeliverTx{} - if isParalle { - ret = chain.app.BaseApp.ParallelTxs(rawTxs, false) - } else { - for _, tx := range rawTxs { - r := chain.app.BaseApp.DeliverTx(abci.RequestDeliverTx{Tx: tx}) - ret = append(ret, &r) - } - } - chain.app.BaseApp.EndBlock(abci.RequestEndBlock{}) - chain.app.BaseApp.Commit(abci.RequestCommit{}) - - return ret -} - -func DeployContractAndGetContractAddress(t *testing.T, chain *Chain) { - rawTxs := [][]byte{} - rawTxs = append(rawTxs, deployContract(t, chain, 0)) - r := runtxs(chain, rawTxs, false) - - for _, e := range r[0].Events { - for _, v := range e.Attributes { - if string(v.Key) == "recipient" { - chain.ContractAddr = v.Value - } - } - } -} - -func TestParalledTxs(t *testing.T) { - env := new(Env) - accountNum := 10 - env.priv = make([]ethsecp256k1.PrivKey, 10) - env.addr = make([]sdk.AccAddress, 10) - for i := 0; i < accountNum; i++ { - priv, _ := ethsecp256k1.GenerateKey() - addr := sdk.AccAddress(priv.PubKey().Address()) - env.priv[i] = priv - env.addr[i] = addr - } - - chainA, chainB := NewChain(env), NewChain(env) - //deploy contract on chainA and chainB - DeployContractAndGetContractAddress(t, chainA) - DeployContractAndGetContractAddress(t, chainB) - - testCases := []struct { - name string - malleate func(t *testing.T, chain *Chain, isParallel bool) ([]byte, []byte) - }{ - { - "five txs one group:a->b b->c c->d d->e e->f", - func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) { - - rawTxs := [][]byte{} - for i := 0; i < 5; i++ { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - - header := abci.Header{Height: chain.app.LastBlockHeight() + 1, ChainID: chain.chainIdStr} - chain.app.BaseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) - ret := runtxs(chain, rawTxs, isParalled) - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - { - "five txs two group, no conflict:a->b b->c / d->e e->f f->g", - func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) { - rawTxs := [][]byte{} - //one group 3txs - for i := 0; i < 3; i++ { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - //one group 2txs - for i := 8; i > 6; i-- { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - ret := runtxs(chain, rawTxs, isParalled) - - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - { - "five txs two group, has conflict", - func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) { - rawTxs := [][]byte{} - - //one group 3txs - for i := 0; i < 3; i++ { - rawTxs = append(rawTxs, callContract(t, chain, i)) - } - ////one group 2txs - for i := 8; i > 6; i-- { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - ret := runtxs(chain, rawTxs, isParalled) - - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - { - "five txs one group with cosmos tx", - func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) { - rawTxs := [][]byte{} - //one group 3txs - for i := 0; i < 2; i++ { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - //cosmostx - rawTxs = append(rawTxs, createCosmosTx(t, chain, 2)) - //one group 2txs - for i := 3; i < 5; i++ { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - ret := runtxs(chain, rawTxs, isParalled) - - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - { - "five txs two group, no conflict with cosmos tx", - func(t *testing.T, chain *Chain, isParalle bool) ([]byte, []byte) { - rawTxs := [][]byte{} - //one group 3txs(2eth and 1 cosmos) - for i := 0; i < 2; i++ { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - //cosmos tx - rawTxs = append(rawTxs, createCosmosTx(t, chain, 2)) - //one group 2txs - for i := 8; i > 6; i-- { - rawTxs = append(rawTxs, createEthTx(t, chain, i)) - } - ret := runtxs(chain, rawTxs, isParalle) - - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - { - "five txs two group, has conflict with cosmos tx", - func(t *testing.T, chain *Chain, isParalled bool) ([]byte, []byte) { - rawTxs := [][]byte{} - - //one group 3txs:2 evm tx with conflict, one cosmos tx - for i := 0; i < 2; i++ { - rawTxs = append(rawTxs, callContract(t, chain, i)) - } - rawTxs = append(rawTxs, createCosmosTx(t, chain, 2)) - ////one group 2txs - for i := 8; i > 6; i-- { - rawTxs = append(rawTxs, createCosmosTx(t, chain, i)) - } - ret := runtxs(chain, rawTxs, isParalled) - - return resultHash(ret), chain.app.BaseApp.LastCommitID().Hash - }, - }, - } - for _, tc := range testCases { - resultHashA, appHashA := tc.malleate(t, chainA, true) - resultHashB, appHashB := tc.malleate(t, chainB, false) - require.True(t, reflect.DeepEqual(resultHashA, resultHashB)) - require.True(t, reflect.DeepEqual(appHashA, appHashB)) - } - -} - -func resultHash(txs []*abci.ResponseDeliverTx) []byte { - results := types2.NewResults(txs) - return results.Hash() -} diff --git a/libs/cosmos-sdk/baseapp/baseapp_parallel.go b/libs/cosmos-sdk/baseapp/baseapp_parallel.go index 05fb432253..2baeb56d8b 100644 --- a/libs/cosmos-sdk/baseapp/baseapp_parallel.go +++ b/libs/cosmos-sdk/baseapp/baseapp_parallel.go @@ -24,14 +24,14 @@ var ( ) type extraDataForTx struct { - supportPara bool - fee sdk.Coins - isEvm bool - isE2C bool - from string - to string - stdTx sdk.Tx - decodeErr error + supportPara bool + fee sdk.Coins + isEvm bool + needUpdateTXCounter bool + from string + to string + stdTx sdk.Tx + decodeErr error } type txWithIndex struct { @@ -71,15 +71,15 @@ func (app *BaseApp) getExtraDataByTxs(txs [][]byte) { app.blockDataCache.SetTx(txBytes, tx) } - coin, isEvm, isE2C, s, toAddr, _, supportPara := app.getTxFeeAndFromHandler(app.getContextForTx(runTxModeDeliver, txBytes), tx) + coin, isEvm, needUpdateTXCounter, s, toAddr, _, supportPara := app.getTxFeeAndFromHandler(app.getContextForTx(runTxModeDeliver, txBytes), tx) para.extraTxsInfo[index] = &extraDataForTx{ - supportPara: supportPara, - fee: coin, - isEvm: isEvm, - isE2C: isE2C, - from: s, - to: toAddr, - stdTx: tx, + supportPara: supportPara, + fee: coin, + isEvm: isEvm, + needUpdateTXCounter: needUpdateTXCounter, + from: s, + to: toAddr, + stdTx: tx, } wg.Done() } @@ -129,49 +129,45 @@ func Union(x string, yString string) { // calGroup cal group by txs func (app *BaseApp) calGroup() { - para := app.parallelTxManage + pm := app.parallelTxManage rootAddr = make(map[string]string, 0) - para.cosmosTxIndexInBlock = 0 - for index, tx := range para.extraTxsInfo { + pm.cosmosTxIndexInBlock = 0 + for index, tx := range pm.extraTxsInfo { if tx.supportPara { //evmTx & wasmTx Union(tx.from, tx.to) } else { - para.haveCosmosTxInBlock = true app.parallelTxManage.putResult(index, &executeResult{paraMsg: &sdk.ParaMsg{}, msIsNil: true}) } - if (!tx.isEvm && tx.supportPara) || tx.isE2C { - // means wasm or e2c tx - para.haveCosmosTxInBlock = true + if tx.needUpdateTXCounter { + pm.txIndexMpUpdateTXCounter[index] = true + pm.txByteMpCosmosIndex[string(pm.txs[index])] = pm.cosmosTxIndexInBlock + pm.cosmosTxIndexInBlock++ } - if !tx.isEvm || tx.isE2C { - para.txByteMpCosmosIndex[string(para.txs[index])] = para.cosmosTxIndexInBlock - para.cosmosTxIndexInBlock++ - } } addrToID := make(map[string]int, 0) - for index, txInfo := range para.extraTxsInfo { + for index, txInfo := range pm.extraTxsInfo { if !txInfo.supportPara { continue } rootAddr := Find(txInfo.from) id, exist := addrToID[rootAddr] if !exist { - id = len(para.groupList) + id = len(pm.groupList) addrToID[rootAddr] = id } - para.groupList[id] = append(para.groupList[id], index) - para.txIndexWithGroup[index] = id + pm.groupList[id] = append(pm.groupList[id], index) + pm.txIndexWithGroup[index] = id } - groupSize := len(para.groupList) + groupSize := len(pm.groupList) for groupIndex := 0; groupIndex < groupSize; groupIndex++ { - list := para.groupList[groupIndex] + list := pm.groupList[groupIndex] for index := 0; index < len(list); index++ { if index+1 <= len(list)-1 { app.parallelTxManage.nextTxInGroup[list[index]] = list[index+1] @@ -247,7 +243,7 @@ func (app *BaseApp) runTxs() []*abci.ResponseDeliverTx { break } isReRun := false - if pm.isConflict(res) || overFlow(currentGas, res.resp.GasUsed, maxGas) { + if pm.isConflict(res) || overFlow(currentGas, res.resp.GasUsed, maxGas) || pm.haveAnteErrTx { rerunIdx++ isReRun = true // conflict rerun tx @@ -256,8 +252,10 @@ func (app *BaseApp) runTxs() []*abci.ResponseDeliverTx { } res = app.deliverTxWithCache(pm.upComingTxIndex) } + if res.paraMsg.AnteErr != nil { res.msIsNil = true + pm.handleAnteErrTx(pm.txIndexMpUpdateTXCounter[pm.upComingTxIndex]) } pm.deliverTxs[pm.upComingTxIndex] = &res.resp @@ -268,7 +266,7 @@ func (app *BaseApp) runTxs() []*abci.ResponseDeliverTx { app.deliverState.ctx.BlockGasMeter().ConsumeGas(sdk.Gas(res.resp.GasUsed), "unexpected error") pm.blockGasMeterMu.Unlock() - pm.SetCurrentIndex(pm.upComingTxIndex, res) + pm.SetCurrentIndexRes(pm.upComingTxIndex, res) if !res.msIsNil { pm.currTxFee = pm.currTxFee.Add(pm.extraTxsInfo[pm.upComingTxIndex].fee.Sub(pm.finalResult[pm.upComingTxIndex].paraMsg.RefundFee)...) @@ -320,7 +318,7 @@ func (app *BaseApp) runTxs() []*abci.ResponseDeliverTx { ctx, _ := app.cacheTxContext(app.getContextForTx(runTxModeDeliver, []byte{}), []byte{}) ctx.SetMultiStore(app.parallelTxManage.cms) - if app.parallelTxManage.haveCosmosTxInBlock { + if app.parallelTxManage.NeedUpdateTXCounter() { app.updateCosmosTxCount(ctx, app.parallelTxManage.cosmosTxIndexInBlock-1) } @@ -454,16 +452,19 @@ func newExecuteResult(r abci.ResponseDeliverTx, ms sdk.CacheMultiStore, counter } type parallelTxManager struct { - blockHeight int64 - groupTasks []*groupTask - blockGasMeterMu sync.Mutex - haveCosmosTxInBlock bool - isAsyncDeliverTx bool - txs [][]byte - txSize int - alreadyEnd bool - cosmosTxIndexInBlock int - txByteMpCosmosIndex map[string]int + blockHeight int64 + groupTasks []*groupTask + blockGasMeterMu sync.Mutex + isAsyncDeliverTx bool + txs [][]byte + txSize int + alreadyEnd bool + + cosmosTxIndexInBlock int + txByteMpCMIndexLock sync.RWMutex + txByteMpCosmosIndex map[string]int + txIndexMpUpdateTXCounter []bool + haveAnteErrTx bool resultCh chan int resultCb func(data int) @@ -634,6 +635,8 @@ func newParallelTxManager() *parallelTxManager { txIndexWithGroup: make(map[int]int), resultCh: make(chan int, maxTxResultInChan), + txByteMpCMIndexLock: sync.RWMutex{}, + blockMpCache: newCacheRWSetList(), chainMpCache: newCacheRWSetList(), blockMultiStores: newCacheMultiStoreList(), @@ -764,7 +767,6 @@ func (pm *parallelTxManager) init(txs [][]byte, blockHeight int64, deliverStateM txSize := len(txs) pm.blockHeight = blockHeight pm.groupTasks = make([]*groupTask, 0) - pm.haveCosmosTxInBlock = false pm.isAsyncDeliverTx = true pm.txs = txs pm.txSize = txSize @@ -788,6 +790,8 @@ func (pm *parallelTxManager) init(txs [][]byte, blockHeight int64, deliverStateM pm.txByteMpCosmosIndex = make(map[string]int, 0) pm.nextTxInGroup = make(map[int]int) + pm.haveAnteErrTx = false + pm.txIndexMpUpdateTXCounter = make([]bool, txSize) pm.extraTxsInfo = make([]*extraDataForTx, txSize) pm.txReps = make([]*executeResult, txSize) pm.finalResult = make([]*executeResult, txSize) @@ -815,7 +819,7 @@ func (pm *parallelTxManager) getParentMsByTxIndex(txIndex int) (sdk.CacheMultiSt return ms, useCurrent } -func (pm *parallelTxManager) SetCurrentIndex(txIndex int, res *executeResult) { +func (pm *parallelTxManager) SetCurrentIndexRes(txIndex int, res *executeResult) { if res.msIsNil { return } @@ -837,3 +841,29 @@ func (pm *parallelTxManager) SetCurrentIndex(txIndex int, res *executeResult) { } } + +func (pm *parallelTxManager) NeedUpdateTXCounter() bool { + res := false + for _, v := range pm.txIndexMpUpdateTXCounter { + res = res || v + } + return res +} + +// When an AnteErr tx is encountered, this tx will be discarded, +// and the cosmosIndex of the remaining tx needs to be corrected. +func (pm *parallelTxManager) handleAnteErrTx(curTxNeedUpdateTXCounter bool) { + pm.haveAnteErrTx = true + pm.txIndexMpUpdateTXCounter[pm.upComingTxIndex] = false + + if curTxNeedUpdateTXCounter { + pm.cosmosTxIndexInBlock-- + pm.txByteMpCMIndexLock.Lock() + for index, tx := range pm.txs { + if _, ok := pm.txByteMpCosmosIndex[string(tx)]; ok && index > pm.upComingTxIndex { + pm.txByteMpCosmosIndex[string(tx)]-- + } + } + pm.txByteMpCMIndexLock.Unlock() + } +} diff --git a/libs/cosmos-sdk/baseapp/gasuseddb.go b/libs/cosmos-sdk/baseapp/gasuseddb.go index a224a6047e..3ca9936966 100644 --- a/libs/cosmos-sdk/baseapp/gasuseddb.go +++ b/libs/cosmos-sdk/baseapp/gasuseddb.go @@ -1,10 +1,11 @@ package baseapp import ( - "encoding/binary" + "log" "path/filepath" "sync" + "github.com/gogo/protobuf/proto" lru "github.com/hashicorp/golang-lru" "github.com/okex/exchain/libs/cosmos-sdk/client/flags" sdk "github.com/okex/exchain/libs/cosmos-sdk/types" @@ -17,13 +18,15 @@ const ( HistoryGasUsedDBName = "hgu" FlagGasUsedFactor = "gu_factor" + preciseBlockNum = 20 ) var ( - once sync.Once - GasUsedFactor = 0.4 - jobQueueLen = 10 - cacheSize = 10000 + once sync.Once + GasUsedFactor = 0.4 + regressionFactor = 0.05 + jobQueueLen = 10 + cacheSize = 10000 historyGasUsedRecordDB HistoryGasUsedRecordDB ) @@ -35,7 +38,7 @@ type gasKey struct { type HistoryGasUsedRecordDB struct { latestGuMtx sync.Mutex - latestGu map[string]int64 + latestGu map[string][]int64 cache *lru.Cache guDB db.DB @@ -46,7 +49,7 @@ func InstanceOfHistoryGasUsedRecordDB() *HistoryGasUsedRecordDB { once.Do(func() { cache, _ := lru.New(cacheSize) historyGasUsedRecordDB = HistoryGasUsedRecordDB{ - latestGu: make(map[string]int64), + latestGu: make(map[string][]int64), cache: cache, guDB: initDb(), jobQueue: make(chan func(), jobQueueLen), @@ -58,13 +61,13 @@ func InstanceOfHistoryGasUsedRecordDB() *HistoryGasUsedRecordDB { func (h *HistoryGasUsedRecordDB) UpdateGasUsed(key []byte, gasUsed int64) { h.latestGuMtx.Lock() - h.latestGu[string(key)] = gasUsed + h.latestGu[string(key)] = append(h.latestGu[string(key)], gasUsed) h.latestGuMtx.Unlock() } -func (h *HistoryGasUsedRecordDB) GetHgu(key []byte) int64 { +func (h *HistoryGasUsedRecordDB) GetHgu(key []byte) *HguRecord { hgu, cacheHit := h.getHgu(key) - if !cacheHit && hgu != -1 { + if hgu != nil && !cacheHit { // add to cache before returning hgu h.cache.Add(string(key), hgu) } @@ -75,43 +78,71 @@ func (h *HistoryGasUsedRecordDB) FlushHgu() { if len(h.latestGu) == 0 { return } - latestGasKeys := make([]gasKey, len(h.latestGu)) - index := 0 - for key, gas := range h.latestGu { - latestGasKeys[index] = gasKey{ - gas: gas, + latestGasKeys := make([]gasKey, 0, len(h.latestGu)) + for key, allGas := range h.latestGu { + latestGasKeys = append(latestGasKeys, gasKey{ + gas: meanGas(allGas), key: key, - } - index++ + }) delete(h.latestGu, key) } h.jobQueue <- func() { h.flushHgu(latestGasKeys...) } // closure } -func (h *HistoryGasUsedRecordDB) getHgu(key []byte) (hgu int64, fromCache bool) { +func (h *HistoryGasUsedRecordDB) getHgu(key []byte) (hgu *HguRecord, fromCache bool) { v, ok := h.cache.Get(string(key)) if ok { - return v.(int64), true + return v.(*HguRecord), true } data, err := h.guDB.Get(key) if err != nil || len(data) == 0 { - return -1, false + return nil, false } - return bytesToInt64(data), false + var r HguRecord + err = proto.Unmarshal(data, &r) + if err != nil { + return nil, false + } + return &r, false } func (h *HistoryGasUsedRecordDB) flushHgu(gks ...gasKey) { for _, gk := range gks { hgu, cacheHit := h.getHgu([]byte(gk.key)) - // avgGas = 0.4 * newGas + 0.6 * oldGas.The value of wasm store contract is too small and need to be rounded up. - avgGas := int64(GasUsedFactor*float64(gk.gas) + (1.0-GasUsedFactor)*float64(hgu) + 0.6) - // add to cache if hit - if cacheHit { - h.cache.Add(gk.key, avgGas) + if hgu == nil { + hgu = &HguRecord{ + MaxGas: gk.gas, + MinGas: gk.gas, + MovingAverageGas: gk.gas, + } + } else { + // MovingAverageGas = 0.4 * newGas + 0.6 * oldMovingAverageGas + hgu.MovingAverageGas = int64(GasUsedFactor*float64(gk.gas) + (1.0-GasUsedFactor)*float64(hgu.MovingAverageGas)) + // MaxGas = 0.05 * MovingAverageGas + 0.95 * oldMaxGas + hgu.MaxGas = int64(regressionFactor*float64(hgu.MovingAverageGas) + (1.0-regressionFactor)*float64(hgu.MaxGas)) + // MinGas = 0.05 * MovingAverageGas + 0.95 * oldMinGas + hgu.MinGas = int64(regressionFactor*float64(hgu.MovingAverageGas) + (1.0-regressionFactor)*float64(hgu.MinGas)) + hgu.BlockNum++ + if gk.gas > hgu.MaxGas { + hgu.MaxGas = gk.gas + } else if gk.gas < hgu.MinGas { + hgu.MinGas = gk.gas + } + // add to cache if hit + if cacheHit { + h.cache.Add(gk.key, hgu) + } + } + + data, err := proto.Marshal(hgu) + if err != nil { + log.Println("flushHgu marshal error:", err) + continue } - h.guDB.Set([]byte(gk.key), int64ToBytes(avgGas)) + + h.guDB.Set([]byte(gk.key), data) } } @@ -132,12 +163,10 @@ func initDb() db.DB { return db } -func int64ToBytes(i int64) []byte { - var buf = make([]byte, 8) - binary.BigEndian.PutUint64(buf, uint64(i)) - return buf -} - -func bytesToInt64(buf []byte) int64 { - return int64(binary.BigEndian.Uint64(buf)) +func meanGas(allGas []int64) int64 { + var totalGas int64 + for _, gas := range allGas { + totalGas += gas + } + return totalGas / int64(len(allGas)) } diff --git a/libs/cosmos-sdk/baseapp/gasuseddb_test.go b/libs/cosmos-sdk/baseapp/gasuseddb_test.go new file mode 100644 index 0000000000..7383c53c13 --- /dev/null +++ b/libs/cosmos-sdk/baseapp/gasuseddb_test.go @@ -0,0 +1,118 @@ +package baseapp + +import ( + "github.com/stretchr/testify/require" + "os" + "testing" + "time" +) + +type hguTestCase struct { + key string + gasUsed int64 +} + +func TestHGU(t *testing.T) { + t.Cleanup(func() { + os.RemoveAll(HistoryGasUsedDbDir) + }) + testCase := []hguTestCase{ + {"test0", 1}, + {"test0", 2}, + {"test0", 3}, + {"test0", 4}, + {"test0", 5}, + {"test1", 10}, + {"test2", 20}, + } + expected := []struct { + key string + record HguRecord + }{ + { + "test0", + HguRecord{ + MaxGas: 3, + MinGas: 3, + MovingAverageGas: 3, + }, + }, + { + "test1", + HguRecord{ + MaxGas: 10, + MinGas: 10, + MovingAverageGas: 10, + }, + }, + { + "test2", + HguRecord{ + MaxGas: 20, + MinGas: 20, + MovingAverageGas: 20, + }, + }, + } + hguDB := InstanceOfHistoryGasUsedRecordDB() + for _, c := range testCase { + hguDB.UpdateGasUsed([]byte(c.key), c.gasUsed) + } + for _, c := range expected { + r, ok := hguDB.getHgu([]byte(c.key)) + require.False(t, ok) + require.Nil(t, r) + } + + hguDB.FlushHgu() + time.Sleep(time.Second) + for _, c := range expected { + r, ok := hguDB.getHgu([]byte(c.key)) + require.False(t, ok) + require.Equal(t, c.record, *r) + } + + for _, c := range expected { + r := hguDB.GetHgu([]byte(c.key)) + require.Equal(t, c.record, *r) + } + + for _, c := range expected { + r, ok := hguDB.getHgu([]byte(c.key)) + require.True(t, ok) + require.Equal(t, c.record, *r) + } + + hguDB.UpdateGasUsed([]byte("test0"), 1) + hguDB.FlushHgu() + hguDB.UpdateGasUsed([]byte("test0"), 10) + hguDB.FlushHgu() + time.Sleep(time.Second) + + r, ok := hguDB.getHgu([]byte("test0")) + require.True(t, ok) + require.Equal(t, int64(10), r.MaxGas) + require.Equal(t, int64(1), r.MinGas) + require.Equal(t, int64(5), r.MovingAverageGas) + require.Equal(t, int64(2), r.BlockNum) +} + +func TestMovingAverageGas(t *testing.T) { + t.Cleanup(func() { + os.RemoveAll(HistoryGasUsedDbDir) + }) + testKey := []byte("test") + cases := []int64{21000, 23000, 25000, 33000, 37000, 53000} + hguDB := InstanceOfHistoryGasUsedRecordDB() + for _, gas := range cases { + hguDB.UpdateGasUsed(testKey, gas) + hguDB.FlushHgu() + } + time.Sleep(time.Second) + + r := hguDB.GetHgu(testKey) + require.Equal(t, int64(53000), r.MaxGas) + require.Equal(t, int64(22811), r.MinGas) + require.Equal(t, int64(39816), r.MovingAverageGas) + require.Equal(t, int64(5), r.BlockNum) +} diff --git a/libs/cosmos-sdk/baseapp/hgu.pb.go b/libs/cosmos-sdk/baseapp/hgu.pb.go new file mode 100644 index 0000000000..612cdf636c --- /dev/null +++ b/libs/cosmos-sdk/baseapp/hgu.pb.go @@ -0,0 +1,102 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: hgu.proto + +package baseapp + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type HguRecord struct { + MaxGas int64 `protobuf:"varint,1,opt,name=MaxGas,proto3" json:"MaxGas,omitempty"` + MinGas int64 `protobuf:"varint,2,opt,name=MinGas,proto3" json:"MinGas,omitempty"` + MovingAverageGas int64 `protobuf:"varint,3,opt,name=MovingAverageGas,proto3" json:"MovingAverageGas,omitempty"` + BlockNum int64 `protobuf:"varint,4,opt,name=BlockNum,proto3" json:"BlockNum,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HguRecord) Reset() { *m = HguRecord{} } +func (m *HguRecord) String() string { return proto.CompactTextString(m) } +func (*HguRecord) ProtoMessage() {} +func (*HguRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_e71af30b0c14e8b0, []int{0} +} +func (m *HguRecord) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HguRecord.Unmarshal(m, b) +} +func (m *HguRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HguRecord.Marshal(b, m, deterministic) +} +func (m *HguRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_HguRecord.Merge(m, src) +} +func (m *HguRecord) XXX_Size() int { + return xxx_messageInfo_HguRecord.Size(m) +} +func (m *HguRecord) XXX_DiscardUnknown() { + xxx_messageInfo_HguRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_HguRecord proto.InternalMessageInfo + +func (m *HguRecord) GetMaxGas() int64 { + if m != nil { + return m.MaxGas + } + return 0 +} + +func (m *HguRecord) GetMinGas() int64 { + if m != nil { + return m.MinGas + } + return 0 +} + +func (m *HguRecord) GetMovingAverageGas() int64 { + if m != nil { + return m.MovingAverageGas + } + return 0 +} + +func (m *HguRecord) GetBlockNum() int64 { + if m != nil { + return m.BlockNum + } + return 0 +} + +func init() { + proto.RegisterType((*HguRecord)(nil), "HguRecord") +} + +func init() { proto.RegisterFile("hgu.proto", fileDescriptor_e71af30b0c14e8b0) } + +var fileDescriptor_e71af30b0c14e8b0 = []byte{ + // 136 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcc, 0x48, 0x2f, 0xd5, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x66, 0xe4, 0xe2, 0xf4, 0x48, 0x2f, 0x0d, 0x4a, 0x4d, + 0xce, 0x2f, 0x4a, 0x11, 0x12, 0xe3, 0x62, 0xf3, 0x4d, 0xac, 0x70, 0x4f, 0x2c, 0x96, 0x60, 0x54, + 0x60, 0xd4, 0x60, 0x0e, 0x82, 0xf2, 0xc0, 0xe2, 0x99, 0x79, 0x20, 0x71, 0x26, 0xa8, 0x38, 0x98, + 0x27, 0xa4, 0xc5, 0x25, 0xe0, 0x9b, 0x5f, 0x96, 0x99, 0x97, 0xee, 0x58, 0x96, 0x5a, 0x94, 0x98, + 0x9e, 0x0a, 0x52, 0xc1, 0x0c, 0x56, 0x81, 0x21, 0x2e, 0x24, 0xc5, 0xc5, 0xe1, 0x94, 0x93, 0x9f, + 0x9c, 0xed, 0x57, 0x9a, 0x2b, 0xc1, 0x02, 0x56, 0x03, 0xe7, 0x3b, 0x71, 0x46, 0xb1, 0x27, 0x25, + 0x16, 0xa7, 0x26, 0x16, 0x14, 0x24, 0xb1, 0x81, 0xdd, 0x65, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, + 0x82, 0xd0, 0xc9, 0x2f, 0xa4, 0x00, 0x00, 0x00, +} diff --git a/libs/cosmos-sdk/baseapp/proto/hgu.proto b/libs/cosmos-sdk/baseapp/proto/hgu.proto new file mode 100644 index 0000000000..f9d9d933e0 --- /dev/null +++ b/libs/cosmos-sdk/baseapp/proto/hgu.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; +option go_package = "baseapp"; + +message HguRecord { + int64 MaxGas = 1; + int64 MinGas = 2; + int64 MovingAverageGas = 3; + int64 BlockNum = 4; +} diff --git a/libs/cosmos-sdk/server/start.go b/libs/cosmos-sdk/server/start.go index ee63cd74fb..055e4f84e0 100644 --- a/libs/cosmos-sdk/server/start.go +++ b/libs/cosmos-sdk/server/start.go @@ -72,7 +72,8 @@ const ( FlagFastSyncGap = "fastsync-gap" - FlagEventBlockTime = "event-block-time" + FlagEventBlockTime = "event-block-time" + FlagStartFromSnapshot = "start-from-snapshot" ) // StartCmd runs the service passed in, either stand-alone or in-process with diff --git a/libs/cosmos-sdk/server/start_okchain.go b/libs/cosmos-sdk/server/start_okchain.go index 687b258a1b..e6e7d33db8 100644 --- a/libs/cosmos-sdk/server/start_okchain.go +++ b/libs/cosmos-sdk/server/start_okchain.go @@ -247,6 +247,7 @@ func RegisterServerFlags(cmd *cobra.Command) *cobra.Command { viper.BindPFlag(FlagEvmImportMode, cmd.Flags().Lookup(FlagEvmImportMode)) viper.BindPFlag(FlagEvmImportPath, cmd.Flags().Lookup(FlagEvmImportPath)) viper.BindPFlag(FlagGoroutineNum, cmd.Flags().Lookup(FlagGoroutineNum)) + viper.BindPFlag(FlagStartFromSnapshot, cmd.Flags().Lookup(FlagStartFromSnapshot)) cmd.Flags().Int(state.FlagDeliverTxsExecMode, 0, "Execution mode for deliver txs, (0:serial[default], 1:deprecated, 2:parallel)") cmd.Flags().Bool(state.FlagEnableConcurrency, false, "Enable concurrency for deliver txs") @@ -275,6 +276,8 @@ func RegisterServerFlags(cmd *cobra.Command) *cobra.Command { cmd.Flags().Int64(FlagCommitGapHeight, 100, "Block interval to commit cached data into db, affects iavl & mpt") cmd.Flags().Int64(FlagFastSyncGap, 20, "Block height interval to switch fast-sync mode") + cmd.Flags().String(FlagStartFromSnapshot, "", "Snapshot URL which uses to start node") + cmd.Flags().MarkHidden(FlagStartFromSnapshot) return cmd } diff --git a/libs/cosmos-sdk/types/context.go b/libs/cosmos-sdk/types/context.go index 61e6ef8a03..d07e66bdeb 100644 --- a/libs/cosmos-sdk/types/context.go +++ b/libs/cosmos-sdk/types/context.go @@ -2,17 +2,17 @@ package types import ( "context" - "github.com/ethereum/go-ethereum/core/vm" "sync" "time" + "github.com/ethereum/go-ethereum/core/vm" "github.com/gogo/protobuf/proto" - "github.com/okex/exchain/libs/system/trace" - abci "github.com/okex/exchain/libs/tendermint/abci/types" - "github.com/okex/exchain/libs/tendermint/libs/log" "github.com/okex/exchain/libs/cosmos-sdk/store/gaskv" stypes "github.com/okex/exchain/libs/cosmos-sdk/store/types" + "github.com/okex/exchain/libs/system/trace" + abci "github.com/okex/exchain/libs/tendermint/abci/types" + "github.com/okex/exchain/libs/tendermint/libs/log" ) /* @@ -93,6 +93,7 @@ func (c *Context) IsDeliverWithSerial() bool { } func (c *Context) UseParamCache() bool { + // c.paraMsg.HaveCosmosTxInBlock is also true when there are only E2C txs in a block return c.isDeliverWithSerial || (c.paraMsg != nil && !c.paraMsg.HaveCosmosTxInBlock) || c.checkTx } diff --git a/libs/tendermint/cmd/tendermint/commands/run_node.go b/libs/tendermint/cmd/tendermint/commands/run_node.go index 365dfdbba5..a576e84763 100644 --- a/libs/tendermint/cmd/tendermint/commands/run_node.go +++ b/libs/tendermint/cmd/tendermint/commands/run_node.go @@ -136,11 +136,25 @@ func AddNodeFlags(cmd *cobra.Command) { false, "enable precise gas used", ) + cmd.Flags().Int64( + "mempool.pgu-percentage-threshold", + 10, + "use pgu when hgu has a margin of at least threshold percent", + ) + cmd.Flags().Int( + "mempool.pgu-concurrency", + 1, + "pgu concurrency", + ) cmd.Flags().Float64( "mempool.pgu-adjustment", 1, "adjustment for pgu, such as 0.9 or 1.1", ) + cmd.Flags().Bool( + "mempool.pgu-persist", + false, + "persist the gas estimated by pgu") cmd.Flags().Bool( "mempool.sort_tx_by_gp", config.Mempool.SortTxByGp, diff --git a/libs/tendermint/config/dynamic_config_okchain.go b/libs/tendermint/config/dynamic_config_okchain.go index 7f33d0cb2b..a7ae0d9da7 100644 --- a/libs/tendermint/config/dynamic_config_okchain.go +++ b/libs/tendermint/config/dynamic_config_okchain.go @@ -11,7 +11,10 @@ type IDynamicConfig interface { GetEnableDeleteMinGPTx() bool GetMaxGasUsedPerBlock() int64 GetEnablePGU() bool + GetPGUPercentageThreshold() int64 + GetPGUConcurrency() int GetPGUAdjustment() float64 + GetPGUPersist() bool GetMempoolFlush() bool GetNodeKeyWhitelist() []string GetMempoolCheckTxCost() bool @@ -81,10 +84,22 @@ func (d MockDynamicConfig) GetEnablePGU() bool { return false } +func (d MockDynamicConfig) GetPGUPercentageThreshold() int64 { + return 10 +} + +func (d MockDynamicConfig) GetPGUConcurrency() int { + return 1 +} + func (d MockDynamicConfig) GetPGUAdjustment() float64 { return 1 } +func (d MockDynamicConfig) GetPGUPersist() bool { + return false +} + func (d MockDynamicConfig) GetMempoolFlush() bool { return false } diff --git a/libs/tendermint/global/commit_mutex.go b/libs/tendermint/global/commit_mutex.go new file mode 100644 index 0000000000..b93d0b5d4a --- /dev/null +++ b/libs/tendermint/global/commit_mutex.go @@ -0,0 +1,30 @@ +package global + +import ( + "sync" +) + +var ( + signalMtx sync.RWMutex + commitSignal = make(chan struct{}) +) + +func init() { + close(commitSignal) +} + +func CommitLock() { + signalMtx.Lock() + commitSignal = make(chan struct{}) + signalMtx.Unlock() +} + +func CommitUnlock() { + close(commitSignal) +} + +func WaitCommit() { + signalMtx.RLock() + <-commitSignal + signalMtx.RUnlock() +} diff --git a/libs/tendermint/mempool/clist_mempool.go b/libs/tendermint/mempool/clist_mempool.go index 2cd554cecb..291928ef75 100644 --- a/libs/tendermint/mempool/clist_mempool.go +++ b/libs/tendermint/mempool/clist_mempool.go @@ -12,23 +12,21 @@ import ( "time" "github.com/VictoriaMetrics/fastcache" - - lru "github.com/hashicorp/golang-lru" - "github.com/tendermint/go-amino" - "github.com/okex/exchain/libs/system/trace" abci "github.com/okex/exchain/libs/tendermint/abci/types" cfg "github.com/okex/exchain/libs/tendermint/config" + "github.com/okex/exchain/libs/tendermint/global" "github.com/okex/exchain/libs/tendermint/libs/clist" "github.com/okex/exchain/libs/tendermint/libs/log" tmmath "github.com/okex/exchain/libs/tendermint/libs/math" "github.com/okex/exchain/libs/tendermint/proxy" "github.com/okex/exchain/libs/tendermint/types" + "github.com/tendermint/go-amino" ) type TxInfoParser interface { GetRawTxInfo(tx types.Tx) ExTxInfo - GetTxHistoryGasUsed(tx types.Tx) int64 + GetTxHistoryGasUsed(tx types.Tx, gasLimit int64) (int64, bool) GetRealTxFromRawTx(rawTx types.Tx) abci.TxEssentials } @@ -78,7 +76,8 @@ type CListMempool struct { eventBus types.TxEventPublisher - logger log.Logger + logger log.Logger + pguLogger log.Logger metrics *Metrics @@ -100,10 +99,7 @@ type CListMempool struct { txs ITransactionQueue - simQueue chan *mempoolTx - - gasCache *lru.Cache - + simQueue chan *mempoolTx rmPendingTxChan chan types.EventDataRmPendingTx gpo *Oracle @@ -140,12 +136,9 @@ func NewCListMempool( txQueue = NewBaseTxQueue() } - gasCache, err := lru.New(1000000) - if err != nil { - panic(err) - } gpoConfig := NewGPOConfig(cfg.DynamicConfig.GetDynamicGpWeight(), cfg.DynamicConfig.GetDynamicGpCheckBlocks()) gpo := NewOracle(gpoConfig) + mempool := &CListMempool{ config: config, proxyAppConn: proxyAppConn, @@ -154,10 +147,10 @@ func NewCListMempool( recheckEnd: nil, eventBus: types.NopEventBus{}, logger: log.NewNopLogger(), + pguLogger: log.NewNopLogger(), metrics: NopMetrics(), txs: txQueue, - simQueue: make(chan *mempoolTx, 100000), - gasCache: gasCache, + simQueue: make(chan *mempoolTx, 200000), gpo: gpo, } @@ -165,7 +158,10 @@ func NewCListMempool( mempool.rmPendingTxChan = make(chan types.EventDataRmPendingTx, 1000) go mempool.fireRmPendingTxEvents() } - go mempool.simulationRoutine() + + for i := 0; i < cfg.DynamicConfig.GetPGUConcurrency(); i++ { + go mempool.simulationRoutine() + } if cfg.DynamicConfig.GetMempoolCacheSize() > 0 { mempool.cache = newMapTxCache(cfg.DynamicConfig.GetMempoolCacheSize()) @@ -205,6 +201,7 @@ func (mem *CListMempool) SetEventBus(eventBus types.TxEventPublisher) { // SetLogger sets the Logger. func (mem *CListMempool) SetLogger(l log.Logger) { mem.logger = l + mem.pguLogger = l.With("module", "pgu") } // WithPreCheck sets a filter for the mempool to reject a tx if f(tx) returns @@ -356,9 +353,6 @@ func (mem *CListMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo Tx defer mem.updateMtx.RUnlock() var err error - if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 { - txInfo.gasUsed = mem.txInfoparser.GetTxHistoryGasUsed(tx) - } if mem.preCheck != nil { if err = mem.preCheck(tx); err != nil { @@ -374,14 +368,18 @@ func (mem *CListMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo Tx if txInfo.from != "" { types.SignatureCache().Add(txkey[:], txInfo.from) } + reqRes := mem.proxyAppConn.CheckTxAsync(abci.RequestCheckTx{Tx: tx, Type: txInfo.checkType, From: txInfo.wtx.GetFrom(), Nonce: nonce}) if r, ok := reqRes.Response.Value.(*abci.Response_CheckTx); ok { - if txInfo.gasUsed <= 0 || txInfo.gasUsed > r.CheckTx.GasWanted { - txInfo.gasUsed = r.CheckTx.GasWanted - } + gasLimit := r.CheckTx.GasWanted if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 { + txHash := tx.Hash(mem.Height()) + txInfo.gasUsed, txInfo.isGasPrecise = mem.txInfoparser.GetTxHistoryGasUsed(tx, gasLimit) // r.CheckTx.GasWanted is gasLimit mem.logger.Info(fmt.Sprintf("mempool.SimulateTx: txhash<%s>, gasLimit<%d>, gasUsed<%d>", - hex.EncodeToString(tx.Hash(mem.Height())), r.CheckTx.GasWanted, txInfo.gasUsed)) + hex.EncodeToString(txHash), r.CheckTx.GasWanted, txInfo.gasUsed)) + } + if txInfo.gasUsed <= 0 || txInfo.gasUsed > gasLimit { + txInfo.gasUsed = gasLimit } } @@ -478,7 +476,7 @@ func (mem *CListMempool) addTx(memTx *mempoolTx) error { if err := mem.txs.Insert(memTx); err != nil { return err } - if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 && cfg.DynamicConfig.GetEnablePGU() { + if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 && cfg.DynamicConfig.GetEnablePGU() && atomic.LoadUint32(&memTx.isSim) == 0 { select { case mem.simQueue <- memTx: default: @@ -715,6 +713,11 @@ func (mem *CListMempool) resCbFirstTime( from: r.CheckTx.Tx.GetEthAddr(), senderNonce: r.CheckTx.SenderNonce, } + if txInfo.isGasPrecise { + // gas for hgu is precise, just mark it simulated, so it will not be simulated again + memTx.isSim = 1 + memTx.hguPrecise = true + } if txInfo.wrapCMTx != nil { memTx.isWrapCMTx = true @@ -833,12 +836,7 @@ func (mem *CListMempool) notifyTxsAvailable() { } func (mem *CListMempool) GetTxSimulateGas(txHash string) int64 { - hash := hex.EncodeToString([]byte(txHash)) - v, ok := mem.gasCache.Get(hash) - if !ok { - return -1 - } - return v.(int64) + return getPGUGas([]byte(txHash)) } func (mem *CListMempool) ReapEssentialTx(tx types.Tx) abci.TxEssentials { @@ -889,6 +887,7 @@ func (mem *CListMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) []types.Tx { // If maxGas is negative, skip this check. // Since newTotalGas < masGas, which // must be non-negative, it follows that this won't overflow. + atomic.AddUint32(&memTx.outdated, 1) gasWanted := atomic.LoadInt64(&memTx.gasWanted) newTotalGas := totalGas + gasWanted if maxGas > -1 && gasWanted >= maxGas { @@ -1028,7 +1027,7 @@ func (mem *CListMempool) Update( gasUsedPerTx := deliverTxResponses[i].GasUsed gasPricePerTx := big.NewInt(0) if ele := mem.cleanTx(height, tx, txCode); ele != nil { - atomic.AddUint32(&(ele.Value.(*mempoolTx).isOutdated), 1) + atomic.AddUint32(&(ele.Value.(*mempoolTx).outdated), 1) addr = ele.Address nonce = ele.Nonce gasPricePerTx = ele.GasPrice @@ -1263,8 +1262,11 @@ type mempoolTx struct { from string senderNonce uint64 - isOutdated uint32 - isSim uint32 + outdated uint32 + isSim uint32 + + // `hguPrecise` is true means hgu for this tx is precise and simulation is not necessary + hguPrecise bool isWrapCMTx bool wrapCMNonce uint64 @@ -1290,7 +1292,7 @@ func (memTx *mempoolTx) ToWrappedMempoolTx() types.WrappedMempoolTx { Signature: memTx.signature, From: memTx.from, SenderNonce: memTx.senderNonce, - Outdated: memTx.isOutdated, + Outdated: memTx.outdated, IsSim: memTx.isSim, IsWrapCMTx: memTx.isWrapCMTx, WrapCMNonce: memTx.wrapCMNonce, @@ -1442,17 +1444,29 @@ func (mem *CListMempool) consumePendingTxQueueJob() { } } -func (mem *CListMempool) simulateTx(tx types.Tx) (*SimulationResponse, error) { +func (mem *CListMempool) simulateTx(tx types.Tx, gasLimit int64) (int64, error) { var simuRes SimulationResponse res, err := mem.proxyAppConn.QuerySync(abci.RequestQuery{ Path: "app/simulate/mempool", Data: tx, }) if err != nil { - return nil, err + return 0, err } err = cdc.UnmarshalBinaryBare(res.Value, &simuRes) - return &simuRes, err + if err != nil { + return 0, err + } + gas := int64(simuRes.GasUsed) * int64(cfg.DynamicConfig.GetPGUAdjustment()*100) / 100 + mem.pguLogger.Info("simulateTx", "txHash", hex.EncodeToString(tx.Hash(mem.Height())), "gas", gas, "gasLimit", gasLimit) + if gas > gasLimit { + gas = gasLimit + } + txHash := tx.Hash(mem.Height()) + if err = updatePGU(txHash, gas); err != nil { + mem.logger.Error("updatePGU", "txHash", hex.EncodeToString(tx.Hash(mem.Height())), "simGas", gas, "error", err) + } + return gas, err } func (mem *CListMempool) simulationRoutine() { @@ -1463,21 +1477,62 @@ func (mem *CListMempool) simulationRoutine() { func (mem *CListMempool) simulationJob(memTx *mempoolTx) { defer types.SignatureCache().Remove(memTx.realTx.TxHash()) - if atomic.LoadUint32(&memTx.isOutdated) != 0 { + if atomic.LoadUint32(&memTx.outdated) != 0 { // memTx is outdated return } - simuRes, err := mem.simulateTx(memTx.tx) + global.WaitCommit() + gas, err := mem.simulateTx(memTx.tx, memTx.gasLimit) if err != nil { mem.logger.Error("simulateTx", "error", err, "txHash", memTx.tx.Hash(mem.Height())) return } - gas := int64(simuRes.GasUsed) * int64(cfg.DynamicConfig.GetPGUAdjustment()*100) / 100 - if gas < atomic.LoadInt64(&memTx.gasLimit) { - atomic.StoreInt64(&memTx.gasWanted, gas) - } + atomic.StoreInt64(&memTx.gasWanted, gas) atomic.AddUint32(&memTx.isSim, 1) - mem.gasCache.Add(hex.EncodeToString(memTx.realTx.TxHash()), gas) +} + +// trySimulate4BlockAfterNext will be called during Update() +// assume that next step is to proposal a block of height `n` through ReapMaxBytesMaxGas +// trySimulate4NextBlock will skip those txs which would be packed into that block, +// and simulate txs to be packed into block of height `n+1` +func (mem *CListMempool) trySimulate4NextBlock() { + maxGu := cfg.DynamicConfig.GetMaxGasUsedPerBlock() + if maxGu < 0 || !cfg.DynamicConfig.GetEnablePGU() { + return + } + + var gu int64 + var ele *clist.CElement + // skip the txs that will be packed into next block + for ele = mem.txs.Front(); ele != nil; ele = ele.Next() { + gu += ele.Value.(*mempoolTx).gasWanted + if gu > maxGu { + break + } + } + + // reset gu for next cycle + gu = 0 + + for ; ele != nil && gu < maxGu; ele = ele.Next() { + memTx := ele.Value.(*mempoolTx) + var gas int64 + var err error + if !memTx.hguPrecise { + gas, err = mem.simulateTx(memTx.tx, memTx.gasLimit) + if err != nil { + mem.logger.Error("trySimulate4BlockAfterNext", "error", err, "txHash", memTx.tx.Hash(mem.Height())) + return + } + atomic.StoreInt64(&memTx.gasWanted, gas) + atomic.AddUint32(&memTx.isSim, 1) + } else { + gas = memTx.gasWanted + } + + gu += gas + } + } func (mem *CListMempool) deleteMinGPTxOnlyFull() { diff --git a/libs/tendermint/mempool/clist_mempool_test.go b/libs/tendermint/mempool/clist_mempool_test.go index b89fff9e01..b334bcedba 100644 --- a/libs/tendermint/mempool/clist_mempool_test.go +++ b/libs/tendermint/mempool/clist_mempool_test.go @@ -105,10 +105,11 @@ func TestReapMaxBytesMaxGas(t *testing.T) { tx0 := mempool.TxsFront().Value.(*mempoolTx) // assert that kv store has gas wanted = 1. require.Equal(t, app.CheckTx(abci.RequestCheckTx{Tx: tx0.tx}).GasWanted, int64(1), "KVStore had a gas value neq to 1") - require.Equal(t, tx0.gasWanted, int64(1), "transactions gas was set incorrectly") + require.Equal(t, tx0.gasLimit, int64(1), "transactions gas was set incorrectly") // ensure each tx is 20 bytes long require.Equal(t, len(tx0.tx), 20, "Tx is longer than 20 bytes") mempool.Flush() + assert.Zero(t, mempool.Size()) // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas @@ -141,6 +142,7 @@ func TestReapMaxBytesMaxGas(t *testing.T) { assert.Equal(t, tt.expectedNumTxs, len(got), "Got %d txs, expected %d, tc #%d", len(got), tt.expectedNumTxs, tcIndex) mempool.Flush() + assert.Zero(t, mempool.Size()) } } diff --git a/libs/tendermint/mempool/mempool.go b/libs/tendermint/mempool/mempool.go index ba0b8fc6cb..53d41feda3 100644 --- a/libs/tendermint/mempool/mempool.go +++ b/libs/tendermint/mempool/mempool.go @@ -118,11 +118,11 @@ type TxInfo struct { // SenderP2PID is the actual p2p.ID of the sender, used e.g. for logging. SenderP2PID p2p.ID - from string - wtx *WrappedTx - checkType abci.CheckTxType - - gasUsed int64 + from string + wtx *WrappedTx + checkType abci.CheckTxType + isGasPrecise bool + gasUsed int64 wrapCMTx *types.WrapCMTx } diff --git a/libs/tendermint/mempool/pgu.go b/libs/tendermint/mempool/pgu.go new file mode 100644 index 0000000000..cc7cdc3a73 --- /dev/null +++ b/libs/tendermint/mempool/pgu.go @@ -0,0 +1,52 @@ +package mempool + +import ( + "encoding/binary" + cfg "github.com/okex/exchain/libs/tendermint/config" + "path/filepath" + "sync" + + "github.com/okex/exchain/libs/cosmos-sdk/client/flags" + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + db "github.com/okex/exchain/libs/tm-db" + "github.com/spf13/viper" +) + +const ( + pguDBDir = "data" + pguDBName = "pgu" +) + +var ( + pguDB db.DB + pguOnce sync.Once +) + +func initDB() { + homeDir := viper.GetString(flags.FlagHome) + dbPath := filepath.Join(homeDir, pguDBDir) + var err error + pguDB, err = sdk.NewDB(pguDBName, dbPath) + if err != nil { + panic(err) + } +} + +func updatePGU(txHash []byte, gas int64) error { + if !cfg.DynamicConfig.GetPGUPersist() { + return nil + } + pguOnce.Do(initDB) + bytesGas := make([]byte, 8) + binary.BigEndian.PutUint64(bytesGas, uint64(gas)) + return pguDB.Set(txHash, bytesGas) +} + +func getPGUGas(txHash []byte) int64 { + pguOnce.Do(initDB) + data, err := pguDB.Get(txHash) + if err != nil || len(data) == 0 { + return -1 + } + return int64(binary.BigEndian.Uint64(data)) +} diff --git a/libs/tendermint/state/execution.go b/libs/tendermint/state/execution.go index 3cac27ace6..808601bf58 100644 --- a/libs/tendermint/state/execution.go +++ b/libs/tendermint/state/execution.go @@ -235,6 +235,10 @@ func (blockExec *BlockExecutor) ApplyBlock( deltaInfo := dc.prepareStateDelta(block.Height) trc.Pin(trace.Abci) + if cfg.DynamicConfig.GetEnablePGU() { + global.CommitLock() + defer global.CommitUnlock() + } startTime := time.Now().UnixNano() diff --git a/libs/tendermint/types/milestone.go b/libs/tendermint/types/milestone.go index 0b6762761c..85e7f78195 100644 --- a/libs/tendermint/types/milestone.go +++ b/libs/tendermint/types/milestone.go @@ -201,6 +201,10 @@ func UnittestOnlySetMilestoneVenus1Height(h int64) { milestoneVenus1Height = h } +func UnittestOnlySetMilestoneVenus6Height(h int64) { + milestoneVenus6Height = h +} + func GetVenus1Height() int64 { return milestoneVenus1Height } diff --git a/x/vmbridge/keeper/evm_test.go b/x/vmbridge/keeper/evm_test.go index 174d822980..a843fcebed 100644 --- a/x/vmbridge/keeper/evm_test.go +++ b/x/vmbridge/keeper/evm_test.go @@ -216,25 +216,25 @@ func (suite *KeeperTestSuite) TestSendToWasmEventHandler_Handle() { data = input }, func() { - queryAddr := sdk.AccAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + queryAddr := sdk.WasmAddress(ethAddr.Bytes()) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, - types.ErrIsNotOKCAddr, + nil, }, { "normal topic,recipient is ex", func() { wasmAddrStr := suite.wasmContract.String() - queryAddr := sdk.AccAddress(ethAddr.Bytes()) + queryAddr := sdk.WasmAddress(ethAddr.Bytes()) input, err := getSendToWasmEventData(wasmAddrStr, queryAddr.String(), big.NewInt(1)) suite.Require().NoError(err) data = input }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, @@ -244,14 +244,14 @@ func (suite *KeeperTestSuite) TestSendToWasmEventHandler_Handle() { "normal topic,amount is zero", func() { wasmAddrStr := suite.wasmContract.String() - queryAddr := sdk.AccAddress(ethAddr.Bytes()) + queryAddr := sdk.WasmAddress(ethAddr.Bytes()) input, err := getSendToWasmEventData(wasmAddrStr, queryAddr.String(), big.NewInt(0)) suite.Require().NoError(err) data = input }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"0\"}", string(result)) }, diff --git a/x/vmbridge/keeper/keeper_test.go b/x/vmbridge/keeper/keeper_test.go index 5bae132cfd..a8c6f021c0 100644 --- a/x/vmbridge/keeper/keeper_test.go +++ b/x/vmbridge/keeper/keeper_test.go @@ -37,7 +37,7 @@ type KeeperTestSuite struct { keeper *keeper.Keeper addr sdk.AccAddress - wasmContract sdk.AccAddress + wasmContract sdk.WasmAddress codeId uint64 evmContract common.Address @@ -87,8 +87,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.Require().NoError(err) initMsg := []byte(fmt.Sprintf("{\"decimals\":10,\"initial_balances\":[{\"address\":\"%s\",\"amount\":\"100000000\"}],\"name\":\"my test token\", \"symbol\":\"MTT\"}", suite.addr.String())) - temp, _, err := suite.app.WasmPermissionKeeper.Instantiate(suite.ctx, suite.codeId, sdk.AccToAWasmddress(suite.addr), sdk.AccToAWasmddress(suite.addr), initMsg, "label", sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) - suite.wasmContract = sdk.WasmToAccAddress(temp) + suite.wasmContract, _, err = suite.app.WasmPermissionKeeper.Instantiate(suite.ctx, suite.codeId, sdk.AccToAWasmddress(suite.addr), sdk.AccToAWasmddress(suite.addr), initMsg, "label", sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}) suite.Require().NoError(err) palyload := "60806040526040518060600160405280603d815260200162002355603d913960079080519060200190620000359291906200004a565b503480156200004357600080fd5b506200015f565b8280546200005890620000fa565b90600052602060002090601f0160209004810192826200007c5760008555620000c8565b82601f106200009757805160ff1916838001178555620000c8565b82800160010185558215620000c8579182015b82811115620000c7578251825591602001919060010190620000aa565b5b509050620000d79190620000db565b5090565b5b80821115620000f6576000816000905550600101620000dc565b5090565b600060028204905060018216806200011357607f821691505b602082108114156200012a576200012962000130565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6121e6806200016f6000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806370a08231116100ad578063cc1207c011610071578063cc1207c014610330578063d069cf761461034c578063d241877c1461037c578063dd62ed3e1461039a578063ee366654146103ca57610121565b806370a08231146102665780638e155cee1461029657806395d89b41146102b2578063a457c2d7146102d0578063a9059cbb1461030057610121565b8063313ce567116100f4578063313ce567146101c257806335b2bd2d146101e057806339509351146101fe5780633a0c76ea1461022e57806340c10f191461024a57610121565b806306fdde0314610126578063095ea7b31461014457806318160ddd1461017457806323b872dd14610192575b600080fd5b61012e6103e8565b60405161013b91906119a9565b60405180910390f35b61015e600480360381019061015991906114c5565b61047a565b60405161016b919061198e565b60405180910390f35b61017c610496565b6040516101899190611b70565b60405180910390f35b6101ac60048036038101906101a79190611472565b6104a0565b6040516101b9919061198e565b60405180910390f35b6101ca6104c8565b6040516101d79190611b8b565b60405180910390f35b6101e86104df565b6040516101f59190611973565b60405180910390f35b610218600480360381019061021391906114c5565b6104f7565b604051610225919061198e565b60405180910390f35b610248600480360381019061024391906115c2565b61059a565b005b610264600480360381019061025f91906114c5565b6105e4565b005b610280600480360381019061027b9190611405565b6105f2565b60405161028d9190611b70565b60405180910390f35b6102b060048036038101906102ab9190611579565b61063b565b005b6102ba610655565b6040516102c791906119a9565b60405180910390f35b6102ea60048036038101906102e591906114c5565b6106e7565b6040516102f7919061198e565b60405180910390f35b61031a600480360381019061031591906114c5565b6107ca565b604051610327919061198e565b60405180910390f35b61034a6004803603810190610345919061164d565b6107e6565b005b61036660048036038101906103619190611505565b6107f5565b604051610373919061198e565b60405180910390f35b6103846108b4565b60405161039191906119a9565b60405180910390f35b6103b460048036038101906103af9190611432565b610942565b6040516103c19190611b70565b60405180910390f35b6103d26109c9565b6040516103df91906119a9565b60405180910390f35b6060600180546103f790611d59565b80601f016020809104026020016040519081016040528092919081815260200182805461042390611d59565b80156104705780601f1061044557610100808354040283529160200191610470565b820191906000526020600020905b81548152906001019060200180831161045357829003601f168201915b5050505050905090565b60008033905061048b8185856109d8565b600191505092915050565b6000600454905090565b6000803390506104b1858285610ba3565b6104bc858585610c2f565b60019150509392505050565b6000600360009054906101000a900460ff16905090565b73c63cf6c8e1f3df41085e9d8af49584dae1432b4f81565b60008033905061058f818585600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461058a9190611c38565b6109d8565b600191505092915050565b6105a43382610e9d565b7f41e4c36823b869e11ae85a7e623a332d31d961ba9ed670a3c9cb71c973c53caa8284836040516105d7939291906119cb565b60405180910390a1505050565b6105ee828261105e565b5050565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b806007908051906020019061065192919061125d565b5050565b60606002805461066490611d59565b80601f016020809104026020016040519081016040528092919081815260200182805461069090611d59565b80156106dd5780601f106106b2576101008083540402835291602001916106dd565b820191906000526020600020905b8154815290600101906020018083116106c057829003601f168201915b5050505050905090565b6000803390506000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050838110156107b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a890611b30565b60405180910390fd5b6107be82868684036109d8565b60019250505092915050565b6000803390506107db818585610c2f565b600191505092915050565b6107f18283836111a7565b5050565b600073c63cf6c8e1f3df41085e9d8af49584dae1432b4f73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461084357600080fd5b6007604051602001610855919061195c565b60405160208183030381529060405280519060200120858560405160200161087e929190611943565b604051602081830303815290604052805190602001201461089e57600080fd5b6108a8838361105e565b60019050949350505050565b600780546108c190611d59565b80601f01602080910402602001604051908101604052809291908181526020018280546108ed90611d59565b801561093a5780601f1061090f5761010080835404028352916020019161093a565b820191906000526020600020905b81548152906001019060200180831161091d57829003601f168201915b505050505081565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b60606109d3610655565b905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610a48576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3f90611b10565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610ab8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aaf90611a50565b60405180910390fd5b80600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051610b969190611b70565b60405180910390a3505050565b6000610baf8484610942565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c295781811015610c1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1290611a90565b60405180910390fd5b610c2884848484036109d8565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610c9f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9690611af0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610d0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0690611a10565b60405180910390fd5b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610d96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8d90611ab0565b60405180910390fd5b818103600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610e2b9190611c38565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610e8f9190611b70565b60405180910390a350505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610f0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0490611ad0565b60405180910390fd5b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610f94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f8b90611a30565b60405180910390fd5b818103600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160046000828254610fec9190611c8e565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516110519190611b70565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156110ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110c590611b50565b60405180910390fd5b80600460008282546110e09190611c38565b9250508190555080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546111369190611c38565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161119b9190611b70565b60405180910390a35050565b60008054906101000a900460ff16156111f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ec90611a70565b60405180910390fd5b60016000806101000a81548160ff021916908315150217905550826001908051906020019061122592919061125d565b50816002908051906020019061123c92919061125d565b5080600360006101000a81548160ff021916908360ff160217905550505050565b82805461126990611d59565b90600052602060002090601f01602090048101928261128b57600085556112d2565b82601f106112a457805160ff19168380011785556112d2565b828001600101855582156112d2579182015b828111156112d15782518255916020019190600101906112b6565b5b5090506112df91906112e3565b5090565b5b808211156112fc5760008160009055506001016112e4565b5090565b600061131361130e84611bcb565b611ba6565b90508281526020810184848401111561132f5761132e611e58565b5b61133a848285611d17565b509392505050565b6000813590506113518161216b565b92915050565b60008083601f84011261136d5761136c611e4e565b5b8235905067ffffffffffffffff81111561138a57611389611e49565b5b6020830191508360018202830111156113a6576113a5611e53565b5b9250929050565b600082601f8301126113c2576113c1611e4e565b5b81356113d2848260208601611300565b91505092915050565b6000813590506113ea81612182565b92915050565b6000813590506113ff81612199565b92915050565b60006020828403121561141b5761141a611e62565b5b600061142984828501611342565b91505092915050565b6000806040838503121561144957611448611e62565b5b600061145785828601611342565b925050602061146885828601611342565b9150509250929050565b60008060006060848603121561148b5761148a611e62565b5b600061149986828701611342565b93505060206114aa86828701611342565b92505060406114bb868287016113db565b9150509250925092565b600080604083850312156114dc576114db611e62565b5b60006114ea85828601611342565b92505060206114fb858286016113db565b9150509250929050565b6000806000806060858703121561151f5761151e611e62565b5b600085013567ffffffffffffffff81111561153d5761153c611e5d565b5b61154987828801611357565b9450945050602061155c87828801611342565b925050604061156d878288016113db565b91505092959194509250565b60006020828403121561158f5761158e611e62565b5b600082013567ffffffffffffffff8111156115ad576115ac611e5d565b5b6115b9848285016113ad565b91505092915050565b6000806000606084860312156115db576115da611e62565b5b600084013567ffffffffffffffff8111156115f9576115f8611e5d565b5b611605868287016113ad565b935050602084013567ffffffffffffffff81111561162657611625611e5d565b5b611632868287016113ad565b9250506040611643868287016113db565b9150509250925092565b6000806040838503121561166457611663611e62565b5b600083013567ffffffffffffffff81111561168257611681611e5d565b5b61168e858286016113ad565b925050602061169f858286016113f0565b9150509250929050565b6116b281611cc2565b82525050565b6116c181611cd4565b82525050565b60006116d38385611c2d565b93506116e0838584611d17565b82840190509392505050565b60006116f782611c11565b6117018185611c1c565b9350611711818560208601611d26565b61171a81611e67565b840191505092915050565b6000815461173281611d59565b61173c8186611c2d565b9450600182166000811461175757600181146117685761179b565b60ff1983168652818601935061179b565b61177185611bfc565b60005b8381101561179357815481890152600182019150602081019050611774565b838801955050505b50505092915050565b60006117b1602383611c1c565b91506117bc82611e78565b604082019050919050565b60006117d4602283611c1c565b91506117df82611ec7565b604082019050919050565b60006117f7602283611c1c565b915061180282611f16565b604082019050919050565b600061181a601b83611c1c565b915061182582611f65565b602082019050919050565b600061183d601d83611c1c565b915061184882611f8e565b602082019050919050565b6000611860602683611c1c565b915061186b82611fb7565b604082019050919050565b6000611883602183611c1c565b915061188e82612006565b604082019050919050565b60006118a6602583611c1c565b91506118b182612055565b604082019050919050565b60006118c9602483611c1c565b91506118d4826120a4565b604082019050919050565b60006118ec602583611c1c565b91506118f7826120f3565b604082019050919050565b600061190f601f83611c1c565b915061191a82612142565b602082019050919050565b61192e81611d00565b82525050565b61193d81611d0a565b82525050565b60006119508284866116c7565b91508190509392505050565b60006119688284611725565b915081905092915050565b600060208201905061198860008301846116a9565b92915050565b60006020820190506119a360008301846116b8565b92915050565b600060208201905081810360008301526119c381846116ec565b905092915050565b600060608201905081810360008301526119e581866116ec565b905081810360208301526119f981856116ec565b9050611a086040830184611925565b949350505050565b60006020820190508181036000830152611a29816117a4565b9050919050565b60006020820190508181036000830152611a49816117c7565b9050919050565b60006020820190508181036000830152611a69816117ea565b9050919050565b60006020820190508181036000830152611a898161180d565b9050919050565b60006020820190508181036000830152611aa981611830565b9050919050565b60006020820190508181036000830152611ac981611853565b9050919050565b60006020820190508181036000830152611ae981611876565b9050919050565b60006020820190508181036000830152611b0981611899565b9050919050565b60006020820190508181036000830152611b29816118bc565b9050919050565b60006020820190508181036000830152611b49816118df565b9050919050565b60006020820190508181036000830152611b6981611902565b9050919050565b6000602082019050611b856000830184611925565b92915050565b6000602082019050611ba06000830184611934565b92915050565b6000611bb0611bc1565b9050611bbc8282611d8b565b919050565b6000604051905090565b600067ffffffffffffffff821115611be657611be5611e1a565b5b611bef82611e67565b9050602081019050919050565b60008190508160005260206000209050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b6000611c4382611d00565b9150611c4e83611d00565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611c8357611c82611dbc565b5b828201905092915050565b6000611c9982611d00565b9150611ca483611d00565b925082821015611cb757611cb6611dbc565b5b828203905092915050565b6000611ccd82611ce0565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b83811015611d44578082015181840152602081019050611d29565b83811115611d53576000848401525b50505050565b60006002820490506001821680611d7157607f821691505b60208210811415611d8557611d84611deb565b5b50919050565b611d9482611e67565b810181811067ffffffffffffffff82111715611db357611db2611e1a565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a20616c726561647920696e697469616c697a65643b0000000000600082015250565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b61217481611cc2565b811461217f57600080fd5b50565b61218b81611d00565b811461219657600080fd5b50565b6121a281611d0a565b81146121ad57600080fd5b5056fea264697066735822122022151d41dd9654958225e494d6adc336a64e7ff8fe7993ba1764f69906eb984064736f6c6343000807003365783134686a32746176713866706573647778786375343472747933686839307668756a7276636d73746c347a723374786d6676773973366671753237" diff --git a/x/vmbridge/keeper/wasm.go b/x/vmbridge/keeper/wasm.go index bec97e7659..b64cd56ba2 100644 --- a/x/vmbridge/keeper/wasm.go +++ b/x/vmbridge/keeper/wasm.go @@ -14,11 +14,7 @@ import ( ) func (k Keeper) SendToWasm(ctx sdk.Context, caller sdk.AccAddress, wasmContractAddr, recipient string, amount sdk.Int) error { - // must check recipient is ex address - if !sdk.IsOKCAddress(recipient) { - return types.ErrIsNotOKCAddr - } - to, err := sdk.AccAddressFromBech32(recipient) + _, err := sdk.WasmAddressFromBech32(recipient) if err != nil { return err } @@ -26,7 +22,7 @@ func (k Keeper) SendToWasm(ctx sdk.Context, caller sdk.AccAddress, wasmContractA if amount.IsNegative() { return types.ErrAmountNegative } - input, err := types.GetMintCW20Input(amount.String(), sdk.AccToAWasmddress(to).String()) + input, err := types.GetMintCW20Input(amount.String(), recipient) if err != nil { return err } diff --git a/x/vmbridge/keeper/wasm_test.go b/x/vmbridge/keeper/wasm_test.go index 328a3e72be..7afe5ad4c5 100644 --- a/x/vmbridge/keeper/wasm_test.go +++ b/x/vmbridge/keeper/wasm_test.go @@ -27,7 +27,7 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { reset := func() { caller = sdk.AccAddress(contract.Bytes()) wasmContractAddr = suite.wasmContract.String() - recipient = sdk.AccAddress(ethAddr.Bytes()).String() + recipient = ethAddr.String() amount = sdk.NewInt(1) } testCases := []struct { @@ -42,7 +42,7 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, @@ -55,11 +55,11 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, - nil, + errors.New("execute wasm contract failed: Generic error: addr_validate errored: Address is not normalized"), }, { "recipient is 0x", @@ -68,11 +68,11 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, - types.ErrIsNotOKCAddr, + nil, }, { "recipient is wasmaddr", @@ -81,24 +81,24 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { }, func() { queryAddr := sdk.WasmAddress(make([]byte, 32)) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, - nil, + errors.New("execute wasm contract failed: Generic error: addr_validate errored: Address is not normalized"), }, { - "recipient is wasmaddr 0x", + "recipient is 0x 32", func() { recipient = "0x" + hex.EncodeToString(make([]byte, 32)) }, func() { queryAddr := sdk.WasmAddress(make([]byte, 32)) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"1\"}", string(result)) }, - types.ErrIsNotOKCAddr, + errors.New("incorrect address length"), }, { "normal topic,amount is zero", @@ -107,7 +107,7 @@ func (suite *KeeperTestSuite) TestKeeper_SendToWasm() { }, func() { queryAddr := sdk.WasmAddress(ethAddr.Bytes()) - result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, sdk.AccToAWasmddress(suite.wasmContract), []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) + result, err := suite.app.WasmKeeper.QuerySmart(suite.ctx, suite.wasmContract, []byte(fmt.Sprintf("{\"balance\":{\"address\":\"%s\"}}", queryAddr.String()))) suite.Require().NoError(err) suite.Require().Equal("{\"balance\":\"0\"}", string(result)) }, diff --git a/x/wasm/keeper/ante.go b/x/wasm/keeper/ante.go index a38077d69d..e3aca72ce3 100644 --- a/x/wasm/keeper/ante.go +++ b/x/wasm/keeper/ante.go @@ -3,10 +3,8 @@ package keeper import ( "encoding/binary" - types2 "github.com/okex/exchain/libs/tendermint/types" - sdk "github.com/okex/exchain/libs/cosmos-sdk/types" - + tmtypes "github.com/okex/exchain/libs/tendermint/types" "github.com/okex/exchain/x/wasm/types" ) @@ -30,7 +28,7 @@ func NewCountTXDecorator(storeKey sdk.StoreKey) *CountTXDecorator { // The ante handler passes the counter value via sdk.Context upstream. See `types.TXCounter(ctx)` to read the value. // Simulations don't get a tx counter value assigned. func (a CountTXDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - if simulate || !types2.HigherThanEarth(ctx.BlockHeight()) { + if simulate || !tmtypes.HigherThanEarth(ctx.BlockHeight()) { return next(ctx, tx, simulate) } currentGasmeter := ctx.GasMeter() @@ -108,7 +106,9 @@ func (d LimitSimulationGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu } func UpdateTxCount(ctx sdk.Context, storeKey sdk.StoreKey, txCount int) { - store := ctx.KVStore(storeKey) - currentHeight := ctx.BlockHeight() - store.Set(types.TXCounterPrefix, encodeHeightCounter(currentHeight, uint32(txCount+1))) + if tmtypes.HigherThanEarth(ctx.BlockHeight()) { + store := ctx.KVStore(storeKey) + currentHeight := ctx.BlockHeight() + store.Set(types.TXCounterPrefix, encodeHeightCounter(currentHeight, uint32(txCount+1))) + } }