Skip to content

Commit

Permalink
x/auth module spec / code reconciliation (cosmos#2964)
Browse files Browse the repository at this point in the history
  • Loading branch information
cwgoes authored and jackzampolin committed Dec 6, 2018
1 parent 8162489 commit ba5e87c
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 4 deletions.
3 changes: 2 additions & 1 deletion PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ IMPROVEMENTS
* Gaia

* SDK
* \#1277 Complete bank module specification
- \#1277 Complete bank module specification
- \#2963 Complete auth module specification
* \#2914 No longer withdraw validator rewards on bond/unbond, but rather move
the rewards to the respective validator's pools.

Expand Down
29 changes: 29 additions & 0 deletions docs/spec/auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Auth module specification

## Abstract

This document specifies the auth module of the Cosmos SDK.

The auth module is responsible for specifying the base transaction and account types
for an application, since the SDK itself is agnostic to these particulars. It contains
the ante handler, where all basic transaction validity checks (signatures, nonces, auxiliary fields)
are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts.

This module will be used in the Cosmos Hub.

## Contents

1. **[State](state.md)**
1. [Accounts](state.md#accounts)
1. [Account Interface](state.md#account-interface)
1. [Base Account](state.md#baseaccount)
1. [Vesting Account](state.md#vestingaccount)
1. **[Types](types.md)**
1. [StdFee](types.md#stdfee)
1. [StdSignature](types.md#stdsignature)
1. [StdTx](types.md#stdtx)
1. [StdSignDoc](types.md#stdsigndoc)
1. **[Keepers](keepers.md)**
1. [AccountKeeper](keepers.md#account-keeper)
1. **[Handlers](handlers.md)**
1. [Ante Handler](handlers.md#ante-handler)
38 changes: 38 additions & 0 deletions docs/spec/auth/handlers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Handlers

The auth module presently has no transaction handlers of its own, but does expose
the special `AnteHandler`, used for performing basic validity checks on a transaction,
such that it could be thrown out of the mempool. Note that the ante handler is called on
`CheckTx`, but *also* on `DeliverTx`, as Tendermint proposers presently have the ability
to include in their proposed block transactions which fail `CheckTx`.

### Ante Handler

```golang
anteHandler(ak AccountKeeper, fck FeeCollectionKeeper, tx sdk.Tx)
if !tx.(StdTx)
fail with "not a StdTx"

if isCheckTx and tx.Fee < config.SubjectiveMinimumFee
fail with "insufficient fee for mempool inclusion"

if tx.ValidateBasic() != nil
fail with "tx failed ValidateBasic"

if tx.Fee > 0
account = GetAccount(tx.GetSigners()[0])
coins := acount.GetCoins()
if coins < tx.Fee
fail with "insufficient fee to pay for transaction"
account.SetCoins(coins - tx.Fee)
fck.AddCollectedFees(tx.Fee)

for index, signature in tx.GetSignatures()
account = GetAccount(tx.GetSigners()[index])
bytesToSign := StdSignBytes(chainID, acc.GetAccountNumber(),
acc.GetSequence(), tx.Fee, tx.Msgs, tx.Memo)
if !signature.Verify(bytesToSign)
fail with "invalid signature"

return
```
39 changes: 39 additions & 0 deletions docs/spec/auth/keepers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Keepers

The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts.

### Account Keeper

Presently only one fully-permissioned account keeper is exposed, which has the ability to both read and write
all fields of all accounts, and to iterate over all stored accounts.

```golang
type AccountKeeper interface {
// Return a new account with the next account number and the specified address. Does not save the new account to the store.
NewAccountWithAddress(AccAddress) Account

// Return a new account with the next account number. Does not save the new account to the store.
NewAccount(Account) Account

// Retrieve an account from the store
GetAccount(AccAddress) Account

// Set an account in the store
SetAccount(Account)

// Remove an account from the store
RemoveAccount(Account)

// Iterate over all accounts, calling the provided function. Stop iteraiton when it returns false.
IterateAccounts(func(Account) (bool))

// Fetch the public key of an account at a specified address
GetPubKey(AccAddress) PubKey

// Fetch the sequence of an account at a specified address
GetSequence(AccAddress) uint64

// Fetch the next account number, and increment the internal counter
GetNextAccountNumber() uint64
}
```
58 changes: 58 additions & 0 deletions docs/spec/auth/state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## State

### Accounts

Accounts contain authentication information for a uniquely identified external user of an SDK blockchain,
including public key, address, and account number / sequence number for replay protection. For efficiency,
since account balances must also be fetched to pay fees, account structs also store the balance of a user
as `sdk.Coins`.

Accounts are exposed externally as an interface, and stored internally as
either a base account or vesting account. Module clients wishing to add more
account types may do so.

- `0x01 | Address -> amino(account)`

#### Account Interface

The account interface exposes methods to read and write standard account information.
Note that all of these methods operate on an account struct confirming to the interface
- in order to write the account to the store, the account keeper will need to be used.

```golang
type Account interface {
GetAddress() AccAddress
SetAddress(AccAddress)

GetPubKey() PubKey
SetPubKey(PubKey)

GetAccountNumber() uint64
SetAccountNumber(uint64)

GetSequence() uint64
SetSequence(uint64)

GetCoins() Coins
SetCoins(Coins)
}
```

#### Base Account

A base account is the simplest and most common account type, which just stores all requisite
fields directly in a struct.

```golang
type BaseAccount struct {
Address AccAddress
Coins Coins
PubKey PubKey
AccountNumber uint64
Sequence uint64
}
```

#### Vesting Account

See [Vesting](vesting.md).
Empty file removed docs/spec/auth/transactions.md
Empty file.
65 changes: 65 additions & 0 deletions docs/spec/auth/types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Types

Besides accounts (specified in [State](state.md)), the types exposed by the auth module
are `StdFee`, the combination of an amount and gas limit, `StdSignature`, the combination
of an optional public key and a cryptographic signature as a byte array, `StdTx`,
a struct which implements the `sdk.Tx` interface using `StdFee` and `StdSignature`, and
`StdSignDoc`, a replay-prevention structure for `StdTx` which transaction senders must sign over.

### StdFee

A `StdFee` is simply the combination of a fee amount, in any number of denominations,
and a gas limit (where dividing the amount by the gas limit gives a "gas price").

```golang
type StdFee struct {
Amount Coins
Gas uint64
}
```

### StdSignature

A `StdSignature` is the combination of an optional public key and a cryptographic signature
as a byte array. The SDK is agnostic to particular key or signature formats and supports any
supported by the `PubKey` interface.

```golang
type StdSignature struct {
PubKey PubKey
Signature []byte
}
```

### StdTx

A `StdTx` is a struct which implements the `sdk.Tx` interface, and is likely to be generic
enough to serve the purposes of many Cosmos SDK blockchains.

```golang
type StdTx struct {
Msgs []sdk.Msg
Fee StdFee
Signatures []StdSignature
Memo string
}
```

### StdSignDoc

A `StdSignDoc` is a replay-prevention structure to be signed over, which ensures that
any submitted transaction (which is simply a signature over a particular bytestring)
will only be executable once on a particular blockchain.

`json.RawMessage` is preferred over using the SDK types for future compatibility.

```golang
type StdSignDoc struct {
AccountNumber uint64
ChainID string
Fee json.RawMessage
Memo string
Msgs []json.RawMessage
Sequence uint64
}
```
11 changes: 8 additions & 3 deletions x/auth/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import (
"github.com/tendermint/tendermint/crypto"
)

var globalAccountNumberKey = []byte("globalAccountNumber")
var (
// Prefix for account-by-address store
AddressStoreKeyPrefix = []byte{0x01}

globalAccountNumberKey = []byte("globalAccountNumber")
)

// This AccountKeeper encodes/decodes accounts using the
// go-amino (binary) encoding/decoding library.
Expand Down Expand Up @@ -61,7 +66,7 @@ func (am AccountKeeper) NewAccount(ctx sdk.Context, acc Account) Account {

// Turn an address to key used to get it from the account store
func AddressStoreKey(addr sdk.AccAddress) []byte {
return append([]byte("account:"), addr.Bytes()...)
return append(AddressStoreKeyPrefix, addr.Bytes()...)
}

// Implements sdk.AccountKeeper.
Expand Down Expand Up @@ -93,7 +98,7 @@ func (am AccountKeeper) RemoveAccount(ctx sdk.Context, acc Account) {
// Implements sdk.AccountKeeper.
func (am AccountKeeper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) {
store := ctx.KVStore(am.key)
iter := sdk.KVStorePrefixIterator(store, []byte("account:"))
iter := sdk.KVStorePrefixIterator(store, AddressStoreKeyPrefix)
defer iter.Close()
for {
if !iter.Valid() {
Expand Down

0 comments on commit ba5e87c

Please sign in to comment.