Skip to content

Commit

Permalink
Merge PR cosmos#5280: Custom JSON Marshal/Unmarshal for Account Types
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Nov 6, 2019
1 parent ede9aae commit 82a2c5d
Show file tree
Hide file tree
Showing 7 changed files with 538 additions and 147 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ if the provided arguments are invalid.

### Client Breaking Changes

* (rest) [\#5270](https://github.com/cosmos/cosmos-sdk/issues/5270) All account types now implement custom JSON serialization.
* (rest) [\#4783](https://github.com/cosmos/cosmos-sdk/issues/4783) The balance field in the DelegationResponse type is now sdk.Coin instead of sdk.Int
* (x/auth) [\#5006](https://github.com/cosmos/cosmos-sdk/pull/5006) The gas required to pass the `AnteHandler` has
increased significantly due to modular `AnteHandler` support. Increase GasLimit accordingly.
Expand Down
113 changes: 73 additions & 40 deletions x/auth/types/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package types

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

"github.com/tendermint/tendermint/crypto"
Expand Down Expand Up @@ -44,24 +44,6 @@ func NewBaseAccount(address sdk.AccAddress, coins sdk.Coins,
}
}

// String implements fmt.Stringer
func (acc BaseAccount) String() string {
var pubkey string

if acc.PubKey != nil {
pubkey = sdk.MustBech32ifyAccPub(acc.PubKey)
}

return fmt.Sprintf(`Account:
Address: %s
Pubkey: %s
Coins: %s
AccountNumber: %d
Sequence: %d`,
acc.Address, pubkey, acc.Coins, acc.AccountNumber, acc.Sequence,
)
}

// ProtoBaseAccount - a prototype function for BaseAccount
func ProtoBaseAccount() exported.Account {
return &BaseAccount{}
Expand Down Expand Up @@ -138,45 +120,96 @@ func (acc *BaseAccount) SpendableCoins(_ time.Time) sdk.Coins {
return acc.GetCoins()
}

// Validate checks for errors on the account fields
func (acc BaseAccount) Validate() error {
if acc.PubKey != nil && acc.Address != nil &&
!bytes.Equal(acc.PubKey.Address().Bytes(), acc.Address.Bytes()) {
return errors.New("pubkey and address pair is invalid")
}

return nil
}

type baseAccountPretty struct {
Address sdk.AccAddress `json:"address" yaml:"address"`
Coins sdk.Coins `json:"coins" yaml:"coins"`
PubKey string `json:"public_key" yaml:"public_key"`
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
Sequence uint64 `json:"sequence" yaml:"sequence"`
}

func (acc BaseAccount) String() string {
out, _ := acc.MarshalYAML()
return out.(string)
}

// MarshalYAML returns the YAML representation of an account.
func (acc BaseAccount) MarshalYAML() (interface{}, error) {
var bs []byte
var err error
var pubkey string
alias := baseAccountPretty{
Address: acc.Address,
Coins: acc.Coins,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
}

if acc.PubKey != nil {
pubkey, err = sdk.Bech32ifyAccPub(acc.PubKey)
pks, err := sdk.Bech32ifyAccPub(acc.PubKey)
if err != nil {
return nil, err
}

alias.PubKey = pks
}

bz, err := yaml.Marshal(alias)
if err != nil {
return nil, err
}

bs, err = yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
}{
return string(bz), err
}

// MarshalJSON returns the JSON representation of a BaseAccount.
func (acc BaseAccount) MarshalJSON() ([]byte, error) {
alias := baseAccountPretty{
Address: acc.Address,
Coins: acc.Coins,
PubKey: pubkey,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
})
if err != nil {
return nil, err
}

return string(bs), err
if acc.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(acc.PubKey)
if err != nil {
return nil, err
}

alias.PubKey = pks
}

return json.Marshal(alias)
}

// Validate checks for errors on the account fields
func (acc BaseAccount) Validate() error {
if acc.PubKey != nil && acc.Address != nil &&
!bytes.Equal(acc.PubKey.Address().Bytes(), acc.Address.Bytes()) {
return errors.New("pubkey and address pair is invalid")
// UnmarshalJSON unmarshals raw JSON bytes into a BaseAccount.
func (acc *BaseAccount) UnmarshalJSON(bz []byte) error {
var alias baseAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}

if alias.PubKey != "" {
pk, err := sdk.GetAccPubKeyBech32(alias.PubKey)
if err != nil {
return err
}

acc.PubKey = pk
}

acc.Address = alias.Address
acc.Coins = alias.Coins
acc.AccountNumber = alias.AccountNumber
acc.Sequence = alias.Sequence

return nil
}
19 changes: 19 additions & 0 deletions x/auth/types/account_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package types

import (
"encoding/json"
"errors"
"testing"

Expand Down Expand Up @@ -128,3 +129,21 @@ func TestGenesisAccountValidate(t *testing.T) {
})
}
}

func TestBaseAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := NewBaseAccount(addr, coins, pubkey, 10, 50)

bz, err := json.Marshal(baseAcc)
require.NoError(t, err)

bz1, err := baseAcc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))

var a BaseAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, baseAcc.String(), a.String())
}
Loading

0 comments on commit 82a2c5d

Please sign in to comment.