Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (ante) [#59](https://github.com/EscanBE/evermint/pull/59) Prevent panic when building error message of fee which overflow int64
- (swagger) [#66](https://github.com/EscanBE/evermint/pull/66) Correct script gen swagger after switched to use vanilla Cosmos-SDK
- (rename-chain) [#80](https://github.com/EscanBE/evermint/pull/80) Handle new cases of rename-chain with recent changes
- (rpc) [#85](https://github.com/EscanBE/evermint/pull/85) Compute and return correct `transactionsRoot` and `receiptsRoot` hashes

### Client Breaking

Expand Down
2 changes: 1 addition & 1 deletion rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ type EVMBackend interface {
GetTxByEthHash(txHash common.Hash) (*evertypes.TxResult, error)
GetTxByTxIndex(height int64, txIndex uint) (*evertypes.TxResult, error)
GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error)
GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error)
GetTransactionReceipt(hash common.Hash) (*rpctypes.RPCReceipt, error)
GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error)
GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error)

Expand Down
81 changes: 58 additions & 23 deletions rpc/backend/backend_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (suite *BackendTestSuite) SetupTest() {
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T())
suite.backend.ctx = rpctypes.ContextWithHeight(1)
suite.backend.indexer = mocks.NewEVMTxIndexer(suite.T())

// Add codec
encCfg := encoding.MakeConfig(app.ModuleBasics)
Expand Down Expand Up @@ -130,40 +131,55 @@ func (suite *BackendTestSuite) buildFormattedBlock(
gasLimit := int64(^uint32(0)) // for `MaxGas = -1` (DefaultConsensusParams)
gasUsed := new(big.Int).SetUint64(uint64(blockRes.TxsResults[0].GasUsed))

root := common.Hash{}.Bytes()
receipt := ethtypes.NewReceipt(root, false, gasUsed.Uint64())
bloom := ethtypes.CreateBloom(ethtypes.Receipts{receipt})

ethRPCTxs := []interface{}{}
var transactions ethtypes.Transactions
var receipts ethtypes.Receipts
if tx != nil {
if fullTx {
rpcTx, err := rpctypes.NewRPCTransaction(
tx.AsTransaction(),
common.BytesToHash(header.Hash()),
uint64(header.Height),
uint64(0),
baseFee,
suite.backend.chainID,
)
suite.Require().NoError(err)
ethRPCTxs = []interface{}{rpcTx}
} else {
ethRPCTxs = []interface{}{common.HexToHash(tx.Hash)}
}
transactions = append(transactions, tx.AsTransaction())
receipt := createTestReceipt(nil, resBlock, tx, false, mockGasUsed)
receipts = append(receipts, receipt)
}

bloom := ethtypes.CreateBloom(receipts)

return rpctypes.FormatBlock(
header,
suite.backend.chainID,
resBlock.Block.Size(),
gasLimit,
gasUsed,
ethRPCTxs,
gasLimit, gasUsed, baseFee,
transactions, fullTx,
receipts,
bloom,
common.BytesToAddress(validator.Bytes()),
baseFee,
suite.backend.logger,
)
}

func createTestReceipt(root []byte, resBlock *tmrpctypes.ResultBlock, tx *evmtypes.MsgEthereumTx, failed bool, gasUsed uint64) *ethtypes.Receipt {
var status uint64
if failed {
status = ethtypes.ReceiptStatusFailed
} else {
status = ethtypes.ReceiptStatusSuccessful
}

transaction := tx.AsTransaction()

return &ethtypes.Receipt{
Type: transaction.Type(),
PostState: root,
Status: status,
CumulativeGasUsed: gasUsed,
Bloom: ethtypes.BytesToBloom(ethtypes.LogsBloom([]*ethtypes.Log{})),
Logs: []*ethtypes.Log{},
TxHash: transaction.Hash(),
ContractAddress: common.Address{},
GasUsed: gasUsed,
BlockHash: common.HexToHash(resBlock.Block.Header.Hash().String()),
BlockNumber: big.NewInt(resBlock.Block.Height),
TransactionIndex: 0,
}
}

func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Keyring, error) {
buf := bufio.NewReader(os.Stdin)
encCfg := encoding.MakeConfig(app.ModuleBasics)
Expand Down Expand Up @@ -191,3 +207,22 @@ func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEth

return txBz
}

func (suite *BackendTestSuite) signMsgEthTx(msgEthereumTx *evmtypes.MsgEthereumTx) (*evmtypes.MsgEthereumTx, []byte) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)

ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msgEthereumTx.From = suite.from.String()
err := msgEthereumTx.Sign(ethSigner, suite.signer)
suite.Require().NoError(err)

tx, err := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), constants.BaseDenom)
suite.Require().NoError(err)

txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
txBz, err := txEncoder(tx)
suite.Require().NoError(err)

return msgEthereumTx, txBz
}
145 changes: 99 additions & 46 deletions rpc/backend/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,45 +370,9 @@ func (b *Backend) RPCBlockFromTendermintBlock(
blockRes *tmrpctypes.ResultBlockResults,
fullTx bool,
) (map[string]interface{}, error) {
ethRPCTxs := []interface{}{}
block := resBlock.Block

baseFee, err := b.BaseFee(blockRes)
if err != nil {
// handle the error for pruned node.
b.logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", block.Height, "error", err)
}

msgs := b.EthMsgsFromTendermintBlock(resBlock, blockRes)
for txIndex, ethMsg := range msgs {
if !fullTx {
hash := common.HexToHash(ethMsg.Hash)
ethRPCTxs = append(ethRPCTxs, hash)
continue
}

tx := ethMsg.AsTransaction()
height := uint64(block.Height) //#nosec G701 -- checked for int overflow already
index := uint64(txIndex) //#nosec G701 -- checked for int overflow already
rpcTx, err := rpctypes.NewRPCTransaction(
tx,
common.BytesToHash(block.Hash()),
height,
index,
baseFee,
b.chainID,
)
if err != nil {
b.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error())
continue
}
ethRPCTxs = append(ethRPCTxs, rpcTx)
}
// prepare block information

bloom, err := b.BlockBloom(blockRes)
if err != nil {
b.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error())
}
block := resBlock.Block

req := &evmtypes.QueryValidatorAccountRequest{
ConsAddress: sdk.ConsAddress(block.Header.ProposerAddress).String(),
Expand All @@ -419,13 +383,15 @@ func (b *Backend) RPCBlockFromTendermintBlock(
ctx := rpctypes.ContextWithHeight(block.Height)
res, err := b.queryClient.ValidatorAccount(ctx, req)
if err != nil {
// TODO ES return error
b.logger.Debug(
"failed to query validator operator address",
"height", block.Height,
"cons-address", req.ConsAddress,
"error", err.Error(),
)
// use zero address as the validator operator address
//goland:noinspection GoRedundantConversion
validatorAccAddr = sdk.AccAddress(common.Address{}.Bytes())
} else {
validatorAccAddr, err = sdk.AccAddressFromBech32(res.AccountAddress)
Expand All @@ -436,27 +402,114 @@ func (b *Backend) RPCBlockFromTendermintBlock(

validatorAddr := common.BytesToAddress(validatorAccAddr)

chainID, err := b.ChainID()
if err != nil {
return nil, err
}

// prepare gas & fee information

gasLimit, err := rpctypes.BlockMaxGasFromConsensusParams(ctx, b.clientCtx, block.Height)
if err != nil {
// TODO ES return error
b.logger.Error("failed to query consensus params", "error", err.Error())
}

gasUsed := uint64(0)
var gasUsed uint64
var gasUsedByTxs []uint64
for _, txResult := range blockRes.TxsResults {
gasUsedByTx := uint64(txResult.GetGasUsed()) // #nosec G701 -- checked for int overflow already

for _, txsResult := range blockRes.TxsResults {
// workaround for cosmos-sdk bug. https://github.com/cosmos/cosmos-sdk/issues/10832
if ShouldIgnoreGasUsed(txsResult) {
if ShouldIgnoreGasUsed(txResult) {
// block gas limit has exceeded, other txs must have failed with same reason.
break
gasUsedByTx = 0
}
gasUsed += uint64(txsResult.GetGasUsed()) // #nosec G701 -- checked for int overflow already

gasUsed += gasUsedByTx
gasUsedByTxs = append(gasUsedByTxs, gasUsedByTx)
}

baseFee, err := b.BaseFee(blockRes)
if err != nil {
// TODO ES return error
// handle the error for pruned node.
b.logger.Error("failed to fetch Base Fee from pruned block. Check node pruning configuration", "height", block.Height, "error", err)
}

// prepare txs information

ethMsgs := b.EthMsgsFromTendermintBlock(resBlock, blockRes)

var transactions ethtypes.Transactions
var receipts ethtypes.Receipts
for transactionIndex, ethMsg := range ethMsgs {
transaction := ethMsg.AsTransaction()

transactions = append(transactions, transaction)

indexedTxByHash, err := b.GetTxByEthHash(transaction.Hash())
if err != nil {
return nil, err
}

var cumulativeGasUsed uint64
for _, gasUsedByTx := range gasUsedByTxs[0:indexedTxByHash.TxIndex] { // previous txs
cumulativeGasUsed += gasUsedByTx
}
cumulativeGasUsed += indexedTxByHash.CumulativeGasUsed

logs, err := TxLogsFromEvents(blockRes.TxsResults[indexedTxByHash.TxIndex].Events, int(indexedTxByHash.MsgIndex))
if err != nil {
// TODO ES return error
b.logger.Debug("failed to parse logs", "hash", transaction.Hash().Hex(), "error", err.Error())
}

txData, err := evmtypes.UnpackTxData(ethMsg.Data)
if err != nil {
return nil, errors.Wrap(err, "failed to unpack tx data")
}

receipt, err := rpctypes.NewRPCReceipt(
ethMsg,
hexutil.Uint64(transactionIndex),
!indexedTxByHash.Failed,
hexutil.Uint64(b.GetGasUsed(indexedTxByHash, txData.GetGasPrice(), txData.GetGas())),
hexutil.Uint64(cumulativeGasUsed),
baseFee,
logs,
common.BytesToHash(resBlock.BlockID.Hash.Bytes()),
hexutil.Uint64(indexedTxByHash.Height),
chainID.ToInt(),
)
if err != nil {
return nil, errors.Wrap(err, "failed to create transaction receipt")
}
receipts = append(receipts, receipt.AsEthReceipt())
}

// prepare block-bloom information

bloom, err := b.BlockBloom(blockRes)
if err != nil {
// TODO ES return error
b.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error())
}

// finalize

formattedBlock := rpctypes.FormatBlock(
block.Header, block.Size(),
gasLimit, new(big.Int).SetUint64(gasUsed),
ethRPCTxs, bloom, validatorAddr, baseFee,
block.Header,
b.chainID,
block.Size(),
gasLimit, new(big.Int).SetUint64(gasUsed), baseFee,
transactions, fullTx,
receipts,
bloom,
validatorAddr,
b.logger,
)

return formattedBlock, nil
}

Expand Down
Loading