diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dfdd0dd68..26d1c87aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,58 @@ # Changelog +## 0.3.0 (March 23, 2017) + +BREAKING CHANGES: + +- Remove `--data` flag and use `BCHOME` to set the home directory (defaults to `~/.basecoin`) +- Remove `--in-proc` flag and start Tendermint in-process by default (expect Tendermint files in $BCHOME/tendermint). +To start just the ABCI app/server, use `basecoin start --without-tendermint`. +- Consolidate genesis files so the Basecoin genesis is an object under `app_options` in Tendermint genesis. For instance: + +``` +{ + "app_hash": "", + "chain_id": "foo_bar_chain", + "genesis_time": "0001-01-01T00:00:00.000Z", + "validators": [ + { + "amount": 10, + "name": "", + "pub_key": [ + 1, + "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" + ] + } + ], + "app_options": { + "accounts": [{ + "pub_key": { + "type": "ed25519", + "data": "6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2" + }, + "coins": [ + { + "denom": "blank", + "amount": 12345 + }, + { + "denom": "ETH", + "amount": 654321 + } + ] + }], + "plugin_options": ["plugin1/key1", "value1", "plugin1/key2", "value2"] + } +} +``` + +Note the array of key-value pairs is now under `app_options.plugin_options` while the `app_options` themselves are well formed. +We also changed `chainID` to `chain_id` and consolidated to have just one of them. + +FEATURES: + +- Introduce `basecoin init` and `basecoin unsafe_reset_all` + ## 0.2.0 (March 6, 2017) BREAKING CHANGES: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..79b078d91c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM alpine:3.5 + +# BCHOME is where your genesis.json, key.json and other files including state are stored. +ENV BCHOME /basecoin + +# Create a basecoin user and group first so the IDs get set the same way, even +# as the rest of this may change over time. +RUN addgroup basecoin && \ + adduser -S -G basecoin basecoin + +RUN mkdir -p $BCHOME && \ + chown -R basecoin:basecoin $BCHOME +WORKDIR $BCHOME + +# Expose the basecoin home directory as a volume since there's mutable state in there. +VOLUME $BCHOME + +# jq and curl used for extracting `pub_key` from private validator while +# deploying tendermint with Kubernetes. It is nice to have bash so the users +# could execute bash commands. +RUN apk add --no-cache bash curl jq + +COPY basecoin /usr/bin/basecoin + +ENTRYPOINT ["basecoin"] + +# By default you will get the basecoin with local MerkleEyes and in-proc Tendermint. +CMD ["start", "--dir=${BCHOME}"] diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000000..ee6cdc6e21 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,12 @@ +FROM golang:latest + +RUN mkdir -p /go/src/github.com/tendermint/basecoin +WORKDIR /go/src/github.com/tendermint/basecoin + +COPY Makefile /go/src/github.com/tendermint/basecoin/ +COPY glide.yaml /go/src/github.com/tendermint/basecoin/ +COPY glide.lock /go/src/github.com/tendermint/basecoin/ + +RUN make get_vendor_deps + +COPY . /go/src/github.com/tendermint/basecoin diff --git a/Makefile b/Makefile index 89f9af72b5..32ec678624 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ -.PHONY: all test get_deps - all: test install NOVENDOR = go list github.com/tendermint/basecoin/... | grep -v /vendor/ @@ -24,3 +22,11 @@ get_vendor_deps: go get github.com/Masterminds/glide glide install +build-docker: + docker run -it --rm -v "$(PWD):/go/src/github.com/tendermint/basecoin" -w "/go/src/github.com/tendermint/basecoin" -e "CGO_ENABLED=0" golang:alpine go build ./cmd/basecoin + docker build -t "tendermint/basecoin" . + +clean: + @rm -f ./basecoin + +.PHONY: all build install test get_deps update_deps get_vendor_deps build-docker clean diff --git a/README.md b/README.md index 6b4b0c34e4..0c15ed0576 100644 --- a/README.md +++ b/README.md @@ -15,46 +15,26 @@ 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 +## Guide -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 - -1. Getting started with the [Basecoin tool](/docs/guide/basecoin-basics.md) +1. Getting started with the [Basecoin basics](/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. +1. [Deploy testnets](/docs/guide/deployment.md) running your basecoin application. diff --git a/app/app.go b/app/app.go index 0b8fb6d2e3..5aafff04ce 100644 --- a/app/app.go +++ b/app/app.go @@ -60,12 +60,12 @@ func (app *Basecoin) SetOption(key string, value string) string { if plugin == nil { return "Invalid plugin name: " + pluginName } - log.Info("SetOption on plugin", "plugin", pluginName, "key", key, "value", value) + log.Notice("SetOption on plugin", "plugin", pluginName, "key", key, "value", value) return plugin.SetOption(app.state, key, value) } else { // Set option on basecoin switch key { - case "chainID": + case "chain_id": app.state.SetChainID(value) return "Success" case "account": @@ -75,7 +75,8 @@ func (app *Basecoin) SetOption(key string, value string) string { return "Error decoding acc message: " + err.Error() } app.state.SetAccount(acc.PubKey.Address(), &acc) - log.Info("SetAccount", "addr", acc.PubKey.Address(), "acc", acc) + log.Notice("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 afa94ecab3..ad8b2b6c9e 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -4,16 +4,35 @@ import ( "encoding/json" "github.com/pkg/errors" + "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" + //tmtypes "github.com/tendermint/tendermint/types" ) func (app *Basecoin) LoadGenesis(path string) error { - kvz, err := loadGenesis(path) + genDoc, err := loadGenesis(path) if err != nil { return err } - for _, kv := range kvz { - app.SetOption(kv.Key, kv.Value) + + // set chain_id + app.SetOption("base/chain_id", genDoc.ChainID) + + // set accounts + for _, acc := range genDoc.AppOptions.Accounts { + accBytes, err := json.Marshal(acc) + if err != nil { + return err + } + r := app.SetOption("base/account", string(accBytes)) + // TODO: SetOption returns an error + log.Notice("Done setting Account via SetOption", "result", r) + } + + // set plugin options + for _, kv := range genDoc.AppOptions.pluginOptions { + r := app.SetOption(kv.Key, kv.Value) + log.Notice("Done setting Plugin key-value pair via SetOption", "result", r, "k", kv.Key, "v", kv.Value) } return nil } @@ -23,16 +42,45 @@ type keyValue struct { Value string `json:"value"` } -func loadGenesis(filePath string) (kvz []keyValue, err error) { - kvz_ := []json.RawMessage{} +// includes tendermint (in the json, we ignore here) +type FullGenesisDoc struct { + ChainID string `json:"chain_id"` + AppOptions *GenesisDoc `json:"app_options"` +} + +type GenesisDoc struct { + Accounts []types.Account `json:"accounts"` + PluginOptions []json.RawMessage `json:"plugin_options"` + + pluginOptions []keyValue // unmarshaled rawmessages +} + +func loadGenesis(filePath string) (*FullGenesisDoc, error) { bytes, err := cmn.ReadFile(filePath) if err != nil { return nil, errors.Wrap(err, "loading genesis file") } - err = json.Unmarshal(bytes, &kvz_) + + // the tendermint genesis is go-wire + // tmGenesis := new(tmtypes.GenesisDoc) + // err = wire.ReadJSONBytes(bytes, tmGenesis) + + // the basecoin genesis go-data :) + genDoc := new(FullGenesisDoc) + err = json.Unmarshal(bytes, genDoc) if err != nil { - return nil, errors.Wrap(err, "parsing genesis file") + return nil, errors.Wrap(err, "unmarshaling genesis file") } + + pluginOpts, err := parseGenesisList(genDoc.AppOptions.PluginOptions) + if err != nil { + return nil, err + } + genDoc.AppOptions.pluginOptions = pluginOpts + return genDoc, nil +} + +func parseGenesisList(kvz_ []json.RawMessage) (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, ...]") } diff --git a/app/testdata/genesis.json b/app/testdata/genesis.json index 0308716c9c..ee8879fd28 100644 --- a/app/testdata/genesis.json +++ b/app/testdata/genesis.json @@ -1,19 +1,22 @@ -[ - "base/chainID", "foo_bar_chain", - "base/account", { - "pub_key": { - "type": "ed25519", - "data": "6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2" - }, - "coins": [ - { - "denom": "blank", - "amount": 12345 +{ + "chain_id": "foo_bar_chain", + "app_options": { + "accounts": [{ + "pub_key": { + "type": "ed25519", + "data": "6880db93598e283a67c4d88fc67a8858aa2de70f713fe94a5109e29c137100c2" }, - { - "denom": "ETH", - "amount": 654321 - } - ] + "coins": [ + { + "denom": "blank", + "amount": 12345 + }, + { + "denom": "ETH", + "amount": 654321 + } + ] + }], + "plugin_options": ["plugin1/key1", "value1", "plugin1/key2", "value2"] } -] +} diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index d16d001f0e..d452aeb6f8 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, @@ -21,6 +22,7 @@ func main() { commands.VerifyCmd, commands.BlockCmd, commands.AccountCmd, + commands.UnsafeResetAllCmd, } app.Run(os.Args) } diff --git a/cmd/commands/flags.go b/cmd/commands/flags.go index 0c4c477707..ccf95769d3 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", + WithoutTendermintFlag = cli.BoolFlag{ + Name: "without-tendermint", + Usage: "Run the Basecoin app without Tendermint", } ) diff --git a/cmd/commands/init.go b/cmd/commands/init.go new file mode 100644 index 0000000000..e60e7d1306 --- /dev/null +++ b/cmd/commands/init.go @@ -0,0 +1,122 @@ +package commands + +import ( + "io/ioutil" + "path" + + "github.com/urfave/cli" + + cmn "github.com/tendermint/go-common" +) + +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 { + rootDir := BasecoinRoot("") + + cmn.EnsureDir(rootDir, 0777) + + // initalize basecoin + genesisFile := path.Join(rootDir, "genesis.json") + privValFile := path.Join(rootDir, "priv_validator.json") + key1File := path.Join(rootDir, "key.json") + key2File := path.Join(rootDir, "key2.json") + + if err := ioutil.WriteFile(genesisFile, []byte(genesisJSON), 0644); err != nil { + return err + } + if err := ioutil.WriteFile(privValFile, []byte(privValJSON), 0400); 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 privValJSON = `{ + "address": "7A956FADD20D3A5B2375042B2959F8AB172A058F", + "last_height": 0, + "last_round": 0, + "last_signature": null, + "last_signbytes": "", + "last_step": 0, + "priv_key": [ + 1, + "D07ABE82A8B15559A983B2DB5D4842B2B6E4D6AF58B080005662F424F17D68C17B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" + ], + "pub_key": [ + 1, + "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" + ] +}` + +const genesisJSON = `{ + "app_hash": "", + "chain_id": "test_chain_id", + "genesis_time": "0001-01-01T00:00:00.000Z", + "validators": [ + { + "amount": 10, + "name": "", + "pub_key": [ + 1, + "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" + ] + } + ], + "app_options": { + "accounts": [{ + "pub_key": { + "type": "ed25519", + "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + }, + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + }] + } +}` + +const key1JSON = `{ + "address": "1B1BE55F969F54064628A63B9559E7C21C925165", + "priv_key": { + "type": "ed25519", + "data": "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + }, + "pub_key": { + "type": "ed25519", + "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + } +}` + +const key2JSON = `{ + "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", + "priv_key": { + "type": "ed25519", + "data": "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A8352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" + }, + "pub_key": { + "type": "ed25519", + "data": "352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" + } +}` diff --git a/cmd/commands/key.go b/cmd/commands/key.go index 2ebd74afd4..b492eb94bc 100644 --- a/cmd/commands/key.go +++ b/cmd/commands/key.go @@ -1,14 +1,17 @@ package commands import ( + "encoding/hex" + "encoding/json" "fmt" "io/ioutil" + "path" + "strings" "github.com/urfave/cli" cmn "github.com/tendermint/go-common" "github.com/tendermint/go-crypto" - "github.com/tendermint/go-wire" ) var ( @@ -31,18 +34,36 @@ var ( func cmdNewKey(c *cli.Context) error { key := genKey() - keyJSON := wire.JSONBytesPretty(key) - fmt.Println(string(keyJSON)) + keyJSON, err := json.MarshalIndent(key, "", "\t") + if err != nil { + return err + } + fmt.Println(keyJSON) return nil } //--------------------------------------------- // simple implementation of a key +type Address [20]byte + +func (a Address) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%x"`, a[:])), nil +} + +func (a *Address) UnmarshalJSON(addrHex []byte) error { + addr, err := hex.DecodeString(strings.Trim(string(addrHex), `"`)) + if err != nil { + return err + } + copy(a[:], addr) + return nil +} + type Key struct { - Address []byte `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` - PrivKey crypto.PrivKey `json:"priv_key"` + Address Address `json:"address"` + PubKey crypto.PubKeyS `json:"pub_key"` + PrivKey crypto.PrivKeyS `json:"priv_key"` } // Implements Signer @@ -53,21 +74,26 @@ func (k *Key) Sign(msg []byte) crypto.Signature { // Generates a new validator with private key. func genKey() *Key { privKey := crypto.GenPrivKeyEd25519() + addrBytes := privKey.PubKey().Address() + var addr Address + copy(addr[:], addrBytes) return &Key{ - Address: privKey.PubKey().Address(), - PubKey: privKey.PubKey(), - PrivKey: privKey, + Address: addr, + PubKey: crypto.PubKeyS{privKey.PubKey()}, + PrivKey: crypto.PrivKeyS{privKey}, } } -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) + key := new(Key) + err = json.Unmarshal(keyJSONBytes, 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/reset.go b/cmd/commands/reset.go new file mode 100644 index 0000000000..d9688fd859 --- /dev/null +++ b/cmd/commands/reset.go @@ -0,0 +1,47 @@ +package commands + +import ( + "os" + "path" + + "github.com/urfave/cli" + + tmcfg "github.com/tendermint/tendermint/config/tendermint" + types "github.com/tendermint/tendermint/types" +) + +var UnsafeResetAllCmd = cli.Command{ + Name: "unsafe_reset_all", + Usage: "Reset all blockchain data", + ArgsUsage: "", + Action: func(c *cli.Context) error { + return cmdUnsafeResetAll(c) + }, +} + +func cmdUnsafeResetAll(c *cli.Context) error { + basecoinDir := BasecoinRoot("") + tmDir := path.Join(basecoinDir) + tmConfig := tmcfg.GetConfig(tmDir) + + // Get and Reset PrivValidator + var privValidator *types.PrivValidator + privValidatorFile := tmConfig.GetString("priv_validator_file") + if _, err := os.Stat(privValidatorFile); err == nil { + privValidator = types.LoadPrivValidator(privValidatorFile) + privValidator.Reset() + log.Notice("Reset PrivValidator", "file", privValidatorFile) + } else { + privValidator = types.GenPrivValidator() + privValidator.SetFile(privValidatorFile) + privValidator.Save() + log.Notice("Generated PrivValidator", "file", privValidatorFile) + } + + // Remove all tendermint data + tmDataDir := tmConfig.GetString("db_dir") + os.RemoveAll(tmDataDir) + log.Notice("Removed all data", "dir", tmDataDir) + + return nil +} diff --git a/cmd/commands/start.go b/cmd/commands/start.go index 72a13107df..1e6861ac06 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, + WithoutTendermintFlag, 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, "data", "merkleeyes.db"), EyesCacheSize) } else { var err error eyesCli, err = eyes.NewClient(c.String("eyes")) @@ -80,23 +76,30 @@ func cmdStart(c *cli.Context) error { basecoinApp.RegisterPlugin(p.newPlugin()) } - // If genesis file exists, set key-value options - genesisFile := path.Join(c.String("dir"), "genesis.json") - if _, err := os.Stat(genesisFile); err == nil { - err := basecoinApp.LoadGenesis(genesisFile) - if err != nil { - return errors.New(cmn.Fmt("%+v", err)) + // if chain_id has not been set yet, load the genesis. + // else, assume it's been loaded + if basecoinApp.GetState().GetChainID() == "" { + // If genesis file exists, set key-value options + genesisFile := path.Join(basecoinDir, "genesis.json") + if _, err := os.Stat(genesisFile); err == nil { + err := basecoinApp.LoadGenesis(genesisFile) + if err != nil { + return errors.New(cmn.Fmt("%+v", err)) + } + } else { + fmt.Printf("No genesis file at %s, skipping...\n", genesisFile) } - } else { - fmt.Printf("No genesis file at %s, skipping...\n", genesisFile) } - if c.Bool("in-proc") { - startTendermint(c, basecoinApp) + chainID := basecoinApp.GetState().GetChainID() + if c.Bool("without-tendermint") { + log.Notice("Starting Basecoin without Tendermint", "chain_id", chainID) + // run just the abci app/server + return startBasecoinABCI(c, basecoinApp) } else { - if err := startBasecoinABCI(c, basecoinApp); err != nil { - return err - } + log.Notice("Starting Basecoin with Tendermint", "chain_id", chainID) + // start the app with tendermint in-process + return startTendermint(basecoinDir, basecoinApp) } return nil @@ -117,23 +120,29 @@ func startBasecoinABCI(c *cli.Context, basecoinApp *app.Basecoin) error { } -func startTendermint(c *cli.Context, basecoinApp *app.Basecoin) { +func startTendermint(dir string, basecoinApp *app.Basecoin) error { // Get configuration - config = tmcfg.GetConfig("") + tmConfig := tmcfg.GetConfig(dir) + // 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() + _, err := n.Start() + if err != nil { + return err + } // Wait forever cmn.TrapSignal(func() { // Cleanup n.Stop() }) + + return nil } diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index de1a923277..3c5cebd837 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{ @@ -87,7 +86,7 @@ func cmdSendTx(c *cli.Context) error { privKey := LoadKey(fromFile) // get the sequence number for the tx - sequence, err := getSeq(c, privKey.Address) + sequence, err := getSeq(c, privKey.Address[:]) if err != nil { return err } @@ -144,9 +143,9 @@ 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) + sequence, err := getSeq(c, privKey.Address[:]) if err != nil { return err } diff --git a/cmd/commands/utils.go b/cmd/commands/utils.go index bfd3d8564b..56c1480780 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("BCHOME") + } + 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/data/genesis.json b/data/genesis.json deleted file mode 100644 index 66d96300cd..0000000000 --- a/data/genesis.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - "base/chainID", "test_chain_id", - "base/account", { - "pub_key": { - "type": "ed25519", - "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } -] diff --git a/data/key.json b/data/key.json deleted file mode 100644 index 34ea194386..0000000000 --- a/data/key.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "address": "1B1BE55F969F54064628A63B9559E7C21C925165", - "priv_key": [ - 1, - "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - ], - "pub_key": [ - 1, - "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - ] -} diff --git a/data/key2.json b/data/key2.json deleted file mode 100644 index 38af8af74b..0000000000 --- a/data/key2.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", - "priv_key": [ - 1, - "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A8352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" - ], - "pub_key": [ - 1, - "352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" - ] -} diff --git a/demo/clean.sh b/demo/clean.sh index e2d519337d..e39f090eec 100644 --- a/demo/clean.sh +++ b/demo/clean.sh @@ -1,13 +1,10 @@ #! /bin/bash killall -9 basecoin tendermint -TMROOT=./data/chain1/tendermint tendermint unsafe_reset_all -TMROOT=./data/chain2/tendermint tendermint unsafe_reset_all - -rm -rf ./data/chain1/basecoin/merkleeyes.db -rm -rf ./data/chain2/basecoin/merkleeyes.db +TMROOT=./data/chain1 tendermint unsafe_reset_all +TMROOT=./data/chain2 tendermint unsafe_reset_all rm ./*.log -rm ./data/chain1/tendermint/*.bak -rm ./data/chain2/tendermint/*.bak +rm ./data/chain1/*.bak +rm ./data/chain2/*.bak diff --git a/demo/data/chain1/basecoin/genesis.json b/demo/data/chain1/basecoin/genesis.json deleted file mode 100644 index 588fc86f4f..0000000000 --- a/demo/data/chain1/basecoin/genesis.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - "base/chainID", "test_chain_1", - "base/account", { - "pub_key": { - "type": "ed25519", - "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } -] diff --git a/demo/data/chain1/basecoin/key.json b/demo/data/chain1/basecoin/key.json deleted file mode 100644 index e610ba89d2..0000000000 --- a/demo/data/chain1/basecoin/key.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "address": "D397BC62B435F3CF50570FBAB4340FE52C60858F", - "priv_key": [ - 1, - "39E75AA1CF7BC710585977EFC375CD1730519186BD231478C339F2819C3C26E7B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - ], - "pub_key": [ - 1, - "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - ] -} - diff --git a/demo/data/chain1/tendermint/config.toml b/demo/data/chain1/config.toml similarity index 100% rename from demo/data/chain1/tendermint/config.toml rename to demo/data/chain1/config.toml diff --git a/demo/data/chain1/genesis.json b/demo/data/chain1/genesis.json new file mode 100644 index 0000000000..d50161a5aa --- /dev/null +++ b/demo/data/chain1/genesis.json @@ -0,0 +1,31 @@ +{ + "app_hash": "", + "chain_id": "test_chain_1", + "genesis_time": "0001-01-01T00:00:00.000Z", + "validators": [ + { + "amount": 10, + "name": "", + "pub_key": [ + 1, + "D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A" + ] + } + ], + "app_options": { + "accounts": [ + { + "pub_key": { + "type": "ed25519", + "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" + }, + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + } + ] + } +} diff --git a/demo/data/chain1/key.json b/demo/data/chain1/key.json new file mode 100644 index 0000000000..751dc858f0 --- /dev/null +++ b/demo/data/chain1/key.json @@ -0,0 +1,12 @@ +{ + "address": "D397BC62B435F3CF50570FBAB4340FE52C60858F", + "priv_key": { + "type": "ed25519", + "data": "39E75AA1CF7BC710585977EFC375CD1730519186BD231478C339F2819C3C26E7B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" + }, + "pub_key": { + "type": "ed25519", + "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" + } +} + diff --git a/demo/data/chain1/tendermint/priv_validator.json b/demo/data/chain1/priv_validator.json similarity index 100% rename from demo/data/chain1/tendermint/priv_validator.json rename to demo/data/chain1/priv_validator.json diff --git a/demo/data/chain1/tendermint/genesis.json b/demo/data/chain1/tendermint/genesis.json deleted file mode 100644 index 91830dd23f..0000000000 --- a/demo/data/chain1/tendermint/genesis.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "app_hash": "", - "chain_id": "test_chain_1", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": [ - 1, - "D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A" - ] - } - ] -} diff --git a/demo/data/chain2/basecoin/genesis.json b/demo/data/chain2/basecoin/genesis.json deleted file mode 100644 index 05df04be5a..0000000000 --- a/demo/data/chain2/basecoin/genesis.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - "base/chainID", "test_chain_2", - "base/account", { - "pub_key": { - "type": "ed25519", - "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } -] diff --git a/demo/data/chain2/basecoin/key.json b/demo/data/chain2/basecoin/key.json deleted file mode 100644 index 90761696de..0000000000 --- a/demo/data/chain2/basecoin/key.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "address": "053BA0F19616AFF975C8756A2CBFF04F408B4D47", - "priv_key": [ - 1, - "22920C428043D869987F253D7C9B2305E7010642C40CE88A52C9F6CE5ACC42080628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - ], - "pub_key": [ - 1, - "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - ] -} diff --git a/demo/data/chain2/tendermint/config.toml b/demo/data/chain2/config.toml similarity index 100% rename from demo/data/chain2/tendermint/config.toml rename to demo/data/chain2/config.toml diff --git a/demo/data/chain2/genesis.json b/demo/data/chain2/genesis.json new file mode 100644 index 0000000000..c534617562 --- /dev/null +++ b/demo/data/chain2/genesis.json @@ -0,0 +1,31 @@ +{ + "app_hash": "", + "chain_id": "test_chain_2", + "genesis_time": "0001-01-01T00:00:00.000Z", + "validators": [ + { + "amount": 10, + "name": "", + "pub_key": [ + 1, + "9A76DDE4CA4EE660C073D288DBE4F8A128F23857881A95F18167682D47E7058F" + ] + } + ], + "app_options": { + "accounts": [ + { + "pub_key": { + "type": "ed25519", + "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" + }, + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + } + ] + } +} diff --git a/demo/data/chain2/key.json b/demo/data/chain2/key.json new file mode 100644 index 0000000000..6aa8b7965f --- /dev/null +++ b/demo/data/chain2/key.json @@ -0,0 +1,11 @@ +{ + "address": "053BA0F19616AFF975C8756A2CBFF04F408B4D47", + "priv_key": { + "type": "ed25519", + "data": "22920C428043D869987F253D7C9B2305E7010642C40CE88A52C9F6CE5ACC42080628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" + }, + "pub_key": { + "type": "ed25519", + "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" + } +} diff --git a/demo/data/chain2/tendermint/priv_validator.json b/demo/data/chain2/priv_validator.json similarity index 100% rename from demo/data/chain2/tendermint/priv_validator.json rename to demo/data/chain2/priv_validator.json diff --git a/demo/data/chain2/tendermint/genesis.json b/demo/data/chain2/tendermint/genesis.json deleted file mode 100644 index 6c9f17c952..0000000000 --- a/demo/data/chain2/tendermint/genesis.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "app_hash": "", - "chain_id": "test_chain_2", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": [ - 1, - "9A76DDE4CA4EE660C073D288DBE4F8A128F23857881A95F18167682D47E7058F" - ] - } - ] -} diff --git a/demo/start.sh b/demo/start.sh index d4891ecdd7..bfc6872350 100644 --- a/demo/start.sh +++ b/demo/start.sh @@ -60,29 +60,34 @@ function waitForBlock() { done } +# make basecoin root vars +export BCHOME="." +BCHOME1="./data/chain1" +BCHOME2="./data/chain2" # grab the chain ids -CHAIN_ID1=$(cat ./data/chain1/basecoin/genesis.json | jq .[1]) +CHAIN_ID1=$(cat $BCHOME1/genesis.json | jq .chain_id) CHAIN_ID1=$(removeQuotes $CHAIN_ID1) -CHAIN_ID2=$(cat ./data/chain2/basecoin/genesis.json | jq .[1]) +CHAIN_ID2=$(cat $BCHOME2/genesis.json | jq .chain_id) CHAIN_ID2=$(removeQuotes $CHAIN_ID2) echo "CHAIN_ID1: $CHAIN_ID1" echo "CHAIN_ID2: $CHAIN_ID2" # make reusable chain flags -CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from ./data/chain1/basecoin/key.json" -CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from ./data/chain2/basecoin/key.json --node tcp://localhost:36657" +CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from $BCHOME1/key.json" +CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node tcp://localhost:36657" + echo "" echo "... starting chains" echo "" # start the first node -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 & +TMROOT=./data/chain1 tendermint node --skip_upnp --log_level=info &> $LOG_DIR/chain1_tendermint.log & +BCHOME=$BCHOME1 basecoin start --without-tendermint &> $LOG_DIR/chain1_basecoin.log & # start the second node -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 & +TMROOT=./data/chain2 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 & +BCHOME=$BCHOME2 basecoin start --address tcp://localhost:36658 --without-tendermint &> $LOG_DIR/chain2_basecoin.log & echo "" echo "... waiting for chains to start" @@ -98,7 +103,7 @@ sleep 3 echo "... registering chain1 on chain2" echo "" # register chain1 on chain2 -basecoin tx ibc --amount 10mycoin $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/genesis.json echo "" echo "... creating egress packet on chain1" 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! diff --git a/docs/guide/basecoin-tool.md b/docs/guide/basecoin-tool.md new file mode 100644 index 0000000000..8af94cdee0 --- /dev/null +++ b/docs/guide/basecoin-tool.md @@ -0,0 +1,142 @@ +# The Basecoin Tool + +In previous tutorials we learned the [basics of the `basecoin` CLI](/docs/guides/basecoin-basics) +and [how to implement a plugin](/docs/guides/example-plugin). +In this tutorial, we provide more details on using the `basecoin` tool. + +# Data Directory + +By default, `basecoin` works out of `~/.basecoin`. To change this, set the `BCHOME` environment variable: + +``` +export BCHOME=~/.my_basecoin_data +basecoin init +basecoin start +``` + +or + +``` +BCHOME=~/.my_basecoin_data basecoin init +BCHOME=~/.my_basecoin_data basecoin start +``` + +# ABCI Server + +So far we have run Basecoin and Tendermint in a single process. +However, since we use ABCI, we can actually run them in different processes. +First, initialize them: + +``` +basecoin init +``` + +This will create a single `genesis.json` file in `~/.basecoin` with the information for both Basecoin and Tendermint. + +Now, In one window, run + +``` +basecoin start --without-tendermint +``` + +and in another, + +``` +TMROOT=~/.basecoin tendermint node +``` + +You should see Tendermint start making blocks! + +Alternatively, you could ignore the Tendermint details in `~/.basecoin/genesis.json` and use a separate directory by running: + +``` +tendermint init +tendermint node +``` + +For more details on using `tendermint`, see [the guide](https://tendermint.com/docs/guides/using-tendermint). + +# Keys and Genesis + +In previous tutorials we used `basecoin init` to initialize `~/.basecoin` with the default configuration. +This command creates files both for Tendermint and for Basecoin, and a single `genesis.json` file for both of them. +For more information on these files, see the [guide to using tendermint](https://tendermint.com/docs/guides/using-tendermint). + +Now let's make our own custom Basecoin data. + +First, create a new directory: + +``` +mkdir example-data +``` + +We can tell `basecoin` to use this directory by exporting the `BCHOME` environment variable: + +``` +export BCHOME=$(pwd)/example-data +``` + +If you're going to be using multiple terminal windows, make sure to add this variable to your shell startup scripts (eg. `~/.bashrc`). + +Now, let's create a new private key: + +``` +basecoin key new > $BCHOME/key.json +``` + +Here's what my `key.json looks like: + +```json +{ + "address": "4EGEhnqOw/gX326c7KARUkY1kic=", + "pub_key": { + "type": "ed25519", + "data": "a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" + }, + "priv_key": { + "type": "ed25519", + "data": "654c845f4b36d1a881deb0ff09381165d3ccd156b4aabb5b51267e91f1d024a5a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" + } +} +``` + +Yours will look different - each key is randomly derrived. + +Now we can make a `genesis.json` file and add an account with our public key: + +```json +{ + "chain_id": "example-chain", + "app_options": { + "accounts": [{ + "pub_key": { + "type": "ed25519", + "data": "a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" + }, + "coins": [ + { + "denom": "gold", + "amount": 1000000000 + } + ] + }] + } +} +``` + +Here we've granted ourselves `1000000000` units of the `gold` token. +Note that we've also set the `chain_id` to be `example-chain`. +All transactions must therefore include the `--chain_id example-chain` in order to make sure they are valid for this chain. +Previously, we didn't need this flag 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. + +Note we have also left out the details of the tendermint genesis. These are documented in the [tendermint guide](https://tendermint.com/docs/guides/using-tendermint). + + +# Reset + +You can reset all blockchain data by running: + +``` +basecoin unsafe_reset_all +``` diff --git a/docs/guide/deployment.md b/docs/guide/deployment.md index e6a7845fc9..74e954a25a 100644 --- a/docs/guide/deployment.md +++ b/docs/guide/deployment.md @@ -1,9 +1,8 @@ ## 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 blockchain with a single validator node running locally. +This is nice for developing, but it's not a real distributed application yet. 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??? +We do this using the [mintnet-kubernetes tool](https://github.com/tendermint/mintnet-kubernetes). diff --git a/docs/guide/example-plugin.md b/docs/guide/example-plugin.md index 73a6b4e854..31aa3479c2 100644 --- a/docs/guide/example-plugin.md +++ b/docs/guide/example-plugin.md @@ -19,6 +19,8 @@ main.go plugin.go ``` +### main.go + The `main.go` is very simple and does not need to be changed: ```golang @@ -45,7 +47,7 @@ In addition, if we want to send transactions to our plugin, we need to add a new command to the CLI. This is where the `cmd.go` comes in. -## Commands +### cmd.go First, we register the plugin: @@ -157,7 +159,7 @@ All plugin data must be serialized (ie. encoded as a byte-array) and sent as data in an `AppTx`. The `commands.AppTx` function does this for us - it creates an `AppTx` with the corresponding data, signs it, and sends it on to the blockchain. -## RunTx +### plugin.go Ok, now we're ready to actually look at the implementation of the plugin in `plugin.go`. Note I'll leave out some of the methods as they don't serve any purpose for this example, @@ -296,94 +298,42 @@ And that's it! Now that we have a simple plugin, let's see how to run it. ## Running your plugin -In the [previous tutorial](basecoin-basics.md), -we used a pre-generated `genesis.json` and `priv_validator.json` for the application. -This time, let's make our own. - -First, let's create a new directory and change into it: +First, initialize the new blockchain with ``` -mkdir example-data -cd example-data +basecoin init ``` -Now, let's create a new private key: +If you've already run a basecoin blockchain, reset the data with ``` -example-plugin key new > key.json +basecoin unsafe_reset_all ``` -Here's what my `key.json looks like: - -```json -{ - "address": "15F591CA434CFCCBDEC1D206F3ED3EBA207BFE7D", - "priv_key": [ - 1, - "737C629667A9EAADBB8E7CF792D5A8F63AA4BB51E06457DDD7FDCC6D7412AAAD43AA6C88034F9EB8D2717CA4BBFCBA745EFF19B13EFCD6F339EDBAAAFCD2F7B3" - ], - "pub_key": [ - 1, - "43AA6C88034F9EB8D2717CA4BBFCBA745EFF19B13EFCD6F339EDBAAAFCD2F7B3" - ] -} -``` - -Now we can make a `genesis.json` file and add an account with out public key: - -```json -[ - "base/chainID", "example-chain", - "base/account", { - "pub_key": [1, "43AA6C88034F9EB8D2717CA4BBFCBA745EFF19B13EFCD6F339EDBAAAFCD2F7B3"], - "coins": [ - { - "denom": "gold", - "amount": 1000000000, - } - ] - } -] -``` - -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: +To start the blockchain with your new plugin, simply run ``` -tendermint init -tendermint unsafe_reset_all -``` - -Great, now we're ready to go. -To start the blockchain, simply run - -``` -example-plugin start --in-proc +example-plugin start ``` In another window, we can try sending some transactions: ``` -example-plugin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --amount 100gold --chain_id example-chain +example-plugin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 100mycoin ``` -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 1gold --chain_id example-chain +example-plugin tx example --amount 1mycoin ``` The transaction is invalid! That's because we didn't specify the `--valid` flag: ``` -example-plugin tx example --valid --amount 1gold --chain_id example-chain +example-plugin tx example --valid --amount 1mycoin ``` Tada! We successfuly created, signed, broadcast, and processed our custom transaction type. @@ -403,13 +353,13 @@ 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 1gold --chain_id example-chain +example-plugin tx example --valid --amount 1mycoin example-plugin query ExamplePlugin.State ``` Neat, right? Notice how the result of the query comes with a proof. This is a Merkle proof that the state is what we say it is. -In a latter [tutorial on Interblockchain Communication](ibc.md), +In a latter [tutorial on InterBlockchain Communication](ibc.md), we'll put this proof to work! ## Next Steps @@ -419,5 +369,5 @@ basecoin CLI to activate the plugin on the blockchain and to send transactions t Hopefully by now you have some ideas for your own plugin, and feel comfortable implementing them. In the [next tutorial](more-examples.md), we tour through some other plugin examples, -adding features for minting new coins, voting, and changin the Tendermint validator set. +adding features for minting new coins, voting, and changing the Tendermint validator set. But first, you may want to learn a bit more about [the design of the plugin system](plugin-design.md) diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index f933c22ea7..9b88c416ba 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -194,15 +194,15 @@ The relevant data is now in the `data` directory. We can start the two chains as follows: ``` -TMROOT=./data/chain1/tendermint tendermint node &> chain1_tendermint.log & -basecoin start --dir ./data/chain1/basecoin &> chain1_basecoin.log & +TMROOT=./data/chain1 tendermint node &> chain1_tendermint.log & +BCHOME=./data/chain1 basecoin start --without-tendermint &> chain1_basecoin.log & ``` and ``` -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 node --node_laddr tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app tcp://localhost:36658 &> chain2_tendermint.log & +BCHOME=./data/chain2 basecoin start --without-tendermint --address tcp://localhost:36658 &> chain2_basecoin.log & ``` Note how we refer to the relevant data directories. Also note how we have to set the various addresses for the second node so as not to conflict with the first. @@ -224,14 +224,16 @@ For the sake of convenience, let's first set some environment variables: export CHAIN_ID1=test_chain_1 export CHAIN_ID2=test_chain_2 -export CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from ./data/chain1/basecoin/key.json" -export CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from ./data/chain2/basecoin/key.json --node tcp://localhost:36657" +export CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from ./data/chain1/key.json" +export CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from ./data/chain2/key.json --node tcp://localhost:36657" + +export BCHOME="." ``` Let's start by registering `test_chain_1` on `test_chain_2`: ``` -basecoin tx ibc --amount 10mycoin $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/genesis.json ``` Now we can create the outgoing packet on `test_chain_1`: @@ -265,7 +267,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 10mycoin $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. @@ -275,10 +277,10 @@ 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 10mycoin $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 +Here, `` is the height retuned by the previous `query` command, and `` and `` are the `value` and `proof` returned in that same query. Tada! diff --git a/docs/guide/install.md b/docs/guide/install.md index 2a04abe73b..ef0ef28a61 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -8,16 +8,17 @@ 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 correct way of compiling from source, assuming you've already -run `go get` or otherwise cloned the repo, is: +Thus, assuming you've already run `go get` or otherwise cloned the repo, +the correct way to install is: ``` cd $GOPATH/src/github.com/tendermint/basecoin -git checkout develop # (until we release v0.9) make get_vendor_deps make install ``` This will create the `basecoin` binary in `$GOPATH/bin`. +Note the `make get_vendor_deps` command will install `glide` and the correct version of all dependencies. + +If you need another branch, make sure to run `git checkout ` before the `make` commands. diff --git a/docs/guide/more-examples.md b/docs/guide/more-examples.md index 7df37ca0be..1fc1b545c4 100644 --- a/docs/guide/more-examples.md +++ b/docs/guide/more-examples.md @@ -1,19 +1,14 @@ # Plugin Examples -Now that we've seen [how to write a simple plugin](example-plugin.md) -and taken a look at [how the plugin system is designed](plugin-design.md), +Now that we've seen [how to write a simple plugin](/docs/guide/example-plugin.md) +and taken a look at [how the plugin system is designed](/docs/guide/plugin-design.md), it's time for some more advanced examples. For now, most examples are contained in the `github.com/tendermint/basecoin-examples` repository. In particular, we have the following: -1. [Mintcoin][0] - a plugin for issuing new Basecoin tokens -2. [Trader][1] - a plugin for adding escrow and options features to Basecoin -3. [Stakecoin][2] - a plugin for bonding and unbonding Tendermint validators and updating the validator set accordingly -4. [PayToVote][3] - a plugin for creating issues and voting on them -5. [IBC][4] - a plugin for facilitating InterBlockchain Communication -[0]: https://github.com/tendermint/basecoin-examples/tree/develop/mintcoin -[1]: https://github.com/tendermint/basecoin-examples/tree/develop/trader -[2]: https://github.com/tendermint/basecoin-examples/tree/develop/stake -[3]: https://github.com/tendermint/basecoin-examples/tree/develop/paytovote -[4]: ibc.md +1. [Mintcoin](https://github.com/tendermint/basecoin-examples/tree/develop/mintcoin) - a plugin for issuing new Basecoin tokens +2. [Trader](https://github.com/tendermint/basecoin-examples/tree/develop/trader) - a plugin for adding escrow and options features to Basecoin +3. [Stakecoin](https://github.com/tendermint/basecoin-examples/tree/develop/stake) - a plugin for bonding and unbonding Tendermint validators and updating the validator set accordingly +4. [PayToVote](https://github.com/tendermint/basecoin-examples/tree/develop/paytovote) - a plugin for creating issues and voting on them +5. [IBC](/docs/guide/ibc.md) - a plugin for facilitating InterBlockchain Communication diff --git a/glide.lock b/glide.lock index 2d3ddd34e4..d53e80837b 100644 --- a/glide.lock +++ b/glide.lock @@ -1,34 +1,34 @@ -hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-03-06T05:37:03.828355251-05:00 +hash: c71c0d6c409bfddb4c4b471d8445f59cebd2cd41e1635a90d6facd81bd09a5e0 +updated: 2017-03-14T17:02:44.512359631-04:00 imports: - name: github.com/btcsuite/btcd - version: d06c0bb181529331be8f8d9350288c420d9e60e4 + version: 583684b21bfbde9b5fc4403916fd7c807feb0289 subpackages: - btcec - name: github.com/BurntSushi/toml - version: 99064174e013895bbd9b025c31100bd1d9b590ca + version: e643e9ef00b049d75de26e61109c5ea01885cd21 - name: github.com/ebuchman/fail-test - version: 13f91f14c826314205cdbed1ec8ac8bf08e03381 + version: 95f809107225be108efcf10a3509e4ea6ceef3c4 - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 8ee79997227bf9b34611aee7946ae64735e6fd93 + version: c9c7427a2a70d2eb3bafa0ab2dc163e45f143317 subpackages: - proto - name: github.com/golang/snappy - version: d9eb7a3d35ec988b8585d4a0068e462c27d28380 + version: 553a641470496b2327abcac10b36396bd98e45c9 - name: github.com/gorilla/websocket version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13 - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/mattn/go-colorable - version: d228849504861217f796da67fae4f6e347643f15 + version: a392f450ea64cee2b268dfaacdc2502b50a22b18 - name: github.com/mattn/go-isatty - version: 30a891c33c7cde7b02a981314b4228ec99380cca + version: 57fdcb988a5c543893cc61bce354a6e24ab70022 - name: github.com/pkg/errors - version: 645ef00459ed84a119197bfb8d8205042c6df63d + version: bfd5150e4e41705ded2129ec33379de1cb90b513 - name: github.com/syndtr/goleveldb - version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65 + version: 3c5717caf1475fd25964109a0fc640bd150fce43 subpackages: - leveldb - leveldb/cache @@ -43,7 +43,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 1236e8fb6eee3a63909f4014a8e84385ead7933d + version: af792eac777de757cd496349a5f6b5313738fcbc subpackages: - client - example/dummy @@ -117,7 +117,7 @@ imports: - name: github.com/urfave/cli version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6 - name: golang.org/x/crypto - version: 7c6cc321c680f03b9ef0764448e780704f486b51 + version: 728b753d0135da6801d45a38e6f43ff55779c5c2 subpackages: - curve25519 - nacl/box @@ -128,7 +128,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: 61557ac0112b576429a0df080e1c2cef5dfbb642 + version: a6577fac2d73be281a500b310739095313165611 subpackages: - context - http2 @@ -138,16 +138,17 @@ imports: - lex/httplex - trace - name: golang.org/x/sys - version: d75a52659825e75fff6158388dddc6a5b04f9ba5 + version: 99f16d856c9836c42d24e7ab64ea72916925fa97 subpackages: - unix - name: google.golang.org/grpc - version: cbcceb2942a489498cf22b2f918536e819d33f0a + version: 0713829b980f4ddd276689a36235c5fcc82a21bf subpackages: - codes - credentials - grpclog - internal + - keepalive - metadata - naming - peer diff --git a/glide.yaml b/glide.yaml index ecf4f151b4..d607c41cb4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,22 +1,22 @@ package: github.com/tendermint/basecoin import: - package: github.com/tendermint/go-common - version: develop + version: master - package: github.com/tendermint/go-crypto - version: develop + version: master - package: github.com/tendermint/go-events - version: develop + version: master - package: github.com/tendermint/go-logger - version: develop + version: master - package: github.com/tendermint/go-rpc - version: develop + version: master - package: github.com/tendermint/go-wire - version: develop + version: master - package: github.com/tendermint/merkleeyes - version: develop + version: master - package: github.com/tendermint/tendermint - version: develop + version: master - package: github.com/tendermint/abci - version: develop + version: master - package: github.com/gorilla/websocket version: v1.1.0 diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index 833b18f86d..9c76544bc5 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -20,7 +20,7 @@ func TestCounterPlugin(t *testing.T) { eyesCli := eyescli.NewLocalClient("", 0) chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) - bcApp.SetOption("base/chainID", chainID) + bcApp.SetOption("base/chain_id", chainID) // t.Log(bcApp.Info()) // Add Counter plugin diff --git a/state/state.go b/state/state.go index 7fb6c48bac..68a7c36243 100644 --- a/state/state.go +++ b/state/state.go @@ -28,12 +28,14 @@ func NewState(store types.KVStore) *State { func (s *State) SetChainID(chainID string) { s.chainID = chainID + s.store.Set([]byte("base/chain_id"), []byte(chainID)) } func (s *State) GetChainID() string { - if s.chainID == "" { - PanicSanity("Expected to have set SetChainID") + if s.chainID != "" { + return s.chainID } + s.chainID = string(s.store.Get([]byte("base/chain_id"))) return s.chainID } diff --git a/tests/tmsp/tmsp_test.go b/tests/tmsp/tmsp_test.go index 309af1a697..eec105deda 100644 --- a/tests/tmsp/tmsp_test.go +++ b/tests/tmsp/tmsp_test.go @@ -18,7 +18,7 @@ func TestSendTx(t *testing.T) { eyesCli := eyescli.NewLocalClient("", 0) chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) - bcApp.SetOption("base/chainID", chainID) + bcApp.SetOption("base/chain_id", chainID) // t.Log(bcApp.Info()) test1PrivAcc := types.PrivAccountFromSecret("test1") @@ -64,7 +64,7 @@ func TestSequence(t *testing.T) { eyesCli := eyescli.NewLocalClient("", 0) chainID := "test_chain_id" bcApp := app.NewBasecoin(eyesCli) - bcApp.SetOption("base/chainID", chainID) + bcApp.SetOption("base/chain_id", chainID) // t.Log(bcApp.Info()) // Get the test account diff --git a/types/tx.go b/types/tx.go index 5dcec7dacc..285902db6f 100644 --- a/types/tx.go +++ b/types/tx.go @@ -152,7 +152,7 @@ func (tx *SendTx) SignBytes(chainID string) []byte { signBytes := wire.BinaryBytes(chainID) sigz := make([]crypto.Signature, len(tx.Inputs)) for i, input := range tx.Inputs { - sigz[i] = input.Signature + sigz[i] = input.Signature.Signature tx.Inputs[i].Signature.Signature = nil } signBytes = append(signBytes, wire.BinaryBytes(tx)...) diff --git a/version/version.go b/version/version.go index 0f685af284..3a114fc238 100644 --- a/version/version.go +++ b/version/version.go @@ -1,7 +1,7 @@ package version const Maj = "0" -const Min = "2" +const Min = "3" const Fix = "0" const Version = Maj + "." + Min + "." + Fix