commit
d4c13b093c
|
@ -21,28 +21,16 @@ import (
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// helper variables and functions
|
// Construct some global addrs and txs for tests.
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Construct genesis key/accounts
|
|
||||||
priv1 = crypto.GenPrivKeyEd25519()
|
priv1 = crypto.GenPrivKeyEd25519()
|
||||||
addr1 = priv1.PubKey().Address()
|
addr1 = priv1.PubKey().Address()
|
||||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||||
|
coins = sdk.Coins{{"foocoin", 10}}
|
||||||
|
|
||||||
sendMsg = bank.SendMsg{
|
sendMsg = bank.SendMsg{
|
||||||
Inputs: []bank.Input{
|
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||||
{
|
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
||||||
Address: addr1,
|
|
||||||
Coins: sdk.Coins{{"foocoin", 10}},
|
|
||||||
Sequence: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: sdk.Coins{{"foocoin", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
whatCoolMsg1 = cool.WhatCoolMsg{
|
whatCoolMsg1 = cool.WhatCoolMsg{
|
||||||
|
@ -80,8 +68,10 @@ func TestMsgs(t *testing.T) {
|
||||||
{setWhatCoolMsg},
|
{setWhatCoolMsg},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chainID := ""
|
||||||
|
sequences := []int64{0}
|
||||||
for i, m := range msgs {
|
for i, m := range msgs {
|
||||||
sig := priv1.Sign(m.msg.GetSignBytes())
|
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, m.msg))
|
||||||
tx := sdk.NewStdTx(m.msg, []sdk.StdSignature{{
|
tx := sdk.NewStdTx(m.msg, []sdk.StdSignature{{
|
||||||
PubKey: priv1.PubKey(),
|
PubKey: priv1.PubKey(),
|
||||||
Signature: sig,
|
Signature: sig,
|
||||||
|
@ -178,9 +168,12 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
||||||
assert.Equal(t, acc1, res1)
|
assert.Equal(t, acc1, res1)
|
||||||
|
|
||||||
// Sign the tx
|
// Sign the tx
|
||||||
|
chainID := "" // TODO: InitChain should get the ChainID
|
||||||
|
sequences := []int64{0}
|
||||||
|
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, sendMsg))
|
||||||
tx := sdk.NewStdTx(sendMsg, []sdk.StdSignature{{
|
tx := sdk.NewStdTx(sendMsg, []sdk.StdSignature{{
|
||||||
PubKey: priv1.PubKey(),
|
PubKey: priv1.PubKey(),
|
||||||
Signature: priv1.Sign(sendMsg.GetSignBytes()),
|
Signature: sig,
|
||||||
}})
|
}})
|
||||||
|
|
||||||
// Run a Check
|
// Run a Check
|
||||||
|
@ -198,6 +191,22 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
||||||
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
||||||
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
||||||
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
||||||
|
|
||||||
|
// Delivering again should cause replay error
|
||||||
|
res = bapp.Deliver(tx)
|
||||||
|
assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log)
|
||||||
|
|
||||||
|
// bumping the txnonce number without resigning should be an auth error
|
||||||
|
tx.Signatures[0].Sequence = 1
|
||||||
|
res = bapp.Deliver(tx)
|
||||||
|
assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log)
|
||||||
|
|
||||||
|
// resigning the tx with the bumped sequence should work
|
||||||
|
sequences = []int64{1}
|
||||||
|
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, tx.Msg))
|
||||||
|
tx.Signatures[0].Signature = sig
|
||||||
|
res = bapp.Deliver(tx)
|
||||||
|
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||||
}
|
}
|
||||||
|
|
||||||
//func TestWhatCoolMsg(t *testing.T) {
|
//func TestWhatCoolMsg(t *testing.T) {
|
||||||
|
|
|
@ -22,12 +22,11 @@ const (
|
||||||
CodeOK CodeType = 0
|
CodeOK CodeType = 0
|
||||||
CodeInternal CodeType = 1
|
CodeInternal CodeType = 1
|
||||||
CodeTxParse CodeType = 2
|
CodeTxParse CodeType = 2
|
||||||
CodeBadNonce CodeType = 3
|
CodeInvalidSequence CodeType = 3
|
||||||
CodeUnauthorized CodeType = 4
|
CodeUnauthorized CodeType = 4
|
||||||
CodeInsufficientFunds CodeType = 5
|
CodeInsufficientFunds CodeType = 5
|
||||||
CodeUnknownRequest CodeType = 6
|
CodeUnknownRequest CodeType = 6
|
||||||
CodeUnrecognizedAddress CodeType = 7
|
CodeUnrecognizedAddress CodeType = 7
|
||||||
CodeInvalidSequence CodeType = 8
|
|
||||||
|
|
||||||
CodeGenesisParse CodeType = 0xdead // TODO: remove ?
|
CodeGenesisParse CodeType = 0xdead // TODO: remove ?
|
||||||
)
|
)
|
||||||
|
@ -41,8 +40,8 @@ func CodeToDefaultMsg(code CodeType) string {
|
||||||
return "Tx parse error"
|
return "Tx parse error"
|
||||||
case CodeGenesisParse:
|
case CodeGenesisParse:
|
||||||
return "Genesis parse error"
|
return "Genesis parse error"
|
||||||
case CodeBadNonce:
|
case CodeInvalidSequence:
|
||||||
return "Bad nonce"
|
return "Invalid sequence"
|
||||||
case CodeUnauthorized:
|
case CodeUnauthorized:
|
||||||
return "Unauthorized"
|
return "Unauthorized"
|
||||||
case CodeInsufficientFunds:
|
case CodeInsufficientFunds:
|
||||||
|
@ -51,8 +50,6 @@ func CodeToDefaultMsg(code CodeType) string {
|
||||||
return "Unknown request"
|
return "Unknown request"
|
||||||
case CodeUnrecognizedAddress:
|
case CodeUnrecognizedAddress:
|
||||||
return "Unrecognized address"
|
return "Unrecognized address"
|
||||||
case CodeInvalidSequence:
|
|
||||||
return "Invalid sequence"
|
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("Unknown code %d", code)
|
return fmt.Sprintf("Unknown code %d", code)
|
||||||
}
|
}
|
||||||
|
@ -72,8 +69,8 @@ func ErrTxParse(msg string) Error {
|
||||||
func ErrGenesisParse(msg string) Error {
|
func ErrGenesisParse(msg string) Error {
|
||||||
return newError(CodeGenesisParse, msg)
|
return newError(CodeGenesisParse, msg)
|
||||||
}
|
}
|
||||||
func ErrBadNonce(msg string) Error {
|
func ErrInvalidSequence(msg string) Error {
|
||||||
return newError(CodeBadNonce, msg)
|
return newError(CodeInvalidSequence, msg)
|
||||||
}
|
}
|
||||||
func ErrUnauthorized(msg string) Error {
|
func ErrUnauthorized(msg string) Error {
|
||||||
return newError(CodeUnauthorized, msg)
|
return newError(CodeUnauthorized, msg)
|
||||||
|
@ -87,9 +84,6 @@ func ErrUnknownRequest(msg string) Error {
|
||||||
func ErrUnrecognizedAddress(addr Address) Error {
|
func ErrUnrecognizedAddress(addr Address) Error {
|
||||||
return newError(CodeUnrecognizedAddress, addr.String())
|
return newError(CodeUnrecognizedAddress, addr.String())
|
||||||
}
|
}
|
||||||
func ErrInvalidSequence(msg string) Error {
|
|
||||||
return newError(CodeInvalidSequence, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// Error & sdkError
|
// Error & sdkError
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
// Transactions messages must fulfill the Msg
|
// Transactions messages must fulfill the Msg
|
||||||
type Msg interface {
|
type Msg interface {
|
||||||
|
|
||||||
|
@ -66,7 +68,31 @@ func (tx StdTx) GetMsg() Msg { return tx.Msg }
|
||||||
func (tx StdTx) GetFeePayer() Address { return tx.Signatures[0].PubKey.Address() } // XXX but PubKey is optional!
|
func (tx StdTx) GetFeePayer() Address { return tx.Signatures[0].PubKey.Address() } // XXX but PubKey is optional!
|
||||||
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }
|
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }
|
||||||
|
|
||||||
//__________________________________________________________
|
// StdSignDoc is replay-prevention structure.
|
||||||
|
// It includes the result of msg.GetSignBytes(),
|
||||||
|
// as well as the ChainID (prevent cross chain replay)
|
||||||
|
// and the Sequence numbers for each signature (prevent
|
||||||
|
// inchain replay and enforce tx ordering per account).
|
||||||
|
type StdSignDoc struct {
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
Sequences []int64 `json:"sequences"`
|
||||||
|
MsgBytes []byte `json:"msg_bytes"`
|
||||||
|
AltBytes []byte `json:"alt_bytes"` // TODO: do we really want this ?
|
||||||
|
}
|
||||||
|
|
||||||
|
func StdSignBytes(chainID string, sequences []int64, msg Msg) []byte {
|
||||||
|
bz, err := json.Marshal(StdSignDoc{
|
||||||
|
ChainID: chainID,
|
||||||
|
Sequences: sequences,
|
||||||
|
MsgBytes: msg.GetSignBytes(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bz
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
// Application function variable used to unmarshal transaction bytes
|
// Application function variable used to unmarshal transaction bytes
|
||||||
type TxDecoder func(txBytes []byte) (Tx, Error)
|
type TxDecoder func(txBytes []byte) (Tx, Error)
|
||||||
|
|
130
x/auth/ante.go
130
x/auth/ante.go
|
@ -1,6 +1,8 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,82 +11,98 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler {
|
||||||
ctx sdk.Context, tx sdk.Tx,
|
ctx sdk.Context, tx sdk.Tx,
|
||||||
) (_ sdk.Context, _ sdk.Result, abort bool) {
|
) (_ sdk.Context, _ sdk.Result, abort bool) {
|
||||||
|
|
||||||
// Deduct the fee from the fee payer.
|
|
||||||
// This is done first because it only
|
|
||||||
// requires fetching 1 account.
|
|
||||||
payerAddr := tx.GetFeePayer()
|
|
||||||
if payerAddr != nil {
|
|
||||||
payerAcc := accountMapper.GetAccount(ctx, payerAddr)
|
|
||||||
if payerAcc == nil {
|
|
||||||
return ctx,
|
|
||||||
sdk.ErrUnrecognizedAddress(payerAddr).Result(),
|
|
||||||
true
|
|
||||||
}
|
|
||||||
// TODO: Charge fee from payerAcc.
|
|
||||||
// TODO: accountMapper.SetAccount(ctx, payerAddr)
|
|
||||||
} else {
|
|
||||||
// TODO: Ensure that some other spam prevention is used.
|
|
||||||
}
|
|
||||||
|
|
||||||
var sigs = tx.GetSignatures()
|
|
||||||
|
|
||||||
// Assert that there are signatures.
|
// Assert that there are signatures.
|
||||||
|
var sigs = tx.GetSignatures()
|
||||||
if len(sigs) == 0 {
|
if len(sigs) == 0 {
|
||||||
return ctx,
|
return ctx,
|
||||||
sdk.ErrUnauthorized("no signers").Result(),
|
sdk.ErrUnauthorized("no signers").Result(),
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that sigs are correct.
|
// TODO: can tx just implement message?
|
||||||
var msg = tx.GetMsg()
|
msg := tx.GetMsg()
|
||||||
var signerAddrs = msg.GetSigners()
|
|
||||||
var signerAccs = make([]sdk.Account, len(signerAddrs))
|
|
||||||
|
|
||||||
// Assert that number of signatures is correct.
|
// Assert that number of signatures is correct.
|
||||||
|
var signerAddrs = msg.GetSigners()
|
||||||
if len(sigs) != len(signerAddrs) {
|
if len(sigs) != len(signerAddrs) {
|
||||||
return ctx,
|
return ctx,
|
||||||
sdk.ErrUnauthorized("wrong number of signers").Result(),
|
sdk.ErrUnauthorized("wrong number of signers").Result(),
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each nonce and sig.
|
// Collect accounts to set in the context
|
||||||
// TODO Refactor out.
|
var signerAccs = make([]sdk.Account, len(signerAddrs))
|
||||||
for i, sig := range sigs {
|
|
||||||
|
|
||||||
var signerAcc = accountMapper.GetAccount(ctx, signerAddrs[i])
|
// 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)
|
||||||
|
|
||||||
|
// 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 for the rest.
|
||||||
|
for i := 1; i < len(sigs); i++ {
|
||||||
|
signerAddr, sig := signerAddrs[i], sigs[i]
|
||||||
|
signerAcc, res := processSig(ctx, accountMapper, signerAddr, sig, signBytes)
|
||||||
|
if !res.IsOK() {
|
||||||
|
return ctx, res, true
|
||||||
|
}
|
||||||
signerAccs[i] = signerAcc
|
signerAccs[i] = signerAcc
|
||||||
|
|
||||||
// If no pubkey, set pubkey.
|
|
||||||
if signerAcc.GetPubKey().Empty() {
|
|
||||||
err := signerAcc.SetPubKey(sig.PubKey)
|
|
||||||
if err != nil {
|
|
||||||
return ctx,
|
|
||||||
sdk.ErrInternal("setting PubKey on signer").Result(),
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and increment sequence number.
|
|
||||||
seq := signerAcc.GetSequence()
|
|
||||||
if seq != sig.Sequence {
|
|
||||||
return ctx,
|
|
||||||
sdk.ErrInvalidSequence("").Result(),
|
|
||||||
true
|
|
||||||
}
|
|
||||||
signerAcc.SetSequence(seq + 1)
|
|
||||||
|
|
||||||
// Check sig.
|
|
||||||
if !sig.PubKey.VerifyBytes(msg.GetSignBytes(), sig.Signature) {
|
|
||||||
return ctx,
|
|
||||||
sdk.ErrUnauthorized("").Result(),
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the account.
|
|
||||||
accountMapper.SetAccount(ctx, signerAcc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = WithSigners(ctx, signerAccs)
|
ctx = WithSigners(ctx, signerAccs)
|
||||||
return ctx, sdk.Result{}, false // continue...
|
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) {
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return nil, sdk.ErrInvalidSequence(
|
||||||
|
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result()
|
||||||
|
}
|
||||||
|
acc.SetSequence(seq + 1)
|
||||||
|
|
||||||
|
// Check and possibly set pubkey.
|
||||||
|
pubKey := acc.GetPubKey()
|
||||||
|
if pubKey.Empty() {
|
||||||
|
pubKey = sig.PubKey
|
||||||
|
err := acc.SetPubKey(pubKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, sdk.ErrInternal("setting PubKey on signer").Result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: should we enforce pubKey == sig.PubKey ?
|
||||||
|
// If not, ppl can send useless PubKeys after first tx
|
||||||
|
|
||||||
|
// Check sig.
|
||||||
|
if !sig.PubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||||
|
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the account.
|
||||||
|
am.SetAccount(ctx, acc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// msg type for testing
|
||||||
|
type testMsg struct {
|
||||||
|
signBytes []byte
|
||||||
|
signers []sdk.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestMsg(addrs ...sdk.Address) *testMsg {
|
||||||
|
return &testMsg{
|
||||||
|
signBytes: []byte("some sign bytes"),
|
||||||
|
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
|
||||||
|
}
|
||||||
|
func (msg *testMsg) ValidateBasic() sdk.Error { return nil }
|
||||||
|
func (msg *testMsg) GetSigners() []sdk.Address {
|
||||||
|
return msg.signers
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a priv key and return it with its address
|
||||||
|
func privAndAddr() (crypto.PrivKey, sdk.Address) {
|
||||||
|
priv := crypto.GenPrivKeyEd25519()
|
||||||
|
addr := priv.PubKey().Address()
|
||||||
|
return priv.Wrap(), addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the tx through the anteHandler and ensure its valid
|
||||||
|
func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx) {
|
||||||
|
_, result, abort := anteHandler(ctx, tx)
|
||||||
|
assert.False(t, abort)
|
||||||
|
assert.Equal(t, sdk.CodeOK, result.Code)
|
||||||
|
assert.True(t, result.IsOK())
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the tx through the anteHandler and ensure it fails with the given code
|
||||||
|
func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, code sdk.CodeType) {
|
||||||
|
_, result, abort := anteHandler(ctx, tx)
|
||||||
|
assert.True(t, abort)
|
||||||
|
assert.Equal(t, code, result.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64) sdk.Tx {
|
||||||
|
signBytes := sdk.StdSignBytes(ctx.ChainID(), seqs, msg)
|
||||||
|
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]}
|
||||||
|
}
|
||||||
|
return sdk.NewStdTx(msg, sigs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test various error cases in the AnteHandler control flow.
|
||||||
|
func TestAnteHandlerSigErrors(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
ms, capKey := setupMultiStore()
|
||||||
|
mapper := NewAccountMapper(capKey, &BaseAccount{})
|
||||||
|
anteHandler := NewAnteHandler(mapper)
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil)
|
||||||
|
|
||||||
|
// keys and addresses
|
||||||
|
priv1, addr1 := privAndAddr()
|
||||||
|
priv2, addr2 := privAndAddr()
|
||||||
|
|
||||||
|
// msg and signatures
|
||||||
|
var tx sdk.Tx
|
||||||
|
msg := newTestMsg(addr1, addr2)
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1, priv2}, []int64{0, 0})
|
||||||
|
|
||||||
|
// test no signatures
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{}, []int64{})
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
|
// test num sigs dont match GetSigners
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
|
// test an unrecognized account
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1, priv2}, []int64{0, 0})
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnrecognizedAddress)
|
||||||
|
|
||||||
|
// save the first account, but second is still unrecognized
|
||||||
|
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||||
|
mapper.SetAccount(ctx, acc1)
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnrecognizedAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test logic around sequence checking with one signer and many signers.
|
||||||
|
func TestAnteHandlerSequences(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
ms, capKey := setupMultiStore()
|
||||||
|
mapper := NewAccountMapper(capKey, &BaseAccount{})
|
||||||
|
anteHandler := NewAnteHandler(mapper)
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil)
|
||||||
|
|
||||||
|
// keys and addresses
|
||||||
|
priv1, addr1 := privAndAddr()
|
||||||
|
priv2, addr2 := privAndAddr()
|
||||||
|
|
||||||
|
// set the accounts
|
||||||
|
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||||
|
mapper.SetAccount(ctx, acc1)
|
||||||
|
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||||
|
mapper.SetAccount(ctx, acc2)
|
||||||
|
|
||||||
|
// msg and signatures
|
||||||
|
var tx sdk.Tx
|
||||||
|
msg := newTestMsg(addr1)
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv1}, []int64{0})
|
||||||
|
|
||||||
|
// test good tx from one signer
|
||||||
|
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})
|
||||||
|
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})
|
||||||
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
|
// replay fails
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
|
// tx from just second signer with incorrect sequence fails
|
||||||
|
msg = newTestMsg(addr2)
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{0})
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
|
// fix the sequence and it passes
|
||||||
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1})
|
||||||
|
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})
|
||||||
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
|
// TODO: test various cases of bad sign bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
|
// TODO: test cases where pubkey is already set on the account
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ import (
|
||||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ sdk.AccountMapper = (*accountMapper)(nil)
|
||||||
|
var _ sdk.AccountMapper = (*sealedAccountMapper)(nil)
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implements sdk.AccountMapper.
|
||||||
// This AccountMapper encodes/decodes accounts using the
|
// This AccountMapper encodes/decodes accounts using the
|
||||||
// go-wire (binary) encoding/decoding library.
|
// go-wire (binary) encoding/decoding library.
|
||||||
|
@ -108,6 +111,7 @@ func (sam sealedAccountMapper) WireCodec() *wire.Codec {
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// misc.
|
// misc.
|
||||||
|
|
||||||
|
// NOTE: currently unused
|
||||||
func (am accountMapper) clonePrototypePtr() interface{} {
|
func (am accountMapper) clonePrototypePtr() interface{} {
|
||||||
protoRt := reflect.TypeOf(am.proto)
|
protoRt := reflect.TypeOf(am.proto)
|
||||||
if protoRt.Kind() == reflect.Ptr {
|
if protoRt.Kind() == reflect.Ptr {
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
oldwire "github.com/tendermint/go-wire"
|
||||||
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
|
||||||
|
db := dbm.NewMemDB()
|
||||||
|
capKey := sdk.NewKVStoreKey("capkey")
|
||||||
|
ms := store.NewCommitMultiStore(db)
|
||||||
|
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.LoadLatestVersion()
|
||||||
|
|
||||||
|
// wire registration while we're at it ... TODO
|
||||||
|
var _ = oldwire.RegisterInterface(
|
||||||
|
struct{ sdk.Account }{},
|
||||||
|
oldwire.ConcreteType{&BaseAccount{}, 0x1},
|
||||||
|
)
|
||||||
|
|
||||||
|
return ms, capKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountMapperGetSet(t *testing.T) {
|
||||||
|
ms, capKey := setupMultiStore()
|
||||||
|
|
||||||
|
// make context and mapper
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||||
|
mapper := NewAccountMapper(capKey, &BaseAccount{})
|
||||||
|
|
||||||
|
addr := sdk.Address([]byte("some-address"))
|
||||||
|
|
||||||
|
// no account before its created
|
||||||
|
acc := mapper.GetAccount(ctx, addr)
|
||||||
|
assert.Nil(t, acc)
|
||||||
|
|
||||||
|
// create account and check default values
|
||||||
|
acc = mapper.NewAccountWithAddress(ctx, addr)
|
||||||
|
assert.NotNil(t, acc)
|
||||||
|
assert.Equal(t, addr, acc.GetAddress())
|
||||||
|
assert.EqualValues(t, crypto.PubKey{}, acc.GetPubKey())
|
||||||
|
assert.EqualValues(t, 0, acc.GetSequence())
|
||||||
|
|
||||||
|
// NewAccount doesn't call Set, so it's still nil
|
||||||
|
assert.Nil(t, mapper.GetAccount(ctx, addr))
|
||||||
|
|
||||||
|
// set some values on the account and save it
|
||||||
|
newSequence := int64(20)
|
||||||
|
acc.SetSequence(newSequence)
|
||||||
|
mapper.SetAccount(ctx, acc)
|
||||||
|
|
||||||
|
// check the new values
|
||||||
|
acc = mapper.GetAccount(ctx, addr)
|
||||||
|
assert.NotNil(t, acc)
|
||||||
|
assert.Equal(t, newSequence, acc.GetSequence())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountMapperSealed(t *testing.T) {
|
||||||
|
_, capKey := setupMultiStore()
|
||||||
|
|
||||||
|
// normal mapper exposes the wire codec
|
||||||
|
mapper := NewAccountMapper(capKey, &BaseAccount{})
|
||||||
|
assert.NotNil(t, mapper.WireCodec())
|
||||||
|
|
||||||
|
// seal mapper, should panic when we try to get the codec
|
||||||
|
mapperSealed := mapper.Seal()
|
||||||
|
assert.Panics(t, func() { mapperSealed.WireCodec() })
|
||||||
|
|
||||||
|
// another way to get a sealed mapper
|
||||||
|
mapperSealed = NewAccountMapperSealed(capKey, &BaseAccount{})
|
||||||
|
assert.Panics(t, func() { mapperSealed.WireCodec() })
|
||||||
|
}
|
19
x/bank/tx.go
19
x/bank/tx.go
|
@ -4,8 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -142,11 +140,8 @@ func (msg IssueMsg) GetSigners() []sdk.Address {
|
||||||
|
|
||||||
// Transaction Output
|
// Transaction Output
|
||||||
type Input struct {
|
type Input struct {
|
||||||
Address sdk.Address `json:"address"`
|
Address sdk.Address `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
Sequence int64 `json:"sequence"`
|
|
||||||
|
|
||||||
signature crypto.Signature
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateBasic - validate transaction input
|
// ValidateBasic - validate transaction input
|
||||||
|
@ -154,9 +149,6 @@ func (in Input) ValidateBasic() sdk.Error {
|
||||||
if len(in.Address) == 0 {
|
if len(in.Address) == 0 {
|
||||||
return ErrInvalidAddress(in.Address.String())
|
return ErrInvalidAddress(in.Address.String())
|
||||||
}
|
}
|
||||||
if in.Sequence < 0 {
|
|
||||||
return ErrInvalidSequence("negative sequence")
|
|
||||||
}
|
|
||||||
if !in.Coins.IsValid() {
|
if !in.Coins.IsValid() {
|
||||||
return ErrInvalidCoins(in.Coins.String())
|
return ErrInvalidCoins(in.Coins.String())
|
||||||
}
|
}
|
||||||
|
@ -179,13 +171,6 @@ func NewInput(addr sdk.Address, coins sdk.Coins) Input {
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputWithSequence - create a transaction input, used with SendMsg
|
|
||||||
func NewInputWithSequence(addr sdk.Address, coins sdk.Coins, seq int64) Input {
|
|
||||||
input := NewInput(addr, coins)
|
|
||||||
input.Sequence = seq
|
|
||||||
return input
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// Output
|
// Output
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,12 @@ func TestNewSendMsg(t *testing.T) {}
|
||||||
|
|
||||||
func TestSendMsgType(t *testing.T) {
|
func TestSendMsgType(t *testing.T) {
|
||||||
// Construct a SendMsg
|
// Construct a SendMsg
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
addr2 := sdk.Address([]byte("output"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = SendMsg{
|
var msg = SendMsg{
|
||||||
Inputs: []Input{
|
Inputs: []Input{NewInput(addr1, coins)},
|
||||||
{
|
Outputs: []Output{NewOutput(addr2, coins)},
|
||||||
Address: sdk.Address([]byte("input")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
Sequence: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []Output{
|
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("output")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO some failures for bad result
|
// TODO some failures for bad result
|
||||||
|
@ -53,18 +45,16 @@ func TestInputValidation(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
// auth works with different apps
|
// auth works with different apps
|
||||||
{true, NewInput(addr1, someCoins)},
|
{true, NewInput(addr1, someCoins)},
|
||||||
{true, NewInputWithSequence(addr1, someCoins, 100)},
|
{true, NewInput(addr2, someCoins)},
|
||||||
{true, NewInputWithSequence(addr2, someCoins, 100)},
|
{true, NewInput(addr2, multiCoins)},
|
||||||
{true, NewInputWithSequence(addr2, multiCoins, 100)},
|
|
||||||
|
|
||||||
{false, NewInput(emptyAddr, someCoins)}, // empty address
|
{false, NewInput(emptyAddr, someCoins)}, // empty address
|
||||||
{false, NewInputWithSequence(addr1, someCoins, -1)}, // negative sequence
|
{false, NewInput(addr1, emptyCoins)}, // invalid coins
|
||||||
{false, NewInput(addr1, emptyCoins)}, // invalid coins
|
{false, NewInput(addr1, emptyCoins2)}, // invalid coins
|
||||||
{false, NewInput(addr1, emptyCoins2)}, // invalid coins
|
{false, NewInput(addr1, someEmptyCoins)}, // invalid coins
|
||||||
{false, NewInput(addr1, someEmptyCoins)}, // invalid coins
|
{false, NewInput(addr1, minusCoins)}, // negative coins
|
||||||
{false, NewInput(addr1, minusCoins)}, // negative coins
|
{false, NewInput(addr1, someMinusCoins)}, // negative coins
|
||||||
{false, NewInput(addr1, someMinusCoins)}, // negative coins
|
{false, NewInput(addr1, unsortedCoins)}, // unsorted coins
|
||||||
{false, NewInput(addr1, unsortedCoins)}, // unsorted coins
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
@ -144,7 +134,7 @@ func TestSendMsgValidation(t *testing.T) {
|
||||||
{false, SendMsg{Inputs: []Input{input1}}}, // just input
|
{false, SendMsg{Inputs: []Input{input1}}}, // just input
|
||||||
{false, SendMsg{Outputs: []Output{output1}}}, // just ouput
|
{false, SendMsg{Outputs: []Output{output1}}}, // just ouput
|
||||||
{false, SendMsg{
|
{false, SendMsg{
|
||||||
Inputs: []Input{NewInputWithSequence(emptyAddr, atom123, 1)}, // invalid input
|
Inputs: []Input{NewInput(emptyAddr, atom123)}, // invalid input
|
||||||
Outputs: []Output{output1}}},
|
Outputs: []Output{output1}}},
|
||||||
{false, SendMsg{
|
{false, SendMsg{
|
||||||
Inputs: []Input{input1},
|
Inputs: []Input{input1},
|
||||||
|
@ -189,82 +179,54 @@ func TestSendMsgValidation(t *testing.T) {
|
||||||
|
|
||||||
func TestSendMsgString(t *testing.T) {
|
func TestSendMsgString(t *testing.T) {
|
||||||
// Construct a SendMsg
|
// Construct a SendMsg
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
addr2 := sdk.Address([]byte("output"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = SendMsg{
|
var msg = SendMsg{
|
||||||
Inputs: []Input{
|
Inputs: []Input{NewInput(addr1, coins)},
|
||||||
{
|
Outputs: []Output{NewOutput(addr2, coins)},
|
||||||
Address: sdk.Address([]byte("input")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
Sequence: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []Output{
|
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("output")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res := msg.String()
|
res := msg.String()
|
||||||
// TODO some failures for bad results
|
// TODO some failures for bad results
|
||||||
assert.Equal(t, res, "SendMsg{[Input{696E707574,10atom}]->[Output{364637353734373037353734,10atom}]}")
|
assert.Equal(t, res, "SendMsg{[Input{696E707574,10atom}]->[Output{364637353734373037353734,10atom}]}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendMsgGet(t *testing.T) {
|
func TestSendMsgGet(t *testing.T) {
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
addr2 := sdk.Address([]byte("output"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = SendMsg{
|
var msg = SendMsg{
|
||||||
Inputs: []Input{
|
Inputs: []Input{NewInput(addr1, coins)},
|
||||||
{
|
Outputs: []Output{NewOutput(addr2, coins)},
|
||||||
Address: sdk.Address([]byte("input")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
Sequence: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []Output{
|
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("output")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
res := msg.Get(nil)
|
res := msg.Get(nil)
|
||||||
assert.Nil(t, res)
|
assert.Nil(t, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendMsgGetSignBytes(t *testing.T) {
|
func TestSendMsgGetSignBytes(t *testing.T) {
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
addr2 := sdk.Address([]byte("output"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = SendMsg{
|
var msg = SendMsg{
|
||||||
Inputs: []Input{
|
Inputs: []Input{NewInput(addr1, coins)},
|
||||||
{
|
Outputs: []Output{NewOutput(addr2, coins)},
|
||||||
Address: sdk.Address([]byte("input")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
Sequence: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []Output{
|
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("output")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
res := msg.GetSignBytes()
|
res := msg.GetSignBytes()
|
||||||
// TODO bad results
|
// TODO bad results
|
||||||
assert.Equal(t, string(res), `{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}],"sequence":1}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}`)
|
assert.Equal(t, string(res), `{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendMsgGetSigners(t *testing.T) {
|
func TestSendMsgGetSigners(t *testing.T) {
|
||||||
var msg = SendMsg{
|
var msg = SendMsg{
|
||||||
Inputs: []Input{
|
Inputs: []Input{
|
||||||
{
|
NewInput(sdk.Address([]byte("input1")), nil),
|
||||||
Address: sdk.Address([]byte("input1")),
|
NewInput(sdk.Address([]byte("input2")), nil),
|
||||||
},
|
NewInput(sdk.Address([]byte("input3")), nil),
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("input2")),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("input3")),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
res := msg.GetSigners()
|
res := msg.GetSigners()
|
||||||
|
// TODO: fix this !
|
||||||
assert.Equal(t, fmt.Sprintf("%v", res), "[696E70757431 696E70757432 696E70757433]")
|
assert.Equal(t, fmt.Sprintf("%v", res), "[696E70757431 696E70757432 696E70757433]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,14 +259,11 @@ func TestNewIssueMsg(t *testing.T) {
|
||||||
|
|
||||||
func TestIssueMsgType(t *testing.T) {
|
func TestIssueMsgType(t *testing.T) {
|
||||||
// Construct an IssueMsg
|
// Construct an IssueMsg
|
||||||
|
addr := sdk.Address([]byte("loan-from-bank"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = IssueMsg{
|
var msg = IssueMsg{
|
||||||
Banker: sdk.Address([]byte("input")),
|
Banker: sdk.Address([]byte("input")),
|
||||||
Outputs: []Output{
|
Outputs: []Output{NewOutput(addr, coins)},
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("loan-from-bank")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO some failures for bad result
|
// TODO some failures for bad result
|
||||||
|
@ -317,42 +276,34 @@ func TestIssueMsgValidation(t *testing.T) {
|
||||||
|
|
||||||
func TestIssueMsgString(t *testing.T) {
|
func TestIssueMsgString(t *testing.T) {
|
||||||
// Construct a IssueMsg
|
// Construct a IssueMsg
|
||||||
|
addr := sdk.Address([]byte("loan-from-bank"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = IssueMsg{
|
var msg = IssueMsg{
|
||||||
Banker: sdk.Address([]byte("input")),
|
Banker: sdk.Address([]byte("input")),
|
||||||
Outputs: []Output{
|
Outputs: []Output{NewOutput(addr, coins)},
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("loan-from-bank")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
res := msg.String()
|
res := msg.String()
|
||||||
|
// TODO: FIX THIS OUTPUT!
|
||||||
assert.Equal(t, res, "IssueMsg{696E707574#[Output{36433646363136453244363637323646364432443632363136453642,10atom}]}")
|
assert.Equal(t, res, "IssueMsg{696E707574#[Output{36433646363136453244363637323646364432443632363136453642,10atom}]}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueMsgGet(t *testing.T) {
|
func TestIssueMsgGet(t *testing.T) {
|
||||||
|
addr := sdk.Address([]byte("loan-from-bank"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = IssueMsg{
|
var msg = IssueMsg{
|
||||||
Banker: sdk.Address([]byte("input")),
|
Banker: sdk.Address([]byte("input")),
|
||||||
Outputs: []Output{
|
Outputs: []Output{NewOutput(addr, coins)},
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("loan-from-bank")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
res := msg.Get(nil)
|
res := msg.Get(nil)
|
||||||
assert.Nil(t, res)
|
assert.Nil(t, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssueMsgGetSignBytes(t *testing.T) {
|
func TestIssueMsgGetSignBytes(t *testing.T) {
|
||||||
|
addr := sdk.Address([]byte("loan-from-bank"))
|
||||||
|
coins := sdk.Coins{{"atom", 10}}
|
||||||
var msg = IssueMsg{
|
var msg = IssueMsg{
|
||||||
Banker: sdk.Address([]byte("input")),
|
Banker: sdk.Address([]byte("input")),
|
||||||
Outputs: []Output{
|
Outputs: []Output{NewOutput(addr, coins)},
|
||||||
{
|
|
||||||
Address: sdk.Address([]byte("loan-from-bank")),
|
|
||||||
Coins: sdk.Coins{{"atom", 10}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
res := msg.GetSignBytes()
|
res := msg.GetSignBytes()
|
||||||
// TODO bad results
|
// TODO bad results
|
||||||
|
|
Loading…
Reference in New Issue