Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cli #17

Merged
merged 5 commits into from
Jan 29, 2017
Merged

Cli #17

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 21 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ Basecoin is a sample [ABCI application](https://github.com/tendermint/abci) desi
## Contents

1. [Installation](#installation)
1. [Learn Go](#learn-go)
1. [Using the plugin system](#using-the-plugin-system)
1. [Forking the codebase](#forking-the-codebase)
1. [Using the cli](#using-the-cli)
1. [Tutorials and other reading](#tutorials-and-other-reading)

## Installation
Expand All @@ -26,15 +25,15 @@ make get_vendor_deps
make install
```

This will create the `basecoin` binary.

## Learn Go

Check out our [guide to programming in Go](/docs/go_basics.md).
This will create the `basecoin` binary in `$GOPATH/bin`.

## Using the Plugin System

Basecoin handles public-key authentication of transaction, maintaining the balance of arbitrary types of currency (BTC, ATOM, ETH, MYCOIN, ...), sending currency (one-to-one or n-to-n multisig), and providing merkle-proofs of the state. These are common factors that many people wish to have in a crypto-currency system, so instead of trying to start from scratch, you can take advantage of the basecoin plugin system.
Basecoin is designed to serve as a common base layer for developers building cryptocurrency applications.
It handles public-key authentication of transactions, maintaining the balance of arbitrary types of currency (BTC, ATOM, ETH, MYCOIN, ...),
sending currency (one-to-one or n-to-m multisig), and providing merkle-proofs of the state.
These are common factors that many people wish to have in a crypto-currency system,
so instead of trying to start from scratch, developers can extend the functionality of Basecoin using the plugin system!

The Plugin interface is defined in `types/plugin.go`:

Expand All @@ -49,28 +48,24 @@ type Plugin interface {
}
```

`RunTx` is where you can handle any special transactions directed to your application. To see a very simple implementation, look at the demo [counter plugin](./plugins/counter/counter.go). If you want to create your own currency using a plugin, you don't have to fork basecoin at all. Just make your own repo, add the implementation of your custom plugin, and then build your own main script that instatiates BaseCoin and registers your plugin.

An example is worth a 1000 words, so please take a look [at this example](https://github.com/tendermint/basecoin/blob/abci_proof/cmd/paytovote/main.go#L25-L31), in a dev branch for now. You can use the same technique in your own repo.
`RunTx` is where you can handle any special transactions directed to your application.
To see a very simple implementation, look at the demo [counter plugin](./plugins/counter/counter.go).
If you want to create your own currency using a plugin, you don't have to fork basecoin at all.
Just make your own repo, add the implementation of your custom plugin, and then build your own main script that instatiates Basecoin and registers your plugin.

There are a lot of changes on the dev branch, which should be merged in my early February, so experiment, but things will change soon....
An example is worth a 1000 words, so please take a look [at this example](https://github.com/tendermint/basecoin/blob/develop/cmd/paytovote/main.go#L25-L31).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

404 error

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed on latest develop, thanks

Note for now it is in a dev branch.
You can use the same technique in your own repo.

## Forking the Codebase
## Using the CLI

If you do want to fork basecoin, we would be happy if this was done in a public repo and any enhancements made as PRs on github. However, this is under the Apache license and you are free to keep the code private if you wish.

If you don't have much experience forking in go, there are a few tricks you want to keep in mind to avoid headaches. Basically, all imports in go are absolute from GOPATH, so if you fork a repo with more than one directory, and you put it under github.com/MYNAME/repo, all the code will start caling github.com/ORIGINAL/repo, which is very confusing. My prefered solution to this is as follows:

* Create your own fork on github, using the fork button.
* Go to the original repo checked out locally (from `go get`)
* `git remote rename origin upstream`
* `git remote add origin git@github.com:YOUR-NAME/basecoin.git`
* `git push -u origin master`
* You can now push all changes to your fork and all code compiles, all other code referencing the original repo, now references your fork.
* If you want to pull in updates from the original repo:
* `git fetch upstream`
* `git rebase upstream/master` (or whatever branch you want)
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 sendtx --to 0x4793A333846E5104C46DD9AB9A00E31821B2F301 --amount 100`
See `basecoin --help` and `basecoin [cmd] --help` for more details`.

## Tutorials and Other Reading

See our [introductory blog post](https://cosmos.network/blog/cosmos-creating-interoperable-blockchains-part-1), which explains the motivation behind Basecoin.

We are working on some tutorials that will show you how to set up the genesis block, build a plugin to add custom logic, deploy to a tendermint testnet, and connect a UI to your blockchain. They should be published during the course of February 2017, so stay tuned....
31 changes: 31 additions & 0 deletions cmd/basecoin/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"encoding/hex"
"errors"
"fmt"

"github.com/urfave/cli"

"github.com/tendermint/go-wire"
)

func cmdAccount(c *cli.Context) error {
if len(c.Args()) != 1 {
return errors.New("account command requires an argument ([address])")
}
addrHex := stripHex(c.Args()[0])

// convert destination address to bytes
addr, err := hex.DecodeString(addrHex)
if err != nil {
return errors.New("Account address is invalid hex: " + err.Error())
}

acc, err := getAcc(c.String("tendermint"), addr)
if err != nil {
return err
}
fmt.Println(string(wire.JSONBytes(acc)))
return nil
}
227 changes: 181 additions & 46 deletions cmd/basecoin/main.go
Original file line number Diff line number Diff line change
@@ -1,55 +1,190 @@
package main

import (
"flag"
"os"

"github.com/tendermint/abci/server"
"github.com/tendermint/basecoin/app"
cmn "github.com/tendermint/go-common"
eyes "github.com/tendermint/merkleeyes/client"
"github.com/urfave/cli"
)

// start flags
var (
addrFlag = cli.StringFlag{
Name: "address",
Value: "tcp://0.0.0.0:46658",
Usage: "Listen address",
}

eyesFlag = cli.StringFlag{
Name: "eyes",
Value: "local",
Usage: "MerkleEyes address, or 'local' for embedded",
}

eyesDBFlag = cli.StringFlag{
Name: "eyes-db",
Value: "merkleeyes.db",
Usage: "MerkleEyes db name for embedded",
}

// TODO: move to config file
// eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")

genesisFlag = cli.StringFlag{
Name: "genesis",
Value: "",
Usage: "Path to genesis file, if it exists",
}

inProcTMFlag = cli.BoolFlag{
Name: "in-proc",
Usage: "Run Tendermint in-process with the App",
}
)

// tx flags

var (
tmAddrFlag = cli.StringFlag{
Name: "tendermint",
Value: "tcp://localhost:46657",
Usage: "Tendermint RPC address",
}

toFlag = cli.StringFlag{
Name: "to",
Value: "",
Usage: "Destination address for the transaction",
}

amountFlag = cli.IntFlag{
Name: "amount",
Value: 0,
Usage: "Amount of coins to send in the transaction",
}

fromFlag = cli.StringFlag{
Name: "from",
Value: "priv_validator.json",
Usage: "Path to a private key to sign the transaction",
}

seqFlag = cli.IntFlag{
Name: "sequence",
Value: 0,
Usage: "Sequence number for the account",
}

coinFlag = cli.StringFlag{
Name: "coin",
Value: "blank",
Usage: "Specify a coin denomination",
}

gasFlag = cli.IntFlag{
Name: "gas",
Value: 0,
Usage: "The amount of gas for the transaction",
}

feeFlag = cli.IntFlag{
Name: "fee",
Value: 0,
Usage: "The transaction fee",
}

dataFlag = cli.StringFlag{
Name: "data",
Value: "",
Usage: "Data to send with the transaction",
}

nameFlag = cli.StringFlag{
Name: "name",
Value: "",
Usage: "Plugin to send the transaction to",
}

chainIDFlag = cli.StringFlag{
Name: "chain_id",
Value: "test_chain_id",
Usage: "ID of the chain for replay protection",
}
)

func main() {
addrPtr := flag.String("address", "tcp://0.0.0.0:46658", "Listen address")
eyesPtr := flag.String("eyes", "local", "MerkleEyes address, or 'local' for embedded")
eyesDBNamePtr := flag.String("eyes-db-name", "local.db", "MerkleEyes db name, for embedded")
eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
genFilePath := flag.String("genesis", "", "Genesis file, if any")
flag.Parse()

// Connect to MerkleEyes
var eyesCli *eyes.Client
if *eyesPtr == "local" {
eyesCli = eyes.NewLocalClient(*eyesDBNamePtr, *eyesCacheSizePtr)
} else {
var err error
eyesCli, err = eyes.NewClient(*eyesPtr)
if err != nil {
cmn.Exit("connect to MerkleEyes: " + err.Error())
}
}

// Create Basecoin app
app := app.NewBasecoin(eyesCli)

// If genesis file was specified, set key-value options
if *genFilePath != "" {
err := app.LoadGenesis(*genFilePath)
if err != nil {
cmn.Exit(cmn.Fmt("%+v", err))
}
}

// Start the listener
svr, err := server.NewServer(*addrPtr, "socket", app)
if err != nil {
cmn.Exit("create listener: " + err.Error())
}

// Wait forever
cmn.TrapSignal(func() {
// Cleanup
svr.Stop()
})
app := cli.NewApp()
app.Name = "basecoin"
app.Usage = "basecoin [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
{
Name: "start",
Usage: "Start basecoin",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdStart(c)
},
Flags: []cli.Flag{
addrFlag,
eyesFlag,
eyesDBFlag,
genesisFlag,
inProcTMFlag,
chainIDFlag,
},
},

{
Name: "sendtx",
Usage: "Broadcast a basecoin SendTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdSendTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
toFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
chainIDFlag,
seqFlag,
},
},

{
Name: "apptx",
Usage: "Broadcast a basecoin AppTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdAppTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
nameFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
dataFlag,
seqFlag,
},
},

{
Name: "account",
Usage: "Get details of an account",
ArgsUsage: "[address]",
Action: func(c *cli.Context) error {
return cmdAccount(c)
},
Flags: []cli.Flag{
tmAddrFlag,
},
},
}
app.Run(os.Args)
}
Loading