Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(evm-rpc-backend): Add testnetwork tests using a node with a real RPC backend #2037

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0868ce8
wip!: checkpoint
Unique-Divine Sep 9, 2024
97da983
Merge branch 'main' into ud/2408/eth-rpc
Unique-Divine Sep 9, 2024
bb6cb20
remove dead code
Unique-Divine Sep 9, 2024
563c253
test(e2e): remove unnecessary skips
Unique-Divine Sep 9, 2024
94519d4
pending chekcpoint
Unique-Divine Sep 10, 2024
0b4b39b
chore(github): Automate labeleing and add-to-project for GH issues/ti…
Unique-Divine Sep 11, 2024
1390371
Merge branch 'main' into ud/2408/eth-rpc
Unique-Divine Sep 11, 2024
f92de5e
chore: changelog
Unique-Divine Sep 11, 2024
121287d
Merge branch 'main' into ud/2408/eth-rpc
Unique-Divine Sep 12, 2024
a580362
chore: linter and changelog
Unique-Divine Sep 12, 2024
1df1e9d
wip!: save
Unique-Divine Sep 12, 2024
2f8b1e4
chore: stopping point
Unique-Divine Sep 12, 2024
255305b
chore: linter
Unique-Divine Sep 12, 2024
b971a9a
refactor(evm): use typed event for tx logs and message emission
Unique-Divine Sep 12, 2024
5bcf6a7
remove rpc/backend mocks and add test setup
Unique-Divine Sep 12, 2024
8441dde
chore: changelog
Unique-Divine Sep 12, 2024
452d47e
Merge branch 'main' into ud/evm-events
Unique-Divine Sep 12, 2024
bd43152
refactor: remove unused
Unique-Divine Sep 12, 2024
180c146
refactor: remove unnecessary code
Unique-Divine Sep 12, 2024
a4a2e65
fix: panic on nil gethcore.Log passed to bloom constructor
Unique-Divine Sep 12, 2024
28628cd
Squashed commit of the following:
Unique-Divine Sep 12, 2024
5122384
test(evm): eth rpc backend test coverage
onikonychev Sep 13, 2024
c0aab07
RPC backend
Unique-Divine Sep 14, 2024
73c7714
Merge branch 'main' into ud/evm-events2
Unique-Divine Sep 14, 2024
bbe5f5f
revert name change
Unique-Divine Sep 14, 2024
f2aea94
Merge branch 'ud/evm-events2' into ud/evm-events
Unique-Divine Sep 14, 2024
6bc52db
test(evm): backend tests for tx_info
onikonychev Sep 14, 2024
f9ef4ee
fix: merge conflict
Unique-Divine Sep 15, 2024
726a38a
Merge branch 'test/evm-backend' into ud/evm-events
Unique-Divine Sep 15, 2024
6f054cf
test: add block query to validator node
Unique-Divine Sep 15, 2024
7e72fad
fix(app-server): remove missing field from tempalte
Unique-Divine Sep 15, 2024
80c91a2
fix: use typed receipt value in GetTransactionReceipt
Unique-Divine Sep 15, 2024
14b7625
test: fix assertions in TestGetTransactionReceipt
Unique-Divine Sep 15, 2024
d43511e
revert: use legacy event
Unique-Divine Sep 16, 2024
b1633b6
Merge branch 'main' into ud/evm-events3
Unique-Divine Sep 19, 2024
943b164
Merge branch 'main' into ud/evm-events
Unique-Divine Sep 19, 2024
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 @@ -119,6 +119,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#2023](https://github.com/NibiruChain/nibiru/pull/2023) - fix(evm)!: adjusted generation and parsing of the block bloom events
- [#2030](https://github.com/NibiruChain/nibiru/pull/2030) - refactor(eth/rpc): Delete unused code and improve logging in the eth and debug namespaces
- [#2031](https://github.com/NibiruChain/nibiru/pull/2031) - fix(evm): debug calls with custom tracer and tracer options
- [#2037](https://github.com/NibiruChain/nibiru/pull/2037) - test(evm-rpc-backend): Add testnetwork tests using a node with a real RPC backend
- [#2039](https://github.com/NibiruChain/nibiru/pull/2039) - refactor(rpc-backend): remove unnecessary interface code
- [#2039](https://github.com/NibiruChain/nibiru/pull/2039) - refactor(rpc-backend): Remove mocks from eth/rpc/backend, partially completing [nibiru#2037](https://github.com/NibiruChain/nibiru/issue/2037).

Expand Down
43 changes: 17 additions & 26 deletions app/server/config/server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ const (
// DefaultEVMTracer is the default vm.Tracer type
DefaultEVMTracer = ""

// DefaultFixRevertGasRefundHeight is the default height at which to overwrite gas refund
DefaultFixRevertGasRefundHeight = 0

// DefaultMaxTxGasWanted is the default gas wanted for each eth tx returned in ante handler in check tx mode
DefaultMaxTxGasWanted = 0

Expand Down Expand Up @@ -160,8 +157,6 @@ type JSONRPCConfig struct {
EnableIndexer bool `mapstructure:"enable-indexer"`
// MetricsAddress defines the metrics server to listen on
MetricsAddress string `mapstructure:"metrics-address"`
// FixRevertGasRefundHeight defines the upgrade height for fix of revert gas refund logic when transaction reverted
FixRevertGasRefundHeight int64 `mapstructure:"fix-revert-gas-refund-height"`
}

// TLSConfig defines the certificate and matching private key for the server.
Expand Down Expand Up @@ -254,24 +249,23 @@ func GetAPINamespaces() []string {
// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default
func DefaultJSONRPCConfig() *JSONRPCConfig {
return &JSONRPCConfig{
Enable: false,
API: GetDefaultAPINamespaces(),
Address: DefaultJSONRPCAddress,
WsAddress: DefaultJSONRPCWsAddress,
GasCap: DefaultEthCallGasLimit,
EVMTimeout: DefaultEVMTimeout,
TxFeeCap: DefaultTxFeeCap,
FilterCap: DefaultFilterCap,
FeeHistoryCap: DefaultFeeHistoryCap,
BlockRangeCap: DefaultBlockRangeCap,
LogsCap: DefaultLogsCap,
HTTPTimeout: DefaultHTTPTimeout,
HTTPIdleTimeout: DefaultHTTPIdleTimeout,
AllowUnprotectedTxs: DefaultAllowUnprotectedTxs,
MaxOpenConnections: DefaultMaxOpenConnections,
EnableIndexer: false,
MetricsAddress: DefaultJSONRPCMetricsAddress,
FixRevertGasRefundHeight: DefaultFixRevertGasRefundHeight,
Enable: false,
API: GetDefaultAPINamespaces(),
Address: DefaultJSONRPCAddress,
WsAddress: DefaultJSONRPCWsAddress,
GasCap: DefaultEthCallGasLimit,
EVMTimeout: DefaultEVMTimeout,
TxFeeCap: DefaultTxFeeCap,
FilterCap: DefaultFilterCap,
FeeHistoryCap: DefaultFeeHistoryCap,
BlockRangeCap: DefaultBlockRangeCap,
LogsCap: DefaultLogsCap,
HTTPTimeout: DefaultHTTPTimeout,
HTTPIdleTimeout: DefaultHTTPIdleTimeout,
AllowUnprotectedTxs: DefaultAllowUnprotectedTxs,
MaxOpenConnections: DefaultMaxOpenConnections,
EnableIndexer: false,
MetricsAddress: DefaultJSONRPCMetricsAddress,
}
}

Expand Down Expand Up @@ -478,9 +472,6 @@ enable-indexer = {{ .JSONRPC.EnableIndexer }}
# Prometheus metrics path: /debug/metrics/prometheus
metrics-address = "{{ .JSONRPC.MetricsAddress }}"

# Upgrade height for fix of revert gas refund logic when transaction reverted.
fix-revert-gas-refund-height = {{ .JSONRPC.FixRevertGasRefundHeight }}

###############################################################################
### TLS Configuration ###
###############################################################################
Expand Down
79 changes: 40 additions & 39 deletions eth/rpc/backend/tx_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,22 @@
return nil, nil
}

// GetGasUsed returns gasUsed from transaction, patching to
// price * gas in the event the tx is reverted.
func (b *Backend) GetGasUsed(res *eth.TxResult, price *big.Int, gas uint64) uint64 {
if res.Failed && res.Height < b.cfg.JSONRPC.FixRevertGasRefundHeight {
return new(big.Int).Mul(price, new(big.Int).SetUint64(gas)).Uint64()
}
return res.GasUsed
// TransactionReceipt represents the results of a transaction. TransactionReceipt
// is an extension of gethcore.Receipt, the response type for the
// "eth_getTransactionReceipt" JSON-RPC method.
// Reason being, the gethcore.Receipt struct has an incorrect JSON struct tag on one
// field and doesn't marshal JSON as expected, so we embed and extend it here.
type TransactionReceipt struct {
gethcore.Receipt

ContractAddress *gethcommon.Address `json:"contractAddress,omitempty"`
From gethcommon.Address
To *gethcommon.Address
EffectiveGasPrice *big.Int
}

// GetTransactionReceipt returns the transaction receipt identified by hash.
func (b *Backend) GetTransactionReceipt(hash gethcommon.Hash) (map[string]interface{}, error) {
func (b *Backend) GetTransactionReceipt(hash gethcommon.Hash) (*TransactionReceipt, error) {
hexTx := hash.Hex()
b.logger.Debug("eth_getTransactionReceipt", "hash", hexTx)

Expand Down Expand Up @@ -175,12 +180,11 @@
}
cumulativeGasUsed += res.CumulativeGasUsed

var status hexutil.Uint
var status uint64 = gethcore.ReceiptStatusSuccessful
if res.Failed {
status = hexutil.Uint(gethcore.ReceiptStatusFailed)
} else {
status = hexutil.Uint(gethcore.ReceiptStatusSuccessful)
status = gethcore.ReceiptStatusFailed

Check warning on line 185 in eth/rpc/backend/tx_info.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/tx_info.go#L185

Added line #L185 was not covered by tests
}

chainID, err := b.ChainID()
if err != nil {
return nil, err
Expand Down Expand Up @@ -213,40 +217,38 @@
return nil, errors.New("can't find index of ethereum tx")
}

// TODO: refactor(evm-rpc-backend): Replace interface with gethcore.Receipt
// in eth_getTransactionReceipt
receipt := map[string]interface{}{
// Consensus fields: These fields are defined by the Yellow Paper
"status": status,
"cumulativeGasUsed": hexutil.Uint64(cumulativeGasUsed),
"logsBloom": gethcore.BytesToBloom(gethcore.LogsBloom(logs)),
"logs": logs,
receipt := TransactionReceipt{
Receipt: gethcore.Receipt{
Type: ethMsg.AsTransaction().Type(),

// Implementation fields: These fields are added by geth when processing a transaction.
// They are stored in the chain database.
"transactionHash": hash,
"contractAddress": nil,
"gasUsed": hexutil.Uint64(b.GetGasUsed(res, txData.GetGasPrice(), txData.GetGas())),
// Consensus fields: These fields are defined by the Etheruem Yellow Paper
Status: status,
CumulativeGasUsed: cumulativeGasUsed,
Bloom: gethcore.BytesToBloom(gethcore.LogsBloom(logs)),
Logs: logs,

// Inclusion information: These fields provide information about the inclusion of the
// transaction corresponding to this receipt.
"blockHash": gethcommon.BytesToHash(resBlock.Block.Header.Hash()).Hex(),
"blockNumber": hexutil.Uint64(res.Height),
"transactionIndex": hexutil.Uint64(res.EthTxIndex),
// Implementation fields: These fields are added by geth when processing a transaction.
// They are stored in the chain database.
TxHash: hash,
GasUsed: res.GasUsed,

// sender and receiver (contract or EOA) addreses
"from": from,
"to": txData.GetTo(),
"type": hexutil.Uint(ethMsg.AsTransaction().Type()),
BlockHash: gethcommon.BytesToHash(resBlock.Block.Header.Hash()),
BlockNumber: big.NewInt(res.Height),
TransactionIndex: uint(res.EthTxIndex),
},
ContractAddress: nil,
From: from,
To: txData.GetTo(),
}

if logs == nil {
receipt["logs"] = [][]*gethcore.Log{}
receipt.Logs = []*gethcore.Log{}
}

// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
if txData.GetTo() == nil {
receipt["contractAddress"] = crypto.CreateAddress(from, txData.GetNonce())
addr := crypto.CreateAddress(from, txData.GetNonce())
receipt.ContractAddress = &addr

Check warning on line 251 in eth/rpc/backend/tx_info.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/tx_info.go#L250-L251

Added lines #L250 - L251 were not covered by tests
}

if dynamicTx, ok := txData.(*evm.DynamicFeeTx); ok {
Expand All @@ -255,11 +257,10 @@
// tolerate the error for pruned node.
b.logger.Error("fetch basefee failed, node is pruned?", "height", res.Height, "error", err)
} else {
receipt["effectiveGasPrice"] = hexutil.Big(*dynamicTx.EffectiveGasPriceWei(baseFee))
receipt.EffectiveGasPrice = dynamicTx.EffectiveGasPriceWei(baseFee)

Check warning on line 260 in eth/rpc/backend/tx_info.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/tx_info.go#L260

Added line #L260 was not covered by tests
}
}

return receipt, nil
return &receipt, nil
}

// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
Expand Down
53 changes: 46 additions & 7 deletions eth/rpc/backend/tx_info_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package backend_test

import (
"encoding/json"
"math/big"

gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gethcore "github.com/ethereum/go-ethereum/core/types"

"github.com/NibiruChain/nibiru/v2/eth/rpc"
"github.com/NibiruChain/nibiru/v2/eth/rpc/backend"
"github.com/NibiruChain/nibiru/v2/x/evm/evmtest"
)

func (s *BackendSuite) TestGetTransactionByHash() {
Expand Down Expand Up @@ -73,13 +77,13 @@ func (s *BackendSuite) TestGetTransactionReceipt() {
s.Require().NotNil(receipt)

// Check fields
// s.Equal(s.fundedAccEthAddr, receipt.From)
// s.Equal(&recipient, receipt.To)
// s.Greater(receipt.GasUsed, uint64(0))
// s.Equal(receipt.GasUsed, receipt.CumulativeGasUsed)
// s.Equal(tc.txHash, receipt.TxHash)
// s.Nil(receipt.ContractAddress)
// s.Require().Equal(gethcore.ReceiptStatusSuccessful, receipt.Status)
s.Equal(s.fundedAccEthAddr, receipt.From)
s.Equal(&recipient, receipt.To)
s.Greater(receipt.GasUsed, uint64(0))
s.Equal(receipt.GasUsed, receipt.CumulativeGasUsed)
s.Equal(tc.txHash, receipt.TxHash)
s.Nil(receipt.ContractAddress)
s.Require().Equal(gethcore.ReceiptStatusSuccessful, receipt.Status)
})
}
}
Expand Down Expand Up @@ -177,3 +181,38 @@ func AssertTxResults(s *BackendSuite, tx *rpc.EthTxJsonRPC, expectedTxHash gethc
s.Require().Equal(expectedTxHash, tx.Hash)
s.Require().Equal(uint64(1), uint64(*tx.TransactionIndex))
}

func (s *BackendSuite) TestReceiptMarshalJson() {
toAddr := evmtest.NewEthPrivAcc().EthAddr
tr := backend.TransactionReceipt{
Receipt: gethcore.Receipt{
Type: 0,
PostState: []byte{},
Status: 0,
CumulativeGasUsed: 0,
Bloom: [256]byte{},
Logs: []*gethcore.Log{},
TxHash: [32]byte{},
ContractAddress: [20]byte{},
GasUsed: 0,
BlockHash: [32]byte{},
BlockNumber: &big.Int{},
TransactionIndex: 0,
},
ContractAddress: nil,
From: evmtest.NewEthPrivAcc().EthAddr,
To: &toAddr,
EffectiveGasPrice: big.NewInt(1),
}

jsonBz, err := json.Marshal(tr)
s.Require().NoError(err)

gethReceipt := new(gethcore.Receipt)
err = json.Unmarshal(jsonBz, gethReceipt)
s.Require().NoError(err)

receipt := new(backend.TransactionReceipt)
err = json.Unmarshal(jsonBz, receipt)
s.Require().NoError(err)
}
27 changes: 21 additions & 6 deletions eth/rpc/backend/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
continue
}

logs, err := ParseTxLogsFromEvent(event)
logs, err := ParseTxLogsFromABCIEvent(event)

Check warning on line 217 in eth/rpc/backend/utils.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L217

Added line #L217 was not covered by tests
if err != nil {
return nil, err
}
Expand All @@ -225,7 +225,9 @@
}

// TxLogsFromEvents parses ethereum logs from cosmos events for specific msg index
func TxLogsFromEvents(events []abci.Event, msgIndex int) ([]*gethcore.Log, error) {
func TxLogsFromEvents(
events []abci.Event, msgIndex int,
) (txLogsForMsgIdx []*gethcore.Log, err error) {
for _, event := range events {
if event.Type != evm.EventTypeTxLog {
continue
Expand All @@ -237,13 +239,14 @@
continue
}

return ParseTxLogsFromEvent(event)
return ParseTxLogsFromABCIEvent(event)
}
return nil, fmt.Errorf("eth tx logs not found for message index %d", msgIndex)
}

// ParseTxLogsFromEvent parse tx logs from one event
func ParseTxLogsFromEvent(event abci.Event) ([]*gethcore.Log, error) {
// ParseTxLogsFromABCIEvent is similar to the [ParseTxLogsFromEvent] function,
// except it's used for the legacy ABCI event for transaction logs.
func ParseTxLogsFromABCIEvent(event abci.Event) ([]*gethcore.Log, error) {
logs := make([]*evm.Log, 0, len(event.Attributes))
for _, attr := range event.Attributes {
if attr.Key != evm.AttributeKeyTxLog {
Expand All @@ -254,12 +257,24 @@
if err := json.Unmarshal([]byte(attr.Value), &log); err != nil {
return nil, err
}

logs = append(logs, &log)
}
return evm.LogsToEthereum(logs), nil
}

// ParseTxLogsFromEvent parse tx logs from one event
func ParseTxLogsFromEvent(event *evm.EventTxLog) ([]*gethcore.Log, error) {
evmTxLogs := []*gethcore.Log{}
for _, txLogStr := range event.TxLogs {
txLog := new(evm.Log)
if err := json.Unmarshal([]byte(txLogStr), txLog); err != nil {
return nil, err

Check warning on line 271 in eth/rpc/backend/utils.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L266-L271

Added lines #L266 - L271 were not covered by tests
}
evmTxLogs = append(evmTxLogs, txLog.ToEthereum())

Check warning on line 273 in eth/rpc/backend/utils.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L273

Added line #L273 was not covered by tests
}
return evmTxLogs, nil

Check warning on line 275 in eth/rpc/backend/utils.go

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L275

Added line #L275 was not covered by tests
}

// ShouldIgnoreGasUsed returns true if the gasUsed in result should be ignored
// workaround for issue: https://github.com/cosmos/cosmos-sdk/issues/10832
func ShouldIgnoreGasUsed(res *abci.ResponseDeliverTx) bool {
Expand Down
4 changes: 2 additions & 2 deletions eth/rpc/rpcapi/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type IEthAPI interface {
// it is a user or a smart contract.
GetTransactionByHash(hash common.Hash) (*rpc.EthTxJsonRPC, error)
GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error)
GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error)
GetTransactionReceipt(hash common.Hash) (*backend.TransactionReceipt, error)
GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpc.EthTxJsonRPC, error)
GetTransactionByBlockNumberAndIndex(blockNum rpc.BlockNumber, idx hexutil.Uint) (*rpc.EthTxJsonRPC, error)
// eth_getBlockReceipts
Expand Down Expand Up @@ -192,7 +192,7 @@ func (e *EthAPI) GetTransactionCount(
// GetTransactionReceipt returns the transaction receipt identified by hash.
func (e *EthAPI) GetTransactionReceipt(
hash common.Hash,
) (map[string]interface{}, error) {
) (*backend.TransactionReceipt, error) {
hexTx := hash.Hex()
e.logger.Debug("eth_getTransactionReceipt", "hash", hexTx)
return e.backend.GetTransactionReceipt(hash)
Expand Down
Loading
Loading