diff --git a/docs/README.md b/docs/README.md index 41cfe403e6..e74d1aef86 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,13 +21,16 @@ NOTE: This documentation is a work-in-progress! - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK - [Ante Handler](core/app2.md#ante-handler) - The AnteHandler authenticates transactions - - [App3 - Modules](core/app3.md) - - [Accounts](core/app3.md#accounts) - Accounts are the prototypical object kept in the store - provides Account lookup on a KVStore - - [Transactions](core/app3.md#transactions) - `StdTx` is the default - implementation of `Tx` - - [CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin - transfer on an underlying AccountMapper + - [App3 - Modules: Auth and Bank](core/app3.md) + - [auth.Account](core/app3.md#accounts) - Accounts are the prototypical object kept in the store + - [auth.AccountMapper](core/app3.md#account-mapper) - AccountMapper gets and sets Account on a KVStore + - [auth.StdTx](core/app3.md#stdtx) - `StdTx` is the default implementation of `Tx` + - [auth.StdSignBytes](core/app3.md#signing) - `StdTx` must be signed with certain + information + - [auth.AnteHandler](core/app3.md#ante-handler) - The `AnteHandler` + verifies `StdTx`, manages accounts, and deducts fees + - [bank.CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin + transfers on an underlying AccountMapper - [App4 - Validator Set Changes](core/app4.md) - [InitChain](core/app4.md#init-chain) - Initialize the application state diff --git a/docs/core/app3.md b/docs/core/app3.md index c9a37c6f3e..bbff36f2c0 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -33,6 +33,10 @@ In this model, an account contains: - Sequence to prevent transaction replays - Coins to carry a balance +Note that the `AccountNumber` is a unique number that is assigned when the account is +created, and the `Sequence` is incremented by one every time a transaction is +sent from the account. + ### Account The `Account` interface captures this account model with getters and setters: @@ -146,7 +150,21 @@ type StdSignature struct { } ``` -And the standard form for a transaction fee is `StdFee`: +The signature includes both an `AccountNumber` and a `Sequence`. +The `Sequence` must match the one in the +corresponding account when the transaction is processed, and will increment by +one with every transaction. This prevents the same +transaction from being replayed multiple times, resolving the insecurity that +remains in App2. + +The `AccountNumber` is also for replay protection - it allows accounts to be +deleted from the store when they run out of accounts. If an account receives +coins after it is deleted, the account will be re-created, with the Sequence +reset to 0, but a new AccountNumber. If it weren't for the AccountNumber, the +last sequence of transactions made by the account before it was deleted could be +replayed! + +Finally, the standard form for a transaction fee is `StdFee`: ```go // StdFee includes the amount of coins paid in fees and the maximum @@ -158,36 +176,71 @@ type StdFee struct { } ``` +The fee must be paid by the first signer. This allows us to quickly check if the +transaction fee can be paid, and reject the transaction if not. + ## Signing -The standard bytes for signers to sign over is provided by: +The `StdTx` supports multiple messages and multiple signers. +To sign the transaction, each signer must collect the following information: + +- the ChainID (TODO haven't mentioned this yet) +- the AccountNumber and Sequence for the given signer's account (from the + blockchain) +- the transaction fee +- the list of transaction messages +- an optional memo + +Then they can compute the transaction bytes to sign using the +`auth.StdSignBytes` function: ```go -TODO +bytesToSign := StdSignBytes(chainID, accNum, accSequence, fee, msgs, memo) ``` ## AnteHandler -TODO +As we saw in `App2`, we can use an `AnteHandler` to authenticate transactions +before we handle any of their internal messages. While previously we implemented +our own simple `AnteHandler`, the `x/auth` module provides a much more advanced +one that uses `AccountMapper` and works with `StdTx`: -The list of signatures in the `StdTx` must match the result of `GetSigners()` -for each `Msg`. The validation rules for the `StdTx` will be defined in the +```go +TODO: feekeeper :( +app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) +``` -Recall that the `Sequence` is expected to increment every time a -message is signed by a given account in order to prevent "replay attacks" where -the same message could be executed over and over again. The `AccountNumber` is -assigned when the account is created or recreated after being emptied. +The AnteHandler provided by `x/auth` enforces the following rules: -The `StdSignature` can also optionally include the public key for verifying the -signature. The public key only needs to be included the first time a transaction -is sent from a given account - from then on it will be stored in the `Account` -and can be left out of transactions. +- the memo must not be too big +- the right number of signatures must be provided (one for each unique signer + returned by `msg.GetSigner` for each `msg`) +- any account signing for the first-time must include a public key in the + StdSignature +- the signatures must be valid when authenticated in the same order as specified + by the messages -The fee is provided in a standard form as `StdFee`: -Note that the address responsible for paying the transactions fee is the first address -returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided -to return this. +Note that validating +signatures requires checking that the correct account number and sequence was +used by each signer, as this information is required in the `StdSignBytes`. +If any of the above are not satisfied, it returns an error. + +If all of the above verifications pass, the AnteHandler makes the following +changes to the state: + +- increment account sequence by one for all signers +- set the pubkey for any first-time signers +- deduct the fee from the first signer + +Recall that incrementing the `Sequence` prevents "replay attacks" where +the same message could be executed over and over again. + +The PubKey is required for signature verification, but it is only required in +the StdSignature once. From that point on, it will be stored in the account. + +The fee is paid by the first address returned by msg.GetSigners() for the first `Msg`. +The convenience function `FeePayer(tx Tx) sdk.Address` is provided to return this. ## App3