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

feat(eth-rpc): Conversion types and functions between Ethereum txs and blocks and Tendermint ones. #1856

Merged
merged 16 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1838](https://github.com/NibiruChain/nibiru/pull/1838) - feat(eth): Go-ethereum, crypto, encoding, and unit tests for evm/types
- [#1841](https://github.com/NibiruChain/nibiru/pull/1841) - feat(eth): Collections encoders for bytes, Ethereum addresses, and Ethereum hashes
- [#1847](https://github.com/NibiruChain/nibiru/pull/1847) - fix(docker-chaosnet): release snapshot docker build failed CI.
- [#1855](https://github.com/NibiruChain/nibiru/pull/1855) - feat(eth-pubsub): Implement in-memory EventBus for real-time topic management and event distribution
- [#1856](https://github.com/NibiruChain/nibiru/pull/1856) - feat(eth-rpc): Conversion types and functions between Ethereum txs and blocks and Tendermint ones.

#### Dapp modules: perp, spot, etc

Expand Down
14 changes: 7 additions & 7 deletions eth/types/account.pb.go → eth/account.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion eth/types/assert.go → eth/assert.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2023-2024 Nibi, Inc.
package types
package eth

import (
"bytes"
Expand Down
145 changes: 145 additions & 0 deletions eth/assert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package eth_test

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/eth"
"github.com/NibiruChain/nibiru/x/common/testutil"
)

func TestIsEmptyHash(t *testing.T) {
testCases := []struct {
name string
hash string
expEmpty bool
}{
{
"empty string", "", true,
},
{
"zero hash", common.Hash{}.String(), true,
},

{
"non-empty hash", common.BytesToHash([]byte{1, 2, 3, 4}).String(), false,
},
}

for _, tc := range testCases {
require.Equal(t, tc.expEmpty, eth.IsEmptyHash(tc.hash), tc.name)
}
}

func TestIsZeroAddress(t *testing.T) {
testCases := []struct {
name string
address string
expEmpty bool
}{
{
"empty string", "", true,
},
{
"zero address", common.Address{}.String(), true,
},

{
"non-empty address", common.BytesToAddress([]byte{1, 2, 3, 4}).String(), false,
},
}

for _, tc := range testCases {
require.Equal(t, tc.expEmpty, eth.IsZeroAddress(tc.address), tc.name)
}
}

func TestValidateAddress(t *testing.T) {
testCases := []struct {
name string
address string
expError bool
}{
{
"empty string", "", true,
},
{
"invalid address", "0x", true,
},
{
"zero address", common.Address{}.String(), false,
},
{
"valid address", testutil.NewEthAddr().Hex(), false,
},
}

for _, tc := range testCases {
err := eth.ValidateAddress(tc.address)

if tc.expError {
require.Error(t, err, tc.name)
} else {
require.NoError(t, err, tc.name)
}
}
}

func TestValidateNonZeroAddress(t *testing.T) {
testCases := []struct {
name string
address string
expError bool
}{
{
"empty string", "", true,
},
{
"invalid address", "0x", true,
},
{
"zero address", common.Address{}.String(), true,
},
{
"valid address", testutil.NewEthAddr().Hex(), false,
},
}

for _, tc := range testCases {
err := eth.ValidateNonZeroAddress(tc.address)

if tc.expError {
require.Error(t, err, tc.name)
} else {
require.NoError(t, err, tc.name)
}
}
}

func TestSafeInt64(t *testing.T) {
testCases := []struct {
name string
value uint64
expError bool
}{
{
"no overflow", 10, false,
},
{
"overflow", 18446744073709551615, true,
},
}

for _, tc := range testCases {
value, err := eth.SafeInt64(tc.value)
if tc.expError {
require.Error(t, err, tc.name)
continue
}

require.NoError(t, err, tc.name)
require.Equal(t, int64(tc.value), value, tc.name)
}
}
2 changes: 1 addition & 1 deletion eth/types/chain_id.go → eth/chain_id.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2023-2024 Nibi, Inc.
package types
package eth

import (
"fmt"
Expand Down
5 changes: 4 additions & 1 deletion eth/types/chain_id_test.go → eth/chain_id_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package types
package eth

import (
"math/big"
Expand Down Expand Up @@ -51,6 +51,9 @@ func TestParseChainID(t *testing.T) {
{
"invalid eip155 chain-id, cannot invalid base", "nibiru_0x212-1", true, nil,
},
{
"invalid eip155 chain-id, cannot invalid base", "nibiru_1-0x212", true, nil,
},
{
"invalid eip155 chain-id, non-integer", "nibiru_nibiru_9000-1", true, nil,
},
Expand Down
19 changes: 16 additions & 3 deletions eth/types/codec.go → eth/codec.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
// Copyright (c) 2023-2024 Nibi, Inc.
package types
package eth

import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/tx"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

// RegisterInterfaces registers the tendermint concrete client-related
// implementations and interfaces.
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
// proto name: "cosmos.auth.v1beta1.AccountI"
registry.RegisterImplementations(
(*authtypes.AccountI)(nil),
&EthAccount{},
// Also impl by: [
// &authtypes.BaseAccount{},
// &authtypes.ModuleAccount{},
// ]
)

// proto name: "cosmos.auth.v1beta1.GenesisAccount"
registry.RegisterImplementations(
(*authtypes.GenesisAccount)(nil),
&EthAccount{},
// Also impl by: [
// &authtypes.BaseAccount{},
// &authtypes.ModuleAccount{},
// ]
)

// proto name: "cosmos.tx.v1beta1.TxExtensionOptionI"
registry.RegisterImplementations(
(*tx.TxExtensionOptionI)(nil),
(*sdktx.TxExtensionOptionI)(nil),
&ExtensionOptionsWeb3Tx{},
&ExtensionOptionDynamicFeeTx{},
)
Expand Down
101 changes: 101 additions & 0 deletions eth/codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package eth

import (
"strings"
"testing"

"github.com/stretchr/testify/suite"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

type CodecTestSuite struct {
suite.Suite
}

func TestCodecSuite(t *testing.T) {
suite.Run(t, new(CodecTestSuite))
}

func (suite *CodecTestSuite) TestRegisterInterfaces() {
type ProtoNameInfo struct {
ProtoName string
Interface interface{}
WantImpls []string
}
protoInfos := []ProtoNameInfo{
{
ProtoName: "cosmos.auth.v1beta1.AccountI",
Interface: new(authtypes.AccountI),
WantImpls: []string{
"/eth.types.v1.EthAccount",
"/cosmos.auth.v1beta1.BaseAccount",
"/cosmos.auth.v1beta1.ModuleAccount",
},
},
{
ProtoName: "cosmos.auth.v1beta1.GenesisAccount",
Interface: new(authtypes.GenesisAccount),
WantImpls: []string{
"/eth.types.v1.EthAccount",
"/cosmos.auth.v1beta1.BaseAccount",
"/cosmos.auth.v1beta1.ModuleAccount",
},
},
{
ProtoName: "cosmos.tx.v1beta1.TxExtensionOptionI",
Interface: new(sdktx.TxExtensionOptionI),
WantImpls: []string{
"/eth.types.v1.ExtensionOptionsWeb3Tx",
"/eth.types.v1.ExtensionOptionDynamicFeeTx",
},
},
}

// -------------------------------------------
// Case 1: Setup: Register all interfaces under test
// -------------------------------------------
registry := codectypes.NewInterfaceRegistry()
for _, protoInfo := range protoInfos {
registry.RegisterInterface(protoInfo.ProtoName, protoInfo.Interface)
}
RegisterInterfaces(registry)
authtypes.RegisterInterfaces(registry)
sdktx.RegisterInterfaces(registry)

// Test: Assert that all expected protobuf interface implementations are
// registered (base + Ethereum)
for _, protoInfo := range protoInfos {
gotImpls := registry.ListImplementations(protoInfo.ProtoName)
suite.Require().ElementsMatch(protoInfo.WantImpls, gotImpls)
}

// -------------------------------------------
// Case 2: Setup: Register only eth interfaces
// -------------------------------------------
registry = codectypes.NewInterfaceRegistry()
for _, protoInfo := range protoInfos {
registry.RegisterInterface(protoInfo.ProtoName, protoInfo.Interface)
}
RegisterInterfaces(registry)

// Test: Assert that all expected protobuf interface implementations are
// registered (Ethereum only)
for _, protoInfo := range protoInfos {
gotImpls := registry.ListImplementations(protoInfo.ProtoName)
wantImpls := filterImplsForEth(protoInfo.WantImpls)
suite.Require().ElementsMatch(wantImpls, gotImpls)
}
}

func filterImplsForEth(implTypeUrls []string) []string {
typeUrls := []string{}
for _, typeUrl := range implTypeUrls {
if strings.Contains(typeUrl, "eth") {
typeUrls = append(typeUrls, typeUrl)
}
}
return typeUrls
}
Comment on lines +93 to +101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function filterImplsForEth is used to filter implementations. Consider adding a test specifically for this function to ensure its correctness across a range of inputs.

Would you like me to help by creating a test case for the filterImplsForEth function?

2 changes: 1 addition & 1 deletion eth/crypto/ethsecp256k1/ethsecp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/crypto"

"github.com/NibiruChain/nibiru/eth/ethereum/eip712"
"github.com/NibiruChain/nibiru/eth/eip712"
)

const (
Expand Down
Loading