diff --git a/README.md b/README.md index 6b4b0c34e4..22b29bcb1a 100644 --- a/README.md +++ b/README.md @@ -15,45 +15,25 @@ WARNING: Currently uses plain-text private keys for transactions and is otherwis ## Prerequisites -* Go to https://golang.org/doc/install to install Golang. -* You will also need to set the $GOPATH environment variable as per the instructions [here](https://golang.org/doc/code.html#GOPATH). +[Install and setup Golang](https://tendermint.com/docs/guides/install-go). ## Installation -On a good day, basecoin can be installed like a normal Go program: - ``` go get -u github.com/tendermint/basecoin/cmd/basecoin ``` - -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 -git checkout develop # (until we release tendermint v0.9) -make get_vendor_deps -make install -``` - -This will create the `basecoin` binary in `$GOPATH/bin`. +See the [install guide](/docs/guide/install.md) for more details. -## Command Line Interface - -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 100btc,10gold` -See `basecoin --help` and `basecoin [cmd] --help` for more details`. - -## Learn more +## Guide 1. Getting started with the [Basecoin tool](/docs/guide/basecoin-basics.md) 1. Learn more about [Basecoin's design](/docs/guide/basecoin-design.md) 1. Extend Basecoin [using the plugin system](/docs/guide/example-plugin.md) 1. Learn more about [plugin design](/docs/guide/plugin-design.md) 1. See some [more example applications](/docs/guide/more-examples.md) +1. More features of the [Basecoin tool](/docs/guide/basecoin-tool.md) 1. Learn how to use [InterBlockchain Communication (IBC)](/docs/guide/ibc.md) 1. [Deploy testnets](deployment.md) running your basecoin application. diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index d16d001f0e..cab2213684 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -14,6 +14,7 @@ func main() { app.Usage = "basecoin [command] [args...]" app.Version = version.Version app.Commands = []cli.Command{ + commands.InitCmd, commands.StartCmd, commands.TxCmd, commands.QueryCmd, diff --git a/cmd/commands/flags.go b/cmd/commands/flags.go index 0c4c477707..06f0ce4233 100644 --- a/cmd/commands/flags.go +++ b/cmd/commands/flags.go @@ -21,15 +21,9 @@ var ( // TODO: move to config file // eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded") - DirFlag = cli.StringFlag{ - Name: "dir", - Value: ".", - Usage: "Root directory", - } - - InProcTMFlag = cli.BoolFlag{ - Name: "in-proc", - Usage: "Run Tendermint in-process with the App", + ABCIServerFlag = cli.BoolFlag{ + Name: "abci-server", + Usage: "Run the Basecoin app and ABCI server, but not Tendermint (run Tendermint in another process)", } ) diff --git a/cmd/commands/init.go b/cmd/commands/init.go new file mode 100644 index 0000000000..9d44167e46 --- /dev/null +++ b/cmd/commands/init.go @@ -0,0 +1,116 @@ +package commands + +import ( + "io/ioutil" + "os" + "path" + + "github.com/urfave/cli" + + cmn "github.com/tendermint/go-common" + tmcfg "github.com/tendermint/tendermint/config/tendermint" + types "github.com/tendermint/tendermint/types" +) + +var InitCmd = cli.Command{ + Name: "init", + Usage: "Initialize a basecoin blockchain", + ArgsUsage: "", + Action: func(c *cli.Context) error { + return cmdInit(c) + }, + Flags: []cli.Flag{ + ChainIDFlag, + }, +} + +func cmdInit(c *cli.Context) error { + basecoinDir := BasecoinRoot("") + tmDir := path.Join(basecoinDir, "tendermint") + + // initalize tendermint + tmConfig := tmcfg.GetConfig(tmDir) + + privValFile := tmConfig.GetString("priv_validator_file") + if _, err := os.Stat(privValFile); os.IsNotExist(err) { + privValidator := types.GenPrivValidator() + privValidator.SetFile(privValFile) + privValidator.Save() + + genFile := tmConfig.GetString("genesis_file") + + if _, err := os.Stat(genFile); os.IsNotExist(err) { + genDoc := types.GenesisDoc{ + ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)), + } + genDoc.Validators = []types.GenesisValidator{types.GenesisValidator{ + PubKey: privValidator.PubKey, + Amount: 10, + }} + + genDoc.SaveAs(genFile) + } + log.Notice("Initialized Tendermint", "genesis", tmConfig.GetString("genesis_file"), "priv_validator", tmConfig.GetString("priv_validator_file")) + } else { + log.Notice("Already initialized Tendermint", "priv_validator", tmConfig.GetString("priv_validator_file")) + } + + // initalize basecoin + genesisFile := path.Join(basecoinDir, "genesis.json") + key1File := path.Join(basecoinDir, "key.json") + key2File := path.Join(basecoinDir, "key2.json") + + if err := ioutil.WriteFile(genesisFile, []byte(genesisJSON), 0644); err != nil { + return err + } + if err := ioutil.WriteFile(key1File, []byte(key1JSON), 0400); err != nil { + return err + } + if err := ioutil.WriteFile(key2File, []byte(key2JSON), 0400); err != nil { + return err + } + + log.Notice("Initialized Basecoin", "genesis", genesisFile, "key", key1File) + + return nil +} + +const genesisJSON = `[ + "base/chainID", "test_chain_id", + "base/account", { + "pub_key": { + "type": "ed25519", + "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + }, + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + } +]` + +const key1JSON = `{ + "address": "1B1BE55F969F54064628A63B9559E7C21C925165", + "priv_key": [ + 1, + "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + ], + "pub_key": [ + 1, + "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + ] +}` + +const key2JSON = `{ + "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", + "priv_key": [ + 1, + "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A8352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" + ], + "pub_key": [ + 1, + "352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" + ] +}` diff --git a/cmd/commands/key.go b/cmd/commands/key.go index 2ebd74afd4..714958a07d 100644 --- a/cmd/commands/key.go +++ b/cmd/commands/key.go @@ -3,6 +3,7 @@ package commands import ( "fmt" "io/ioutil" + "path" "github.com/urfave/cli" @@ -60,14 +61,15 @@ func genKey() *Key { } } -func LoadKey(filePath string) *Key { +func LoadKey(keyFile string) *Key { + filePath := path.Join(BasecoinRoot(""), keyFile) 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)) + cmn.Exit(cmn.Fmt("Error reading key from %v: %v\n", filePath, err)) } return key } diff --git a/cmd/commands/log.go b/cmd/commands/log.go new file mode 100644 index 0000000000..720e168b57 --- /dev/null +++ b/cmd/commands/log.go @@ -0,0 +1,7 @@ +package commands + +import ( + "github.com/tendermint/go-logger" +) + +var log = logger.New("module", "commands") diff --git a/cmd/commands/start.go b/cmd/commands/start.go index 72a13107df..4c4afd199d 100644 --- a/cmd/commands/start.go +++ b/cmd/commands/start.go @@ -10,8 +10,6 @@ import ( "github.com/tendermint/abci/server" cmn "github.com/tendermint/go-common" - cfg "github.com/tendermint/go-config" - //logger "github.com/tendermint/go-logger" eyes "github.com/tendermint/merkleeyes/client" tmcfg "github.com/tendermint/tendermint/config/tendermint" @@ -23,8 +21,6 @@ import ( "github.com/tendermint/basecoin/types" ) -var config cfg.Config - const EyesCacheSize = 10000 var StartCmd = cli.Command{ @@ -37,8 +33,7 @@ var StartCmd = cli.Command{ Flags: []cli.Flag{ AddrFlag, EyesFlag, - DirFlag, - InProcTMFlag, + ABCIServerFlag, ChainIDFlag, }, } @@ -56,11 +51,12 @@ func RegisterStartPlugin(name string, newPlugin func() types.Plugin) { } func cmdStart(c *cli.Context) error { + basecoinDir := BasecoinRoot("") // Connect to MerkleEyes var eyesCli *eyes.Client if c.String("eyes") == "local" { - eyesCli = eyes.NewLocalClient(path.Join(c.String("dir"), "merkleeyes.db"), EyesCacheSize) + eyesCli = eyes.NewLocalClient(path.Join(basecoinDir, "merkleeyes.db"), EyesCacheSize) } else { var err error eyesCli, err = eyes.NewClient(c.String("eyes")) @@ -81,7 +77,7 @@ func cmdStart(c *cli.Context) error { } // If genesis file exists, set key-value options - genesisFile := path.Join(c.String("dir"), "genesis.json") + genesisFile := path.Join(basecoinDir, "genesis.json") if _, err := os.Stat(genesisFile); err == nil { err := basecoinApp.LoadGenesis(genesisFile) if err != nil { @@ -91,12 +87,14 @@ func cmdStart(c *cli.Context) error { fmt.Printf("No genesis file at %s, skipping...\n", genesisFile) } - if c.Bool("in-proc") { - startTendermint(c, basecoinApp) - } else { + if c.Bool("abci-server") { + // run just the abci app/server if err := startBasecoinABCI(c, basecoinApp); err != nil { return err } + } else { + // start the app with tendermint in-process + startTendermint(basecoinDir, basecoinApp) } return nil @@ -117,17 +115,18 @@ func startBasecoinABCI(c *cli.Context, basecoinApp *app.Basecoin) error { } -func startTendermint(c *cli.Context, basecoinApp *app.Basecoin) { +func startTendermint(dir string, basecoinApp *app.Basecoin) { // Get configuration - config = tmcfg.GetConfig("") + tmConfig := tmcfg.GetConfig(path.Join(dir, "tendermint")) + // logger.SetLogLevel("notice") //config.GetString("log_level")) // parseFlags(config, args[1:]) // Command line overrides // Create & start tendermint node - privValidatorFile := config.GetString("priv_validator_file") + privValidatorFile := tmConfig.GetString("priv_validator_file") privValidator := tmtypes.LoadOrGenPrivValidator(privValidatorFile) - n := node.NewNode(config, privValidator, proxy.NewLocalClientCreator(basecoinApp)) + n := node.NewNode(tmConfig, privValidator, proxy.NewLocalClientCreator(basecoinApp)) n.Start() diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index de1a923277..b4a900832e 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -14,7 +14,6 @@ import ( client "github.com/tendermint/go-rpc/client" "github.com/tendermint/go-wire" ctypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" ) var TxFlags = []cli.Flag{ @@ -144,7 +143,7 @@ func AppTx(c *cli.Context, name string, data []byte) error { gas := int64(c.Int("gas")) chainID := c.String("chain_id") - privKey := tmtypes.LoadPrivValidator(fromFile) + privKey := LoadKey(fromFile) sequence, err := getSeq(c, privKey.Address) if err != nil { diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index bfd3d8564b..35af75baae 100644 --- a/cmd/commands/utils.go +++ b/cmd/commands/utils.go @@ -3,6 +3,7 @@ package commands import ( "encoding/hex" "errors" + "os" "regexp" "strconv" "strings" @@ -20,6 +21,16 @@ import ( tmtypes "github.com/tendermint/tendermint/types" ) +func BasecoinRoot(rootDir string) string { + if rootDir == "" { + rootDir = os.Getenv("BASECOIN_ROOT") + } + if rootDir == "" { + rootDir = os.Getenv("HOME") + "/.basecoin" + } + return rootDir +} + // Returns true for non-empty hex-string prefixed with "0x" func isHex(s string) bool { if len(s) > 2 && s[:2] == "0x" { diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 0dccb32622..9ecb08c447 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -5,77 +5,34 @@ 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). +Installing basecoin is simple: -**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) +``` +go get -u github.com/tendermint/basecoin/cmd/basecoin +``` + +If you have trouble, see the [installation guide](install.md). ## Initialization -Basecoin is an ABCI application that runs on Tendermint, so we first need to initialize Tendermint: +To initialize a new Basecoin blockchain, run: ``` -tendermint init +basecoin 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 -(note this will delete all chain data, so back it up if you need it): - -``` -tendermint unsafe_reset_all -``` - -Now we need some initialization files for basecoin. -We have included some defaults in the basecoin directory, under `data`. -For purposes of convenience, change to that directory: - -``` -cd $GOPATH/src/github.com/tendermint/basecoin/data -``` - -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`). +This will create the necessary files for a Basecoin blockchain with one validator and one account in `~/.basecoin`. +For more options on setup, see the [guide to using the Basecoin tool](/docs/guide/basecoin-tool.md). ## Start 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: - -``` -basecoin start --in-proc --dir PATH/TO/CUSTOM/DATA -``` - -Note that `--in-proc` stands for "in process", which means -basecoin will be started with the Tendermint node running in the same process. -To start Tendermint in a separate process instead, use: - ``` basecoin start ``` -and in another window: - -``` -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. +You should see blocks start streaming in! ## Send transactions @@ -98,8 +55,7 @@ Let's send funds from the first account to the second: 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`. +By default, the CLI looks for a `key.json` to sign the transaction with. To specify a different key, we can use the `--from` flag. Now if we check the second account, it should have `10` 'mycoin' coins!