Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

Commit

Permalink
types: unmarshal account from hex address (#504)
Browse files Browse the repository at this point in the history
* types: unmarshal account from hex address:

* changelog
  • Loading branch information
fedekunze committed Sep 8, 2020
1 parent 1505ba8 commit d678370
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (types) [\#504](https://github.com/ChainSafe/ethermint/pull/504) Unmarshal a JSON `EthAccount` using an Ethereum hex address in addition to Bech32.
* (types) [\#503](https://github.com/ChainSafe/ethermint/pull/503) Add `--coin-denom` flag to testnet command that sets the given coin denomination to SDK and Ethermint parameters.
* (types) [\#502](https://github.com/ChainSafe/ethermint/pull/502) `EthAccount` now also exposes the Ethereum hex address in `string` format to clients.
* (types) [\#494](https://github.com/ChainSafe/ethermint/pull/494) Update `EthAccount` public key JSON type to `string`.
Expand Down
41 changes: 40 additions & 1 deletion types/account.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package types

import (
"bytes"
"encoding/json"
"fmt"

"gopkg.in/yaml.v2"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
Expand Down Expand Up @@ -114,9 +116,15 @@ func (acc EthAccount) MarshalYAML() (interface{}, error) {

// MarshalJSON returns the JSON representation of an EthAccount.
func (acc EthAccount) MarshalJSON() ([]byte, error) {
var ethAddress = ""

if acc.BaseAccount != nil && acc.Address != nil {
ethAddress = acc.EthAddress().String()
}

alias := ethermintAccountPretty{
Address: acc.Address,
EthAddress: acc.EthAddress().String(),
EthAddress: ethAddress,
Coins: acc.Coins,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
Expand Down Expand Up @@ -146,6 +154,37 @@ func (acc *EthAccount) UnmarshalJSON(bz []byte) error {
return err
}

switch {
case !alias.Address.Empty() && alias.EthAddress != "":
// Both addresses provided. Verify correctness
ethAddress := ethcmn.HexToAddress(alias.EthAddress)
ethAddressFromAccAddress := ethcmn.BytesToAddress(alias.Address.Bytes())

if !bytes.Equal(ethAddress.Bytes(), alias.Address.Bytes()) {
err = sdkerrors.Wrapf(
sdkerrors.ErrInvalidAddress,
"expected %s, got %s",
ethAddressFromAccAddress.String(), ethAddress.String(),
)
}

case !alias.Address.Empty() && alias.EthAddress == "":
// unmarshal sdk.AccAddress only. Do nothing here
case alias.Address.Empty() && alias.EthAddress != "":
// retrieve sdk.AccAddress from ethereum address
ethAddress := ethcmn.HexToAddress(alias.EthAddress)
alias.Address = sdk.AccAddress(ethAddress.Bytes())
case alias.Address.Empty() && alias.EthAddress == "":
err = sdkerrors.Wrapf(
sdkerrors.ErrInvalidAddress,
"account must contain address in Ethereum Hex or Cosmos Bech32 format",
)
}

if err != nil {
return err
}

acc.BaseAccount = &authtypes.BaseAccount{
Coins: alias.Coins,
Address: alias.Address,
Expand Down
40 changes: 37 additions & 3 deletions types/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (

"github.com/stretchr/testify/require"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"

tmamino "github.com/tendermint/tendermint/crypto/encoding/amino"
"github.com/tendermint/tendermint/crypto/secp256k1"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"

emintcrypto "github.com/cosmos/ethermint/crypto"
)

Expand Down Expand Up @@ -106,9 +106,43 @@ func TestEthermintAccount_MarshalJSON(t *testing.T) {

bz, err := ethAcc.MarshalJSON()
require.NoError(t, err)
require.Contains(t, string(bz), ethAcc.EthAddress().String())

res := new(EthAccount)
err = res.UnmarshalJSON(bz)
require.NoError(t, err)
require.Equal(t, ethAcc, res)

bech32pubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, pubkey)
require.NoError(t, err)

// test that the sdk.AccAddress is populated from the hex address
jsonAcc := fmt.Sprintf(
`{"address":"","eth_address":"%s","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
ethAcc.EthAddress().String(), bech32pubkey,
)

res = new(EthAccount)
err = res.UnmarshalJSON([]byte(jsonAcc))
require.NoError(t, err)
require.Equal(t, addr.String(), res.Address.String())

jsonAcc = fmt.Sprintf(
`{"address":"","eth_address":"","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
bech32pubkey,
)

res = new(EthAccount)
err = res.UnmarshalJSON([]byte(jsonAcc))
require.Error(t, err, "should fail if both address are empty")

// test that the sdk.AccAddress is populated from the hex address
jsonAcc = fmt.Sprintf(
`{"address": "%s","eth_address":"0x0000000000000000000000000000000000000000","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
ethAcc.Address.String(), bech32pubkey,
)

res = new(EthAccount)
err = res.UnmarshalJSON([]byte(jsonAcc))
require.Error(t, err, "should fail if addresses mismatch")
}

0 comments on commit d678370

Please sign in to comment.