Removed a whole lot of old crud
This commit is contained in:
parent
5c813833a0
commit
912c24093f
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
eyesCli := eyes.NewLocalClient("", 0)
|
||||
|
||||
acc := new(types.Account)
|
||||
acc.Sequence = 1
|
||||
|
||||
//reset the store/state/cache
|
||||
reset := func() {
|
||||
store = types.NewMemKVStore()
|
||||
|
|
|
@ -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()
|
||||
// }
|
||||
|
|
|
@ -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
|
||||
|
||||
// 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 {
|
||||
// //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}}
|
||||
// accs = append(accs, privAcc)
|
||||
// return privAcc
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
|
||||
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)
|
||||
// }
|
||||
// }
|
||||
|
|
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