2018-01-12 11:49:53 -08:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
2018-03-12 17:40:04 -07:00
|
|
|
"fmt"
|
2018-03-16 17:57:28 -07:00
|
|
|
"reflect"
|
2018-03-12 17:40:04 -07:00
|
|
|
|
2018-01-12 14:30:02 -08:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-01-12 11:49:53 -08:00
|
|
|
)
|
|
|
|
|
2018-01-22 05:44:24 -08:00
|
|
|
func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler {
|
2018-01-12 11:49:53 -08:00
|
|
|
return func(
|
2018-01-12 14:30:02 -08:00
|
|
|
ctx sdk.Context, tx sdk.Tx,
|
2018-01-26 05:11:01 -08:00
|
|
|
) (_ sdk.Context, _ sdk.Result, abort bool) {
|
2018-01-12 11:49:53 -08:00
|
|
|
|
2018-01-26 06:22:56 -08:00
|
|
|
// Assert that there are signatures.
|
2018-03-03 23:32:39 -08:00
|
|
|
var sigs = tx.GetSignatures()
|
2018-02-17 13:19:34 -08:00
|
|
|
if len(sigs) == 0 {
|
|
|
|
return ctx,
|
|
|
|
sdk.ErrUnauthorized("no signers").Result(),
|
|
|
|
true
|
2018-01-12 11:49:53 -08:00
|
|
|
}
|
2018-01-26 04:19:33 -08:00
|
|
|
|
2018-03-03 23:32:39 -08:00
|
|
|
// TODO: can tx just implement message?
|
|
|
|
msg := tx.GetMsg()
|
2018-01-26 06:22:56 -08:00
|
|
|
|
2018-01-26 04:19:33 -08:00
|
|
|
// Assert that number of signatures is correct.
|
2018-03-03 23:32:39 -08:00
|
|
|
var signerAddrs = msg.GetSigners()
|
2018-02-17 13:19:34 -08:00
|
|
|
if len(sigs) != len(signerAddrs) {
|
|
|
|
return ctx,
|
|
|
|
sdk.ErrUnauthorized("wrong number of signers").Result(),
|
|
|
|
true
|
|
|
|
}
|
2018-01-12 11:49:53 -08:00
|
|
|
|
2018-03-03 23:32:39 -08:00
|
|
|
// Collect accounts to set in the context
|
|
|
|
var signerAccs = make([]sdk.Account, len(signerAddrs))
|
2018-01-12 11:49:53 -08:00
|
|
|
|
2018-03-10 15:57:39 -08:00
|
|
|
// Get the sign bytes by collecting 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)
|
2018-03-04 00:15:26 -08:00
|
|
|
|
|
|
|
// Check fee payer sig and nonce, and deduct fee.
|
2018-03-03 23:32:39 -08:00
|
|
|
// This is done first because it only
|
|
|
|
// requires fetching 1 account.
|
2018-03-10 15:57:39 -08:00
|
|
|
payerAddr, payerSig := signerAddrs[0], sigs[0]
|
2018-03-04 00:15:26 -08:00
|
|
|
payerAcc, res := processSig(ctx, accountMapper, payerAddr, payerSig, signBytes)
|
2018-03-03 23:32:39 -08:00
|
|
|
if !res.IsOK() {
|
|
|
|
return ctx, res, true
|
|
|
|
}
|
|
|
|
signerAccs[0] = payerAcc
|
|
|
|
// TODO: Charge fee from payerAcc.
|
|
|
|
// TODO: accountMapper.SetAccount(ctx, payerAddr)
|
2018-01-12 11:49:53 -08:00
|
|
|
|
2018-03-03 23:32:39 -08:00
|
|
|
// Check sig and nonce for the rest.
|
|
|
|
for i := 1; i < len(sigs); i++ {
|
2018-03-04 00:15:26 -08:00
|
|
|
signerAddr, sig := signerAddrs[i], sigs[i]
|
|
|
|
signerAcc, res := processSig(ctx, accountMapper, signerAddr, sig, signBytes)
|
2018-03-03 23:32:39 -08:00
|
|
|
if !res.IsOK() {
|
|
|
|
return ctx, res, true
|
2018-01-12 11:49:53 -08:00
|
|
|
}
|
2018-03-03 23:32:39 -08:00
|
|
|
signerAccs[i] = signerAcc
|
2018-01-12 11:49:53 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx = WithSigners(ctx, signerAccs)
|
2018-01-12 14:30:02 -08:00
|
|
|
return ctx, sdk.Result{}, false // continue...
|
2018-01-12 11:49:53 -08:00
|
|
|
}
|
|
|
|
}
|
2018-03-03 23:32:39 -08:00
|
|
|
|
|
|
|
// 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) {
|
|
|
|
|
|
|
|
// Get the account
|
|
|
|
acc = am.GetAccount(ctx, addr)
|
|
|
|
if acc == nil {
|
|
|
|
return nil, sdk.ErrUnrecognizedAddress(addr).Result()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check and increment sequence number.
|
|
|
|
seq := acc.GetSequence()
|
|
|
|
if seq != sig.Sequence {
|
2018-03-12 17:40:04 -07:00
|
|
|
return nil, sdk.ErrInvalidSequence(
|
|
|
|
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result()
|
2018-03-03 23:32:39 -08:00
|
|
|
}
|
|
|
|
acc.SetSequence(seq + 1)
|
|
|
|
|
|
|
|
// Check and possibly set pubkey.
|
|
|
|
pubKey := acc.GetPubKey()
|
|
|
|
if pubKey.Empty() {
|
2018-03-16 17:57:28 -07:00
|
|
|
if sig.PubKey.Empty() {
|
|
|
|
return nil, sdk.ErrInternal("public Key not found").Result()
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(sig.PubKey.Address(), addr) {
|
|
|
|
return nil, sdk.ErrInternal(
|
|
|
|
fmt.Sprintf("invalid PubKey for address %v", addr)).Result()
|
|
|
|
}
|
2018-03-03 23:32:39 -08:00
|
|
|
pubKey = sig.PubKey
|
|
|
|
err := acc.SetPubKey(pubKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, sdk.ErrInternal("setting PubKey on signer").Result()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check sig.
|
2018-03-16 17:57:28 -07:00
|
|
|
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
2018-03-04 00:15:26 -08:00
|
|
|
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
2018-03-03 23:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Save the account.
|
|
|
|
am.SetAccount(ctx, acc)
|
|
|
|
return
|
|
|
|
}
|