Merge pull request #177 from tendermint/feature/104-autoseq

Auto Sequencing, Error Cleanup, Bash Tests Cleanup
This commit is contained in:
Ethan Frey 2017-07-19 12:36:18 +02:00 committed by GitHub
commit 29273e5656
52 changed files with 497 additions and 364 deletions

View File

@ -7,10 +7,12 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/basecoin/modules/coin"
eyescli "github.com/tendermint/merkleeyes/client" eyescli "github.com/tendermint/merkleeyes/client"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/basecoin/modules/coin"
) )
const genesisFilepath = "./testdata/genesis.json" const genesisFilepath = "./testdata/genesis.json"

View File

@ -15,19 +15,19 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers"
"github.com/tendermint/light-client/certifiers/files"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
"github.com/tendermint/light-client/certifiers"
"github.com/tendermint/light-client/certifiers/files"
) )
var ( var (
dirPerm = os.FileMode(0700) dirPerm = os.FileMode(0700)
) )
//nolint
const ( const (
SeedFlag = "seed" SeedFlag = "seed"
HashFlag = "valhash" HashFlag = "valhash"

View File

@ -8,12 +8,11 @@ import (
wire "github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
lc "github.com/tendermint/light-client"
"github.com/tendermint/light-client/proofs"
"github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/client"
lc "github.com/tendermint/light-client"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/light-client/proofs"
) )
// GetAndParseAppProof does most of the work of the query commands, but is quite // GetAndParseAppProof does most of the work of the query commands, but is quite

View File

@ -4,24 +4,25 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
"github.com/tendermint/light-client/proofs"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/light-client/proofs"
) )
var KeyCmd = &cobra.Command{ // KeyQueryCmd - CLI command to query a state by key with proof
var KeyQueryCmd = &cobra.Command{
Use: "key [key]", Use: "key [key]",
Short: "Handle proofs for state of abci app", Short: "Handle proofs for state of abci app",
Long: `This will look up a given key in the abci app, verify the proof, Long: `This will look up a given key in the abci app, verify the proof,
and output it as hex. and output it as hex.
If you want json output, use an app-specific command that knows key and value structure.`, If you want json output, use an app-specific command that knows key and value structure.`,
RunE: commands.RequireInit(doKeyQuery), RunE: commands.RequireInit(keyQueryCmd),
} }
// Note: we cannot yse GetAndParseAppProof here, as we don't use go-wire to // Note: we cannot yse GetAndParseAppProof here, as we don't use go-wire to
// parse the object, but rather return the raw bytes // parse the object, but rather return the raw bytes
func doKeyQuery(cmd *cobra.Command, args []string) error { func keyQueryCmd(cmd *cobra.Command, args []string) error {
// parse cli // parse cli
height := GetHeight() height := GetHeight()
key, err := ParseHexKey(args, "key") key, err := ParseHexKey(args, "key")

View File

@ -3,13 +3,16 @@ package proofs
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/light-client/proofs" "github.com/tendermint/light-client/proofs"
"github.com/tendermint/basecoin/client/commands"
) )
//nolint TODO add description
var TxPresenters = proofs.NewPresenters() var TxPresenters = proofs.NewPresenters()
var TxCmd = &cobra.Command{ // TxQueryCmd - CLI command to query a transaction with proof
var TxQueryCmd = &cobra.Command{
Use: "tx [txhash]", Use: "tx [txhash]",
Short: "Handle proofs of commited txs", Short: "Handle proofs of commited txs",
Long: `Proofs allows you to validate abci state with merkle proofs. Long: `Proofs allows you to validate abci state with merkle proofs.
@ -18,10 +21,10 @@ These proofs tie the data to a checkpoint, which is managed by "seeds".
Here we can validate these proofs and import/export them to prove specific Here we can validate these proofs and import/export them to prove specific
data to other peers as needed. data to other peers as needed.
`, `,
RunE: commands.RequireInit(doTxQuery), RunE: commands.RequireInit(txQueryCmd),
} }
func doTxQuery(cmd *cobra.Command, args []string) error { func txQueryCmd(cmd *cobra.Command, args []string) error {
// parse cli // parse cli
height := GetHeight() height := GetHeight()
bkey, err := ParseHexKey(args, "txhash") bkey, err := ParseHexKey(args, "txhash")

View File

@ -7,14 +7,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
cmn "github.com/tendermint/tmlibs/common" certclient "github.com/tendermint/light-client/certifiers/client"
"github.com/tendermint/tmlibs/log"
"github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/core" "github.com/tendermint/tendermint/rpc/core"
rpc "github.com/tendermint/tendermint/rpc/lib/server" rpc "github.com/tendermint/tendermint/rpc/lib/server"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
certclient "github.com/tendermint/light-client/certifiers/client"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -2,6 +2,7 @@ package rpc
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -6,9 +6,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
certclient "github.com/tendermint/light-client/certifiers/client"
"github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/client"
certclient "github.com/tendermint/light-client/certifiers/client"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -3,6 +3,7 @@ package rpc
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -4,6 +4,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -6,7 +6,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers" "github.com/tendermint/light-client/certifiers"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -7,7 +7,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/light-client/certifiers" "github.com/tendermint/light-client/certifiers"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -4,7 +4,9 @@ import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/tendermint/light-client/certifiers" "github.com/tendermint/light-client/certifiers"
"github.com/tendermint/basecoin/client/commands" "github.com/tendermint/basecoin/client/commands"
) )

View File

@ -2,6 +2,7 @@ package txs
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
wire "github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
"github.com/tendermint/light-client/proofs" "github.com/tendermint/light-client/proofs"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"

View File

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
) )

View File

@ -51,8 +51,8 @@ func main() {
// Prepare queries // Prepare queries
proofs.RootCmd.AddCommand( proofs.RootCmd.AddCommand(
// These are default parsers, but optional in your app (you can remove key) // These are default parsers, but optional in your app (you can remove key)
proofs.TxCmd, proofs.TxQueryCmd,
proofs.KeyCmd, proofs.KeyQueryCmd,
coincmd.AccountQueryCmd, coincmd.AccountQueryCmd,
noncecmd.NonceQueryCmd, noncecmd.NonceQueryCmd,
) )

View File

@ -8,8 +8,6 @@ import (
"path" "path"
"strings" "strings"
//"github.com/pkg/errors"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/go-crypto" "github.com/tendermint/go-crypto"

View File

@ -3,9 +3,10 @@ package main
import ( import (
"os" "os"
"github.com/tendermint/tmlibs/cli"
"github.com/tendermint/basecoin/app" "github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/cmd/basecoin/commands" "github.com/tendermint/basecoin/cmd/basecoin/commands"
"github.com/tendermint/tmlibs/cli"
) )
func main() { func main() {

View File

@ -39,8 +39,8 @@ func main() {
// Prepare queries // Prepare queries
proofs.RootCmd.AddCommand( proofs.RootCmd.AddCommand(
// These are default parsers, optional in your app // These are default parsers, optional in your app
proofs.TxCmd, proofs.TxQueryCmd,
proofs.KeyCmd, proofs.KeyQueryCmd,
coincmd.AccountQueryCmd, coincmd.AccountQueryCmd,
noncecmd.NonceQueryCmd, noncecmd.NonceQueryCmd,

View File

@ -5,27 +5,17 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/pkg/errors"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
) )
var ( var (
errDecoding = fmt.Errorf("Error decoding input") errDecoding = fmt.Errorf("Error decoding input")
errUnauthorized = fmt.Errorf("Unauthorized") errUnauthorized = fmt.Errorf("Unauthorized")
errInvalidSignature = fmt.Errorf("Invalid Signature")
errTooLarge = fmt.Errorf("Input size too large") errTooLarge = fmt.Errorf("Input size too large")
errNoSigners = fmt.Errorf("There are no signers")
errMissingSignature = fmt.Errorf("Signature missing") errMissingSignature = fmt.Errorf("Signature missing")
errTooManySignatures = fmt.Errorf("Too many signatures")
errNoChain = fmt.Errorf("No chain id provided")
errTxEmpty = fmt.Errorf("The provided Tx is empty")
errWrongChain = fmt.Errorf("Wrong chain for tx")
errUnknownTxType = fmt.Errorf("Tx type unknown") errUnknownTxType = fmt.Errorf("Tx type unknown")
errInvalidFormat = fmt.Errorf("Invalid format") errInvalidFormat = fmt.Errorf("Invalid format")
errUnknownModule = fmt.Errorf("Unknown module") errUnknownModule = fmt.Errorf("Unknown module")
errExpired = fmt.Errorf("Tx expired")
errUnknownKey = fmt.Errorf("Unknown key")
internalErr = abci.CodeType_InternalError internalErr = abci.CodeType_InternalError
encodingErr = abci.CodeType_EncodingError encodingErr = abci.CodeType_EncodingError
@ -70,14 +60,6 @@ func IsUnknownModuleErr(err error) bool {
return IsSameError(errUnknownModule, err) return IsSameError(errUnknownModule, err)
} }
func ErrUnknownKey(mod string) TMError {
w := errors.Wrap(errUnknownKey, mod)
return WithCode(w, abci.CodeType_UnknownRequest)
}
func IsUnknownKeyErr(err error) bool {
return IsSameError(errUnknownKey, err)
}
func ErrInternal(msg string) TMError { func ErrInternal(msg string) TMError {
return New(msg, internalErr) return New(msg, internalErr)
} }
@ -104,10 +86,6 @@ func IsUnauthorizedErr(err error) bool {
return HasErrorCode(err, unauthorized) return HasErrorCode(err, unauthorized)
} }
func ErrNoSigners() TMError {
return WithCode(errNoSigners, unauthorized)
}
func ErrMissingSignature() TMError { func ErrMissingSignature() TMError {
return WithCode(errMissingSignature, unauthorized) return WithCode(errMissingSignature, unauthorized)
} }
@ -115,49 +93,9 @@ func IsMissingSignatureErr(err error) bool {
return IsSameError(errMissingSignature, err) return IsSameError(errMissingSignature, err)
} }
func ErrTooManySignatures() TMError {
return WithCode(errTooManySignatures, unauthorized)
}
func IsTooManySignaturesErr(err error) bool {
return IsSameError(errTooManySignatures, err)
}
func ErrInvalidSignature() TMError {
return WithCode(errInvalidSignature, unauthorized)
}
func IsInvalidSignatureErr(err error) bool {
return IsSameError(errInvalidSignature, err)
}
func ErrNoChain() TMError {
return WithCode(errNoChain, unauthorized)
}
func IsNoChainErr(err error) bool {
return IsSameError(errNoChain, err)
}
func ErrTxEmpty() TMError {
return WithCode(errTxEmpty, unauthorized)
}
func ErrWrongChain(chain string) TMError {
msg := errors.Wrap(errWrongChain, chain)
return WithCode(msg, unauthorized)
}
func IsWrongChainErr(err error) bool {
return IsSameError(errWrongChain, err)
}
func ErrTooLarge() TMError { func ErrTooLarge() TMError {
return WithCode(errTooLarge, encodingErr) return WithCode(errTooLarge, encodingErr)
} }
func IsTooLargeErr(err error) bool { func IsTooLargeErr(err error) bool {
return IsSameError(errTooLarge, err) return IsSameError(errTooLarge, err)
} }
func ErrExpired() TMError {
return WithCode(errExpired, unauthorized)
}
func IsExpiredErr(err error) bool {
return IsSameError(errExpired, err)
}

View File

@ -42,7 +42,6 @@ func TestErrorMatches(t *testing.T) {
{errUnauthorized, ErrUnauthorized(), true}, {errUnauthorized, ErrUnauthorized(), true},
{errMissingSignature, ErrUnauthorized(), false}, {errMissingSignature, ErrUnauthorized(), false},
{errMissingSignature, ErrMissingSignature(), true}, {errMissingSignature, ErrMissingSignature(), true},
{errWrongChain, ErrWrongChain("hakz"), true},
{errUnknownTxType, ErrUnknownTxType(holder{}), true}, {errUnknownTxType, ErrUnknownTxType(holder{}), true},
{errUnknownTxType, ErrUnknownTxType("some text here..."), true}, {errUnknownTxType, ErrUnknownTxType("some text here..."), true},
{errUnknownTxType, ErrUnknownTxType(demoTx{5}.Wrap()), true}, {errUnknownTxType, ErrUnknownTxType(demoTx{5}.Wrap()), true},
@ -66,13 +65,6 @@ func TestChecks(t *testing.T) {
{ErrDecoding(), IsDecodingErr, true}, {ErrDecoding(), IsDecodingErr, true},
{ErrUnauthorized(), IsDecodingErr, false}, {ErrUnauthorized(), IsDecodingErr, false},
{ErrUnauthorized(), IsUnauthorizedErr, true}, {ErrUnauthorized(), IsUnauthorizedErr, true},
{ErrInvalidSignature(), IsInvalidSignatureErr, true},
// unauthorized includes InvalidSignature, but not visa versa
{ErrInvalidSignature(), IsUnauthorizedErr, true},
{ErrUnauthorized(), IsInvalidSignatureErr, false},
// make sure WrongChain works properly
{ErrWrongChain("fooz"), IsUnauthorizedErr, true},
{ErrWrongChain("barz"), IsWrongChainErr, true},
// make sure lots of things match InternalErr, but not everything // make sure lots of things match InternalErr, but not everything
{ErrInternal("bad db connection"), IsInternalErr, true}, {ErrInternal("bad db connection"), IsInternalErr, true},
{Wrap(errors.New("wrapped")), IsInternalErr, true}, {Wrap(errors.New("wrapped")), IsInternalErr, true},

31
modules/auth/errors.go Normal file
View File

@ -0,0 +1,31 @@
//nolint
package auth
import (
"fmt"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/basecoin/errors"
)
var (
errInvalidSignature = fmt.Errorf("Invalid Signature") //move auth
errTooManySignatures = fmt.Errorf("Too many signatures") //move auth
unauthorized = abci.CodeType_Unauthorized
)
func ErrTooManySignatures() errors.TMError {
return errors.WithCode(errTooManySignatures, unauthorized)
}
func IsTooManySignaturesErr(err error) bool {
return errors.IsSameError(errTooManySignatures, err)
}
func ErrInvalidSignature() errors.TMError {
return errors.WithCode(errInvalidSignature, unauthorized)
}
func IsInvalidSignatureErr(err error) bool {
return errors.IsSameError(errInvalidSignature, err)
}

View File

@ -0,0 +1,29 @@
package auth
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tendermint/basecoin/errors"
)
func TestChecks(t *testing.T) {
// TODO: make sure the Is and Err methods match
assert := assert.New(t)
cases := []struct {
err error
check func(error) bool
match bool
}{
// unauthorized includes InvalidSignature, but not visa versa
{ErrInvalidSignature(), IsInvalidSignatureErr, true},
{ErrInvalidSignature(), errors.IsUnauthorizedErr, true},
}
for i, tc := range cases {
match := tc.check(tc.err)
assert.Equal(tc.match, match, "%d", i)
}
}

View File

@ -106,7 +106,7 @@ func (s *OneSig) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
return errors.ErrMissingSignature() return errors.ErrMissingSignature()
} }
if !s.Empty() { if !s.Empty() {
return errors.ErrTooManySignatures() return ErrTooManySignatures()
} }
// set the value once we are happy // set the value once we are happy
s.Signed = signed s.Signed = signed
@ -121,7 +121,7 @@ func (s *OneSig) Signers() ([]crypto.PubKey, error) {
return nil, errors.ErrMissingSignature() return nil, errors.ErrMissingSignature()
} }
if !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) { if !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
return nil, errors.ErrInvalidSignature() return nil, ErrInvalidSignature()
} }
return []crypto.PubKey{s.Pubkey}, nil return []crypto.PubKey{s.Pubkey}, nil
} }
@ -194,7 +194,7 @@ func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
for i := range s.Sigs { for i := range s.Sigs {
ms := s.Sigs[i] ms := s.Sigs[i]
if !ms.Pubkey.VerifyBytes(data, ms.Sig) { if !ms.Pubkey.VerifyBytes(data, ms.Sig) {
return nil, errors.ErrInvalidSignature() return nil, ErrInvalidSignature()
} }
keys[i] = ms.Pubkey keys[i] = ms.Pubkey
} }

View File

@ -6,7 +6,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/basecoin/stack"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/cryptostore" "github.com/tendermint/go-crypto/keys/cryptostore"
@ -14,6 +13,7 @@ import (
wire "github.com/tendermint/go-wire" wire "github.com/tendermint/go-wire"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/stack"
) )
func checkSignBytes(t *testing.T, bytes []byte, expected string) { func checkSignBytes(t *testing.T, bytes []byte, expected string) {

View File

@ -2,7 +2,6 @@ package base
import ( import (
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/stack" "github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/state"
) )
@ -48,7 +47,7 @@ func (c Chain) checkChainTx(chainID string, height uint64, tx basecoin.Tx) (base
// make sure it is a chaintx // make sure it is a chaintx
ctx, ok := tx.Unwrap().(ChainTx) ctx, ok := tx.Unwrap().(ChainTx)
if !ok { if !ok {
return tx, errors.ErrNoChain() return tx, ErrNoChain()
} }
// basic validation // basic validation
@ -59,10 +58,10 @@ func (c Chain) checkChainTx(chainID string, height uint64, tx basecoin.Tx) (base
// compare against state // compare against state
if ctx.ChainID != chainID { if ctx.ChainID != chainID {
return tx, errors.ErrWrongChain(ctx.ChainID) return tx, ErrWrongChain(ctx.ChainID)
} }
if ctx.ExpiresAt != 0 && ctx.ExpiresAt <= height { if ctx.ExpiresAt != 0 && ctx.ExpiresAt <= height {
return tx, errors.ErrExpired() return tx, ErrExpired()
} }
return ctx.Tx, nil return ctx.Tx, nil
} }

View File

@ -6,9 +6,8 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/tendermint/basecoin/client/commands"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/client/commands"
txcmd "github.com/tendermint/basecoin/client/commands/txs" txcmd "github.com/tendermint/basecoin/client/commands/txs"
"github.com/tendermint/basecoin/modules/base" "github.com/tendermint/basecoin/modules/base"
) )

37
modules/base/errors.go Normal file
View File

@ -0,0 +1,37 @@
//nolint
package base
import (
"fmt"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/basecoin/errors"
)
var (
errNoChain = fmt.Errorf("No chain id provided") //move base
errWrongChain = fmt.Errorf("Wrong chain for tx") //move base
errExpired = fmt.Errorf("Tx expired") //move base
unauthorized = abci.CodeType_Unauthorized
)
func ErrNoChain() errors.TMError {
return errors.WithCode(errNoChain, unauthorized)
}
func IsNoChainErr(err error) bool {
return errors.IsSameError(errNoChain, err)
}
func ErrWrongChain(chain string) errors.TMError {
return errors.WithMessage(chain, errWrongChain, unauthorized)
}
func IsWrongChainErr(err error) bool {
return errors.IsSameError(errWrongChain, err)
}
func ErrExpired() errors.TMError {
return errors.WithCode(errExpired, unauthorized)
}
func IsExpiredErr(err error) bool {
return errors.IsSameError(errExpired, err)
}

View File

@ -0,0 +1,45 @@
package base
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tendermint/basecoin/errors"
)
func TestErrorMatches(t *testing.T) {
assert := assert.New(t)
cases := []struct {
pattern, err error
match bool
}{
{errWrongChain, ErrWrongChain("hakz"), true},
}
for i, tc := range cases {
same := errors.IsSameError(tc.pattern, tc.err)
assert.Equal(tc.match, same, "%d: %#v / %#v", i, tc.pattern, tc.err)
}
}
func TestChecks(t *testing.T) {
// TODO: make sure the Is and Err methods match
assert := assert.New(t)
cases := []struct {
err error
check func(error) bool
match bool
}{
// make sure WrongChain works properly
{ErrWrongChain("fooz"), errors.IsUnauthorizedErr, true},
{ErrWrongChain("barz"), IsWrongChainErr, true},
}
for i, tc := range cases {
match := tc.check(tc.err)
assert.Equal(tc.match, match, "%d", i)
}
}

View File

@ -86,10 +86,10 @@ func (c ChainTx) Wrap() basecoin.Tx {
} }
func (c ChainTx) ValidateBasic() error { func (c ChainTx) ValidateBasic() error {
if c.ChainID == "" { if c.ChainID == "" {
return errors.ErrNoChain() return ErrNoChain()
} }
if !chainPattern.MatchString(c.ChainID) { if !chainPattern.MatchString(c.ChainID) {
return errors.ErrWrongChain(c.ChainID) return ErrWrongChain(c.ChainID)
} }
if c.Tx.Empty() { if c.Tx.Empty() {
return errors.ErrUnknownTxType(c.Tx) return errors.ErrUnknownTxType(c.Tx)

View File

@ -7,10 +7,10 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/stack"
) )
func TestEncoding(t *testing.T) { func TestEncoding(t *testing.T) {

View File

@ -5,9 +5,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
lc "github.com/tendermint/light-client" lc "github.com/tendermint/light-client"
lcmd "github.com/tendermint/basecoin/client/commands" lcmd "github.com/tendermint/basecoin/client/commands"
proofcmd "github.com/tendermint/basecoin/client/commands/proofs" proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
"github.com/tendermint/basecoin/modules/auth" "github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/coin" "github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/stack" "github.com/tendermint/basecoin/stack"
@ -17,10 +17,10 @@ import (
var AccountQueryCmd = &cobra.Command{ var AccountQueryCmd = &cobra.Command{
Use: "account [address]", Use: "account [address]",
Short: "Get details of an account, with proof", Short: "Get details of an account, with proof",
RunE: lcmd.RequireInit(doAccountQuery), RunE: lcmd.RequireInit(accountQueryCmd),
} }
func doAccountQuery(cmd *cobra.Command, args []string) error { func accountQueryCmd(cmd *cobra.Command, args []string) error {
addr, err := proofcmd.ParseHexKey(args, "address") addr, err := proofcmd.ParseHexKey(args, "address")
if err != nil { if err != nil {
return err return err

View File

@ -14,7 +14,7 @@ import (
var SendTxCmd = &cobra.Command{ var SendTxCmd = &cobra.Command{
Use: "send", Use: "send",
Short: "send tokens from one account to another", Short: "send tokens from one account to another",
RunE: commands.RequireInit(doSendTx), RunE: commands.RequireInit(sendTxCmd),
} }
//nolint //nolint
@ -31,8 +31,8 @@ func init() {
flags.String(FlagFrom, "", "Address sending coins, if not first signer") flags.String(FlagFrom, "", "Address sending coins, if not first signer")
} }
// doSendTx is an example of how to make a tx // sendTxCmd is an example of how to make a tx
func doSendTx(cmd *cobra.Command, args []string) error { func sendTxCmd(cmd *cobra.Command, args []string) error {
// load data from json or flags // load data from json or flags
// var tx basecoin.Tx // var tx basecoin.Tx
// found, err := txcmd.LoadJSON(&tx) // found, err := txcmd.LoadJSON(&tx)

View File

@ -5,23 +5,23 @@ import (
"fmt" "fmt"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
"github.com/tendermint/basecoin/errors" "github.com/tendermint/basecoin/errors"
) )
var ( var (
errNoAccount = fmt.Errorf("No such account") errNoAccount = fmt.Errorf("No such account")
errInsufficientFunds = fmt.Errorf("Insufficient Funds") errInsufficientFunds = fmt.Errorf("Insufficient funds")
errNoInputs = fmt.Errorf("No Input Coins") errNoInputs = fmt.Errorf("No input coins")
errNoOutputs = fmt.Errorf("No Output Coins") errNoOutputs = fmt.Errorf("No output coins")
errInvalidAddress = fmt.Errorf("Invalid Address") errInvalidAddress = fmt.Errorf("Invalid address")
errInvalidCoins = fmt.Errorf("Invalid Coins") errInvalidCoins = fmt.Errorf("Invalid coins")
errInvalidSequence = fmt.Errorf("Invalid Sequence") errUnknownKey = fmt.Errorf("Unknown key")
)
var (
invalidInput = abci.CodeType_BaseInvalidInput invalidInput = abci.CodeType_BaseInvalidInput
invalidOutput = abci.CodeType_BaseInvalidOutput invalidOutput = abci.CodeType_BaseInvalidOutput
unknownAddress = abci.CodeType_BaseUnknownAddress unknownAddress = abci.CodeType_BaseUnknownAddress
unknownRequest = abci.CodeType_UnknownRequest
) )
// here are some generic handlers to grab classes of errors based on code // here are some generic handlers to grab classes of errors based on code
@ -80,3 +80,10 @@ func ErrNoOutputs() errors.TMError {
func IsNoOutputsErr(err error) bool { func IsNoOutputsErr(err error) bool {
return errors.IsSameError(errNoOutputs, err) return errors.IsSameError(errNoOutputs, err)
} }
func ErrUnknownKey(mod string) errors.TMError {
return errors.WithMessage(mod, errUnknownKey, unknownRequest)
}
func IsUnknownKeyErr(err error) bool {
return errors.IsSameError(errUnknownKey, err)
}

View File

@ -99,7 +99,7 @@ func (h Handler) SetOption(l log.Logger, store state.KVStore, module, key, value
return "Success", nil return "Success", nil
} }
return "", errors.ErrUnknownKey(key) return "", ErrUnknownKey(key)
} }
func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) { func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {

View File

@ -1,11 +1,11 @@
package coin package coin
import ( import (
"github.com/tendermint/basecoin/modules/auth"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/auth"
) )
// AccountWithKey is a helper for tests, that includes and account // AccountWithKey is a helper for tests, that includes and account

View File

@ -10,19 +10,21 @@ import (
) )
var ( var (
errInsufficientFees = fmt.Errorf("Insufficient Fees") errInsufficientFees = fmt.Errorf("Insufficient fees")
errWrongFeeDenom = fmt.Errorf("Required fee denomination") errWrongFeeDenom = fmt.Errorf("Required fee denomination")
invalidInput = abci.CodeType_BaseInvalidInput
) )
func ErrInsufficientFees() errors.TMError { func ErrInsufficientFees() errors.TMError {
return errors.WithCode(errInsufficientFees, abci.CodeType_BaseInvalidInput) return errors.WithCode(errInsufficientFees, invalidInput)
} }
func IsInsufficientFeesErr(err error) bool { func IsInsufficientFeesErr(err error) bool {
return errors.IsSameError(errInsufficientFees, err) return errors.IsSameError(errInsufficientFees, err)
} }
func ErrWrongFeeDenom(denom string) errors.TMError { func ErrWrongFeeDenom(denom string) errors.TMError {
return errors.WithMessage(denom, errWrongFeeDenom, abci.CodeType_BaseInvalidInput) return errors.WithMessage(denom, errWrongFeeDenom, invalidInput)
} }
func IsWrongFeeDenomErr(err error) bool { func IsWrongFeeDenomErr(err error) bool {
return errors.IsSameError(errWrongFeeDenom, err) return errors.IsSameError(errWrongFeeDenom, err)

View File

@ -7,9 +7,10 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
lc "github.com/tendermint/light-client" lc "github.com/tendermint/light-client"
"github.com/tendermint/basecoin"
lcmd "github.com/tendermint/basecoin/client/commands" lcmd "github.com/tendermint/basecoin/client/commands"
proofcmd "github.com/tendermint/basecoin/client/commands/proofs" proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
"github.com/tendermint/basecoin/modules/nonce" "github.com/tendermint/basecoin/modules/nonce"
"github.com/tendermint/basecoin/stack" "github.com/tendermint/basecoin/stack"
) )
@ -18,28 +19,36 @@ import (
var NonceQueryCmd = &cobra.Command{ var NonceQueryCmd = &cobra.Command{
Use: "nonce [address]", Use: "nonce [address]",
Short: "Get details of a nonce sequence number, with proof", Short: "Get details of a nonce sequence number, with proof",
RunE: lcmd.RequireInit(doNonceQuery), RunE: lcmd.RequireInit(nonceQueryCmd),
} }
func doNonceQuery(cmd *cobra.Command, args []string) error { func nonceQueryCmd(cmd *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.New("Missing required argument [address]") return errors.New("Missing required argument [address]")
} }
addr := strings.Join(args, ",") addr := strings.Join(args, ",")
act, err := parseActors(addr)
signers, err := parseActors(addr)
if err != nil { if err != nil {
return err return err
} }
key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(act)) seq, proof, err := doNonceQuery(signers)
if err != nil {
var seq uint32
proof, err := proofcmd.GetAndParseAppProof(key, &seq)
if lc.IsNoDataErr(err) {
return errors.Errorf("Sequence is empty for address %s ", addr)
} else if err != nil {
return err return err
} }
return proofcmd.OutputProof(seq, proof.BlockHeight()) return proofcmd.OutputProof(seq, proof.BlockHeight())
} }
func doNonceQuery(signers []basecoin.Actor) (sequence uint32, proof lc.Proof, err error) {
key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(signers))
proof, err = proofcmd.GetAndParseAppProof(key, &sequence)
if lc.IsNoDataErr(err) {
err = errors.Errorf("Sequence is empty for key %s ", key)
}
return
}

View File

@ -28,15 +28,17 @@ var _ txcmd.Wrapper = NonceWrapper{}
// the tx with this nonce. Grabs the permission from the signer, // the tx with this nonce. Grabs the permission from the signer,
// as we still only support single sig on the cli // as we still only support single sig on the cli
func (NonceWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) { func (NonceWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) {
seq, err := readSequence()
if err != nil {
return res, err
}
signers, err := readNonceKey() signers, err := readNonceKey()
if err != nil { if err != nil {
return res, err return res, err
} }
seq, err := readSequence(signers)
if err != nil {
return res, err
}
res = nonce.NewTx(seq, signers, tx) res = nonce.NewTx(seq, signers, tx)
return return
} }
@ -67,13 +69,28 @@ func parseActors(key string) (signers []basecoin.Actor, err error) {
return return
} }
func readSequence() (uint32, error) { // read the sequence from the flag or query for it if flag is -1
func readSequence(signers []basecoin.Actor) (seq uint32, err error) {
//add the nonce tx layer to the tx //add the nonce tx layer to the tx
seq := viper.GetInt(FlagSequence) seqFlag := viper.GetInt(FlagSequence)
if seq > 0 {
return uint32(seq), nil switch {
case seqFlag > 0:
seq = uint32(seqFlag)
case seqFlag == -1:
//autocalculation for default sequence
seq, _, err = doNonceQuery(signers)
if err != nil {
return
} }
// TODO: try to download from query.. //increase the sequence by 1!
return 0, fmt.Errorf("sequence must be greater than 0") seq++
default:
err = fmt.Errorf("sequence must be either greater than 0, or -1 for autocalculation")
}
return
} }

View File

@ -11,22 +11,31 @@ import (
var ( var (
errNoNonce = fmt.Errorf("Tx doesn't contain nonce") errNoNonce = fmt.Errorf("Tx doesn't contain nonce")
errNotMember = fmt.Errorf("nonce contains non-permissioned member") errNotMember = fmt.Errorf("Nonce contains non-permissioned member")
errZeroSequence = fmt.Errorf("Sequence number cannot be zero") errZeroSequence = fmt.Errorf("Sequence number cannot be zero")
errNoSigners = fmt.Errorf("There are no signers")
errTxEmpty = fmt.Errorf("The provided Tx is empty")
unauthorized = abci.CodeType_Unauthorized unauthorized = abci.CodeType_Unauthorized
badNonce = abci.CodeType_BadNonce
invalidInput = abci.CodeType_BaseInvalidInput
) )
func ErrBadNonce(got, expected uint32) errors.TMError { func ErrBadNonce(got, expected uint32) errors.TMError {
return errors.WithCode(fmt.Errorf("Bad nonce sequence, got %d, expected %d", got, expected), unauthorized) return errors.WithCode(fmt.Errorf("Bad nonce sequence, got %d, expected %d", got, expected), badNonce)
} }
func ErrNoNonce() errors.TMError { func ErrNoNonce() errors.TMError {
return errors.WithCode(errNoNonce, unauthorized) return errors.WithCode(errNoNonce, badNonce)
} }
func ErrNotMember() errors.TMError { func ErrNotMember() errors.TMError {
return errors.WithCode(errNotMember, unauthorized) return errors.WithCode(errNotMember, unauthorized)
} }
func ErrZeroSequence() errors.TMError { func ErrZeroSequence() errors.TMError {
return errors.WithCode(errZeroSequence, unauthorized) return errors.WithCode(errZeroSequence, invalidInput)
}
func ErrNoSigners() errors.TMError {
return errors.WithCode(errNoSigners, invalidInput)
}
func ErrTxEmpty() errors.TMError {
return errors.WithCode(errTxEmpty, invalidInput)
} }

View File

@ -11,7 +11,6 @@ import (
"sort" "sort"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/state"
) )
@ -50,11 +49,11 @@ func (n Tx) Wrap() basecoin.Tx {
func (n Tx) ValidateBasic() error { func (n Tx) ValidateBasic() error {
switch { switch {
case n.Tx.Empty(): case n.Tx.Empty():
return errors.ErrTxEmpty() return ErrTxEmpty()
case n.Sequence == 0: case n.Sequence == 0:
return ErrZeroSequence() return ErrZeroSequence()
case len(n.Signers) == 0: case len(n.Signers) == 0:
return errors.ErrNoSigners() return ErrNoSigners()
} }
return n.Tx.ValidateBasic() return n.Tx.ValidateBasic()
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
"github.com/tendermint/basecoin/errors" "github.com/tendermint/basecoin/errors"
) )
@ -16,54 +17,56 @@ var (
errNoMembers = fmt.Errorf("No members specified") errNoMembers = fmt.Errorf("No members specified")
errTooManyMembers = fmt.Errorf("Too many members specified") errTooManyMembers = fmt.Errorf("Too many members specified")
errNotEnoughMembers = fmt.Errorf("Not enough members specified") errNotEnoughMembers = fmt.Errorf("Not enough members specified")
unauthorized = abci.CodeType_Unauthorized
) )
// TODO: codegen? // TODO: codegen?
// ex: err-gen NoRole,"No such role",CodeType_Unauthorized // ex: err-gen NoRole,"No such role",CodeType_Unauthorized
func ErrNoRole() errors.TMError { func ErrNoRole() errors.TMError {
return errors.WithCode(errNoRole, abci.CodeType_Unauthorized) return errors.WithCode(errNoRole, unauthorized)
} }
func IsNoRoleErr(err error) bool { func IsNoRoleErr(err error) bool {
return errors.IsSameError(errNoRole, err) return errors.IsSameError(errNoRole, err)
} }
func ErrRoleExists() errors.TMError { func ErrRoleExists() errors.TMError {
return errors.WithCode(errRoleExists, abci.CodeType_Unauthorized) return errors.WithCode(errRoleExists, unauthorized)
} }
func IsRoleExistsErr(err error) bool { func IsRoleExistsErr(err error) bool {
return errors.IsSameError(errRoleExists, err) return errors.IsSameError(errRoleExists, err)
} }
func ErrNotMember() errors.TMError { func ErrNotMember() errors.TMError {
return errors.WithCode(errNotMember, abci.CodeType_Unauthorized) return errors.WithCode(errNotMember, unauthorized)
} }
func IsNotMemberErr(err error) bool { func IsNotMemberErr(err error) bool {
return errors.IsSameError(errNotMember, err) return errors.IsSameError(errNotMember, err)
} }
func ErrInsufficientSigs() errors.TMError { func ErrInsufficientSigs() errors.TMError {
return errors.WithCode(errInsufficientSigs, abci.CodeType_Unauthorized) return errors.WithCode(errInsufficientSigs, unauthorized)
} }
func IsInsufficientSigsErr(err error) bool { func IsInsufficientSigsErr(err error) bool {
return errors.IsSameError(errInsufficientSigs, err) return errors.IsSameError(errInsufficientSigs, err)
} }
func ErrNoMembers() errors.TMError { func ErrNoMembers() errors.TMError {
return errors.WithCode(errNoMembers, abci.CodeType_Unauthorized) return errors.WithCode(errNoMembers, unauthorized)
} }
func IsNoMembersErr(err error) bool { func IsNoMembersErr(err error) bool {
return errors.IsSameError(errNoMembers, err) return errors.IsSameError(errNoMembers, err)
} }
func ErrTooManyMembers() errors.TMError { func ErrTooManyMembers() errors.TMError {
return errors.WithCode(errTooManyMembers, abci.CodeType_Unauthorized) return errors.WithCode(errTooManyMembers, unauthorized)
} }
func IsTooManyMembersErr(err error) bool { func IsTooManyMembersErr(err error) bool {
return errors.IsSameError(errTooManyMembers, err) return errors.IsSameError(errTooManyMembers, err)
} }
func ErrNotEnoughMembers() errors.TMError { func ErrNotEnoughMembers() errors.TMError {
return errors.WithCode(errNotEnoughMembers, abci.CodeType_Unauthorized) return errors.WithCode(errNotEnoughMembers, unauthorized)
} }
func IsNotEnoughMembersErr(err error) bool { func IsNotEnoughMembersErr(err error) bool {
return errors.IsSameError(errNotEnoughMembers, err) return errors.IsSameError(errNotEnoughMembers, err)

View File

@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/roles" "github.com/tendermint/basecoin/modules/roles"
"github.com/tendermint/basecoin/stack" "github.com/tendermint/basecoin/stack"

View File

@ -3,10 +3,11 @@ package roles
import ( import (
"fmt" "fmt"
wire "github.com/tendermint/go-wire"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/errors" "github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/state"
wire "github.com/tendermint/go-wire"
) )
// NewPerm creates a role permission with the given label // NewPerm creates a role permission with the given label

View File

@ -6,11 +6,11 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/state"
"github.com/tendermint/go-wire/data"
) )
// writerMid is a middleware that writes the given bytes on CheckTx and DeliverTx // writerMid is a middleware that writes the given bytes on CheckTx and DeliverTx

View File

@ -21,20 +21,20 @@ test00GetAccount() {
SENDER=$(getAddr $RICH) SENDER=$(getAddr $RICH)
RECV=$(getAddr $POOR) RECV=$(getAddr $POOR)
assertFalse "requires arg" "${CLIENT_EXE} query account" assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account"
checkAccount $SENDER "9007199254740992" checkAccount $SENDER "9007199254740992"
ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null) ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null)
assertFalse "has no genesis account" $? assertFalse "line=${LINENO}, has no genesis account" $?
} }
test01SendTx() { test01SendTx() {
SENDER=$(getAddr $RICH) SENDER=$(getAddr $RICH)
RECV=$(getAddr $POOR) RECV=$(getAddr $POOR)
assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1" assertFalse "line=${LINENO}, missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1"
assertFalse "bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH" assertFalse "line=${LINENO}, bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH"
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH) TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH)
txSucceeded $? "$TX" "$RECV" txSucceeded $? "$TX" "$RECV"
HASH=$(echo $TX | jq .hash | tr -d \") HASH=$(echo $TX | jq .hash | tr -d \")
@ -53,7 +53,8 @@ test02SendTxWithFee() {
SENDER=$(getAddr $RICH) SENDER=$(getAddr $RICH)
RECV=$(getAddr $POOR) RECV=$(getAddr $POOR)
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=2 --to=$RECV --name=$RICH) # Test to see if the auto-sequencing works, the sequence here should be calculated to be 2
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=-1 --to=$RECV --name=$RICH)
txSucceeded $? "$TX" "$RECV" txSucceeded $? "$TX" "$RECV"
HASH=$(echo $TX | jq .hash | tr -d \") HASH=$(echo $TX | jq .hash | tr -d \")
TX_HEIGHT=$(echo $TX | jq .height) TX_HEIGHT=$(echo $TX | jq .height)
@ -67,7 +68,7 @@ test02SendTxWithFee() {
# assert replay protection # assert replay protection
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null) TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=90mycoin --fee=10mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null)
assertFalse "replay: $TX" $? assertFalse "line=${LINENO}, replay: $TX" $?
checkAccount $SENDER "9007199254739900" checkAccount $SENDER "9007199254739900"
checkAccount $RECV "1082" checkAccount $RECV "1082"
@ -76,7 +77,7 @@ test02SendTxWithFee() {
if [ -n "$DEBUG" ]; then echo $NONCE; echo; fi if [ -n "$DEBUG" ]; then echo $NONCE; echo; fi
# TODO: note that cobra returns error code 0 on parse failure, # TODO: note that cobra returns error code 0 on parse failure,
# so currently this check passes even if there is no nonce query command # so currently this check passes even if there is no nonce query command
if assertTrue "no nonce query" $?; then if assertTrue "line=${LINENO}, no nonce query" $?; then
assertEquals "line=${LINENO}, proper nonce" "2" $(echo $NONCE | jq .data) assertEquals "line=${LINENO}, proper nonce" "2" $(echo $NONCE | jq .data)
fi fi
} }

View File

@ -141,7 +141,7 @@ checkAccount() {
# XXX Ex Usage: txSucceeded $? "$TX" "$RECIEVER" # XXX Ex Usage: txSucceeded $? "$TX" "$RECIEVER"
# Desc: Must be called right after the `tx` command, makes sure it got a success response # Desc: Must be called right after the `tx` command, makes sure it got a success response
txSucceeded() { txSucceeded() {
if (assertTrue "sent tx ($3): $2" $1); then if (assertTrue "line=${LINENO}, sent tx ($3): $2" $1); then
TX=$2 TX=$2
assertEquals "line=${LINENO}, good check ($3): $TX" "0" $(echo $TX | jq .check_tx.code) assertEquals "line=${LINENO}, good check ($3): $TX" "0" $(echo $TX | jq .check_tx.code)
assertEquals "line=${LINENO}, good deliver ($3): $TX" "0" $(echo $TX | jq .deliver_tx.code) assertEquals "line=${LINENO}, good deliver ($3): $TX" "0" $(echo $TX | jq .deliver_tx.code)
@ -177,7 +177,7 @@ checkSendTx() {
# and that the first input was from this sender for this amount # and that the first input was from this sender for this amount
checkSendFeeTx() { checkSendFeeTx() {
TX=$(${CLIENT_EXE} query tx $1) TX=$(${CLIENT_EXE} query tx $1)
assertTrue "found tx" $? assertTrue "line=${LINENO}, found tx" $?
if [ -n "$DEBUG" ]; then echo $TX; echo; fi if [ -n "$DEBUG" ]; then echo $TX; echo; fi
assertEquals "line=${LINENO}, proper height" $2 $(echo $TX | jq .height) assertEquals "line=${LINENO}, proper height" $2 $(echo $TX | jq .height)

View File

@ -104,7 +104,7 @@ test03AddCount() {
# make sure we cannot replay the counter, no state change # make sure we cannot replay the counter, no state change
TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --countfee=10mycoin --sequence=2 --name=${RICH} --valid 2>/dev/null) TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --countfee=10mycoin --sequence=2 --name=${RICH} --valid 2>/dev/null)
assertFalse "replay: $TX" $? assertFalse "line=${LINENO}, replay: $TX" $?
checkCounter "2" "17" checkCounter "2" "17"
checkAccount $SENDER "9007199254739979" checkAccount $SENDER "9007199254739979"
} }

View File

@ -66,21 +66,21 @@ test00GetAccount() {
RECV_1=$(BC_HOME=${CLIENT_1} getAddr $POOR) RECV_1=$(BC_HOME=${CLIENT_1} getAddr $POOR)
export BC_HOME=${CLIENT_1} export BC_HOME=${CLIENT_1}
assertFalse "requires arg" "${CLIENT_EXE} query account 2>/dev/null" assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account 2>/dev/null"
assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_1 2>/dev/null" assertFalse "line=${LINENO}, has no genesis account" "${CLIENT_EXE} query account $RECV_1 2>/dev/null"
checkAccount $SENDER_1 "0" "9007199254740992" checkAccount $SENDER_1 "0" "9007199254740992"
export BC_HOME=${CLIENT_2} export BC_HOME=${CLIENT_2}
SENDER_2=$(getAddr $RICH) SENDER_2=$(getAddr $RICH)
RECV_2=$(getAddr $POOR) RECV_2=$(getAddr $POOR)
assertFalse "requires arg" "${CLIENT_EXE} query account 2>/dev/null" assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account 2>/dev/null"
assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_2 2>/dev/null" assertFalse "line=${LINENO}, has no genesis account" "${CLIENT_EXE} query account $RECV_2 2>/dev/null"
checkAccount $SENDER_2 "0" "9007199254740992" checkAccount $SENDER_2 "0" "9007199254740992"
# Make sure that they have different addresses on both chains (they are random keys) # Make sure that they have different addresses on both chains (they are random keys)
assertNotEquals "sender keys must be different" "$SENDER_1" "$SENDER_2" assertNotEquals "line=${LINENO}, sender keys must be different" "$SENDER_1" "$SENDER_2"
assertNotEquals "recipient keys must be different" "$RECV_1" "$RECV_2" assertNotEquals "line=${LINENO}, recipient keys must be different" "$RECV_1" "$RECV_2"
} }
test01SendIBCTx() { test01SendIBCTx() {
@ -105,7 +105,7 @@ test01SendIBCTx() {
# Make sure nothing arrived - yet # Make sure nothing arrived - yet
waitForBlock ${PORT_1} waitForBlock ${PORT_1}
assertFalse "no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV" assertFalse "line=${LINENO}, no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV"
# Start the relay and wait a few blocks... # Start the relay and wait a few blocks...
# (already sent a tx on chain1, so use higher sequence) # (already sent a tx on chain1, so use higher sequence)

View File

@ -13,7 +13,7 @@ oneTimeSetUp() {
HEX="deadbeef1234deadbeef1234deadbeef1234aaaa" HEX="deadbeef1234deadbeef1234deadbeef1234aaaa"
${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG" ${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG"
if ! assertTrue $?; then return 1; fi if ! assertTrue "line=${LINENO}" $?; then return 1; fi
GENESIS_FILE=${SERVER}/genesis.json GENESIS_FILE=${SERVER}/genesis.json
CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \") CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \")
@ -38,69 +38,69 @@ oneTimeTearDown() {
test01goodInit() { test01goodInit() {
export BCHOME=${BASE}/client-01 export BCHOME=${BASE}/client-01
assertFalse "ls ${BCHOME} 2>/dev/null >&2" assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2"
echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null
assertTrue "initialized light-client" $? assertTrue "line=${LINENO}, initialized light-client" $?
checkDir $BCHOME 3 checkDir $BCHOME 3
} }
test02badInit() { test02badInit() {
export BCHOME=${BASE}/client-02 export BCHOME=${BASE}/client-02
assertFalse "ls ${BCHOME} 2>/dev/null >&2" assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2"
# no node where we go # no node where we go
echo y | ${CLIENT_EXE} init --node=tcp://localhost:9999 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 echo y | ${CLIENT_EXE} init --node=tcp://localhost:9999 --chain-id="${CHAIN_ID}" > /dev/null 2>&1
assertFalse "invalid init" $? assertFalse "line=${LINENO}, invalid init" $?
# dir there, but empty... # dir there, but empty...
checkDir $BCHOME 0 checkDir $BCHOME 0
# try with invalid chain id # try with invalid chain id
echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="bad-chain-id" > /dev/null 2>&1 echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="bad-chain-id" > /dev/null 2>&1
assertFalse "invalid init" $? assertFalse "line=${LINENO}, invalid init" $?
checkDir $BCHOME 0 checkDir $BCHOME 0
# reject the response # reject the response
echo n | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 echo n | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1
assertFalse "invalid init" $? assertFalse "line=${LINENO}, invalid init" $?
checkDir $BCHOME 0 checkDir $BCHOME 0
} }
test03noDoubleInit() { test03noDoubleInit() {
export BCHOME=${BASE}/client-03 export BCHOME=${BASE}/client-03
assertFalse "ls ${BCHOME} 2>/dev/null >&2" assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2"
# init properly # init properly
echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1
assertTrue "initialized light-client" $? assertTrue "line=${LINENO}, initialized light-client" $?
checkDir $BCHOME 3 checkDir $BCHOME 3
# try again, and we get an error # try again, and we get an error
echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 echo y | ${CLIENT_EXE} init --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1
assertFalse "warning on re-init" $? assertFalse "line=${LINENO}, warning on re-init" $?
checkDir $BCHOME 3 checkDir $BCHOME 3
# unless we --force-reset # unless we --force-reset
echo y | ${CLIENT_EXE} init --force-reset --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1 echo y | ${CLIENT_EXE} init --force-reset --node=tcp://localhost:46657 --chain-id="${CHAIN_ID}" > /dev/null 2>&1
assertTrue "re-initialized light-client" $? assertTrue "line=${LINENO}, re-initialized light-client" $?
checkDir $BCHOME 3 checkDir $BCHOME 3
} }
test04acceptGenesisFile() { test04acceptGenesisFile() {
export BCHOME=${BASE}/client-04 export BCHOME=${BASE}/client-04
assertFalse "ls ${BCHOME} 2>/dev/null >&2" assertFalse "line=${LINENO}" "ls ${BCHOME} 2>/dev/null >&2"
# init properly # init properly
${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1 ${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1
assertTrue "initialized light-client" $? assertTrue "line=${LINENO}, initialized light-client" $?
checkDir $BCHOME 3 checkDir $BCHOME 3
} }
# XXX Ex: checkDir $DIR $FILES # XXX Ex: checkDir $DIR $FILES
# Makes sure directory exists and has the given number of files # Makes sure directory exists and has the given number of files
checkDir() { checkDir() {
assertTrue "ls ${1} 2>/dev/null >&2" assertTrue "line=${LINENO}" "ls ${1} 2>/dev/null >&2"
assertEquals "no files created" "$2" $(ls $1 | wc -l) assertEquals "line=${LINENO}, no files created" "$2" $(ls $1 | wc -l)
} }
# load and run these tests with shunit2! # load and run these tests with shunit2!

View File

@ -7,21 +7,21 @@ oneTimeSetUp() {
PASS=qwertyuiop PASS=qwertyuiop
export BCHOME=$HOME/.bc_keys_test export BCHOME=$HOME/.bc_keys_test
${CLIENT_EXE} reset_all ${CLIENT_EXE} reset_all
assertTrue $? assertTrue "line ${LINENO}" $?
} }
newKey(){ newKey(){
assertNotNull "keyname required" "$1" assertNotNull "keyname required" "$1"
KEYPASS=${2:-qwertyuiop} KEYPASS=${2:-qwertyuiop}
echo $KEYPASS | ${CLIENT_EXE} keys new $1 >/dev/null 2>&1 echo $KEYPASS | ${CLIENT_EXE} keys new $1 >/dev/null 2>&1
assertTrue "created $1" $? assertTrue "line ${LINENO}, created $1" $?
} }
testMakeKeys() { testMakeKeys() {
USER=demouser USER=demouser
assertFalse "already user $USER" "${CLIENT_EXE} keys get $USER" assertFalse "line ${LINENO}, already user $USER" "${CLIENT_EXE} keys get $USER"
newKey $USER newKey $USER
assertTrue "no user $USER" "${CLIENT_EXE} keys get $USER" assertTrue "line ${LINENO}, no user $USER" "${CLIENT_EXE} keys get $USER"
} }
# load and run these tests with shunit2! # load and run these tests with shunit2!

View File

@ -13,7 +13,7 @@ oneTimeSetUp() {
HEX="deadbeef1234deadbeef1234deadbeef1234aaaa" HEX="deadbeef1234deadbeef1234deadbeef1234aaaa"
${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG" ${SERVER_EXE} init ${HEX} --home="$SERVER" >> "$SERVER_LOG"
if ! assertTrue $?; then return 1; fi if ! assertTrue "line=${LINENO}" $?; then return 1; fi
GENESIS_FILE=${SERVER}/genesis.json GENESIS_FILE=${SERVER}/genesis.json
CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \") CHAIN_ID=$(cat ${GENESIS_FILE} | jq .chain_id | tr -d \")
@ -32,7 +32,7 @@ oneTimeSetUp() {
# this sets the base for all client queries in the tests # this sets the base for all client queries in the tests
export BCHOME=${BASE}/client export BCHOME=${BASE}/client
${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1 ${CLIENT_EXE} init --node=tcp://localhost:46657 --genesis=${GENESIS_FILE} > /dev/null 2>&1
if ! assertTrue "initialized light-client" "$?"; then if ! assertTrue "line=${LINENO}, initialized light-client" "$?"; then
return 1 return 1
fi fi
} }
@ -43,86 +43,86 @@ oneTimeTearDown() {
sleep 1 sleep 1
} }
test01getInsecure() { test01GetInsecure() {
GENESIS=$(${CLIENT_EXE} rpc genesis) GENESIS=$(${CLIENT_EXE} rpc genesis)
assertTrue "get genesis" "$?" assertTrue "line=${LINENO}, get genesis" "$?"
MYCHAIN=$(echo ${GENESIS} | jq .genesis.chain_id | tr -d \") MYCHAIN=$(echo ${GENESIS} | jq .genesis.chain_id | tr -d \")
assertEquals "genesis chain matches" "${CHAIN_ID}" "${MYCHAIN}" assertEquals "line=${LINENO}, genesis chain matches" "${CHAIN_ID}" "${MYCHAIN}"
STATUS=$(${CLIENT_EXE} rpc status) STATUS=$(${CLIENT_EXE} rpc status)
assertTrue "get status" "$?" assertTrue "line=${LINENO}, get status" "$?"
SHEIGHT=$(echo ${STATUS} | jq .latest_block_height) SHEIGHT=$(echo ${STATUS} | jq .latest_block_height)
assertTrue "parsed status" "$?" assertTrue "line=${LINENO}, parsed status" "$?"
assertNotNull "has a height" "${SHEIGHT}" assertNotNull "line=${LINENO}, has a height" "${SHEIGHT}"
VALS=$(${CLIENT_EXE} rpc validators) VALS=$(${CLIENT_EXE} rpc validators)
assertTrue "get validators" "$?" assertTrue "line=${LINENO}, get validators" "$?"
VHEIGHT=$(echo ${VALS} | jq .block_height) VHEIGHT=$(echo ${VALS} | jq .block_height)
assertTrue "parsed validators" "$?" assertTrue "line=${LINENO}, parsed validators" "$?"
assertTrue "sensible heights: $SHEIGHT / $VHEIGHT" "test $VHEIGHT -ge $SHEIGHT" assertTrue "line=${LINENO}, sensible heights: $SHEIGHT / $VHEIGHT" "test $VHEIGHT -ge $SHEIGHT"
VCNT=$(echo ${VALS} | jq '.validators | length') VCNT=$(echo ${VALS} | jq '.validators | length')
assertEquals "one validator" "1" "$VCNT" assertEquals "line=${LINENO}, one validator" "1" "$VCNT"
INFO=$(${CLIENT_EXE} rpc info) INFO=$(${CLIENT_EXE} rpc info)
assertTrue "get info" "$?" assertTrue "line=${LINENO}, get info" "$?"
DATA=$(echo $INFO | jq .response.data) DATA=$(echo $INFO | jq .response.data)
assertEquals "basecoin info" '"Basecoin v0.6.1"' "$DATA" assertEquals "line=${LINENO}, basecoin info" '"Basecoin v0.6.1"' "$DATA"
} }
test02getSecure() { test02GetSecure() {
HEIGHT=$(${CLIENT_EXE} rpc status | jq .latest_block_height) HEIGHT=$(${CLIENT_EXE} rpc status | jq .latest_block_height)
assertTrue "get status" "$?" assertTrue "line=${LINENO}, get status" "$?"
# check block produces something reasonable # check block produces something reasonable
assertFalse "missing height" "${CLIENT_EXE} rpc block" assertFalse "line=${LINENO}, missing height" "${CLIENT_EXE} rpc block"
BLOCK=$(${CLIENT_EXE} rpc block --height=$HEIGHT) BLOCK=$(${CLIENT_EXE} rpc block --height=$HEIGHT)
assertTrue "get block" "$?" assertTrue "line=${LINENO}, get block" "$?"
MHEIGHT=$(echo $BLOCK | jq .block_meta.header.height) MHEIGHT=$(echo $BLOCK | jq .block_meta.header.height)
assertEquals "meta height" "${HEIGHT}" "${MHEIGHT}" assertEquals "line=${LINENO}, meta height" "${HEIGHT}" "${MHEIGHT}"
BHEIGHT=$(echo $BLOCK | jq .block.header.height) BHEIGHT=$(echo $BLOCK | jq .block.header.height)
assertEquals "meta height" "${HEIGHT}" "${BHEIGHT}" assertEquals "line=${LINENO}, meta height" "${HEIGHT}" "${BHEIGHT}"
# check commit produces something reasonable # check commit produces something reasonable
assertFalse "missing height" "${CLIENT_EXE} rpc commit" assertFalse "line=${LINENO}, missing height" "${CLIENT_EXE} rpc commit"
let "CHEIGHT = $HEIGHT - 1" let "CHEIGHT = $HEIGHT - 1"
COMMIT=$(${CLIENT_EXE} rpc commit --height=$CHEIGHT) COMMIT=$(${CLIENT_EXE} rpc commit --height=$CHEIGHT)
assertTrue "get commit" "$?" assertTrue "line=${LINENO}, get commit" "$?"
HHEIGHT=$(echo $COMMIT | jq .header.height) HHEIGHT=$(echo $COMMIT | jq .header.height)
assertEquals "commit height" "${CHEIGHT}" "${HHEIGHT}" assertEquals "line=${LINENO}, commit height" "${CHEIGHT}" "${HHEIGHT}"
assertEquals "canonical" "true" $(echo $COMMIT | jq .canonical) assertEquals "line=${LINENO}, canonical" "true" $(echo $COMMIT | jq .canonical)
BSIG=$(echo $BLOCK | jq .block.last_commit) BSIG=$(echo $BLOCK | jq .block.last_commit)
CSIG=$(echo $COMMIT | jq .commit) CSIG=$(echo $COMMIT | jq .commit)
assertEquals "block and commit" "$BSIG" "$CSIG" assertEquals "line=${LINENO}, block and commit" "$BSIG" "$CSIG"
# now let's get some headers # now let's get some headers
# assertFalse "missing height" "${CLIENT_EXE} rpc headers" # assertFalse "missing height" "${CLIENT_EXE} rpc headers"
HEADERS=$(${CLIENT_EXE} rpc headers --min=$CHEIGHT --max=$HEIGHT) HEADERS=$(${CLIENT_EXE} rpc headers --min=$CHEIGHT --max=$HEIGHT)
assertTrue "get headers" "$?" assertTrue "line=${LINENO}, get headers" "$?"
assertEquals "proper height" "$HEIGHT" $(echo $HEADERS | jq '.last_height') assertEquals "line=${LINENO}, proper height" "$HEIGHT" $(echo $HEADERS | jq '.last_height')
assertEquals "two headers" "2" $(echo $HEADERS | jq '.block_metas | length') assertEquals "line=${LINENO}, two headers" "2" $(echo $HEADERS | jq '.block_metas | length')
# should we check these headers? # should we check these headers?
CHEAD=$(echo $COMMIT | jq .header) CHEAD=$(echo $COMMIT | jq .header)
# most recent first, so the commit header is second.... # most recent first, so the commit header is second....
HHEAD=$(echo $HEADERS | jq .block_metas[1].header) HHEAD=$(echo $HEADERS | jq .block_metas[1].header)
assertEquals "commit and header" "$CHEAD" "$HHEAD" assertEquals "line=${LINENO}, commit and header" "$CHEAD" "$HHEAD"
} }
test03waiting() { test03Waiting() {
START=$(${CLIENT_EXE} rpc status | jq .latest_block_height) START=$(${CLIENT_EXE} rpc status | jq .latest_block_height)
assertTrue "get status" "$?" assertTrue "line=${LINENO}, get status" "$?"
let "NEXT = $START + 5" let "NEXT = $START + 5"
assertFalse "no args" "${CLIENT_EXE} rpc wait" assertFalse "line=${LINENO}, no args" "${CLIENT_EXE} rpc wait"
assertFalse "too long" "${CLIENT_EXE} rpc wait --height=1234" assertFalse "line=${LINENO}, too long" "${CLIENT_EXE} rpc wait --height=1234"
assertTrue "normal wait" "${CLIENT_EXE} rpc wait --height=$NEXT" assertTrue "line=${LINENO}, normal wait" "${CLIENT_EXE} rpc wait --height=$NEXT"
STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height) STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height)
assertEquals "wait until height" "$NEXT" "$STEP" assertEquals "line=${LINENO}, wait until height" "$NEXT" "$STEP"
let "NEXT = $STEP + 3" let "NEXT = $STEP + 3"
assertTrue "${CLIENT_EXE} rpc wait --delta=3" assertTrue "line=${LINENO}, ${CLIENT_EXE} rpc wait --delta=3"
STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height) STEP=$(${CLIENT_EXE} rpc status | jq .latest_block_height)
assertEquals "wait for delta" "$NEXT" "$STEP" assertEquals "line=${LINENO}, wait for delta" "$NEXT" "$STEP"
} }
# load and run these tests with shunit2! # load and run these tests with shunit2!