From 3055d939edd968deee8a0c2ad33fef8664e8bd1d Mon Sep 17 00:00:00 2001 From: sunnya97 Date: Wed, 23 May 2018 19:26:54 -0700 Subject: [PATCH] in progress --- baseapp/baseapp.go | 3 +- client/context/helpers.go | 9 +- client/context/types.go | 6 +- client/tx/query.go | 3 +- cmd/gaia/app/app.go | 13 +- cmd/gaia/app/genesis.go | 11 +- types/account.go | 29 ----- types/handler.go | 3 - types/signature.go | 10 -- types/tx_msg.go | 117 ----------------- x/auth/account.go | 25 ++++ x/auth/ante.go | 30 ++--- x/auth/client/cli/account.go | 7 +- x/auth/context.go | 8 +- x/auth/mapper.go | 30 +++-- x/auth/stdtx.go | 131 ++++++++++++++++++++ x/auth/wire.go | 12 -- x/bank/keeper.go | 27 ++-- x/{auth => baseaccount}/baseaccount.go | 9 +- x/{auth => baseaccount}/baseaccount_test.go | 2 +- x/{auth => baseaccount}/handler.go | 13 +- x/{auth => baseaccount}/msgs.go | 7 +- x/{auth => baseaccount}/msgs_test.go | 2 +- x/baseaccount/wire.go | 14 +++ x/stake/test_common.go | 13 +- 25 files changed, 270 insertions(+), 264 deletions(-) delete mode 100644 types/signature.go create mode 100644 x/auth/account.go create mode 100644 x/auth/stdtx.go delete mode 100644 x/auth/wire.go rename x/{auth => baseaccount}/baseaccount.go (90%) rename x/{auth => baseaccount}/baseaccount_test.go (99%) rename x/{auth => baseaccount}/handler.go (58%) rename x/{auth => baseaccount}/msgs.go (87%) rename x/{auth => baseaccount}/msgs_test.go (97%) create mode 100644 x/baseaccount/wire.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ef3bbc3c7..4ce8a05d9 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Key to store the header in the DB itself. @@ -125,7 +126,7 @@ func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) { // default custom logic for transaction decoding func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx = sdk.StdTx{} + var tx = auth.StdTx{} if len(txBytes) == 0 { return nil, sdk.ErrTxDecode("txBytes are empty") diff --git a/client/context/helpers.go b/client/context/helpers.go index 562bde9b4..f4686befd 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" cmn "github.com/tendermint/tmlibs/common" @@ -109,11 +110,11 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w return nil, errors.Errorf("Chain ID required but not specified") } sequence := ctx.Sequence - signMsg := sdk.StdSignMsg{ + signMsg := auth.StdSignMsg{ ChainID: chainID, Sequences: []int64{sequence}, Msg: msg, - Fee: sdk.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? + Fee: auth.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? } keybase, err := keys.GetKeyBase() @@ -128,14 +129,14 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w if err != nil { return nil, err } - sigs := []sdk.StdSignature{{ + sigs := []auth.StdSignature{{ PubKey: pubkey, Signature: sig, Sequence: sequence, }} // marshal bytes - tx := sdk.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) + tx := auth.NewStdTx(signMsg.Msg, signMsg.Fee, sigs) return cdc.MarshalBinary(tx) } diff --git a/client/context/types.go b/client/context/types.go index e580027d6..da15b3293 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -3,7 +3,7 @@ package context import ( rpcclient "github.com/tendermint/tendermint/rpc/client" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // typical context created in sdk modules for transactions/queries @@ -15,7 +15,7 @@ type CoreContext struct { FromAddressName string Sequence int64 Client rpcclient.Client - Decoder sdk.AccountDecoder + Decoder auth.AccountDecoder AccountStore string } @@ -63,7 +63,7 @@ func (c CoreContext) WithClient(client rpcclient.Client) CoreContext { } // WithDecoder - return a copy of the context with an updated Decoder -func (c CoreContext) WithDecoder(decoder sdk.AccountDecoder) CoreContext { +func (c CoreContext) WithDecoder(decoder auth.AccountDecoder) CoreContext { c.Decoder = decoder return c } diff --git a/client/tx/query.go b/client/tx/query.go index 2078b7883..7673dd38d 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // Get the default command for a tx query @@ -95,7 +96,7 @@ type txInfo struct { } func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) { - var tx sdk.StdTx + var tx auth.StdTx err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { return nil, err diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 5ff532bff..df4429ee2 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -40,7 +41,7 @@ type GaiaApp struct { keyStake *sdk.KVStoreKey // Manage getting and setting accounts - accountMapper sdk.AccountMapper + accountMapper auth.AccountMapper coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper @@ -62,8 +63,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &auth.BaseAccount{}, // prototype + app.keyAccount, // target store + &baseaccount.BaseAccount{}, // prototype ) // add handlers @@ -81,7 +82,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, stake.FeeHandler)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) @@ -96,7 +97,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) - auth.RegisterWire(cdc) + baseaccount.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) return cdc @@ -131,7 +132,7 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { // iterate to get the accounts accounts := []GenesisAccount{} - appendAccount := func(acc sdk.Account) (stop bool) { + appendAccount := func(acc auth.Account) (stop bool) { account := NewGenesisAccountI(acc) accounts = append(accounts, account) return false diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 7cb7564dd..fb02a19ef 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/baseaccount" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -28,14 +29,14 @@ type GenesisAccount struct { Coins sdk.Coins `json:"coins"` } -func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { +func NewGenesisAccount(acc *baseaccount.BaseAccount) GenesisAccount { return GenesisAccount{ Address: acc.Address, Coins: acc.Coins, } } -func NewGenesisAccountI(acc sdk.Account) GenesisAccount { +func NewGenesisAccountI(acc auth.Account) GenesisAccount { return GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), @@ -43,8 +44,8 @@ func NewGenesisAccountI(acc sdk.Account) GenesisAccount { } // convert GenesisAccount to auth.BaseAccount -func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { - return &auth.BaseAccount{ +func (ga *GenesisAccount) ToAccount() (acc *baseaccount.BaseAccount) { + return &baseaccount.BaseAccount{ Address: ga.Address, Coins: ga.Coins.Sort(), } @@ -148,7 +149,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso } // create the genesis account, give'm few steaks and a buncha token with there name - accAuth := auth.NewBaseAccountWithAddress(genTx.Address) + accAuth := baseaccount.NewBaseAccountWithAddress(genTx.Address) accAuth.Coins = sdk.Coins{ {genTx.Name + "Token", 1000}, {"steak", freeFermionsAcc}, diff --git a/types/account.go b/types/account.go index 74cd87f38..be8b90a1c 100644 --- a/types/account.go +++ b/types/account.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "errors" - crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" ) @@ -22,31 +21,3 @@ func GetAddress(address string) (addr Address, err error) { } return Address(bz), nil } - -// Account is a standard account using a sequence number for replay protection -// and a pubkey for authentication. -type Account interface { - GetAddress() Address - SetAddress(Address) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetSequence() int64 - SetSequence(int64) error - - GetCoins() Coins - SetCoins(Coins) error -} - -// AccountMapper stores and retrieves accounts from stores -// retrieved from the context. -type AccountMapper interface { - NewAccountWithAddress(ctx Context, addr Address) Account - GetAccount(ctx Context, addr Address) Account - SetAccount(ctx Context, acc Account) - IterateAccounts(ctx Context, process func(Account) (stop bool)) -} - -// AccountDecoder unmarshals account bytes -type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/types/handler.go b/types/handler.go index 679a3b1a7..129f42647 100644 --- a/types/handler.go +++ b/types/handler.go @@ -3,8 +3,5 @@ package types // core function variable which application runs for transactions type Handler func(ctx Context, msg Msg) Result -// core function variable which application runs to handle fees -type FeeHandler func(ctx Context, tx Tx, fee Coins) - // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) diff --git a/types/signature.go b/types/signature.go deleted file mode 100644 index 5bca2f606..000000000 --- a/types/signature.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import crypto "github.com/tendermint/go-crypto" - -// Standard Signature -type StdSignature struct { - crypto.PubKey `json:"pub_key"` // optional - crypto.Signature `json:"signature"` - Sequence int64 `json:"sequence"` -} diff --git a/types/tx_msg.go b/types/tx_msg.go index e17d152a5..186cf9b24 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -31,123 +31,6 @@ type Tx interface { // Gets the Msg. GetMsg() Msg - - // 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 - // matches. - // CONTRACT: If the signature is missing (ie the Msg is - // invalid), then the corresponding signature is - // .Empty(). - GetSignatures() []StdSignature -} - -var _ Tx = (*StdTx)(nil) - -// StdTx is a standard way to wrap a Msg with Fee and Signatures. -// NOTE: the first signature is the FeePayer (Signatures must not be nil). -type StdTx struct { - Msg `json:"msg"` - Fee StdFee `json:"fee"` - Signatures []StdSignature `json:"signatures"` -} - -func NewStdTx(msg Msg, fee StdFee, sigs []StdSignature) StdTx { - return StdTx{ - Msg: msg, - Fee: fee, - Signatures: sigs, - } -} - -//nolint -func (tx StdTx) GetMsg() Msg { return tx.Msg } -func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } - -// FeePayer returns the address responsible for paying the fees -// for the transactions. It's the first address returned by msg.GetSigners(). -// If GetSigners() is empty, this panics. -func FeePayer(tx Tx) Address { - return tx.GetMsg().GetSigners()[0] -} - -//__________________________________________________________ - -// StdFee includes the amount of coins paid in fees and the maximum -// gas to be used by the transaction. The ratio yields an effective "gasprice", -// which must be above some miminum to be accepted into the mempool. -type StdFee struct { - Amount Coins `json:"amount"` - Gas int64 `json:"gas"` -} - -func NewStdFee(gas int64, amount ...Coin) StdFee { - return StdFee{ - Amount: amount, - Gas: gas, - } -} - -// fee bytes for signing later -func (fee StdFee) Bytes() []byte { - // normalize. XXX - // this is a sign of something ugly - // (in the lcd_test, client side its null, - // server side its []) - if len(fee.Amount) == 0 { - fee.Amount = Coins{} - } - bz, err := json.Marshal(fee) // TODO - if err != nil { - panic(err) - } - return bz -} - -//__________________________________________________________ - -// StdSignDoc is replay-prevention structure. -// It includes the result of msg.GetSignBytes(), -// as well as the ChainID (prevent cross chain replay) -// and the Sequence numbers for each signature (prevent -// inchain replay and enforce tx ordering per account). -type StdSignDoc struct { - ChainID string `json:"chain_id"` - Sequences []int64 `json:"sequences"` - FeeBytes []byte `json:"fee_bytes"` - MsgBytes []byte `json:"msg_bytes"` - AltBytes []byte `json:"alt_bytes"` -} - -// StdSignBytes returns the bytes to sign for a transaction. -// TODO: change the API to just take a chainID and StdTx ? -func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg Msg) []byte { - bz, err := json.Marshal(StdSignDoc{ - ChainID: chainID, - Sequences: sequences, - FeeBytes: fee.Bytes(), - MsgBytes: msg.GetSignBytes(), - }) - if err != nil { - panic(err) - } - return bz -} - -// StdSignMsg is a convenience structure for passing along -// a Msg with the other requirements for a StdSignDoc before -// it is signed. For use in the CLI. -type StdSignMsg struct { - ChainID string - Sequences []int64 - Fee StdFee - Msg Msg - // XXX: Alt -} - -// get message bytes -func (msg StdSignMsg) Bytes() []byte { - return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) } //__________________________________________________________ diff --git a/x/auth/account.go b/x/auth/account.go new file mode 100644 index 000000000..28366467a --- /dev/null +++ b/x/auth/account.go @@ -0,0 +1,25 @@ +package auth + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +// Account is a standard account using a sequence number for replay protection +// and a pubkey for authentication. +type Account interface { + GetAddress() sdk.Address + SetAddress(sdk.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetSequence() int64 + SetSequence(int64) error + + GetCoins() sdk.Coins + SetCoins(sdk.Coins) error +} + +// AccountDecoder unmarshals account bytes +type AccountDecoder func(accountBytes []byte) (Account, error) diff --git a/x/auth/ante.go b/x/auth/ante.go index 248083206..213952407 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -15,13 +15,20 @@ const ( // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures, // and deducts fees from the first signer. -func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHandler { +func NewAnteHandler(am AccountMapper) sdk.AnteHandler { + return func( ctx sdk.Context, tx sdk.Tx, ) (_ sdk.Context, _ sdk.Result, abort bool) { + // This AnteHandler requires Txs to be StdTxs + stdTx, ok := tx.(StdTx) + if !ok { + return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true + } + // Assert that there are signatures. - var sigs = tx.GetSignatures() + var sigs = stdTx.GetSignatures() if len(sigs) == 0 { return ctx, sdk.ErrUnauthorized("no signers").Result(), @@ -30,12 +37,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan msg := tx.GetMsg() - // TODO: will this always be a stdtx? should that be used in the function signature? - stdTx, ok := tx.(sdk.StdTx) - if !ok { - return ctx, sdk.ErrInternal("tx must be sdk.StdTx").Result(), true - } - // Assert that number of signatures is correct. var signerAddrs = msg.GetSigners() if len(sigs) != len(signerAddrs) { @@ -56,10 +57,10 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan if chainID == "" { chainID = viper.GetString("chain-id") } - signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, fee, msg) + signBytes := StdSignBytes(ctx.ChainID(), sequences, fee, msg) // Check sig and nonce and collect signer accounts. - var signerAccs = make([]sdk.Account, len(signerAddrs)) + var signerAccs = make([]Account, len(signerAddrs)) for i := 0; i < len(sigs); i++ { signerAddr, sig := signerAddrs[i], sigs[i] @@ -77,7 +78,6 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // TODO: min fee if !fee.Amount.IsZero() { signerAcc, res = deductFees(signerAcc, fee) - feeHandler(ctx, tx, fee.Amount) if !res.IsOK() { return ctx, res, true } @@ -104,9 +104,9 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // verify the signature and increment the sequence. // if the account doesn't have a pubkey, set it. func processSig( - ctx sdk.Context, am sdk.AccountMapper, - addr sdk.Address, sig sdk.StdSignature, signBytes []byte) ( - acc sdk.Account, res sdk.Result) { + ctx sdk.Context, am AccountMapper, + addr sdk.Address, sig StdSignature, signBytes []byte) ( + acc Account, res sdk.Result) { // Get the account. acc = am.GetAccount(ctx, addr) @@ -152,7 +152,7 @@ func processSig( // Deduct the fee from the account. // We could use the CoinKeeper (in addition to the AccountMapper, // because the CoinKeeper doesn't give us accounts), but it seems easier to do this. -func deductFees(acc sdk.Account, fee sdk.StdFee) (sdk.Account, sdk.Result) { +func deductFees(acc Account, fee StdFee) (Account, sdk.Result) { coins := acc.GetCoins() feeAmount := fee.Amount diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index b45cb12dd..08bd520fb 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) // GetAccountCmd for the auth.BaseAccount type @@ -17,8 +18,8 @@ func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command { } // Get account decoder for auth.DefaultAccount -func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { - return func(accBytes []byte) (acct sdk.Account, err error) { +func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { + return func(accBytes []byte) (acct auth.Account, err error) { // acct := new(auth.BaseAccount) err = cdc.UnmarshalBinaryBare(accBytes, &acct) if err != nil { @@ -30,7 +31,7 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { // GetAccountCmd returns a query account that will display the // state of the account at a given address -func GetAccountCmd(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) *cobra.Command { +func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command { return &cobra.Command{ Use: "account [address]", Short: "Query account balance", diff --git a/x/auth/context.go b/x/auth/context.go index b233f1e86..40fb17785 100644 --- a/x/auth/context.go +++ b/x/auth/context.go @@ -34,15 +34,15 @@ const ( ) // add the signers to the context -func WithSigners(ctx types.Context, accounts []types.Account) types.Context { +func WithSigners(ctx types.Context, accounts []Account) types.Context { return ctx.WithValue(contextKeySigners, accounts) } // get the signers from the context -func GetSigners(ctx types.Context) []types.Account { +func GetSigners(ctx types.Context) []Account { v := ctx.Value(contextKeySigners) if v == nil { - return []types.Account{} + return []Account{} } - return v.([]types.Account) + return v.([]Account) } diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 3666f13b6..cdab2480e 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -9,9 +9,6 @@ import ( crypto "github.com/tendermint/go-crypto" ) -var _ sdk.AccountMapper = (*AccountMapper)(nil) - -// Implements sdk.AccountMapper. // This AccountMapper encodes/decodes accounts using the // go-amino (binary) encoding/decoding library. type AccountMapper struct { @@ -19,8 +16,8 @@ type AccountMapper struct { // The (unexposed) key used to access the store from the Context. key sdk.StoreKey - // The prototypical sdk.Account concrete type. - proto sdk.Account + // The prototypical Account concrete type. + proto Account // The wire codec for binary encoding/decoding of accounts. cdc *wire.Codec @@ -29,7 +26,7 @@ type AccountMapper struct { // NewAccountMapper returns a new sdk.AccountMapper that // uses go-amino to (binary) encode and decode concrete sdk.Accounts. // nolint -func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) AccountMapper { +func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountMapper { return AccountMapper{ key: key, proto: proto, @@ -38,14 +35,14 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) Acco } // Implaements sdk.AccountMapper. -func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) Account { acc := am.clonePrototype() acc.SetAddress(addr) return acc } // Implements sdk.AccountMapper. -func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Account { +func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) Account { store := ctx.KVStore(am.key) bz := store.Get(addr) if bz == nil { @@ -56,7 +53,7 @@ func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Accoun } // Implements sdk.AccountMapper. -func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { +func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) { addr := acc.GetAddress() store := ctx.KVStore(am.key) bz := am.encodeAccount(acc) @@ -64,7 +61,7 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) { } // Implements sdk.AccountMapper. -func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) { +func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) { store := ctx.KVStore(am.key) iter := store.Iterator(nil, nil) for { @@ -89,7 +86,8 @@ func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.Address) (crypto.Pub return acc.GetPubKey(), nil } -func (am AccountMapper) setPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { +// Sets the PubKey of the account at address +func (am AccountMapper) SetPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error { acc := am.GetAccount(ctx, addr) if acc == nil { return sdk.ErrUnknownAddress(addr.String()) @@ -122,7 +120,7 @@ func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.Address, newSequen // misc. // Creates a new struct (or pointer to struct) from am.proto. -func (am AccountMapper) clonePrototype() sdk.Account { +func (am AccountMapper) clonePrototype() Account { protoRt := reflect.TypeOf(am.proto) if protoRt.Kind() == reflect.Ptr { protoCrt := protoRt.Elem() @@ -130,7 +128,7 @@ func (am AccountMapper) clonePrototype() sdk.Account { panic("accountMapper requires a struct proto sdk.Account, or a pointer to one") } protoRv := reflect.New(protoCrt) - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } @@ -138,14 +136,14 @@ func (am AccountMapper) clonePrototype() sdk.Account { } protoRv := reflect.New(protoRt).Elem() - clone, ok := protoRv.Interface().(sdk.Account) + clone, ok := protoRv.Interface().(Account) if !ok { panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) } return clone } -func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { +func (am AccountMapper) encodeAccount(acc Account) []byte { bz, err := am.cdc.MarshalBinaryBare(acc) if err != nil { panic(err) @@ -153,7 +151,7 @@ func (am AccountMapper) encodeAccount(acc sdk.Account) []byte { return bz } -func (am AccountMapper) decodeAccount(bz []byte) (acc sdk.Account) { +func (am AccountMapper) decodeAccount(bz []byte) (acc Account) { err := am.cdc.UnmarshalBinaryBare(bz, &acc) if err != nil { panic(err) diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go new file mode 100644 index 000000000..bc01b0149 --- /dev/null +++ b/x/auth/stdtx.go @@ -0,0 +1,131 @@ +package auth + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +var _ sdk.Tx = (*StdTx)(nil) + +// StdTx is a standard way to wrap a Msg with Fee and Signatures. +// NOTE: the first signature is the FeePayer (Signatures must not be nil). +type StdTx struct { + Msg sdk.Msg `json:"msg"` + Fee StdFee `json:"fee"` + Signatures []StdSignature `json:"signatures"` +} + +func NewStdTx(msg sdk.Msg, fee StdFee, sigs []StdSignature) StdTx { + return StdTx{ + Msg: msg, + Fee: fee, + Signatures: sigs, + } +} + +//nolint +func (tx StdTx) GetMsg() sdk.Msg { return tx.Msg } + +// 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 +// matches. +// CONTRACT: If the signature is missing (ie the Msg is +// invalid), then the corresponding signature is +// .Empty(). +func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } + +// FeePayer returns the address responsible for paying the fees +// for the transactions. It's the first address returned by msg.GetSigners(). +// If GetSigners() is empty, this panics. +func FeePayer(tx sdk.Tx) sdk.Address { + return tx.GetMsg().GetSigners()[0] +} + +//__________________________________________________________ + +// StdFee includes the amount of coins paid in fees and the maximum +// gas to be used by the transaction. The ratio yields an effective "gasprice", +// which must be above some miminum to be accepted into the mempool. +type StdFee struct { + Amount sdk.Coins `json:"amount"` + Gas int64 `json:"gas"` +} + +func NewStdFee(gas int64, amount ...sdk.Coin) StdFee { + return StdFee{ + Amount: amount, + Gas: gas, + } +} + +// fee bytes for signing later +func (fee StdFee) Bytes() []byte { + // normalize. XXX + // this is a sign of something ugly + // (in the lcd_test, client side its null, + // server side its []) + if len(fee.Amount) == 0 { + fee.Amount = sdk.Coins{} + } + bz, err := json.Marshal(fee) // TODO + if err != nil { + panic(err) + } + return bz +} + +//__________________________________________________________ + +// StdSignDoc is replay-prevention structure. +// It includes the result of msg.GetSignBytes(), +// as well as the ChainID (prevent cross chain replay) +// and the Sequence numbers for each signature (prevent +// inchain replay and enforce tx ordering per account). +type StdSignDoc struct { + ChainID string `json:"chain_id"` + Sequences []int64 `json:"sequences"` + FeeBytes []byte `json:"fee_bytes"` + MsgBytes []byte `json:"msg_bytes"` + AltBytes []byte `json:"alt_bytes"` +} + +// StdSignBytes returns the bytes to sign for a transaction. +// TODO: change the API to just take a chainID and StdTx ? +func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte { + bz, err := json.Marshal(StdSignDoc{ + ChainID: chainID, + Sequences: sequences, + FeeBytes: fee.Bytes(), + MsgBytes: msg.GetSignBytes(), + }) + if err != nil { + panic(err) + } + return bz +} + +// StdSignMsg is a convenience structure for passing along +// a Msg with the other requirements for a StdSignDoc before +// it is signed. For use in the CLI. +type StdSignMsg struct { + ChainID string + Sequences []int64 + Fee StdFee + Msg sdk.Msg + // XXX: Alt +} + +// get message bytes +func (msg StdSignMsg) Bytes() []byte { + return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg) +} + +// Standard Signature +type StdSignature struct { + crypto.PubKey `json:"pub_key"` // optional + crypto.Signature `json:"signature"` + Sequence int64 `json:"sequence"` +} diff --git a/x/auth/wire.go b/x/auth/wire.go deleted file mode 100644 index 9db1b85cc..000000000 --- a/x/auth/wire.go +++ /dev/null @@ -1,12 +0,0 @@ -package auth - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" -) - -// Register concrete types on wire codec for default AppAccount -func RegisterWire(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil) -} diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 6ef73c68b..b14da4d81 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) const ( @@ -16,11 +17,11 @@ const ( // Keeper manages transfers between accounts type Keeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewKeeper returns a new Keeper -func NewKeeper(am sdk.AccountMapper) Keeper { +func NewKeeper(am auth.AccountMapper) Keeper { return Keeper{am: am} } @@ -63,11 +64,11 @@ func (keeper Keeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outputs [ // SendKeeper only allows transfers between accounts, without the possibility of creating coins type SendKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewSendKeeper returns a new Keeper -func NewSendKeeper(am sdk.AccountMapper) SendKeeper { +func NewSendKeeper(am auth.AccountMapper) SendKeeper { return SendKeeper{am: am} } @@ -95,11 +96,11 @@ func (keeper SendKeeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outpu // ViewKeeper only allows reading of balances type ViewKeeper struct { - am sdk.AccountMapper + am auth.AccountMapper } // NewViewKeeper returns a new Keeper -func NewViewKeeper(am sdk.AccountMapper) ViewKeeper { +func NewViewKeeper(am auth.AccountMapper) ViewKeeper { return ViewKeeper{am: am} } @@ -115,7 +116,7 @@ func (keeper ViewKeeper) HasCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coi //______________________________________________________________________________________________ -func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins { +func getCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address) sdk.Coins { ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -124,7 +125,7 @@ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins return acc.GetCoins() } -func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { +func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins") acc := am.GetAccount(ctx, addr) if acc == nil { @@ -136,13 +137,13 @@ func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C } // HasCoins returns whether or not an account has at least amt coins. -func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { +func hasCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins") return getCoins(ctx, am, addr).IsGTE(amt) } // SubtractCoins subtracts amt from the coins at the addr. -func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func subtractCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Minus(amt) @@ -155,7 +156,7 @@ func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt } // AddCoins adds amt to the coins at the addr. -func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { +func addCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Plus(amt) @@ -169,7 +170,7 @@ func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C // SendCoins moves coins from one account to another // NOTE: Make sure to revert state changes from tx on error -func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { +func sendCoins(ctx sdk.Context, am auth.AccountMapper, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) (sdk.Tags, sdk.Error) { _, subTags, err := subtractCoins(ctx, am, fromAddr, amt) if err != nil { return nil, err @@ -185,7 +186,7 @@ func sendCoins(ctx sdk.Context, am sdk.AccountMapper, fromAddr sdk.Address, toAd // InputOutputCoins handles a list of inputs and outputs // NOTE: Make sure to revert state changes from tx on error -func inputOutputCoins(ctx sdk.Context, am sdk.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { +func inputOutputCoins(ctx sdk.Context, am auth.AccountMapper, inputs []Input, outputs []Output) (sdk.Tags, sdk.Error) { allTags := sdk.EmptyTags() for _, in := range inputs { diff --git a/x/auth/baseaccount.go b/x/baseaccount/baseaccount.go similarity index 90% rename from x/auth/baseaccount.go rename to x/baseaccount/baseaccount.go index ff907fc38..9701ac41d 100644 --- a/x/auth/baseaccount.go +++ b/x/baseaccount/baseaccount.go @@ -1,18 +1,19 @@ -package auth +package baseaccount import ( "errors" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) //----------------------------------------------------------- // BaseAccount -var _ sdk.Account = (*BaseAccount)(nil) +var _ auth.Account = (*BaseAccount)(nil) // BaseAccount - base account structure. // Extend this by embedding this in your AppAccount. @@ -82,7 +83,7 @@ func (acc *BaseAccount) SetSequence(seq int64) error { // Most users shouldn't use this, but this comes handy for tests. func RegisterBaseAccount(cdc *wire.Codec) { - cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil) wire.RegisterCrypto(cdc) } diff --git a/x/auth/baseaccount_test.go b/x/baseaccount/baseaccount_test.go similarity index 99% rename from x/auth/baseaccount_test.go rename to x/baseaccount/baseaccount_test.go index d3363e4fb..ed1a322c2 100644 --- a/x/auth/baseaccount_test.go +++ b/x/baseaccount/baseaccount_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/auth/handler.go b/x/baseaccount/handler.go similarity index 58% rename from x/auth/handler.go rename to x/baseaccount/handler.go index 8a0e1061a..46307c881 100644 --- a/x/auth/handler.go +++ b/x/baseaccount/handler.go @@ -1,19 +1,20 @@ -package auth +package baseaccount import ( "reflect" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) -// NewHandler returns a handler for "auth" type messages. -func NewHandler(am AccountMapper) sdk.Handler { +// NewHandler returns a handler for "baseaccount" type messages. +func NewHandler(am auth.AccountMapper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgChangeKey: return handleMsgChangeKey(ctx, am, msg) default: - errMsg := "Unrecognized auth Msg type: " + reflect.TypeOf(msg).Name() + errMsg := "Unrecognized baseaccount Msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -21,9 +22,9 @@ func NewHandler(am AccountMapper) sdk.Handler { // Handle MsgChangeKey // Should be very expensive, because once this happens, an account is un-prunable -func handleMsgChangeKey(ctx sdk.Context, am AccountMapper, msg MsgChangeKey) sdk.Result { +func handleMsgChangeKey(ctx sdk.Context, am auth.AccountMapper, msg MsgChangeKey) sdk.Result { - err := am.setPubKey(ctx, msg.Address, msg.NewPubKey) + err := am.SetPubKey(ctx, msg.Address, msg.NewPubKey) if err != nil { return err.Result() } diff --git a/x/auth/msgs.go b/x/baseaccount/msgs.go similarity index 87% rename from x/auth/msgs.go rename to x/baseaccount/msgs.go index 545b296e5..f0319ac7f 100644 --- a/x/auth/msgs.go +++ b/x/baseaccount/msgs.go @@ -1,11 +1,10 @@ -package auth +package baseaccount import ( "encoding/json" - "github.com/tendermint/go-crypto" - sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" ) // MsgChangeKey - high level transaction of the auth module @@ -22,7 +21,7 @@ func NewMsgChangeKey(addr sdk.Address, pubkey crypto.PubKey) MsgChangeKey { } // Implements Msg. -func (msg MsgChangeKey) Type() string { return "auth" } +func (msg MsgChangeKey) Type() string { return "baseaccount" } // Implements Msg. func (msg MsgChangeKey) ValidateBasic() sdk.Error { diff --git a/x/auth/msgs_test.go b/x/baseaccount/msgs_test.go similarity index 97% rename from x/auth/msgs_test.go rename to x/baseaccount/msgs_test.go index 30c98b073..46797fa0d 100644 --- a/x/auth/msgs_test.go +++ b/x/baseaccount/msgs_test.go @@ -1,4 +1,4 @@ -package auth +package baseaccount import ( "testing" diff --git a/x/baseaccount/wire.go b/x/baseaccount/wire.go new file mode 100644 index 000000000..4c77d1c72 --- /dev/null +++ b/x/baseaccount/wire.go @@ -0,0 +1,14 @@ +package baseaccount + +import ( + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&BaseAccount{}, "baseaccount/BaseAccount", nil) + wire.RegisterCrypto(cdc) + cdc.RegisterConcrete(MsgChangeKey{}, "baseaccount/changekey", nil) +} diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 27acebe08..5a87081af 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/baseaccount" ) // dummy addresses used for testing @@ -129,8 +130,8 @@ func makeTestCodec() *wire.Codec { cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil) // Register AppAccount - cdc.RegisterInterface((*sdk.Account)(nil), nil) - cdc.RegisterConcrete(&auth.BaseAccount{}, "test/stake/Account", nil) + cdc.RegisterInterface((*auth.Account)(nil), nil) + cdc.RegisterConcrete(&baseaccount.BaseAccount{}, "test/stake/Account", nil) wire.RegisterCrypto(cdc) return cdc @@ -148,7 +149,7 @@ func paramsNoInflation() Params { } // hogpodge of all sorts of input required for testing -func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, sdk.AccountMapper, Keeper) { +func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) { db := dbm.NewMemDB() keyStake := sdk.NewKVStoreKey("stake") keyMain := keyStake //sdk.NewKVStoreKey("main") //TODO fix multistore @@ -161,9 +162,9 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( - cdc, // amino codec - keyMain, // target store - &auth.BaseAccount{}, // prototype + cdc, // amino codec + keyMain, // target store + &baseaccount.BaseAccount{}, // prototype ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace)