Removed a whole lot of old crud
This commit is contained in:
parent
5c813833a0
commit
912c24093f
|
@ -2,7 +2,6 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
"github.com/tendermint/basecoin/stack"
|
"github.com/tendermint/basecoin/stack"
|
||||||
"github.com/tendermint/basecoin/txs"
|
"github.com/tendermint/basecoin/txs"
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
wire "github.com/tendermint/go-wire"
|
wire "github.com/tendermint/go-wire"
|
||||||
eyes "github.com/tendermint/merkleeyes/client"
|
eyes "github.com/tendermint/merkleeyes/client"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -28,8 +26,8 @@ type appTest struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
chainID string
|
chainID string
|
||||||
app *Basecoin
|
app *Basecoin
|
||||||
accIn types.PrivAccount
|
acctIn *coin.AccountWithKey
|
||||||
accOut types.PrivAccount
|
acctOut *coin.AccountWithKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAppTest(t *testing.T) *appTest {
|
func newAppTest(t *testing.T) *appTest {
|
||||||
|
@ -41,32 +39,27 @@ func newAppTest(t *testing.T) *appTest {
|
||||||
return at
|
return at
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a tx sending 5mycoin from each accIn to accOut
|
// make a tx sending 5mycoin from each acctIn to acctOut
|
||||||
func (at *appTest) getTx(seq int, coins types.Coins) basecoin.Tx {
|
func (at *appTest) getTx(seq int, coins types.Coins) basecoin.Tx {
|
||||||
addrIn := at.accIn.Account.PubKey.Address()
|
in := []coin.TxInput{{Address: at.acctIn.Actor(), Coins: coins, Sequence: seq}}
|
||||||
addrOut := at.accOut.Account.PubKey.Address()
|
out := []coin.TxOutput{{Address: at.acctOut.Actor(), Coins: coins}}
|
||||||
|
|
||||||
in := []coin.TxInput{{Address: stack.SigPerm(addrIn), Coins: coins, Sequence: seq}}
|
|
||||||
out := []coin.TxOutput{{Address: stack.SigPerm(addrOut), Coins: coins}}
|
|
||||||
tx := coin.NewSendTx(in, out)
|
tx := coin.NewSendTx(in, out)
|
||||||
tx = txs.NewChain(at.chainID, tx)
|
tx = txs.NewChain(at.chainID, tx)
|
||||||
stx := txs.NewMulti(tx)
|
stx := txs.NewMulti(tx)
|
||||||
txs.Sign(stx, at.accIn.PrivKey)
|
txs.Sign(stx, at.acctIn.Key)
|
||||||
return stx.Wrap()
|
return stx.Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the account on the app through SetOption
|
// set the account on the app through SetOption
|
||||||
func (at *appTest) acc2app(acc types.Account) {
|
func (at *appTest) initAccount(acct *coin.AccountWithKey) {
|
||||||
accBytes, err := json.Marshal(acc)
|
res := at.app.SetOption("coin/account", acct.MakeOption())
|
||||||
require.Nil(at.t, err)
|
|
||||||
res := at.app.SetOption("coin/account", string(accBytes))
|
|
||||||
require.EqualValues(at.t, res, "Success")
|
require.EqualValues(at.t, res, "Success")
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the in and out accs to be one account each with 7mycoin
|
// reset the in and out accs to be one account each with 7mycoin
|
||||||
func (at *appTest) reset() {
|
func (at *appTest) reset() {
|
||||||
at.accIn = types.MakeAcc("input0")
|
at.acctIn = coin.NewAccountWithKey(types.Coins{{"mycoin", 7}})
|
||||||
at.accOut = types.MakeAcc("output0")
|
at.acctOut = coin.NewAccountWithKey(types.Coins{{"mycoin", 7}})
|
||||||
|
|
||||||
eyesCli := eyes.NewLocalClient("", 0)
|
eyesCli := eyes.NewLocalClient("", 0)
|
||||||
// logger := log.TestingLogger().With("module", "app"),
|
// logger := log.TestingLogger().With("module", "app"),
|
||||||
|
@ -81,30 +74,30 @@ func (at *appTest) reset() {
|
||||||
res := at.app.SetOption("base/chain_id", at.chainID)
|
res := at.app.SetOption("base/chain_id", at.chainID)
|
||||||
require.EqualValues(at.t, res, "Success")
|
require.EqualValues(at.t, res, "Success")
|
||||||
|
|
||||||
at.acc2app(at.accIn.Account)
|
at.initAccount(at.acctIn)
|
||||||
at.acc2app(at.accOut.Account)
|
at.initAccount(at.acctOut)
|
||||||
|
|
||||||
resabci := at.app.Commit()
|
resabci := at.app.Commit()
|
||||||
require.True(at.t, resabci.IsOK(), resabci)
|
require.True(at.t, resabci.IsOK(), resabci)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBalance(pk crypto.PubKey, state types.KVStore) (types.Coins, error) {
|
func getBalance(key basecoin.Actor, state types.KVStore) (types.Coins, error) {
|
||||||
return getAddr(pk.Address(), state)
|
acct, err := coin.NewAccountant("").GetAccount(state, key)
|
||||||
|
return acct.Coins, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAddr(addr []byte, state types.KVStore) (types.Coins, error) {
|
func getAddr(addr []byte, state types.KVStore) (types.Coins, error) {
|
||||||
actor := stack.SigPerm(addr)
|
actor := stack.SigPerm(addr)
|
||||||
acct, err := coin.NewAccountant("").GetAccount(state, actor)
|
return getBalance(actor, state)
|
||||||
return acct.Coins, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the final balance and expected balance for input and output accounts
|
// returns the final balance and expected balance for input and output accounts
|
||||||
func (at *appTest) exec(t *testing.T, tx basecoin.Tx, checkTx bool) (res abci.Result, diffIn, diffOut types.Coins) {
|
func (at *appTest) exec(t *testing.T, tx basecoin.Tx, checkTx bool) (res abci.Result, diffIn, diffOut types.Coins) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
initBalIn, err := getBalance(at.accIn.Account.PubKey, at.app.GetState())
|
initBalIn, err := getBalance(at.acctIn.Actor(), at.app.GetState())
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
initBalOut, err := getBalance(at.accOut.Account.PubKey, at.app.GetState())
|
initBalOut, err := getBalance(at.acctOut.Actor(), at.app.GetState())
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
|
|
||||||
txBytes := wire.BinaryBytes(tx)
|
txBytes := wire.BinaryBytes(tx)
|
||||||
|
@ -114,9 +107,9 @@ func (at *appTest) exec(t *testing.T, tx basecoin.Tx, checkTx bool) (res abci.Re
|
||||||
res = at.app.DeliverTx(txBytes)
|
res = at.app.DeliverTx(txBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
endBalIn, err := getBalance(at.accIn.Account.PubKey, at.app.GetState())
|
endBalIn, err := getBalance(at.acctIn.Actor(), at.app.GetState())
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
endBalOut, err := getBalance(at.accOut.Account.PubKey, at.app.GetState())
|
endBalOut, err := getBalance(at.acctOut.Actor(), at.app.GetState())
|
||||||
require.Nil(err, "%+v", err)
|
require.Nil(err, "%+v", err)
|
||||||
return res, endBalIn.Minus(initBalIn), endBalOut.Minus(initBalOut)
|
return res, endBalIn.Minus(initBalIn), endBalOut.Minus(initBalOut)
|
||||||
}
|
}
|
||||||
|
@ -141,16 +134,15 @@ func TestSetOption(t *testing.T) {
|
||||||
assert.EqualValues(res, "Success")
|
assert.EqualValues(res, "Success")
|
||||||
|
|
||||||
// make a nice account...
|
// make a nice account...
|
||||||
accIn := types.MakeAcc("input0").Account
|
bal := types.Coins{{"atom", 77}, {"eth", 12}}
|
||||||
accsInBytes, err := json.Marshal(accIn)
|
acct := coin.NewAccountWithKey(bal)
|
||||||
assert.Nil(err)
|
res = app.SetOption("coin/account", acct.MakeOption())
|
||||||
res = app.SetOption("coin/account", string(accsInBytes))
|
|
||||||
require.EqualValues(res, "Success")
|
require.EqualValues(res, "Success")
|
||||||
|
|
||||||
// make sure it is set correctly, with some balance
|
// make sure it is set correctly, with some balance
|
||||||
coins, err := getBalance(accIn.PubKey, app.state)
|
coins, err := getBalance(acct.Actor(), app.state)
|
||||||
require.Nil(err)
|
require.Nil(err)
|
||||||
assert.Equal(accIn.Balance, coins)
|
assert.Equal(bal, coins)
|
||||||
|
|
||||||
// let's parse an account with badly sorted coins...
|
// let's parse an account with badly sorted coins...
|
||||||
unsortAddr, err := hex.DecodeString("C471FB670E44D219EE6DF2FC284BE38793ACBCE1")
|
unsortAddr, err := hex.DecodeString("C471FB670E44D219EE6DF2FC284BE38793ACBCE1")
|
||||||
|
@ -197,8 +189,8 @@ func TestTx(t *testing.T) {
|
||||||
at := newAppTest(t)
|
at := newAppTest(t)
|
||||||
|
|
||||||
//Bad Balance
|
//Bad Balance
|
||||||
at.accIn.Balance = types.Coins{{"mycoin", 2}}
|
at.acctIn.Coins = types.Coins{{"mycoin", 2}}
|
||||||
at.acc2app(at.accIn.Account)
|
at.initAccount(at.acctIn)
|
||||||
res, _, _ := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), true)
|
res, _, _ := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), true)
|
||||||
assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)
|
assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res)
|
||||||
res, diffIn, diffOut := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), false)
|
res, diffIn, diffOut := at.exec(t, at.getTx(1, types.Coins{{"mycoin", 5}}), false)
|
||||||
|
@ -229,7 +221,7 @@ func TestQuery(t *testing.T) {
|
||||||
|
|
||||||
resQueryPreCommit := at.app.Query(abci.RequestQuery{
|
resQueryPreCommit := at.app.Query(abci.RequestQuery{
|
||||||
Path: "/account",
|
Path: "/account",
|
||||||
Data: at.accIn.Account.PubKey.Address(),
|
Data: at.acctIn.Address(),
|
||||||
})
|
})
|
||||||
|
|
||||||
res = at.app.Commit()
|
res = at.app.Commit()
|
||||||
|
@ -237,7 +229,7 @@ func TestQuery(t *testing.T) {
|
||||||
|
|
||||||
resQueryPostCommit := at.app.Query(abci.RequestQuery{
|
resQueryPostCommit := at.app.Query(abci.RequestQuery{
|
||||||
Path: "/account",
|
Path: "/account",
|
||||||
Data: at.accIn.Account.PubKey.Address(),
|
Data: at.acctIn.Address(),
|
||||||
})
|
})
|
||||||
assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit")
|
assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tendermint/basecoin/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type plugin struct {
|
|
||||||
name string
|
|
||||||
newPlugin func() types.Plugin
|
|
||||||
}
|
|
||||||
|
|
||||||
var plugins = []plugin{}
|
|
||||||
|
|
||||||
// RegisterStartPlugin - used to enable a plugin
|
|
||||||
func RegisterStartPlugin(name string, newPlugin func() types.Plugin) {
|
|
||||||
plugins = append(plugins, plugin{name: name, newPlugin: newPlugin})
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuickVersionCmd - returns a version command based on version input
|
|
||||||
func QuickVersionCmd(version string) *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "version",
|
|
||||||
Short: "Show version info",
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println(version)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +1,6 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import "encoding/hex"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
wire "github.com/tendermint/go-wire"
|
|
||||||
|
|
||||||
"github.com/tendermint/basecoin/types"
|
|
||||||
|
|
||||||
client "github.com/tendermint/tendermint/rpc/client"
|
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Returns true for non-empty hex-string prefixed with "0x"
|
// Returns true for non-empty hex-string prefixed with "0x"
|
||||||
func isHex(s string) bool {
|
func isHex(s string) bool {
|
||||||
|
@ -34,77 +21,3 @@ func StripHex(s string) string {
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query - send an abci query
|
|
||||||
func Query(tmAddr string, key []byte) (*abci.ResultQuery, error) {
|
|
||||||
httpClient := client.NewHTTP(tmAddr, "/websocket")
|
|
||||||
return queryWithClient(httpClient, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryWithClient(httpClient *client.HTTP, key []byte) (*abci.ResultQuery, error) {
|
|
||||||
res, err := httpClient.ABCIQuery("/key", key, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Errorf("Error calling /abci_query: %v", err)
|
|
||||||
}
|
|
||||||
if !res.Code.IsOK() {
|
|
||||||
return nil, errors.Errorf("Query got non-zero exit code: %v. %s", res.Code, res.Log)
|
|
||||||
}
|
|
||||||
return res.ResultQuery, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch the account by querying the app
|
|
||||||
func getAccWithClient(httpClient *client.HTTP, address []byte) (*types.Account, error) {
|
|
||||||
|
|
||||||
key := types.AccountKey(address)
|
|
||||||
response, err := queryWithClient(httpClient, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
accountBytes := response.Value
|
|
||||||
|
|
||||||
if len(accountBytes) == 0 {
|
|
||||||
return nil, fmt.Errorf("Account bytes are empty for address: %X ", address) //never stack trace
|
|
||||||
}
|
|
||||||
|
|
||||||
var acc *types.Account
|
|
||||||
err = wire.ReadBinaryBytes(accountBytes, &acc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Errorf("Error reading account %X error: %v",
|
|
||||||
accountBytes, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHeaderAndCommit(tmAddr string, height int) (*tmtypes.Header, *tmtypes.Commit, error) {
|
|
||||||
httpClient := client.NewHTTP(tmAddr, "/websocket")
|
|
||||||
res, err := httpClient.Commit(height)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, errors.Errorf("Error on commit: %v", err)
|
|
||||||
}
|
|
||||||
header := res.Header
|
|
||||||
commit := res.Commit
|
|
||||||
|
|
||||||
return header, commit, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForBlock(httpClient *client.HTTP) error {
|
|
||||||
res, err := httpClient.Status()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
lastHeight := res.LatestBlockHeight
|
|
||||||
for {
|
|
||||||
res, err := httpClient.Status()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if res.LatestBlockHeight > lastHeight {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,3 +16,14 @@ var VersionCmd = &cobra.Command{
|
||||||
fmt.Println(version.Version)
|
fmt.Println(version.Version)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickVersionCmd - returns a version command based on version input
|
||||||
|
func QuickVersionCmd(version string) *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Show version info",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(version)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package counter
|
package counter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -9,6 +8,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/basecoin/app"
|
"github.com/tendermint/basecoin/app"
|
||||||
|
"github.com/tendermint/basecoin/modules/coin"
|
||||||
"github.com/tendermint/basecoin/txs"
|
"github.com/tendermint/basecoin/txs"
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
"github.com/tendermint/go-wire"
|
"github.com/tendermint/go-wire"
|
||||||
|
@ -34,14 +34,9 @@ func TestCounterPlugin(t *testing.T) {
|
||||||
bcApp.SetOption("base/chain_id", chainID)
|
bcApp.SetOption("base/chain_id", chainID)
|
||||||
|
|
||||||
// Account initialization
|
// Account initialization
|
||||||
test1PrivAcc := types.PrivAccountFromSecret("test1")
|
bal := types.Coins{{"", 1000}, {"gold", 1000}}
|
||||||
|
acct := coin.NewAccountWithKey(bal)
|
||||||
// Seed Basecoin with account
|
log := bcApp.SetOption("coin/account", acct.MakeOption())
|
||||||
test1Acc := test1PrivAcc.Account
|
|
||||||
test1Acc.Balance = types.Coins{{"", 1000}, {"gold", 1000}}
|
|
||||||
accOpt, err := json.Marshal(test1Acc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
log := bcApp.SetOption("coin/account", string(accOpt))
|
|
||||||
require.Equal(t, "Success", log)
|
require.Equal(t, "Success", log)
|
||||||
|
|
||||||
// Deliver a CounterTx
|
// Deliver a CounterTx
|
||||||
|
@ -49,7 +44,7 @@ func TestCounterPlugin(t *testing.T) {
|
||||||
tx := NewTx(valid, counterFee, inputSequence)
|
tx := NewTx(valid, counterFee, inputSequence)
|
||||||
tx = txs.NewChain(chainID, tx)
|
tx = txs.NewChain(chainID, tx)
|
||||||
stx := txs.NewSig(tx)
|
stx := txs.NewSig(tx)
|
||||||
txs.Sign(stx, test1PrivAcc.PrivKey)
|
txs.Sign(stx, acct.Key)
|
||||||
txBytes := wire.BinaryBytes(stx.Wrap())
|
txBytes := wire.BinaryBytes(stx.Wrap())
|
||||||
return bcApp.DeliverTx(txBytes)
|
return bcApp.DeliverTx(txBytes)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package coin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
"github.com/tendermint/basecoin/stack"
|
||||||
|
"github.com/tendermint/basecoin/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
"github.com/tendermint/go-wire/data"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountWithKey is a helper for tests, that includes and account
|
||||||
|
// along with the private key to access it.
|
||||||
|
type AccountWithKey struct {
|
||||||
|
Key crypto.PrivKey
|
||||||
|
Account
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAccountWithKey creates an account with the given balance
|
||||||
|
// and a random private key
|
||||||
|
func NewAccountWithKey(coins types.Coins) *AccountWithKey {
|
||||||
|
return &AccountWithKey{
|
||||||
|
Key: crypto.GenPrivKeyEd25519().Wrap(),
|
||||||
|
Account: Account{Coins: coins},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address returns the public key address for this account
|
||||||
|
func (a *AccountWithKey) Address() []byte {
|
||||||
|
return a.Key.PubKey().Address()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actor returns the basecoin actor associated with this account
|
||||||
|
func (a *AccountWithKey) Actor() basecoin.Actor {
|
||||||
|
return stack.SigPerm(a.Key.PubKey().Address())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeOption returns a string to use with SetOption to initialize this account
|
||||||
|
//
|
||||||
|
// This is intended for use in test cases
|
||||||
|
func (a *AccountWithKey) MakeOption() string {
|
||||||
|
info := GenesisAccount{
|
||||||
|
Address: a.Address(),
|
||||||
|
Sequence: a.Sequence,
|
||||||
|
Balance: a.Coins,
|
||||||
|
}
|
||||||
|
js, err := data.ToJSON(info)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(js)
|
||||||
|
}
|
|
@ -20,9 +20,6 @@ func TestState(t *testing.T) {
|
||||||
cache := state.CacheWrap()
|
cache := state.CacheWrap()
|
||||||
eyesCli := eyes.NewLocalClient("", 0)
|
eyesCli := eyes.NewLocalClient("", 0)
|
||||||
|
|
||||||
acc := new(types.Account)
|
|
||||||
acc.Sequence = 1
|
|
||||||
|
|
||||||
//reset the store/state/cache
|
//reset the store/state/cache
|
||||||
reset := func() {
|
reset := func() {
|
||||||
store = types.NewMemKVStore()
|
store = types.NewMemKVStore()
|
||||||
|
|
|
@ -1,140 +1,142 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
func main() {}
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
// import (
|
||||||
"github.com/tendermint/basecoin/types"
|
// "fmt"
|
||||||
wire "github.com/tendermint/go-wire"
|
// "time"
|
||||||
_ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
|
|
||||||
"github.com/tendermint/tendermint/rpc/lib/client"
|
|
||||||
"github.com/tendermint/tendermint/rpc/lib/types"
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
// "github.com/gorilla/websocket"
|
||||||
// ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
|
// "github.com/tendermint/basecoin/types"
|
||||||
ws := rpcclient.NewWSClient("192.168.99.100:46657", "/websocket")
|
// wire "github.com/tendermint/go-wire"
|
||||||
chainID := "test_chain_id"
|
// _ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
|
||||||
|
// "github.com/tendermint/tendermint/rpc/lib/client"
|
||||||
|
// "github.com/tendermint/tendermint/rpc/lib/types"
|
||||||
|
// cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
// )
|
||||||
|
|
||||||
_, err := ws.Start()
|
// func main() {
|
||||||
if err != nil {
|
// // ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
|
||||||
cmn.Exit(err.Error())
|
// ws := rpcclient.NewWSClient("192.168.99.100:46657", "/websocket")
|
||||||
}
|
// chainID := "test_chain_id"
|
||||||
var counter = 0
|
|
||||||
|
|
||||||
// Read a bunch of responses
|
// _, err := ws.Start()
|
||||||
go func() {
|
// if err != nil {
|
||||||
for {
|
// cmn.Exit(err.Error())
|
||||||
res, ok := <-ws.ResultsCh
|
// }
|
||||||
if !ok {
|
// var counter = 0
|
||||||
break
|
|
||||||
}
|
|
||||||
fmt.Println(counter, "res:", cmn.Blue(string(res)))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Get the root account
|
// // Read a bunch of responses
|
||||||
root := types.PrivAccountFromSecret("test")
|
// go func() {
|
||||||
sequence := int(0)
|
// for {
|
||||||
// Make a bunch of PrivAccounts
|
// res, ok := <-ws.ResultsCh
|
||||||
privAccounts := types.RandAccounts(1000, 1000000, 0)
|
// if !ok {
|
||||||
privAccountSequences := make(map[string]int)
|
// break
|
||||||
|
// }
|
||||||
|
// fmt.Println(counter, "res:", cmn.Blue(string(res)))
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
|
||||||
// Send coins to each account
|
// // Get the root account
|
||||||
for i := 0; i < len(privAccounts); i++ {
|
// root := types.PrivAccountFromSecret("test")
|
||||||
privAccount := privAccounts[i]
|
// sequence := int(0)
|
||||||
tx := &types.SendTx{
|
// // Make a bunch of PrivAccounts
|
||||||
Inputs: []types.TxInput{
|
// privAccounts := types.RandAccounts(1000, 1000000, 0)
|
||||||
types.TxInput{
|
// privAccountSequences := make(map[string]int)
|
||||||
Address: root.Account.PubKey.Address(),
|
|
||||||
PubKey: root.Account.PubKey, // TODO is this needed?
|
|
||||||
Coins: types.Coins{{"", 1000002}},
|
|
||||||
Sequence: sequence,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []types.TxOutput{
|
|
||||||
types.TxOutput{
|
|
||||||
Address: privAccount.Account.PubKey.Address(),
|
|
||||||
Coins: types.Coins{{"", 1000000}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
// Sign request
|
// // Send coins to each account
|
||||||
signBytes := tx.SignBytes(chainID)
|
// for i := 0; i < len(privAccounts); i++ {
|
||||||
sig := root.Sign(signBytes)
|
// privAccount := privAccounts[i]
|
||||||
tx.Inputs[0].Signature = sig
|
// tx := &types.SendTx{
|
||||||
//fmt.Println("tx:", tx)
|
// Inputs: []types.TxInput{
|
||||||
|
// types.TxInput{
|
||||||
|
// Address: root.Account.PubKey.Address(),
|
||||||
|
// PubKey: root.Account.PubKey, // TODO is this needed?
|
||||||
|
// Coins: types.Coins{{"", 1000002}},
|
||||||
|
// Sequence: sequence,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// Outputs: []types.TxOutput{
|
||||||
|
// types.TxOutput{
|
||||||
|
// Address: privAccount.Account.PubKey.Address(),
|
||||||
|
// Coins: types.Coins{{"", 1000000}},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// sequence += 1
|
||||||
|
|
||||||
// Write request
|
// // Sign request
|
||||||
txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
// signBytes := tx.SignBytes(chainID)
|
||||||
request, err := rpctypes.MapToRequest("fakeid", "broadcast_tx_sync", map[string]interface{}{"tx": txBytes})
|
// sig := root.Sign(signBytes)
|
||||||
if err != nil {
|
// tx.Inputs[0].Signature = sig
|
||||||
cmn.Exit("cannot encode request: " + err.Error())
|
// //fmt.Println("tx:", tx)
|
||||||
}
|
|
||||||
reqBytes := wire.JSONBytes(request)
|
|
||||||
//fmt.Print(".")
|
|
||||||
err = ws.WriteMessage(websocket.TextMessage, reqBytes)
|
|
||||||
if err != nil {
|
|
||||||
cmn.Exit("writing websocket request: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now send coins between these accounts
|
// // Write request
|
||||||
for {
|
// txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
||||||
counter += 1
|
// request, err := rpctypes.MapToRequest("fakeid", "broadcast_tx_sync", map[string]interface{}{"tx": txBytes})
|
||||||
time.Sleep(time.Millisecond * 10)
|
// if err != nil {
|
||||||
|
// cmn.Exit("cannot encode request: " + err.Error())
|
||||||
|
// }
|
||||||
|
// reqBytes := wire.JSONBytes(request)
|
||||||
|
// //fmt.Print(".")
|
||||||
|
// err = ws.WriteMessage(websocket.TextMessage, reqBytes)
|
||||||
|
// if err != nil {
|
||||||
|
// cmn.Exit("writing websocket request: " + err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
randA := cmn.RandInt() % len(privAccounts)
|
// // Now send coins between these accounts
|
||||||
randB := cmn.RandInt() % len(privAccounts)
|
// for {
|
||||||
if randA == randB {
|
// counter += 1
|
||||||
continue
|
// time.Sleep(time.Millisecond * 10)
|
||||||
}
|
|
||||||
|
|
||||||
privAccountA := privAccounts[randA]
|
// randA := cmn.RandInt() % len(privAccounts)
|
||||||
privAccountASequence := privAccountSequences[privAccountA.Account.PubKey.KeyString()]
|
// randB := cmn.RandInt() % len(privAccounts)
|
||||||
privAccountSequences[privAccountA.Account.PubKey.KeyString()] = privAccountASequence + 1
|
// if randA == randB {
|
||||||
privAccountB := privAccounts[randB]
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
tx := &types.SendTx{
|
// privAccountA := privAccounts[randA]
|
||||||
Inputs: []types.TxInput{
|
// privAccountASequence := privAccountSequences[privAccountA.Account.PubKey.KeyString()]
|
||||||
types.TxInput{
|
// privAccountSequences[privAccountA.Account.PubKey.KeyString()] = privAccountASequence + 1
|
||||||
Address: privAccountA.Account.PubKey.Address(),
|
// privAccountB := privAccounts[randB]
|
||||||
PubKey: privAccountA.Account.PubKey,
|
|
||||||
Coins: types.Coins{{"", 3}},
|
|
||||||
Sequence: privAccountASequence + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []types.TxOutput{
|
|
||||||
types.TxOutput{
|
|
||||||
Address: privAccountB.Account.PubKey.Address(),
|
|
||||||
Coins: types.Coins{{"", 1}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign request
|
// tx := &types.SendTx{
|
||||||
signBytes := tx.SignBytes(chainID)
|
// Inputs: []types.TxInput{
|
||||||
sig := privAccountA.Sign(signBytes)
|
// types.TxInput{
|
||||||
tx.Inputs[0].Signature = sig
|
// Address: privAccountA.Account.PubKey.Address(),
|
||||||
//fmt.Println("tx:", tx)
|
// PubKey: privAccountA.Account.PubKey,
|
||||||
|
// Coins: types.Coins{{"", 3}},
|
||||||
|
// Sequence: privAccountASequence + 1,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// Outputs: []types.TxOutput{
|
||||||
|
// types.TxOutput{
|
||||||
|
// Address: privAccountB.Account.PubKey.Address(),
|
||||||
|
// Coins: types.Coins{{"", 1}},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
// Write request
|
// // Sign request
|
||||||
txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
// signBytes := tx.SignBytes(chainID)
|
||||||
request, err := rpctypes.MapToRequest("fakeid", "broadcast_tx_sync", map[string]interface{}{"tx": txBytes})
|
// sig := privAccountA.Sign(signBytes)
|
||||||
if err != nil {
|
// tx.Inputs[0].Signature = sig
|
||||||
cmn.Exit("cannot encode request: " + err.Error())
|
// //fmt.Println("tx:", tx)
|
||||||
}
|
|
||||||
reqBytes := wire.JSONBytes(request)
|
|
||||||
//fmt.Print(".")
|
|
||||||
err = ws.WriteMessage(websocket.TextMessage, reqBytes)
|
|
||||||
if err != nil {
|
|
||||||
cmn.Exit("writing websocket request: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.Stop()
|
// // Write request
|
||||||
}
|
// txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
||||||
|
// request, err := rpctypes.MapToRequest("fakeid", "broadcast_tx_sync", map[string]interface{}{"tx": txBytes})
|
||||||
|
// if err != nil {
|
||||||
|
// cmn.Exit("cannot encode request: " + err.Error())
|
||||||
|
// }
|
||||||
|
// reqBytes := wire.JSONBytes(request)
|
||||||
|
// //fmt.Print(".")
|
||||||
|
// err = ws.WriteMessage(websocket.TextMessage, reqBytes)
|
||||||
|
// if err != nil {
|
||||||
|
// cmn.Exit("writing websocket request: " + err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ws.Stop()
|
||||||
|
// }
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/tendermint/go-crypto"
|
|
||||||
"github.com/tendermint/go-wire"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Account struct {
|
|
||||||
PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known.
|
|
||||||
Sequence int `json:"sequence"`
|
|
||||||
Balance Coins `json:"coins"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (acc *Account) Copy() *Account {
|
|
||||||
if acc == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
accCopy := *acc
|
|
||||||
return &accCopy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (acc *Account) String() string {
|
|
||||||
if acc == nil {
|
|
||||||
return "nil-Account"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Account{%v %v %v}",
|
|
||||||
acc.PubKey, acc.Sequence, acc.Balance)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type PrivAccount struct {
|
|
||||||
crypto.PrivKey
|
|
||||||
Account
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type AccountGetter interface {
|
|
||||||
GetAccount(addr []byte) *Account
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountSetter interface {
|
|
||||||
SetAccount(addr []byte, acc *Account)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountGetterSetter interface {
|
|
||||||
GetAccount(addr []byte) *Account
|
|
||||||
SetAccount(addr []byte, acc *Account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func AccountKey(addr []byte) []byte {
|
|
||||||
return append([]byte("base/a/"), addr...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAccount(store KVStore, addr []byte) *Account {
|
|
||||||
data := store.Get(AccountKey(addr))
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var acc *Account
|
|
||||||
err := wire.ReadBinaryBytes(data, &acc)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Error reading account %X error: %v",
|
|
||||||
data, err.Error()))
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetAccount(store KVStore, addr []byte, acc *Account) {
|
|
||||||
accBytes := wire.BinaryBytes(acc)
|
|
||||||
store.Set(AccountKey(addr), accBytes)
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNilAccount(t *testing.T) {
|
|
||||||
|
|
||||||
var acc Account
|
|
||||||
|
|
||||||
//test Copy
|
|
||||||
accCopy := acc.Copy()
|
|
||||||
//note that the assert.True is used instead of assert.Equal because looking at pointers
|
|
||||||
assert.True(t, &acc != accCopy, "Account Copy Error, acc1: %v, acc2: %v", &acc, accCopy)
|
|
||||||
assert.Equal(t, acc.Sequence, accCopy.Sequence)
|
|
||||||
|
|
||||||
//test sending nils for panic
|
|
||||||
var nilAcc *Account
|
|
||||||
nilAcc.String()
|
|
||||||
nilAcc.Copy()
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Plugin interface {
|
|
||||||
|
|
||||||
// Name of this plugin, should be short.
|
|
||||||
Name() string
|
|
||||||
|
|
||||||
// Run a transaction from ABCI DeliverTx
|
|
||||||
RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result)
|
|
||||||
|
|
||||||
// Other ABCI message handlers
|
|
||||||
SetOption(store KVStore, key, value string) (log string)
|
|
||||||
InitChain(store KVStore, vals []*abci.Validator)
|
|
||||||
BeginBlock(store KVStore, hash []byte, header *abci.Header)
|
|
||||||
EndBlock(store KVStore, height uint64) abci.ResponseEndBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type CallContext struct {
|
|
||||||
CallerAddress []byte // Caller's Address (hash of PubKey)
|
|
||||||
CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted
|
|
||||||
Coins Coins // The coins that the caller wishes to spend, excluding fees
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCallContext(callerAddress []byte, callerAccount *Account, coins Coins) CallContext {
|
|
||||||
return CallContext{
|
|
||||||
CallerAddress: callerAddress,
|
|
||||||
CallerAccount: callerAccount,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type Plugins struct {
|
|
||||||
byName map[string]Plugin
|
|
||||||
plist []Plugin
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPlugins() *Plugins {
|
|
||||||
return &Plugins{
|
|
||||||
byName: make(map[string]Plugin),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pgz *Plugins) RegisterPlugin(plugin Plugin) {
|
|
||||||
name := plugin.Name()
|
|
||||||
if name == "" {
|
|
||||||
panic("Plugin name cannot be blank")
|
|
||||||
}
|
|
||||||
if _, exists := pgz.byName[name]; exists {
|
|
||||||
panic(fmt.Sprintf("Plugin already exists by the name of %v", name))
|
|
||||||
}
|
|
||||||
pgz.byName[name] = plugin
|
|
||||||
pgz.plist = append(pgz.plist, plugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pgz *Plugins) GetByName(name string) Plugin {
|
|
||||||
return pgz.byName[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pgz *Plugins) GetList() []Plugin {
|
|
||||||
return pgz.plist
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
//----------------------------------
|
|
||||||
|
|
||||||
type Dummy struct{}
|
|
||||||
|
|
||||||
func (d *Dummy) Name() string {
|
|
||||||
return "dummy"
|
|
||||||
}
|
|
||||||
func (d *Dummy) RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (d *Dummy) SetOption(storei KVStore, key, value string) (log string) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
func (d *Dummy) InitChain(store KVStore, vals []*abci.Validator) {
|
|
||||||
}
|
|
||||||
func (d *Dummy) BeginBlock(store KVStore, hash []byte, header *abci.Header) {
|
|
||||||
}
|
|
||||||
func (d *Dummy) EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------
|
|
||||||
|
|
||||||
func TestPlugin(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
plugins := NewPlugins()
|
|
||||||
assert.Zero(len(plugins.GetList()), "plugins object init with a objects")
|
|
||||||
plugins.RegisterPlugin(&Dummy{})
|
|
||||||
assert.Equal(len(plugins.GetList()), 1, "plugin wasn't added to plist after registered")
|
|
||||||
assert.Equal(plugins.GetByName("dummy").Name(), "dummy", "plugin wasn't retrieved properly with GetByName")
|
|
||||||
}
|
|
|
@ -1,105 +1,105 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
// Helper functions for testing
|
// // Helper functions for testing
|
||||||
|
|
||||||
import (
|
// import (
|
||||||
"github.com/tendermint/go-crypto"
|
// "github.com/tendermint/go-crypto"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
// cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
// )
|
||||||
|
|
||||||
// Creates a PrivAccount from secret.
|
// // Creates a PrivAccount from secret.
|
||||||
// The amount is not set.
|
// // The amount is not set.
|
||||||
func PrivAccountFromSecret(secret string) PrivAccount {
|
// func PrivAccountFromSecret(secret string) PrivAccount {
|
||||||
privKey :=
|
// privKey :=
|
||||||
crypto.GenPrivKeyEd25519FromSecret([]byte(secret)).Wrap()
|
// crypto.GenPrivKeyEd25519FromSecret([]byte(secret)).Wrap()
|
||||||
privAccount := PrivAccount{
|
// privAccount := PrivAccount{
|
||||||
PrivKey: privKey,
|
// PrivKey: privKey,
|
||||||
Account: Account{
|
// Account: Account{
|
||||||
PubKey: privKey.PubKey(),
|
// PubKey: privKey.PubKey(),
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
return privAccount
|
// return privAccount
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Make `num` random accounts
|
// // Make `num` random accounts
|
||||||
func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount {
|
// func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount {
|
||||||
privAccs := make([]PrivAccount, num)
|
// privAccs := make([]PrivAccount, num)
|
||||||
for i := 0; i < num; i++ {
|
// for i := 0; i < num; i++ {
|
||||||
|
|
||||||
balance := minAmount
|
// balance := minAmount
|
||||||
if maxAmount > minAmount {
|
// if maxAmount > minAmount {
|
||||||
balance += cmn.RandInt64() % (maxAmount - minAmount)
|
// balance += cmn.RandInt64() % (maxAmount - minAmount)
|
||||||
}
|
// }
|
||||||
|
|
||||||
privKey := crypto.GenPrivKeyEd25519().Wrap()
|
// privKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||||
pubKey := privKey.PubKey()
|
// pubKey := privKey.PubKey()
|
||||||
privAccs[i] = PrivAccount{
|
// privAccs[i] = PrivAccount{
|
||||||
PrivKey: privKey,
|
// PrivKey: privKey,
|
||||||
Account: Account{
|
// Account: Account{
|
||||||
PubKey: pubKey,
|
// PubKey: pubKey,
|
||||||
Balance: Coins{Coin{"", balance}},
|
// Balance: Coins{Coin{"", balance}},
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return privAccs
|
// return privAccs
|
||||||
}
|
// }
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//func MakeAccs(secrets ...string) (accs []PrivAccount) {
|
// //func MakeAccs(secrets ...string) (accs []PrivAccount) {
|
||||||
// for _, secret := range secrets {
|
// // for _, secret := range secrets {
|
||||||
// privAcc := PrivAccountFromSecret(secret)
|
// // privAcc := PrivAccountFromSecret(secret)
|
||||||
// privAcc.Account.Balance = Coins{{"mycoin", 7}}
|
// // privAcc.Account.Balance = Coins{{"mycoin", 7}}
|
||||||
// accs = append(accs, privAcc)
|
// // accs = append(accs, privAcc)
|
||||||
// }
|
// // }
|
||||||
// return
|
// // return
|
||||||
//}
|
// //}
|
||||||
|
|
||||||
func MakeAcc(secret string) PrivAccount {
|
// func MakeAcc(secret string) PrivAccount {
|
||||||
privAcc := PrivAccountFromSecret(secret)
|
// privAcc := PrivAccountFromSecret(secret)
|
||||||
privAcc.Account.Balance = Coins{{"mycoin", 7}}
|
// privAcc.Account.Balance = Coins{{"mycoin", 7}}
|
||||||
return privAcc
|
// return privAcc
|
||||||
}
|
// }
|
||||||
|
|
||||||
func Accs2TxInputs(seq int, accs ...PrivAccount) []TxInput {
|
// func Accs2TxInputs(seq int, accs ...PrivAccount) []TxInput {
|
||||||
var txs []TxInput
|
// var txs []TxInput
|
||||||
for _, acc := range accs {
|
// for _, acc := range accs {
|
||||||
tx := NewTxInput(
|
// tx := NewTxInput(
|
||||||
acc.Account.PubKey,
|
// acc.Account.PubKey,
|
||||||
Coins{{"mycoin", 5}},
|
// Coins{{"mycoin", 5}},
|
||||||
seq)
|
// seq)
|
||||||
txs = append(txs, tx)
|
// txs = append(txs, tx)
|
||||||
}
|
// }
|
||||||
return txs
|
// return txs
|
||||||
}
|
// }
|
||||||
|
|
||||||
//turn a list of accounts into basic list of transaction outputs
|
// //turn a list of accounts into basic list of transaction outputs
|
||||||
func Accs2TxOutputs(accs ...PrivAccount) []TxOutput {
|
// func Accs2TxOutputs(accs ...PrivAccount) []TxOutput {
|
||||||
var txs []TxOutput
|
// var txs []TxOutput
|
||||||
for _, acc := range accs {
|
// for _, acc := range accs {
|
||||||
tx := TxOutput{
|
// tx := TxOutput{
|
||||||
acc.Account.PubKey.Address(),
|
// acc.Account.PubKey.Address(),
|
||||||
Coins{{"mycoin", 4}}}
|
// Coins{{"mycoin", 4}}}
|
||||||
txs = append(txs, tx)
|
// txs = append(txs, tx)
|
||||||
}
|
// }
|
||||||
return txs
|
// return txs
|
||||||
}
|
// }
|
||||||
|
|
||||||
func MakeSendTx(seq int, accOut PrivAccount, accsIn ...PrivAccount) *SendTx {
|
// func MakeSendTx(seq int, accOut PrivAccount, accsIn ...PrivAccount) *SendTx {
|
||||||
tx := &SendTx{
|
// tx := &SendTx{
|
||||||
Gas: 0,
|
// Gas: 0,
|
||||||
Fee: Coin{"mycoin", 1},
|
// Fee: Coin{"mycoin", 1},
|
||||||
Inputs: Accs2TxInputs(seq, accsIn...),
|
// Inputs: Accs2TxInputs(seq, accsIn...),
|
||||||
Outputs: Accs2TxOutputs(accOut),
|
// Outputs: Accs2TxOutputs(accOut),
|
||||||
}
|
// }
|
||||||
|
|
||||||
return tx
|
// return tx
|
||||||
}
|
// }
|
||||||
|
|
||||||
func SignTx(chainID string, tx *SendTx, accs ...PrivAccount) {
|
// func SignTx(chainID string, tx *SendTx, accs ...PrivAccount) {
|
||||||
signBytes := tx.SignBytes(chainID)
|
// signBytes := tx.SignBytes(chainID)
|
||||||
for i, _ := range tx.Inputs {
|
// for i, _ := range tx.Inputs {
|
||||||
tx.Inputs[i].Signature = accs[i].Sign(signBytes)
|
// tx.Inputs[i].Signature = accs[i].Sign(signBytes)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
240
types/tx.go
240
types/tx.go
|
@ -1,240 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
"github.com/tendermint/go-crypto"
|
|
||||||
"github.com/tendermint/go-wire"
|
|
||||||
"github.com/tendermint/go-wire/data"
|
|
||||||
. "github.com/tendermint/tmlibs/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tx (Transaction) is an atomic operation on the ledger state.
|
|
||||||
|
|
||||||
Account Types:
|
|
||||||
- SendTx Send coins to address
|
|
||||||
- AppTx Send a msg to a contract that runs in the vm
|
|
||||||
*/
|
|
||||||
type Tx interface {
|
|
||||||
AssertIsTx()
|
|
||||||
SignBytes(chainID string) []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Types of Tx implementations
|
|
||||||
const (
|
|
||||||
// Account transactions
|
|
||||||
TxTypeSend = byte(0x01)
|
|
||||||
TxTypeApp = byte(0x02)
|
|
||||||
TxNameSend = "send"
|
|
||||||
TxNameApp = "app"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (_ *SendTx) AssertIsTx() {}
|
|
||||||
func (_ *AppTx) AssertIsTx() {}
|
|
||||||
|
|
||||||
var txMapper data.Mapper
|
|
||||||
|
|
||||||
// register both private key types with go-wire/data (and thus go-wire)
|
|
||||||
func init() {
|
|
||||||
txMapper = data.NewMapper(TxS{}).
|
|
||||||
RegisterImplementation(&SendTx{}, TxNameSend, TxTypeSend).
|
|
||||||
RegisterImplementation(&AppTx{}, TxNameApp, TxTypeApp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxS add json serialization to Tx
|
|
||||||
type TxS struct {
|
|
||||||
Tx `json:"unwrap"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p TxS) MarshalJSON() ([]byte, error) {
|
|
||||||
return txMapper.ToJSON(p.Tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *TxS) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
parsed, err := txMapper.FromJSON(data)
|
|
||||||
if err == nil {
|
|
||||||
p.Tx = parsed.(Tx)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type TxInput struct {
|
|
||||||
Address data.Bytes `json:"address"` // Hash of the PubKey
|
|
||||||
Coins Coins `json:"coins"` //
|
|
||||||
Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput
|
|
||||||
Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
|
|
||||||
PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (txIn TxInput) ValidateBasic() abci.Result {
|
|
||||||
if len(txIn.Address) != 20 {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog("Invalid address length")
|
|
||||||
}
|
|
||||||
if !txIn.Coins.IsValid() {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog(Fmt("Invalid coins %v", txIn.Coins))
|
|
||||||
}
|
|
||||||
if txIn.Coins.IsZero() {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog("Coins cannot be zero")
|
|
||||||
}
|
|
||||||
if txIn.Sequence <= 0 {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog("Sequence must be greater than 0")
|
|
||||||
}
|
|
||||||
if txIn.Sequence == 1 && txIn.PubKey.Empty() {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog("PubKey must be present when Sequence == 1")
|
|
||||||
}
|
|
||||||
if txIn.Sequence > 1 && !txIn.PubKey.Empty() {
|
|
||||||
return abci.ErrBaseInvalidInput.AppendLog("PubKey must be nil when Sequence > 1")
|
|
||||||
}
|
|
||||||
return abci.OK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (txIn TxInput) String() string {
|
|
||||||
return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Coins, txIn.Sequence, txIn.Signature, txIn.PubKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTxInput(pubKey crypto.PubKey, coins Coins, sequence int) TxInput {
|
|
||||||
input := TxInput{
|
|
||||||
Address: pubKey.Address(),
|
|
||||||
Coins: coins,
|
|
||||||
Sequence: sequence,
|
|
||||||
}
|
|
||||||
if sequence == 1 {
|
|
||||||
input.PubKey = pubKey
|
|
||||||
}
|
|
||||||
return input
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type TxOutput struct {
|
|
||||||
Address data.Bytes `json:"address"` // Hash of the PubKey
|
|
||||||
Coins Coins `json:"coins"` //
|
|
||||||
}
|
|
||||||
|
|
||||||
// An output destined for another chain may be formatted as `chainID/address`.
|
|
||||||
// ChainAndAddress returns the chainID prefix and the address.
|
|
||||||
// If there is no chainID prefix, the first returned value is nil.
|
|
||||||
func (txOut TxOutput) ChainAndAddress() ([]byte, []byte, abci.Result) {
|
|
||||||
var chainPrefix []byte
|
|
||||||
address := txOut.Address
|
|
||||||
if len(address) > 20 {
|
|
||||||
spl := bytes.SplitN(address, []byte("/"), 2)
|
|
||||||
if len(spl) != 2 {
|
|
||||||
return nil, nil, abci.ErrBaseInvalidOutput.AppendLog("Invalid address format")
|
|
||||||
}
|
|
||||||
chainPrefix = spl[0]
|
|
||||||
address = spl[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(address) != 20 {
|
|
||||||
return nil, nil, abci.ErrBaseInvalidOutput.AppendLog("Invalid address length")
|
|
||||||
}
|
|
||||||
return chainPrefix, address, abci.OK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (txOut TxOutput) ValidateBasic() abci.Result {
|
|
||||||
_, _, r := txOut.ChainAndAddress()
|
|
||||||
if r.IsErr() {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
if !txOut.Coins.IsValid() {
|
|
||||||
return abci.ErrBaseInvalidOutput.AppendLog(Fmt("Invalid coins %v", txOut.Coins))
|
|
||||||
}
|
|
||||||
if txOut.Coins.IsZero() {
|
|
||||||
return abci.ErrBaseInvalidOutput.AppendLog("Coins cannot be zero")
|
|
||||||
}
|
|
||||||
return abci.OK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (txOut TxOutput) String() string {
|
|
||||||
return Fmt("TxOutput{%X,%v}", txOut.Address, txOut.Coins)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type SendTx struct {
|
|
||||||
Gas int64 `json:"gas"` // Gas
|
|
||||||
Fee Coin `json:"fee"` // Fee
|
|
||||||
Inputs []TxInput `json:"inputs"`
|
|
||||||
Outputs []TxOutput `json:"outputs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *SendTx) SignBytes(chainID string) []byte {
|
|
||||||
signBytes := wire.BinaryBytes(chainID)
|
|
||||||
sigz := make([]crypto.Signature, len(tx.Inputs))
|
|
||||||
for i := range tx.Inputs {
|
|
||||||
sigz[i] = tx.Inputs[i].Signature
|
|
||||||
tx.Inputs[i].Signature = crypto.Signature{}
|
|
||||||
}
|
|
||||||
signBytes = append(signBytes, wire.BinaryBytes(tx)...)
|
|
||||||
for i := range tx.Inputs {
|
|
||||||
tx.Inputs[i].Signature = sigz[i]
|
|
||||||
}
|
|
||||||
return signBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *SendTx) SetSignature(addr []byte, sig crypto.Signature) bool {
|
|
||||||
for i, input := range tx.Inputs {
|
|
||||||
if bytes.Equal(input.Address, addr) {
|
|
||||||
tx.Inputs[i].Signature = sig
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *SendTx) String() string {
|
|
||||||
return Fmt("SendTx{%v/%v %v->%v}", tx.Gas, tx.Fee, tx.Inputs, tx.Outputs)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type AppTx struct {
|
|
||||||
Gas int64 `json:"gas"` // Gas
|
|
||||||
Fee Coin `json:"fee"` // Fee
|
|
||||||
Name string `json:"type"` // Which plugin
|
|
||||||
Input TxInput `json:"input"` // Hmmm do we want coins?
|
|
||||||
Data json.RawMessage `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *AppTx) SignBytes(chainID string) []byte {
|
|
||||||
signBytes := wire.BinaryBytes(chainID)
|
|
||||||
sig := tx.Input.Signature
|
|
||||||
tx.Input.Signature = crypto.Signature{}
|
|
||||||
signBytes = append(signBytes, wire.BinaryBytes(tx)...)
|
|
||||||
tx.Input.Signature = sig
|
|
||||||
return signBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *AppTx) SetSignature(sig crypto.Signature) bool {
|
|
||||||
tx.Input.Signature = sig
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *AppTx) String() string {
|
|
||||||
return Fmt("AppTx{%v/%v %v %v %X}", tx.Gas, tx.Fee, tx.Name, tx.Input, tx.Data)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func TxID(chainID string, tx Tx) []byte {
|
|
||||||
signBytes := tx.SignBytes(chainID)
|
|
||||||
return wire.BinaryRipemd160(signBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Contract: This function is deterministic and completely reversible.
|
|
||||||
func jsonEscape(str string) string {
|
|
||||||
escapedBytes, err := json.Marshal(str)
|
|
||||||
if err != nil {
|
|
||||||
PanicSanity(Fmt("Error json-escaping a string", str))
|
|
||||||
}
|
|
||||||
return string(escapedBytes)
|
|
||||||
}
|
|
177
types/tx_test.go
177
types/tx_test.go
|
@ -1,177 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
data "github.com/tendermint/go-wire/data"
|
|
||||||
)
|
|
||||||
|
|
||||||
var chainID string = "test_chain"
|
|
||||||
|
|
||||||
func TestSendTxSignable(t *testing.T) {
|
|
||||||
sendTx := &SendTx{
|
|
||||||
Gas: 222,
|
|
||||||
Fee: Coin{"", 111},
|
|
||||||
Inputs: []TxInput{
|
|
||||||
TxInput{
|
|
||||||
Address: []byte("input1"),
|
|
||||||
Coins: Coins{{"", 12345}},
|
|
||||||
Sequence: 67890,
|
|
||||||
},
|
|
||||||
TxInput{
|
|
||||||
Address: []byte("input2"),
|
|
||||||
Coins: Coins{{"", 111}},
|
|
||||||
Sequence: 222,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []TxOutput{
|
|
||||||
TxOutput{
|
|
||||||
Address: []byte("output1"),
|
|
||||||
Coins: Coins{{"", 333}},
|
|
||||||
},
|
|
||||||
TxOutput{
|
|
||||||
Address: []byte("output2"),
|
|
||||||
Coins: Coins{{"", 444}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
signBytes := sendTx.SignBytes(chainID)
|
|
||||||
signBytesHex := fmt.Sprintf("%X", signBytes)
|
|
||||||
expected := "010A746573745F636861696E0100000000000000DE00000000000000006F01020106696E7075743101010000000000000030390301093200000106696E70757432010100000000000000006F01DE0000010201076F757470757431010100000000000000014D01076F75747075743201010000000000000001BC"
|
|
||||||
|
|
||||||
assert.Equal(t, signBytesHex, expected,
|
|
||||||
"Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppTxSignable(t *testing.T) {
|
|
||||||
callTx := &AppTx{
|
|
||||||
Gas: 222,
|
|
||||||
Fee: Coin{"", 111},
|
|
||||||
Name: "X",
|
|
||||||
Input: TxInput{
|
|
||||||
Address: []byte("input1"),
|
|
||||||
Coins: Coins{{"", 12345}},
|
|
||||||
Sequence: 67890,
|
|
||||||
},
|
|
||||||
Data: []byte("data1"),
|
|
||||||
}
|
|
||||||
signBytes := callTx.SignBytes(chainID)
|
|
||||||
signBytesHex := fmt.Sprintf("%X", signBytes)
|
|
||||||
expected := "010A746573745F636861696E0100000000000000DE00000000000000006F0101580106696E70757431010100000000000000303903010932000001056461746131"
|
|
||||||
|
|
||||||
assert.Equal(t, signBytesHex, expected,
|
|
||||||
"Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSendTxJSON(t *testing.T) {
|
|
||||||
assert, require := assert.New(t), require.New(t)
|
|
||||||
|
|
||||||
chainID := "test_chain_id"
|
|
||||||
test1PrivAcc := PrivAccountFromSecret("sendtx1")
|
|
||||||
test2PrivAcc := PrivAccountFromSecret("sendtx2")
|
|
||||||
|
|
||||||
// Construct a SendTx signature
|
|
||||||
tx := &SendTx{
|
|
||||||
Gas: 1,
|
|
||||||
Fee: Coin{"foo", 2},
|
|
||||||
Inputs: []TxInput{
|
|
||||||
NewTxInput(test1PrivAcc.PubKey, Coins{{"foo", 10}}, 1),
|
|
||||||
},
|
|
||||||
Outputs: []TxOutput{
|
|
||||||
TxOutput{
|
|
||||||
Address: test2PrivAcc.PubKey.Address(),
|
|
||||||
Coins: Coins{{"foo", 8}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// serialize this as json and back
|
|
||||||
js, err := data.ToJSON(TxS{tx})
|
|
||||||
require.Nil(err)
|
|
||||||
// fmt.Println(string(js))
|
|
||||||
txs := TxS{}
|
|
||||||
err = data.FromJSON(js, &txs)
|
|
||||||
require.Nil(err)
|
|
||||||
tx2, ok := txs.Tx.(*SendTx)
|
|
||||||
require.True(ok)
|
|
||||||
|
|
||||||
// make sure they are the same!
|
|
||||||
signBytes := tx.SignBytes(chainID)
|
|
||||||
signBytes2 := tx2.SignBytes(chainID)
|
|
||||||
assert.Equal(signBytes, signBytes2)
|
|
||||||
assert.Equal(tx, tx2)
|
|
||||||
|
|
||||||
// sign this thing
|
|
||||||
sig := test1PrivAcc.Sign(signBytes)
|
|
||||||
// we handle both raw sig and wrapped sig the same
|
|
||||||
tx.SetSignature(test1PrivAcc.PubKey.Address(), sig)
|
|
||||||
tx2.SetSignature(test1PrivAcc.PubKey.Address(), sig)
|
|
||||||
assert.Equal(tx, tx2)
|
|
||||||
|
|
||||||
// let's marshal / unmarshal this with signature
|
|
||||||
js, err = data.ToJSON(TxS{tx})
|
|
||||||
require.Nil(err)
|
|
||||||
// fmt.Println(string(js))
|
|
||||||
err = data.FromJSON(js, &txs)
|
|
||||||
require.Nil(err)
|
|
||||||
tx2, ok = txs.Tx.(*SendTx)
|
|
||||||
require.True(ok)
|
|
||||||
|
|
||||||
// and make sure the sig is preserved
|
|
||||||
assert.Equal(tx, tx2)
|
|
||||||
assert.False(tx2.Inputs[0].Signature.Empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSendTxIBC(t *testing.T) {
|
|
||||||
assert, require := assert.New(t), require.New(t)
|
|
||||||
|
|
||||||
good, err := hex.DecodeString("1960CA7E170862837AA8F22A947194F41F61860B")
|
|
||||||
require.Nil(err)
|
|
||||||
short, err := hex.DecodeString("1960CA7E170862837AA8F22F947194F41F610B")
|
|
||||||
require.Nil(err)
|
|
||||||
long, err := hex.DecodeString("1960CA7E170862837AA8F22F947194F41F6186120B")
|
|
||||||
require.Nil(err)
|
|
||||||
slash, err := hex.DecodeString("F40ECECEA86F29D0FDF2980EF72F1708687BD4BF")
|
|
||||||
require.Nil(err)
|
|
||||||
|
|
||||||
coins := Coins{{"atom", 5}}
|
|
||||||
|
|
||||||
addrs := []struct {
|
|
||||||
addr []byte
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{good, true},
|
|
||||||
{slash, true},
|
|
||||||
{long, false},
|
|
||||||
{short, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixes := []struct {
|
|
||||||
prefix []byte
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{nil, true},
|
|
||||||
{[]byte("chain-1/"), true},
|
|
||||||
{[]byte("chain/with/paths/"), false},
|
|
||||||
{[]byte("no-slash-here"), false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range addrs {
|
|
||||||
for j, pc := range prefixes {
|
|
||||||
addr := append(pc.prefix, tc.addr...)
|
|
||||||
output := TxOutput{Address: addr, Coins: coins}
|
|
||||||
res := output.ValidateBasic()
|
|
||||||
|
|
||||||
if tc.valid && pc.valid {
|
|
||||||
assert.True(res.IsOK(), "%d,%d: %s", i, j, res.Log)
|
|
||||||
} else {
|
|
||||||
assert.False(res.IsOK(), "%d,%d: %s", i, j, res.Log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue