From 7c481f8c724c09a295b27b47f99b64f5ae3f31c7 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 13 Feb 2017 16:50:17 +0100 Subject: [PATCH 01/49] Add /account path to query --- app/app.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/app.go b/app/app.go index 621d17a6ec..492aa3a024 100644 --- a/app/app.go +++ b/app/app.go @@ -130,6 +130,12 @@ func (app *Basecoin) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQu return } + // handle special path for account info + if reqQuery.Path == "/account" { + reqQuery.Path = "/key" + reqQuery.Data = append([]byte("base/a/"), reqQuery.Data...) + } + resQuery, err := app.eyesCli.QuerySync(reqQuery) if err != nil { resQuery.Log = "Failed to query MerkleEyes: " + err.Error() From 50e787af0a331eab8c97f9791d2c0ba1e1ed264d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 9 Feb 2017 19:46:50 -0500 Subject: [PATCH 02/49] added query subcommand register --- cmd/commands/query.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/commands/query.go b/cmd/commands/query.go index 41635e2882..d8fd980f2b 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -66,6 +66,11 @@ var ( } ) +// Register a subcommand of TxCmd to craft transactions for plugins +func RegisterQuerySubcommand(cmd cli.Command) { + QueryCmd.Subcommands = append(QueryCmd.Subcommands, cmd) +} + func cmdQuery(c *cli.Context) error { if len(c.Args()) != 1 { return errors.New("query command requires an argument ([key])") From e3302bb1bb8ffc5f2f310b6ea1f63237cbfee362 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 9 Feb 2017 21:48:42 -0500 Subject: [PATCH 03/49] CLI fee and amount now use string inputs specifying the coin type readme update intermin --- README.md | 2 +- cmd/commands/flags.go | 18 +++----- cmd/commands/tx.go | 56 +++++++++++++++---------- cmd/commands/utils.go | 44 ++++++++++++++++++- docs/guide/src/example-plugin/plugin.go | 2 +- plugins/counter/counter_test.go | 2 +- 6 files changed, 87 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index c6303458aa..b765165b61 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This will create the `basecoin` binary in `$GOPATH/bin`. The basecoin CLI can be used to start a stand-alone basecoin instance (`basecoin start`), or to start basecoin with Tendermint in the same process (`basecoin start --in-proc`). -It can also be used to send transactions, eg. `basecoin tx send --to 0x4793A333846E5104C46DD9AB9A00E31821B2F301 --amount 100` +It can also be used to send transactions, eg. `basecoin tx send --to 0x4793A333846E5104C46DD9AB9A00E31821B2F301 --amount 100btc,10gold` See `basecoin --help` and `basecoin [cmd] --help` for more details`. ## Learn more diff --git a/cmd/commands/flags.go b/cmd/commands/flags.go index 00aae351cd..980c0b67a1 100644 --- a/cmd/commands/flags.go +++ b/cmd/commands/flags.go @@ -48,10 +48,10 @@ var ( Usage: "Destination address for the transaction", } - AmountFlag = cli.IntFlag{ + AmountFlag = cli.StringFlag{ Name: "amount", - Value: 0, - Usage: "Amount of coins to send in the transaction", + Value: "", + Usage: "Coins to send in transaction of the format ,,... (eg: 1gold,2silver,5btc)", } FromFlag = cli.StringFlag{ @@ -66,22 +66,16 @@ var ( Usage: "Sequence number for the account", } - CoinFlag = cli.StringFlag{ - Name: "coin", - Value: "mycoin", - Usage: "Specify a coin denomination", - } - GasFlag = cli.IntFlag{ Name: "gas", Value: 0, Usage: "The amount of gas for the transaction", } - FeeFlag = cli.IntFlag{ + FeeFlag = cli.StringFlag{ Name: "fee", - Value: 0, - Usage: "The transaction fee", + Value: "", + Usage: "Coins for the transaction fee of the format ,,... (eg: 1gold,2silver,5btc)", } DataFlag = cli.StringFlag{ diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index 9b8ce21cd8..f54b6d0c27 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -23,7 +23,6 @@ var TxFlags = []cli.Flag{ FromFlag, AmountFlag, - CoinFlag, GasFlag, FeeFlag, SeqFlag, @@ -71,9 +70,9 @@ func RegisterTxSubcommand(cmd cli.Command) { func cmdSendTx(c *cli.Context) error { toHex := c.String("to") fromFile := c.String("from") - amount := int64(c.Int("amount")) - coin := c.String("coin") - gas, fee := c.Int("gas"), int64(c.Int("fee")) + amount := c.String("amount") + gas := int64(c.Int("gas")) + fee := c.String("fee") chainID := c.String("chain_id") // convert destination address to bytes @@ -91,12 +90,22 @@ func cmdSendTx(c *cli.Context) error { return err } + //parse the fee and amounts into coin types + feeCoin, err := ParseCoin(fee) + if err != nil { + return err + } + amountCoins, err := ParseCoins(amount) + if err != nil { + return err + } + // craft the tx - input := types.NewTxInput(privKey.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) - output := newOutput(to, coin, amount) + input := types.NewTxInput(privKey.PubKey, amountCoins, sequence) + output := newOutput(to, amountCoins) tx := &types.SendTx{ - Gas: int64(gas), - Fee: types.Coin{coin, fee}, + Gas: gas, + Fee: feeCoin, Inputs: []types.TxInput{input}, Outputs: []types.TxOutput{output}, } @@ -128,9 +137,9 @@ func cmdAppTx(c *cli.Context) error { func AppTx(c *cli.Context, name string, data []byte) error { fromFile := c.String("from") - amount := int64(c.Int("amount")) - coin := c.String("coin") - gas, fee := c.Int("gas"), int64(c.Int("fee")) + amount := c.String("amount") + fee := c.String("fee") + gas := int64(c.Int("gas")) chainID := c.String("chain_id") privKey := tmtypes.LoadPrivValidator(fromFile) @@ -140,10 +149,20 @@ func AppTx(c *cli.Context, name string, data []byte) error { return err } - input := types.NewTxInput(privKey.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) + //parse the fee and amounts into coin types + feeCoin, err := ParseCoin(fee) + if err != nil { + return err + } + amountCoins, err := ParseCoins(amount) + if err != nil { + return err + } + + input := types.NewTxInput(privKey.PubKey, amountCoins, sequence) tx := &types.AppTx{ - Gas: int64(gas), - Fee: types.Coin{coin, fee}, + Gas: gas, + Fee: feeCoin, Name: name, Input: input, Data: data, @@ -205,15 +224,10 @@ func getSeq(c *cli.Context, address []byte) (int, error) { return acc.Sequence + 1, nil } -func newOutput(to []byte, coin string, amount int64) types.TxOutput { +func newOutput(to []byte, amount types.Coins) types.TxOutput { return types.TxOutput{ Address: to, - Coins: types.Coins{ - types.Coin{ - Denom: coin, - Amount: amount, - }, - }, + Coins: amount, } } diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 92a805734a..fa57267b34 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -3,9 +3,13 @@ package commands import ( "encoding/hex" "errors" + "regexp" + "strconv" + "strings" "github.com/urfave/cli" + "github.com/tendermint/basecoin/state" "github.com/tendermint/basecoin/types" abci "github.com/tendermint/abci/types" @@ -35,6 +39,44 @@ func StripHex(s string) string { return s } +func ParseCoin(str string) (types.Coin, error) { + + var coin types.Coin + + coins, err := ParseCoins(str) + + if err != nil { + return coin, err + } + + if len(coins) > 0 { + coin = coins[0] + } + + return coin, nil +} + +//regex codes from +var reAmt = regexp.MustCompile("(\\d+)") +var reCoin = regexp.MustCompile("([^\\d\\W]+)") + +func ParseCoins(str string) (types.Coins, error) { + + split := strings.Split(str, ",") + var coins []types.Coin + + for _, el := range split { + amt, err := strconv.Atoi(reAmt.FindString(el)) + if err != nil { + return coins, err + } + coin := reCoin.FindString(el) + coins = append(coins, types.Coin{coin, int64(amt)}) + } + + return coins, nil +} + func Query(tmAddr string, key []byte) (*abci.ResponseQuery, error) { clientURI := client.NewClientURI(tmAddr) tmResult := new(ctypes.TMResult) @@ -58,7 +100,7 @@ func Query(tmAddr string, key []byte) (*abci.ResponseQuery, error) { // fetch the account by querying the app func getAcc(tmAddr string, address []byte) (*types.Account, error) { - key := append([]byte("base/a/"), address...) + key := state.AccountKey(address) response, err := Query(tmAddr, key) if err != nil { return nil, err diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go index e930ffbf90..f6fd5d6a62 100644 --- a/docs/guide/src/example-plugin/plugin.go +++ b/docs/guide/src/example-plugin/plugin.go @@ -69,7 +69,7 @@ func (ep *ExamplePlugin) RunTx(store types.KVStore, ctx types.CallContext, txByt return abci.OK } -func (ep *ExamplePlugin) InitChain(store types.KVStore, vals []*abci.Validator) { +func (cp *ExamplePlugin) InitChain(store types.KVStore, vals []*abci.Validator) { } func (ep *ExamplePlugin) BeginBlock(store types.KVStore, hash []byte, header *abci.Header) { diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index 0b8ee4a866..a4c4236230 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -39,7 +39,7 @@ func TestCounterPlugin(t *testing.T) { tx := &types.AppTx{ Gas: gas, Fee: fee, - Name: "counter", + Name: counterPlugin.Name(), Input: types.NewTxInput(test1Acc.PubKey, inputCoins, inputSequence), Data: wire.BinaryBytes(CounterTx{Valid: true, Fee: appFee}), } From d2ac609fa3599c195f760aa70a69acca1f9693ca Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Feb 2017 12:06:12 -0500 Subject: [PATCH 04/49] CLI no coins sent fix --- cmd/commands/utils.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index fa57267b34..1196fe375b 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -66,12 +66,14 @@ func ParseCoins(str string) (types.Coins, error) { var coins []types.Coin for _, el := range split { - amt, err := strconv.Atoi(reAmt.FindString(el)) - if err != nil { - return coins, err + if len(el) > 0 { + amt, err := strconv.Atoi(reAmt.FindString(el)) + if err != nil { + return coins, err + } + coin := reCoin.FindString(el) + coins = append(coins, types.Coin{coin, int64(amt)}) } - coin := reCoin.FindString(el) - coins = append(coins, types.Coin{coin, int64(amt)}) } return coins, nil From c835ebf650caeb0f778f75979975cfc81351f04f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Feb 2017 13:53:40 -0500 Subject: [PATCH 05/49] Fix Coin.IsGTE logic bug flag redescription --- cmd/commands/flags.go | 4 ++-- types/coin.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/commands/flags.go b/cmd/commands/flags.go index 980c0b67a1..0c4c477707 100644 --- a/cmd/commands/flags.go +++ b/cmd/commands/flags.go @@ -51,7 +51,7 @@ var ( AmountFlag = cli.StringFlag{ Name: "amount", Value: "", - Usage: "Coins to send in transaction of the format ,,... (eg: 1gold,2silver,5btc)", + Usage: "Coins to send in transaction of the format ,,... (eg: 1btc,2gold,5silver)", } FromFlag = cli.StringFlag{ @@ -75,7 +75,7 @@ var ( FeeFlag = cli.StringFlag{ Name: "fee", Value: "", - Usage: "Coins for the transaction fee of the format ,,... (eg: 1gold,2silver,5btc)", + Usage: "Coins for the transaction fee of the format ", } DataFlag = cli.StringFlag{ diff --git a/types/coin.go b/types/coin.go index 23dc8f0868..b64f78bc97 100644 --- a/types/coin.go +++ b/types/coin.go @@ -100,7 +100,7 @@ func (coinsA Coins) IsGTE(coinsB Coins) bool { if len(diff) == 0 { return true } - return diff.IsPositive() + return diff.IsNonnegative() } func (coins Coins) IsZero() bool { From 05c975e7feccf01afab28d8df542d7b3ef909e79 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Feb 2017 16:51:09 -0500 Subject: [PATCH 06/49] comment update --- cmd/commands/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/commands/query.go b/cmd/commands/query.go index d8fd980f2b..97eff67277 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -66,7 +66,7 @@ var ( } ) -// Register a subcommand of TxCmd to craft transactions for plugins +// Register a subcommand of QueryCmd for plugin specific query functionality func RegisterQuerySubcommand(cmd cli.Command) { QueryCmd.Subcommands = append(QueryCmd.Subcommands, cmd) } From 49c3ab0828df516869406340c33b5d4e54071677 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 10 Feb 2017 18:02:27 -0500 Subject: [PATCH 07/49] addressed ebuchman comments --- cmd/commands/utils.go | 28 ++++++++++++------------- docs/guide/basecoin-basics.md | 8 +++---- docs/guide/example-plugin.md | 19 ++++++++--------- docs/guide/ibc.md | 8 +++---- docs/guide/src/example-plugin/plugin.go | 2 +- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 1196fe375b..0cbd5c8d76 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -39,27 +39,26 @@ func StripHex(s string) string { return s } +//regex codes for extracting coins from CLI input +var reDenom = regexp.MustCompile("([^\\d\\W]+)") +var reAmt = regexp.MustCompile("(\\d+)") + func ParseCoin(str string) (types.Coin, error) { var coin types.Coin - coins, err := ParseCoins(str) - - if err != nil { - return coin, err - } - - if len(coins) > 0 { - coin = coins[0] + if len(str) > 0 { + amt, err := strconv.Atoi(reAmt.FindString(str)) + if err != nil { + return coin, err + } + denom := reDenom.FindString(str) + coin = types.Coin{denom, int64(amt)} } return coin, nil } -//regex codes from -var reAmt = regexp.MustCompile("(\\d+)") -var reCoin = regexp.MustCompile("([^\\d\\W]+)") - func ParseCoins(str string) (types.Coins, error) { split := strings.Split(str, ",") @@ -67,12 +66,11 @@ func ParseCoins(str string) (types.Coins, error) { for _, el := range split { if len(el) > 0 { - amt, err := strconv.Atoi(reAmt.FindString(el)) + coin, err := ParseCoin(el) if err != nil { return coins, err } - coin := reCoin.FindString(el) - coins = append(coins, types.Coin{coin, int64(amt)}) + coins = append(coins, coin) } } diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 400136b496..f09213daa9 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -91,14 +91,14 @@ The first account is flush with cash, while the second account doesn't exist. Let's send funds from the first account to the second: ``` -basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10 +basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10blank ``` By default, the CLI looks for a `priv_validator.json` to sign the transaction with, so this will only work if you are in the `$GOPATH/src/github.com/tendermint/basecoin/data`. To specify a different key, we can use the `--from` flag. -Now if we check the second account, it should have `10` coins! +Now if we check the second account, it should have `10` 'blank' coins! ``` basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 @@ -107,7 +107,7 @@ basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 We can send some of these coins back like so: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5 +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5blank ``` Note how we use the `--from` flag to select a different account to send from. @@ -115,7 +115,7 @@ Note how we use the `--from` flag to select a different account to send from. If we try to send too much, we'll get an error: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100 +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100blank ``` See `basecoin tx send --help` for additional details. diff --git a/docs/guide/example-plugin.md b/docs/guide/example-plugin.md index b08f336fb7..28368bf3bb 100644 --- a/docs/guide/example-plugin.md +++ b/docs/guide/example-plugin.md @@ -132,10 +132,9 @@ OPTIONS: --node value Tendermint RPC address (default: "tcp://localhost:46657") --chain_id value ID of the chain for replay protection (default: "test_chain_id") --from value Path to a private key to sign the transaction (default: "key.json") - --amount value Amount of coins to send in the transaction (default: 0) - --coin value Specify a coin denomination (default: "mycoin") + --amount value Coins to send in transaction of the format ,,... (eg: 1btc,2gold,5silver) --gas value The amount of gas for the transaction (default: 0) - --fee value The transaction fee (default: 0) + --fee value Coins for the transaction fee of the format --sequence value Sequence number for the account (default: 0) --valid Set this to make the transaction valid ``` @@ -363,25 +362,25 @@ example-plugin start --in-proc In another window, we can try sending some transactions: ``` -example-plugin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --amount 100 --coin gold --chain_id example-chain +example-plugin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --amount 100gold --chain_id example-chain ``` -Note the `--coin` and `--chain_id` flags. In the [previous tutorial](basecoin-basics.md), -we didn't need them because we were using the default coin type ("mycoin") and chain ID ("test_chain_id"). -Now that we're using custom values, we need to specify them explicitly on the command line. +Note the `--chain_id` flag. In the [previous tutorial](basecoin-basics.md), +we didn't include it because we were using the default chain ID ("test_chain_id"). +Now that we're using a custom chain, we need to specify the chain explicitly on the command line. Ok, so that's how we can send a `SendTx` transaction using our `example-plugin` CLI, but we were already able to do that with the `basecoin` CLI. With our new CLI, however, we can also send an `ExamplePluginTx`: ``` -example-plugin tx example --amount 1 --coin gold --chain_id example-chain +example-plugin tx example --amount 1gold --chain_id example-chain ``` The transaction is invalid! That's because we didn't specify the `--valid` flag: ``` -example-plugin tx example --valid --amount 1 --coin gold --chain_id example-chain +example-plugin tx example --valid --amount 1gold --chain_id example-chain ``` Tada! We successfuly created, signed, broadcast, and processed our custom transaction type. @@ -401,7 +400,7 @@ which contains only an integer. If we send another transaction, and then query again, we'll see the value increment: ``` -example-plugin tx example --valid --amount 1 --coin gold --chain_id example-chain +example-plugin tx example --valid --amount 1gold --chain_id example-chain example-plugin query ExamplePlugin.State ``` diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 4bd3228140..36ae260877 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -236,13 +236,13 @@ export CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from ./data/chain2/basecoin/key.jso Let's start by registering `test_chain_1` on `test_chain_2`: ``` -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json +basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json ``` Now we can create the outgoing packet on `test_chain_1`: ``` -basecoin tx ibc --amount 10 $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --sequence 1 +basecoin tx ibc --amount 10blank $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --sequence 1 ``` Note our payload is just `DEADBEEF`. @@ -270,7 +270,7 @@ The former is used as input for later commands; the latter is human-readable, so Let's send this updated information about `test_chain_1` to `test_chain_2`: ``` -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 update --header 0x
--commit 0x +basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 update --header 0x
--commit 0x ``` where `
` and `` are the hex-encoded header and commit returned by the previous `block` command. @@ -280,7 +280,7 @@ along with proof the packet was committed on `test_chain_1`. Since `test_chain_2 of `test_chain_1`, it will be able to verify the proof! ``` -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height --packet 0x --proof 0x +basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height --packet 0x --proof 0x ``` Here, `` is one greater than the height retuned by the previous `query` command, and `` and `` are the diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go index f6fd5d6a62..e930ffbf90 100644 --- a/docs/guide/src/example-plugin/plugin.go +++ b/docs/guide/src/example-plugin/plugin.go @@ -69,7 +69,7 @@ func (ep *ExamplePlugin) RunTx(store types.KVStore, ctx types.CallContext, txByt return abci.OK } -func (cp *ExamplePlugin) InitChain(store types.KVStore, vals []*abci.Validator) { +func (ep *ExamplePlugin) InitChain(store types.KVStore, vals []*abci.Validator) { } func (ep *ExamplePlugin) BeginBlock(store types.KVStore, hash []byte, header *abci.Header) { From 0cf7ce2f23114037cbc7d06b4dbf44cb84b7ffa0 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 16 Feb 2017 18:03:01 +0100 Subject: [PATCH 08/49] Print warning when no genesis file found --- cmd/commands/start.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/commands/start.go b/cmd/commands/start.go index 9996e551c9..16e47fa602 100644 --- a/cmd/commands/start.go +++ b/cmd/commands/start.go @@ -2,6 +2,7 @@ package commands import ( "errors" + "fmt" "os" "path" @@ -83,6 +84,8 @@ func cmdStart(c *cli.Context) error { if err != nil { return errors.New(cmn.Fmt("%+v", err)) } + } else { + fmt.Printf("No genesis file at %s, skipping...\n", genesisFile) } if c.Bool("in-proc") { From 6a21ad51440197d302bdcd09608a7b3b27688587 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Feb 2017 00:13:04 -0500 Subject: [PATCH 09/49] tests, now uses mycoin whoops --- cmd/commands/utils_test.go | 40 +++++++++++++++++++++++++++++++++++ docs/guide/basecoin-basics.md | 8 +++---- docs/guide/ibc.md | 8 +++---- 3 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 cmd/commands/utils_test.go diff --git a/cmd/commands/utils_test.go b/cmd/commands/utils_test.go new file mode 100644 index 0000000000..c530b04a14 --- /dev/null +++ b/cmd/commands/utils_test.go @@ -0,0 +1,40 @@ +package commands + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tendermint/basecoin/types" +) + +//Test the parse coin and parse coins functionality +func TestParse(t *testing.T) { + + makeCoin := func(str string) types.Coin { + coin, err := ParseCoin(str) + if err != nil { + panic(err.Error()) + } + return coin + } + + makeCoins := func(str string) types.Coins { + coin, err := ParseCoins(str) + if err != nil { + panic(err.Error()) + } + return coin + } + + //testing ParseCoin Function + assert.True(t, types.Coin{} == makeCoin(""), "parseCoin makes bad empty coin") + assert.True(t, types.Coin{"fooCoin", 1} == makeCoin("1fooCoin"), "parseCoin makes bad coins") + assert.True(t, types.Coin{"barCoin", 10} == makeCoin("10 barCoin"), "parseCoin makes bad coins") + + //testing ParseCoins Function + assert.True(t, types.Coins{{"fooCoin", 1}}.IsEqual(makeCoins("1fooCoin")), "parseCoins doesn't parse a single coin") + assert.True(t, types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99barCoin,1fooCoin")), + "parseCoins doesn't properly parse two coins") + assert.True(t, types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99 barCoin, 1 fooCoin")), + "parseCoins doesn't properly parse two coins which use spaces") +} diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index f09213daa9..585b0a00ae 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -91,14 +91,14 @@ The first account is flush with cash, while the second account doesn't exist. Let's send funds from the first account to the second: ``` -basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10blank +basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10mycoin ``` By default, the CLI looks for a `priv_validator.json` to sign the transaction with, so this will only work if you are in the `$GOPATH/src/github.com/tendermint/basecoin/data`. To specify a different key, we can use the `--from` flag. -Now if we check the second account, it should have `10` 'blank' coins! +Now if we check the second account, it should have `10` 'mycoin' coins! ``` basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 @@ -107,7 +107,7 @@ basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 We can send some of these coins back like so: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5blank +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5mycoin ``` Note how we use the `--from` flag to select a different account to send from. @@ -115,7 +115,7 @@ Note how we use the `--from` flag to select a different account to send from. If we try to send too much, we'll get an error: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100blank +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100mycoin ``` See `basecoin tx send --help` for additional details. diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 36ae260877..718754363c 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -236,13 +236,13 @@ export CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from ./data/chain2/basecoin/key.jso Let's start by registering `test_chain_1` on `test_chain_2`: ``` -basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json ``` Now we can create the outgoing packet on `test_chain_1`: ``` -basecoin tx ibc --amount 10blank $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --sequence 1 +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --sequence 1 ``` Note our payload is just `DEADBEEF`. @@ -270,7 +270,7 @@ The former is used as input for later commands; the latter is human-readable, so Let's send this updated information about `test_chain_1` to `test_chain_2`: ``` -basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 update --header 0x
--commit 0x +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x
--commit 0x ``` where `
` and `` are the hex-encoded header and commit returned by the previous `block` command. @@ -280,7 +280,7 @@ along with proof the packet was committed on `test_chain_1`. Since `test_chain_2 of `test_chain_1`, it will be able to verify the proof! ``` -basecoin tx ibc --amount 10blank $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height --packet 0x --proof 0x +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height --packet 0x --proof 0x ``` Here, `` is one greater than the height retuned by the previous `query` command, and `` and `` are the From 1d8f59644f80db6a3a22fc8ba0ea84a146d47389 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 17 Feb 2017 13:16:11 +0100 Subject: [PATCH 10/49] Updated dependencies --- app/app.go | 4 ++-- glide.lock | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/app.go b/app/app.go index 492aa3a024..59f9003478 100644 --- a/app/app.go +++ b/app/app.go @@ -196,7 +196,7 @@ func splitKey(key string) (prefix string, suffix string) { } // (not meant to be called) -// assert that Basecoin implements `abci.BlockchainAware` at compile-time -func _assertABCIBlockchainAware(basecoin *Basecoin) abci.BlockchainAware { +// assert that Basecoin implements `abci.Application` at compile-time +func _assertABCIApplication(basecoin *Basecoin) abci.Application { return basecoin } diff --git a/glide.lock b/glide.lock index e14238be1f..90bae6db42 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-01-29T22:09:11.408245895-08:00 +updated: 2017-02-17T13:24:05.234809983+01:00 imports: - name: github.com/btcsuite/btcd version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 @@ -14,23 +14,23 @@ imports: - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 1f49d83d9aa00e6ce4fc8258c71cc7786aec968a + version: 8ee79997227bf9b34611aee7946ae64735e6fd93 subpackages: - proto - name: github.com/golang/snappy - version: d9eb7a3d35ec988b8585d4a0068e462c27d28380 + version: 7db9049039a047d955fe8c19b83c8ff5abd765c7 - name: github.com/gorilla/websocket version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13 - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/mattn/go-colorable - version: ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 + version: 5411d3eea5978e6cdc258b30de592b60df6aba96 - name: github.com/mattn/go-isatty - version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 + version: 281032e84ae07510239465db46bf442aa44b953a - name: github.com/pkg/errors version: 248dadf4e9068a0b3e79f02ed0a610d935de5302 - name: github.com/syndtr/goleveldb - version: 6ae1797c0b42b9323fc27ff7dcf568df88f2f33d + version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65 subpackages: - leveldb - leveldb/cache @@ -45,11 +45,10 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 8df0bc3a40ccad0d2be10e33c62c404e65c92502 + version: 31bdda27ad80e47d372e4b9e4acfd4c0ef81d3e4 subpackages: - client - example/dummy - - example/nil - server - types - name: github.com/tendermint/ed25519 @@ -78,7 +77,7 @@ imports: - name: github.com/tendermint/go-logger version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2 - name: github.com/tendermint/go-merkle - version: 653cb1f631528351ddbc359b994eb0c96f0341cd + version: 9f20e80cb188d07860caa70196dd7700659ec4a4 - name: github.com/tendermint/go-p2p version: 67c9086b7458eb45b1970483decd01cd744c477a subpackages: @@ -92,16 +91,16 @@ imports: - name: github.com/tendermint/go-wire version: 3216ec9d47bbdf8d4fc27d22169ea86a6688bc15 - name: github.com/tendermint/log15 - version: 9545b249b3aacafa97f79e0838b02b274adc6f5f + version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6 subpackages: - term - name: github.com/tendermint/merkleeyes - version: 7c1ec0ef86c42b7a461e3967efb6c35bd5652101 + version: 87b0a111a716f1495f30ce58bd469e36ac220e09 subpackages: - app - client - name: github.com/tendermint/tendermint - version: 67ab574e9889c0641ae959296d391e3cadec55e3 + version: 3ebd69db1bc9133777883e5e0734f4a09f738e8a subpackages: - blockchain - config/tendermint @@ -116,9 +115,9 @@ imports: - types - version - name: github.com/urfave/cli - version: 8ef3805c9de2519805c3f060524b695bba2cd715 + version: 347a9884a87374d000eec7e6445a34487c1f4a2b - name: golang.org/x/crypto - version: aa2481cbfe81d911eb62b642b7a6b5ec58bbea71 + version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8 subpackages: - curve25519 - nacl/box @@ -129,20 +128,21 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: cfe3c2a7525b50c3d707256e371c90938cfef98a + version: 61557ac0112b576429a0df080e1c2cef5dfbb642 subpackages: - context - http2 - http2/hpack + - idna - internal/timeseries - lex/httplex - trace - name: golang.org/x/sys - version: 30de6d19a3bd89a5f38ae4028e23aaa5582648af + version: e24f485414aeafb646f6fca458b0bf869c0880a1 subpackages: - unix - name: google.golang.org/grpc - version: 50955793b0183f9de69bd78e2ec251cf20aab121 + version: cbcceb2942a489498cf22b2f918536e819d33f0a subpackages: - codes - credentials From 558df7da151b22d866caa7565d95ea63cc7bd6c6 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 13 Feb 2017 17:04:49 -0500 Subject: [PATCH 11/49] enable ibc by default --- app/app.go | 12 +++++++----- app/genesis.go | 2 +- cmd/basecoin/main.go | 4 ++-- cmd/commands/ibc.go | 12 +++++------- cmd/commands/start.go | 9 +++++++-- cmd/commands/tx.go | 5 +++-- state/execution.go | 4 ++-- 7 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/app.go b/app/app.go index 59f9003478..54d9d22d02 100644 --- a/app/app.go +++ b/app/app.go @@ -51,14 +51,15 @@ func (app *Basecoin) RegisterPlugin(plugin types.Plugin) { } // ABCI::SetOption -func (app *Basecoin) SetOption(key string, value string) (log string) { - PluginName, key := splitKey(key) - if PluginName != PluginNameBase { +func (app *Basecoin) SetOption(key string, value string) string { + pluginName, key := splitKey(key) + if pluginName != PluginNameBase { // Set option on plugin - plugin := app.plugins.GetByName(PluginName) + plugin := app.plugins.GetByName(pluginName) if plugin == nil { - return "Invalid plugin name: " + PluginName + return "Invalid plugin name: " + pluginName } + log.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value) return plugin.SetOption(app.state, key, value) } else { // Set option on basecoin @@ -74,6 +75,7 @@ func (app *Basecoin) SetOption(key string, value string) (log string) { return "Error decoding acc message: " + err.Error() } app.state.SetAccount(acc.PubKey.Address(), acc) + log.Info("SetAccount", "addr", acc.PubKey.Address(), "acc", acc) return "Success" } return "Unrecognized option key " + key diff --git a/app/genesis.go b/app/genesis.go index 93848c893a..6933780b37 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -17,7 +17,7 @@ func (app *Basecoin) LoadGenesis(path string) error { for _, kv := range kvz { log := app.SetOption(kv.Key, kv.Value) // TODO: remove debug output - fmt.Printf("Set %v=%v. Log: %v", kv.Key, kv.Value, log) + fmt.Printf("Set %v=%v. Log: %v\n", kv.Key, kv.Value, log) } return nil } diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 77f9827fdd..8a39a4902d 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -17,8 +17,8 @@ func main() { commands.TxCmd, commands.QueryCmd, commands.KeyCmd, - commands.VerifyCmd, // TODO: move to merkleeyes? - commands.BlockCmd, // TODO: move to adam? + commands.VerifyCmd, + commands.BlockCmd, commands.AccountCmd, } app.Run(os.Args) diff --git a/cmd/commands/ibc.go b/cmd/commands/ibc.go index f8d0e0b619..34f4b7923d 100644 --- a/cmd/commands/ibc.go +++ b/cmd/commands/ibc.go @@ -9,7 +9,6 @@ import ( "github.com/urfave/cli" "github.com/tendermint/basecoin/plugins/ibc" - "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" "github.com/tendermint/go-merkle" @@ -17,10 +16,9 @@ import ( tmtypes "github.com/tendermint/tendermint/types" ) -// Register the IBC plugin at start and for transactions -func RegisterIBC() { - RegisterTxSubcommand(IbcCmd) - RegisterStartPlugin("ibc", func() types.Plugin { return ibc.New() }) +// returns a new IBC plugin to be registered with Basecoin +func NewIBCPlugin() *ibc.IBCPlugin { + return ibc.New() } //--------------------------------------------------------------------- @@ -104,9 +102,9 @@ var ( // ibc commands var ( - IbcCmd = cli.Command{ + IbcTxCmd = cli.Command{ Name: "ibc", - Usage: "Send a transaction to the interblockchain (ibc) plugin", + Usage: "an IBC transaction, for InterBlockchain Communication", Flags: TxFlags, Subcommands: []cli.Command{ IbcRegisterTxCmd, diff --git a/cmd/commands/start.go b/cmd/commands/start.go index 16e47fa602..72a13107df 100644 --- a/cmd/commands/start.go +++ b/cmd/commands/start.go @@ -72,7 +72,10 @@ func cmdStart(c *cli.Context) error { // Create Basecoin app basecoinApp := app.NewBasecoin(eyesCli) - // register all plugins + // register IBC plugn + basecoinApp.RegisterPlugin(NewIBCPlugin()) + + // register all other plugins for _, p := range plugins { basecoinApp.RegisterPlugin(p.newPlugin()) } @@ -91,7 +94,9 @@ func cmdStart(c *cli.Context) error { if c.Bool("in-proc") { startTendermint(c, basecoinApp) } else { - startBasecoinABCI(c, basecoinApp) + if err := startBasecoinABCI(c, basecoinApp); err != nil { + return err + } } return nil diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index 9b8ce21cd8..d2185609ca 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -37,12 +37,13 @@ var ( Subcommands: []cli.Command{ SendTxCmd, AppTxCmd, + IbcTxCmd, }, } SendTxCmd = cli.Command{ Name: "send", - Usage: "Create, sign, and broadcast a SendTx transaction", + Usage: "a SendTx transaction, for sending tokens around", ArgsUsage: "", Action: func(c *cli.Context) error { return cmdSendTx(c) @@ -52,7 +53,7 @@ var ( AppTxCmd = cli.Command{ Name: "app", - Usage: "Create, sign, and broadcast a raw AppTx transaction", + Usage: "an AppTx transaction, for sending raw data to plugins", ArgsUsage: "", Action: func(c *cli.Context) error { return cmdAppTx(c) diff --git a/state/execution.go b/state/execution.go index 6e722bdc9c..0b464c45a4 100644 --- a/state/execution.go +++ b/state/execution.go @@ -95,7 +95,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e } if !tx.Input.Coins.IsGTE(types.Coins{tx.Fee}) { log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) - return abci.ErrBaseInsufficientFunds + return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("input coins is %d, but fee is %d", tx.Input.Coins, types.Coins{tx.Fee})) } // Validate call address @@ -238,7 +238,7 @@ func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInpu } // Check amount if !balance.IsGTE(in.Coins) { - return abci.ErrBaseInsufficientFunds + return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("balance is %d, tried to send %d", balance, in.Coins)) } // Check signatures if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { From 0b77bcfce6d16e0585e5db76b860ea7c937be67d Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 13 Feb 2017 21:10:21 -0500 Subject: [PATCH 12/49] Query: Height -> LastHeight --- app/app.go | 6 ------ cmd/commands/query.go | 10 +++++----- glide.lock | 9 ++++----- glide.yaml | 4 ++-- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/app/app.go b/app/app.go index 54d9d22d02..72f8a61c42 100644 --- a/app/app.go +++ b/app/app.go @@ -196,9 +196,3 @@ func splitKey(key string) (prefix string, suffix string) { } return key, "" } - -// (not meant to be called) -// assert that Basecoin implements `abci.Application` at compile-time -func _assertABCIApplication(basecoin *Basecoin) abci.Application { - return basecoin -} diff --git a/cmd/commands/query.go b/cmd/commands/query.go index 41635e2882..ddcd5c433d 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -92,13 +92,13 @@ func cmdQuery(c *cli.Context) error { val := resp.Value proof := resp.Proof - height := resp.Height + lastHeight := resp.LastHeight fmt.Println(string(wire.JSONBytes(struct { - Value []byte `json:"value"` - Proof []byte `json:"proof"` - Height uint64 `json:"height"` - }{val, proof, height}))) + Value []byte `json:"value"` + Proof []byte `json:"proof"` + LastHeight uint64 `json:"last_height"` + }{val, proof, lastHeight}))) return nil } diff --git a/glide.lock b/glide.lock index 90bae6db42..f87f437b8c 100644 --- a/glide.lock +++ b/glide.lock @@ -2,11 +2,9 @@ hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 updated: 2017-02-17T13:24:05.234809983+01:00 imports: - name: github.com/btcsuite/btcd - version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 + version: d06c0bb181529331be8f8d9350288c420d9e60e4 subpackages: - btcec -- name: github.com/btcsuite/fastsha256 - version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: 99064174e013895bbd9b025c31100bd1d9b590ca - name: github.com/ebuchman/fail-test @@ -156,14 +154,15 @@ imports: - transport testImports: - name: github.com/davecgh/go-spew - version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 + version: 346938d642f2ec3594ed81d874461961cd0faa76 subpackages: - spew - name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + version: 792786c7400a136282c1664665ae0a8db921c6c2 subpackages: - difflib - name: github.com/stretchr/testify version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert + - require diff --git a/glide.yaml b/glide.yaml index ecf4f151b4..570a80e24b 100644 --- a/glide.yaml +++ b/glide.yaml @@ -13,9 +13,9 @@ import: - package: github.com/tendermint/go-wire version: develop - package: github.com/tendermint/merkleeyes - version: develop + version: last_height - package: github.com/tendermint/tendermint - version: develop + version: last_height - package: github.com/tendermint/abci version: develop - package: github.com/gorilla/websocket From bc6c79ef04549b01ebc43ea2fc5e3e0f34735a39 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 13 Feb 2017 21:28:48 -0500 Subject: [PATCH 13/49] cmd: fix query height --- cmd/commands/query.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/commands/query.go b/cmd/commands/query.go index ddcd5c433d..4f8102034e 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -133,11 +133,7 @@ func cmdBlock(c *cli.Context) error { return errors.New(cmn.Fmt("Height must be an int, got %v: %v", heightString, err)) } - /*block, err := getBlock(c, height) - if err != nil { - return err - }*/ - nextBlock, err := getBlock(c, height+1) + nextBlock, err := getBlock(c, height) if err != nil { return err } From 6e6a5892c5004ae32e597f2fef10746fc104fe6a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 13 Feb 2017 21:29:11 -0500 Subject: [PATCH 14/49] ibc: check commit is for header --- plugins/ibc/ibc.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index 91b8c54985..4d1e6a5ec2 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -329,6 +329,7 @@ func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { save(sm.store, packetKeyIngress, packet) // Load Header and make sure it exists + // If it exists, we already checked a valid commit for it in UpdateChainTx var header tm.Header exists, err := load(sm.store, headerKey, &header) if err != nil { @@ -341,16 +342,6 @@ func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { return } - /* - // Read Proof - var proof *merkle.IAVLProof - err = wire.ReadBinaryBytes(tx.Proof, &proof) - if err != nil { - sm.res.Code = IBCEncodingError - sm.res.Log = cmn.Fmt("Reading Proof: %v", err.Error()) - return - } - */ proof := tx.Proof if proof == nil { sm.res.Code = IBCCodeInvalidProof @@ -368,7 +359,6 @@ func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { } return - } func (ibc *IBCPlugin) InitChain(store types.KVStore, vals []*abci.Validator) { @@ -432,6 +422,7 @@ func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Comm if chainState.ChainID != header.ChainID { return errors.New(cmn.Fmt("Expected header.ChainID %v, got %v", chainState.ChainID, header.ChainID)) } + // Ensure things aren't empty if len(chainState.Validators) == 0 { return errors.New(cmn.Fmt("Blockchain has no validators")) // NOTE: Why would this happen? } @@ -443,6 +434,11 @@ func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Comm vals := chainState.Validators valSet := tm.NewValidatorSet(vals) + // Ensure the commit is for the header + if !bytes.Equal(header.Hash(), vote0.BlockID.Hash) { + return errors.New(cmn.Fmt("Commit.BlockID.Hash (%X) does not match header.Hash (%X)", vote0.BlockID.Hash, header.Hash())) + } + // NOTE: Currently this only works with the exact same validator set. // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose // the functionality to verify commits even after validator changes. From dcfc9a542d825f4b881cd2eea379fcfdc7838a9b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 13 Feb 2017 23:22:31 -0500 Subject: [PATCH 15/49] fetch commit separate from header --- cmd/commands/query.go | 10 +++++----- cmd/commands/utils.go | 17 +++++++++++++---- demo/start.sh | 44 ++++++++++++++++++++++++++++++++++++++----- plugins/ibc/ibc.go | 1 + 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/cmd/commands/query.go b/cmd/commands/query.go index 4f8102034e..33e616c64d 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -133,7 +133,7 @@ func cmdBlock(c *cli.Context) error { return errors.New(cmn.Fmt("Height must be an int, got %v: %v", heightString, err)) } - nextBlock, err := getBlock(c, height) + header, commit, err := getHeaderAndCommit(c, height) if err != nil { return err } @@ -143,12 +143,12 @@ func cmdBlock(c *cli.Context) error { JSON BlockJSON `json:"json"` }{ BlockHex{ - Header: wire.BinaryBytes(nextBlock.Header), - Commit: wire.BinaryBytes(nextBlock.LastCommit), + Header: wire.BinaryBytes(header), + Commit: wire.BinaryBytes(commit), }, BlockJSON{ - Header: nextBlock.Header, - Commit: nextBlock.LastCommit, + Header: header, + Commit: commit, }, }))) diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 92a805734a..8ef18e3dfe 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -80,15 +80,24 @@ func getAcc(tmAddr string, address []byte) (*types.Account, error) { return acc, nil } -func getBlock(c *cli.Context, height int) (*tmtypes.Block, error) { +func getHeaderAndCommit(c *cli.Context, height int) (*tmtypes.Header, *tmtypes.Commit, error) { tmResult := new(ctypes.TMResult) tmAddr := c.String("node") clientURI := client.NewClientURI(tmAddr) _, err := clientURI.Call("block", map[string]interface{}{"height": height}, tmResult) if err != nil { - return nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) + return nil, nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) } - res := (*tmResult).(*ctypes.ResultBlock) - return res.Block, nil + resBlock := (*tmResult).(*ctypes.ResultBlock) + header := resBlock.Block.Header + + _, err = clientURI.Call("commit", map[string]interface{}{"height": height}, tmResult) + if err != nil { + return nil, nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) + } + resCommit := (*tmResult).(*ctypes.ResultCommit) + commit := resCommit.Commit + + return header, commit, nil } diff --git a/demo/start.sh b/demo/start.sh index ad5da68d1c..b404a33c01 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -9,6 +9,32 @@ function removeQuotes() { echo "$temp" } +function waitForNode() { + addr=$1 + set +e + curl -s $addr/status > /dev/null + ERR=$? + while [ "$ERR" != 0 ]; do + sleep 1 + curl -s $addr/status > /dev/null + ERR=$? + done + set -e + echo "... node $addr is up" +} + +function waitForBlock() { + addr=$1 + b1=`curl -s $addr/status | jq .result[1].latest_block_height` + b2=$b1 + while [ "$b2" != "$b1" ]; do + echo "Waiting for node $addr to commit a block ..." + sleep 1 + b2=`curl -s $addr/status | jq .result[1].latest_block_height` + done +} + + # grab the chain ids CHAIN_ID1=$(cat ./data/chain1/basecoin/genesis.json | jq .[1]) CHAIN_ID1=$(removeQuotes $CHAIN_ID1) @@ -35,7 +61,9 @@ basecoin start --address tcp://localhost:36658 --dir ./data/chain2/basecoin &> c echo "" echo "... waiting for chains to start" echo "" -sleep 10 + +waitForNode localhost:46657 +waitForNode localhost:36657 echo "... registering chain1 on chain2" echo "" @@ -54,14 +82,14 @@ echo "... querying for packet data" echo "" # query for the packet data and proof QUERY_RESULT=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) -HEIGHT=$(echo $QUERY_RESULT | jq .height) +LAST_HEIGHT=$(echo $QUERY_RESULT | jq .last_height) PACKET=$(echo $QUERY_RESULT | jq .value) PROOF=$(echo $QUERY_RESULT | jq .proof) PACKET=$(removeQuotes $PACKET) PROOF=$(removeQuotes $PROOF) echo "" echo "QUERY_RESULT: $QUERY_RESULT" -echo "HEIGHT: $HEIGHT" +echo "LAST_HEIGHT: $LAST_HEIGHT" echo "PACKET: $PACKET" echo "PROOF: $PROOF" @@ -71,6 +99,12 @@ echo "... waiting for some blocks to be mined" echo "" sleep 5 +waitForBlock localhost:46657 +waitForBlock localhost:36657 + +# we need the header at height H=LAST_HEIGHT + 1 +HEIGHT=$(($LAST_HEIGHT + 1)) + echo "" echo "... querying for block data" echo "" @@ -95,12 +129,12 @@ echo "" echo "... posting packet from chain1 on chain2" echo "" # post the packet from chain1 to chain2 -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height $((HEIGHT + 1)) --packet 0x$PACKET --proof 0x$PROOF +basecoin tx ibc --amount 10 $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF echo "" echo "... checking if the packet is present on chain2" echo "" -# query for the packet on chain2 ! +# query for the packet on chain2 basecoin query --node tcp://localhost:36657 ibc,ingress,test_chain_2,test_chain_1,1 echo "" diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index 4d1e6a5ec2..d1bd8d53b3 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -1,6 +1,7 @@ package ibc import ( + "bytes" "errors" "net/url" "strings" From 67cf948f261d392546f813290cad94479c97fcd2 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 14 Feb 2017 01:34:24 -0500 Subject: [PATCH 16/49] ibc: check commit against blockID --- plugins/ibc/ibc.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index d1bd8d53b3..53913b438c 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -431,23 +431,22 @@ func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Comm return errors.New(cmn.Fmt("Commit has no signatures")) } chainID := chainState.ChainID - vote0 := commit.Precommits[0] vals := chainState.Validators valSet := tm.NewValidatorSet(vals) - // Ensure the commit is for the header - if !bytes.Equal(header.Hash(), vote0.BlockID.Hash) { - return errors.New(cmn.Fmt("Commit.BlockID.Hash (%X) does not match header.Hash (%X)", vote0.BlockID.Hash, header.Hash())) - } - // NOTE: Currently this only works with the exact same validator set. // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose // the functionality to verify commits even after validator changes. - err := valSet.VerifyCommit(chainID, vote0.BlockID, vote0.Height, commit) + blockID, err := valSet.VerifyCommitReturnBlockID(chainID, header.Height, commit) if err != nil { return err } + // Ensure the committed blockID matches the header + if !bytes.Equal(header.Hash(), blockID.Hash) { + return errors.New(cmn.Fmt("blockID.Hash (%X) does not match header.Hash (%X)", blockID.Hash, header.Hash())) + } + // All ok! return nil } From e4ec1a651f6c05ed4a56352e47c97ea5b1b3f304 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 14 Feb 2017 17:21:21 -0500 Subject: [PATCH 17/49] Query: LastHeight -> Height :) --- cmd/commands/query.go | 10 +++++----- demo/start.sh | 7 ++----- glide.lock | 5 ++--- glide.yaml | 4 ++-- plugins/ibc/ibc.go | 3 ++- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/cmd/commands/query.go b/cmd/commands/query.go index 33e616c64d..f0ac1ff58a 100644 --- a/cmd/commands/query.go +++ b/cmd/commands/query.go @@ -92,13 +92,13 @@ func cmdQuery(c *cli.Context) error { val := resp.Value proof := resp.Proof - lastHeight := resp.LastHeight + height := resp.Height fmt.Println(string(wire.JSONBytes(struct { - Value []byte `json:"value"` - Proof []byte `json:"proof"` - LastHeight uint64 `json:"last_height"` - }{val, proof, lastHeight}))) + Value []byte `json:"value"` + Proof []byte `json:"proof"` + Height uint64 `json:"height"` + }{val, proof, height}))) return nil } diff --git a/demo/start.sh b/demo/start.sh index b404a33c01..2ab83166c6 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -82,14 +82,14 @@ echo "... querying for packet data" echo "" # query for the packet data and proof QUERY_RESULT=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) -LAST_HEIGHT=$(echo $QUERY_RESULT | jq .last_height) +HEIGHT=$(echo $QUERY_RESULT | jq .height) PACKET=$(echo $QUERY_RESULT | jq .value) PROOF=$(echo $QUERY_RESULT | jq .proof) PACKET=$(removeQuotes $PACKET) PROOF=$(removeQuotes $PROOF) echo "" echo "QUERY_RESULT: $QUERY_RESULT" -echo "LAST_HEIGHT: $LAST_HEIGHT" +echo "HEIGHT: $HEIGHT" echo "PACKET: $PACKET" echo "PROOF: $PROOF" @@ -102,9 +102,6 @@ sleep 5 waitForBlock localhost:46657 waitForBlock localhost:36657 -# we need the header at height H=LAST_HEIGHT + 1 -HEIGHT=$(($LAST_HEIGHT + 1)) - echo "" echo "... querying for block data" echo "" diff --git a/glide.lock b/glide.lock index f87f437b8c..be56206ed2 100644 --- a/glide.lock +++ b/glide.lock @@ -154,15 +154,14 @@ imports: - transport testImports: - name: github.com/davecgh/go-spew - version: 346938d642f2ec3594ed81d874461961cd0faa76 + version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 subpackages: - spew - name: github.com/pmezard/go-difflib - version: 792786c7400a136282c1664665ae0a8db921c6c2 + version: d8ed2627bdf02c080bf22230dbb337003b7aba2d subpackages: - difflib - name: github.com/stretchr/testify version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert - - require diff --git a/glide.yaml b/glide.yaml index 570a80e24b..3229227306 100644 --- a/glide.yaml +++ b/glide.yaml @@ -13,9 +13,9 @@ import: - package: github.com/tendermint/go-wire version: develop - package: github.com/tendermint/merkleeyes - version: last_height + version: develop - package: github.com/tendermint/tendermint - version: last_height + version: rpc-commit - package: github.com/tendermint/abci version: develop - package: github.com/gorilla/websocket diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index 53913b438c..25f5a6da86 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -433,11 +433,12 @@ func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Comm chainID := chainState.ChainID vals := chainState.Validators valSet := tm.NewValidatorSet(vals) + blockID := commit.Precommits[0].BlockID // XXX: incorrect // NOTE: Currently this only works with the exact same validator set. // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose // the functionality to verify commits even after validator changes. - blockID, err := valSet.VerifyCommitReturnBlockID(chainID, header.Height, commit) + err := valSet.VerifyCommit(chainID, blockID, header.Height, commit) if err != nil { return err } From 35c221b49692f880abf864c6306bde75015b5d94 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 14 Feb 2017 17:31:59 -0500 Subject: [PATCH 18/49] use new tendermint /commit endpoint --- cmd/commands/utils.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 8ef18e3dfe..6e594b7fc6 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -85,18 +85,12 @@ func getHeaderAndCommit(c *cli.Context, height int) (*tmtypes.Header, *tmtypes.C tmAddr := c.String("node") clientURI := client.NewClientURI(tmAddr) - _, err := clientURI.Call("block", map[string]interface{}{"height": height}, tmResult) - if err != nil { - return nil, nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) - } - resBlock := (*tmResult).(*ctypes.ResultBlock) - header := resBlock.Block.Header - - _, err = clientURI.Call("commit", map[string]interface{}{"height": height}, tmResult) + _, err := clientURI.Call("commit", map[string]interface{}{"height": height}, tmResult) if err != nil { return nil, nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) } resCommit := (*tmResult).(*ctypes.ResultCommit) + header := resCommit.Header commit := resCommit.Commit return header, commit, nil From 33cafd1b86c7b4a7f7c385966342272a93bcfa09 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 16 Feb 2017 15:36:46 -0500 Subject: [PATCH 19/49] demo: fix waitForBlocks --- cmd/commands/utils.go | 5 +++-- demo/start.sh | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index 6e594b7fc6..13d57bd50e 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -85,9 +85,10 @@ func getHeaderAndCommit(c *cli.Context, height int) (*tmtypes.Header, *tmtypes.C tmAddr := c.String("node") clientURI := client.NewClientURI(tmAddr) - _, err := clientURI.Call("commit", map[string]interface{}{"height": height}, tmResult) + method := "commit" + _, err := clientURI.Call(method, map[string]interface{}{"height": height}, tmResult) if err != nil { - return nil, nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) + return nil, nil, errors.New(cmn.Fmt("Error on %s: %v", method, err)) } resCommit := (*tmResult).(*ctypes.ResultCommit) header := resCommit.Header diff --git a/demo/start.sh b/demo/start.sh index 2ab83166c6..f2b85a5812 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -27,7 +27,7 @@ function waitForBlock() { addr=$1 b1=`curl -s $addr/status | jq .result[1].latest_block_height` b2=$b1 - while [ "$b2" != "$b1" ]; do + while [ "$b2" == "$b1" ]; do echo "Waiting for node $addr to commit a block ..." sleep 1 b2=`curl -s $addr/status | jq .result[1].latest_block_height` @@ -94,10 +94,11 @@ echo "PACKET: $PACKET" echo "PROOF: $PROOF" +# the query returns the height of the next block, which contains the app hash +# but which may not be committed yet, so we have to wait for it to query the commit echo "" -echo "... waiting for some blocks to be mined" +echo "... waiting for a block to be committed" echo "" -sleep 5 waitForBlock localhost:46657 waitForBlock localhost:36657 From dbbf6617d8426caba2cbe4cb25eda1f37494a129 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 17 Feb 2017 09:44:01 -0500 Subject: [PATCH 20/49] update glide --- glide.lock | 19 ++++++++++--------- glide.yaml | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/glide.lock b/glide.lock index be56206ed2..83d5df5392 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-02-17T13:24:05.234809983+01:00 +updated: 2017-02-17T09:41:20.209551862-05:00 imports: - name: github.com/btcsuite/btcd version: d06c0bb181529331be8f8d9350288c420d9e60e4 @@ -16,7 +16,7 @@ imports: subpackages: - proto - name: github.com/golang/snappy - version: 7db9049039a047d955fe8c19b83c8ff5abd765c7 + version: 553a641470496b2327abcac10b36396bd98e45c9 - name: github.com/gorilla/websocket version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13 - name: github.com/jmhodges/levigo @@ -24,7 +24,7 @@ imports: - name: github.com/mattn/go-colorable version: 5411d3eea5978e6cdc258b30de592b60df6aba96 - name: github.com/mattn/go-isatty - version: 281032e84ae07510239465db46bf442aa44b953a + version: dda3de49cbfcec471bd7a70e6cc01fcc3ff90109 - name: github.com/pkg/errors version: 248dadf4e9068a0b3e79f02ed0a610d935de5302 - name: github.com/syndtr/goleveldb @@ -113,7 +113,7 @@ imports: - types - version - name: github.com/urfave/cli - version: 347a9884a87374d000eec7e6445a34487c1f4a2b + version: 2526b57c56f30b50466c96c4133b1a4ad0f0191f - name: golang.org/x/crypto version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8 subpackages: @@ -126,7 +126,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: 61557ac0112b576429a0df080e1c2cef5dfbb642 + version: b4690f45fa1cafc47b1c280c2e75116efe40cc13 subpackages: - context - http2 @@ -136,11 +136,11 @@ imports: - lex/httplex - trace - name: golang.org/x/sys - version: e24f485414aeafb646f6fca458b0bf869c0880a1 + version: 075e574b89e4c2d22f2286a7e2b919519c6f3547 subpackages: - unix - name: google.golang.org/grpc - version: cbcceb2942a489498cf22b2f918536e819d33f0a + version: d0c32ee6a441117d49856d6120ca9552af413ee0 subpackages: - codes - credentials @@ -154,14 +154,15 @@ imports: - transport testImports: - name: github.com/davecgh/go-spew - version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 + version: 346938d642f2ec3594ed81d874461961cd0faa76 subpackages: - spew - name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + version: 792786c7400a136282c1664665ae0a8db921c6c2 subpackages: - difflib - name: github.com/stretchr/testify version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert + - require diff --git a/glide.yaml b/glide.yaml index 3229227306..ecf4f151b4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -15,7 +15,7 @@ import: - package: github.com/tendermint/merkleeyes version: develop - package: github.com/tendermint/tendermint - version: rpc-commit + version: develop - package: github.com/tendermint/abci version: develop - package: github.com/gorilla/websocket From 78167b4e3ac7358fa9bb45fec512f42f350b1f20 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 16 Feb 2017 21:36:49 -0500 Subject: [PATCH 21/49] added unit tests squash me squash me squash --- cmd/commands/utils_test.go | 17 ++++++++++ plugins/counter/counter.go | 2 +- state/state.go | 14 +++++--- state/state_test.go | 68 ++++++++++++++++++++++++++++++++++++++ types/account.go | 3 ++ types/account_test.go | 28 ++++++++++++++++ types/coin_test.go | 5 +++ types/kvstore.go | 1 + types/kvstore_test.go | 59 +++++++++++++++++++++++++++++++++ types/plugin.go | 2 +- types/plugin_test.go | 42 +++++++++++++++++++++++ 11 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 state/state_test.go create mode 100644 types/account_test.go create mode 100644 types/kvstore_test.go create mode 100644 types/plugin_test.go diff --git a/cmd/commands/utils_test.go b/cmd/commands/utils_test.go index c530b04a14..012431e35f 100644 --- a/cmd/commands/utils_test.go +++ b/cmd/commands/utils_test.go @@ -1,12 +1,29 @@ package commands import ( + "encoding/hex" "testing" "github.com/stretchr/testify/assert" "github.com/tendermint/basecoin/types" ) +func TestHex(t *testing.T) { + + //test isHex + hexNoPrefix := hex.EncodeToString([]byte("foobar")) + hexWPrefix := "0x" + hexNoPrefix + str := "foobar" + strWPrefix := "0xfoobar" + assert.True(t, isHex(hexWPrefix), "isHex not identifying hex with 0x prefix") + assert.True(t, !isHex(hexNoPrefix), "isHex shouldn't identify hex without 0x prefix") + assert.True(t, !isHex(str), "isHex shouldn't identify non-hex string") + assert.True(t, !isHex(strWPrefix), "isHex shouldn't identify non-hex string with 0x prefix") + + //test strip hex + assert.True(t, StripHex(hexWPrefix) == hexNoPrefix, "StripHex doesn't remove first two characters") +} + //Test the parse coin and parse coins functionality func TestParse(t *testing.T) { diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index 9d849d1d05..79694c4052 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -35,7 +35,7 @@ func New() *CounterPlugin { return &CounterPlugin{} } -func (cp *CounterPlugin) SetOption(store types.KVStore, key string, value string) (log string) { +func (cp *CounterPlugin) SetOption(store types.KVStore, key, value string) (log string) { return "" } diff --git a/state/state.go b/state/state.go index 026c6a9ad9..385c17dc9b 100644 --- a/state/state.go +++ b/state/state.go @@ -38,7 +38,7 @@ func (s *State) GetChainID() string { } func (s *State) Get(key []byte) (value []byte) { - if s.readCache != nil { + if s.readCache != nil { //if not a cachewrap value, ok := s.readCache[string(key)] if ok { return value @@ -48,7 +48,7 @@ func (s *State) Get(key []byte) (value []byte) { } func (s *State) Set(key []byte, value []byte) { - if s.readCache != nil { + if s.readCache != nil { //if not a cachewrap s.readCache[string(key)] = value } s.store.Set(key, value) @@ -78,8 +78,14 @@ func (s *State) CacheSync() { } func (s *State) Commit() abci.Result { - s.readCache = make(map[string][]byte) - return s.store.(*eyes.Client).CommitSync() + switch s.store.(type) { + case *eyes.Client: + s.readCache = make(map[string][]byte) + return s.store.(*eyes.Client).CommitSync() + default: + return abci.NewError(abci.CodeType_InternalError, "can only use commit is store is merkleeyes") + } + } //---------------------------------------- diff --git a/state/state_test.go b/state/state_test.go new file mode 100644 index 0000000000..f1feac492e --- /dev/null +++ b/state/state_test.go @@ -0,0 +1,68 @@ +package state + +import ( + "bytes" + "testing" + + "github.com/tendermint/basecoin/types" + eyes "github.com/tendermint/merkleeyes/client" + + "github.com/stretchr/testify/assert" +) + +func TestState(t *testing.T) { + + s := NewState(types.NewMemKVStore()) + + s.SetChainID("testchain") + assert.True(t, s.GetChainID() == "testchain", "ChainID is improperly stored") + + setRecords := func(kv types.KVStore) { + kv.Set([]byte("foo"), []byte("snake")) + kv.Set([]byte("bar"), []byte("mouse")) + } + + setRecords(s) + assert.True(t, bytes.Equal(s.Get([]byte("foo")), []byte("snake")), "state doesn't retrieve after Set") + assert.True(t, bytes.Equal(s.Get([]byte("bar")), []byte("mouse")), "state doesn't retrieve after Set") + + // Test account retrieve + dumAddr := []byte("dummyAddress") + + acc := &types.Account{ + PubKey: nil, + Sequence: 1, + Balance: nil, + } + + s.SetAccount(dumAddr, acc) + assert.True(t, s.GetAccount(dumAddr).Sequence == 1, "GetAccount not retrieving") + + //Test CacheWrap with local mem store + store := types.NewMemKVStore() + s = NewState(store) + cache := s.CacheWrap() + setRecords(cache) + assert.True(t, !bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store retrieving before Commit") + assert.True(t, !bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store retrieving before Commit") + cache.CacheSync() + assert.True(t, bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store doesn't retrieve after Commit") + assert.True(t, bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store doesn't retrieve after Commit") + + //Test Commit on state with non-merkle store + assert.True(t, !s.Commit().IsOK(), "Commit shouldn't work with non-merkle store") + + //Test CacheWrap with merkleeyes client store + eyesCli := eyes.NewLocalClient("", 0) + s = NewState(eyesCli) + + cache = s.CacheWrap() + setRecords(cache) + assert.True(t, !bytes.Equal(eyesCli.Get([]byte("foo")), []byte("snake")), "store retrieving before Commit") + assert.True(t, !bytes.Equal(eyesCli.Get([]byte("bar")), []byte("mouse")), "store retrieving before Commit") + cache.CacheSync() + assert.True(t, s.Commit().IsOK(), "Bad Commit") + assert.True(t, bytes.Equal(eyesCli.Get([]byte("foo")), []byte("snake")), "store doesn't retrieve after Commit") + assert.True(t, bytes.Equal(eyesCli.Get([]byte("bar")), []byte("mouse")), "store doesn't retrieve after Commit") + +} diff --git a/types/account.go b/types/account.go index d78f560a6e..d1e62d8321 100644 --- a/types/account.go +++ b/types/account.go @@ -13,6 +13,9 @@ type Account struct { } func (acc *Account) Copy() *Account { + if acc == nil { + return nil + } accCopy := *acc return &accCopy } diff --git a/types/account_test.go b/types/account_test.go new file mode 100644 index 0000000000..771e7f07c6 --- /dev/null +++ b/types/account_test.go @@ -0,0 +1,28 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAccount(t *testing.T) { + + acc := Account{ + PubKey: nil, + Sequence: 0, + Balance: nil, + } + + //test Copy + accCopy := acc.Copy() + accCopy.Sequence = 1 + t.Log(acc.Sequence) + t.Log(accCopy.Sequence) + assert.True(t, acc.Sequence != accCopy.Sequence, "Account Copy Error") + + //test sending nils for panic + var nilAcc *Account + nilAcc.String() + nilAcc.Copy() +} diff --git a/types/coin_test.go b/types/coin_test.go index 158f159c50..7a3fc2ecdd 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -19,6 +19,11 @@ func TestCoins(t *testing.T) { t.Fatalf("Expected coins to be positive: %v", coins) } + emptyCoins := Coins{Coin{"GOLD", 0}} + if !coins.IsGTE(emptyCoins) { + t.Fatalf("Expected %v to be >= %v", coins, emptyCoins) + } + negCoins := coins.Negative() if negCoins.IsPositive() { t.Fatalf("Expected neg coins to not be positive: %v", negCoins) diff --git a/types/kvstore.go b/types/kvstore.go index 96f8c7d0ff..15088bdfb3 100644 --- a/types/kvstore.go +++ b/types/kvstore.go @@ -113,6 +113,7 @@ func (kvc *KVCache) Get(key []byte) (value []byte) { } } +//Update the store with the values from the cache func (kvc *KVCache) Sync() { for e := kvc.keys.Front(); e != nil; e = e.Next() { key := e.Value.([]byte) diff --git a/types/kvstore_test.go b/types/kvstore_test.go new file mode 100644 index 0000000000..5c40a2597b --- /dev/null +++ b/types/kvstore_test.go @@ -0,0 +1,59 @@ +package types + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMemKVStore(t *testing.T) { + + ms := NewMemKVStore() + ms.Set([]byte("foo"), []byte("snake")) + ms.Set([]byte("bar"), []byte("mouse")) + assert.True(t, bytes.Equal(ms.Get([]byte("foo")), []byte("snake")), "MemKVStore doesn't retrieve after Set") + assert.True(t, bytes.Equal(ms.Get([]byte("bar")), []byte("mouse")), "MemKVStore doesn't retrieve after Set") +} + +func TestKVCache(t *testing.T) { + + store := NewMemKVStore() + kvc := NewKVCache(store) + + setRecords := func() { + kvc.Set([]byte("foo"), []byte("snake")) + kvc.Set([]byte("bar"), []byte("mouse")) + } + + //test read/write + setRecords() + assert.True(t, bytes.Equal(kvc.Get([]byte("foo")), []byte("snake")), "KVCache doesn't retrieve after Set") + assert.True(t, bytes.Equal(kvc.Get([]byte("bar")), []byte("mouse")), "KVCache doesn't retrieve after Set") + + //test reset + kvc.Reset() + assert.True(t, !bytes.Equal(kvc.Get([]byte("foo")), []byte("snake")), "KVCache retrieving after reset") + assert.True(t, !bytes.Equal(kvc.Get([]byte("bar")), []byte("mouse")), "KVCache retrieving after reset") + + //test sync + setRecords() + assert.True(t, !bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store retrieving before synced") + assert.True(t, !bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store retrieving before synced") + kvc.Sync() + assert.True(t, bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store isn't retrieving after synced") + assert.True(t, bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store isn't retrieving after synced") + + //test logging + assert.True(t, len(kvc.GetLogLines()) == 0, "logging events existed before using SetLogging") + fmt.Println(len(kvc.GetLogLines())) + + kvc.SetLogging() + setRecords() + assert.True(t, len(kvc.GetLogLines()) == 2, "incorrect number of logging events recorded") + + kvc.ClearLogLines() + assert.True(t, len(kvc.GetLogLines()) == 0, "logging events still exists after ClearLogLines") + +} diff --git a/types/plugin.go b/types/plugin.go index ac95cac679..9783f2c7c4 100644 --- a/types/plugin.go +++ b/types/plugin.go @@ -15,7 +15,7 @@ type Plugin interface { RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result) // Other ABCI message handlers - SetOption(store KVStore, key string, value string) (log string) + 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 diff --git a/types/plugin_test.go b/types/plugin_test.go new file mode 100644 index 0000000000..21cd92114d --- /dev/null +++ b/types/plugin_test.go @@ -0,0 +1,42 @@ +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) { + + plugins := NewPlugins() + assert.True(t, len(plugins.GetList()) == 0, "plugins object init with a objects") + plugins.RegisterPlugin(&Dummy{}) + assert.True(t, len(plugins.GetList()) == 1, "plugin wasn't added to plist after registered") + dum := plugins.GetByName("dummy") + assert.True(t, dum.Name() == "dummy", "plugin wasn't retrieved properly with GetByName") +} From c5f837c68eee41121a2fbafe6f20ceed415bd0e2 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Feb 2017 01:57:21 -0500 Subject: [PATCH 22/49] doc edits go basics doc update exposed comment --- docs/go_basics.md | 71 ++++++++++++++++++---- docs/guide/basecoin-basics.md | 16 +++-- docs/guide/basecoin-design.md | 20 ++++--- docs/guide/deployment.md | 6 +- docs/guide/example-plugin.md | 37 ++++++------ docs/guide/ibc.md | 50 ++++++++-------- docs/guide/plugin-design.md | 8 +-- docs/guide/src/example-plugin/cmd.go | 18 +++++- docs/guide/src/example-plugin/main.go | 1 + docs/guide/src/example-plugin/plugin.go | 80 +++++++++++++++++++++---- 10 files changed, 225 insertions(+), 82 deletions(-) diff --git a/docs/go_basics.md b/docs/go_basics.md index 28081350df..fd753da90c 100644 --- a/docs/go_basics.md +++ b/docs/go_basics.md @@ -1,25 +1,71 @@ # Go Basics -This document is designed for developers new to the go language, especially experienced developers who are learning go for the purpose of using tendermint. +This document is designed for developers new to the go language, especially +experienced developers who are learning go for the purpose of using Tendermint. -Go is a rather simple language, which aims to produce fast, maintainable programs, while minimizing development effort. In order to speed up development, the go community has adopted quite a number of conventions, which are used in almost every open source project. The same way one rails dev can learn a new project quickly as they all have the same enforced layout, programming following these conventions allows for interoperability with much of the go tooling, and a much more fluid development experience. +Go is a rather simple language, which aims to produce fast, maintainable +programs, while minimizing development effort. In order to speed up +development, the go community has adopted quite a number of conventions, which +are used in almost every open source project. The same way one rails dev can +learn a new project quickly as they all have the same enforced layout, +programming following these conventions allows for interoperability with much +of the go tooling, and a much more fluid development experience. -First of all, you should read through [Effective Go](https://golang.org/doc/effective_go.html) to get a feel for the language and the constructs. And maybe pick up a book, read a tutorial, or do what you feel best to feel comfortable with the syntax. +First of all, you should read through [Effective +Go](https://golang.org/doc/effective_go.html) to get a feel for the language +and the constructs. And maybe pick up a book, read a tutorial, or do what you +feel best to feel comfortable with the syntax. -Second, you need to set up your go environment. In go, all code hangs out GOPATH. You don't have a separate root directory for each project. Pick a nice locations (like `$HOME/go`) and `export GOPATH` in your startup scripts (`.bashrc` or the like). Note that go compiles all programs to `$GOPATH/bin`, similarly PATH will need to be updated in the startup scripts. If your are editing `.bashrc` (typically found in HOME) you would add the following lines: +Second, you need to set up your go environment. In go, all code hangs out +GOPATH. You don't have a separate root directory for each project. Pick a nice +locations (like `$HOME/go`) and `export GOPATH` in your startup scripts +(`.bashrc` or the like). Note that go compiles all programs to `$GOPATH/bin`, +similarly PATH will need to be updated in the startup scripts. If your are +editing `.bashrc` (typically found in HOME) you would add the following lines: ``` export GOPATH=$HOME/go export PATH=$PATH:$GOROOT/bin:$GOPATH/bin ``` -Now, when you run `go get github.com/tendermint/basecoin`, this will create the directory `$GOPATH/src/github.com/tendermint/basecoin`, checkout the master branch with git, and try to compile if there are any scripts. All your repos will fit under GOPATH with a similar logic. Just pick good names for your github repos. If you put your code outside of GOPATH/src or have a path other than the url of the repo, you can expect errors. There are ways to do this, but quite complex and not worth the bother. +Now, when you run `go get github.com/tendermint/basecoin`, this will create the +directory `$GOPATH/src/github.com/tendermint/basecoin`, checkout the master +branch with git, and try to compile if there are any scripts. All your repos +will fit under GOPATH with a similar logic. Just pick good names for your +github repos. If you put your code outside of GOPATH/src or have a path other +than the url of the repo, you can expect errors. There are ways to do this, +but quite complex and not worth the bother. -Third, every repo in `$GOPATH/src` is checkout out of a version control system (commonly git), and you can go into those directories and manipulate them like any git repo (`git checkout develop`, `git pull`, `git remote set-url origin $MY_FORK`). `go get -u $REPO` is a nice convenience to do a `git pull` on the master branch and recompile if needed. If you work on develop, get used to using the git commands directly in these repos. [here](https://tendermint.com/docs/guides/contributing) are some more tips on using git with open source go projects with absolute dependencies such as tendermint. +Third, every repo in `$GOPATH/src` is checkout out of a version control system +(commonly git), and you can go into those directories and manipulate them like +any git repo (`git checkout develop`, `git pull`, `git remote set-url origin +$MY_FORK`). `go get -u $REPO` is a nice convenience to do a `git pull` on the +master branch and recompile if needed. If you work on develop, get used to +using the git commands directly in these repos. +[Here](https://tendermint.com/docs/guides/contributing) are some more tips on +using git with open source go projects with absolute dependencies such as +Tendermint. -Fourth, installing a go program is rather easy if you know what to do. First to note is all programs compiles with `go install` and end up in `$GOPATH/bin`. `go get` will checkout the repo, then try to `go install` it. Many repos are mainly a library that also export (one or more) commands, in these cases there is a subdir called `cmd`, with a different subdir for each command, using the command name as the directory name. To compile these commands, you can go something like `go install github.com/tendermint/basecoin/cmd/basecoin` or to compile all the commands `go install github.com/tendermint/basecoin/cmd/...` (... is a go tooling shortcut for all subdirs, like `*`). +Fourth, installing a go program is rather easy if you know what to do. First +to note is all programs compiles with `go install` and end up in `$GOPATH/bin`. +`go get` will checkout the repo, then try to `go install` it. Many repos are +mainly a library that also export (one or more) commands, in these cases there +is a subdir called `cmd`, with a different subdir for each command, using the +command name as the directory name. To compile these commands, you can go +something like `go install github.com/tendermint/basecoin/cmd/basecoin` or to +compile all the commands `go install github.com/tendermint/basecoin/cmd/...` +(... is a go tooling shortcut for all subdirs, like `*`). -Fifth, there isn't good dependency management built into go. By default, when compiling a go program which imports another repo, go will compile using the latest master branch, or whichever version you have checked out and located. This can cause serious issues, and there is tooling to do dependency management. As of go 1.6, the `vendor` directory is standard and a copy of a repo will be used rather than the repo under GOPATH. In order to create and maintain the code in the vendor directory, various tools have been created, with [glide](https://github.com/Masterminds/glide) being popular and in use in all the tendermint repos. In this case, `go install` is not enough. If you are working on code from the tendermint, you will usually want to do: +Fifth, there isn't good dependency management built into go. By default, when +compiling a go program which imports another repo, go will compile using the +latest master branch, or whichever version you have checked out and located. +This can cause serious issues, and there is tooling to do dependency +management. As of go 1.6, the `vendor` directory is standard and a copy of a +repo will be used rather than the repo under GOPATH. In order to create and +maintain the code in the vendor directory, various tools have been created, +with [glide](https://github.com/Masterminds/glide) being popular and in use in +all the Tendermint repos. In this case, `go install` is not enough. If you are +working on code from the Tendermint, you will usually want to do: ``` go get github.com/tendermint/$REPO @@ -29,6 +75,11 @@ make install make test ``` -`make get_vendor_deps` should update the vendor directory using glide, `make install` will compile all commands. `make test` is good to run the test suite and make sure things are working with your environment... failing tests are much easier to debug than a malfunctioning program. +`make get_vendor_deps` should update the vendor directory using glide, `make +install` will compile all commands. `make test` is good to run the test suite +and make sure things are working with your environment... failing tests are +much easier to debug than a malfunctioning program. + +Okay, that's it, with this info you should be able to follow along and +trouble-shoot any issues you have with the rest of the guide. -Okay, that's it, with this info you should be able to follow along and trouble-shoot any issues you have with the rest of the guide. diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 400136b496..cf88211a66 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -1,13 +1,16 @@ # Basecoin Basics -Here we explain how to get started with a simple Basecoin blockchain, and how to send transactions between accounts using the `basecoin` tool. +Here we explain how to get started with a simple Basecoin blockchain, +and how to send transactions between accounts using the `basecoin` tool. ## Install Make sure you have [basecoin installed](install.md). -You will also need to [install tendermint](https://tendermint.com/intro/getting-started/download). +You will also need to [install Tendermint](https://tendermint.com/intro/getting-started/download). -**Note** All code is on the 0.9 pre-release branch, you may have to [install tendermint from source](https://tendermint.com/docs/guides/install) until 0.9 is released. (Make sure to add `git checkout develop` to the linked install instructions) +**Note** All code is on the 0.9 pre-release branch, you may have to +[install Tendermint from source](https://tendermint.com/docs/guides/install) +until 0.9 is released. (Make sure to add `git checkout develop` to the linked install instructions) ## Initialization @@ -18,7 +21,7 @@ tendermint init ``` This will create the necessary files for a single Tendermint node in `~/.tendermint`. -If you had previously run tendermint, make sure you reset the chain +If you had previously run Tendermint, make sure you reset the chain (note this will delete all chain data, so back it up if you need it): ``` @@ -49,7 +52,8 @@ Now we can start basecoin: basecoin start --in-proc ``` -This will initialize the chain with the `genesis.json` file from the current directory. If you want to specify another location, you can run: +This will initialize the chain with the `genesis.json` file from the current directory. +If you want to specify another location, you can run: ``` basecoin start --in-proc --dir PATH/TO/CUSTOM/DATA @@ -71,7 +75,7 @@ tendermint node In either case, you should see blocks start streaming in! Note, however, that currently basecoin currently requires the -`develop` branch of tendermint for this to work. +`develop` branch of Tendermint for this to work. ## Send transactions diff --git a/docs/guide/basecoin-design.md b/docs/guide/basecoin-design.md index e91ab9ac7e..b35a6e5295 100644 --- a/docs/guide/basecoin-design.md +++ b/docs/guide/basecoin-design.md @@ -14,7 +14,7 @@ This type of account was directly inspired by accounts in Ethereum, and is unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). Note Basecoin is a multi-asset cryptocurrency, so each account can have many different kinds of tokens. -``` +```golang type Account struct { PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. Sequence int `json:"sequence"` @@ -42,7 +42,7 @@ The `SendTx` takes a list of inputs and a list of outputs, and transfers all the tokens listed in the inputs from their corresponding accounts to the accounts listed in the output. The `SendTx` is structured as follows: -``` +```golang type SendTx struct { Gas int64 `json:"gas"` Fee Coin `json:"fee"` @@ -55,7 +55,7 @@ type TxInput struct { 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 + PubKey crypto.PubKey `json:"pub_key"` // Is present if Sequence == 0 } type TxOutput struct { @@ -71,15 +71,21 @@ This is slightly different from Ethereum's concept of `Gas` and `GasPrice`, where `Fee = Gas x GasPrice`. In Basecoin, the `Gas` and `Fee` are independent, and the `GasPrice` is implicit. -In tendermint, the `Fee` is meant to be used by the validators to inform the ordering of transactions, like in bitcoin. And the `Gas` is meant to be used by the application plugin to control its execution. There is currently no means to pass `Fee` information to the tendermint validators, but it will come soon... +In Tendermint, the `Fee` is meant to be used by the validators to inform the ordering +of transactions, like in bitcoin. And the `Gas` is meant to be used by the application +plugin to control its execution. There is currently no means to pass `Fee` information +to the Tendermint validators, but it will come soon... Second, notice that the `PubKey` only needs to be sent for `Sequence == 0`. After that, it is stored under the account in the Merkle tree and subsequent transactions can exclude it, using only the `Address` to refer to the sender. Ethereum does not require public keys to be sent in transactions -as it uses a different elliptic curve scheme which enables the public key to be derrived from the signature itself. +as it uses a different elliptic curve scheme which enables the public key to be derived from the signature itself. -Finally, note that the use of multiple inputs and multiple outputs allows us to send many different types of tokens between many different accounts -at once in an atomic transaction. Thus, the `SendTx` can serve as a basic unit of decentralized exchange. When using multiple inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. +Finally, note that the use of multiple inputs and multiple outputs allows us to send many +different types of tokens between many different accounts at once in an atomic transaction. +Thus, the `SendTx` can serve as a basic unit of decentralized exchange. When using multiple +inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of +coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. ## Plugins diff --git a/docs/guide/deployment.md b/docs/guide/deployment.md index af3f7feb12..e6a7845fc9 100644 --- a/docs/guide/deployment.md +++ b/docs/guide/deployment.md @@ -1,7 +1,9 @@ ## Deployment -Up until this point, we have only been testing the code as a stand-alone abci app, which is nice for developing, but it is no blockchain. Just a blockchain-ready application. +Up until this point, we have only been testing the code as a stand-alone abci app, +which is nice for developing, but it is no blockchain. Just a blockchain-ready application. -This section will demonstrate how to launch your basecoin-based application along with a tendermint testnet and initialize the genesis block for fun and profit. +This section will demonstrate how to launch your basecoin-based application along +with a tendermint testnet and initialize the genesis block for fun and profit. **TODO** Maybe we link to a blog post for this??? diff --git a/docs/guide/example-plugin.md b/docs/guide/example-plugin.md index b08f336fb7..f62f4de9bc 100644 --- a/docs/guide/example-plugin.md +++ b/docs/guide/example-plugin.md @@ -21,7 +21,7 @@ plugin.go The `main.go` is very simple and does not need to be changed: -``` +```golang func main() { app := cli.NewApp() app.Name = "example-plugin" @@ -50,7 +50,7 @@ This is where the `cmd.go` comes in. First, we register the plugin: -``` +```golang func init() { commands.RegisterTxSubcommand(ExamplePluginTxCmd) commands.RegisterStartPlugin("example-plugin", func() types.Plugin { return NewExamplePlugin() }) @@ -61,7 +61,7 @@ This creates a new subcommand under `tx` (defined below), and ensures the plugin is activated when we start the app. Now we actually define the new command: -``` +```golang var ( ExampleFlag = cli.BoolFlag{ Name: "valid", @@ -88,13 +88,13 @@ func cmdExamplePluginTx(c *cli.Context) error { It's a simple command with one flag, which is just a boolean. However, it actually inherits more flags from the Basecoin framework: -``` +```golang Flags: append(commands.TxFlags, ExampleFlag), ``` The `commands.TxFlags` is defined in `cmd/commands/tx.go`: -``` +```golang var TxFlags = []cli.Flag{ NodeFlag, ChainIDFlag, @@ -144,7 +144,7 @@ Cool, eh? Before we move on to `plugin.go`, let's look at the `cmdExamplePluginTx` function in `cmd.go`: -``` +```golang func cmdExamplePluginTx(c *cli.Context) error { exampleFlag := c.Bool("valid") exampleTx := ExamplePluginTx{exampleFlag} @@ -166,7 +166,7 @@ but are necessary boilerplate. Your plugin may have additional requirements that utilize these other methods. Here's what's relevant for us: -``` +```golang type ExamplePluginState struct { Counter int } @@ -236,7 +236,7 @@ and then using the `RunTx` method to define how the transaction updates the stat Let's break down `RunTx` in parts. First, we deserialize the transaction: -``` +```golang // Decode tx var tx ExamplePluginTx err := wire.ReadBinaryBytes(txBytes, &tx) @@ -250,9 +250,9 @@ as defined in the `github.com/tendermint/go-wire` package. If it's not encoded properly, we return an error. -If the transaction deserializes currectly, we can now check if it's valid: +If the transaction deserializes correctly, we can now check if it's valid: -``` +```golang // Validate tx if !tx.Valid { return abci.ErrInternalError.AppendLog("Valid must be true") @@ -264,7 +264,7 @@ Finally, we can update the state. In this example, the state simply counts how m we've processed. But the state itself is serialized and kept in some `store`, which is typically a Merkle tree. So first we have to load the state from the store and deserialize it: -``` +```golang // Load PluginState var pluginState ExamplePluginState stateBytes := store.Get(ep.StateKey()) @@ -276,11 +276,14 @@ if len(stateBytes) > 0 { } ``` -Note the state is stored under `ep.StateKey()`, which is defined above as `ExamplePlugin.State`. Also note, that we do nothing if there is no existing state data. Is that a bug? No, we just make use of Go's variable initialization, that `pluginState` will contain a `Counter` value of 0. If your app needs more initialization than empty variables, then do this logic here in an `else` block. +Note the state is stored under `ep.StateKey()`, which is defined above as `ExamplePlugin.State`. +Also note, that we do nothing if there is no existing state data. Is that a bug? No, we just make +use of Go's variable initialization, that `pluginState` will contain a `Counter` value of 0. +If your app needs more initialization than empty variables, then do this logic here in an `else` block. Finally, we can update the state's `Counter`, and save the state back to the store: -``` +```golang //App Logic pluginState.Counter += 1 @@ -313,7 +316,7 @@ example-plugin key new > key.json Here's what my `key.json looks like: -``` +```json { "address": "15F591CA434CFCCBDEC1D206F3ED3EBA207BFE7D", "priv_key": [ @@ -329,7 +332,7 @@ Here's what my `key.json looks like: Now we can make a `genesis.json` file and add an account with out public key: -``` +```json [ "base/chainID", "example-chain", "base/account", { @@ -346,7 +349,7 @@ Now we can make a `genesis.json` file and add an account with out public key: Here we've granted ourselves `1000000000` units of the `gold` token. -Before we can start the blockchain, we must initialize and/or reset the tendermint state for a new blockchain: +Before we can start the blockchain, we must initialize and/or reset the Tendermint state for a new blockchain: ``` tendermint init @@ -410,7 +413,7 @@ This is a Merkle proof that the state is what we say it is. In a latter [tutorial on Interblockchain Communication](ibc.md), we'll put this proof to work! -## Next Stpes +## Next Steps In this tutorial we demonstrated how to create a new plugin and how to extend the basecoin CLI to activate the plugin on the blockchain and to send transactions to it. diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 4bd3228140..6862d1b9c5 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -24,16 +24,16 @@ The purpose of IBC is to enable one blockchain to function as a light-client of Since we are using a classical Byzantine Fault Tolerant consensus algorithm, light-client verification is cheap and easy: all we have to do is check validator signatures on the latest block, -and verify a merkle proof of the state. +and verify a Merkle proof of the state. In Tendermint, validators agree on a block before processing it. This means that the signatures and state root for that block aren't included until the next block. Thus, each block contains a field called `LastCommit`, which contains the votes responsible for committing the previous block, and a field -in the block header called `AppHash`, which refers to the merkle root hash of +in the block header called `AppHash`, which refers to the Merkle root hash of the application after processing the transactions from the previous block. So, -if we want to verify the `AppHash` from height H, we need the signatures from `LastCommit` at height H+1. (And remember that this `AppHash` only contains the results from all transactions up to and including block H-1) - +if we want to verify the `AppHash` from height H, we need the signatures from `LastCommit` +at height H+1. (And remember that this `AppHash` only contains the results from all transactions up to and including block H-1) Unlike Proof-of-Work, the light-client protocol does not need to download and check all the headers in the blockchain - the client can always jump straight @@ -46,15 +46,12 @@ postpone handling validator set changes for another time. Now we can describe exactly how IBC works. Suppose we have two blockchains, `chain1` and `chain2`, and we want to send some data from `chain1` to `chain2`. We need to do the following: - -``` -1. Register the details (ie. chain ID and genesis configuration) of `chain1` on `chain2` -2. Within `chain1`, broadcast a transaction that creates an outgoing IBC packet destined for `chain2` -3. Broadcast a transaction to `chain2` informing it of the latest state (ie. header and commit signatures) of `chain1` -4. Post the outgoing packet from `chain1` to `chain2`, including the proof that + 1. Register the details (ie. chain ID and genesis configuration) of `chain1` on `chain2` + 2. Within `chain1`, broadcast a transaction that creates an outgoing IBC packet destined for `chain2` + 3. Broadcast a transaction to `chain2` informing it of the latest state (ie. header and commit signatures) of `chain1` + 4. Post the outgoing packet from `chain1` to `chain2`, including the proof that it was indeed committed on `chain1`. Note `chain2` can only verify this proof because it has a recent header and commit. -``` Each of these steps involves a separate IBC transaction type. Let's take them up in turn. @@ -63,7 +60,7 @@ Each of these steps involves a separate IBC transaction type. Let's take them up The `IBCRegisterChainTx` is used to register one chain on another. It contains the chain ID and genesis configuration of the chain to register: -``` +```golang type IBCRegisterChainTx struct { BlockchainGenesis } @@ -82,7 +79,7 @@ This transaction should only be sent once for a given chain ID, and successive s The `IBCUpdateChainTx` is used to update the state of one chain on another. It contains the header and commit signatures for some block in the chain: -``` +```golang type IBCUpdateChainTx struct { Header tm.Header Commit tm.Commit @@ -96,11 +93,11 @@ Anyone can relay an `IBCUpdateChainTx`, and they only need to do so as frequentl The `IBCPacketCreateTx` is used to create an outgoing packet on one chain. The packet itself contains the source and destination chain IDs, -a sequence number (ie. an integer that increments with every message sent between this pair of chains), -a packet type (eg. coin, data, etc.), +a sequence number (i.e. an integer that increments with every message sent between this pair of chains), +a packet type (e.g. coin, data, etc.), and a payload. -``` +```golang type IBCPacketCreateTx struct { Packet } @@ -129,7 +126,7 @@ Those funds can only be unlocked with corresponding IBC messages back from The `IBCPacketPostTx` is used to post an outgoing packet from one chain to another. It contains the packet and a proof that the packet was committed into the state of the sending chain: -``` +```golang type IBCPacketPostTx struct { FromChainID string // The immediate source of the packet, not always Packet.SrcChainID FromChainHeight uint64 // The block height in which Packet was committed, to check Proof @@ -138,7 +135,7 @@ type IBCPacketPostTx struct { } ``` -The proof is a merkle proof in an IAVL tree, our implementation of a balanced, Merklized binary search tree. +The proof is a Merkle proof in an IAVL tree, our implementation of a balanced, Merklized binary search tree. It contains a list of nodes in the tree, which can be hashed together to get the Merkle root hash. This hash must match the `AppHash` contained in the header at `FromChainHeight + 1` - note the `+ 1` is necessary since `FromChainHeight` is the height in which the packet was committed, @@ -147,14 +144,12 @@ and the resulting state root is not included until the next block. ### IBC State Now that we've seen all the transaction types, let's talk about the state. -Each chain stores some IBC state in its merkle tree. +Each chain stores some IBC state in its Merkle tree. For each chain being tracked by our chain, we store: -``` - Genesis configuration - Latest state - Headers for recent heights -``` We also store all incoming (ingress) and outgoing (egress) packets. @@ -180,8 +175,13 @@ The results of a query can thus be used as proof in an `IBCPacketPostTx`. Now that we have all the background knowledge, let's actually walk through the tutorial. Make sure you have installed +<<<<<<< 5be9db68dbd6a69ba886c5a6e55b90f2cecd2ca8 [tendermint](https://tendermint.com/intro/getting-started/download) and [basecoin](/docs/guide/install.md). +======= +[Tendermint](https://tendermint.com/intro/getting-started/download) and +[adam](/docs/guide/install.md). +>>>>>>> doc edits `basecoin` is a framework for creating new cryptocurrency applications. @@ -252,8 +252,8 @@ Now that the packet is committed in the chain, let's get some proof by querying: basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1 ``` -The result contains the latest height, a value (ie. the hex-encoded binary serialization of our packet), -and a proof (ie. hex-encoded binary serialization of a list of nodes from the Merkle tree) that the value is in the Merkle tree. +The result contains the latest height, a value (i.e. the hex-encoded binary serialization of our packet), +and a proof (i.e. hex-encoded binary serialization of a list of nodes from the Merkle tree) that the value is in the Merkle tree. If we want to send this data to `test_chain_2`, we first have to update what it knows about `test_chain_1`. We'll need a recent block header and a set of commit signatures. @@ -288,13 +288,13 @@ Here, `` is one greater than the height retuned by the previous `que Tada! - ## Conclusion In this tutorial we explained how IBC works, and demonstrated how to use it to communicate between two chains. We did the simplest communciation possible: a one way transfer of data from chain1 to chain2. -The most important part was that we updated chain2 with the latest state (ie. header and commit) of chain1, +The most important part was that we updated chain2 with the latest state (i.e. header and commit) of chain1, and then were able to post a proof to chain2 that a packet was committed to the outgoing state of chain1. In a future tutorial, we will demonstrate how to use IBC to actually transfer tokens between two blockchains, but we'll do it with real testnets deployed across multiple nodes on the network. Stay tuned! + diff --git a/docs/guide/plugin-design.md b/docs/guide/plugin-design.md index ff88bca77b..8f744ee014 100644 --- a/docs/guide/plugin-design.md +++ b/docs/guide/plugin-design.md @@ -9,7 +9,7 @@ Here we describe how that functionality can be achieved through a plugin system. In addition to the `SendTx`, Basecoin also defines another transaction type, the `AppTx`: -``` +```golang type AppTx struct { Gas int64 `json:"gas"` Fee Coin `json:"fee"` @@ -20,7 +20,7 @@ type AppTx struct { ``` The `AppTx` enables Basecoin to be extended with arbitrary additional functionality through the use of plugins. -The `Name` field in the `AppTx` refers to the particular plugin which should process the transasaction, +The `Name` field in the `AppTx` refers to the particular plugin which should process the transaction, and the `Data` field of the `AppTx` is the data to be forwarded to the plugin for processing. Note the `AppTx` also has a `Gas` and `Fee`, with the same meaning as for the `SendTx`. @@ -31,7 +31,7 @@ and some coins that can be forwarded to the plugin as well. A plugin is simply a Go package that implements the `Plugin` interface: -``` +```golang type Plugin interface { // Name of this plugin, should be short. @@ -61,7 +61,7 @@ while the `Input` from the `AppTx` is used to populate the `CallContext`. Note that `RunTx` also takes a `KVStore` - this is an abstraction for the underlying Merkle tree which stores the account data. By passing this to the plugin, we enable plugins to update accounts in the Basecoin state directly, and also to store arbitrary other information in the state. -In this way, the functionality and state of a Basecoin-derrived cryptocurrency can be greatly extended. +In this way, the functionality and state of a Basecoin-derived cryptocurrency can be greatly extended. One could imagine going so far as to implement the Ethereum Virtual Machine as a plugin! ## Examples diff --git a/docs/guide/src/example-plugin/cmd.go b/docs/guide/src/example-plugin/cmd.go index b2fb3ecdae..29e34e126c 100644 --- a/docs/guide/src/example-plugin/cmd.go +++ b/docs/guide/src/example-plugin/cmd.go @@ -8,17 +8,24 @@ import ( "github.com/tendermint/basecoin/types" ) +//Called during CLI initialization func init() { + + //Register a plugin specific CLI command as a subcommand of the tx command commands.RegisterTxSubcommand(ExamplePluginTxCmd) + + //Register the example with basecoin at start commands.RegisterStartPlugin("example-plugin", func() types.Plugin { return NewExamplePlugin() }) } var ( + //CLI Flags ExampleFlag = cli.BoolFlag{ Name: "valid", Usage: "Set this to make the transaction valid", } + //CLI Plugin Commands ExamplePluginTxCmd = cli.Command{ Name: "example", Usage: "Create, sign, and broadcast a transaction to the example plugin", @@ -29,8 +36,17 @@ var ( } ) +//Send a transaction func cmdExamplePluginTx(c *cli.Context) error { + //Retrieve any flag results exampleFlag := c.Bool("valid") + + //Create a transaction object with flag results exampleTx := ExamplePluginTx{exampleFlag} - return commands.AppTx(c, "example-plugin", wire.BinaryBytes(exampleTx)) + + //Encode transaction bytes + exampleTxBytes := wire.BinaryBytes(exampleTx) + + //Send the transaction and return any errors + return commands.AppTx(c, "example-plugin", exampleTxBytes) } diff --git a/docs/guide/src/example-plugin/main.go b/docs/guide/src/example-plugin/main.go index e1347334c1..d8cc38a958 100644 --- a/docs/guide/src/example-plugin/main.go +++ b/docs/guide/src/example-plugin/main.go @@ -8,6 +8,7 @@ import ( ) func main() { + //Initialize an instance of basecoin with default basecoin commands app := cli.NewApp() app.Name = "example-plugin" app.Usage = "example-plugin [command] [args...]" diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go index e930ffbf90..4c0d2b3667 100644 --- a/docs/guide/src/example-plugin/plugin.go +++ b/docs/guide/src/example-plugin/plugin.go @@ -6,46 +6,104 @@ import ( "github.com/tendermint/go-wire" ) +//----------------------------------------- +// Structs +// * Note the fields in each struct may be expanded/modified + +// Plugin State Struct +// * Intended to store the current state of the plugin +// * This example contains a field which holds the execution count +// * Used by go-wire as the encoding/decoding struct to hold the plugin state +// * All fields must be exposed (for go-wire) +// * The state is stored within the KVStore using the key retrieved +// from the ExamplePlugin.StateKey() function type ExamplePluginState struct { Counter int } +// Transaction Struct +// * Stores transaction-specific plugin-customized information +// * This example contains a dummy field 'Valid' intended to specify +// if the transaction is a valid and should proceed +// * Used by go-wire as the encoding/decoding struct to pass transaction +// * All fields must be exposed (for go-wire) +// * Passed through txBytes in the RunTx func. type ExamplePluginTx struct { Valid bool } +// Plugin Struct +// * Struct which satisfies the basecoin Plugin interface +// * Stores global plugin settings, in this example just the plugin name type ExamplePlugin struct { name string } -func (ep *ExamplePlugin) Name() string { - return ep.name -} - -func (ep *ExamplePlugin) StateKey() []byte { - return []byte("ExamplePlugin.State") -} +//----------------------------------------- +// Non-Mandatory Functions +// Return a new example plugin pointer with a hard-coded name. Within other +// plugin implementations may choose to include other initialization +// information to populate custom fields of your Plugin struct in this example +// named ExamplePlugin func NewExamplePlugin() *ExamplePlugin { return &ExamplePlugin{ name: "example-plugin", } } +// Return a byte array unique to this plugin which will be used as the key which +// to store the plugin state (ExamplePluginState) +func (ep *ExamplePlugin) StateKey() []byte { + return []byte("ExamplePlugin.State") +} + +//----------------------------------------- +// Basecoin Plugin Interface Functions + +//Return the name of the plugin +func (ep *ExamplePlugin) Name() string { + return ep.name +} + +// SetOption may be called during genesis of basecoin and can be used to set +// initial plugin parameters. Within genesis.json file entries are made in +// the format: "/", "" Where is the plugin name, +// in this file ExamplePlugin.name, and and are the strings passed +// into the plugin SetOption function. This function is intended to be used to +// set plugin specific information such as the plugin state. Within this example +// SetOption is left unimplemented. func (ep *ExamplePlugin) SetOption(store types.KVStore, key string, value string) (log string) { return "" } +// The core tx logic of the app is containted within the RunTx function +// Input fields: +// - store types.KVStore +// - This term provides read/write capabilities to the merkelized data store +// which is accessible cross-plugin +// - ctx types.CallContext +// - The ctx contains the callers address, a pointer to the callers account, +// and an amount of coins sent with the transaction +// - txBytes []byte +// - Used to send customized information from the basecoin +// application to your plugin +// +// Other more complex plugins may have a variant on the process order within this +// example including loading and saving multiple or variable states, or not +// including a state stored in the KVStore whatsoever. func (ep *ExamplePlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { - // Decode tx + // Decode txBytes using go-wire. Attempt to write the txBytes to the variable + // tx, if the txBytes have not been properly encoded from a ExamplePluginTx + // struct wire will produce an error. var tx ExamplePluginTx err := wire.ReadBinaryBytes(txBytes, &tx) if err != nil { return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) } - // Validate tx + // Perform Transaction Validation if !tx.Valid { return abci.ErrInternalError.AppendLog("Valid must be true") } @@ -53,8 +111,10 @@ func (ep *ExamplePlugin) RunTx(store types.KVStore, ctx types.CallContext, txByt // Load PluginState var pluginState ExamplePluginState stateBytes := store.Get(ep.StateKey()) + // If the state does not exist, stateBytes will be initialized + // as an empty byte array with length of zero if len(stateBytes) > 0 { - err = wire.ReadBinaryBytes(stateBytes, &pluginState) + err = wire.ReadBinaryBytes(stateBytes, &pluginState) //decode using go-wire if err != nil { return abci.ErrInternalError.AppendLog("Error decoding state: " + err.Error()) } From 20dc3a1d4b2ce786c9c540ddc4cea0c07f71e523 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 13 Feb 2017 22:39:08 -0500 Subject: [PATCH 23/49] interim --- docs/guide/ibc.md | 7 +------ docs/guide/src/example-plugin/plugin.go | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 6862d1b9c5..e65905f7d1 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -175,13 +175,8 @@ The results of a query can thus be used as proof in an `IBCPacketPostTx`. Now that we have all the background knowledge, let's actually walk through the tutorial. Make sure you have installed -<<<<<<< 5be9db68dbd6a69ba886c5a6e55b90f2cecd2ca8 -[tendermint](https://tendermint.com/intro/getting-started/download) and -[basecoin](/docs/guide/install.md). -======= [Tendermint](https://tendermint.com/intro/getting-started/download) and -[adam](/docs/guide/install.md). ->>>>>>> doc edits +[basecoin](/docs/guide/install.md). `basecoin` is a framework for creating new cryptocurrency applications. diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go index 4c0d2b3667..12f5b6a663 100644 --- a/docs/guide/src/example-plugin/plugin.go +++ b/docs/guide/src/example-plugin/plugin.go @@ -52,7 +52,7 @@ func NewExamplePlugin() *ExamplePlugin { } } -// Return a byte array unique to this plugin which will be used as the key which +// Return a byte array unique to this plugin which is used as the key // to store the plugin state (ExamplePluginState) func (ep *ExamplePlugin) StateKey() []byte { return []byte("ExamplePlugin.State") From d8b2ceb07c9a6974f60bf011cec6a196ef32d0b1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 14 Feb 2017 14:01:18 -0500 Subject: [PATCH 24/49] ebuchman comments 2 --- docs/guide/plugin-design.md | 8 ++++++++ docs/guide/src/example-plugin/cmd.go | 20 +++++++++++++++++--- docs/guide/src/example-plugin/plugin.go | 22 ++++++++-------------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/docs/guide/plugin-design.md b/docs/guide/plugin-design.md index 8f744ee014..17cb200101 100644 --- a/docs/guide/plugin-design.md +++ b/docs/guide/plugin-design.md @@ -64,6 +64,14 @@ and also to store arbitrary other information in the state. In this way, the functionality and state of a Basecoin-derived cryptocurrency can be greatly extended. One could imagine going so far as to implement the Ethereum Virtual Machine as a plugin! +Any required plugin initialization should be constructed within `SetOption`. +`SetOption` may be called during genesis of basecoin and can be used to set +initial plugin parameters. Within genesis.json file entries are made in +the format: "/", "" Where is the plugin name, +and and are the strings passed into the plugin SetOption function. +This function is intended to be used to set plugin specific information such +as the plugin state. + ## Examples To get started with plugins, see [the example-plugin tutorial](example-plugin.md). diff --git a/docs/guide/src/example-plugin/cmd.go b/docs/guide/src/example-plugin/cmd.go index 29e34e126c..f9a3ff6af6 100644 --- a/docs/guide/src/example-plugin/cmd.go +++ b/docs/guide/src/example-plugin/cmd.go @@ -41,12 +41,26 @@ func cmdExamplePluginTx(c *cli.Context) error { //Retrieve any flag results exampleFlag := c.Bool("valid") - //Create a transaction object with flag results + // Create a transaction object with flag results + // This object is responsible for passing on custom plugin information exampleTx := ExamplePluginTx{exampleFlag} - //Encode transaction bytes + // The custom plugin object is passed to the plugin in the form of + // a byte array. This is achieved serializing the object using go-wire. + // Once received in the plugin, these exampleTxBytes are decoded back + // into the original object struct ExamplePluginTx exampleTxBytes := wire.BinaryBytes(exampleTx) - //Send the transaction and return any errors + // Send the transaction and return any errors. + // Here exampleTxBytes will be passed on to the plugin through the + // following series of function calls: + // - commands.AppTx as data (cmd/commands/tx.go) + // - commands.broadcastTx as tx.Data (cmd/commands/tx.go) + // - after being broadcast the Tendermint transaction + // will be run through app.CheckTx, and if successful DeliverTx, + // let's assume app.CheckTx passes + // - app.DeliverTx serialized within txBytes as tx.Data (app/app.go) + // - state.ExecTx as tx.Data (state/execution.go) + // - plugin.RunTx as txBytes (docs/guide/src/example-plugin/plugin.go) return commands.AppTx(c, "example-plugin", exampleTxBytes) } diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go index 12f5b6a663..97e80520a4 100644 --- a/docs/guide/src/example-plugin/plugin.go +++ b/docs/guide/src/example-plugin/plugin.go @@ -13,10 +13,9 @@ import ( // Plugin State Struct // * Intended to store the current state of the plugin // * This example contains a field which holds the execution count -// * Used by go-wire as the encoding/decoding struct to hold the plugin state -// * All fields must be exposed (for go-wire) -// * The state is stored within the KVStore using the key retrieved -// from the ExamplePlugin.StateKey() function +// * Serialized (by go-wire) and stored within the KVStore using the key retrieved +// from the ExamplePlugin.StateKey() function/ +// * All fields must be exposed for serialization by external libs (here go-wire) type ExamplePluginState struct { Counter int } @@ -25,9 +24,8 @@ type ExamplePluginState struct { // * Stores transaction-specific plugin-customized information // * This example contains a dummy field 'Valid' intended to specify // if the transaction is a valid and should proceed -// * Used by go-wire as the encoding/decoding struct to pass transaction -// * All fields must be exposed (for go-wire) -// * Passed through txBytes in the RunTx func. +// * Deserialized (by go-wire) from txBytes in ExamplePlugin.RunTx +// * All fields must be exposed for serialization by external libs (here go-wire) type ExamplePluginTx struct { Valid bool } @@ -42,10 +40,7 @@ type ExamplePlugin struct { //----------------------------------------- // Non-Mandatory Functions -// Return a new example plugin pointer with a hard-coded name. Within other -// plugin implementations may choose to include other initialization -// information to populate custom fields of your Plugin struct in this example -// named ExamplePlugin +// Return a new ExamplePlugin pointer with a hard-coded name func NewExamplePlugin() *ExamplePlugin { return &ExamplePlugin{ name: "example-plugin", @@ -81,13 +76,12 @@ func (ep *ExamplePlugin) SetOption(store types.KVStore, key string, value string // Input fields: // - store types.KVStore // - This term provides read/write capabilities to the merkelized data store -// which is accessible cross-plugin +// which holds the basecoin state and is accessible to all plugins // - ctx types.CallContext // - The ctx contains the callers address, a pointer to the callers account, // and an amount of coins sent with the transaction // - txBytes []byte -// - Used to send customized information from the basecoin -// application to your plugin +// - Used to send customized information to your plugin // // Other more complex plugins may have a variant on the process order within this // example including loading and saving multiple or variable states, or not From c1a946d4e51abe27b26e04b7f3796738f764b007 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 19 Feb 2017 13:52:02 -0500 Subject: [PATCH 25/49] some doc fixes --- docs/guide/basecoin-design.md | 2 +- docs/guide/plugin-design.md | 4 ++-- docs/guide/src/example-plugin/cmd.go | 30 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/guide/basecoin-design.md b/docs/guide/basecoin-design.md index b35a6e5295..a9bf5d5030 100644 --- a/docs/guide/basecoin-design.md +++ b/docs/guide/basecoin-design.md @@ -55,7 +55,7 @@ type TxInput struct { 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 if Sequence == 0 + PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0 } type TxOutput struct { diff --git a/docs/guide/plugin-design.md b/docs/guide/plugin-design.md index 17cb200101..f59ce736c6 100644 --- a/docs/guide/plugin-design.md +++ b/docs/guide/plugin-design.md @@ -67,8 +67,8 @@ One could imagine going so far as to implement the Ethereum Virtual Machine as a Any required plugin initialization should be constructed within `SetOption`. `SetOption` may be called during genesis of basecoin and can be used to set initial plugin parameters. Within genesis.json file entries are made in -the format: "/", "" Where is the plugin name, -and and are the strings passed into the plugin SetOption function. +the format: `"/", ""`, where `` is the plugin name, +and `` and `` are the strings passed into the plugin SetOption function. This function is intended to be used to set plugin specific information such as the plugin state. diff --git a/docs/guide/src/example-plugin/cmd.go b/docs/guide/src/example-plugin/cmd.go index f9a3ff6af6..6d7c29a799 100644 --- a/docs/guide/src/example-plugin/cmd.go +++ b/docs/guide/src/example-plugin/cmd.go @@ -41,26 +41,26 @@ func cmdExamplePluginTx(c *cli.Context) error { //Retrieve any flag results exampleFlag := c.Bool("valid") - // Create a transaction object with flag results - // This object is responsible for passing on custom plugin information + // Create a transaction using the flag. + // The tx passes on custom information to the plugin exampleTx := ExamplePluginTx{exampleFlag} - // The custom plugin object is passed to the plugin in the form of - // a byte array. This is achieved serializing the object using go-wire. + // The tx is passed to the plugin in the form of + // a byte array. This is achieved by serializing the object using go-wire. // Once received in the plugin, these exampleTxBytes are decoded back - // into the original object struct ExamplePluginTx + // into the original ExamplePluginTx struct exampleTxBytes := wire.BinaryBytes(exampleTx) // Send the transaction and return any errors. - // Here exampleTxBytes will be passed on to the plugin through the - // following series of function calls: - // - commands.AppTx as data (cmd/commands/tx.go) - // - commands.broadcastTx as tx.Data (cmd/commands/tx.go) - // - after being broadcast the Tendermint transaction - // will be run through app.CheckTx, and if successful DeliverTx, - // let's assume app.CheckTx passes - // - app.DeliverTx serialized within txBytes as tx.Data (app/app.go) - // - state.ExecTx as tx.Data (state/execution.go) - // - plugin.RunTx as txBytes (docs/guide/src/example-plugin/plugin.go) + // Here exampleTxBytes is packaged in the `tx.Data` field of an AppTx, + // and passed on to the plugin through the following sequence: + // - passed as `data` to `commands.AppTx` (cmd/commands/tx.go) + // - set as the `tx.Data` field of an AppTx, which is then passed to commands.broadcastTx (cmd/commands/tx.go) + // - the tx is broadcast to Tendermint, which runs it through app.CheckTx (app/app.go) + // - after passing CheckTx, it will eventually be included in a block and run through app.DeliverTx (app/app.go) + // - DeliverTx receives txBytes, which is the serialization of the full AppTx (app/app.go) + // - Once deserialized, the tx is passed to `state.ExecTx` (state/execution.go) + // - If the tx passes various checks, the `tx.Data` is forwarded as `txBytes` to `plugin.RunTx` (docs/guide/src/example-plugin/plugin.go) + // - Finally, it deserialized back to the ExamplePluginTx return commands.AppTx(c, "example-plugin", exampleTxBytes) } From 5c3550acce082871921202944af78d605761740d Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 19 Feb 2017 14:22:38 -0500 Subject: [PATCH 26/49] fix typo --- state/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/state.go b/state/state.go index 385c17dc9b..7fb6c48bac 100644 --- a/state/state.go +++ b/state/state.go @@ -83,7 +83,7 @@ func (s *State) Commit() abci.Result { s.readCache = make(map[string][]byte) return s.store.(*eyes.Client).CommitSync() default: - return abci.NewError(abci.CodeType_InternalError, "can only use commit is store is merkleeyes") + return abci.NewError(abci.CodeType_InternalError, "can only use Commit if store is merkleeyes") } } From b593954285123b5e617a9462fae15f1693370346 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 21 Feb 2017 16:44:27 -0500 Subject: [PATCH 27/49] forgot log.go file --- app/log.go | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/log.go diff --git a/app/log.go b/app/log.go new file mode 100644 index 0000000000..52dc2ddfa4 --- /dev/null +++ b/app/log.go @@ -0,0 +1,7 @@ +package app + +import ( + "github.com/tendermint/go-logger" +) + +var log = logger.New("module", "app") From e6579cf9e9e9f9b0ae280eece5ca1d022b868f9c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 22 Feb 2017 17:30:50 -0500 Subject: [PATCH 28/49] table driven testing squash --- cmd/commands/utils_test.go | 55 ++++++++++++----- state/state_test.go | 119 +++++++++++++++++++++++++------------ types/account_test.go | 5 +- types/coin_test.go | 88 +++++++++++---------------- types/kvstore_test.go | 92 +++++++++++++++++----------- types/plugin_test.go | 26 +++++++- types/tx_test.go | 20 ++++--- 7 files changed, 246 insertions(+), 159 deletions(-) diff --git a/cmd/commands/utils_test.go b/cmd/commands/utils_test.go index 012431e35f..f16927d486 100644 --- a/cmd/commands/utils_test.go +++ b/cmd/commands/utils_test.go @@ -15,13 +15,24 @@ func TestHex(t *testing.T) { hexWPrefix := "0x" + hexNoPrefix str := "foobar" strWPrefix := "0xfoobar" - assert.True(t, isHex(hexWPrefix), "isHex not identifying hex with 0x prefix") - assert.True(t, !isHex(hexNoPrefix), "isHex shouldn't identify hex without 0x prefix") - assert.True(t, !isHex(str), "isHex shouldn't identify non-hex string") - assert.True(t, !isHex(strWPrefix), "isHex shouldn't identify non-hex string with 0x prefix") - //test strip hex - assert.True(t, StripHex(hexWPrefix) == hexNoPrefix, "StripHex doesn't remove first two characters") + //define the list of coin tests + var testList = []struct { + testPass bool + errMsg string + }{ + {isHex(hexWPrefix), "isHex not identifying hex with 0x prefix"}, + {!isHex(hexNoPrefix), "isHex shouldn't identify hex without 0x prefix"}, + {!isHex(str), "isHex shouldn't identify non-hex string"}, + {!isHex(strWPrefix), "isHex shouldn't identify non-hex string with 0x prefix"}, + {StripHex(hexWPrefix) == hexNoPrefix, "StripHex doesn't remove first two characters"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass, tl.errMsg) + } + } //Test the parse coin and parse coins functionality @@ -43,15 +54,27 @@ func TestParse(t *testing.T) { return coin } - //testing ParseCoin Function - assert.True(t, types.Coin{} == makeCoin(""), "parseCoin makes bad empty coin") - assert.True(t, types.Coin{"fooCoin", 1} == makeCoin("1fooCoin"), "parseCoin makes bad coins") - assert.True(t, types.Coin{"barCoin", 10} == makeCoin("10 barCoin"), "parseCoin makes bad coins") + //define the list of coin tests + var testList = []struct { + testPass bool + errMsg string + }{ + //testing ParseCoin Function + {types.Coin{} == makeCoin(""), "parseCoin makes bad empty coin"}, + {types.Coin{"fooCoin", 1} == makeCoin("1fooCoin"), "parseCoin makes bad coins"}, + {types.Coin{"barCoin", 10} == makeCoin("10 barCoin"), "parseCoin makes bad coins"}, - //testing ParseCoins Function - assert.True(t, types.Coins{{"fooCoin", 1}}.IsEqual(makeCoins("1fooCoin")), "parseCoins doesn't parse a single coin") - assert.True(t, types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99barCoin,1fooCoin")), - "parseCoins doesn't properly parse two coins") - assert.True(t, types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99 barCoin, 1 fooCoin")), - "parseCoins doesn't properly parse two coins which use spaces") + //testing ParseCoins Function + {types.Coins{{"fooCoin", 1}}.IsEqual(makeCoins("1fooCoin")), + "parseCoins doesn't parse a single coin"}, + {types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99barCoin,1fooCoin")), + "parseCoins doesn't properly parse two coins"}, + {types.Coins{{"barCoin", 99}, {"fooCoin", 1}}.IsEqual(makeCoins("99 barCoin, 1 fooCoin")), + "parseCoins doesn't properly parse two coins which use spaces"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass, tl.errMsg) + } } diff --git a/state/state_test.go b/state/state_test.go index f1feac492e..162b8e9f76 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -12,21 +12,13 @@ import ( func TestState(t *testing.T) { - s := NewState(types.NewMemKVStore()) + //States and Stores for tests + store := types.NewMemKVStore() + state := NewState(store) + cache := state.CacheWrap() + eyesCli := eyes.NewLocalClient("", 0) - s.SetChainID("testchain") - assert.True(t, s.GetChainID() == "testchain", "ChainID is improperly stored") - - setRecords := func(kv types.KVStore) { - kv.Set([]byte("foo"), []byte("snake")) - kv.Set([]byte("bar"), []byte("mouse")) - } - - setRecords(s) - assert.True(t, bytes.Equal(s.Get([]byte("foo")), []byte("snake")), "state doesn't retrieve after Set") - assert.True(t, bytes.Equal(s.Get([]byte("bar")), []byte("mouse")), "state doesn't retrieve after Set") - - // Test account retrieve + //Account and address for tests dumAddr := []byte("dummyAddress") acc := &types.Account{ @@ -35,34 +27,83 @@ func TestState(t *testing.T) { Balance: nil, } - s.SetAccount(dumAddr, acc) - assert.True(t, s.GetAccount(dumAddr).Sequence == 1, "GetAccount not retrieving") + //reset the store/state/cache + reset := func() { + store = types.NewMemKVStore() + state = NewState(store) + cache = state.CacheWrap() + } - //Test CacheWrap with local mem store - store := types.NewMemKVStore() - s = NewState(store) - cache := s.CacheWrap() - setRecords(cache) - assert.True(t, !bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store retrieving before Commit") - assert.True(t, !bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store retrieving before Commit") - cache.CacheSync() - assert.True(t, bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store doesn't retrieve after Commit") - assert.True(t, bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store doesn't retrieve after Commit") + //set the state to using the eyesCli instead of MemKVStore + useEyesCli := func() { + state = NewState(eyesCli) + cache = state.CacheWrap() + } - //Test Commit on state with non-merkle store - assert.True(t, !s.Commit().IsOK(), "Commit shouldn't work with non-merkle store") + //key value pairs to be tested within the system + keyvalue := []struct { + key string + value string + }{ + {"foo", "snake"}, + {"bar", "mouse"}, + } - //Test CacheWrap with merkleeyes client store - eyesCli := eyes.NewLocalClient("", 0) - s = NewState(eyesCli) + //set the kvc to have all the key value pairs + setRecords := func(kv types.KVStore) { + for _, n := range keyvalue { + kv.Set([]byte(n.key), []byte(n.value)) + } + } - cache = s.CacheWrap() - setRecords(cache) - assert.True(t, !bytes.Equal(eyesCli.Get([]byte("foo")), []byte("snake")), "store retrieving before Commit") - assert.True(t, !bytes.Equal(eyesCli.Get([]byte("bar")), []byte("mouse")), "store retrieving before Commit") - cache.CacheSync() - assert.True(t, s.Commit().IsOK(), "Bad Commit") - assert.True(t, bytes.Equal(eyesCli.Get([]byte("foo")), []byte("snake")), "store doesn't retrieve after Commit") - assert.True(t, bytes.Equal(eyesCli.Get([]byte("bar")), []byte("mouse")), "store doesn't retrieve after Commit") + //store has all the key value pairs + storeHasAll := func(kv types.KVStore) bool { + for _, n := range keyvalue { + if !bytes.Equal(kv.Get([]byte(n.key)), []byte(n.value)) { + return false + } + } + return true + } + //define the test list + testList := []struct { + testPass func() bool + errMsg string + }{ + //test chainID + {func() bool { state.SetChainID("testchain"); return state.GetChainID() == "testchain" }, + "ChainID is improperly stored"}, + + //test basic retrieve + {func() bool { setRecords(state); return storeHasAll(state) }, + "state doesn't retrieve after Set"}, + + // Test account retrieve + {func() bool { state.SetAccount(dumAddr, acc); return state.GetAccount(dumAddr).Sequence == 1 }, + "GetAccount not retrieving"}, + + //Test CacheWrap with local mem store + {func() bool { reset(); setRecords(cache); return !storeHasAll(store) }, + "store retrieving before CacheSync"}, + {func() bool { cache.CacheSync(); return storeHasAll(store) }, + "store doesn't retrieve after CacheSync"}, + + //Test Commit on state with non-merkle store + {func() bool { return !state.Commit().IsOK() }, + "Commit shouldn't work with non-merkle store"}, + + //Test CacheWrap with merkleeyes client store + {func() bool { useEyesCli(); setRecords(cache); return !storeHasAll(eyesCli) }, + "eyesCli retrieving before Commit"}, + {func() bool { cache.CacheSync(); return state.Commit().IsOK() }, + "Bad Commit"}, + {func() bool { return storeHasAll(eyesCli) }, + "eyesCli doesn't retrieve after Commit"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass(), tl.errMsg) + } } diff --git a/types/account_test.go b/types/account_test.go index 771e7f07c6..2f4d49260f 100644 --- a/types/account_test.go +++ b/types/account_test.go @@ -16,10 +16,7 @@ func TestAccount(t *testing.T) { //test Copy accCopy := acc.Copy() - accCopy.Sequence = 1 - t.Log(acc.Sequence) - t.Log(accCopy.Sequence) - assert.True(t, acc.Sequence != accCopy.Sequence, "Account Copy Error") + assert.True(t, &acc != accCopy, "Account Copy Error") //test sending nils for panic var nilAcc *Account diff --git a/types/coin_test.go b/types/coin_test.go index 7a3fc2ecdd..36767ae6b9 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -2,84 +2,64 @@ package types import ( "testing" + + cmn "github.com/tendermint/go-common" + + "github.com/stretchr/testify/assert" ) func TestCoins(t *testing.T) { - coins := Coins{ + + //Define the coins to be used in tests + good := Coins{ Coin{"GAS", 1}, Coin{"MINERAL", 1}, Coin{"TREE", 1}, } - - if !coins.IsValid() { - t.Fatal("Coins are valid") + neg := good.Negative() + sum := good.Plus(neg) + empty := Coins{ + Coin{"GOLD", 0}, } - - if !coins.IsPositive() { - t.Fatalf("Expected coins to be positive: %v", coins) - } - - emptyCoins := Coins{Coin{"GOLD", 0}} - if !coins.IsGTE(emptyCoins) { - t.Fatalf("Expected %v to be >= %v", coins, emptyCoins) - } - - negCoins := coins.Negative() - if negCoins.IsPositive() { - t.Fatalf("Expected neg coins to not be positive: %v", negCoins) - } - - sumCoins := coins.Plus(negCoins) - if len(sumCoins) != 0 { - t.Fatal("Expected 0 coins") - } -} - -func TestCoinsBadSort(t *testing.T) { - coins := Coins{ + badSort1 := Coins{ Coin{"TREE", 1}, Coin{"GAS", 1}, Coin{"MINERAL", 1}, } - - if coins.IsValid() { - t.Fatal("Coins are not sorted") - } -} - -func TestCoinsBadSort2(t *testing.T) { - // both are after the first one, but the second and third are in the wrong order - coins := Coins{ + badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order Coin{"GAS", 1}, Coin{"TREE", 1}, Coin{"MINERAL", 1}, } - - if coins.IsValid() { - t.Fatal("Coins are not sorted") - } -} - -func TestCoinsBadAmount(t *testing.T) { - coins := Coins{ + badAmt := Coins{ Coin{"GAS", 1}, Coin{"TREE", 0}, Coin{"MINERAL", 1}, } - - if coins.IsValid() { - t.Fatal("Coins cannot include 0 amounts") - } -} - -func TestCoinsDuplicate(t *testing.T) { - coins := Coins{ + dup := Coins{ Coin{"GAS", 1}, Coin{"GAS", 1}, Coin{"MINERAL", 1}, } - if coins.IsValid() { - t.Fatal("Duplicate coin") + //define the list of coin tests + var testList = []struct { + testPass bool + errMsg string + }{ + {good.IsValid(), "Coins are valid"}, + {good.IsPositive(), cmn.Fmt("Expected coins to be positive: %v", good)}, + {good.IsGTE(empty), cmn.Fmt("Expected %v to be >= %v", good, empty)}, + {!neg.IsPositive(), cmn.Fmt("Expected neg coins to not be positive: %v", neg)}, + {len(sum) == 0, "Expected 0 coins"}, + {!badSort1.IsValid(), "Coins are not sorted"}, + {!badSort2.IsValid(), "Coins are not sorted"}, + {!badAmt.IsValid(), "Coins cannot include 0 amounts"}, + {!dup.IsValid(), "Duplicate coin"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass, tl.errMsg) } } diff --git a/types/kvstore_test.go b/types/kvstore_test.go index 5c40a2597b..76ba009f30 100644 --- a/types/kvstore_test.go +++ b/types/kvstore_test.go @@ -2,58 +2,78 @@ package types import ( "bytes" - "fmt" "testing" "github.com/stretchr/testify/assert" ) -func TestMemKVStore(t *testing.T) { +func TestKVStore(t *testing.T) { + //stores to be tested ms := NewMemKVStore() - ms.Set([]byte("foo"), []byte("snake")) - ms.Set([]byte("bar"), []byte("mouse")) - assert.True(t, bytes.Equal(ms.Get([]byte("foo")), []byte("snake")), "MemKVStore doesn't retrieve after Set") - assert.True(t, bytes.Equal(ms.Get([]byte("bar")), []byte("mouse")), "MemKVStore doesn't retrieve after Set") -} - -func TestKVCache(t *testing.T) { - store := NewMemKVStore() kvc := NewKVCache(store) - setRecords := func() { - kvc.Set([]byte("foo"), []byte("snake")) - kvc.Set([]byte("bar"), []byte("mouse")) + //key value pairs to be tested within the system + var keyvalue = []struct { + key string + value string + }{ + {"foo", "snake"}, + {"bar", "mouse"}, } - //test read/write - setRecords() - assert.True(t, bytes.Equal(kvc.Get([]byte("foo")), []byte("snake")), "KVCache doesn't retrieve after Set") - assert.True(t, bytes.Equal(kvc.Get([]byte("bar")), []byte("mouse")), "KVCache doesn't retrieve after Set") + //set the kvc to have all the key value pairs + setRecords := func(kv KVStore) { + for _, n := range keyvalue { + kv.Set([]byte(n.key), []byte(n.value)) + } + } - //test reset - kvc.Reset() - assert.True(t, !bytes.Equal(kvc.Get([]byte("foo")), []byte("snake")), "KVCache retrieving after reset") - assert.True(t, !bytes.Equal(kvc.Get([]byte("bar")), []byte("mouse")), "KVCache retrieving after reset") + //store has all the key value pairs + storeHasAll := func(kv KVStore) bool { + for _, n := range keyvalue { + if !bytes.Equal(kv.Get([]byte(n.key)), []byte(n.value)) { + return false + } + } + return true + } - //test sync - setRecords() - assert.True(t, !bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store retrieving before synced") - assert.True(t, !bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store retrieving before synced") - kvc.Sync() - assert.True(t, bytes.Equal(store.Get([]byte("foo")), []byte("snake")), "store isn't retrieving after synced") - assert.True(t, bytes.Equal(store.Get([]byte("bar")), []byte("mouse")), "store isn't retrieving after synced") + //define the test list + var testList = []struct { + testPass func() bool + errMsg string + }{ + //test read/write for MemKVStore + {func() bool { setRecords(ms); return storeHasAll(ms) }, + "MemKVStore doesn't retrieve after Set"}, - //test logging - assert.True(t, len(kvc.GetLogLines()) == 0, "logging events existed before using SetLogging") - fmt.Println(len(kvc.GetLogLines())) + //test read/write for KVCache + {func() bool { setRecords(kvc); return storeHasAll(kvc) }, + "KVCache doesn't retrieve after Set"}, - kvc.SetLogging() - setRecords() - assert.True(t, len(kvc.GetLogLines()) == 2, "incorrect number of logging events recorded") + //test reset + {func() bool { kvc.Reset(); return !storeHasAll(kvc) }, + "KVCache retrieving after reset"}, - kvc.ClearLogLines() - assert.True(t, len(kvc.GetLogLines()) == 0, "logging events still exists after ClearLogLines") + //test sync + {func() bool { setRecords(kvc); return !storeHasAll(store) }, + "store retrieving before synced"}, + {func() bool { kvc.Sync(); return storeHasAll(store) }, + "store isn't retrieving after synced"}, + //test logging + {func() bool { return len(kvc.GetLogLines()) == 0 }, + "logging events existed before using SetLogging"}, + {func() bool { kvc.SetLogging(); setRecords(kvc); return len(kvc.GetLogLines()) == 2 }, + "incorrect number of logging events recorded"}, + {func() bool { kvc.ClearLogLines(); return len(kvc.GetLogLines()) == 0 }, + "logging events still exists after ClearLogLines"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass(), tl.errMsg) + } } diff --git a/types/plugin_test.go b/types/plugin_test.go index 21cd92114d..2bb9e08490 100644 --- a/types/plugin_test.go +++ b/types/plugin_test.go @@ -31,7 +31,7 @@ func (d *Dummy) EndBlock(store KVStore, height uint64) (res abci.ResponseEndBloc //---------------------------------- -func TestPlugin(t *testing.T) { +/*func TestPlugin(t *testing.T) { plugins := NewPlugins() assert.True(t, len(plugins.GetList()) == 0, "plugins object init with a objects") @@ -39,4 +39,28 @@ func TestPlugin(t *testing.T) { assert.True(t, len(plugins.GetList()) == 1, "plugin wasn't added to plist after registered") dum := plugins.GetByName("dummy") assert.True(t, dum.Name() == "dummy", "plugin wasn't retrieved properly with GetByName") +}*/ + +func TestPlugin(t *testing.T) { + + plugins := NewPlugins() + + //define the test list + var testList = []struct { + testPass func() bool + errMsg string + }{ + {func() bool { return (len(plugins.GetList()) == 0) }, + "plugins object init with a objects"}, + {func() bool { plugins.RegisterPlugin(&Dummy{}); return (len(plugins.GetList()) == 1) }, + "plugin wasn't added to plist after registered"}, + {func() bool { return (plugins.GetByName("dummy").Name() == "dummy") }, + "plugin wasn't retrieved properly with GetByName"}, + } + + //execute the tests + for _, tl := range testList { + assert.True(t, tl.testPass(), tl.errMsg) + } + } diff --git a/types/tx_test.go b/types/tx_test.go index 43bcc032c6..072b78d206 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -3,7 +3,9 @@ package types import ( "testing" - . "github.com/tendermint/go-common" + cmn "github.com/tendermint/go-common" + + "github.com/stretchr/testify/assert" ) var chainID string = "test_chain" @@ -36,11 +38,11 @@ func TestSendTxSignable(t *testing.T) { }, } signBytes := sendTx.SignBytes(chainID) - signBytesHex := Fmt("%X", signBytes) + signBytesHex := cmn.Fmt("%X", signBytes) expected := "010A746573745F636861696E0100000000000000DE00000000000000006F01020106696E7075743101010000000000000030390301093200000106696E70757432010100000000000000006F01DE0000010201076F757470757431010100000000000000014D01076F75747075743201010000000000000001BC" - if signBytesHex != expected { - t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex) - } + + assert.True(t, signBytesHex == expected, + cmn.Fmt("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)) } func TestAppTxSignable(t *testing.T) { @@ -56,9 +58,9 @@ func TestAppTxSignable(t *testing.T) { Data: []byte("data1"), } signBytes := callTx.SignBytes(chainID) - signBytesHex := Fmt("%X", signBytes) + signBytesHex := cmn.Fmt("%X", signBytes) expected := "010A746573745F636861696E0100000000000000DE00000000000000006F0101580106696E70757431010100000000000000303903010932000001056461746131" - if signBytesHex != expected { - t.Errorf("Got unexpected sign string for AppTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex) - } + + assert.True(t, signBytesHex == expected, + cmn.Fmt("Got unexpected sign string for AppTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)) } From 157d46ff519b71547dfe00df2e121291cc5bfdb8 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 23 Feb 2017 18:55:20 -0500 Subject: [PATCH 29/49] string formatting --- cmd/commands/tx.go | 16 ++++++++-------- state/execution.go | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index d1c8980c69..68b0afa102 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -119,7 +119,7 @@ func cmdSendTx(c *cli.Context) error { fmt.Println(string(wire.JSONBytes(tx))) // broadcast the transaction to tendermint - if _, err := broadcastTx(c, tx); err != nil { + if _, _, err := broadcastTx(c, tx); err != nil { return err } return nil @@ -174,17 +174,17 @@ func AppTx(c *cli.Context, name string, data []byte) error { fmt.Println("Signed AppTx:") fmt.Println(string(wire.JSONBytes(tx))) - res, err := broadcastTx(c, tx) + data, log, err := broadcastTx(c, tx) if err != nil { return err } - fmt.Printf("Response: %X\n", res) + fmt.Printf("Response: %X ; %s\n", data, log) return nil } // broadcast the transaction to tendermint -func broadcastTx(c *cli.Context, tx types.Tx) ([]byte, error) { +func broadcastTx(c *cli.Context, tx types.Tx) ([]byte, string, error) { tmResult := new(ctypes.TMResult) tmAddr := c.String("node") clientURI := client.NewClientURI(tmAddr) @@ -196,19 +196,19 @@ func broadcastTx(c *cli.Context, tx types.Tx) ([]byte, error) { }{tx})) _, err := clientURI.Call("broadcast_tx_commit", map[string]interface{}{"tx": txBytes}, tmResult) if err != nil { - return nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) + return nil, "", errors.New(cmn.Fmt("Error on broadcast tx: %v", err)) } res := (*tmResult).(*ctypes.ResultBroadcastTxCommit) // if it fails check, we don't even get a delivertx back! if !res.CheckTx.Code.IsOK() { r := res.CheckTx - return nil, errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)) + return nil, "", errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)) } if !res.DeliverTx.Code.IsOK() { r := res.DeliverTx - return nil, errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)) + return nil, "", errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)) } - return res.DeliverTx.Data, nil + return res.DeliverTx.Data, res.DeliverTx.Log, nil } // if the sequence flag is set, return it; diff --git a/state/execution.go b/state/execution.go index 0b464c45a4..b44c748ecc 100644 --- a/state/execution.go +++ b/state/execution.go @@ -68,7 +68,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e } */ - return abci.OK + return abci.NewResultOK(types.TxID(chainID, tx), "") case *types.AppTx: // Validate input, basic @@ -238,7 +238,7 @@ func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInpu } // Check amount if !balance.IsGTE(in.Coins) { - return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("balance is %d, tried to send %d", balance, in.Coins)) + return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("balance is %v, tried to send %v", balance, in.Coins)) } // Check signatures if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { From 0c12e78d986b3f4638aeb02f0461da29ec877095 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 23 Feb 2017 19:10:19 -0500 Subject: [PATCH 30/49] remove commented test --- types/account_test.go | 1 + types/plugin_test.go | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/types/account_test.go b/types/account_test.go index 2f4d49260f..c6385f36ef 100644 --- a/types/account_test.go +++ b/types/account_test.go @@ -17,6 +17,7 @@ func TestAccount(t *testing.T) { //test Copy accCopy := acc.Copy() assert.True(t, &acc != accCopy, "Account Copy Error") + assert.True(t, acc.Sequence == accCopy.Sequence) //test sending nils for panic var nilAcc *Account diff --git a/types/plugin_test.go b/types/plugin_test.go index 2bb9e08490..9f4b332d0c 100644 --- a/types/plugin_test.go +++ b/types/plugin_test.go @@ -31,16 +31,6 @@ func (d *Dummy) EndBlock(store KVStore, height uint64) (res abci.ResponseEndBloc //---------------------------------- -/*func TestPlugin(t *testing.T) { - - plugins := NewPlugins() - assert.True(t, len(plugins.GetList()) == 0, "plugins object init with a objects") - plugins.RegisterPlugin(&Dummy{}) - assert.True(t, len(plugins.GetList()) == 1, "plugin wasn't added to plist after registered") - dum := plugins.GetByName("dummy") - assert.True(t, dum.Name() == "dummy", "plugin wasn't retrieved properly with GetByName") -}*/ - func TestPlugin(t *testing.T) { plugins := NewPlugins() From 5bba7f6b5655fe7667d3430cc758139fc7da56e9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 23 Feb 2017 20:17:03 -0500 Subject: [PATCH 31/49] glide update --- glide.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/glide.lock b/glide.lock index 83d5df5392..3b315bbef6 100644 --- a/glide.lock +++ b/glide.lock @@ -1,10 +1,12 @@ hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-02-17T09:41:20.209551862-05:00 +updated: 2017-02-23T19:11:29.680601042-05:00 imports: - name: github.com/btcsuite/btcd - version: d06c0bb181529331be8f8d9350288c420d9e60e4 + version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 subpackages: - btcec +- name: github.com/btcsuite/fastsha256 + version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: 99064174e013895bbd9b025c31100bd1d9b590ca - name: github.com/ebuchman/fail-test @@ -12,23 +14,23 @@ imports: - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 8ee79997227bf9b34611aee7946ae64735e6fd93 + version: 1f49d83d9aa00e6ce4fc8258c71cc7786aec968a subpackages: - proto - name: github.com/golang/snappy - version: 553a641470496b2327abcac10b36396bd98e45c9 + version: d9eb7a3d35ec988b8585d4a0068e462c27d28380 - name: github.com/gorilla/websocket version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13 - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/mattn/go-colorable - version: 5411d3eea5978e6cdc258b30de592b60df6aba96 + version: ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 - name: github.com/mattn/go-isatty - version: dda3de49cbfcec471bd7a70e6cc01fcc3ff90109 + version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 - name: github.com/pkg/errors version: 248dadf4e9068a0b3e79f02ed0a610d935de5302 - name: github.com/syndtr/goleveldb - version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65 + version: 6ae1797c0b42b9323fc27ff7dcf568df88f2f33d subpackages: - leveldb - leveldb/cache @@ -43,7 +45,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 31bdda27ad80e47d372e4b9e4acfd4c0ef81d3e4 + version: 33e52343d00552dd57ad45621947eb8957ebbca4 subpackages: - client - example/dummy @@ -75,7 +77,7 @@ imports: - name: github.com/tendermint/go-logger version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2 - name: github.com/tendermint/go-merkle - version: 9f20e80cb188d07860caa70196dd7700659ec4a4 + version: 653cb1f631528351ddbc359b994eb0c96f0341cd - name: github.com/tendermint/go-p2p version: 67c9086b7458eb45b1970483decd01cd744c477a subpackages: @@ -89,16 +91,16 @@ imports: - name: github.com/tendermint/go-wire version: 3216ec9d47bbdf8d4fc27d22169ea86a6688bc15 - name: github.com/tendermint/log15 - version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6 + version: 9545b249b3aacafa97f79e0838b02b274adc6f5f subpackages: - term - name: github.com/tendermint/merkleeyes - version: 87b0a111a716f1495f30ce58bd469e36ac220e09 + version: acd8e9c42e1d819c51e9e1cd3870ea4d94b167f5 subpackages: - app - client - name: github.com/tendermint/tendermint - version: 3ebd69db1bc9133777883e5e0734f4a09f738e8a + version: f73f53c486f0571396e414f338902cee4607f51d subpackages: - blockchain - config/tendermint @@ -113,9 +115,9 @@ imports: - types - version - name: github.com/urfave/cli - version: 2526b57c56f30b50466c96c4133b1a4ad0f0191f + version: 8ef3805c9de2519805c3f060524b695bba2cd715 - name: golang.org/x/crypto - version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8 + version: aa2481cbfe81d911eb62b642b7a6b5ec58bbea71 subpackages: - curve25519 - nacl/box @@ -126,21 +128,20 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: b4690f45fa1cafc47b1c280c2e75116efe40cc13 + version: cfe3c2a7525b50c3d707256e371c90938cfef98a subpackages: - context - http2 - http2/hpack - - idna - internal/timeseries - lex/httplex - trace - name: golang.org/x/sys - version: 075e574b89e4c2d22f2286a7e2b919519c6f3547 + version: 30de6d19a3bd89a5f38ae4028e23aaa5582648af subpackages: - unix - name: google.golang.org/grpc - version: d0c32ee6a441117d49856d6120ca9552af413ee0 + version: 50955793b0183f9de69bd78e2ec251cf20aab121 subpackages: - codes - credentials @@ -154,15 +155,14 @@ imports: - transport testImports: - name: github.com/davecgh/go-spew - version: 346938d642f2ec3594ed81d874461961cd0faa76 + version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 subpackages: - spew - name: github.com/pmezard/go-difflib - version: 792786c7400a136282c1664665ae0a8db921c6c2 + version: d8ed2627bdf02c080bf22230dbb337003b7aba2d subpackages: - difflib - name: github.com/stretchr/testify version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert - - require From 1ecfe90f35b66992421478c2e74bf6a85efeb5a9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 23 Feb 2017 20:17:11 -0500 Subject: [PATCH 32/49] fix demo --amount --- demo/start.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demo/start.sh b/demo/start.sh index f2b85a5812..4b6d518870 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -68,14 +68,14 @@ waitForNode localhost:36657 echo "... registering chain1 on chain2" echo "" # register chain1 on chain2 -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/tendermint/genesis.json echo "" echo "... creating egress packet on chain1" echo "" # create a packet on chain1 destined for chain2 PAYLOAD="DEADBEEF" #TODO -basecoin tx ibc --amount 10 $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload $PAYLOAD --sequence 1 +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload $PAYLOAD --sequence 1 echo "" echo "... querying for packet data" @@ -121,13 +121,13 @@ echo "" echo "... updating state of chain1 on chain2" echo "" # update the state of chain1 on chain2 -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 update --header 0x$HEADER --commit 0x$COMMIT +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x$HEADER --commit 0x$COMMIT echo "" echo "... posting packet from chain1 on chain2" echo "" # post the packet from chain1 to chain2 -basecoin tx ibc --amount 10 $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF +basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF echo "" echo "... checking if the packet is present on chain2" From 4fb3924d223885b89d5b18860de9564bb6ba3eeb Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 24 Feb 2017 16:59:44 -0500 Subject: [PATCH 33/49] fix data/key.json --- data/key.json | 2 +- data/key2.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/key.json b/data/key.json index 7a8c075604..34ea194386 100644 --- a/data/key.json +++ b/data/key.json @@ -2,7 +2,7 @@ "address": "1B1BE55F969F54064628A63B9559E7C21C925165", "priv_key": [ 1, - "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D10000000000000000000000000000000000000000000000000000000000000000" + "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" ], "pub_key": [ 1, diff --git a/data/key2.json b/data/key2.json index f6f8d3693a..38af8af74b 100644 --- a/data/key2.json +++ b/data/key2.json @@ -2,7 +2,7 @@ "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", "priv_key": [ 1, - "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A80000000000000000000000000000000000000000000000000000000000000000" + "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A8352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" ], "pub_key": [ 1, From fe81f87a138d404ffb302fceb3d033d972b16151 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 24 Feb 2017 17:12:05 -0500 Subject: [PATCH 34/49] fix for empty coins in Plus() --- state/execution.go | 33 +++++++++++++++++++-------------- types/coin.go | 2 ++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/state/execution.go b/state/execution.go index b44c748ecc..b73cab4dc0 100644 --- a/state/execution.go +++ b/state/execution.go @@ -3,7 +3,7 @@ package state import ( abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/types" - . "github.com/tendermint/go-common" + cmn "github.com/tendermint/go-common" "github.com/tendermint/go-events" ) @@ -44,8 +44,13 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e return res.PrependLog("in validateInputsAdvanced()") } outTotal := sumOutputs(tx.Outputs) - if !inTotal.IsEqual(outTotal.Plus(types.Coins{tx.Fee})) { - return abci.ErrBaseInvalidOutput.AppendLog("Input total != output total + fees") + outPlusFees := outTotal + fees := types.Coins{tx.Fee} + if fees.IsValid() { // TODO: fix coins.Plus() + outPlusFees = outTotal.Plus(fees) + } + if !inTotal.IsEqual(outPlusFees) { + return abci.ErrBaseInvalidOutput.AppendLog(cmn.Fmt("Input total (%v) != output total + fees (%v)", inTotal, outPlusFees)) } // TODO: Fee validation for SendTx @@ -90,19 +95,19 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e signBytes := tx.SignBytes(chainID) res = validateInputAdvanced(inAcc, signBytes, tx.Input) if res.IsErr() { - log.Info(Fmt("validateInputAdvanced failed on %X: %v", tx.Input.Address, res)) + log.Info(cmn.Fmt("validateInputAdvanced failed on %X: %v", tx.Input.Address, res)) return res.PrependLog("in validateInputAdvanced()") } if !tx.Input.Coins.IsGTE(types.Coins{tx.Fee}) { - log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) - return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("input coins is %d, but fee is %d", tx.Input.Coins, types.Coins{tx.Fee})) + log.Info(cmn.Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) + return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("input coins is %d, but fee is %d", tx.Input.Coins, types.Coins{tx.Fee})) } // Validate call address plugin := pgz.GetByName(tx.Name) if plugin == nil { return abci.ErrBaseUnknownAddress.AppendLog( - Fmt("Unrecognized plugin name%v", tx.Name)) + cmn.Fmt("Unrecognized plugin name%v", tx.Name)) } // Good! @@ -218,7 +223,7 @@ func validateInputsAdvanced(accounts map[string]*types.Account, signBytes []byte for _, in := range ins { acc := accounts[string(in.Address)] if acc == nil { - PanicSanity("validateInputsAdvanced() expects account in accounts") + cmn.PanicSanity("validateInputsAdvanced() expects account in accounts") } res = validateInputAdvanced(acc, signBytes, in) if res.IsErr() { @@ -234,15 +239,15 @@ func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInpu // Check sequence/coins seq, balance := acc.Sequence, acc.Balance if seq+1 != in.Sequence { - return abci.ErrBaseInvalidSequence.AppendLog(Fmt("Got %v, expected %v. (acc.seq=%v)", in.Sequence, seq+1, acc.Sequence)) + return abci.ErrBaseInvalidSequence.AppendLog(cmn.Fmt("Got %v, expected %v. (acc.seq=%v)", in.Sequence, seq+1, acc.Sequence)) } // Check amount if !balance.IsGTE(in.Coins) { - return abci.ErrBaseInsufficientFunds.AppendLog(Fmt("balance is %v, tried to send %v", balance, in.Coins)) + return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("balance is %v, tried to send %v", balance, in.Coins)) } // Check signatures if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { - return abci.ErrBaseInvalidSignature.AppendLog(Fmt("SignBytes: %X", signBytes)) + return abci.ErrBaseInvalidSignature.AppendLog(cmn.Fmt("SignBytes: %X", signBytes)) } return abci.OK } @@ -268,10 +273,10 @@ func adjustByInputs(state types.AccountSetter, accounts map[string]*types.Accoun for _, in := range ins { acc := accounts[string(in.Address)] if acc == nil { - PanicSanity("adjustByInputs() expects account in accounts") + cmn.PanicSanity("adjustByInputs() expects account in accounts") } if !acc.Balance.IsGTE(in.Coins) { - PanicSanity("adjustByInputs() expects sufficient funds") + cmn.PanicSanity("adjustByInputs() expects sufficient funds") } acc.Balance = acc.Balance.Minus(in.Coins) acc.Sequence += 1 @@ -283,7 +288,7 @@ func adjustByOutputs(state types.AccountSetter, accounts map[string]*types.Accou for _, out := range outs { acc := accounts[string(out.Address)] if acc == nil { - PanicSanity("adjustByOutputs() expects account in accounts") + cmn.PanicSanity("adjustByOutputs() expects account in accounts") } acc.Balance = acc.Balance.Plus(out.Coins) if !isCheckTx { diff --git a/types/coin.go b/types/coin.go index b64f78bc97..90b2f30c0f 100644 --- a/types/coin.go +++ b/types/coin.go @@ -42,6 +42,8 @@ func (coins Coins) IsValid() bool { } } +// TODO: handle empty coins! +// Currently appends an empty coin ... func (coinsA Coins) Plus(coinsB Coins) Coins { sum := []Coin{} indexA, indexB := 0, 0 From c1fa8cb0d21d3bb424638a4e694b2a86f3b4fe36 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 23 Feb 2017 17:04:03 +0100 Subject: [PATCH 35/49] Use new go-crypto S structs to get full go-data support --- cmd/commands/tx.go | 5 +- glide.lock | 4 +- plugins/counter/counter_test.go | 5 +- plugins/ibc/ibc_test.go | 2 +- state/execution.go | 12 ++--- state/state_test.go | 2 - tests/tendermint/main.go | 9 ++-- tests/tmsp/tmsp_test.go | 21 +++++---- testutils/testing.go | 8 ++-- types/account.go | 8 ++-- types/tx.go | 83 ++++++++++++++++++++++----------- 11 files changed, 94 insertions(+), 65 deletions(-) diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index 68b0afa102..de1a923277 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -8,6 +8,7 @@ import ( "github.com/urfave/cli" "github.com/tendermint/basecoin/types" + crypto "github.com/tendermint/go-crypto" cmn "github.com/tendermint/go-common" client "github.com/tendermint/go-rpc/client" @@ -113,7 +114,7 @@ func cmdSendTx(c *cli.Context) error { // sign that puppy signBytes := tx.SignBytes(chainID) - tx.Inputs[0].Signature = privKey.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{privKey.Sign(signBytes)} fmt.Println("Signed SendTx:") fmt.Println(string(wire.JSONBytes(tx))) @@ -169,7 +170,7 @@ func AppTx(c *cli.Context, name string, data []byte) error { Data: data, } - tx.Input.Signature = privKey.Sign(tx.SignBytes(chainID)) + tx.Input.Signature = crypto.SignatureS{privKey.Sign(tx.SignBytes(chainID))} fmt.Println("Signed AppTx:") fmt.Println(string(wire.JSONBytes(tx))) diff --git a/glide.lock b/glide.lock index 3b315bbef6..ca1aad031b 100644 --- a/glide.lock +++ b/glide.lock @@ -65,7 +65,9 @@ imports: - name: github.com/tendermint/go-config version: e64b424499acd0eb9856b88e10c0dff41628c0d6 - name: github.com/tendermint/go-crypto - version: 4b11d62bdb324027ea01554e5767b71174680ba0 + version: b6a2c5949f7ea1d064cbb9dc638eb0a3dca9af34 +- name: github.com/tendermint/go-data + version: 35a95d275fa845b635e1208c3dd65b19c4eda811 - name: github.com/tendermint/go-db version: 2645626c33d8702739e52a61a55d705c2dfe4530 - name: github.com/tendermint/go-events diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index a4c4236230..e96cbc56b0 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -8,6 +8,7 @@ import ( "github.com/tendermint/basecoin/app" "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" eyescli "github.com/tendermint/merkleeyes/client" ) @@ -47,8 +48,8 @@ func TestCounterPlugin(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) t.Logf("Sign bytes: %X\n", signBytes) - sig := test1PrivAcc.PrivKey.Sign(signBytes) - tx.Input.Signature = sig + sig := test1PrivAcc.Sign(signBytes) + tx.Input.Signature = crypto.SignatureS{sig} t.Logf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) // Write request diff --git a/plugins/ibc/ibc_test.go b/plugins/ibc/ibc_test.go index 6bc3f0706e..51ee5f31f9 100644 --- a/plugins/ibc/ibc_test.go +++ b/plugins/ibc/ibc_test.go @@ -31,7 +31,7 @@ func genGenesisDoc(chainID string, numVals int) (*tm.GenesisDoc, []types.PrivAcc name := cmn.Fmt("%v_val_%v", chainID, i) privAcc := testutils.PrivAccountFromSecret(name) genDoc.Validators = append(genDoc.Validators, tm.GenesisValidator{ - PubKey: privAcc.Account.PubKey, + PubKey: privAcc.PubKey.PubKey, Amount: 1, Name: name, }) diff --git a/state/execution.go b/state/execution.go index b73cab4dc0..3452c399ab 100644 --- a/state/execution.go +++ b/state/execution.go @@ -87,7 +87,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e if inAcc == nil { return abci.ErrBaseUnknownAddress } - if tx.Input.PubKey != nil { + if !tx.Input.PubKey.Empty() { inAcc.PubKey = tx.Input.PubKey } @@ -176,7 +176,7 @@ func getInputs(state types.AccountGetter, ins []types.TxInput) (map[string]*type return nil, abci.ErrBaseUnknownAddress } - if in.PubKey != nil { + if !in.PubKey.Empty() { acc.PubKey = in.PubKey } accounts[string(in.Address)] = acc @@ -197,10 +197,8 @@ func getOrMakeOutputs(state types.AccountGetter, accounts map[string]*types.Acco acc := state.GetAccount(out.Address) // output account may be nil (new) if acc == nil { - acc = &types.Account{ - PubKey: nil, - Sequence: 0, - } + // zero value is valid, empty account + acc = &types.Account{} } accounts[string(out.Address)] = acc } @@ -246,7 +244,7 @@ func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInpu return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("balance is %v, tried to send %v", balance, in.Coins)) } // Check signatures - if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { + if !acc.PubKey.VerifyBytes(signBytes, in.Signature.Signature) { return abci.ErrBaseInvalidSignature.AppendLog(cmn.Fmt("SignBytes: %X", signBytes)) } return abci.OK diff --git a/state/state_test.go b/state/state_test.go index 162b8e9f76..6eae18de91 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -22,9 +22,7 @@ func TestState(t *testing.T) { dumAddr := []byte("dummyAddress") acc := &types.Account{ - PubKey: nil, Sequence: 1, - Balance: nil, } //reset the store/state/cache diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go index 1776952b3b..27618ca368 100644 --- a/tests/tendermint/main.go +++ b/tests/tendermint/main.go @@ -8,6 +8,7 @@ import ( "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-rpc/client" "github.com/tendermint/go-rpc/types" "github.com/tendermint/go-wire" @@ -66,8 +67,8 @@ func main() { // Sign request signBytes := tx.SignBytes(chainID) - sig := root.PrivKey.Sign(signBytes) - tx.Inputs[0].Signature = sig + sig := root.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{sig} //fmt.Println("tx:", tx) // Write request @@ -116,8 +117,8 @@ func main() { // Sign request signBytes := tx.SignBytes(chainID) - sig := privAccountA.PrivKey.Sign(signBytes) - tx.Inputs[0].Signature = sig + sig := privAccountA.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{sig} //fmt.Println("tx:", tx) // Write request diff --git a/tests/tmsp/tmsp_test.go b/tests/tmsp/tmsp_test.go index c00cadedbe..62f16eb6ea 100644 --- a/tests/tmsp/tmsp_test.go +++ b/tests/tmsp/tmsp_test.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" eyescli "github.com/tendermint/merkleeyes/client" ) @@ -44,12 +45,12 @@ func TestSendTx(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) t.Log("Sign bytes: %X\n", signBytes) - sig := test1PrivAcc.PrivKey.Sign(signBytes) - tx.Inputs[0].Signature = sig - t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) + sig := test1PrivAcc.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{sig} + t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(types.TxS{tx})) // Write request - txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) + txBytes := wire.BinaryBytes(types.TxS{tx}) res := bcApp.DeliverTx(txBytes) t.Log(res) if res.IsErr() { @@ -96,8 +97,8 @@ func TestSequence(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) - sig := test1PrivAcc.PrivKey.Sign(signBytes) - tx.Inputs[0].Signature = sig + sig := test1PrivAcc.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{sig} // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) // Write request @@ -133,11 +134,11 @@ func TestSequence(t *testing.T) { Gas: 2, Fee: types.Coin{"", 2}, Inputs: []types.TxInput{ - types.NewTxInput(privAccountA.Account.PubKey, types.Coins{{"", 3}}, privAccountASequence+1), + types.NewTxInput(privAccountA.PubKey, types.Coins{{"", 3}}, privAccountASequence+1), }, Outputs: []types.TxOutput{ types.TxOutput{ - Address: privAccountB.Account.PubKey.Address(), + Address: privAccountB.PubKey.Address(), Coins: types.Coins{{"", 1}}, }, }, @@ -145,8 +146,8 @@ func TestSequence(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) - sig := privAccountA.PrivKey.Sign(signBytes) - tx.Inputs[0].Signature = sig + sig := privAccountA.Sign(signBytes) + tx.Inputs[0].Signature = crypto.SignatureS{sig} // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address) // Write request diff --git a/testutils/testing.go b/testutils/testing.go index f91394a0e1..930b3a7149 100644 --- a/testutils/testing.go +++ b/testutils/testing.go @@ -12,9 +12,9 @@ import ( func PrivAccountFromSecret(secret string) types.PrivAccount { privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret)) privAccount := types.PrivAccount{ - PrivKey: privKey, + PrivKeyS: crypto.PrivKeyS{privKey}, Account: types.Account{ - PubKey: privKey.PubKey(), + PubKey: crypto.PubKeyS{privKey.PubKey()}, Sequence: 0, }, } @@ -32,9 +32,9 @@ func RandAccounts(num int, minAmount int64, maxAmount int64) []types.PrivAccount } privKey := crypto.GenPrivKeyEd25519() - pubKey := privKey.PubKey() + pubKey := crypto.PubKeyS{privKey.PubKey()} privAccs[i] = types.PrivAccount{ - PrivKey: privKey, + PrivKeyS: crypto.PrivKeyS{privKey}, Account: types.Account{ PubKey: pubKey, Sequence: 0, diff --git a/types/account.go b/types/account.go index d1e62d8321..b3478fce0c 100644 --- a/types/account.go +++ b/types/account.go @@ -7,9 +7,9 @@ import ( ) type Account struct { - PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. - Sequence int `json:"sequence"` - Balance Coins `json:"coins"` + PubKey crypto.PubKeyS `json:"pub_key"` // May be nil, if not known. + Sequence int `json:"sequence"` + Balance Coins `json:"coins"` } func (acc *Account) Copy() *Account { @@ -31,7 +31,7 @@ func (acc *Account) String() string { //---------------------------------------- type PrivAccount struct { - crypto.PrivKey + crypto.PrivKeyS Account } diff --git a/types/tx.go b/types/tx.go index b8757e44aa..92f69d84fc 100644 --- a/types/tx.go +++ b/types/tx.go @@ -7,6 +7,7 @@ import ( abci "github.com/tendermint/abci/types" . "github.com/tendermint/go-common" "github.com/tendermint/go-crypto" + "github.com/tendermint/go-data" "github.com/tendermint/go-wire" ) @@ -17,7 +18,6 @@ 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 @@ -28,25 +28,47 @@ const ( // Account transactions TxTypeSend = byte(0x01) TxTypeApp = byte(0x02) + TxNameSend = "send" + TxNameApp = "app" ) func (_ *SendTx) AssertIsTx() {} func (_ *AppTx) AssertIsTx() {} -var _ = wire.RegisterInterface( - struct{ Tx }{}, - wire.ConcreteType{&SendTx{}, TxTypeSend}, - wire.ConcreteType{&AppTx{}, TxTypeApp}, -) +var txMapper data.Mapper + +// register both private key types with go-data (and thus go-wire) +func init() { + txMapper = data.NewMapper(TxS{}). + RegisterInterface(&SendTx{}, TxNameSend, TxTypeSend). + RegisterInterface(&AppTx{}, TxNameApp, TxTypeApp) +} + +// TxS add json serialization to Tx +type TxS struct { + Tx +} + +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 []byte `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 + 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.SignatureS `json:"signature"` // Depends on the PubKey type and the whole Tx + PubKey crypto.PubKeyS `json:"pub_key"` // Is present iff Sequence == 0 } func (txIn TxInput) ValidateBasic() abci.Result { @@ -62,10 +84,10 @@ func (txIn TxInput) ValidateBasic() abci.Result { if txIn.Sequence <= 0 { return abci.ErrBaseInvalidInput.AppendLog("Sequence must be greater than 0") } - if txIn.Sequence == 1 && txIn.PubKey == nil { + if txIn.Sequence == 1 && txIn.PubKey.Empty() { return abci.ErrBaseInvalidInput.AppendLog("PubKey must be present when Sequence == 1") } - if txIn.Sequence > 1 && txIn.PubKey != nil { + if txIn.Sequence > 1 && !txIn.PubKey.Empty() { return abci.ErrBaseInvalidInput.AppendLog("PubKey must be nil when Sequence > 1") } return abci.OK @@ -78,12 +100,17 @@ func (txIn TxInput) String() string { func NewTxInput(pubKey crypto.PubKey, coins Coins, sequence int) TxInput { input := TxInput{ Address: pubKey.Address(), - PubKey: pubKey, Coins: coins, Sequence: sequence, } - if sequence > 1 { - input.PubKey = nil + if sequence == 1 { + // safely wrap if needed + // TODO: extract this as utility function? + ps, ok := pubKey.(crypto.PubKeyS) + if !ok { + ps = crypto.PubKeyS{pubKey} + } + input.PubKey = ps } return input } @@ -91,8 +118,8 @@ func NewTxInput(pubKey crypto.PubKey, coins Coins, sequence int) TxInput { //----------------------------------------------------------------------------- type TxOutput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // + Address data.Bytes `json:"address"` // Hash of the PubKey + Coins Coins `json:"coins"` // } func (txOut TxOutput) ValidateBasic() abci.Result { @@ -126,11 +153,11 @@ func (tx *SendTx) SignBytes(chainID string) []byte { sigz := make([]crypto.Signature, len(tx.Inputs)) for i, input := range tx.Inputs { sigz[i] = input.Signature - tx.Inputs[i].Signature = nil + tx.Inputs[i].Signature.Signature = nil } signBytes = append(signBytes, wire.BinaryBytes(tx)...) for i := range tx.Inputs { - tx.Inputs[i].Signature = sigz[i] + tx.Inputs[i].Signature.Signature = sigz[i] } return signBytes } @@ -138,7 +165,7 @@ func (tx *SendTx) SignBytes(chainID string) []byte { 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 + tx.Inputs[i].Signature.Signature = sig return true } } @@ -152,24 +179,24 @@ func (tx *SendTx) String() string { //----------------------------------------------------------------------------- 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 []byte `json:"data"` + 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 = nil + tx.Input.Signature.Signature = nil signBytes = append(signBytes, wire.BinaryBytes(tx)...) tx.Input.Signature = sig return signBytes } func (tx *AppTx) SetSignature(sig crypto.Signature) bool { - tx.Input.Signature = sig + tx.Input.Signature.Signature = sig return true } From 4ad645f318014ff32711607c903490b25218d6b2 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 23 Feb 2017 18:30:57 +0100 Subject: [PATCH 36/49] Proper json marshalling/unmarshalling of sendtx with or w/o sig --- glide.lock | 4 +-- types/account_test.go | 8 ++--- types/tx.go | 12 +++++-- types/tx_test.go | 76 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/glide.lock b/glide.lock index ca1aad031b..661701940d 100644 --- a/glide.lock +++ b/glide.lock @@ -65,9 +65,9 @@ imports: - name: github.com/tendermint/go-config version: e64b424499acd0eb9856b88e10c0dff41628c0d6 - name: github.com/tendermint/go-crypto - version: b6a2c5949f7ea1d064cbb9dc638eb0a3dca9af34 + version: 8c9b889ccfe1f891ce8ab36c843f15794ce8f30f - name: github.com/tendermint/go-data - version: 35a95d275fa845b635e1208c3dd65b19c4eda811 + version: f199ef165cd5a50d569b179201702c5ec8899013 - name: github.com/tendermint/go-db version: 2645626c33d8702739e52a61a55d705c2dfe4530 - name: github.com/tendermint/go-events diff --git a/types/account_test.go b/types/account_test.go index c6385f36ef..77dfba9d8b 100644 --- a/types/account_test.go +++ b/types/account_test.go @@ -6,13 +6,9 @@ import ( "github.com/stretchr/testify/assert" ) -func TestAccount(t *testing.T) { +func TestNilAccount(t *testing.T) { - acc := Account{ - PubKey: nil, - Sequence: 0, - Balance: nil, - } + acc := Account{} //test Copy accCopy := acc.Copy() diff --git a/types/tx.go b/types/tx.go index 92f69d84fc..5dcec7dacc 100644 --- a/types/tx.go +++ b/types/tx.go @@ -163,9 +163,13 @@ func (tx *SendTx) SignBytes(chainID string) []byte { } func (tx *SendTx) SetSignature(addr []byte, sig crypto.Signature) bool { + sigs, ok := sig.(crypto.SignatureS) + if !ok { + sigs = crypto.SignatureS{sig} + } for i, input := range tx.Inputs { if bytes.Equal(input.Address, addr) { - tx.Inputs[i].Signature.Signature = sig + tx.Inputs[i].Signature = sigs return true } } @@ -196,7 +200,11 @@ func (tx *AppTx) SignBytes(chainID string) []byte { } func (tx *AppTx) SetSignature(sig crypto.Signature) bool { - tx.Input.Signature.Signature = sig + sigs, ok := sig.(crypto.SignatureS) + if !ok { + sigs = crypto.SignatureS{sig} + } + tx.Input.Signature = sigs return true } diff --git a/types/tx_test.go b/types/tx_test.go index 072b78d206..982ceb1bf9 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -3,9 +3,11 @@ package types import ( "testing" - cmn "github.com/tendermint/go-common" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + cmn "github.com/tendermint/go-common" + crypto "github.com/tendermint/go-crypto" + data "github.com/tendermint/go-data" ) var chainID string = "test_chain" @@ -62,5 +64,73 @@ func TestAppTxSignable(t *testing.T) { expected := "010A746573745F636861696E0100000000000000DE00000000000000006F0101580106696E70757431010100000000000000303903010932000001056461746131" assert.True(t, signBytesHex == expected, - cmn.Fmt("Got unexpected sign string for AppTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)) + cmn.Fmt("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)) +} + +// d'oh, can't use the version in testutils due to circular imports :( +func makePrivAcct() PrivAccount { + privKey := crypto.PrivKeyS{crypto.GenPrivKeyEd25519()} + return PrivAccount{ + PrivKeyS: privKey, + Account: Account{ + PubKey: crypto.PubKeyS{privKey.PubKey()}, + }, + } +} + +func TestSendTxJSON(t *testing.T) { + chainID := "test_chain_id" + test1PrivAcc := makePrivAcct() + test2PrivAcc := makePrivAcct() + + // 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(t, err) + // fmt.Println(string(js)) + txs := TxS{} + err = data.FromJSON(js, &txs) + require.Nil(t, err) + tx2, ok := txs.Tx.(*SendTx) + require.True(t, ok) + + // make sure they are the same! + signBytes := tx.SignBytes(chainID) + signBytes2 := tx2.SignBytes(chainID) + assert.Equal(t, signBytes, signBytes2) + assert.Equal(t, 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(), crypto.SignatureS{sig}) + assert.Equal(t, tx, tx2) + + // let's marshal / unmarshal this with signature + js, err = data.ToJSON(TxS{tx}) + require.Nil(t, err) + // fmt.Println(string(js)) + err = data.FromJSON(js, &txs) + require.Nil(t, err) + tx2, ok = txs.Tx.(*SendTx) + require.True(t, ok) + + // and make sure the sig is preserved + assert.Equal(t, tx, tx2) + assert.False(t, tx2.Inputs[0].Signature.Empty()) } From 1fd2d17cd99bb8060796102d23e93bbe132e334c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 24 Feb 2017 22:24:01 +0100 Subject: [PATCH 37/49] Update go-crypto, move testutils into types --- Makefile | 2 +- glide.lock | 2 +- plugins/counter/counter_test.go | 3 +-- plugins/ibc/ibc_test.go | 3 +-- tests/tendermint/main.go | 5 ++-- tests/tmsp/tmsp_test.go | 9 +++---- testutils/testing.go | 47 --------------------------------- types/test_helpers.go | 45 +++++++++++++++++++++++++++++++ types/tx_test.go | 15 ++--------- 9 files changed, 57 insertions(+), 74 deletions(-) delete mode 100644 testutils/testing.go create mode 100644 types/test_helpers.go diff --git a/Makefile b/Makefile index 42ccfc69c9..89f9af72b5 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ install: go install github.com/tendermint/basecoin/cmd/... test: - go test --race `${NOVENDOR}` + go test `${NOVENDOR}` #go run tests/tendermint/*.go get_deps: diff --git a/glide.lock b/glide.lock index 661701940d..7c681e9a9d 100644 --- a/glide.lock +++ b/glide.lock @@ -65,7 +65,7 @@ imports: - name: github.com/tendermint/go-config version: e64b424499acd0eb9856b88e10c0dff41628c0d6 - name: github.com/tendermint/go-crypto - version: 8c9b889ccfe1f891ce8ab36c843f15794ce8f30f + version: 562b4cc9ef0d20217f6e95679f9e83cb7bc98b17 - name: github.com/tendermint/go-data version: f199ef165cd5a50d569b179201702c5ec8899013 - name: github.com/tendermint/go-db diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index e96cbc56b0..d93333b009 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/assert" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/app" - "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" @@ -27,7 +26,7 @@ func TestCounterPlugin(t *testing.T) { bcApp.RegisterPlugin(counterPlugin) // Account initialization - test1PrivAcc := testutils.PrivAccountFromSecret("test1") + test1PrivAcc := types.PrivAccountFromSecret("test1") // Seed Basecoin with account test1Acc := test1PrivAcc.Account diff --git a/plugins/ibc/ibc_test.go b/plugins/ibc/ibc_test.go index 51ee5f31f9..0f2ab88540 100644 --- a/plugins/ibc/ibc_test.go +++ b/plugins/ibc/ibc_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/assert" abci "github.com/tendermint/abci/types" - "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" crypto "github.com/tendermint/go-crypto" @@ -29,7 +28,7 @@ func genGenesisDoc(chainID string, numVals int) (*tm.GenesisDoc, []types.PrivAcc for i := 0; i < numVals; i++ { name := cmn.Fmt("%v_val_%v", chainID, i) - privAcc := testutils.PrivAccountFromSecret(name) + privAcc := types.PrivAccountFromSecret(name) genDoc.Validators = append(genDoc.Validators, tm.GenesisValidator{ PubKey: privAcc.PubKey.PubKey, Amount: 1, diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go index 27618ca368..5481bfd3a8 100644 --- a/tests/tendermint/main.go +++ b/tests/tendermint/main.go @@ -5,7 +5,6 @@ import ( "time" "github.com/gorilla/websocket" - "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" crypto "github.com/tendermint/go-crypto" @@ -38,10 +37,10 @@ func main() { }() // Get the root account - root := testutils.PrivAccountFromSecret("test") + root := types.PrivAccountFromSecret("test") sequence := int(0) // Make a bunch of PrivAccounts - privAccounts := testutils.RandAccounts(1000, 1000000, 0) + privAccounts := types.RandAccounts(1000, 1000000, 0) privAccountSequences := make(map[string]int) // Send coins to each account diff --git a/tests/tmsp/tmsp_test.go b/tests/tmsp/tmsp_test.go index 62f16eb6ea..4d250394b5 100644 --- a/tests/tmsp/tmsp_test.go +++ b/tests/tmsp/tmsp_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/tendermint/basecoin/app" - "github.com/tendermint/basecoin/testutils" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" crypto "github.com/tendermint/go-crypto" @@ -19,8 +18,8 @@ func TestSendTx(t *testing.T) { bcApp.SetOption("base/chainID", chainID) t.Log(bcApp.Info()) - test1PrivAcc := testutils.PrivAccountFromSecret("test1") - test2PrivAcc := testutils.PrivAccountFromSecret("test2") + test1PrivAcc := types.PrivAccountFromSecret("test1") + test2PrivAcc := types.PrivAccountFromSecret("test2") // Seed Basecoin with account test1Acc := test1PrivAcc.Account @@ -66,14 +65,14 @@ func TestSequence(t *testing.T) { t.Log(bcApp.Info()) // Get the test account - test1PrivAcc := testutils.PrivAccountFromSecret("test1") + test1PrivAcc := types.PrivAccountFromSecret("test1") test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1 << 53}} t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) sequence := int(1) // Make a bunch of PrivAccounts - privAccounts := testutils.RandAccounts(1000, 1000000, 0) + privAccounts := types.RandAccounts(1000, 1000000, 0) privAccountSequences := make(map[string]int) // Send coins to each account diff --git a/testutils/testing.go b/testutils/testing.go deleted file mode 100644 index 930b3a7149..0000000000 --- a/testutils/testing.go +++ /dev/null @@ -1,47 +0,0 @@ -// Functions used in testing throughout -package testutils - -import ( - "github.com/tendermint/basecoin/types" - . "github.com/tendermint/go-common" - "github.com/tendermint/go-crypto" -) - -// Creates a PrivAccount from secret. -// The amount is not set. -func PrivAccountFromSecret(secret string) types.PrivAccount { - privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret)) - privAccount := types.PrivAccount{ - PrivKeyS: crypto.PrivKeyS{privKey}, - Account: types.Account{ - PubKey: crypto.PubKeyS{privKey.PubKey()}, - Sequence: 0, - }, - } - return privAccount -} - -// Make `num` random accounts -func RandAccounts(num int, minAmount int64, maxAmount int64) []types.PrivAccount { - privAccs := make([]types.PrivAccount, num) - for i := 0; i < num; i++ { - - balance := minAmount - if maxAmount > minAmount { - balance += RandInt64() % (maxAmount - minAmount) - } - - privKey := crypto.GenPrivKeyEd25519() - pubKey := crypto.PubKeyS{privKey.PubKey()} - privAccs[i] = types.PrivAccount{ - PrivKeyS: crypto.PrivKeyS{privKey}, - Account: types.Account{ - PubKey: pubKey, - Sequence: 0, - Balance: types.Coins{types.Coin{"", balance}}, - }, - } - } - - return privAccs -} diff --git a/types/test_helpers.go b/types/test_helpers.go new file mode 100644 index 0000000000..c7ce21ff0f --- /dev/null +++ b/types/test_helpers.go @@ -0,0 +1,45 @@ +package types + +// Helper functions for testing + +import ( + cmn "github.com/tendermint/go-common" + "github.com/tendermint/go-crypto" +) + +// Creates a PrivAccount from secret. +// The amount is not set. +func PrivAccountFromSecret(secret string) PrivAccount { + privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret)) + privAccount := PrivAccount{ + PrivKeyS: crypto.PrivKeyS{privKey}, + Account: Account{ + PubKey: crypto.PubKeyS{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++ { + + balance := minAmount + if maxAmount > minAmount { + balance += cmn.RandInt64() % (maxAmount - minAmount) + } + + privKey := crypto.GenPrivKeyEd25519() + pubKey := crypto.PubKeyS{privKey.PubKey()} + privAccs[i] = PrivAccount{ + PrivKeyS: crypto.PrivKeyS{privKey}, + Account: Account{ + PubKey: pubKey, + Balance: Coins{Coin{"", balance}}, + }, + } + } + + return privAccs +} diff --git a/types/tx_test.go b/types/tx_test.go index 982ceb1bf9..5bfb3bc4c0 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -67,21 +67,10 @@ func TestAppTxSignable(t *testing.T) { cmn.Fmt("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signBytesHex)) } -// d'oh, can't use the version in testutils due to circular imports :( -func makePrivAcct() PrivAccount { - privKey := crypto.PrivKeyS{crypto.GenPrivKeyEd25519()} - return PrivAccount{ - PrivKeyS: privKey, - Account: Account{ - PubKey: crypto.PubKeyS{privKey.PubKey()}, - }, - } -} - func TestSendTxJSON(t *testing.T) { chainID := "test_chain_id" - test1PrivAcc := makePrivAcct() - test2PrivAcc := makePrivAcct() + test1PrivAcc := PrivAccountFromSecret("sendtx1") + test2PrivAcc := PrivAccountFromSecret("sendtx2") // Construct a SendTx signature tx := &SendTx{ From a6f62023b2bb6e437967a8a1ff61a2be0bcd4c33 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 24 Feb 2017 23:25:48 +0100 Subject: [PATCH 38/49] test LoadGenesis and change format --- app/app.go | 8 ++--- app/genesis.go | 35 +++++++++------------ app/genesis_test.go | 43 ++++++++++++++++++++++++++ app/testdata/genesis.json | 19 ++++++++++++ data/genesis.json | 13 +++++--- demo/data/chain1/basecoin/genesis.json | 13 +++++--- demo/data/chain2/basecoin/genesis.json | 13 +++++--- plugins/counter/counter_test.go | 12 ++++--- tests/tmsp/tmsp_test.go | 38 +++++++++++------------ 9 files changed, 130 insertions(+), 64 deletions(-) create mode 100644 app/genesis_test.go create mode 100644 app/testdata/genesis.json diff --git a/app/app.go b/app/app.go index 72f8a61c42..0b8fb6d2e3 100644 --- a/app/app.go +++ b/app/app.go @@ -1,6 +1,7 @@ package app import ( + "encoding/json" "strings" abci "github.com/tendermint/abci/types" @@ -68,13 +69,12 @@ func (app *Basecoin) SetOption(key string, value string) string { app.state.SetChainID(value) return "Success" case "account": - var err error - var acc *types.Account - wire.ReadJSONPtr(&acc, []byte(value), &err) + var acc types.Account + err := json.Unmarshal([]byte(value), &acc) if err != nil { return "Error decoding acc message: " + err.Error() } - app.state.SetAccount(acc.PubKey.Address(), acc) + app.state.SetAccount(acc.PubKey.Address(), &acc) log.Info("SetAccount", "addr", acc.PubKey.Address(), "acc", acc) return "Success" } diff --git a/app/genesis.go b/app/genesis.go index 6933780b37..afa94ecab3 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -2,8 +2,6 @@ package app import ( "encoding/json" - "fmt" - "reflect" "github.com/pkg/errors" cmn "github.com/tendermint/go-common" @@ -15,9 +13,7 @@ func (app *Basecoin) LoadGenesis(path string) error { return err } for _, kv := range kvz { - log := app.SetOption(kv.Key, kv.Value) - // TODO: remove debug output - fmt.Printf("Set %v=%v. Log: %v\n", kv.Key, kv.Value, log) + app.SetOption(kv.Key, kv.Value) } return nil } @@ -28,7 +24,7 @@ type keyValue struct { } func loadGenesis(filePath string) (kvz []keyValue, err error) { - kvz_ := []interface{}{} + kvz_ := []json.RawMessage{} bytes, err := cmn.ReadFile(filePath) if err != nil { return nil, errors.Wrap(err, "loading genesis file") @@ -40,24 +36,21 @@ func loadGenesis(filePath string) (kvz []keyValue, err error) { if len(kvz_)%2 != 0 { return nil, errors.New("genesis cannot have an odd number of items. Format = [key1, value1, key2, value2, ...]") } + for i := 0; i < len(kvz_); i += 2 { - keyIfc := kvz_[i] - valueIfc := kvz_[i+1] - var key, value string - key, ok := keyIfc.(string) - if !ok { - return nil, errors.Errorf("genesis had invalid key %v of type %v", keyIfc, reflect.TypeOf(keyIfc)) + kv := keyValue{} + rawK := []byte(kvz_[i]) + err := json.Unmarshal(rawK, &(kv.Key)) + if err != nil { + return nil, errors.Errorf("Non-string key: %s", string(rawK)) } - if value_, ok := valueIfc.(string); ok { - value = value_ - } else { - valueBytes, err := json.Marshal(valueIfc) - if err != nil { - return nil, errors.Errorf("genesis had invalid value %v: %v", value_, err.Error()) - } - value = string(valueBytes) + // convert value to string if possible (otherwise raw json) + rawV := kvz_[i+1] + err = json.Unmarshal(rawV, &(kv.Value)) + if err != nil { + kv.Value = string(rawV) } - kvz = append(kvz, keyValue{key, value}) + kvz = append(kvz, kv) } return kvz, nil } diff --git a/app/genesis_test.go b/app/genesis_test.go new file mode 100644 index 0000000000..90f61e152c --- /dev/null +++ b/app/genesis_test.go @@ -0,0 +1,43 @@ +package app + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/go-crypto" + eyescli "github.com/tendermint/merkleeyes/client" +) + +func TestLoadGenesis(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + eyesCli := eyescli.NewLocalClient("", 0) + app := NewBasecoin(eyesCli) + err := app.LoadGenesis("./testdata/genesis.json") + require.Nil(err, "%+v", err) + + // check the chain id + assert.Equal("foo_bar_chain", app.GetState().GetChainID()) + + // and check the account info - previously calculated values + addr, _ := hex.DecodeString("eb98e0688217cfdeb70eddf4b33cdcc37fc53197") + pkbyte, _ := hex.DecodeString("6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2") + + acct := app.GetState().GetAccount(addr) + require.NotNil(acct) + + // make sure balance is proper + assert.Equal(2, len(acct.Balance)) + assert.EqualValues(12345, acct.Balance[0].Amount) + assert.EqualValues("blank", acct.Balance[0].Denom) + + // and public key is parsed properly + apk := acct.PubKey.PubKey + require.NotNil(apk) + epk, ok := apk.(crypto.PubKeyEd25519) + if assert.True(ok) { + assert.EqualValues(pkbyte, epk[:]) + } +} diff --git a/app/testdata/genesis.json b/app/testdata/genesis.json new file mode 100644 index 0000000000..0308716c9c --- /dev/null +++ b/app/testdata/genesis.json @@ -0,0 +1,19 @@ +[ + "base/chainID", "foo_bar_chain", + "base/account", { + "pub_key": { + "type": "ed25519", + "data": "6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2" + }, + "coins": [ + { + "denom": "blank", + "amount": 12345 + }, + { + "denom": "ETH", + "amount": 654321 + } + ] + } +] diff --git a/data/genesis.json b/data/genesis.json index 2936a0e4d6..66d96300cd 100644 --- a/data/genesis.json +++ b/data/genesis.json @@ -1,12 +1,15 @@ [ "base/chainID", "test_chain_id", "base/account", { - "pub_key": [1, "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279"], + "pub_key": { + "type": "ed25519", + "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + }, "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } + { + "denom": "mycoin", + "amount": 9007199254740992 + } ] } ] diff --git a/demo/data/chain1/basecoin/genesis.json b/demo/data/chain1/basecoin/genesis.json index b060121774..588fc86f4f 100644 --- a/demo/data/chain1/basecoin/genesis.json +++ b/demo/data/chain1/basecoin/genesis.json @@ -1,12 +1,15 @@ [ "base/chainID", "test_chain_1", "base/account", { - "pub_key": [1, "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"], + "pub_key": { + "type": "ed25519", + "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" + }, "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } + { + "denom": "mycoin", + "amount": 9007199254740992 + } ] } ] diff --git a/demo/data/chain2/basecoin/genesis.json b/demo/data/chain2/basecoin/genesis.json index ca690c2cdb..05df04be5a 100644 --- a/demo/data/chain2/basecoin/genesis.json +++ b/demo/data/chain2/basecoin/genesis.json @@ -1,12 +1,15 @@ [ "base/chainID", "test_chain_2", "base/account", { - "pub_key": [1, "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D"], + "pub_key": { + "type": "ed25519", + "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" + }, "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } + { + "denom": "mycoin", + "amount": 9007199254740992 + } ] } ] diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index d93333b009..833b18f86d 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -1,9 +1,11 @@ package counter import ( + "encoding/json" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" "github.com/tendermint/basecoin/app" "github.com/tendermint/basecoin/types" @@ -19,7 +21,7 @@ func TestCounterPlugin(t *testing.T) { chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) bcApp.SetOption("base/chainID", chainID) - t.Log(bcApp.Info()) + // t.Log(bcApp.Info()) // Add Counter plugin counterPlugin := New() @@ -31,7 +33,9 @@ func TestCounterPlugin(t *testing.T) { // Seed Basecoin with account test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1000}, {"gold", 1000}} - bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc))) + accOpt, err := json.Marshal(test1Acc) + require.Nil(t, err) + bcApp.SetOption("base/account", string(accOpt)) // Deliver a CounterTx DeliverCounterTx := func(gas int64, fee types.Coin, inputCoins types.Coins, inputSequence int, appFee types.Coins) abci.Result { @@ -46,10 +50,10 @@ func TestCounterPlugin(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) - t.Logf("Sign bytes: %X\n", signBytes) + // t.Logf("Sign bytes: %X\n", signBytes) sig := test1PrivAcc.Sign(signBytes) tx.Input.Signature = crypto.SignatureS{sig} - t.Logf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) + // t.Logf("Signed TX bytes: %X\n", wire.BinaryBytes(struct{ types.Tx }{tx})) // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) diff --git a/tests/tmsp/tmsp_test.go b/tests/tmsp/tmsp_test.go index 4d250394b5..309af1a697 100644 --- a/tests/tmsp/tmsp_test.go +++ b/tests/tmsp/tmsp_test.go @@ -1,8 +1,11 @@ package tmsp_test import ( + "encoding/json" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/basecoin/app" "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" @@ -16,7 +19,7 @@ func TestSendTx(t *testing.T) { chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) bcApp.SetOption("base/chainID", chainID) - t.Log(bcApp.Info()) + // t.Log(bcApp.Info()) test1PrivAcc := types.PrivAccountFromSecret("test1") test2PrivAcc := types.PrivAccountFromSecret("test2") @@ -24,7 +27,9 @@ func TestSendTx(t *testing.T) { // Seed Basecoin with account test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1000}} - t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) + accOpt, err := json.Marshal(test1Acc) + require.Nil(t, err) + bcApp.SetOption("base/account", string(accOpt)) // Construct a SendTx signature tx := &types.SendTx{ @@ -43,18 +48,16 @@ func TestSendTx(t *testing.T) { // Sign request signBytes := tx.SignBytes(chainID) - t.Log("Sign bytes: %X\n", signBytes) + // t.Log("Sign bytes: %X\n", signBytes) sig := test1PrivAcc.Sign(signBytes) tx.Inputs[0].Signature = crypto.SignatureS{sig} - t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(types.TxS{tx})) + // t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(types.TxS{tx})) // Write request txBytes := wire.BinaryBytes(types.TxS{tx}) res := bcApp.DeliverTx(txBytes) - t.Log(res) - if res.IsErr() { - t.Errorf("Failed: %v", res.Error()) - } + // t.Log(res) + assert.False(t, res.IsErr(), "Failed: %v", res.Error()) } func TestSequence(t *testing.T) { @@ -62,13 +65,15 @@ func TestSequence(t *testing.T) { chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) bcApp.SetOption("base/chainID", chainID) - t.Log(bcApp.Info()) + // t.Log(bcApp.Info()) // Get the test account test1PrivAcc := types.PrivAccountFromSecret("test1") test1Acc := test1PrivAcc.Account test1Acc.Balance = types.Coins{{"", 1 << 53}} - t.Log(bcApp.SetOption("base/account", string(wire.JSONBytes(test1Acc)))) + accOpt, err := json.Marshal(test1Acc) + require.Nil(t, err) + bcApp.SetOption("base/account", string(accOpt)) sequence := int(1) // Make a bunch of PrivAccounts @@ -103,16 +108,11 @@ func TestSequence(t *testing.T) { // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.DeliverTx(txBytes) - if res.IsErr() { - t.Errorf("DeliverTx error: " + res.Error()) - } - + assert.False(t, res.IsErr(), "DeliverTx error: %v", res.Error()) } res := bcApp.Commit() - if res.IsErr() { - t.Errorf("Failed Commit: %v", res.Error()) - } + assert.False(t, res.IsErr(), "Failed Commit: %v", res.Error()) t.Log("-------------------- RANDOM SENDS --------------------") @@ -152,8 +152,6 @@ func TestSequence(t *testing.T) { // Write request txBytes := wire.BinaryBytes(struct{ types.Tx }{tx}) res := bcApp.DeliverTx(txBytes) - if res.IsErr() { - t.Errorf("DeliverTx error: " + res.Error()) - } + assert.False(t, res.IsErr(), "DeliverTx error: %v", res.Error()) } } From 0dd57257909466ed87407e83e68e0cd7f9e1b3ed Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 26 Feb 2017 12:52:24 -0500 Subject: [PATCH 39/49] run demo test on circle --- circle.yml | 3 ++- demo/start.sh | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/circle.yml b/circle.yml index ef59921583..f24f3ab383 100644 --- a/circle.yml +++ b/circle.yml @@ -17,10 +17,11 @@ dependencies: - go get github.com/Masterminds/glide - go version - glide --version - - "cd $REPO && glide install" + - "cd $REPO && glide install && go install ./cmd/basecoin" test: override: - "cd $REPO && make test" + - "cd $REPO/demo && bash start.sh" diff --git a/demo/start.sh b/demo/start.sh index 4b6d518870..06dadb7c74 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -1,8 +1,27 @@ #! /bin/bash -set -eu +set -e cd $GOPATH/src/github.com/tendermint/basecoin/demo +LOG_DIR="." + +if [[ "$CIRCLECI" == "true" ]]; then + # set log dir + LOG_DIR="${CIRCLE_ARTIFACTS}" + + # install tendermint + set +e + go get github.com/tendermint/tendermint + pushd $GOPATH/src/github.com/tendermint/tendermint + git checkout develop + glide install + go install ./cmd/tendermint + popd + set -e +fi + +set -u + function removeQuotes() { temp="${1%\"}" temp="${temp#\"}" @@ -14,10 +33,17 @@ function waitForNode() { set +e curl -s $addr/status > /dev/null ERR=$? + i=0 while [ "$ERR" != 0 ]; do + if [[ "$i" == 10 ]]; then + echo "waited to long for chain to start" + exit 1 + fi + echo "...... still waiting on $addr" sleep 1 curl -s $addr/status > /dev/null ERR=$? + i=$((i+1)) done set -e echo "... node $addr is up" @@ -51,12 +77,12 @@ echo "" echo "... starting chains" echo "" # start the first node -TMROOT=./data/chain1/tendermint tendermint node &> chain1_tendermint.log & -basecoin start --dir ./data/chain1/basecoin &> chain1_basecoin.log & +TMROOT=./data/chain1/tendermint tendermint node --skip_upnp --log_level=info &> $LOG_DIR/chain1_tendermint.log & +basecoin start --dir ./data/chain1/basecoin &> $LOG_DIR/chain1_basecoin.log & # start the second node -TMROOT=./data/chain2/tendermint tendermint node --node_laddr tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app tcp://localhost:36658 &> chain2_tendermint.log & -basecoin start --address tcp://localhost:36658 --dir ./data/chain2/basecoin &> chain2_basecoin.log & +TMROOT=./data/chain2/tendermint tendermint node --skip_upnp --log_level=info --node_laddr tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app tcp://localhost:36658 &> $LOG_DIR/chain2_tendermint.log & +basecoin start --address tcp://localhost:36658 --dir ./data/chain2/basecoin &> $LOG_DIR/chain2_basecoin.log & echo "" echo "... waiting for chains to start" From cd3a5452648408c43ebfe8f6dc40d11cab92ca7c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 26 Feb 2017 13:51:39 -0500 Subject: [PATCH 40/49] version bump to 0.2.0 --- cmd/basecoin/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 8a39a4902d..d16d001f0e 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -4,6 +4,7 @@ import ( "os" "github.com/tendermint/basecoin/cmd/commands" + "github.com/tendermint/basecoin/version" "github.com/urfave/cli" ) @@ -11,7 +12,7 @@ func main() { app := cli.NewApp() app.Name = "basecoin" app.Usage = "basecoin [command] [args...]" - app.Version = "0.1.0" + app.Version = version.Version app.Commands = []cli.Command{ commands.StartCmd, commands.TxCmd, From d27b82d366aa381f66b5619c31bca49061cb73a9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 1 Mar 2017 13:12:25 -0500 Subject: [PATCH 41/49] version fix, closes #45 --- version/version.go | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 version/version.go diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000000..0f685af284 --- /dev/null +++ b/version/version.go @@ -0,0 +1,7 @@ +package version + +const Maj = "0" +const Min = "2" +const Fix = "0" + +const Version = Maj + "." + Min + "." + Fix From b30661e5f7c6db65e008a3aeab2b9708e199b7f5 Mon Sep 17 00:00:00 2001 From: H Copperm Date: Wed, 1 Mar 2017 13:01:47 -0800 Subject: [PATCH 42/49] Update README for n00bs * --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b765165b61..82c646570e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ and away you go with a full-stack blockchain and command line tool for transacti WARNING: Currently uses plain-text private keys for transactions and is otherwise not production ready. +## Prerequisites + +* Go to https://golang.org/doc/install to install Golang. +* Once you have Golang installed you will also need to install the Golang package manager `glide`: https://github.com/Masterminds/glide. +* You will also need to set the $GOPATH environment variable as per the instructions [here](https://golang.org/doc/code.html#GOPATH). + ## Installation On a good day, basecoin can be installed like a normal Go program: From 196da33437acdd4475f96cc7c511b84d66a94ed0 Mon Sep 17 00:00:00 2001 From: "Paul W. Homer" Date: Thu, 2 Mar 2017 12:07:40 -0500 Subject: [PATCH 43/49] Changed the format for the error message from %d to %v --- state/execution.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/execution.go b/state/execution.go index 3452c399ab..eb7f3c6906 100644 --- a/state/execution.go +++ b/state/execution.go @@ -100,7 +100,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e } if !tx.Input.Coins.IsGTE(types.Coins{tx.Fee}) { log.Info(cmn.Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) - return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("input coins is %d, but fee is %d", tx.Input.Coins, types.Coins{tx.Fee})) + return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("input coins is %v, but fee is %v", tx.Input.Coins, types.Coins{tx.Fee})) } // Validate call address From f538761329ad79c41384935f4bf5ecb65b431b0f Mon Sep 17 00:00:00 2001 From: H Copperm Date: Thu, 2 Mar 2017 19:37:13 -0800 Subject: [PATCH 44/49] clarify re. compiling from source --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 82c646570e..fea9226d47 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ WARNING: Currently uses plain-text private keys for transactions and is otherwis ## Prerequisites * Go to https://golang.org/doc/install to install Golang. -* Once you have Golang installed you will also need to install the Golang package manager `glide`: https://github.com/Masterminds/glide. * You will also need to set the $GOPATH environment variable as per the instructions [here](https://golang.org/doc/code.html#GOPATH). ## Installation @@ -27,14 +26,14 @@ On a good day, basecoin can be installed like a normal Go program: go get -u github.com/tendermint/basecoin/cmd/basecoin ``` -In some cases, if that fails, or if another branch is required, -we use `glide` for dependency management. -The guaranteed correct way of compiling from source, assuming you've already -run `go get` or otherwise cloned the repo, is: +In some cases, if that fails, or if another branch is required, you may have to compile from source. +You will first need to install the Golang package manager [`glide`](https://github.com/Masterminds/glide). ``` -cd $GOPATH/src/github.com/tendermint/basecoin +cd $GOPATH +git clone git@github.com:tendermint/basecoin.git +cd src/github.com/tendermint/basecoin git checkout develop # (until we release tendermint v0.9) make get_vendor_deps make install From 17585244a19539d5a1d8c372afb078b2d690e836 Mon Sep 17 00:00:00 2001 From: H Copperm Date: Fri, 3 Mar 2017 13:39:38 -0800 Subject: [PATCH 45/49] updated per ethan's instructions --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fea9226d47..6b4b0c34e4 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,11 @@ go get -u github.com/tendermint/basecoin/cmd/basecoin ``` -In some cases, if that fails, or if another branch is required, you may have to compile from source. +If that fails, or if another branch is required, you may have to compile from source. You will first need to install the Golang package manager [`glide`](https://github.com/Masterminds/glide). ``` -cd $GOPATH -git clone git@github.com:tendermint/basecoin.git -cd src/github.com/tendermint/basecoin +cd $GOPATH/src/github.com/tendermint/basecoin git checkout develop # (until we release tendermint v0.9) make get_vendor_deps make install From e3826a2f4502fbd7b5dcbd019d593aeddf0c5c09 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 23 Feb 2017 20:50:20 -0500 Subject: [PATCH 46/49] use default vals for new accounts --- state/state_test.go | 5 ++--- types/account_test.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/state/state_test.go b/state/state_test.go index 6eae18de91..8c74162195 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -21,9 +21,8 @@ func TestState(t *testing.T) { //Account and address for tests dumAddr := []byte("dummyAddress") - acc := &types.Account{ - Sequence: 1, - } + acc := new(types.Account) + acc.Sequence = 1 //reset the store/state/cache reset := func() { diff --git a/types/account_test.go b/types/account_test.go index 77dfba9d8b..5a9118f1df 100644 --- a/types/account_test.go +++ b/types/account_test.go @@ -8,7 +8,7 @@ import ( func TestNilAccount(t *testing.T) { - acc := Account{} + var acc Account //test Copy accCopy := acc.Copy() From 6ea7f4c7a067ead0a0940f36daae630351d63287 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 6 Mar 2017 04:50:24 -0500 Subject: [PATCH 47/49] glide update --- demo/start.sh | 4 ++++ glide.lock | 62 +++++++++++++++++++++++++-------------------------- glide.yaml | 2 +- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/demo/start.sh b/demo/start.sh index 06dadb7c74..d4891ecdd7 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -91,6 +91,10 @@ echo "" waitForNode localhost:46657 waitForNode localhost:36657 +# TODO: remove the sleep +# Without it we sometimes get "Account bytes are empty for address: 053BA0F19616AFF975C8756A2CBFF04F408B4D47" +sleep 3 + echo "... registering chain1 on chain2" echo "" # register chain1 on chain2 diff --git a/glide.lock b/glide.lock index 7c681e9a9d..bcfcf13e78 100644 --- a/glide.lock +++ b/glide.lock @@ -1,20 +1,18 @@ -hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-02-23T19:11:29.680601042-05:00 +hash: c58fd706e6ebc2c1c1c5d8e0af20c8e3b6ce9a4dae6b7b85b1b7368e9683060e +updated: 2017-03-06T04:45:25.988962093-05:00 imports: - name: github.com/btcsuite/btcd - version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 + version: d06c0bb181529331be8f8d9350288c420d9e60e4 subpackages: - btcec -- name: github.com/btcsuite/fastsha256 - version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: 99064174e013895bbd9b025c31100bd1d9b590ca - name: github.com/ebuchman/fail-test - version: c1eddaa09da2b4017351245b0d43234955276798 + version: 13f91f14c826314205cdbed1ec8ac8bf08e03381 - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 1f49d83d9aa00e6ce4fc8258c71cc7786aec968a + version: 8ee79997227bf9b34611aee7946ae64735e6fd93 subpackages: - proto - name: github.com/golang/snappy @@ -24,13 +22,13 @@ imports: - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/mattn/go-colorable - version: ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 + version: d228849504861217f796da67fae4f6e347643f15 - name: github.com/mattn/go-isatty - version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 + version: 30a891c33c7cde7b02a981314b4228ec99380cca - name: github.com/pkg/errors - version: 248dadf4e9068a0b3e79f02ed0a610d935de5302 + version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/syndtr/goleveldb - version: 6ae1797c0b42b9323fc27ff7dcf568df88f2f33d + version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65 subpackages: - leveldb - leveldb/cache @@ -45,7 +43,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 33e52343d00552dd57ad45621947eb8957ebbca4 + version: 1236e8fb6eee3a63909f4014a8e84385ead7933d subpackages: - client - example/dummy @@ -57,21 +55,21 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-autofile - version: 0416e0aa9c68205aa44844096f9f151ada9d0405 + version: 48b17de82914e1ec2f134ce823ba426337d2c518 - name: github.com/tendermint/go-clist version: 3baa390bbaf7634251c42ad69a8682e7e3990552 - name: github.com/tendermint/go-common - version: 339e135776142939d82bc8e699db0bf391fd938d + version: dcb015dff6c7af21e65c8e2f3b450df19d38c777 - name: github.com/tendermint/go-config - version: e64b424499acd0eb9856b88e10c0dff41628c0d6 + version: 620dcbbd7d587cf3599dedbf329b64311b0c307a - name: github.com/tendermint/go-crypto - version: 562b4cc9ef0d20217f6e95679f9e83cb7bc98b17 + version: 3f47cfac5fcd9e0f1727c7db980b3559913b3e3a - name: github.com/tendermint/go-data - version: f199ef165cd5a50d569b179201702c5ec8899013 + version: 32271140e8fd5abdbb22e268d7a02421fa382f0b - name: github.com/tendermint/go-db - version: 2645626c33d8702739e52a61a55d705c2dfe4530 + version: eac3f2bc147023957c8bf69432a4e6c4dc5c3f72 - name: github.com/tendermint/go-events - version: 2337086736a6adeb2de6f66739b66ecd77535997 + version: f8ffbfb2be3483e9e7927495590a727f51c0c11f - name: github.com/tendermint/go-flowrate version: a20c98e61957faa93b4014fbd902f20ab9317a6a subpackages: @@ -79,30 +77,30 @@ imports: - name: github.com/tendermint/go-logger version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2 - name: github.com/tendermint/go-merkle - version: 653cb1f631528351ddbc359b994eb0c96f0341cd + version: 714d4d04557fd068a7c2a1748241ce8428015a96 - name: github.com/tendermint/go-p2p - version: 67c9086b7458eb45b1970483decd01cd744c477a + version: 97a5ed2d1a17eaee8717b8a32cfaf7a9a82a273d subpackages: - upnp - name: github.com/tendermint/go-rpc - version: 6177eb8398ebd4613fbecb71fd96d7c7d97303ec + version: fcea0cda21f64889be00a0f4b6d13266b1a76ee7 subpackages: - client - server - types - name: github.com/tendermint/go-wire - version: 3216ec9d47bbdf8d4fc27d22169ea86a6688bc15 + version: f530b7af7a8b06e612c2063bff6ace49060a085e - name: github.com/tendermint/log15 - version: 9545b249b3aacafa97f79e0838b02b274adc6f5f + version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6 subpackages: - term - name: github.com/tendermint/merkleeyes - version: acd8e9c42e1d819c51e9e1cd3870ea4d94b167f5 + version: 9fb76efa5aebe773a598f97e68e75fe53d520e70 subpackages: - app - client - name: github.com/tendermint/tendermint - version: f73f53c486f0571396e414f338902cee4607f51d + version: e31ed6dc2fb7cd28beb531bc92862646688365d7 subpackages: - blockchain - config/tendermint @@ -117,9 +115,9 @@ imports: - types - version - name: github.com/urfave/cli - version: 8ef3805c9de2519805c3f060524b695bba2cd715 + version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6 - name: golang.org/x/crypto - version: aa2481cbfe81d911eb62b642b7a6b5ec58bbea71 + version: 7c6cc321c680f03b9ef0764448e780704f486b51 subpackages: - curve25519 - nacl/box @@ -130,20 +128,21 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: cfe3c2a7525b50c3d707256e371c90938cfef98a + version: 61557ac0112b576429a0df080e1c2cef5dfbb642 subpackages: - context - http2 - http2/hpack + - idna - internal/timeseries - lex/httplex - trace - name: golang.org/x/sys - version: 30de6d19a3bd89a5f38ae4028e23aaa5582648af + version: d75a52659825e75fff6158388dddc6a5b04f9ba5 subpackages: - unix - name: google.golang.org/grpc - version: 50955793b0183f9de69bd78e2ec251cf20aab121 + version: cbcceb2942a489498cf22b2f918536e819d33f0a subpackages: - codes - credentials @@ -168,3 +167,4 @@ testImports: version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert + - require diff --git a/glide.yaml b/glide.yaml index ecf4f151b4..c9f3576cd9 100644 --- a/glide.yaml +++ b/glide.yaml @@ -15,7 +15,7 @@ import: - package: github.com/tendermint/merkleeyes version: develop - package: github.com/tendermint/tendermint - version: develop + version: release-0.9.0 - package: github.com/tendermint/abci version: develop - package: github.com/gorilla/websocket From 43dca48eebd3a3e5ef822b15b79a1392d0813a91 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 6 Mar 2017 05:11:27 -0500 Subject: [PATCH 48/49] CHANGELOG --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..8dfdd0dd68 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog + +## 0.2.0 (March 6, 2017) + +BREAKING CHANGES: + +- Update to ABCI v0.4.0 and Tendermint v0.9.0 +- Coins are specified on the CLI as `Xcoin`, eg. `5gold` +- `Cost` is now `Fee` + +FEATURES: + +- CLI for sending transactions and querying the state, +designed to be easily extensible as plugins are implemented +- Run Basecoin in-process with Tendermint +- Add `/account` path in Query +- IBC plugin for InterBlockchain Communication +- Demo script of IBC between two chains + +IMPROVEMENTS: + +- Use new Tendermint `/commit` endpoint for crafting IBC transactions +- More unit tests +- Use go-crypto S structs and go-data for more standard JSON +- Demo uses fewer sleeps + +BUG FIXES: + +- Various little fixes in coin arithmetic +- More commit validation in IBC +- Return results from transactions + +## PreHistory + +##### January 14-18, 2017 + +- Update to Tendermint v0.8.0 +- Cleanup a bit and release blog post + +##### September 22, 2016 + +- Basecoin compiles again + + + From da1f09b5ef014ad1c49ae9da5d68dfcc5264ebc8 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 6 Mar 2017 05:50:18 -0500 Subject: [PATCH 49/49] glide update --- glide.lock | 6 +++--- glide.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/glide.lock b/glide.lock index bcfcf13e78..2d3ddd34e4 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: c58fd706e6ebc2c1c1c5d8e0af20c8e3b6ce9a4dae6b7b85b1b7368e9683060e -updated: 2017-03-06T04:45:25.988962093-05:00 +hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 +updated: 2017-03-06T05:37:03.828355251-05:00 imports: - name: github.com/btcsuite/btcd version: d06c0bb181529331be8f8d9350288c420d9e60e4 @@ -100,7 +100,7 @@ imports: - app - client - name: github.com/tendermint/tendermint - version: e31ed6dc2fb7cd28beb531bc92862646688365d7 + version: d4f625455109d88e7f55a999fdb25e208f174802 subpackages: - blockchain - config/tendermint diff --git a/glide.yaml b/glide.yaml index c9f3576cd9..ecf4f151b4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -15,7 +15,7 @@ import: - package: github.com/tendermint/merkleeyes version: develop - package: github.com/tendermint/tendermint - version: release-0.9.0 + version: develop - package: github.com/tendermint/abci version: develop - package: github.com/gorilla/websocket