cli: key command
This commit is contained in:
parent
abac65bacc
commit
d54763965e
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
}
|
||||
|
||||
|
||||
@ -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() })
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
73
cmd/commands/key.go
Normal file
73
cmd/commands/key.go
Normal file
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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)))
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -15,6 +15,7 @@ func main() {
|
||||
app.Commands = []cli.Command{
|
||||
commands.StartCmd,
|
||||
commands.TxCmd,
|
||||
commands.KeyCmd,
|
||||
commands.QueryCmd,
|
||||
commands.AccountCmd,
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[
|
||||
"base/chainID", "test_chain_id",
|
||||
"base/account", {
|
||||
"pub_key": [1, "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF"],
|
||||
"pub_key": [1, "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279"],
|
||||
"coins": [
|
||||
{
|
||||
"denom": "blank",
|
||||
|
||||
11
data/key.json
Normal file
11
data/key.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"address": "1B1BE55F969F54064628A63B9559E7C21C925165",
|
||||
"priv_key": [
|
||||
1,
|
||||
"C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D10000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"pub_key": [
|
||||
1,
|
||||
"619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279"
|
||||
]
|
||||
}
|
||||
11
data/key2.json
Normal file
11
data/key2.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090",
|
||||
"priv_key": [
|
||||
1,
|
||||
"34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A80000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"pub_key": [
|
||||
1,
|
||||
"352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8"
|
||||
]
|
||||
}
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user