Skip to content

Commit

Permalink
fix receipt indexing to include contract address if that is creation
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Jul 16, 2024
1 parent 387ff14 commit 5ba56cc
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 108 deletions.
36 changes: 33 additions & 3 deletions indexer/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,45 @@ func (e *EVMIndexerImpl) ListenFinalizeBlock(ctx context.Context, req abci.Reque
}

ethTxs = append(ethTxs, ethTx)
ethLogs := e.extractLogsFromEvents(txResults.Events)
receipts = append(receipts, &coretypes.Receipt{

// extract logs and contract address from tx results
var ethLogs []*coretypes.Log
var contractAddr *common.Address
if ethTx.To() == nil {
var resp types.MsgCreateResponse
if err := unpackData(txResults.Data, &resp); err != nil {
e.logger.Error("failed to unpack MsgCreateResponse", "err", err)
return err
}

Check warning on line 73 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L64-L73

Added lines #L64 - L73 were not covered by tests

ethLogs = types.Logs(resp.Logs).ToEthLogs()
contractAddr_ := common.HexToAddress(resp.ContractAddr)
contractAddr = &contractAddr_
} else {
var resp types.MsgCallResponse
if err := unpackData(txResults.Data, &resp); err != nil {
e.logger.Error("failed to unpack MsgCallResponse", "err", err)
return err
}

Check warning on line 83 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L75-L83

Added lines #L75 - L83 were not covered by tests

ethLogs = types.Logs(resp.Logs).ToEthLogs()

Check warning on line 85 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L85

Added line #L85 was not covered by tests
}

receipt := coretypes.Receipt{

Check warning on line 88 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L88

Added line #L88 was not covered by tests
PostState: nil,
Status: txStatus,
CumulativeGasUsed: usedGas,
Bloom: coretypes.Bloom(coretypes.LogsBloom(ethLogs)),
Logs: ethLogs,
TransactionIndex: txIndex,
})
}

// fill in contract address if it's a contract creation
if contractAddr != nil {
receipt.ContractAddress = *contractAddr
}

Check warning on line 100 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L95-L100

Added lines #L95 - L100 were not covered by tests

receipts = append(receipts, &receipt)

Check warning on line 102 in indexer/abci.go

View check run for this annotation

Codecov / codecov/patch

indexer/abci.go#L102

Added line #L102 was not covered by tests
}

chainId := types.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID())
Expand Down
66 changes: 16 additions & 50 deletions indexer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,31 @@ package indexer
import (
"encoding/json"
"fmt"
"path/filepath"

"github.com/spf13/cast"

abci "github.com/cometbft/cometbft/abci/types"

collcodec "cosmossdk.io/collections/codec"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"

coretypes "github.com/ethereum/go-ethereum/core/types"

"github.com/initia-labs/minievm/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/gogoproto/proto"
)

// helper function to make config creation independent of root dir
func rootify(path, root string) string {
if filepath.IsAbs(path) {
return path
// unpackData extracts msg response from the data
func unpackData(data []byte, resp proto.Message) error {
var txMsgData sdk.TxMsgData
if err := proto.Unmarshal(data, &txMsgData); err != nil {
return err

Check warning on line 16 in indexer/utils.go

View check run for this annotation

Codecov / codecov/patch

indexer/utils.go#L16

Added line #L16 was not covered by tests
}
return filepath.Join(root, path)
}

// getDBConfig returns the database configuration for the EVM indexer
func getDBConfig(appOpts servertypes.AppOptions) (string, dbm.BackendType) {
rootDir := cast.ToString(appOpts.Get("home"))
dbDir := cast.ToString(appOpts.Get("db_dir"))
dbBackend := server.GetAppDBBackend(appOpts)

return rootify(dbDir, rootDir), dbBackend
}
msgResp := txMsgData.MsgResponses[0]
expectedTypeUrl := sdk.MsgTypeURL(resp)
if msgResp.TypeUrl != expectedTypeUrl {
return fmt.Errorf("unexpected type URL; got: %s, expected: %s", msgResp.TypeUrl, expectedTypeUrl)
}

Check warning on line 23 in indexer/utils.go

View check run for this annotation

Codecov / codecov/patch

indexer/utils.go#L22-L23

Added lines #L22 - L23 were not covered by tests

// extractLogsFromEvents extracts logs from the events
func (e *EVMIndexerImpl) extractLogsFromEvents(events []abci.Event) []*coretypes.Log {
var ethLogs []*coretypes.Log
for _, event := range events {
if event.Type == types.EventTypeEVM {
logs := make(types.Logs, 0, len(event.Attributes))

for _, attr := range event.Attributes {
if attr.Key == types.AttributeKeyLog {
var log types.Log
err := json.Unmarshal([]byte(attr.Value), &log)
if err != nil {
e.logger.Error("failed to unmarshal log", "err", err)
continue
}

logs = append(logs, log)
}
}

ethLogs = logs.ToEthLogs()
break
}
// Unpack the response
if err := proto.Unmarshal(msgResp.Value, resp); err != nil {
return err

Check warning on line 27 in indexer/utils.go

View check run for this annotation

Codecov / codecov/patch

indexer/utils.go#L27

Added line #L27 was not covered by tests
}

return ethLogs
return nil
}

// CollJsonVal is used for protobuf values of the newest google.golang.org/protobuf API.
Expand Down
37 changes: 37 additions & 0 deletions indexer/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package indexer

import (
"testing"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"

"github.com/initia-labs/minievm/x/evm/types"
)

func Test_UnpackData(t *testing.T) {
resp := types.MsgCreateResponse{
Result: "ret",
ContractAddr: types.StdAddress.Hex(),
Logs: []types.Log{
{
Address: types.StdAddress.Hex(),
Topics: []string{"topic"},
Data: "data",
},
},
}

anyResp, err := codectypes.NewAnyWithValue(&resp)
require.NoError(t, err)

data, err := proto.Marshal(&sdk.TxMsgData{MsgResponses: []*codectypes.Any{anyResp}})
require.NoError(t, err)

var respOut types.MsgCreateResponse
err = unpackData(data, &respOut)
require.NoError(t, err)
require.Equal(t, resp, respOut)
}
6 changes: 3 additions & 3 deletions jsonrpc/backend/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,17 @@ func (b *JSONRPCBackend) PendingTransactions() ([]*rpctypes.RPCTransaction, erro
func marshalReceipt(receipt *coretypes.Receipt, tx *rpctypes.RPCTransaction) map[string]interface{} {
fields := map[string]interface{}{
"blockHash": tx.BlockHash,
"blockNumber": hexutil.Big(*tx.BlockNumber),
"blockNumber": hexutil.Uint64(tx.BlockNumber.ToInt().Uint64()),

Check warning on line 258 in jsonrpc/backend/tx.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/tx.go#L258

Added line #L258 was not covered by tests
"transactionHash": tx.Hash,
"transactionIndex": hexutil.Uint64(*tx.TransactionIndex),
"transactionIndex": *tx.TransactionIndex,

Check warning on line 260 in jsonrpc/backend/tx.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/tx.go#L260

Added line #L260 was not covered by tests
"from": tx.From,
"to": tx.To,
"gasUsed": hexutil.Uint64(receipt.GasUsed),
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
"contractAddress": nil,
"logs": receipt.Logs,
"logsBloom": receipt.Bloom,
"type": hexutil.Uint(coretypes.LegacyTxType),
"type": hexutil.Uint(tx.Type),

Check warning on line 268 in jsonrpc/backend/tx.go

View check run for this annotation

Codecov / codecov/patch

jsonrpc/backend/tx.go#L268

Added line #L268 was not covered by tests
"effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice),
}

Expand Down
7 changes: 2 additions & 5 deletions proto/minievm/evm/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,8 @@ message QueryCallRequest {
// hex encoded call input
string input = 3;
// Value is the amount of fee denom token to transfer to the contract.
string value = 4 [
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];
string value = 4
[(gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
// whether to trace the call
// `nil` means no trace
TraceOptions trace_options = 5;
Expand Down
12 changes: 10 additions & 2 deletions proto/minievm/evm/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ message MsgCreateResponse {

// hex encoded address
string contract_addr = 2;

// logs are the contract logs generated by the contract execution.
repeated Log logs = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgCreate2 is a message to create a contract with the CREATE2 opcode.
Expand Down Expand Up @@ -81,6 +84,9 @@ message MsgCreate2Response {

// hex encoded address
string contract_addr = 2;

// logs are the contract logs generated by the contract execution.
repeated Log logs = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgCall is a message to call an Ethereum contract.
Expand Down Expand Up @@ -109,8 +115,10 @@ message MsgCall {

// MsgCallResponse defines the Msg/Call response type.
message MsgCallResponse {
string result = 1;
repeated Log logs = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
string result = 1;

// logs are the contract logs generated by the contract execution.
repeated Log logs = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgUpdateParams defines a Msg for updating the x/evm module parameters.
Expand Down
2 changes: 1 addition & 1 deletion proto/minievm/evm/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ message Params {
(gogoproto.moretags) = "yaml:\"allowed_custom_erc20s\"",
(amino.dont_omitempty) = true
];

// fee_denom defines the fee denom for the evm transactions
string fee_denom = 5 [(gogoproto.moretags) = "yaml:\"fee_denom\""];
}
Expand Down
6 changes: 4 additions & 2 deletions x/evm/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ func (ms *msgServerImpl) Create(ctx context.Context, msg *types.MsgCreate) (*typ
}

// deploy a contract
retBz, contractAddr, _, err := ms.EVMCreate(ctx, caller, codeBz, value)
retBz, contractAddr, logs, err := ms.EVMCreate(ctx, caller, codeBz, value)
if err != nil {
return nil, types.ErrEVMCallFailed.Wrap(err.Error())
}

return &types.MsgCreateResponse{
Result: hexutil.Encode(retBz),
ContractAddr: contractAddr.Hex(),
Logs: logs,
}, nil
}

Expand Down Expand Up @@ -125,14 +126,15 @@ func (ms *msgServerImpl) Create2(ctx context.Context, msg *types.MsgCreate2) (*t
}

// deploy a contract
retBz, contractAddr, _, err := ms.EVMCreate2(ctx, caller, codeBz, value, msg.Salt)
retBz, contractAddr, logs, err := ms.EVMCreate2(ctx, caller, codeBz, value, msg.Salt)
if err != nil {
return nil, types.ErrEVMCallFailed.Wrap(err.Error())
}

return &types.MsgCreate2Response{
Result: hexutil.Encode(retBz),
ContractAddr: contractAddr.Hex(),
Logs: logs,
}, nil
}

Expand Down
Loading

0 comments on commit 5ba56cc

Please sign in to comment.