fix and clean fees and x/auth
This commit is contained in:
@@ -124,7 +124,7 @@ func SignAndBuild(msg sdk.Msg, cdc *wire.Codec) ([]byte, error) {
|
||||
}}
|
||||
|
||||
// marshal bytes
|
||||
tx := sdk.NewStdTx(signMsg.Msg, sigs)
|
||||
tx := sdk.NewStdTx(signMsg.Msg, signMsg.Fee, sigs)
|
||||
|
||||
return cdc.MarshalBinary(tx)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ var (
|
||||
addr1 = priv1.PubKey().Address()
|
||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
coins = sdk.Coins{{"foocoin", 10}}
|
||||
fee = sdk.StdFee{
|
||||
sdk.Coins{{"foocoin", 0}},
|
||||
0,
|
||||
}
|
||||
|
||||
sendMsg = bank.SendMsg{
|
||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
@@ -82,8 +86,8 @@ func TestMsgs(t *testing.T) {
|
||||
|
||||
sequences := []int64{0}
|
||||
for i, m := range msgs {
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, m.msg))
|
||||
tx := sdk.NewStdTx(m.msg, []sdk.StdSignature{{
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, m.msg))
|
||||
tx := sdk.NewStdTx(m.msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
@@ -180,8 +184,8 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
||||
|
||||
// Sign the tx
|
||||
sequences := []int64{0}
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, sendMsg))
|
||||
tx := sdk.NewStdTx(sendMsg, []sdk.StdSignature{{
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, sendMsg))
|
||||
tx := sdk.NewStdTx(sendMsg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
@@ -213,7 +217,7 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
||||
|
||||
// resigning the tx with the bumped sequence should work
|
||||
sequences = []int64{1}
|
||||
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, tx.Msg))
|
||||
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg))
|
||||
tx.Signatures[0].Signature = sig
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
@@ -269,10 +273,13 @@ func TestQuizMsg(t *testing.T) {
|
||||
|
||||
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
||||
|
||||
// TODO:
|
||||
var fee sdk.StdFee
|
||||
|
||||
// Sign the tx
|
||||
tx := sdk.NewStdTx(msg, []sdk.StdSignature{{
|
||||
tx := sdk.NewStdTx(msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, msg)),
|
||||
Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, fee, msg)),
|
||||
Sequence: seq,
|
||||
}})
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func (msg SetTrendMsg) String() string {
|
||||
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
|
||||
func (msg SetTrendMsg) ValidateBasic() sdk.Error {
|
||||
if len(msg.Sender) == 0 {
|
||||
return sdk.ErrUnrecognizedAddress(msg.Sender).Trace("")
|
||||
return sdk.ErrUnrecognizedAddress(msg.Sender.String()).Trace("")
|
||||
}
|
||||
if strings.Contains(msg.Cool, "hot") {
|
||||
return sdk.ErrUnauthorized("").Trace("hot is not cool")
|
||||
@@ -88,7 +88,7 @@ func (msg QuizMsg) String() string {
|
||||
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
|
||||
func (msg QuizMsg) ValidateBasic() sdk.Error {
|
||||
if len(msg.Sender) == 0 {
|
||||
return sdk.ErrUnrecognizedAddress(msg.Sender).Trace("")
|
||||
return sdk.ErrUnrecognizedAddress(msg.Sender.String()).Trace("")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+6
-6
@@ -27,7 +27,7 @@ const (
|
||||
CodeInsufficientFunds CodeType = 5
|
||||
CodeUnknownRequest CodeType = 6
|
||||
CodeUnrecognizedAddress CodeType = 7
|
||||
CodeMissingPubKey CodeType = 8
|
||||
CodeInvalidPubKey CodeType = 8
|
||||
|
||||
CodeGenesisParse CodeType = 0xdead // TODO: remove ?
|
||||
)
|
||||
@@ -51,7 +51,7 @@ func CodeToDefaultMsg(code CodeType) string {
|
||||
return "Unknown request"
|
||||
case CodeUnrecognizedAddress:
|
||||
return "Unrecognized address"
|
||||
case CodeMissingPubKey:
|
||||
case CodeInvalidPubKey:
|
||||
return "Missing pubkey"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown code %d", code)
|
||||
@@ -84,11 +84,11 @@ func ErrInsufficientFunds(msg string) Error {
|
||||
func ErrUnknownRequest(msg string) Error {
|
||||
return newError(CodeUnknownRequest, msg)
|
||||
}
|
||||
func ErrUnrecognizedAddress(addr Address) Error {
|
||||
return newError(CodeUnrecognizedAddress, addr.String())
|
||||
func ErrUnrecognizedAddress(msg string) Error {
|
||||
return newError(CodeUnrecognizedAddress, msg)
|
||||
}
|
||||
func ErrMissingPubKey(addr Address) Error {
|
||||
return newError(CodeMissingPubKey, addr.String())
|
||||
func ErrInvalidPubKey(msg string) Error {
|
||||
return newError(CodeInvalidPubKey, msg)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
+37
-24
@@ -45,7 +45,7 @@ type Tx interface {
|
||||
|
||||
var _ Tx = (*StdTx)(nil)
|
||||
|
||||
// StdTx is a standard way to wrap a Msg with Signatures.
|
||||
// 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"`
|
||||
@@ -53,19 +53,14 @@ type StdTx struct {
|
||||
Signatures []StdSignature `json:"signatures"`
|
||||
}
|
||||
|
||||
func NewStdTx(msg Msg, sigs []StdSignature) StdTx {
|
||||
func NewStdTx(msg Msg, fee StdFee, sigs []StdSignature) StdTx {
|
||||
return StdTx{
|
||||
Msg: msg,
|
||||
Fee: fee,
|
||||
Signatures: sigs,
|
||||
}
|
||||
}
|
||||
|
||||
// SetFee sets the StdFee on the transaction.
|
||||
func (tx StdTx) SetFee(fee StdFee) StdTx {
|
||||
tx.Fee = fee
|
||||
return tx
|
||||
}
|
||||
|
||||
//nolint
|
||||
func (tx StdTx) GetMsg() Msg { return tx.Msg }
|
||||
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }
|
||||
@@ -77,6 +72,8 @@ 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.
|
||||
@@ -92,6 +89,16 @@ func NewStdFee(gas int64, amount ...Coin) StdFee {
|
||||
}
|
||||
}
|
||||
|
||||
func (fee StdFee) Bytes() []byte {
|
||||
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)
|
||||
@@ -100,27 +107,18 @@ func NewStdFee(gas int64, amount ...Coin) StdFee {
|
||||
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"` // TODO: do we really want this ?
|
||||
AltBytes []byte `json:"alt_bytes"`
|
||||
}
|
||||
|
||||
// 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
|
||||
Msg Msg
|
||||
}
|
||||
|
||||
func (msg StdSignMsg) Bytes() []byte {
|
||||
return StdSignBytes(msg.ChainID, msg.Sequences, msg.Msg)
|
||||
}
|
||||
|
||||
func StdSignBytes(chainID string, sequences []int64, msg Msg) []byte {
|
||||
// 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 {
|
||||
@@ -129,7 +127,22 @@ func StdSignBytes(chainID string, sequences []int64, msg Msg) []byte {
|
||||
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
|
||||
}
|
||||
|
||||
func (msg StdSignMsg) Bytes() []byte {
|
||||
return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg)
|
||||
}
|
||||
|
||||
//__________________________________________________________
|
||||
|
||||
// Application function variable used to unmarshal transaction bytes
|
||||
type TxDecoder func(txBytes []byte) (Tx, Error)
|
||||
|
||||
+50
-37
@@ -1,8 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
@@ -40,44 +40,61 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler {
|
||||
true
|
||||
}
|
||||
|
||||
// Get the sign bytes (requires all sequence numbers)
|
||||
// Get the sign bytes (requires all sequence numbers and the fee)
|
||||
sequences := make([]int64, len(signerAddrs))
|
||||
for i := 0; i < len(signerAddrs); i++ {
|
||||
sequences[i] = sigs[i].Sequence
|
||||
}
|
||||
signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, msg)
|
||||
fee := stdTx.Fee
|
||||
signBytes := sdk.StdSignBytes(ctx.ChainID(), sequences, fee, msg)
|
||||
|
||||
// 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
|
||||
|
||||
signerAddr, sig := signerAddrs[i], sigs[i]
|
||||
signerAcc, res := processSig(ctx, accountMapper, signerAddr, sig,
|
||||
signBytes, isFeePayer, stdTx.Fee.Amount)
|
||||
|
||||
// check signature, return account with incremented nonce
|
||||
signerAcc, res := processSig(
|
||||
ctx, accountMapper,
|
||||
signerAddr, sig, signBytes,
|
||||
)
|
||||
if !res.IsOK() {
|
||||
return ctx, res, true
|
||||
}
|
||||
|
||||
// first sig pays the fees
|
||||
if i == 0 {
|
||||
signerAcc, res = deductFees(signerAcc, fee)
|
||||
if !res.IsOK() {
|
||||
return ctx, res, true
|
||||
}
|
||||
}
|
||||
|
||||
// Save the account.
|
||||
accountMapper.SetAccount(ctx, signerAcc)
|
||||
signerAccs[i] = signerAcc
|
||||
}
|
||||
|
||||
// cache the signer accounts in the context
|
||||
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.
|
||||
// deduct fee from fee payer.
|
||||
func processSig(ctx sdk.Context, am sdk.AccountMapper,
|
||||
addr sdk.Address, sig sdk.StdSignature, signBytes []byte,
|
||||
isFeePayer bool, feeAmount sdk.Coins) (acc sdk.Account, res sdk.Result) {
|
||||
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
|
||||
// Get the account.
|
||||
acc = am.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
return nil, sdk.ErrUnrecognizedAddress(addr).Result()
|
||||
return nil, sdk.ErrUnrecognizedAddress(addr.String()).Result()
|
||||
}
|
||||
|
||||
// Check and increment sequence number.
|
||||
@@ -89,23 +106,20 @@ func processSig(ctx sdk.Context, am sdk.AccountMapper,
|
||||
acc.SetSequence(seq + 1)
|
||||
|
||||
// If pubkey is not known for account,
|
||||
// set it from the StdSignature
|
||||
// set it from the StdSignature.
|
||||
pubKey := acc.GetPubKey()
|
||||
if pubKey.Empty() {
|
||||
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()
|
||||
}
|
||||
pubKey = sig.PubKey
|
||||
if pubKey.Empty() {
|
||||
return nil, sdk.ErrMissingPubKey(addr).Result()
|
||||
return nil, sdk.ErrInvalidPubKey("PubKey not found").Result()
|
||||
}
|
||||
if !bytes.Equal(pubKey.Address(), addr) {
|
||||
return nil, sdk.ErrInvalidPubKey(
|
||||
fmt.Sprintf("PubKey does not match Signer address %v", addr)).Result()
|
||||
}
|
||||
err := acc.SetPubKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrInternal("setting PubKey on signer").Result()
|
||||
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
|
||||
}
|
||||
}
|
||||
// Check sig.
|
||||
@@ -113,19 +127,18 @@ func processSig(ctx sdk.Context, am sdk.AccountMapper,
|
||||
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||
}
|
||||
|
||||
// If this is the fee payer, deduct the fee.
|
||||
if isFeePayer {
|
||||
coins := acc.GetCoins()
|
||||
newCoins := coins.Minus(feeAmount)
|
||||
if !newCoins.IsNotNegative() {
|
||||
errMsg := fmt.Sprintf("%s < %s", coins, feeAmount)
|
||||
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
||||
}
|
||||
|
||||
acc.SetCoins(newCoins)
|
||||
}
|
||||
|
||||
// Save the account.
|
||||
am.SetAccount(ctx, acc)
|
||||
return
|
||||
}
|
||||
|
||||
// deduct the fee from the account
|
||||
func deductFees(acc sdk.Account, fee sdk.StdFee) (sdk.Account, sdk.Result) {
|
||||
coins := acc.GetCoins()
|
||||
feeAmount := fee.Amount
|
||||
newCoins := coins.Minus(feeAmount)
|
||||
if !newCoins.IsNotNegative() {
|
||||
errMsg := fmt.Sprintf("%s < %s", coins, feeAmount)
|
||||
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
||||
}
|
||||
acc.SetCoins(newCoins)
|
||||
return acc, sdk.Result{}
|
||||
}
|
||||
|
||||
+93
-41
@@ -1,38 +1,54 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
// msg type for testing
|
||||
type testMsg struct {
|
||||
signBytes []byte
|
||||
signers []sdk.Address
|
||||
signers []sdk.Address
|
||||
}
|
||||
|
||||
func newTestMsg(addrs ...sdk.Address) *testMsg {
|
||||
return &testMsg{
|
||||
signBytes: []byte(addrs[0]),
|
||||
signers: addrs,
|
||||
signers: addrs,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *testMsg) Type() string { return "testMsg" }
|
||||
func (msg *testMsg) Get(key interface{}) (value interface{}) { return nil }
|
||||
func (msg *testMsg) GetSignBytes() []byte {
|
||||
return msg.signBytes
|
||||
bz, err := json.Marshal(msg.signers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
}
|
||||
func (msg *testMsg) ValidateBasic() sdk.Error { return nil }
|
||||
func (msg *testMsg) GetSigners() []sdk.Address {
|
||||
return msg.signers
|
||||
}
|
||||
|
||||
func newStdFee() sdk.StdFee {
|
||||
return sdk.NewStdFee(100,
|
||||
sdk.Coin{"atom", 150},
|
||||
)
|
||||
}
|
||||
|
||||
// coins to more than cover the fee
|
||||
func newCoins() sdk.Coins {
|
||||
return sdk.Coins{
|
||||
{"atom", 10000000},
|
||||
}
|
||||
}
|
||||
|
||||
// generate a priv key and return it with its address
|
||||
func privAndAddr() (crypto.PrivKey, sdk.Address) {
|
||||
priv := crypto.GenPrivKeyEd25519()
|
||||
@@ -55,18 +71,17 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
|
||||
assert.Equal(t, code, result.Code)
|
||||
}
|
||||
|
||||
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, feeAmount int64) sdk.Tx {
|
||||
signBytes := sdk.StdSignBytes(ctx.ChainID(), seqs, msg)
|
||||
return newTestTxWithSignBytes(msg, privs, seqs, signBytes)
|
||||
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee) sdk.Tx {
|
||||
signBytes := sdk.StdSignBytes(ctx.ChainID(), seqs, fee, msg)
|
||||
return newTestTxWithSignBytes(msg, privs, seqs, fee, signBytes)
|
||||
}
|
||||
|
||||
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, signBytes []byte) sdk.Tx {
|
||||
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee, signBytes []byte) sdk.Tx {
|
||||
sigs := make([]sdk.StdSignature, len(privs))
|
||||
for i, priv := range privs {
|
||||
sigs[i] = sdk.StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), Sequence: seqs[i]}
|
||||
}
|
||||
tx := sdk.NewStdTx(msg, sigs)
|
||||
tx.SetFee(sdk.StdFee{Gas: 0, Amount: sdk.Coins{sdk.Coin{Amount: feeAmount, Denom: "atom"}}})
|
||||
tx := sdk.NewStdTx(msg, fee, sigs)
|
||||
return tx
|
||||
}
|
||||
|
||||
@@ -85,21 +100,26 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
||||
// msg and signatures
|
||||
var tx sdk.Tx
|
||||
msg := newTestMsg(addr1, addr2)
|
||||
fee := newStdFee()
|
||||
|
||||
// test no signatures
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{}, []int64{}, int64(0))
|
||||
privs, seqs := []crypto.PrivKey{}, []int64{}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
|
||||
// test num sigs dont match GetSigners
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0}, int64(0))
|
||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
|
||||
// test an unrecognized account
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1, priv2}, []int64{0, 0}, int64(0))
|
||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnrecognizedAddress)
|
||||
|
||||
// save the first account, but second is still unrecognized
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(fee.Amount)
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnrecognizedAddress)
|
||||
}
|
||||
@@ -118,28 +138,34 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||
|
||||
// set the accounts
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc2)
|
||||
|
||||
// msg and signatures
|
||||
var tx sdk.Tx
|
||||
msg := newTestMsg(addr1)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0}, int64(0))
|
||||
fee := newStdFee()
|
||||
|
||||
// test good tx from one signer
|
||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
// test sending it again fails (replay protection)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||
|
||||
// fix sequence, should pass
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{1}, int64(0))
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
// new tx with another signer and correct sequences
|
||||
msg = newTestMsg(addr1, addr2)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1, priv2}, []int64{2, 0}, int64(0))
|
||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{2, 0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
// replay fails
|
||||
@@ -147,16 +173,18 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||
|
||||
// tx from just second signer with incorrect sequence fails
|
||||
msg = newTestMsg(addr2)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{0}, int64(0))
|
||||
privs, seqs = []crypto.PrivKey{priv2}, []int64{0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||
|
||||
// fix the sequence and it passes
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, int64(0))
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
// another tx from both of them that passes
|
||||
msg = newTestMsg(addr1, addr2)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1, priv2}, []int64{3, 2}, int64(0))
|
||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{3, 2}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
}
|
||||
|
||||
@@ -199,35 +227,55 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||
|
||||
// set the accounts
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc2)
|
||||
|
||||
var tx sdk.Tx
|
||||
msg := newTestMsg(addr1)
|
||||
fee := newStdFee()
|
||||
|
||||
// test good tx and signBytes
|
||||
msg := newTestMsg(addr1)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
// test invalid chain_id
|
||||
tx = newTestTxWithSignBytes(msg, []crypto.PrivKey{priv1}, []int64{1}, sdk.StdSignBytes("", []int64{1}, msg))
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
// test wrong seqs
|
||||
tx = newTestTxWithSignBytes(msg, []crypto.PrivKey{priv1}, []int64{1}, sdk.StdSignBytes(ctx.ChainID(), []int64{2}, msg))
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
// test wrong msg
|
||||
tx = newTestTxWithSignBytes(msg, []crypto.PrivKey{priv1}, []int64{1}, sdk.StdSignBytes(ctx.ChainID(), []int64{1}, newTestMsg(addr2)))
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
chainID := ctx.ChainID()
|
||||
codeUnauth := sdk.CodeUnauthorized
|
||||
|
||||
cases := []struct {
|
||||
chainID string
|
||||
seqs []int64
|
||||
fee sdk.StdFee
|
||||
msg sdk.Msg
|
||||
code sdk.CodeType
|
||||
}{
|
||||
{"", []int64{1}, fee, msg, codeUnauth}, // test invalid chain_id
|
||||
{chainID, []int64{2}, fee, msg, codeUnauth}, // test wrong seqs
|
||||
{chainID, []int64{1}, fee, newTestMsg(addr2), codeUnauth}, // test wrong msg
|
||||
}
|
||||
|
||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{1}
|
||||
for _, cs := range cases {
|
||||
tx := newTestTxWithSignBytes(
|
||||
msg, privs, seqs, fee,
|
||||
sdk.StdSignBytes(cs.chainID, cs.seqs, cs.fee, cs.msg),
|
||||
)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, cs.code)
|
||||
}
|
||||
|
||||
// test wrong signer if public key exist
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1})
|
||||
privs, seqs = []crypto.PrivKey{priv2}, []int64{1}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||
|
||||
// test wrong signer if public doesn't exist
|
||||
msg = newTestMsg(addr2)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInternal)
|
||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||
|
||||
}
|
||||
|
||||
@@ -244,33 +292,37 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||
|
||||
// set the accounts
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc2)
|
||||
|
||||
var tx sdk.Tx
|
||||
|
||||
// test good tx and set public key
|
||||
msg := newTestMsg(addr1)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
||||
fee := newStdFee()
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx)
|
||||
|
||||
acc1 = mapper.GetAccount(ctx, addr1)
|
||||
reflect.DeepEqual(acc1.GetPubKey(), priv1.PubKey())
|
||||
require.Equal(t, acc1.GetPubKey(), priv1.PubKey())
|
||||
|
||||
// test public key not found
|
||||
msg = newTestMsg(addr2)
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
sigs := tx.GetSignatures()
|
||||
sigs[0].PubKey = crypto.PubKey{}
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInternal)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||
|
||||
acc2 = mapper.GetAccount(ctx, addr2)
|
||||
assert.True(t, acc2.GetPubKey().Empty())
|
||||
|
||||
// test invalid signature and public key
|
||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInternal)
|
||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||
|
||||
acc2 = mapper.GetAccount(ctx, addr2)
|
||||
assert.True(t, acc2.GetPubKey().Empty())
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ func NewCoinKeeper(am sdk.AccountMapper) CoinKeeper {
|
||||
func (ck CoinKeeper) SubtractCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Error) {
|
||||
acc := ck.am.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
return amt, sdk.ErrUnrecognizedAddress(addr)
|
||||
return amt, sdk.ErrUnrecognizedAddress(addr.String())
|
||||
}
|
||||
|
||||
coins := acc.GetCoins()
|
||||
|
||||
Reference in New Issue
Block a user