diff --git a/types/errors.go b/types/errors.go index 9d8175e309..008bd6f086 100644 --- a/types/errors.go +++ b/types/errors.go @@ -27,6 +27,7 @@ const ( CodeInsufficientFunds CodeType = 5 CodeUnknownRequest CodeType = 6 CodeUnrecognizedAddress CodeType = 7 + CodeMissingPubKey CodeType = 8 CodeGenesisParse CodeType = 0xdead // TODO: remove ? ) @@ -50,6 +51,8 @@ func CodeToDefaultMsg(code CodeType) string { return "Unknown request" case CodeUnrecognizedAddress: return "Unrecognized address" + case CodeMissingPubKey: + return "Missing pubkey" default: return fmt.Sprintf("Unknown code %d", code) } @@ -84,6 +87,9 @@ func ErrUnknownRequest(msg string) Error { func ErrUnrecognizedAddress(addr Address) Error { return newError(CodeUnrecognizedAddress, addr.String()) } +func ErrMissingPubKey(addr Address) Error { + return newError(CodeMissingPubKey, addr.String()) +} //---------------------------------------- // Error & sdkError diff --git a/types/tx_msg.go b/types/tx_msg.go index b829bef961..81719f18a7 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -78,7 +78,7 @@ func FeePayer(tx Tx) Address { } // StdFee includes the amount of coins paid in fees and the maximum -// gas to be used by the transaction. The ratio yields an effectie "gasprice", +// 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"` diff --git a/x/auth/ante.go b/x/auth/ante.go index f2495af78d..f602f8911b 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -7,6 +7,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// NewAnteHandler returns an AnteHandler that checks +// and increments sequence numbers, checks signatures, +// and deducts fees from the first signer. func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, @@ -31,32 +34,20 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { true } - // Collect accounts to set in the context - var signerAccs = make([]sdk.Account, len(signerAddrs)) - - // Get the sign bytes by collecting all sequence numbers + // Get the sign bytes (requires all sequence numbers) sequences := make([]int64, len(signerAddrs)) for i := 0; i < len(signerAddrs); i++ { sequences[i] = sigs[i].Sequence } signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, msg) - // Check fee payer sig and nonce, and deduct fee. - // This is done first because it only - // requires fetching 1 account. - payerAddr, payerSig := signerAddrs[0], sigs[0] - payerAcc, res := processSig(ctx, accountMapper, payerAddr, payerSig, signBytes) - if !res.IsOK() { - return ctx, res, true - } - signerAccs[0] = payerAcc - // TODO: Charge fee from payerAcc. - // TODO: accountMapper.SetAccount(ctx, payerAddr) + // Check sig and nonce and collect signer accounts. + var signerAccs = make([]sdk.Account, len(signerAddrs)) + for i := 0; i < len(sigs); i++ { + isFeePayer := i == 0 // first sig pays the fees - // Check sig and nonce for the rest. - for i := 1; i < len(sigs); i++ { signerAddr, sig := signerAddrs[i], sigs[i] - signerAcc, res := processSig(ctx, accountMapper, signerAddr, sig, signBytes) + signerAcc, res := processSig(ctx, accountMapper, signerAddr, sig, signBytes, isFeePayer) if !res.IsOK() { return ctx, res, true } @@ -64,13 +55,17 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { } ctx = WithSigners(ctx, signerAccs) + // TODO: tx tags (?) return ctx, sdk.Result{}, false // continue... } } // verify the signature and increment the sequence. -// if the account doesn't have a pubkey, set it as well. -func processSig(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, sig sdk.StdSignature, signBytes []byte) (acc sdk.Account, res sdk.Result) { +// if the account doesn't have a pubkey, set it. +// deduct fee from fee payer. +func processSig(ctx sdk.Context, am sdk.AccountMapper, + addr sdk.Address, sig sdk.StdSignature, signBytes []byte, + isFeePayer bool) (acc sdk.Account, res sdk.Result) { // Get the account acc = am.GetAccount(ctx, addr) @@ -86,7 +81,8 @@ func processSig(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, sig sdk } acc.SetSequence(seq + 1) - // Check and possibly set pubkey. + // If pubkey is not known for account, + // set it from the StdSignature pubKey := acc.GetPubKey() if pubKey.Empty() { if sig.PubKey.Empty() { @@ -97,6 +93,9 @@ func processSig(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, sig sdk fmt.Sprintf("invalid PubKey for address %v", addr)).Result() } pubKey = sig.PubKey + if pubKey.Empty() { + return nil, sdk.ErrMissingPubKey(addr).Result() + } err := acc.SetPubKey(pubKey) if err != nil { return nil, sdk.ErrInternal("setting PubKey on signer").Result() @@ -107,6 +106,10 @@ func processSig(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, sig sdk return nil, sdk.ErrUnauthorized("signature verification failed").Result() } + if isFeePayer { + // TODO: pay fees + } + // Save the account. am.SetAccount(ctx, acc) return