Skip to content

Commit

Permalink
auth.AccountStore assumes go-wire; Remove GetTxBytes() from Tx
Browse files Browse the repository at this point in the history
  • Loading branch information
jaekwon committed Jan 21, 2018
1 parent 6d3b5cb commit 8fda920
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 79 deletions.
1 change: 0 additions & 1 deletion app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ func (tx testTx) Get(key interface{}) (value interface{}) { return nil }
func (tx testTx) GetSignBytes() []byte { return nil }
func (tx testTx) ValidateBasic() error { return nil }
func (tx testTx) GetSigners() []crypto.Address { return nil }
func (tx testTx) GetTxBytes() []byte { return nil }
func (tx testTx) GetFeePayer() crypto.Address { return nil }
func (tx testTx) GetSignatures() []sdk.StdSignature { return nil }

Expand Down
16 changes: 13 additions & 3 deletions examples/basecoin/app/stores.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,18 @@ func (app *BasecoinApp) initMultiStore() {

// depends on initKeys()
func (app *BasecoinApp) initAppStore() {
app.accStore = auth.NewAccountStore(
app.mainStoreKey,
types.NewAppAccountCodecFromWireCodec(app.cdc),
accStore := auth.NewAccountStore(
app.mainStoreKey, // where accounts are persisted.
&types.AppAccount{}, // prototype sdk.Account.
)

// If there are additional interfaces & concrete types that need to be
// registered w/ wire.Codec, they can be registered here before the
// accStore is sealed.
//
// cdc := accStore.WireCodec()
// cdc.RegisterInterface(...)
// cdc.RegisterConcrete(...)

app.accStore = accStore.Seal()
}
32 changes: 5 additions & 27 deletions examples/basecoin/types/account.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package types

import (
wire "github.com/tendermint/go-wire"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
Expand All @@ -12,7 +10,11 @@ var _ sdk.Account = (*AppAccount)(nil)
type AppAccount struct {
auth.BaseAccount

// Custom extensions for this application.
// Custom extensions for this application. This is just an example of
// extending auth.BaseAccount with custom fields.
//
// This is compatible with the stock auth.AccountStore, since
// auth.AccountStore uses the flexible go-wire library.
Name string
}

Expand All @@ -23,27 +25,3 @@ func (acc AppAccount) GetName() string {
func (acc *AppAccount) SetName(name string) {
acc.Name = name
}

//----------------------------------------

type AppAccountCodec struct {
cdc *wire.Codec
}

func NewAppAccountCodecFromWireCodec(cdc *wire.Codec) AppAccountCodec {
return AppAccountCodec{cdc}
}

func (_ AppAccountCodec) Prototype() interface{} {
return &AppAccount{}
}

func (aac AppAccountCodec) Encode(o interface{}) (bz []byte, err error) {
return aac.cdc.MarshalBinary(o)
}

func (aac AppAccountCodec) Decode(bz []byte) (o interface{}, err error) {
o = aac.Prototype()
err = aac.cdc.UnmarshalBinary(bz, o)
return o, err
}
4 changes: 0 additions & 4 deletions examples/dummy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@ func (tx dummyTx) GetSigners() []crypto.Address {
return nil
}

func (tx dummyTx) GetTxBytes() []byte {
return tx.bytes
}

func (tx dummyTx) GetSignatures() []sdk.StdSignature {
return nil
}
Expand Down
14 changes: 0 additions & 14 deletions types/codec.go

This file was deleted.

14 changes: 1 addition & 13 deletions types/tx_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package types

import (
crypto "github.com/tendermint/go-crypto"
wire "github.com/tendermint/go-wire"
)

type Msg interface {
Expand Down Expand Up @@ -34,10 +33,6 @@ type Tx interface {
// deducted before the Msg is processed.
GetFeePayer() crypto.Address

// Get the canonical byte representation of the Tx.
// Includes any signatures (or empty slots).
GetTxBytes() []byte

// Signatures returns the signature of signers who signed the Msg.
// CONTRACT: Length returned is same as length of
// pubkeys returned from MsgKeySigners, and the order
Expand All @@ -55,14 +50,7 @@ type StdTx struct {
Signatures []StdSignature
}

func (tx StdTx) GetFeePayer() crypto.Address { return tx.Signatures[0].PubKey.Address() }
func (tx StdTx) GetTxBytes() []byte {
bz, err := wire.MarshalBinary(tx) // XXX: this is bad
if err != nil {
panic(err)
}
return bz
}
func (tx StdTx) GetFeePayer() crypto.Address { return tx.Signatures[0].PubKey.Address() }
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }

type TxDecoder func(txBytes []byte) (Tx, error)
116 changes: 99 additions & 17 deletions x/auth/store.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,134 @@
package auth

import (
"fmt"
"reflect"

crypto "github.com/tendermint/go-crypto"
wire "github.com/tendermint/go-wire"

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

// Implements sdk.AccountStore
// Implements sdk.AccountStore.
// This AccountStore encodes/decodes accounts using the
// go-wire (binary) encoding/decoding library.
type accountStore struct {
key sdk.SubstoreKey
codec sdk.Codec

// The (unexposed) key used to access the store from the Context.
key sdk.SubstoreKey

// The prototypical sdk.Account concrete type.
proto sdk.Account

// The wire codec for binary encoding/decoding of accounts.
cdc *wire.Codec
}

func NewAccountStore(key sdk.SubstoreKey, codec sdk.Codec) accountStore {
// NewAccountStore returns a new sdk.AccountStore that
// uses go-wire to (binary) encode and decode concrete sdk.Accounts.
func NewAccountStore(key sdk.SubstoreKey, proto sdk.Account) accountStore {
return accountStore{
key: key,
codec: codec,
proto: proto,
cdc: wire.NewCodec(),
}
}

// Implements sdk.AccountStore
// Returns the go-wire codec. You may need to register interfaces
// and concrete types here, if your app's sdk.Account
// implementation includes interface fields.
// NOTE: It is not secure to expose the codec, so check out
// .Seal().
func (as accountStore) WireCodec() *wire.Codec {
return as.cdc
}

// Returns a "sealed" accountStore.
// The codec is not accessible from a sealedAccountStore
func (as accountStore) Seal() sealedAccountStore {
return sealedAccountStore{as}
}

// Implements sdk.AccountStore.
func (as accountStore) NewAccountWithAddress(ctx sdk.Context, addr crypto.Address) sdk.Account {
acc := as.codec.Prototype().(sdk.Account)
acc := as.clonePrototype()
acc.SetAddress(addr)
return acc
}

// Implements sdk.AccountStore
// Implements sdk.AccountStore.
func (as accountStore) GetAccount(ctx sdk.Context, addr crypto.Address) sdk.Account {
store := ctx.KVStore(as.key)
bz := store.Get(addr)
if bz == nil {
return nil // XXX
return nil
}
o, err := as.codec.Decode(bz)
if err != nil {
panic(err)
}
return o.(sdk.Account)
acc := as.decodeAccount(bz)
return acc
}

// Implements sdk.AccountStore
// Implements sdk.AccountStore.
func (as accountStore) SetAccount(ctx sdk.Context, acc sdk.Account) {
addr := acc.GetAddress()
store := ctx.KVStore(as.key)
bz, err := as.codec.Encode(acc)
bz := as.encodeAccount(acc)
store.Set(addr, bz)
}

//----------------------------------------
// misc.

// Creates a new struct (or pointer to struct) from as.proto.
func (as accountStore) clonePrototype() sdk.Account {
protoRt := reflect.TypeOf(as.proto)
if protoRt.Kind() == reflect.Ptr {
protoCrt := protoRt.Elem()
if protoCrt.Kind() != reflect.Struct {
panic("AccountStore requires a struct proto sdk.Account, or a pointer to one")
}
protoRv := reflect.New(protoCrt)
clone, ok := protoRv.Interface().(sdk.Account)
if !ok {
panic(fmt.Sprintf("AccountStore requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt))
}
return clone
} else {
protoRv := reflect.New(protoRt).Elem()
clone, ok := protoRv.Interface().(sdk.Account)
if !ok {
panic(fmt.Sprintf("AccountStore requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt))
}
return clone
}
}

func (as accountStore) encodeAccount(acc sdk.Account) []byte {
bz, err := as.cdc.MarshalBinary(acc)
if err != nil {
panic(err)
}
store.Set(addr, bz)
return bz
}

func (as accountStore) decodeAccount(bz []byte) sdk.Account {
acc := as.clonePrototype()
err := as.cdc.UnmarshalBinary(bz, &acc)
if err != nil {
panic(err)
}
return acc
}

//----------------------------------------
// sealedAccountStore

type sealedAccountStore struct {
accountStore
}

// There's no way for external modules to mutate the
// sas.accountStore.ctx from here, even with reflection.
func (sas sealedAccountStore) WireCodec() *wire.Codec {
panic("accountStore is sealed")
}

0 comments on commit 8fda920

Please sign in to comment.