diff --git a/app/app_test.go b/app/app_test.go index 2cb636e1c..048240be5 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -2,7 +2,6 @@ package app import ( "encoding/hex" - "encoding/json" "os" "testing" @@ -15,7 +14,6 @@ import ( "github.com/tendermint/basecoin/stack" "github.com/tendermint/basecoin/txs" "github.com/tendermint/basecoin/types" - crypto "github.com/tendermint/go-crypto" wire "github.com/tendermint/go-wire" eyes "github.com/tendermint/merkleeyes/client" "github.com/tendermint/tmlibs/log" @@ -28,8 +26,8 @@ type appTest struct { t *testing.T chainID string app *Basecoin - accIn types.PrivAccount - accOut types.PrivAccount + acctIn *coin.AccountWithKey + acctOut *coin.AccountWithKey } func newAppTest(t *testing.T) *appTest { @@ -41,32 +39,27 @@ func newAppTest(t *testing.T) *appTest { 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 { - addrIn := at.accIn.Account.PubKey.Address() - addrOut := at.accOut.Account.PubKey.Address() - - in := []coin.TxInput{{Address: stack.SigPerm(addrIn), Coins: coins, Sequence: seq}} - out := []coin.TxOutput{{Address: stack.SigPerm(addrOut), Coins: coins}} + in := []coin.TxInput{{Address: at.acctIn.Actor(), Coins: coins, Sequence: seq}} + out := []coin.TxOutput{{Address: at.acctOut.Actor(), Coins: coins}} tx := coin.NewSendTx(in, out) tx = txs.NewChain(at.chainID, tx) stx := txs.NewMulti(tx) - txs.Sign(stx, at.accIn.PrivKey) + txs.Sign(stx, at.acctIn.Key) return stx.Wrap() } // set the account on the app through SetOption -func (at *appTest) acc2app(acc types.Account) { - accBytes, err := json.Marshal(acc) - require.Nil(at.t, err) - res := at.app.SetOption("coin/account", string(accBytes)) +func (at *appTest) initAccount(acct *coin.AccountWithKey) { + res := at.app.SetOption("coin/account", acct.MakeOption()) require.EqualValues(at.t, res, "Success") } // reset the in and out accs to be one account each with 7mycoin func (at *appTest) reset() { - at.accIn = types.MakeAcc("input0") - at.accOut = types.MakeAcc("output0") + at.acctIn = coin.NewAccountWithKey(types.Coins{{"mycoin", 7}}) + at.acctOut = coin.NewAccountWithKey(types.Coins{{"mycoin", 7}}) eyesCli := eyes.NewLocalClient("", 0) // logger := log.TestingLogger().With("module", "app"), @@ -81,30 +74,30 @@ func (at *appTest) reset() { res := at.app.SetOption("base/chain_id", at.chainID) require.EqualValues(at.t, res, "Success") - at.acc2app(at.accIn.Account) - at.acc2app(at.accOut.Account) + at.initAccount(at.acctIn) + at.initAccount(at.acctOut) resabci := at.app.Commit() require.True(at.t, resabci.IsOK(), resabci) } -func getBalance(pk crypto.PubKey, state types.KVStore) (types.Coins, error) { - return getAddr(pk.Address(), state) +func getBalance(key basecoin.Actor, state types.KVStore) (types.Coins, error) { + acct, err := coin.NewAccountant("").GetAccount(state, key) + return acct.Coins, err } func getAddr(addr []byte, state types.KVStore) (types.Coins, error) { actor := stack.SigPerm(addr) - acct, err := coin.NewAccountant("").GetAccount(state, actor) - return acct.Coins, err + return getBalance(actor, state) } // 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) { 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) - initBalOut, err := getBalance(at.accOut.Account.PubKey, at.app.GetState()) + initBalOut, err := getBalance(at.acctOut.Actor(), at.app.GetState()) require.Nil(err, "%+v", err) 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) } - endBalIn, err := getBalance(at.accIn.Account.PubKey, at.app.GetState()) + endBalIn, err := getBalance(at.acctIn.Actor(), at.app.GetState()) 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) return res, endBalIn.Minus(initBalIn), endBalOut.Minus(initBalOut) } @@ -141,16 +134,15 @@ func TestSetOption(t *testing.T) { assert.EqualValues(res, "Success") // make a nice account... - accIn := types.MakeAcc("input0").Account - accsInBytes, err := json.Marshal(accIn) - assert.Nil(err) - res = app.SetOption("coin/account", string(accsInBytes)) + bal := types.Coins{{"atom", 77}, {"eth", 12}} + acct := coin.NewAccountWithKey(bal) + res = app.SetOption("coin/account", acct.MakeOption()) require.EqualValues(res, "Success") // 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) - assert.Equal(accIn.Balance, coins) + assert.Equal(bal, coins) // let's parse an account with badly sorted coins... unsortAddr, err := hex.DecodeString("C471FB670E44D219EE6DF2FC284BE38793ACBCE1") @@ -197,8 +189,8 @@ func TestTx(t *testing.T) { at := newAppTest(t) //Bad Balance - at.accIn.Balance = types.Coins{{"mycoin", 2}} - at.acc2app(at.accIn.Account) + at.acctIn.Coins = types.Coins{{"mycoin", 2}} + at.initAccount(at.acctIn) 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) 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{ Path: "/account", - Data: at.accIn.Account.PubKey.Address(), + Data: at.acctIn.Address(), }) res = at.app.Commit() @@ -237,7 +229,7 @@ func TestQuery(t *testing.T) { resQueryPostCommit := at.app.Query(abci.RequestQuery{ Path: "/account", - Data: at.accIn.Account.PubKey.Address(), + Data: at.acctIn.Address(), }) assert.NotEqual(resQueryPreCommit, resQueryPostCommit, "Query should change before/after commit") } diff --git a/cmd/basecoin/commands/plugin_util.go b/cmd/basecoin/commands/plugin_util.go deleted file mode 100644 index ee56d7b92..000000000 --- a/cmd/basecoin/commands/plugin_util.go +++ /dev/null @@ -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) - }, - } -} diff --git a/cmd/basecoin/commands/utils.go b/cmd/basecoin/commands/utils.go index a039f0014..8df68faac 100644 --- a/cmd/basecoin/commands/utils.go +++ b/cmd/basecoin/commands/utils.go @@ -1,19 +1,6 @@ package commands -import ( - "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" -) +import "encoding/hex" // Returns true for non-empty hex-string prefixed with "0x" func isHex(s string) bool { @@ -34,77 +21,3 @@ func StripHex(s string) string { } 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 -} diff --git a/cmd/basecoin/commands/version.go b/cmd/basecoin/commands/version.go index fe72d26ca..b45addae8 100644 --- a/cmd/basecoin/commands/version.go +++ b/cmd/basecoin/commands/version.go @@ -16,3 +16,14 @@ var VersionCmd = &cobra.Command{ 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) + }, + } +} diff --git a/docs/guide/counter/plugins/counter/counter_test.go b/docs/guide/counter/plugins/counter/counter_test.go index ceeb9a552..f839002a1 100644 --- a/docs/guide/counter/plugins/counter/counter_test.go +++ b/docs/guide/counter/plugins/counter/counter_test.go @@ -1,7 +1,6 @@ package counter import ( - "encoding/json" "os" "testing" @@ -9,6 +8,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/app" + "github.com/tendermint/basecoin/modules/coin" "github.com/tendermint/basecoin/txs" "github.com/tendermint/basecoin/types" "github.com/tendermint/go-wire" @@ -34,14 +34,9 @@ func TestCounterPlugin(t *testing.T) { bcApp.SetOption("base/chain_id", chainID) // Account initialization - test1PrivAcc := types.PrivAccountFromSecret("test1") - - // Seed Basecoin with account - 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)) + bal := types.Coins{{"", 1000}, {"gold", 1000}} + acct := coin.NewAccountWithKey(bal) + log := bcApp.SetOption("coin/account", acct.MakeOption()) require.Equal(t, "Success", log) // Deliver a CounterTx @@ -49,7 +44,7 @@ func TestCounterPlugin(t *testing.T) { tx := NewTx(valid, counterFee, inputSequence) tx = txs.NewChain(chainID, tx) stx := txs.NewSig(tx) - txs.Sign(stx, test1PrivAcc.PrivKey) + txs.Sign(stx, acct.Key) txBytes := wire.BinaryBytes(stx.Wrap()) return bcApp.DeliverTx(txBytes) } diff --git a/modules/coin/helper.go b/modules/coin/helper.go new file mode 100644 index 000000000..684affa36 --- /dev/null +++ b/modules/coin/helper.go @@ -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) +} diff --git a/state/state_test.go b/state/state_test.go index 4d3486c5b..171790d4a 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -20,9 +20,6 @@ func TestState(t *testing.T) { cache := state.CacheWrap() eyesCli := eyes.NewLocalClient("", 0) - acc := new(types.Account) - acc.Sequence = 1 - //reset the store/state/cache reset := func() { store = types.NewMemKVStore() diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go index 04a39f9f6..fbe4c2077 100644 --- a/tests/tendermint/main.go +++ b/tests/tendermint/main.go @@ -1,140 +1,142 @@ package main -import ( - "fmt" - "time" +func main() {} - "github.com/gorilla/websocket" - "github.com/tendermint/basecoin/types" - wire "github.com/tendermint/go-wire" - _ "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" -) +// import ( +// "fmt" +// "time" -func main() { - // ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket") - ws := rpcclient.NewWSClient("192.168.99.100:46657", "/websocket") - chainID := "test_chain_id" +// "github.com/gorilla/websocket" +// "github.com/tendermint/basecoin/types" +// wire "github.com/tendermint/go-wire" +// _ "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() - if err != nil { - cmn.Exit(err.Error()) - } - var counter = 0 +// func main() { +// // ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket") +// ws := rpcclient.NewWSClient("192.168.99.100:46657", "/websocket") +// chainID := "test_chain_id" - // Read a bunch of responses - go func() { - for { - res, ok := <-ws.ResultsCh - if !ok { - break - } - fmt.Println(counter, "res:", cmn.Blue(string(res))) - } - }() +// _, err := ws.Start() +// if err != nil { +// cmn.Exit(err.Error()) +// } +// var counter = 0 - // Get the root account - root := types.PrivAccountFromSecret("test") - sequence := int(0) - // Make a bunch of PrivAccounts - privAccounts := types.RandAccounts(1000, 1000000, 0) - privAccountSequences := make(map[string]int) +// // Read a bunch of responses +// go func() { +// for { +// res, ok := <-ws.ResultsCh +// if !ok { +// break +// } +// fmt.Println(counter, "res:", cmn.Blue(string(res))) +// } +// }() - // Send coins to each account - for i := 0; i < len(privAccounts); i++ { - privAccount := privAccounts[i] - tx := &types.SendTx{ - 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 +// // Get the root account +// root := types.PrivAccountFromSecret("test") +// sequence := int(0) +// // Make a bunch of PrivAccounts +// privAccounts := types.RandAccounts(1000, 1000000, 0) +// privAccountSequences := make(map[string]int) - // Sign request - signBytes := tx.SignBytes(chainID) - sig := root.Sign(signBytes) - tx.Inputs[0].Signature = sig - //fmt.Println("tx:", tx) +// // Send coins to each account +// for i := 0; i < len(privAccounts); i++ { +// privAccount := privAccounts[i] +// tx := &types.SendTx{ +// 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 - 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()) - } - } +// // Sign request +// signBytes := tx.SignBytes(chainID) +// sig := root.Sign(signBytes) +// tx.Inputs[0].Signature = sig +// //fmt.Println("tx:", tx) - // Now send coins between these accounts - for { - counter += 1 - time.Sleep(time.Millisecond * 10) +// // 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()) +// } +// } - randA := cmn.RandInt() % len(privAccounts) - randB := cmn.RandInt() % len(privAccounts) - if randA == randB { - continue - } +// // Now send coins between these accounts +// for { +// counter += 1 +// time.Sleep(time.Millisecond * 10) - privAccountA := privAccounts[randA] - privAccountASequence := privAccountSequences[privAccountA.Account.PubKey.KeyString()] - privAccountSequences[privAccountA.Account.PubKey.KeyString()] = privAccountASequence + 1 - privAccountB := privAccounts[randB] +// randA := cmn.RandInt() % len(privAccounts) +// randB := cmn.RandInt() % len(privAccounts) +// if randA == randB { +// continue +// } - tx := &types.SendTx{ - Inputs: []types.TxInput{ - types.TxInput{ - Address: privAccountA.Account.PubKey.Address(), - 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}}, - }, - }, - } +// privAccountA := privAccounts[randA] +// privAccountASequence := privAccountSequences[privAccountA.Account.PubKey.KeyString()] +// privAccountSequences[privAccountA.Account.PubKey.KeyString()] = privAccountASequence + 1 +// privAccountB := privAccounts[randB] - // Sign request - signBytes := tx.SignBytes(chainID) - sig := privAccountA.Sign(signBytes) - tx.Inputs[0].Signature = sig - //fmt.Println("tx:", tx) +// tx := &types.SendTx{ +// Inputs: []types.TxInput{ +// types.TxInput{ +// Address: privAccountA.Account.PubKey.Address(), +// 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 - 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()) - } - } +// // Sign request +// signBytes := tx.SignBytes(chainID) +// sig := privAccountA.Sign(signBytes) +// tx.Inputs[0].Signature = sig +// //fmt.Println("tx:", tx) - 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() +// } diff --git a/types/account.go b/types/account.go deleted file mode 100644 index ec4154fc4..000000000 --- a/types/account.go +++ /dev/null @@ -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) -} diff --git a/types/account_test.go b/types/account_test.go deleted file mode 100644 index 6bcb997d8..000000000 --- a/types/account_test.go +++ /dev/null @@ -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() -} diff --git a/types/plugin.go b/types/plugin.go deleted file mode 100644 index 9783f2c7c..000000000 --- a/types/plugin.go +++ /dev/null @@ -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 -} diff --git a/types/plugin_test.go b/types/plugin_test.go deleted file mode 100644 index 071ed2974..000000000 --- a/types/plugin_test.go +++ /dev/null @@ -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") -} diff --git a/types/test_helpers.go b/types/test_helpers.go index 2b7be27a9..7bcccc11a 100644 --- a/types/test_helpers.go +++ b/types/test_helpers.go @@ -1,105 +1,105 @@ package types -// Helper functions for testing +// // Helper functions for testing -import ( - "github.com/tendermint/go-crypto" - cmn "github.com/tendermint/tmlibs/common" -) +// import ( +// "github.com/tendermint/go-crypto" +// cmn "github.com/tendermint/tmlibs/common" +// ) -// Creates a PrivAccount from secret. -// The amount is not set. -func PrivAccountFromSecret(secret string) PrivAccount { - privKey := - crypto.GenPrivKeyEd25519FromSecret([]byte(secret)).Wrap() - privAccount := PrivAccount{ - PrivKey: privKey, - Account: Account{ - PubKey: privKey.PubKey(), - }, - } - return privAccount -} +// // Creates a PrivAccount from secret. +// // The amount is not set. +// func PrivAccountFromSecret(secret string) PrivAccount { +// privKey := +// crypto.GenPrivKeyEd25519FromSecret([]byte(secret)).Wrap() +// privAccount := PrivAccount{ +// PrivKey: privKey, +// Account: Account{ +// PubKey: privKey.PubKey(), +// }, +// } +// return privAccount +// } -// Make `num` random accounts -func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount { - privAccs := make([]PrivAccount, num) - for i := 0; i < num; i++ { +// // Make `num` random accounts +// func RandAccounts(num int, minAmount int64, maxAmount int64) []PrivAccount { +// privAccs := make([]PrivAccount, num) +// for i := 0; i < num; i++ { - balance := minAmount - if maxAmount > minAmount { - balance += cmn.RandInt64() % (maxAmount - minAmount) - } +// balance := minAmount +// if maxAmount > minAmount { +// balance += cmn.RandInt64() % (maxAmount - minAmount) +// } - privKey := crypto.GenPrivKeyEd25519().Wrap() - pubKey := privKey.PubKey() - privAccs[i] = PrivAccount{ - PrivKey: privKey, - Account: Account{ - PubKey: pubKey, - Balance: Coins{Coin{"", balance}}, - }, - } - } +// privKey := crypto.GenPrivKeyEd25519().Wrap() +// pubKey := privKey.PubKey() +// privAccs[i] = PrivAccount{ +// PrivKey: privKey, +// Account: Account{ +// PubKey: pubKey, +// Balance: Coins{Coin{"", balance}}, +// }, +// } +// } - return privAccs -} +// return privAccs +// } -///////////////////////////////////////////////////////////////// +// ///////////////////////////////////////////////////////////////// -//func MakeAccs(secrets ...string) (accs []PrivAccount) { -// for _, secret := range secrets { -// privAcc := PrivAccountFromSecret(secret) -// privAcc.Account.Balance = Coins{{"mycoin", 7}} -// accs = append(accs, privAcc) -// } -// return -//} +// //func MakeAccs(secrets ...string) (accs []PrivAccount) { +// // for _, secret := range secrets { +// // privAcc := PrivAccountFromSecret(secret) +// // privAcc.Account.Balance = Coins{{"mycoin", 7}} +// // accs = append(accs, privAcc) +// // } +// // return +// //} -func MakeAcc(secret string) PrivAccount { - privAcc := PrivAccountFromSecret(secret) - privAcc.Account.Balance = Coins{{"mycoin", 7}} - return privAcc -} +// func MakeAcc(secret string) PrivAccount { +// privAcc := PrivAccountFromSecret(secret) +// privAcc.Account.Balance = Coins{{"mycoin", 7}} +// return privAcc +// } -func Accs2TxInputs(seq int, accs ...PrivAccount) []TxInput { - var txs []TxInput - for _, acc := range accs { - tx := NewTxInput( - acc.Account.PubKey, - Coins{{"mycoin", 5}}, - seq) - txs = append(txs, tx) - } - return txs -} +// func Accs2TxInputs(seq int, accs ...PrivAccount) []TxInput { +// var txs []TxInput +// for _, acc := range accs { +// tx := NewTxInput( +// acc.Account.PubKey, +// Coins{{"mycoin", 5}}, +// seq) +// txs = append(txs, tx) +// } +// return txs +// } -//turn a list of accounts into basic list of transaction outputs -func Accs2TxOutputs(accs ...PrivAccount) []TxOutput { - var txs []TxOutput - for _, acc := range accs { - tx := TxOutput{ - acc.Account.PubKey.Address(), - Coins{{"mycoin", 4}}} - txs = append(txs, tx) - } - return txs -} +// //turn a list of accounts into basic list of transaction outputs +// func Accs2TxOutputs(accs ...PrivAccount) []TxOutput { +// var txs []TxOutput +// for _, acc := range accs { +// tx := TxOutput{ +// acc.Account.PubKey.Address(), +// Coins{{"mycoin", 4}}} +// txs = append(txs, tx) +// } +// return txs +// } -func MakeSendTx(seq int, accOut PrivAccount, accsIn ...PrivAccount) *SendTx { - tx := &SendTx{ - Gas: 0, - Fee: Coin{"mycoin", 1}, - Inputs: Accs2TxInputs(seq, accsIn...), - Outputs: Accs2TxOutputs(accOut), - } +// func MakeSendTx(seq int, accOut PrivAccount, accsIn ...PrivAccount) *SendTx { +// tx := &SendTx{ +// Gas: 0, +// Fee: Coin{"mycoin", 1}, +// Inputs: Accs2TxInputs(seq, accsIn...), +// Outputs: Accs2TxOutputs(accOut), +// } - return tx -} +// return tx +// } -func SignTx(chainID string, tx *SendTx, accs ...PrivAccount) { - signBytes := tx.SignBytes(chainID) - for i, _ := range tx.Inputs { - tx.Inputs[i].Signature = accs[i].Sign(signBytes) - } -} +// func SignTx(chainID string, tx *SendTx, accs ...PrivAccount) { +// signBytes := tx.SignBytes(chainID) +// for i, _ := range tx.Inputs { +// tx.Inputs[i].Signature = accs[i].Sign(signBytes) +// } +// } diff --git a/types/tx.go b/types/tx.go deleted file mode 100644 index 4d1455d7a..000000000 --- a/types/tx.go +++ /dev/null @@ -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) -} diff --git a/types/tx_test.go b/types/tx_test.go deleted file mode 100644 index 73ccbf54d..000000000 --- a/types/tx_test.go +++ /dev/null @@ -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) - } - } - } - -}