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

fix: genesis auth account format #517

Merged
merged 12 commits into from
May 11, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/wasm) [\#453](https://github.com/line/lbm-sdk/pull/453) modify wasm grpc query api path
* (client) [\#476](https://github.com/line/lbm-sdk/pull/476) change the default value of the client output format in the config
* (server/grpc) [\#516](https://github.com/line/lbm-sdk/pull/516) restore build norace flag
* (genesis) [\#517](https://github.com/line/lbm-sdk/pull/517) fix genesis auth account format(cosmos-sdk style -> lbm-sdk style)
Copy link
Member

Choose a reason for hiding this comment

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

lbm-sdk -> cosmos-sdk style ?


### Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion baseapp/block_gas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestBaseApp_BlockGas(t *testing.T) {
require.Equal(t, []byte("ok"), okValue)
}
// check block gas is always consumed
baseGas := uint64(36950) // baseGas is the gas consumed before tx msg
baseGas := uint64(35000) // baseGas is the gas consumed before tx msg
expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas)
if expGasConsumed > txtypes.MaxGasWanted {
// capped by gasLimit
Expand Down
5 changes: 2 additions & 3 deletions x/auth/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,13 @@ func (ak AccountKeeper) decodeAccount(bz []byte) types.AccountI {

// MarshalAccount protobuf serializes an Account interface
func (ak AccountKeeper) MarshalAccount(accountI types.AccountI) ([]byte, error) { // nolint:interfacer
return ak.cdc.MarshalInterface(accountI)
return types.MarshalAccountX(ak.cdc, accountI)
}

// UnmarshalAccount returns an Account interface from raw encoded account
// bytes of a Proto-based Account type
func (ak AccountKeeper) UnmarshalAccount(bz []byte) (types.AccountI, error) {
var acc types.AccountI
return acc, ak.cdc.UnmarshalInterface(bz, &acc)
return types.UnmarshalAccountX(ak.cdc, bz)
}

// GetCodec return codec.Codec object used by the keeper
Expand Down
173 changes: 170 additions & 3 deletions x/auth/types/account.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package types

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"

"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"github.com/line/ostracon/crypto"
"gopkg.in/yaml.v2"
Expand All @@ -31,8 +34,9 @@ var (
ModuleAccountSig = []byte("macc")

PubKeyTypeSecp256k1 = byte(1)
PubKeyTypeEd25519 = byte(2)
PubKeyTypeMultisig = byte(3)
PubKeyTypeSecp256R1 = byte(2)
PubKeyTypeEd25519 = byte(3)
PubKeyTypeMultisig = byte(4)
)

// NewBaseAccount creates a new BaseAccount object
Expand Down Expand Up @@ -359,7 +363,38 @@ type AccountI interface {
MarshalX() ([]byte, error)
}

// TODO(dudong2): remove MarshalAccountX, UnmarshalAccountX(because codec.BinaryMarshaler is removed -> build failed) - ref. https://github.com/line/lbm-sdk/pull/320
func MarshalAccountX(cdc codec.BinaryCodec, acc AccountI) ([]byte, error) {
if bacc, ok := acc.(*BaseAccount); ok && bacc.MultisigPubKey == nil {
return acc.MarshalX()
} else if macc, ok := acc.(*ModuleAccount); ok && macc.MultisigPubKey == nil {
return acc.MarshalX()
} else {
return cdc.MarshalInterface(acc)
}
}

func UnmarshalAccountX(cdc codec.BinaryCodec, bz []byte) (AccountI, error) {
sigLen := len(BaseAccountSig)
if len(bz) < sigLen {
return nil, fmt.Errorf("invalid data")
}
if bytes.Equal(bz[:sigLen], BaseAccountSig) {
acc := &BaseAccount{}
if err := acc.Unmarshal(bz[sigLen:]); err != nil {
return nil, err
}
return acc, nil
} else if bytes.Equal(bz[:sigLen], ModuleAccountSig) {
acc := &ModuleAccount{}
if err := acc.Unmarshal(bz[sigLen:]); err != nil {
return nil, err
}
return acc, nil
} else {
var acc AccountI
return acc, cdc.UnmarshalInterface(bz, &acc)
}
}

// ModuleAccountI defines an account interface for modules that hold tokens in
// an escrow.
Expand Down Expand Up @@ -392,3 +427,135 @@ type GenesisAccount interface {

Validate() error
}

// custom json marshaler for BaseAccount & ModuleAccount

type PubKeyJSON struct {
Type byte `json:"type"`
Key []byte `json:"key"`
}

type BaseAccountJSON struct {
Address string `json:"address"`
PubKey PubKeyJSON `json:"pub_key"`
AccountNumber uint64 `json:"account_number"`
Sequence string `json:"sequence"`
}

func (acc BaseAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) {
var bi BaseAccountJSON

bi.Address = acc.GetAddress().String()
bi.AccountNumber = acc.GetAccountNumber()
bi.Sequence = strconv.FormatUint(acc.Sequence, 10)
var bz []byte
var err error
if acc.Secp256K1PubKey != nil {
bi.PubKey.Type = PubKeyTypeSecp256k1
bz, err = acc.Secp256K1PubKey.Marshal()
} else if acc.Secp256R1PubKey != nil {
bi.PubKey.Type = PubKeyTypeSecp256R1
bz, err = acc.Secp256R1PubKey.Marshal()
} else if acc.Ed25519PubKey != nil {
bi.PubKey.Type = PubKeyTypeEd25519
bz, err = acc.Ed25519PubKey.Marshal()
} else if acc.MultisigPubKey != nil {
bi.PubKey.Type = PubKeyTypeMultisig
bz, err = acc.MultisigPubKey.Marshal()
}
if err != nil {
return nil, err
}
bi.PubKey.Key = bz
return json.Marshal(bi)
}

func (acc *BaseAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error {
var bi BaseAccountJSON

err := json.Unmarshal(bz, &bi)
if err != nil {
return err
}
/* TODO: do we need to validate address format here
err = sdk.ValidateAccAddress(bi.Address)
if err != nil {
return err
}
*/

acc.Address = bi.Address
acc.AccountNumber = bi.AccountNumber
acc.Sequence, err = strconv.ParseUint(bi.Sequence, 10, 64)
if err != nil {
return err
}

switch bi.PubKey.Type {
case PubKeyTypeEd25519:
pk := new(ed25519.PubKey)
if err := pk.Unmarshal(bi.PubKey.Key); err != nil {
return err
}
acc.SetPubKey(pk)
case PubKeyTypeSecp256k1:
pk := new(secp256k1.PubKey)
if err := pk.Unmarshal(bi.PubKey.Key); err != nil {
return err
}
acc.SetPubKey(pk)
case PubKeyTypeSecp256R1:
pk := new(secp256r1.PubKey)
if err := pk.Unmarshal(bi.PubKey.Key); err != nil {
return err
}
acc.SetPubKey(pk)
case PubKeyTypeMultisig:
pk := new(multisig.LegacyAminoPubKey)
if err := pk.Unmarshal(bi.PubKey.Key); err != nil {
return err
}
acc.SetPubKey(pk)
}
return nil
}

type ModuleAccountJSON struct {
BaseAccount json.RawMessage `json:"base_account"`
Name string `json:"name"`
Permissions []string `json:"permissions"`
}

func (ma ModuleAccount) MarshalJSONPB(m *jsonpb.Marshaler) ([]byte, error) {
var mi ModuleAccountJSON

bz, err := ma.BaseAccount.MarshalJSONPB(m)
if err != nil {
return nil, err
}
mi.BaseAccount = bz
mi.Name = ma.Name
mi.Permissions = ma.Permissions

return json.Marshal(mi)
}

func (ma *ModuleAccount) UnmarshalJSONPB(m *jsonpb.Unmarshaler, bz []byte) error {
var mi ModuleAccountJSON

err := json.Unmarshal(bz, &mi)
if err != nil {
return err
}

ma.Name = mi.Name
ma.Permissions = mi.Permissions

ba := new(BaseAccount)
if err := m.Unmarshal(strings.NewReader(string(mi.BaseAccount)), ba); err != nil {
return err
}
ma.BaseAccount = ba

return nil
}
23 changes: 23 additions & 0 deletions x/auth/types/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"testing"

"github.com/gogo/protobuf/jsonpb"
"github.com/stretchr/testify/require"
yaml "gopkg.in/yaml.v2"

Expand Down Expand Up @@ -214,6 +215,28 @@ func TestModuleAccountJSON(t *testing.T) {
require.Equal(t, acc.String(), a.String())
}

func TestModuleAccountJSONPB(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.BytesToAccAddress(pubkey.Address())
baseAcc := types.NewBaseAccount(addr, nil, 10, 50)
acc := types.NewModuleAccount(baseAcc, "test", types.Burner)

jm := jsonpb.Marshaler{}
bz, err := acc.MarshalJSONPB(&jm)
require.NoError(t, err)

jum := jsonpb.Unmarshaler{}
addr2 := sdk.AccAddress("")
baseAcc2 := types.NewBaseAccount(addr2, nil, 0, 0)
acc2 := types.NewModuleAccount(baseAcc2, "")
err = acc2.UnmarshalJSONPB(&jum, bz)
require.NoError(t, err)

// error on bad bytes
err = acc2.UnmarshalJSONPB(&jum, bz[:len(bz)/2])
require.Error(t, err)
}

func TestGenesisAccountsContains(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.BytesToAccAddress(pubkey.Address())
Expand Down
Loading