From d54763965ea70bde0c22bac7cb579f2a09fba819 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 7 Feb 2017 16:10:17 -0500 Subject: [PATCH] cli: key command --- cmd/adam/main.go | 1 + cmd/basecoin/main.go | 1 + cmd/commands/flags.go | 2 +- cmd/commands/ibc.go | 4 +- cmd/commands/key.go | 73 +++++++++++++++++++++++++++++++++++ cmd/commands/start.go | 10 ++--- cmd/commands/tx.go | 19 +++++---- cmd/counter/cmd.go | 4 +- cmd/counter/main.go | 1 + data/genesis.json | 2 +- data/key.json | 11 ++++++ data/key2.json | 11 ++++++ data/priv_validator.json | 17 -------- data/priv_validator2.json | 16 -------- docs/guide/basecoin-basics.md | 52 +++++++++---------------- 15 files changed, 135 insertions(+), 89 deletions(-) create mode 100644 cmd/commands/key.go create mode 100644 data/key.json create mode 100644 data/key2.json delete mode 100644 data/priv_validator.json delete mode 100644 data/priv_validator2.json diff --git a/cmd/adam/main.go b/cmd/adam/main.go index ef55d7aced..9be7255e7c 100644 --- a/cmd/adam/main.go +++ b/cmd/adam/main.go @@ -20,6 +20,7 @@ func main() { app.Commands = []cli.Command{ commands.StartCmd, commands.TxCmd, + commands.KeyCmd, commands.QueryCmd, commands.VerifyCmd, // TODO: move to merkleeyes? commands.BlockCmd, diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 3c31ae38fd..77f9827fdd 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -16,6 +16,7 @@ func main() { commands.StartCmd, commands.TxCmd, commands.QueryCmd, + commands.KeyCmd, commands.VerifyCmd, // TODO: move to merkleeyes? commands.BlockCmd, // TODO: move to adam? commands.AccountCmd, diff --git a/cmd/commands/flags.go b/cmd/commands/flags.go index dc91754687..4670ee9fcd 100644 --- a/cmd/commands/flags.go +++ b/cmd/commands/flags.go @@ -56,7 +56,7 @@ var ( FromFlag = cli.StringFlag{ Name: "from", - Value: "priv_validator.json", + Value: "key.json", Usage: "Path to a private key to sign the transaction", } diff --git a/cmd/commands/ibc.go b/cmd/commands/ibc.go index 1b513d4047..2427433195 100644 --- a/cmd/commands/ibc.go +++ b/cmd/commands/ibc.go @@ -20,9 +20,7 @@ import ( // Register the IBC plugin at start and for transactions func RegisterIBC() { RegisterTxSubcommand(IbcCmd) - RegisterStartPlugin("ibc", func() types.Plugin { - return ibc.New() - }) + RegisterStartPlugin("ibc", func() types.Plugin { return ibc.New() }) } //--------------------------------------------------------------------- diff --git a/cmd/commands/key.go b/cmd/commands/key.go new file mode 100644 index 0000000000..2ebd74afd4 --- /dev/null +++ b/cmd/commands/key.go @@ -0,0 +1,73 @@ +package commands + +import ( + "fmt" + "io/ioutil" + + "github.com/urfave/cli" + + cmn "github.com/tendermint/go-common" + "github.com/tendermint/go-crypto" + "github.com/tendermint/go-wire" +) + +var ( + KeyCmd = cli.Command{ + Name: "key", + Usage: "Manage keys", + ArgsUsage: "", + Subcommands: []cli.Command{NewKeyCmd}, + } + + NewKeyCmd = cli.Command{ + Name: "new", + Usage: "Create a new private key", + ArgsUsage: "", + Action: func(c *cli.Context) error { + return cmdNewKey(c) + }, + } +) + +func cmdNewKey(c *cli.Context) error { + key := genKey() + keyJSON := wire.JSONBytesPretty(key) + fmt.Println(string(keyJSON)) + return nil +} + +//--------------------------------------------- +// simple implementation of a key + +type Key struct { + Address []byte `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + PrivKey crypto.PrivKey `json:"priv_key"` +} + +// Implements Signer +func (k *Key) Sign(msg []byte) crypto.Signature { + return k.PrivKey.Sign(msg) +} + +// Generates a new validator with private key. +func genKey() *Key { + privKey := crypto.GenPrivKeyEd25519() + return &Key{ + Address: privKey.PubKey().Address(), + PubKey: privKey.PubKey(), + PrivKey: privKey, + } +} + +func LoadKey(filePath string) *Key { + keyJSONBytes, err := ioutil.ReadFile(filePath) + if err != nil { + cmn.Exit(err.Error()) + } + key := wire.ReadJSON(&Key{}, keyJSONBytes, &err).(*Key) + if err != nil { + cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) + } + return key +} diff --git a/cmd/commands/start.go b/cmd/commands/start.go index 9ce201a108..9996e551c9 100644 --- a/cmd/commands/start.go +++ b/cmd/commands/start.go @@ -43,15 +43,15 @@ var StartCmd = cli.Command{ } type plugin struct { - name string - init func() types.Plugin + name string + newPlugin func() types.Plugin } var plugins = []plugin{} // RegisterStartPlugin is used to enable a plugin -func RegisterStartPlugin(name string, initFunc func() types.Plugin) { - plugins = append(plugins, plugin{name: name, init: initFunc}) +func RegisterStartPlugin(name string, newPlugin func() types.Plugin) { + plugins = append(plugins, plugin{name: name, newPlugin: newPlugin}) } func cmdStart(c *cli.Context) error { @@ -73,7 +73,7 @@ func cmdStart(c *cli.Context) error { // register all plugins for _, p := range plugins { - basecoinApp.RegisterPlugin(p.init()) + basecoinApp.RegisterPlugin(p.newPlugin()) } // If genesis file exists, set key-value options diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index cba6e70639..9b8ce21cd8 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -82,18 +82,17 @@ func cmdSendTx(c *cli.Context) error { return errors.New("To address is invalid hex: " + err.Error()) } - // load the priv validator - // XXX: this is overkill for now, we need a keys solution - privVal := tmtypes.LoadPrivValidator(fromFile) + // load the priv key + privKey := LoadKey(fromFile) // get the sequence number for the tx - sequence, err := getSeq(c, privVal.Address) + sequence, err := getSeq(c, privKey.Address) if err != nil { return err } // craft the tx - input := types.NewTxInput(privVal.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) + input := types.NewTxInput(privKey.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) output := newOutput(to, coin, amount) tx := &types.SendTx{ Gas: int64(gas), @@ -104,7 +103,7 @@ func cmdSendTx(c *cli.Context) error { // sign that puppy signBytes := tx.SignBytes(chainID) - tx.Inputs[0].Signature = privVal.Sign(signBytes) + tx.Inputs[0].Signature = privKey.Sign(signBytes) fmt.Println("Signed SendTx:") fmt.Println(string(wire.JSONBytes(tx))) @@ -134,14 +133,14 @@ func AppTx(c *cli.Context, name string, data []byte) error { gas, fee := c.Int("gas"), int64(c.Int("fee")) chainID := c.String("chain_id") - privVal := tmtypes.LoadPrivValidator(fromFile) + privKey := tmtypes.LoadPrivValidator(fromFile) - sequence, err := getSeq(c, privVal.Address) + sequence, err := getSeq(c, privKey.Address) if err != nil { return err } - input := types.NewTxInput(privVal.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) + input := types.NewTxInput(privKey.PubKey, types.Coins{types.Coin{coin, amount}}, sequence) tx := &types.AppTx{ Gas: int64(gas), Fee: types.Coin{coin, fee}, @@ -150,7 +149,7 @@ func AppTx(c *cli.Context, name string, data []byte) error { Data: data, } - tx.Input.Signature = privVal.Sign(tx.SignBytes(chainID)) + tx.Input.Signature = privKey.Sign(tx.SignBytes(chainID)) fmt.Println("Signed AppTx:") fmt.Println(string(wire.JSONBytes(tx))) diff --git a/cmd/counter/cmd.go b/cmd/counter/cmd.go index 6b5e02ab55..c125feb4f6 100644 --- a/cmd/counter/cmd.go +++ b/cmd/counter/cmd.go @@ -13,9 +13,7 @@ import ( func init() { commands.RegisterTxSubcommand(CounterTxCmd) - commands.RegisterStartPlugin("counter", func() types.Plugin { - return counter.New("counter") - }) + commands.RegisterStartPlugin("counter", func() types.Plugin { return counter.New() }) } var ( diff --git a/cmd/counter/main.go b/cmd/counter/main.go index 11967841c1..72395a9b07 100644 --- a/cmd/counter/main.go +++ b/cmd/counter/main.go @@ -15,6 +15,7 @@ func main() { app.Commands = []cli.Command{ commands.StartCmd, commands.TxCmd, + commands.KeyCmd, commands.QueryCmd, commands.AccountCmd, } diff --git a/data/genesis.json b/data/genesis.json index 7aea6cb9bc..3a4c177526 100644 --- a/data/genesis.json +++ b/data/genesis.json @@ -1,7 +1,7 @@ [ "base/chainID", "test_chain_id", "base/account", { - "pub_key": [1, "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"], + "pub_key": [1, "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279"], "coins": [ { "denom": "blank", diff --git a/data/key.json b/data/key.json new file mode 100644 index 0000000000..7a8c075604 --- /dev/null +++ b/data/key.json @@ -0,0 +1,11 @@ +{ + "address": "1B1BE55F969F54064628A63B9559E7C21C925165", + "priv_key": [ + 1, + "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D10000000000000000000000000000000000000000000000000000000000000000" + ], + "pub_key": [ + 1, + "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + ] +} diff --git a/data/key2.json b/data/key2.json new file mode 100644 index 0000000000..f6f8d3693a --- /dev/null +++ b/data/key2.json @@ -0,0 +1,11 @@ +{ + "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", + "priv_key": [ + 1, + "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A80000000000000000000000000000000000000000000000000000000000000000" + ], + "pub_key": [ + 1, + "352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" + ] +} diff --git a/data/priv_validator.json b/data/priv_validator.json deleted file mode 100644 index 15d7919240..0000000000 --- a/data/priv_validator.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "address": "D397BC62B435F3CF50570FBAB4340FE52C60858F", - "last_height": 0, - "last_round": 0, - "last_signature": null, - "last_signbytes": "", - "last_step": 0, - "priv_key": [ - 1, - "39E75AA1CF7BC710585977EFC375CD1730519186BD231478C339F2819C3C26E7B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - ], - "pub_key": [ - 1, - "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - ] -} - diff --git a/data/priv_validator2.json b/data/priv_validator2.json deleted file mode 100644 index 08256d1fd8..0000000000 --- a/data/priv_validator2.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "address": "4793A333846E5104C46DD9AB9A00E31821B2F301", - "last_height": 0, - "last_round": 0, - "last_signature": null, - "last_signbytes": "", - "last_step": 0, - "priv_key": [ - 1, - "13A04A552ABAA2CCFA1F618CF9C97F1FD59FC3EE4968FE87DF3637C9B0F2FAAA93766F08BE7135E78DBFFA76B61BC7C52B96256EB4394A224B4EF8BCC954DE2E" - ], - "pub_key": [ - 1, - "93766F08BE7135E78DBFFA76B61BC7C52B96256EB4394A224B4EF8BCC954DE2E" - ] -} diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 34aaae4046..c60480ed4f 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -35,6 +35,9 @@ The directory contains a genesis file and two private keys. You can generate your own private keys with `tendermint gen_validator`, and construct the `genesis.json` as you like. +Note, however, that you must be careful with the `chain_id` field, +as every transaction must contain the correct `chain_id` +(default is `test_chain_id`). ## Start @@ -65,26 +68,28 @@ 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. ## Send transactions Now we are ready to send some transactions. If you take a look at the `genesis.json` file, you will see one account listed there. -This account corresponds to the private key in `priv_validator.json`. -We also included the private key for another account, in `priv_validator2.json`. +This account corresponds to the private key in `key.json`. +We also included the private key for another account, in `key2.json`. Let's check the balance of these two accounts: ``` -basecoin account 0xD397BC62B435F3CF50570FBAB4340FE52C60858F -basecoin account 0x4793A333846E5104C46DD9AB9A00E31821B2F301 +basecoin account 0x1B1BE55F969F54064628A63B9559E7C21C925165 +basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 ``` 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 sendtx --to 0x4793A333846E5104C46DD9AB9A00E31821B2F301 --amount 10 +basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10 ``` By default, the CLI looks for a `priv_validator.json` to sign the transaction with, @@ -94,13 +99,13 @@ To specify a different key, we can use the `--from` flag. Now if we check the second account, it should have `10` coins! ``` -basecoin account 0x4793A333846E5104C46DD9AB9A00E31821B2F301 +basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 ``` We can send some of these coins back like so: ``` -basecoin sendtx --to 0xD397BC62B435F3CF50570FBAB4340FE52C60858F --from priv_validator2.json --amount 5 +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5 ``` Note how we use the `--from` flag to select a different account to send from. @@ -108,38 +113,19 @@ 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 sendtx --to 0xD397BC62B435F3CF50570FBAB4340FE52C60858F --from priv_validator2.json --amount 100 +basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100 ``` -See `basecoin sendtx --help` for additional details. +See `basecoin tx send --help` for additional details. ## Plugins - -The `sendtx` command creates and broadcasts a transaction of type `SendTx`, +The `tx send` command creates and broadcasts a transaction of type `SendTx`, which is only useful for moving tokens around. Fortunately, Basecoin supports another transaction type, the `AppTx`, which can trigger code registered via a plugin system. -For instance, we implemented a simple plugin called `counter`, -which just counts the number of transactions it processed. -To run it, kill the other processes, run `tendermint unsafe_reset_all`, and then - -``` -basecoin start --in-proc --counter-plugin -``` - -Now in another window, we can send transactions with: - -``` -TODO -``` - -## Next steps - -1. Learn more about [Basecoin's design](basecoin-design.md) -1. Make your own [cryptocurrency using Basecoin plugins](example-counter.md) -1. Learn more about [plugin design](plugin-design.md) -1. See some [more example applications](more-examples.md) -1. Learn how to use [InterBlockchain Communication (IBC)](ibc.md) -1. [Deploy testnets](deployment.md) running your basecoin application. +In the [next tutorial](example-counter.md), +we demonstrate how to implement a plugin +and extend the CLI to support new transaction types! +But first, you may want to learn a bit more about [Basecoin's design](basecoin-design.md)