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 @@ -51,6 +51,7 @@

### FEATURES

- [\#665](https://github.com/cosmos/evm/pull/665) Add EvmCodec address codec implementation
- [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation
- [\#337](https://github.com/cosmos/evm/pull/337) Support state overrides in eth_call.
- [\#502](https://github.com/cosmos/evm/pull/502) Add block time in derived logs.
Expand Down
63 changes: 63 additions & 0 deletions encoding/address/address_codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package address

import (
"strings"

"github.com/ethereum/go-ethereum/common"

"github.com/cosmos/evm/utils"

"cosmossdk.io/core/address"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

var _ address.Codec = (*evmCodec)(nil)

// evmCodec defines an address codec for EVM compatible cosmos modules
type evmCodec struct {
bech32Prefix string
}

// NewEvmCodec returns a new EvmCodec with the given bech32 prefix
func NewEvmCodec(prefix string) address.Codec {
return evmCodec{prefix}
}

// StringToBytes decodes text to bytes using either hex or bech32 encoding
func (bc evmCodec) StringToBytes(text string) ([]byte, error) {
if len(strings.TrimSpace(text)) == 0 {
return []byte{}, sdkerrors.ErrInvalidAddress.Wrap("empty address string is not allowed")
}

switch {
case common.IsHexAddress(text):
return common.HexToAddress(text).Bytes(), nil
case utils.IsBech32Address(text):
hrp, bz, err := bech32.DecodeAndConvert(text)
if err != nil {
return nil, err
}
if hrp != bc.bech32Prefix {
return nil, sdkerrors.ErrLogic.Wrapf("hrp does not match bech32 prefix: expected '%s' got '%s'", bc.bech32Prefix, hrp)
}
if err := sdk.VerifyAddressFormat(bz); err != nil {
return nil, err
}
return bz, nil
default:
return nil, sdkerrors.ErrUnknownAddress.Wrapf("unknown address format: %s", text)
}
}

// BytesToString decodes bytes to text
func (bc evmCodec) BytesToString(bz []byte) (string, error) {
text, err := bech32.ConvertAndEncode(bc.bech32Prefix, bz)
if err != nil {
return "", err
}

return text, nil
}
165 changes: 165 additions & 0 deletions encoding/address/address_codec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package address_test

import (
"testing"

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

evmaddress "github.com/cosmos/evm/encoding/address"

"cosmossdk.io/core/address"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

const (
hex = "0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02E"
bech32 = "cosmos10jmp6sgh4cc6zt3e8gw05wavvejgr5pwsjskvv"
)

func TestStringToBytes(t *testing.T) {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount("cosmos", "cosmospub")
addrBz := common.HexToAddress(hex).Bytes()

testCases := []struct {
name string
cdcPrefix string
input string
expBz []byte
expErr error
}{
{
"success: valid bech32 address",
"cosmos",
bech32,
addrBz,
nil,
},
{
"success: valid hex address",
"cosmos",
hex,
addrBz,
nil,
},
{
"failure: invalid bech32 address (wrong prefix)",
"evmos",
bech32,
nil,
sdkerrors.ErrLogic.Wrapf("hrp does not match bech32 prefix: expected '%s' got '%s'", "evmos", "cosmos"),
},
{
"failure: invalid bech32 address (too long)",
"cosmos",
"cosmos10jmp6sgh4cc6zt3e8gw05wavvejgr5pwsjskvvv", // extra char at the end
nil,
sdkerrors.ErrUnknownAddress,
},
{
"failure: invalid bech32 address (invalid format)",
"cosmos",
"cosmos10jmp6sgh4cc6zt3e8gw05wavvejgr5pwsjskv", // missing last char
nil,
sdkerrors.ErrUnknownAddress,
},
{
"failure: invalid hex address (odd length)",
"cosmos",
"0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02", // missing last char
nil,
sdkerrors.ErrUnknownAddress,
},
{
"failure: invalid hex address (even length)",
"cosmos",
"0x7cB61D4117AE31a12E393a1Cfa3BaC666481D0", // missing last 2 char
nil,
sdkerrors.ErrUnknownAddress,
},
{
"failure: invalid hex address (too long)",
"cosmos",
"0x7cB61D4117AE31a12E393a1Cfa3BaC666481D02E00", // extra 2 char at the end
nil,
sdkerrors.ErrUnknownAddress,
},
{
"failure: empty string",
"cosmos",
"",
nil,
sdkerrors.ErrInvalidAddress.Wrap("empty address string is not allowed"),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cdc := evmaddress.NewEvmCodec(tc.cdcPrefix)
bz, err := cdc.StringToBytes(tc.input)
if tc.expErr == nil {
require.NoError(t, err)
require.Equal(t, tc.expBz, bz)
} else {
require.ErrorContains(t, err, tc.expErr.Error())
}
})
}
}

func TestBytesToString(t *testing.T) {
// Keep the same fixtures as your StringToBytes test
config := sdk.GetConfig()
config.SetBech32PrefixForAccount("cosmos", "cosmospub")

addrBz := common.HexToAddress(hex).Bytes() // 20 bytes

// Helper codec (used only where we want to derive bytes from the bech32 string)
var cdc address.Codec

type tc struct {
name string
input func() []byte
expRes string
expErr error
}

testCases := []tc{
{
name: "success: from 20-byte input (hex-derived)",
input: func() []byte {
cdc = evmaddress.NewEvmCodec("cosmos")
return addrBz
},
expRes: bech32,
expErr: nil,
},
{
name: "success: from bech32-derived bytes",
input: func() []byte {
cdc = evmaddress.NewEvmCodec("cosmos")
bz, err := cdc.StringToBytes(bech32)
require.NoError(t, err)
require.Len(t, bz, 20)
return bz
},
expRes: bech32,
expErr: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := cdc.BytesToString(tc.input())
if tc.expErr == nil {
require.NoError(t, err)
require.Equal(t, tc.expRes, got)
} else {
require.ErrorContains(t, err, tc.expErr.Error())
}
})
}
}
10 changes: 3 additions & 7 deletions encoding/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package encoding
import (
"google.golang.org/protobuf/reflect/protoreflect"

evmaddress "github.com/cosmos/evm/encoding/address"
enccodec "github.com/cosmos/evm/encoding/codec"
"github.com/cosmos/evm/ethereum/eip712"
erc20types "github.com/cosmos/evm/x/erc20/types"
Expand All @@ -13,7 +14,6 @@ import (

"github.com/cosmos/cosmos-sdk/client"
amino "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
Expand All @@ -33,12 +33,8 @@ type Config struct {
func MakeConfig(evmChainID uint64) Config {
cdc := amino.NewLegacyAmino()
signingOptions := signing.Options{
AddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
},
ValidatorAddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
},
AddressCodec: evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
ValidatorAddressCodec: evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
CustomGetSigners: map[protoreflect.FullName]signing.GetSignersFunc{
evmtypes.MsgEthereumTxCustomGetSigner.MsgType: evmtypes.MsgEthereumTxCustomGetSigner.Fn,
erc20types.MsgConvertERC20CustomGetSigner.MsgType: erc20types.MsgConvertERC20CustomGetSigner.Fn,
Expand Down
6 changes: 2 additions & 4 deletions ethereum/eip712/preprocess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/cosmos/evm/encoding"
evmaddress "github.com/cosmos/evm/encoding/address"
"github.com/cosmos/evm/ethereum/eip712"
"github.com/cosmos/evm/testutil/constants"
utiltx "github.com/cosmos/evm/testutil/tx"
Expand All @@ -18,7 +19,6 @@ import (
"cosmossdk.io/math"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec/address"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -107,9 +107,7 @@ func TestLedgerPreprocessing(t *testing.T) {
// Verify tx fields are unchanged
tx := tc.txBuilder.GetTx()

addrCodec := address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
}
addrCodec := evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix())

txFeePayer, err := addrCodec.BytesToString(tx.FeePayer())
require.NoError(t, err)
Expand Down
14 changes: 7 additions & 7 deletions evmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
evmante "github.com/cosmos/evm/ante"
evmconfig "github.com/cosmos/evm/config"
evmosencoding "github.com/cosmos/evm/encoding"
evmaddress "github.com/cosmos/evm/encoding/address"
evmmempool "github.com/cosmos/evm/mempool"
srvflags "github.com/cosmos/evm/server/flags"
cosmosevmtypes "github.com/cosmos/evm/types"
Expand Down Expand Up @@ -93,7 +94,6 @@ import (
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
Expand Down Expand Up @@ -292,7 +292,7 @@ func NewExampleApp(
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec, runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount, evmconfig.GetMaccPerms(),
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
sdk.GetConfig().GetBech32AccountAddrPrefix(),
authAddr,
)
Expand Down Expand Up @@ -327,8 +327,8 @@ func NewExampleApp(
app.AccountKeeper,
app.BankKeeper,
authAddr,
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
)

app.MintKeeper = mintkeeper.NewKeeper(
Expand Down Expand Up @@ -1134,8 +1134,8 @@ func (app *EVMD) AutoCliOpts() autocli.AppOptions {
return autocli.AppOptions{
Modules: modules,
ModuleOptions: runtimeservices.ExtractAutoCLIOptions(app.ModuleManager.Modules),
AddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
ValidatorAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
AddressCodec: evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
ValidatorAddressCodec: evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
ConsensusAddressCodec: evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
}
}
Loading
Loading