From 47920a49e92c82be5a1605bdbd858eebd545c02c Mon Sep 17 00:00:00 2001 From: YuanXingqiang <707312973@qq.com> Date: Mon, 10 Jan 2022 18:04:25 +0800 Subject: [PATCH] =?UTF-8?q?Merge=20PR=20=EF=BC=9ARLP=20encode=20is=20not?= =?UTF-8?q?=20allowed=20until=20venus=20height=20(#1407)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * RLP encode is not allowed until venus height * add optional heights paramter in sdk.TxDecoder * update rpc * update HigherThanVenus * txpool is not allowed until venus height * update global height when restarting the node Co-authored-by: KamiD <44460798+KamiD@users.noreply.github.com> --- app/rpc/backend/backend.go | 18 +++++++++++--- app/rpc/namespaces/eth/api.go | 25 ++++++++++++++++--- app/rpc/namespaces/eth/tx_pool.go | 6 ++++- libs/cosmos-sdk/baseapp/abci.go | 2 +- libs/cosmos-sdk/baseapp/baseapp_test.go | 2 +- libs/cosmos-sdk/server/mock/tx.go | 2 +- libs/cosmos-sdk/server/start.go | 5 +++- libs/cosmos-sdk/types/tx_msg.go | 2 +- libs/cosmos-sdk/x/auth/types/stdtx.go | 5 +++- libs/tendermint/global/height.go | 15 +++++++++++ libs/tendermint/state/execution.go | 33 +++++++++++++------------ libs/tendermint/types/milestone.go | 23 +++++++++-------- x/evm/types/utils.go | 25 ++++++++++++++----- 13 files changed, 116 insertions(+), 47 deletions(-) create mode 100644 libs/tendermint/global/height.go diff --git a/app/rpc/backend/backend.go b/app/rpc/backend/backend.go index 14cb54992b..8e410ed1f7 100644 --- a/app/rpc/backend/backend.go +++ b/app/rpc/backend/backend.go @@ -235,6 +235,10 @@ func (b *EthermintBackend) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.L // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error) { + info, err := b.clientCtx.Client.BlockchainInfo(0, 0) + if err != nil { + return nil, err + } pendingTxs, err := b.clientCtx.Client.UnconfirmedTxs(-1) if err != nil { return nil, err @@ -249,7 +253,7 @@ func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error } // TODO: check signer and reference against accounts the node manages - rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Hash(b.clientCtx.Height)), common.Hash{}, 0, 0) + rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Hash(info.LastHeight)), common.Hash{}, 0, 0) if err != nil { return nil, err } @@ -277,6 +281,10 @@ func (b *EthermintBackend) UserPendingTransactionsCnt(address string) (int, erro } func (b *EthermintBackend) UserPendingTransactions(address string, limit int) ([]*rpctypes.Transaction, error) { + info, err := b.clientCtx.Client.BlockchainInfo(0, 0) + if err != nil { + return nil, err + } result, err := b.clientCtx.Client.UserUnconfirmedTxs(address, limit) if err != nil { return nil, err @@ -290,7 +298,7 @@ func (b *EthermintBackend) UserPendingTransactions(address string, limit int) ([ } // TODO: check signer and reference against accounts the node manages - rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Hash(b.clientCtx.Height)), common.Hash{}, 0, 0) + rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Hash(info.LastHeight)), common.Hash{}, 0, 0) if err != nil { return nil, err } @@ -312,6 +320,10 @@ func (b *EthermintBackend) PendingAddressList() ([]string, error) { // PendingTransactions returns the transaction that is in the transaction pool // and have a from address that is one of the accounts this node manages. func (b *EthermintBackend) PendingTransactionsByHash(target common.Hash) (*rpctypes.Transaction, error) { + info, err := b.clientCtx.Client.BlockchainInfo(0, 0) + if err != nil { + return nil, err + } pendingTx, err := b.clientCtx.Client.GetUnconfirmedTxByHash(target) if err != nil { return nil, err @@ -321,7 +333,7 @@ func (b *EthermintBackend) PendingTransactionsByHash(target common.Hash) (*rpcty // ignore non Ethermint EVM transactions return nil, err } - rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(pendingTx.Hash(b.clientCtx.Height)), common.Hash{}, 0, 0) + rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(pendingTx.Hash(info.LastHeight)), common.Hash{}, 0, 0) if err != nil { return nil, err } diff --git a/app/rpc/namespaces/eth/api.go b/app/rpc/namespaces/eth/api.go index 9d27461171..d6ff502636 100644 --- a/app/rpc/namespaces/eth/api.go +++ b/app/rpc/namespaces/eth/api.go @@ -670,6 +670,10 @@ func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common. defer monitor.OnEnd("args", args) // TODO: Change this functionality to find an unlocked account by address + height, err := api.BlockNumber() + if err != nil { + return common.Hash{}, err + } key, exist := rpctypes.GetKeyByAddress(api.keys, *args.From) if !exist { api.logger.Debug("failed to find key in keyring", "key", args.From) @@ -700,7 +704,12 @@ func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common. return common.Hash{}, err } - txEncoder := authclient.GetTxEncoder(nil, authclient.WithEthereumTx()) + var txEncoder sdk.TxEncoder + if tmtypes.HigherThanVenus(int64(height)) { + txEncoder = authclient.GetTxEncoder(nil, authclient.WithEthereumTx()) + } else { + txEncoder = authclient.GetTxEncoder(api.clientCtx.Codec) + } // Encode transaction by RLP encoder txBytes, err := txEncoder(tx) @@ -709,7 +718,7 @@ func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common. } // send chanData to txPool - if api.txPool != nil { + if tmtypes.HigherThanVenus(int64(height)) && api.txPool != nil { return broadcastTxByTxPool(api, tx, txBytes) } @@ -732,6 +741,10 @@ func (api *PublicEthereumAPI) SendTransaction(args rpctypes.SendTxArgs) (common. func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { monitor := monitor.GetMonitor("eth_sendRawTransaction", api.logger, api.Metrics).OnBegin() defer monitor.OnEnd("data", data) + height, err := api.BlockNumber() + if err != nil { + return common.Hash{}, err + } tx := new(evmtypes.MsgEthereumTx) // RLP decode raw transaction bytes @@ -741,9 +754,15 @@ func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Has } txBytes := data + if !tmtypes.HigherThanVenus(int64(height)) { + txBytes, err = authclient.GetTxEncoder(api.clientCtx.Codec)(tx) + if err != nil { + return common.Hash{}, err + } + } // send chanData to txPool - if api.txPool != nil { + if tmtypes.HigherThanVenus(int64(height)) && api.txPool != nil { return broadcastTxByTxPool(api, tx, txBytes) } diff --git a/app/rpc/namespaces/eth/tx_pool.go b/app/rpc/namespaces/eth/tx_pool.go index 8f095d14cf..56a532e32d 100644 --- a/app/rpc/namespaces/eth/tx_pool.go +++ b/app/rpc/namespaces/eth/tx_pool.go @@ -121,6 +121,10 @@ func (pool *TxPool) initDB(api *PublicEthereumAPI) error { } func broadcastTxByTxPool(api *PublicEthereumAPI, tx *evmtypes.MsgEthereumTx, txBytes []byte) (common.Hash, error) { + info, err := api.clientCtx.Client.BlockchainInfo(0, 0) + if err != nil { + return common.Hash{}, err + } // Get sender address chainIDEpoch, err := ethermint.ParseChainID(api.clientCtx.ChainID) if err != nil { @@ -139,7 +143,7 @@ func broadcastTxByTxPool(api *PublicEthereumAPI, tx *evmtypes.MsgEthereumTx, txB return common.Hash{}, err } - return common.BytesToHash(types.Tx(txBytes).Hash(api.clientCtx.Height)), nil + return common.BytesToHash(types.Tx(txBytes).Hash(info.LastHeight)), nil } func (pool *TxPool) CacheAndBroadcastTx(api *PublicEthereumAPI, address common.Address, tx *evmtypes.MsgEthereumTx) error { diff --git a/libs/cosmos-sdk/baseapp/abci.go b/libs/cosmos-sdk/baseapp/abci.go index 25ab2d6738..54941e22c5 100644 --- a/libs/cosmos-sdk/baseapp/abci.go +++ b/libs/cosmos-sdk/baseapp/abci.go @@ -181,7 +181,7 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // will contain releveant error information. Regardless of tx execution outcome, // the ResponseCheckTx will contain relevant gas execution context. func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { - tx, err := app.txDecoder(req.Tx) + tx, err := app.txDecoder(req.Tx, app.Info(abci.RequestInfo{}).LastBlockHeight) if err != nil { return sdkerrors.ResponseCheckTx(err, 0, 0, app.trace) } diff --git a/libs/cosmos-sdk/baseapp/baseapp_test.go b/libs/cosmos-sdk/baseapp/baseapp_test.go index 03a0412aa2..209006302a 100644 --- a/libs/cosmos-sdk/baseapp/baseapp_test.go +++ b/libs/cosmos-sdk/baseapp/baseapp_test.go @@ -662,7 +662,7 @@ func (msg msgCounter2) ValidateBasic() error { // amino decode func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, error) { + return func(txBytes []byte, _ ...int64) (sdk.Tx, error) { var tx txTest if len(txBytes) == 0 { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") diff --git a/libs/cosmos-sdk/server/mock/tx.go b/libs/cosmos-sdk/server/mock/tx.go index 4a4bd37a62..fc796d7f2f 100644 --- a/libs/cosmos-sdk/server/mock/tx.go +++ b/libs/cosmos-sdk/server/mock/tx.go @@ -77,7 +77,7 @@ func (tx kvstoreTx) GetTxFnSignatureInfo() ([]byte, int) { // takes raw transaction bytes and decodes them into an sdk.Tx. An sdk.Tx has // all the signatures and can be used to authenticate. -func decodeTx(txBytes []byte) (sdk.Tx, error) { +func decodeTx(txBytes []byte, _ ...int64) (sdk.Tx, error) { var tx sdk.Tx split := bytes.Split(txBytes, []byte("=")) diff --git a/libs/cosmos-sdk/server/start.go b/libs/cosmos-sdk/server/start.go index f0a65af884..8597271213 100644 --- a/libs/cosmos-sdk/server/start.go +++ b/libs/cosmos-sdk/server/start.go @@ -6,6 +6,7 @@ import ( "fmt" sdk "github.com/okex/exchain/libs/cosmos-sdk/types" "github.com/okex/exchain/libs/system" + "github.com/okex/exchain/libs/tendermint/global" "github.com/okex/exchain/libs/tendermint/libs/log" "os" "runtime/pprof" @@ -296,6 +297,8 @@ func startInProcess(ctx *Context, cdc *codec.Codec, appCreator AppCreator, appSt return nil, err } + global.SetGlobalHeight(tmNode.ConsensusState().Height) + app.SetOption(abci.RequestSetOption{ Key: "CheckChainID", Value: tmNode.ConsensusState().GetState().ChainID, @@ -304,7 +307,7 @@ func startInProcess(ctx *Context, cdc *codec.Codec, appCreator AppCreator, appSt ctx.Logger.Info("startInProcess", "ConsensusStateChainID", tmNode.ConsensusState().GetState().ChainID, "GenesisDocChainID", tmNode.GenesisDoc().ChainID, - ) + ) if err := tmNode.Start(); err != nil { return nil, err } diff --git a/libs/cosmos-sdk/types/tx_msg.go b/libs/cosmos-sdk/types/tx_msg.go index 86fad0e8f7..a79c09ffaa 100644 --- a/libs/cosmos-sdk/types/tx_msg.go +++ b/libs/cosmos-sdk/types/tx_msg.go @@ -54,7 +54,7 @@ type Tx interface { //__________________________________________________________ // TxDecoder unmarshals transaction bytes -type TxDecoder func(txBytes []byte) (Tx, error) +type TxDecoder func(txBytes []byte, height ...int64) (Tx, error) // TxEncoder marshals transaction to bytes type TxEncoder func(tx Tx) ([]byte, error) diff --git a/libs/cosmos-sdk/x/auth/types/stdtx.go b/libs/cosmos-sdk/x/auth/types/stdtx.go index 861ffab10a..e8dd4bfa13 100644 --- a/libs/cosmos-sdk/x/auth/types/stdtx.go +++ b/libs/cosmos-sdk/x/auth/types/stdtx.go @@ -400,7 +400,10 @@ type StdSignature struct { // DefaultTxDecoder logic for standard transaction decoding func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, error) { + return func(txBytes []byte, heights ...int64) (sdk.Tx, error) { + if len(heights) > 0 { + return nil, fmt.Errorf("too many height parameters") + } var tx = StdTx{} if len(txBytes) == 0 { diff --git a/libs/tendermint/global/height.go b/libs/tendermint/global/height.go new file mode 100644 index 0000000000..c9e48daab6 --- /dev/null +++ b/libs/tendermint/global/height.go @@ -0,0 +1,15 @@ +package global + +import "sync/atomic" + +var lastCommittedHeight int64 + +// SetGlobalHeight sets lastCommittedHeight safely. +func SetGlobalHeight(height int64) { + atomic.StoreInt64(&lastCommittedHeight, height) +} + +// GetGlobalHeight gets lastCommittedHeight safely. +func GetGlobalHeight() int64 { + return atomic.LoadInt64(&lastCommittedHeight) +} diff --git a/libs/tendermint/state/execution.go b/libs/tendermint/state/execution.go index 21c9484668..5319f2922d 100644 --- a/libs/tendermint/state/execution.go +++ b/libs/tendermint/state/execution.go @@ -2,6 +2,7 @@ package state import ( "fmt" + "github.com/okex/exchain/libs/tendermint/global" "github.com/okex/exchain/libs/tendermint/libs/automation" "time" @@ -38,7 +39,7 @@ type BlockExecutor struct { mempool mempl.Mempool evpool EvidencePool - logger log.Logger + logger log.Logger metrics *Metrics isAsync bool @@ -50,7 +51,6 @@ type BlockExecutor struct { isFastSync bool } - type BlockExecutorOption func(executor *BlockExecutor) func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption { @@ -70,16 +70,16 @@ func NewBlockExecutor( options ...BlockExecutorOption, ) *BlockExecutor { res := &BlockExecutor{ - db: db, - proxyApp: proxyApp, - eventBus: types.NopEventBus{}, - mempool: mempool, - evpool: evpool, - logger: logger, - metrics: NopMetrics(), - isAsync: viper.GetBool(FlagParalleledTx), - prerunCtx: newPrerunContex(logger), - deltaContext: newDeltaContext(logger), + db: db, + proxyApp: proxyApp, + eventBus: types.NopEventBus{}, + mempool: mempool, + evpool: evpool, + logger: logger, + metrics: NopMetrics(), + isAsync: viper.GetBool(FlagParalleledTx), + prerunCtx: newPrerunContex(logger), + deltaContext: newDeltaContext(logger), } for _, option := range options { @@ -235,6 +235,7 @@ func (blockExec *BlockExecutor) ApplyBlock( if err != nil { return state, 0, fmt.Errorf("commit failed for application: %v", err) } + global.SetGlobalHeight(block.Height) trc.Pin("evpool") // Update evpool with the block and state. @@ -298,6 +299,7 @@ func (blockExec *BlockExecutor) runAbci(block *types.Block, delta *types.Deltas) return abciResponses, err } + // Commit locks the mempool, runs the ABCI Commit message, and updates the // mempool. // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any). @@ -664,9 +666,9 @@ func ExecCommitBlock( ) ([]byte, error) { ctx := &executionTask{ - logger: logger, - block: block, - db: stateDB, + logger: logger, + block: block, + db: stateDB, proxyApp: appConnConsensus, } @@ -684,4 +686,3 @@ func ExecCommitBlock( // ResponseCommit has no error or log, just data return res.Data, nil } - diff --git a/libs/tendermint/types/milestone.go b/libs/tendermint/types/milestone.go index 37442f823e..4afd6c8919 100644 --- a/libs/tendermint/types/milestone.go +++ b/libs/tendermint/types/milestone.go @@ -11,27 +11,26 @@ import ( // 3. BankTransferBlock var ( - MILESTONE_GENESIS_HEIGHT string - genesisHeight int64 + MILESTONE_GENESIS_HEIGHT string + genesisHeight int64 - MILESTONE_MERCURY_HEIGHT string - milestoneMercuryHeight int64 + MILESTONE_MERCURY_HEIGHT string + milestoneMercuryHeight int64 - MILESTONE_VENUS_HEIGHT string - milestoneVenusHeight int64 + MILESTONE_VENUS_HEIGHT string + milestoneVenusHeight int64 - once sync.Once + once sync.Once ) func init() { once.Do(func() { - genesisHeight = string2number(MILESTONE_GENESIS_HEIGHT) + genesisHeight = string2number(MILESTONE_GENESIS_HEIGHT) milestoneMercuryHeight = string2number(MILESTONE_MERCURY_HEIGHT) - milestoneVenusHeight = string2number(MILESTONE_VENUS_HEIGHT) + milestoneVenusHeight = string2number(MILESTONE_VENUS_HEIGHT) }) } - func string2number(input string) int64 { if len(input) == 0 { input = "0" @@ -56,7 +55,7 @@ func HigherThanVenus(height int64) bool { if milestoneVenusHeight == 0 { return false } - return height > milestoneVenusHeight + return height >= milestoneVenusHeight } // 2322600 is mainnet GenesisHeight @@ -79,4 +78,4 @@ func GetVenusHeight() int64 { func GetMercuryHeight() int64 { return milestoneMercuryHeight -} \ No newline at end of file +} diff --git a/x/evm/types/utils.go b/x/evm/types/utils.go index e0000234bb..127d3f16a8 100644 --- a/x/evm/types/utils.go +++ b/x/evm/types/utils.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "fmt" authtypes "github.com/okex/exchain/libs/cosmos-sdk/x/auth/types" + "github.com/okex/exchain/libs/tendermint/global" + "github.com/okex/exchain/libs/tendermint/types" "math/big" "strings" @@ -533,18 +535,29 @@ func DecodeResultData(in []byte) (ResultData, error) { // TxDecoder returns an sdk.TxDecoder that can decode both auth.StdTx and // MsgEthereumTx transactions. func TxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, error) { + return func(txBytes []byte, heights ...int64) (sdk.Tx, error) { + if len(heights) > 1 { + return nil, fmt.Errorf("to many height parameters") + } var tx sdk.Tx var err error if len(txBytes) == 0 { return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } - // TODO: Is there a better way to Decode RLP-encoded MsgEthereumTx? - // Try to decode as MsgEthereumTx through RLP - var ethTx MsgEthereumTx - if err = authtypes.EthereumTxDecode(txBytes, ðTx); err == nil { - return ethTx, nil + var height int64 + if len(heights) == 1 { + height = heights[0] + } else { + height = global.GetGlobalHeight() + } + + if types.HigherThanVenus(height) { + // Try to decode as MsgEthereumTx through RLP + var ethTx MsgEthereumTx + if err = authtypes.EthereumTxDecode(txBytes, ðTx); err == nil { + return ethTx, nil + } } // sdk.Tx is an interface. The concrete message types