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

refactor(evm): remove double JSON escaping of EventEthereumTx logs #2188

Merged
merged 7 commits into from
Feb 4, 2025
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 @@ -94,6 +94,7 @@ needed to include double quotes around the hexadecimal string.
- [#2183](https://github.com/NibiruChain/nibiru/pull/2183) - fix(evm): bank keeper extension gas meter type
- [#2184](https://github.com/NibiruChain/nibiru/pull/2184) - test(evm): e2e tests configuration enhancements
- [#2187](https://github.com/NibiruChain/nibiru/pull/2187) - fix(evm): fix eip55 address encoding
- [#2188](https://github.com/NibiruChain/nibiru/pull/2188) - refactor(evm): update logs emission
- [#2192](https://github.com/NibiruChain/nibiru/pull/2192) - fix(oracle): correctly handle misscount

#### Nibiru EVM | Before Audit 2 - 2024-12-06
Expand Down
5 changes: 3 additions & 2 deletions eth/rpc/backend/tx_logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"

"github.com/NibiruChain/nibiru/v2/eth"
"github.com/NibiruChain/nibiru/v2/eth/rpc/backend"
"github.com/NibiruChain/nibiru/v2/x/common/testutil"
"github.com/NibiruChain/nibiru/v2/x/evm"
"github.com/NibiruChain/nibiru/v2/x/evm/embeds"
Expand Down Expand Up @@ -241,8 +240,10 @@ func (s *BackendSuite) assertTxLogsAndTxIndex(
foundEthTx := false
for _, event := range events {
if event.Type == evm.TypeUrlEventTxLog {
logs, err := backend.ParseTxLogsFromEvent(event)
eventTxLog, err := evm.EventTxLogFromABCIEvent(event)
s.Require().NoError(err)

logs := evm.LogsToEthereum(eventTxLog.Logs)
if len(expectedTxLogs) > 0 {
s.Require().GreaterOrEqual(len(logs), len(expectedTxLogs))
s.assertTxLogsMatch(expectedTxLogs, logs, txInfo)
Expand Down
68 changes: 23 additions & 45 deletions eth/rpc/backend/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
package backend

import (
"encoding/json"
"fmt"
"math/big"
"sort"
Expand All @@ -11,7 +10,6 @@
"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

Expand Down Expand Up @@ -210,28 +208,10 @@
return nil
}

// AllTxLogsFromEvents parses all ethereum logs from cosmos events
func AllTxLogsFromEvents(events []abci.Event) ([][]*gethcore.Log, error) {
allLogs := make([][]*gethcore.Log, 0, 4)
for _, event := range events {
if event.Type != proto.MessageName(new(evm.EventTxLog)) {
continue
}

logs, err := ParseTxLogsFromEvent(event)
if err != nil {
return nil, err
}

allLogs = append(allLogs, logs)
}
return allLogs, nil
}

// TxLogsFromEvents parses ethereum logs from cosmos events for specific msg index
func TxLogsFromEvents(events []abci.Event, msgIndex int) ([]*gethcore.Log, error) {
for _, event := range events {
if event.Type != proto.MessageName(new(evm.EventTxLog)) {
if event.Type != evm.TypeUrlEventTxLog {
continue
}

Expand All @@ -241,26 +221,13 @@
continue
}

return ParseTxLogsFromEvent(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) {
eventTxLog, err := evm.EventTxLogFromABCIEvent(event)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse event tx log")
}
var evmLogs []*evm.Log
for _, logString := range eventTxLog.TxLogs {
var evmLog evm.Log
if err = json.Unmarshal([]byte(logString), &evmLog); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal event tx log")
eventTxLog, err := evm.EventTxLogFromABCIEvent(event)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse event tx log")

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

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L226

Added line #L226 was not covered by tests
}
evmLogs = append(evmLogs, &evmLog)
return evm.LogsToEthereum(eventTxLog.Logs), nil
}
return evm.LogsToEthereum(evmLogs), nil
return nil, fmt.Errorf("eth tx logs not found for message index %d", msgIndex)

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

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L230

Added line #L230 was not covered by tests
}

// ShouldIgnoreGasUsed returns true if the gasUsed in result should be ignored
Expand All @@ -272,16 +239,27 @@
// GetLogsFromBlockResults returns the list of event logs from the tendermint block result response
func GetLogsFromBlockResults(
blockRes *tmrpctypes.ResultBlockResults,
) ([][]*gethcore.Log, error) {
blockLogs := [][]*gethcore.Log{}
) (blockLogs [][]*gethcore.Log, err error) {
blockLogs = [][]*gethcore.Log{}
for _, txResult := range blockRes.TxsResults {
logs, err := AllTxLogsFromEvents(txResult.Events)
if err != nil {
return nil, err
txLogs := []*gethcore.Log{}

for _, event := range txResult.Events {
if event.Type != evm.TypeUrlEventTxLog {
continue
}

eventTxLogs, err := evm.EventTxLogFromABCIEvent(event)
if err != nil {
return nil, err
}

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

View check run for this annotation

Codecov / codecov/patch

eth/rpc/backend/utils.go#L254-L255

Added lines #L254 - L255 were not covered by tests

txLogs = append(txLogs, evm.LogsToEthereum(eventTxLogs.Logs)...)
}

blockLogs = append(blockLogs, logs...)
blockLogs = append(blockLogs, txLogs)
}

return blockLogs, nil
}

Expand Down
10 changes: 3 additions & 7 deletions eth/rpc/events_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
abci "github.com/cometbft/cometbft/abci/types"
tmrpctypes "github.com/cometbft/cometbft/rpc/core/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/gogoproto/proto"
gethcommon "github.com/ethereum/go-ethereum/common"

"github.com/NibiruChain/nibiru/v2/eth"
Expand Down Expand Up @@ -39,9 +38,6 @@ type ParsedTxs struct {

// ParseTxResult parses eth tx info from the ABCI events of Eth tx msgs
func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error) {
eventTypePendingEthereumTx := evm.PendingEthereumTxEvent
eventTypeEthereumTx := proto.MessageName((*evm.EventEthereumTx)(nil))

// Parsed txs is the structure being populated from the events
// So far (until we allow ethereum_txs as cosmos tx messages) it'll have single tx
parsedTxs := &ParsedTxs{
Expand All @@ -53,7 +49,7 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error
msgIndex := -1
for _, event := range result.Events {
// Pending tx event could be single if tx didn't succeed
if event.Type == eventTypePendingEthereumTx {
if event.Type == evm.PendingEthereumTxEvent {
msgIndex++
ethHash, txIndex, err := evm.GetEthHashAndIndexFromPendingEthereumTxEvent(event)
if err != nil {
Expand All @@ -66,7 +62,7 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error
}
parsedTxs.Txs = append(parsedTxs.Txs, pendingTx)
parsedTxs.TxHashes[ethHash] = msgIndex
} else if event.Type == eventTypeEthereumTx { // Full event replaces the pending tx
} else if event.Type == evm.TypeUrlEventEthereumTx { // Full event replaces the pending tx
eventEthereumTx, err := evm.EventEthereumTxFromABCIEvent(event)
if err != nil {
return nil, err
Expand All @@ -84,7 +80,7 @@ func ParseTxResult(result *abci.ResponseDeliverTx, tx sdk.Tx) (*ParsedTxs, error
EthTxIndex: int32(ethTxIndexFromEvent),
EthHash: gethcommon.HexToHash(eventEthereumTx.EthHash),
GasUsed: gasUsed,
Failed: len(eventEthereumTx.EthTxFailed) > 0,
Failed: len(eventEthereumTx.VmError) > 0,
}
// find the pending tx to replace by tx hash
pendingMsgIndex, found := parsedTxs.TxHashes[committedTx.EthHash]
Expand Down
12 changes: 6 additions & 6 deletions eth/rpc/events_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,16 @@ func pendingEthereumTxEvent(txHash string, txIndex int) abci.Event {
}

func ethereumTxEvent(txHash string, txIndex int, gasUsed int, failed bool) abci.Event {
failure := ""
var vmError string
if failed {
failure = "failed"
vmError = "failed"
}
event, err := sdk.TypedEventToEvent(
&evm.EventEthereumTx{
EthHash: txHash,
Index: strconv.Itoa(txIndex),
GasUsed: strconv.Itoa(gasUsed),
EthTxFailed: failure,
EthHash: txHash,
Index: strconv.Itoa(txIndex),
GasUsed: strconv.Itoa(gasUsed),
VmError: vmError,
},
)
if err != nil {
Expand Down
7 changes: 4 additions & 3 deletions proto/eth/evm/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import "cosmos/base/v1beta1/coin.proto";
import "gogoproto/gogo.proto";
import "eth/evm/v1/evm.proto";

option go_package = "github.com/NibiruChain/nibiru/v2/x/evm";

Expand All @@ -21,14 +22,14 @@
string hash = 5;
// recipient of the transaction
string recipient = 6;
// eth_tx_failed contains a VM error should it occur
string eth_tx_failed = 7;
// vm_error contains a VM error should it occur
string vm_error = 7;

Check failure on line 26 in proto/eth/evm/v1/events.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "7" with name "vm_error" on message "EventEthereumTx" changed option "json_name" from "ethTxFailed" to "vmError".

Check failure on line 26 in proto/eth/evm/v1/events.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "7" on message "EventEthereumTx" changed name from "eth_tx_failed" to "vm_error".
}

// EventTxLog defines the event for an Ethereum transaction log
message EventTxLog {
// tx_logs is an array of transaction logs
repeated string tx_logs = 1;
repeated Log logs = 1 [ (gogoproto.nullable) = false ];

Check failure on line 32 in proto/eth/evm/v1/events.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "1" with name "logs" on message "EventTxLog" changed option "json_name" from "txLogs" to "logs".

Check failure on line 32 in proto/eth/evm/v1/events.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "1" with name "logs" on message "EventTxLog" changed type from "string" to "message".

Check failure on line 32 in proto/eth/evm/v1/events.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "1" on message "EventTxLog" changed name from "tx_logs" to "logs".
}

// EventBlockBloom defines an Ethereum block bloom filter event
Expand Down
40 changes: 3 additions & 37 deletions proto/eth/evm/v1/evm.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2024 Nibi, Inc.

Check failure on line 1 in proto/eth/evm/v1/evm.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present message "TransactionLogs" was deleted from file.

Check failure on line 1 in proto/eth/evm/v1/evm.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present message "TxResult" was deleted from file.
syntax = "proto3";
package eth.evm.v1;

Expand Down Expand Up @@ -68,16 +68,6 @@
string value = 2;
}

// TransactionLogs define the logs generated from a transaction execution
// with a given hash. It it used for import/export data as transactions are not
// persisted on blockchain state after an upgrade.
message TransactionLogs {
// hash of the transaction
string hash = 1;
// logs is an array of Logs for the given transaction hash
repeated Log logs = 2;
}

// Log represents an protobuf compatible Ethereum Log that defines a contract
// log event. These events are generated by the LOG opcode and stored/indexed by
// the node.
Expand Down Expand Up @@ -109,31 +99,6 @@
bool removed = 9;
}

// TxResult stores results of Tx execution.
message TxResult {
option (gogoproto.goproto_getters) = false;

// contract_address contains the ethereum address of the created contract (if
// any). If the state transition is an evm.Call, the contract address will be
// empty.
string contract_address = 1
[ (gogoproto.moretags) = "yaml:\"contract_address\"" ];
// bloom represents the bloom filter bytes
bytes bloom = 2;
// tx_logs contains the transaction hash and the proto-compatible ethereum
// logs.
TransactionLogs tx_logs = 3 [
(gogoproto.moretags) = "yaml:\"tx_logs\"",
(gogoproto.nullable) = false
];
// ret defines the bytes from the execution.
bytes ret = 4;
// reverted flag is set to true when the call has been reverted
bool reverted = 5;
// gas_used notes the amount of gas consumed while execution
uint64 gas_used = 6;
}

// AccessTuple is the element type of an access list.
message AccessTuple {
option (gogoproto.goproto_getters) = false;
Expand All @@ -144,9 +109,10 @@
repeated string storage_keys = 2 [ (gogoproto.jsontag) = "storageKeys" ];
}

// TracerConfig stores additional tracer args. For geth it's only one attr: onlyTopCall
// TracerConfig stores additional tracer args. For geth it's only one attr:
// onlyTopCall
message TracerConfig {
bool only_top_call = 1 [ (gogoproto.jsontag) = "onlyTopCall" ];
bool only_top_call = 1 [ (gogoproto.jsontag) = "onlyTopCall" ];
}

// TraceConfig holds extra parameters to trace functions.
Expand Down
Loading
Loading