Merge PR #5280: Custom JSON Marshal/Unmarshal for Account Types

This commit is contained in:
Alexander Bezobchuk 2019-11-06 13:06:26 -07:00 committed by GitHub
parent ede9aaed3b
commit 82a2c5d6d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 565 additions and 174 deletions

View File

@ -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.

View File

@ -2,8 +2,8 @@ package types
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/tendermint/tendermint/crypto"
@ -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{}
@ -138,39 +120,6 @@ func (acc *BaseAccount) SpendableCoins(_ time.Time) sdk.Coins {
return acc.GetCoins()
}
// MarshalYAML returns the YAML representation of an account.
func (acc BaseAccount) MarshalYAML() (interface{}, error) {
var bs []byte
var err error
var pubkey string
if acc.PubKey != nil {
pubkey, err = sdk.Bech32ifyAccPub(acc.PubKey)
if err != nil {
return nil, err
}
}
bs, err = yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
}{
Address: acc.Address,
Coins: acc.Coins,
PubKey: pubkey,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
})
if err != nil {
return nil, err
}
return string(bs), err
}
// Validate checks for errors on the account fields
func (acc BaseAccount) Validate() error {
if acc.PubKey != nil && acc.Address != nil &&
@ -180,3 +129,87 @@ func (acc BaseAccount) Validate() error {
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) {
alias := baseAccountPretty{
Address: acc.Address,
Coins: acc.Coins,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
}
if acc.PubKey != nil {
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
}
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,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
}
if acc.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(acc.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
return json.Marshal(alias)
}
// 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
}

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"errors"
"testing"
@ -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())
}

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"errors"
"time"
@ -8,16 +9,18 @@ import (
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
"github.com/tendermint/tendermint/crypto"
"gopkg.in/yaml.v2"
)
// Assert BaseVestingAccount implements authexported.Account at compile-time
var _ authexported.Account = (*BaseVestingAccount)(nil)
// Assert vesting accounts implement vestexported.VestingAccount at compile-time
var _ vestexported.VestingAccount = (*ContinuousVestingAccount)(nil)
var _ vestexported.VestingAccount = (*PeriodicVestingAccount)(nil)
var _ vestexported.VestingAccount = (*DelayedVestingAccount)(nil)
// Compile-time type assertions
var (
_ authexported.Account = (*BaseVestingAccount)(nil)
_ vestexported.VestingAccount = (*ContinuousVestingAccount)(nil)
_ vestexported.VestingAccount = (*PeriodicVestingAccount)(nil)
_ vestexported.VestingAccount = (*DelayedVestingAccount)(nil)
)
// Register the vesting account types on the auth module codec
func init() {
@ -182,45 +185,108 @@ func (bva BaseVestingAccount) Validate() error {
return bva.BaseAccount.Validate()
}
// MarshalYAML returns the YAML representation of an account.
type vestingAccountPretty 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"`
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"`
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"`
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"`
EndTime int64 `json:"end_time" yaml:"end_time"`
// custom fields based on concrete vesting type which can be omitted
StartTime int64 `json:"start_time,omitempty" yaml:"start_time,omitempty"`
VestingPeriods Periods `json:"vesting_periods,omitempty" yaml:"vesting_periods,omitempty"`
}
func (bva BaseVestingAccount) String() string {
out, _ := bva.MarshalYAML()
return out.(string)
}
// MarshalYAML returns the YAML representation of a BaseVestingAccount.
func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) {
var bs []byte
var err error
var pubkey string
if bva.PubKey != nil {
pubkey, err = sdk.Bech32ifyAccPub(bva.PubKey)
if err != nil {
return nil, err
}
}
bs, err = yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
OriginalVesting sdk.Coins
DelegatedFree sdk.Coins
DelegatedVesting sdk.Coins
EndTime int64
}{
alias := vestingAccountPretty{
Address: bva.Address,
Coins: bva.Coins,
PubKey: pubkey,
AccountNumber: bva.AccountNumber,
Sequence: bva.Sequence,
OriginalVesting: bva.OriginalVesting,
DelegatedFree: bva.DelegatedFree,
DelegatedVesting: bva.DelegatedVesting,
EndTime: bva.EndTime,
})
}
if bva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(bva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
bz, err := yaml.Marshal(alias)
if err != nil {
return nil, err
}
return string(bs), err
return string(bz), err
}
// MarshalJSON returns the JSON representation of a BaseVestingAccount.
func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountPretty{
Address: bva.Address,
Coins: bva.Coins,
AccountNumber: bva.AccountNumber,
Sequence: bva.Sequence,
OriginalVesting: bva.OriginalVesting,
DelegatedFree: bva.DelegatedFree,
DelegatedVesting: bva.DelegatedVesting,
EndTime: bva.EndTime,
}
if bva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(bva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
return json.Marshal(alias)
}
// UnmarshalJSON unmarshals raw JSON bytes into a BaseVestingAccount.
func (bva *BaseVestingAccount) UnmarshalJSON(bz []byte) error {
var alias vestingAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}
var (
pk crypto.PubKey
err error
)
if alias.PubKey != "" {
pk, err = sdk.GetAccPubKeyBech32(alias.PubKey)
if err != nil {
return err
}
}
bva.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence)
bva.OriginalVesting = alias.OriginalVesting
bva.DelegatedFree = alias.DelegatedFree
bva.DelegatedVesting = alias.DelegatedVesting
bva.EndTime = alias.EndTime
return nil
}
//-----------------------------------------------------------------------------
@ -320,34 +386,16 @@ func (cva ContinuousVestingAccount) Validate() error {
return cva.BaseVestingAccount.Validate()
}
// MarshalYAML returns the YAML representation of an account.
func (cva ContinuousVestingAccount) String() string {
out, _ := cva.MarshalYAML()
return out.(string)
}
// MarshalYAML returns the YAML representation of a ContinuousVestingAccount.
func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) {
var bs []byte
var err error
var pubkey string
if cva.PubKey != nil {
pubkey, err = sdk.Bech32ifyAccPub(cva.PubKey)
if err != nil {
return nil, err
}
}
bs, err = yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
OriginalVesting sdk.Coins
DelegatedFree sdk.Coins
DelegatedVesting sdk.Coins
EndTime int64
StartTime int64
}{
alias := vestingAccountPretty{
Address: cva.Address,
Coins: cva.Coins,
PubKey: pubkey,
AccountNumber: cva.AccountNumber,
Sequence: cva.Sequence,
OriginalVesting: cva.OriginalVesting,
@ -355,12 +403,80 @@ func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) {
DelegatedVesting: cva.DelegatedVesting,
EndTime: cva.EndTime,
StartTime: cva.StartTime,
})
}
if cva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(cva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
bz, err := yaml.Marshal(alias)
if err != nil {
return nil, err
}
return string(bs), err
return string(bz), err
}
// MarshalJSON returns the JSON representation of a ContinuousVestingAccount.
func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountPretty{
Address: cva.Address,
Coins: cva.Coins,
AccountNumber: cva.AccountNumber,
Sequence: cva.Sequence,
OriginalVesting: cva.OriginalVesting,
DelegatedFree: cva.DelegatedFree,
DelegatedVesting: cva.DelegatedVesting,
EndTime: cva.EndTime,
StartTime: cva.StartTime,
}
if cva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(cva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
return json.Marshal(alias)
}
// UnmarshalJSON unmarshals raw JSON bytes into a ContinuousVestingAccount.
func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error {
var alias vestingAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}
var (
pk crypto.PubKey
err error
)
if alias.PubKey != "" {
pk, err = sdk.GetAccPubKeyBech32(alias.PubKey)
if err != nil {
return err
}
}
cva.BaseVestingAccount = &BaseVestingAccount{
BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence),
OriginalVesting: alias.OriginalVesting,
DelegatedFree: alias.DelegatedFree,
DelegatedVesting: alias.DelegatedVesting,
EndTime: alias.EndTime,
}
cva.StartTime = alias.StartTime
return nil
}
//-----------------------------------------------------------------------------
@ -485,35 +601,16 @@ func (pva PeriodicVestingAccount) Validate() error {
return pva.BaseVestingAccount.Validate()
}
// MarshalYAML returns the YAML representation of an account.
func (pva PeriodicVestingAccount) String() string {
out, _ := pva.MarshalYAML()
return out.(string)
}
// MarshalYAML returns the YAML representation of a PeriodicVestingAccount.
func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) {
var bs []byte
var err error
var pubkey string
if pva.PubKey != nil {
pubkey, err = sdk.Bech32ifyAccPub(pva.PubKey)
if err != nil {
return nil, err
}
}
bs, err = yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
OriginalVesting sdk.Coins
DelegatedFree sdk.Coins
DelegatedVesting sdk.Coins
EndTime int64
StartTime int64
VestingPeriods Periods
}{
alias := vestingAccountPretty{
Address: pva.Address,
Coins: pva.Coins,
PubKey: pubkey,
AccountNumber: pva.AccountNumber,
Sequence: pva.Sequence,
OriginalVesting: pva.OriginalVesting,
@ -522,12 +619,82 @@ func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) {
EndTime: pva.EndTime,
StartTime: pva.StartTime,
VestingPeriods: pva.VestingPeriods,
})
}
if pva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(pva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
bz, err := yaml.Marshal(alias)
if err != nil {
return nil, err
}
return string(bs), err
return string(bz), err
}
// MarshalJSON returns the JSON representation of a PeriodicVestingAccount.
func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountPretty{
Address: pva.Address,
Coins: pva.Coins,
AccountNumber: pva.AccountNumber,
Sequence: pva.Sequence,
OriginalVesting: pva.OriginalVesting,
DelegatedFree: pva.DelegatedFree,
DelegatedVesting: pva.DelegatedVesting,
EndTime: pva.EndTime,
StartTime: pva.StartTime,
VestingPeriods: pva.VestingPeriods,
}
if pva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(pva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
return json.Marshal(alias)
}
// UnmarshalJSON unmarshals raw JSON bytes into a PeriodicVestingAccount.
func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error {
var alias vestingAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}
var (
pk crypto.PubKey
err error
)
if alias.PubKey != "" {
pk, err = sdk.GetAccPubKeyBech32(alias.PubKey)
if err != nil {
return err
}
}
pva.BaseVestingAccount = &BaseVestingAccount{
BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence),
OriginalVesting: alias.OriginalVesting,
DelegatedFree: alias.DelegatedFree,
DelegatedVesting: alias.DelegatedVesting,
EndTime: alias.EndTime,
}
pva.StartTime = alias.StartTime
pva.VestingPeriods = alias.VestingPeriods
return nil
}
//-----------------------------------------------------------------------------
@ -599,3 +766,58 @@ func (dva DelayedVestingAccount) GetStartTime() int64 {
func (dva DelayedVestingAccount) Validate() error {
return dva.BaseVestingAccount.Validate()
}
// MarshalJSON returns the JSON representation of a DelayedVestingAccount.
func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountPretty{
Address: dva.Address,
Coins: dva.Coins,
AccountNumber: dva.AccountNumber,
Sequence: dva.Sequence,
OriginalVesting: dva.OriginalVesting,
DelegatedFree: dva.DelegatedFree,
DelegatedVesting: dva.DelegatedVesting,
EndTime: dva.EndTime,
}
if dva.PubKey != nil {
pks, err := sdk.Bech32ifyAccPub(dva.PubKey)
if err != nil {
return nil, err
}
alias.PubKey = pks
}
return json.Marshal(alias)
}
// UnmarshalJSON unmarshals raw JSON bytes into a DelayedVestingAccount.
func (dva *DelayedVestingAccount) UnmarshalJSON(bz []byte) error {
var alias vestingAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}
var (
pk crypto.PubKey
err error
)
if alias.PubKey != "" {
pk, err = sdk.GetAccPubKeyBech32(alias.PubKey)
if err != nil {
return err
}
}
dva.BaseVestingAccount = &BaseVestingAccount{
BaseAccount: authtypes.NewBaseAccount(alias.Address, alias.Coins, pk, alias.AccountNumber, alias.Sequence),
OriginalVesting: alias.OriginalVesting,
DelegatedFree: alias.DelegatedFree,
DelegatedVesting: alias.DelegatedVesting,
EndTime: alias.EndTime,
}
return nil
}

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"errors"
"testing"
"time"
@ -732,3 +733,86 @@ func TestGenesisAccountValidate(t *testing.T) {
})
}
}
func TestBaseVestingAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50)
acc, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix())
require.NoError(t, err)
bz, err := json.Marshal(acc)
require.NoError(t, err)
bz1, err := acc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))
var a BaseVestingAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, acc.String(), a.String())
}
func TestContinuousVestingAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50)
baseVesting, err := NewBaseVestingAccount(baseAcc, coins, time.Now().Unix())
acc := NewContinuousVestingAccountRaw(baseVesting, baseVesting.EndTime)
require.NoError(t, err)
bz, err := json.Marshal(acc)
require.NoError(t, err)
bz1, err := acc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))
var a ContinuousVestingAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, acc.String(), a.String())
}
func TestPeriodicVestingAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50)
acc := NewPeriodicVestingAccount(baseAcc, time.Now().Unix(), Periods{Period{3600, coins}})
bz, err := json.Marshal(acc)
require.NoError(t, err)
bz1, err := acc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))
var a PeriodicVestingAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, acc.String(), a.String())
}
func TestDelayedVestingAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := authtypes.NewBaseAccount(addr, coins, pubkey, 10, 50)
acc := NewDelayedVestingAccount(baseAcc, time.Now().Unix())
bz, err := json.Marshal(acc)
require.NoError(t, err)
bz1, err := acc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))
var a DelayedVestingAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, acc.String(), a.String())
}

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/json"
"errors"
"fmt"
"strings"
@ -30,6 +31,7 @@ func init() {
// ModuleAccount defines an account for modules that holds coins on a pool
type ModuleAccount struct {
*authtypes.BaseAccount
Name string `json:"name" yaml:"name"` // name of the module
Permissions []string `json:"permissions" yaml:"permissions"` // permissions of module account
}
@ -100,15 +102,6 @@ func (ma ModuleAccount) SetSequence(seq uint64) error {
return fmt.Errorf("not supported for module accounts")
}
// String follows stringer interface
func (ma ModuleAccount) String() string {
b, err := yaml.Marshal(ma)
if err != nil {
panic(err)
}
return string(b)
}
// Validate checks for errors on the account fields
func (ma ModuleAccount) Validate() error {
if strings.TrimSpace(ma.Name) == "" {
@ -121,17 +114,24 @@ func (ma ModuleAccount) Validate() error {
return ma.BaseAccount.Validate()
}
type moduleAccountPretty 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"`
Name string `json:"name" yaml:"name"`
Permissions []string `json:"permissions" yaml:"permissions"`
}
func (ma ModuleAccount) String() string {
out, _ := ma.MarshalYAML()
return out.(string)
}
// MarshalYAML returns the YAML representation of a ModuleAccount.
func (ma ModuleAccount) MarshalYAML() (interface{}, error) {
bs, err := yaml.Marshal(struct {
Address sdk.AccAddress
Coins sdk.Coins
PubKey string
AccountNumber uint64
Sequence uint64
Name string
Permissions []string
}{
bs, err := yaml.Marshal(moduleAccountPretty{
Address: ma.Address,
Coins: ma.Coins,
PubKey: "",
@ -147,3 +147,30 @@ func (ma ModuleAccount) MarshalYAML() (interface{}, error) {
return string(bs), nil
}
// MarshalJSON returns the JSON representation of a ModuleAccount.
func (ma ModuleAccount) MarshalJSON() ([]byte, error) {
return json.Marshal(moduleAccountPretty{
Address: ma.Address,
Coins: ma.Coins,
PubKey: "",
AccountNumber: ma.AccountNumber,
Sequence: ma.Sequence,
Name: ma.Name,
Permissions: ma.Permissions,
})
}
// UnmarshalJSON unmarshals raw JSON bytes into a ModuleAccount.
func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error {
var alias moduleAccountPretty
if err := json.Unmarshal(bz, &alias); err != nil {
return err
}
ma.BaseAccount = authtypes.NewBaseAccount(alias.Address, alias.Coins, nil, alias.AccountNumber, alias.Sequence)
ma.Name = alias.Name
ma.Permissions = alias.Permissions
return nil
}

View File

@ -1,13 +1,13 @@
package types
import (
"encoding/json"
"errors"
"fmt"
"testing"
yaml "gopkg.in/yaml.v2"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -20,25 +20,11 @@ import (
func TestModuleAccountMarshalYAML(t *testing.T) {
name := "test"
moduleAcc := NewEmptyModuleAccount(name, Minter, Burner, Staking)
moduleAddress := sdk.AccAddress(crypto.AddressHash([]byte(name)))
bs, err := yaml.Marshal(moduleAcc)
require.NoError(t, err)
want := fmt.Sprintf(`|
address: %s
coins: []
pubkey: ""
accountnumber: 0
sequence: 0
name: %s
permissions:
- %s
- %s
- %s
`, moduleAddress, name, Minter, Burner, Staking)
want := "|\n address: cosmos1n7rdpqvgf37ktx30a2sv2kkszk3m7ncmg5drhe\n coins: []\n public_key: \"\"\n account_number: 0\n sequence: 0\n name: test\n permissions:\n - minter\n - burner\n - staking\n"
require.Equal(t, want, string(bs))
require.Equal(t, want, moduleAcc.String())
}
func TestHasPermissions(t *testing.T) {
@ -96,3 +82,22 @@ func TestValidate(t *testing.T) {
})
}
}
func TestModuleAccountJSON(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 5))
baseAcc := authtypes.NewBaseAccount(addr, coins, nil, 10, 50)
acc := NewModuleAccount(baseAcc, "test", "burner")
bz, err := json.Marshal(acc)
require.NoError(t, err)
bz1, err := acc.MarshalJSON()
require.NoError(t, err)
require.Equal(t, string(bz1), string(bz))
var a ModuleAccount
require.NoError(t, json.Unmarshal(bz, &a))
require.Equal(t, acc.String(), a.String())
}