Moved basecoin into examples
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# Run your own (super) lightweight node
|
||||
|
||||
In addition to providing command-line tooling that goes cryptographic verification
|
||||
on all the data your receive from the node, we have implemented a proxy mode, that
|
||||
allows you to run a super lightweight node. It does not follow the chain on
|
||||
every block or even every header, but only as needed. But still providing the
|
||||
same security as running a full non-validator node on your local machine.
|
||||
|
||||
Basically, it runs as a proxy that exposes the same rpc interface as the full node
|
||||
and connects to a (potentially untrusted) full node. Every response is cryptographically
|
||||
verified before being passed through, returning an error if it doesn't match.
|
||||
|
||||
You can expect 2 rpc calls for every query plus <= 1 query for each validator set
|
||||
change. Going offline for a while allows you to verify multiple validator set changes
|
||||
with one call. Cuz at 1 block/sec and 1000 tx/block, it just doesn't make sense
|
||||
to run a full node just to get security
|
||||
|
||||
## Setup
|
||||
|
||||
Just initialize your client with the proper validator set as in the [README](README.md)
|
||||
|
||||
```
|
||||
$ export BCHOME=~/.lightnode
|
||||
$ basecli init --node tcp://<host>:<port> --chain-id <chain>
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
```
|
||||
$ basecli proxy --serve tcp://localhost:7890
|
||||
...
|
||||
curl localhost:7890/status
|
||||
curl localhost:7890/block\?height=20
|
||||
```
|
||||
|
||||
You can even subscribe to events over websockets and they are all verified
|
||||
before passing them though. Though if you want every block, you might as
|
||||
well run a full (nonvalidating) node.
|
||||
|
||||
## Seeds
|
||||
|
||||
Every time the validator set changes, the light node verifies if it is legal,
|
||||
and then creates a seed at that point. These "seeds" are verified checkpoints
|
||||
that we can trace any proof back to, starting with one on `init`.
|
||||
|
||||
To make sure you are based on the most recent header, you can run:
|
||||
|
||||
```
|
||||
basecli seeds update
|
||||
basecli seeds show
|
||||
```
|
||||
|
||||
## Feedback
|
||||
|
||||
This is the first release of basecli and the light-weight proxy. It is secure, but
|
||||
may not be useful for your workflow. Please try it out and open github issues
|
||||
for any enhancements or bugs you find. I am aiming to make this a very useful
|
||||
tool by tendermint 0.11, for which I need community feedback.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Basic run through of using basecli....
|
||||
|
||||
To keep things clear, let's have two shells...
|
||||
|
||||
`$` is for basecoin (server), `%` is for basecli (client)
|
||||
|
||||
## Set up your basecli with a new key
|
||||
|
||||
```
|
||||
% export BCHOME=~/.democli
|
||||
% basecli keys new demo
|
||||
% basecli keys get demo -o json
|
||||
```
|
||||
|
||||
And set up a few more keys for fun...
|
||||
|
||||
```
|
||||
% basecli keys new buddy
|
||||
% basecli keys list
|
||||
% ME=$(basecli keys get demo | awk '{print $2}')
|
||||
% YOU=$(basecli keys get buddy | awk '{print $2}')
|
||||
```
|
||||
|
||||
## Set up a clean basecoin, initialized with your account
|
||||
|
||||
```
|
||||
$ export BCHOME=~/.demoserve
|
||||
$ basecoin init $ME
|
||||
$ basecoin start
|
||||
```
|
||||
|
||||
## Connect your basecli the first time
|
||||
|
||||
```
|
||||
% basecli init --chain-id test_chain_id --node tcp://localhost:46657
|
||||
```
|
||||
|
||||
## Check your balances...
|
||||
|
||||
```
|
||||
% basecli query account $ME
|
||||
% basecli query account $YOU
|
||||
```
|
||||
|
||||
## Send the money
|
||||
|
||||
```
|
||||
% basecli tx send --name demo --amount 1000mycoin --sequence 1 --to $YOU
|
||||
-> copy hash to HASH
|
||||
% basecli query tx $HASH
|
||||
% basecli query account $YOU
|
||||
```
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
keycmd "github.com/tendermint/go-crypto/cmd"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/commands"
|
||||
"github.com/cosmos/cosmos-sdk/client/commands/auto"
|
||||
"github.com/cosmos/cosmos-sdk/client/commands/proxy"
|
||||
"github.com/cosmos/cosmos-sdk/client/commands/query"
|
||||
rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/commands/seeds"
|
||||
txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/modules/auth/commands"
|
||||
basecmd "github.com/cosmos/cosmos-sdk/modules/base/commands"
|
||||
coincmd "github.com/cosmos/cosmos-sdk/modules/coin/commands"
|
||||
feecmd "github.com/cosmos/cosmos-sdk/modules/fee/commands"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/modules/ibc/commands"
|
||||
noncecmd "github.com/cosmos/cosmos-sdk/modules/nonce/commands"
|
||||
rolecmd "github.com/cosmos/cosmos-sdk/modules/roles/commands"
|
||||
)
|
||||
|
||||
// BaseCli - main basecoin client command
|
||||
var BaseCli = &cobra.Command{
|
||||
Use: "basecli",
|
||||
Short: "Light client for Tendermint",
|
||||
Long: `Basecli is a certifying light client for the basecoin abci app.
|
||||
|
||||
It leverages the power of the tendermint consensus algorithm get full
|
||||
cryptographic proof of all queries while only syncing a fraction of the
|
||||
block headers.`,
|
||||
}
|
||||
|
||||
func main() {
|
||||
commands.AddBasicFlags(BaseCli)
|
||||
|
||||
// Prepare queries
|
||||
query.RootCmd.AddCommand(
|
||||
// These are default parsers, but optional in your app (you can remove key)
|
||||
query.TxQueryCmd,
|
||||
query.KeyQueryCmd,
|
||||
coincmd.AccountQueryCmd,
|
||||
noncecmd.NonceQueryCmd,
|
||||
rolecmd.RoleQueryCmd,
|
||||
ibccmd.IBCQueryCmd,
|
||||
)
|
||||
|
||||
// set up the middleware
|
||||
txcmd.Middleware = txcmd.Wrappers{
|
||||
feecmd.FeeWrapper{},
|
||||
rolecmd.RoleWrapper{},
|
||||
noncecmd.NonceWrapper{},
|
||||
basecmd.ChainWrapper{},
|
||||
authcmd.SigWrapper{},
|
||||
}
|
||||
txcmd.Middleware.Register(txcmd.RootCmd.PersistentFlags())
|
||||
|
||||
// you will always want this for the base send command
|
||||
txcmd.RootCmd.AddCommand(
|
||||
// This is the default transaction, optional in your app
|
||||
coincmd.SendTxCmd,
|
||||
coincmd.CreditTxCmd,
|
||||
// this enables creating roles
|
||||
rolecmd.CreateRoleTxCmd,
|
||||
// these are for handling ibc
|
||||
ibccmd.RegisterChainTxCmd,
|
||||
ibccmd.UpdateChainTxCmd,
|
||||
ibccmd.PostPacketTxCmd,
|
||||
)
|
||||
|
||||
// Set up the various commands to use
|
||||
BaseCli.AddCommand(
|
||||
commands.InitCmd,
|
||||
commands.ResetCmd,
|
||||
keycmd.RootCmd,
|
||||
seeds.RootCmd,
|
||||
rpccmd.RootCmd,
|
||||
query.RootCmd,
|
||||
txcmd.RootCmd,
|
||||
proxy.RootCmd,
|
||||
commands.VersionCmd,
|
||||
auto.AutoCompleteCmd,
|
||||
)
|
||||
|
||||
cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli"))
|
||||
cmd.Execute()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package commands
|
||||
|
||||
// import "github.com/cosmos/cosmos-sdk/plugins/ibc"
|
||||
|
||||
// // returns a new IBC plugin to be registered with Basecoin
|
||||
// func NewIBCPlugin() *ibc.IBCPlugin {
|
||||
// return ibc.New()
|
||||
// }
|
||||
@@ -0,0 +1,147 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
// InitCmd - node initialization command
|
||||
var InitCmd = &cobra.Command{
|
||||
Use: "init [address]",
|
||||
Short: "Initialize a basecoin blockchain",
|
||||
RunE: initCmd,
|
||||
}
|
||||
|
||||
//nolint - flags
|
||||
var (
|
||||
FlagChainID = "chain-id" //TODO group with other flags or remove? is this already a flag here?
|
||||
)
|
||||
|
||||
func init() {
|
||||
InitCmd.Flags().String(FlagChainID, "test_chain_id", "Chain ID")
|
||||
}
|
||||
|
||||
// returns 1 iff it set a file, otherwise 0 (so we can add them)
|
||||
func setupFile(path, data string, perm os.FileMode) (int, error) {
|
||||
_, err := os.Stat(path)
|
||||
if !os.IsNotExist(err) { //note, os.IsExist(err) != !os.IsNotExist(err)
|
||||
return 0, nil
|
||||
}
|
||||
err = ioutil.WriteFile(path, []byte(data), perm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func initCmd(cmd *cobra.Command, args []string) error {
|
||||
// this will ensure that config.toml is there if not yet created, and create dir
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) != 1 {
|
||||
return fmt.Errorf("`init` takes one argument, a basecoin account address. Generate one using `basecli keys new mykey`")
|
||||
}
|
||||
userAddr := args[0]
|
||||
// verify this account is correct
|
||||
data, err := hex.DecodeString(cmn.StripHex(userAddr))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Invalid address")
|
||||
}
|
||||
if len(data) != 20 {
|
||||
return errors.New("Address must be 20-bytes in hex")
|
||||
}
|
||||
|
||||
genesis := GetGenesisJSON(viper.GetString(FlagChainID), userAddr)
|
||||
return CreateGenesisValidatorFiles(cfg, genesis, cmd.Root().Name())
|
||||
}
|
||||
|
||||
// CreateGenesisValidatorFiles creates a genesis file with these
|
||||
// contents and a private validator file
|
||||
func CreateGenesisValidatorFiles(cfg *config.Config, genesis, appName string) error {
|
||||
genesisFile := cfg.GenesisFile()
|
||||
privValFile := cfg.PrivValidatorFile()
|
||||
|
||||
mod1, err := setupFile(genesisFile, genesis, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod2, err := setupFile(privValFile, PrivValJSON, 0400)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if (mod1 + mod2) > 0 {
|
||||
msg := fmt.Sprintf("Initialized %s", appName)
|
||||
logger.Info(msg, "genesis", genesisFile, "priv_validator", privValFile)
|
||||
} else {
|
||||
logger.Info("Already initialized", "priv_validator", privValFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrivValJSON - validator private key file contents in json
|
||||
var PrivValJSON = `{
|
||||
"address": "7A956FADD20D3A5B2375042B2959F8AB172A058F",
|
||||
"last_height": 0,
|
||||
"last_round": 0,
|
||||
"last_signature": null,
|
||||
"last_signbytes": "",
|
||||
"last_step": 0,
|
||||
"priv_key": {
|
||||
"type": "ed25519",
|
||||
"data": "D07ABE82A8B15559A983B2DB5D4842B2B6E4D6AF58B080005662F424F17D68C17B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30"
|
||||
},
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30"
|
||||
}
|
||||
}`
|
||||
|
||||
// GetGenesisJSON returns a new tendermint genesis with Basecoin app_options
|
||||
// that grant a large amount of "mycoin" to a single address
|
||||
// TODO: A better UX for generating genesis files
|
||||
func GetGenesisJSON(chainID, addr string) string {
|
||||
return fmt.Sprintf(`{
|
||||
"app_hash": "",
|
||||
"chain_id": "%s",
|
||||
"genesis_time": "0001-01-01T00:00:00.000Z",
|
||||
"validators": [
|
||||
{
|
||||
"amount": 10,
|
||||
"name": "",
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30"
|
||||
}
|
||||
}
|
||||
],
|
||||
"app_options": {
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}],
|
||||
"plugin_options": [
|
||||
"coin/issuer", {"app": "sigs", "addr": "%s"}
|
||||
]
|
||||
}
|
||||
}`, chainID, addr, addr)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
)
|
||||
|
||||
//---------------------------------------------
|
||||
// simple implementation of a key
|
||||
|
||||
// Address - public address for a key
|
||||
type Address [20]byte
|
||||
|
||||
// MarshalJSON - marshal the json bytes of the address
|
||||
func (a Address) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf(`"%x"`, a[:])), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON - unmarshal the json bytes of the address
|
||||
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
|
||||
}
|
||||
|
||||
// Key - full private key
|
||||
type Key struct {
|
||||
Address Address `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
PrivKey crypto.PrivKey `json:"priv_key"`
|
||||
}
|
||||
|
||||
// Sign - Implements Signer
|
||||
func (k *Key) Sign(msg []byte) crypto.Signature {
|
||||
return k.PrivKey.Sign(msg)
|
||||
}
|
||||
|
||||
// LoadKey - load key from json file
|
||||
func LoadKey(keyFile string) (*Key, error) {
|
||||
filePath := keyFile
|
||||
|
||||
if !strings.HasPrefix(keyFile, "/") && !strings.HasPrefix(keyFile, ".") {
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
filePath = path.Join(rootDir, keyFile)
|
||||
}
|
||||
|
||||
keyJSONBytes, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := new(Key)
|
||||
err = json.Unmarshal(keyJSONBytes, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading key from %v: %v", filePath, err) //never stack trace
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package commands
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
// "strconv"
|
||||
// "time"
|
||||
|
||||
// "github.com/pkg/errors"
|
||||
// "github.com/spf13/cobra"
|
||||
|
||||
// // "github.com/spf13/viper"
|
||||
// // "github.com/tendermint/tmlibs/cli"
|
||||
// // "github.com/tendermint/tmlibs/log"
|
||||
|
||||
// "github.com/tendermint/go-wire"
|
||||
// "github.com/tendermint/merkleeyes/iavl"
|
||||
// cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
// "github.com/cosmos/cosmos-sdk/plugins/ibc"
|
||||
// "github.com/cosmos/cosmos-sdk/types"
|
||||
// "github.com/tendermint/tendermint/rpc/client"
|
||||
// tmtypes "github.com/tendermint/tendermint/types"
|
||||
// )
|
||||
|
||||
// var RelayCmd = &cobra.Command{
|
||||
// Use: "relay",
|
||||
// Short: "Relay ibc packets between two chains",
|
||||
// }
|
||||
|
||||
// var RelayStartCmd = &cobra.Command{
|
||||
// Use: "start",
|
||||
// Short: "Start basecoin relayer to relay IBC packets between chains",
|
||||
// RunE: relayStartCmd,
|
||||
// }
|
||||
|
||||
// var RelayInitCmd = &cobra.Command{
|
||||
// Use: "init",
|
||||
// Short: "Register both chains with each other, to prepare the relayer to run",
|
||||
// RunE: relayInitCmd,
|
||||
// }
|
||||
|
||||
// //flags
|
||||
// var (
|
||||
// chain1AddrFlag string
|
||||
// chain2AddrFlag string
|
||||
|
||||
// chain1IDFlag string
|
||||
// chain2IDFlag string
|
||||
|
||||
// fromFileFlag string
|
||||
|
||||
// genesisFile1Flag string
|
||||
// genesisFile2Flag string
|
||||
// )
|
||||
|
||||
// func init() {
|
||||
// flags := []Flag2Register{
|
||||
// {&chain1AddrFlag, "chain1-addr", "tcp://localhost:46657", "Node address for chain1"},
|
||||
// {&chain2AddrFlag, "chain2-addr", "tcp://localhost:36657", "Node address for chain2"},
|
||||
// {&chain1IDFlag, "chain1-id", "test_chain_1", "ChainID for chain1"},
|
||||
// {&chain2IDFlag, "chain2-id", "test_chain_2", "ChainID for chain2"},
|
||||
// {&fromFileFlag, "from", "key.json", "Path to a private key to sign the transaction"},
|
||||
// }
|
||||
// RegisterPersistentFlags(RelayCmd, flags)
|
||||
|
||||
// initFlags := []Flag2Register{
|
||||
// {&genesisFile1Flag, "genesis1", "", "Path to genesis file for chain1"},
|
||||
// {&genesisFile2Flag, "genesis2", "", "Path to genesis file for chain2"},
|
||||
// }
|
||||
// RegisterFlags(RelayInitCmd, initFlags)
|
||||
|
||||
// RelayCmd.AddCommand(RelayStartCmd)
|
||||
// RelayCmd.AddCommand(RelayInitCmd)
|
||||
// }
|
||||
|
||||
// func relayStartCmd(cmd *cobra.Command, args []string) error {
|
||||
// go loop(chain1AddrFlag, chain2AddrFlag, chain1IDFlag, chain2IDFlag)
|
||||
// go loop(chain2AddrFlag, chain1AddrFlag, chain2IDFlag, chain1IDFlag)
|
||||
|
||||
// cmn.TrapSignal(func() {
|
||||
// // TODO: Cleanup
|
||||
// })
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func relayInitCmd(cmd *cobra.Command, args []string) error {
|
||||
// err := registerChain(chain1IDFlag, chain1AddrFlag, chain2IDFlag, genesisFile2Flag, fromFileFlag)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = registerChain(chain2IDFlag, chain2AddrFlag, chain1IDFlag, genesisFile1Flag, fromFileFlag)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// func registerChain(chainID, node, registerChainID, registerGenesis, keyFile string) error {
|
||||
// genesisBytes, err := ioutil.ReadFile(registerGenesis)
|
||||
// if err != nil {
|
||||
// return errors.Errorf("Error reading genesis file %v: %v\n", registerGenesis, err)
|
||||
// }
|
||||
|
||||
// ibcTx := ibc.IBCRegisterChainTx{
|
||||
// ibc.BlockchainGenesis{
|
||||
// ChainID: registerChainID,
|
||||
// Genesis: string(genesisBytes),
|
||||
// },
|
||||
// }
|
||||
|
||||
// privKey, err := LoadKey(keyFile)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// relay := newRelayer(privKey, chainID, node)
|
||||
// return relay.appTx(ibcTx)
|
||||
// }
|
||||
|
||||
// func loop(addr1, addr2, id1, id2 string) {
|
||||
// nextSeq := 0
|
||||
|
||||
// // load the priv key
|
||||
// privKey, err := LoadKey(fromFileFlag)
|
||||
// if err != nil {
|
||||
// logger.Error(err.Error())
|
||||
// cmn.PanicCrisis(err.Error())
|
||||
// }
|
||||
|
||||
// // relay from chain1 to chain2
|
||||
// thisRelayer := newRelayer(privKey, id2, addr2)
|
||||
|
||||
// logger.Info(fmt.Sprintf("Relaying from chain %v on %v to chain %v on %v", id1, addr1, id2, addr2))
|
||||
|
||||
// httpClient := client.NewHTTP(addr1, "/websocket")
|
||||
|
||||
// OUTER:
|
||||
// for {
|
||||
|
||||
// time.Sleep(time.Second)
|
||||
|
||||
// // get the latest ibc packet sequence number
|
||||
// key := fmt.Sprintf("ibc,egress,%v,%v", id1, id2)
|
||||
// query, err := queryWithClient(httpClient, []byte(key))
|
||||
// if err != nil {
|
||||
// logger.Error("Error querying for latest sequence", "key", key, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
// if len(query.Value) == 0 {
|
||||
// // nothing yet
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// seq, err := strconv.ParseUint(string(query.Value), 10, 64)
|
||||
// if err != nil {
|
||||
// logger.Error("Error parsing sequence number from query", "query.Value", query.Value, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
// seq -= 1 // seq is the packet count. -1 because 0-indexed
|
||||
|
||||
// if nextSeq <= int(seq) {
|
||||
// logger.Info("Got new packets", "last-sequence", nextSeq-1, "new-sequence", seq)
|
||||
// }
|
||||
|
||||
// // get all packets since the last one we relayed
|
||||
// for ; nextSeq <= int(seq); nextSeq++ {
|
||||
// key := fmt.Sprintf("ibc,egress,%v,%v,%d", id1, id2, nextSeq)
|
||||
// query, err := queryWithClient(httpClient, []byte(key))
|
||||
// if err != nil {
|
||||
// logger.Error("Error querying for packet", "seqeuence", nextSeq, "key", key, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// var packet ibc.Packet
|
||||
// err = wire.ReadBinaryBytes(query.Value, &packet)
|
||||
// if err != nil {
|
||||
// logger.Error("Error unmarshalling packet", "key", key, "query.Value", query.Value, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// proof := new(iavl.IAVLProof)
|
||||
// err = wire.ReadBinaryBytes(query.Proof, &proof)
|
||||
// if err != nil {
|
||||
// logger.Error("Error unmarshalling proof", "query.Proof", query.Proof, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// // query.Height is actually for the next block,
|
||||
// // so wait a block before we fetch the header & commit
|
||||
// if err := waitForBlock(httpClient); err != nil {
|
||||
// logger.Error("Error waiting for a block", "addr", addr1, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// // get the header and commit from the height the query was done at
|
||||
// res, err := httpClient.Commit(int(query.Height))
|
||||
// if err != nil {
|
||||
// logger.Error("Error fetching header and commits", "height", query.Height, "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// // update the chain state on the other chain
|
||||
// updateTx := ibc.IBCUpdateChainTx{
|
||||
// Header: *res.Header,
|
||||
// Commit: *res.Commit,
|
||||
// }
|
||||
// logger.Info("Updating chain", "src-chain", id1, "height", res.Header.Height, "appHash", res.Header.AppHash)
|
||||
// if err := thisRelayer.appTx(updateTx); err != nil {
|
||||
// logger.Error("Error creating/sending IBCUpdateChainTx", "error", err.Error())
|
||||
// continue OUTER
|
||||
// }
|
||||
|
||||
// // relay the packet and proof
|
||||
// logger.Info("Relaying packet", "src-chain", id1, "height", query.Height, "sequence", nextSeq)
|
||||
// postTx := ibc.IBCPacketPostTx{
|
||||
// FromChainID: id1,
|
||||
// FromChainHeight: query.Height,
|
||||
// Packet: packet,
|
||||
// Proof: proof,
|
||||
// }
|
||||
|
||||
// if err := thisRelayer.appTx(postTx); err != nil {
|
||||
// logger.Error("Error creating/sending IBCPacketPostTx", "error", err.Error())
|
||||
// // dont `continue OUTER` here. the error might be eg. Already exists
|
||||
// // TODO: catch this programmatically ?
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// type relayer struct {
|
||||
// privKey *Key
|
||||
// chainID string
|
||||
// nodeAddr string
|
||||
// client *client.HTTP
|
||||
// }
|
||||
|
||||
// func newRelayer(privKey *Key, chainID, nodeAddr string) *relayer {
|
||||
// httpClient := client.NewHTTP(nodeAddr, "/websocket")
|
||||
// return &relayer{
|
||||
// privKey: privKey,
|
||||
// chainID: chainID,
|
||||
// nodeAddr: nodeAddr,
|
||||
// client: httpClient,
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (r *relayer) appTx(ibcTx ibc.IBCTx) error {
|
||||
// acc, err := getAccWithClient(r.client, r.privKey.Address[:])
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// sequence := acc.Sequence + 1
|
||||
|
||||
// data := []byte(wire.BinaryBytes(struct {
|
||||
// ibc.IBCTx `json:"unwrap"`
|
||||
// }{ibcTx}))
|
||||
|
||||
// smallCoins := coin.Coin{"mycoin", 1}
|
||||
|
||||
// input := types.NewTxInput(r.privKey.PubKey, coin.Coins{smallCoins}, sequence)
|
||||
// tx := &types.AppTx{
|
||||
// Gas: 0,
|
||||
// Fee: smallCoins,
|
||||
// Name: "IBC",
|
||||
// Input: input,
|
||||
// Data: data,
|
||||
// }
|
||||
|
||||
// tx.Input.Signature = r.privKey.Sign(tx.SignBytes(r.chainID))
|
||||
// txBytes := []byte(wire.BinaryBytes(struct {
|
||||
// types.Tx `json:"unwrap"`
|
||||
// }{tx}))
|
||||
|
||||
// data, log, err := broadcastTxWithClient(r.client, txBytes)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// _, _ = data, log
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // broadcast the transaction to tendermint
|
||||
// func broadcastTxWithClient(httpClient *client.HTTP, tx tmtypes.Tx) ([]byte, string, error) {
|
||||
// res, err := httpClient.BroadcastTxCommit(tx)
|
||||
// if err != nil {
|
||||
// return nil, "", errors.Errorf("Error on broadcast tx: %v", err)
|
||||
// }
|
||||
|
||||
// if !res.CheckTx.Code.IsOK() {
|
||||
// r := res.CheckTx
|
||||
// return nil, "", errors.Errorf("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)
|
||||
// }
|
||||
|
||||
// if !res.DeliverTx.Code.IsOK() {
|
||||
// r := res.DeliverTx
|
||||
// return nil, "", errors.Errorf("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log)
|
||||
// }
|
||||
|
||||
// return res.DeliverTx.Data, res.DeliverTx.Log, nil
|
||||
// }
|
||||
@@ -0,0 +1,23 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
)
|
||||
|
||||
// UnsafeResetAllCmd - extension of the tendermint command, resets initialization
|
||||
var UnsafeResetAllCmd = &cobra.Command{
|
||||
Use: "unsafe_reset_all",
|
||||
Short: "Reset all blockchain data",
|
||||
RunE: unsafeResetAllCmd,
|
||||
}
|
||||
|
||||
func unsafeResetAllCmd(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), logger)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
tmflags "github.com/tendermint/tmlibs/cli/flags"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
//nolint
|
||||
const (
|
||||
defaultLogLevel = "error"
|
||||
FlagLogLevel = "log_level"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "main")
|
||||
)
|
||||
|
||||
// RootCmd - main node command
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: "basecoin",
|
||||
Short: "A cryptocurrency framework in Golang based on Tendermint-Core",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
level := viper.GetString(FlagLogLevel)
|
||||
logger, err = tmflags.ParseLogLevel(level, logger, defaultLogLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if viper.GetBool(cli.TraceFlag) {
|
||||
logger = log.NewTracingLogger(logger)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.PersistentFlags().String(FlagLogLevel, defaultLogLevel, "Log level")
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/abci/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/node"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/app"
|
||||
)
|
||||
|
||||
// StartCmd - command to start running the basecoin node!
|
||||
var StartCmd = &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Start basecoin",
|
||||
RunE: startCmd,
|
||||
}
|
||||
|
||||
// nolint TODO: move to config file
|
||||
const EyesCacheSize = 10000
|
||||
|
||||
//nolint
|
||||
const (
|
||||
FlagAddress = "address"
|
||||
FlagWithoutTendermint = "without-tendermint"
|
||||
)
|
||||
|
||||
var (
|
||||
// Handler - use a global to store the handler, so we can set it in main.
|
||||
// TODO: figure out a cleaner way to register plugins
|
||||
Handler sdk.Handler
|
||||
)
|
||||
|
||||
func init() {
|
||||
flags := StartCmd.Flags()
|
||||
flags.String(FlagAddress, "tcp://0.0.0.0:46658", "Listen address")
|
||||
flags.Bool(FlagWithoutTendermint, false, "Only run basecoin abci app, assume external tendermint process")
|
||||
// add all standard 'tendermint node' flags
|
||||
tcmd.AddNodeFlags(StartCmd)
|
||||
}
|
||||
|
||||
func startCmd(cmd *cobra.Command, args []string) error {
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
|
||||
store, err := app.NewStore(
|
||||
path.Join(rootDir, "data", "merkleeyes.db"),
|
||||
EyesCacheSize,
|
||||
logger.With("module", "store"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create Basecoin app
|
||||
basecoinApp := app.NewBasecoin(Handler, store, logger.With("module", "app"))
|
||||
|
||||
// if chain_id has not been set yet, load the genesis.
|
||||
// else, assume it's been loaded
|
||||
if basecoinApp.GetChainID() == "" {
|
||||
// If genesis file exists, set key-value options
|
||||
genesisFile := path.Join(rootDir, "genesis.json")
|
||||
if _, err := os.Stat(genesisFile); err == nil {
|
||||
err := basecoinApp.LoadGenesis(genesisFile)
|
||||
if err != nil {
|
||||
return errors.Errorf("Error in LoadGenesis: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("No genesis file at %s, skipping...\n", genesisFile)
|
||||
}
|
||||
}
|
||||
|
||||
chainID := basecoinApp.GetChainID()
|
||||
if viper.GetBool(FlagWithoutTendermint) {
|
||||
logger.Info("Starting Basecoin without Tendermint", "chain_id", chainID)
|
||||
// run just the abci app/server
|
||||
return startBasecoinABCI(basecoinApp)
|
||||
}
|
||||
logger.Info("Starting Basecoin with Tendermint", "chain_id", chainID)
|
||||
// start the app with tendermint in-process
|
||||
return startTendermint(rootDir, basecoinApp)
|
||||
}
|
||||
|
||||
func startBasecoinABCI(basecoinApp *app.Basecoin) error {
|
||||
// Start the ABCI listener
|
||||
addr := viper.GetString(FlagAddress)
|
||||
svr, err := server.NewServer(addr, "socket", basecoinApp)
|
||||
if err != nil {
|
||||
return errors.Errorf("Error creating listener: %v\n", err)
|
||||
}
|
||||
svr.SetLogger(logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
// Wait forever
|
||||
cmn.TrapSignal(func() {
|
||||
// Cleanup
|
||||
svr.Stop()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func startTendermint(dir string, basecoinApp *app.Basecoin) error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create & start tendermint node
|
||||
privValidator := types.LoadOrGenPrivValidator(cfg.PrivValidatorFile(), logger)
|
||||
n := node.NewNode(cfg, privValidator, proxy.NewLocalClientCreator(basecoinApp), logger.With("module", "node"))
|
||||
|
||||
_, err = n.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Trap signal, run forever.
|
||||
n.RunForever()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk"
|
||||
client "github.com/cosmos/cosmos-sdk/client/commands"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/cmd/basecoin/commands"
|
||||
"github.com/cosmos/cosmos-sdk/modules/auth"
|
||||
"github.com/cosmos/cosmos-sdk/modules/base"
|
||||
"github.com/cosmos/cosmos-sdk/modules/coin"
|
||||
"github.com/cosmos/cosmos-sdk/modules/fee"
|
||||
"github.com/cosmos/cosmos-sdk/modules/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/modules/nonce"
|
||||
"github.com/cosmos/cosmos-sdk/modules/roles"
|
||||
"github.com/cosmos/cosmos-sdk/stack"
|
||||
)
|
||||
|
||||
// BuildApp constructs the stack we want to use for this app
|
||||
func BuildApp(feeDenom string) sdk.Handler {
|
||||
return stack.New(
|
||||
base.Logger{},
|
||||
stack.Recovery{},
|
||||
auth.Signatures{},
|
||||
base.Chain{},
|
||||
stack.Checkpoint{OnCheck: true},
|
||||
nonce.ReplayCheck{},
|
||||
).
|
||||
IBC(ibc.NewMiddleware()).
|
||||
Apps(
|
||||
roles.NewMiddleware(),
|
||||
fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank),
|
||||
stack.Checkpoint{OnDeliver: true},
|
||||
).
|
||||
Dispatch(
|
||||
coin.NewHandler(),
|
||||
stack.WrapHandler(roles.NewHandler()),
|
||||
stack.WrapHandler(ibc.NewHandler()),
|
||||
)
|
||||
}
|
||||
|
||||
func main() {
|
||||
rt := commands.RootCmd
|
||||
|
||||
// require all fees in mycoin - change this in your app!
|
||||
commands.Handler = BuildApp("mycoin")
|
||||
|
||||
rt.AddCommand(
|
||||
commands.InitCmd,
|
||||
commands.StartCmd,
|
||||
//commands.RelayCmd,
|
||||
commands.UnsafeResetAllCmd,
|
||||
client.VersionCmd,
|
||||
)
|
||||
|
||||
cmd := cli.PrepareMainCmd(rt, "BC", os.ExpandEnv("$HOME/.basecoin"))
|
||||
cmd.Execute()
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
# baseserver
|
||||
|
||||
baseserver is the REST counterpart to basecli
|
||||
|
||||
## Compiling and running it
|
||||
```shell
|
||||
$ go get -u -v github.com/tendermint/basecoin/cmd/baseserver
|
||||
$ baseserver init
|
||||
$ baseserver serve --port 8888
|
||||
```
|
||||
|
||||
to run the server at localhost:8888, otherwise if you don't specify --port,
|
||||
by default the server will be run on port 8998.
|
||||
|
||||
## Supported routes
|
||||
Route | Method | Completed | Description
|
||||
---|---|---|---
|
||||
/keys|GET|✔️|Lists all keys
|
||||
/keys|POST|✔️|Generate a new key. It expects fields: "name", "algo", "passphrase"
|
||||
/keys/{name}|GET|✔️|Retrieves the specific key
|
||||
/keys/{name}|POST/PUT|✔️|Updates the named key
|
||||
/keys/{name}|DELETE|✔️|Deletes the named key
|
||||
/build/send|POST|✔️|Send a transaction
|
||||
/sign|POST|✔️|Sign a transaction
|
||||
/tx|POST|✖️|Post a transaction to the blockchain
|
||||
/seeds/status|GET|✖️|Returns the information on the last seed
|
||||
/build/create_role|POST|✔️|Creates a role. Please note that the role MUST be valid hex for example instead of sending "role", send its hex encoded equivalent "726f6c65"
|
||||
|
||||
## Preamble:
|
||||
In the examples below, we assume that URL is set to `http://localhost:8889`
|
||||
which can be set for example
|
||||
URL=http://localhost:8889
|
||||
|
||||
## Sample usage
|
||||
- Generate a key
|
||||
```shell
|
||||
$ curl -X POST $URL/keys --data '{"algo": "ed25519", "name": "SampleX", "passphrase": "Say no more"}'
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"key": {
|
||||
"name": "SampleX",
|
||||
"address": "603EE63C41E322FC7A247864A9CD0181282EB458",
|
||||
"pubkey": {
|
||||
"type": "ed25519",
|
||||
"data": "C050948CFC087F5E1068C7E244DDC30E03702621CC9442A28E6C9EDA7771AA0C"
|
||||
}
|
||||
},
|
||||
"seed_phrase": "border almost future parade speak soccer bulk orange real brisk caution body river chapter"
|
||||
}
|
||||
```
|
||||
|
||||
- Sign a key
|
||||
```shell
|
||||
$ curl -X POST $URL/sign --data '{
|
||||
"name": "matt",
|
||||
"password": "Say no more",
|
||||
"tx": {
|
||||
"type": "sigs/multi",
|
||||
"data": {
|
||||
"tx": {"type":"coin/send","data":{"inputs":[{"address":{"chain":"","app":"role","addr":"62616E6B32"},"coins":[{"denom":"mycoin","amount":900000}]}],"outputs":[{"address":{"chain":"","app":"sigs","addr":"BDADF167E6CF2CDF2D621E590FF1FED2787A40E0"},"coins":[{"denom":"mycoin","amount":900000}]}]}},
|
||||
"signatures": null
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "sigs/multi",
|
||||
"data": {
|
||||
"tx": {
|
||||
"type": "coin/send",
|
||||
"data": {
|
||||
"inputs": [
|
||||
{
|
||||
"address": {
|
||||
"chain": "",
|
||||
"app": "role",
|
||||
"addr": "62616E6B32"
|
||||
},
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 900000
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"address": {
|
||||
"chain": "",
|
||||
"app": "sigs",
|
||||
"addr": "BDADF167E6CF2CDF2D621E590FF1FED2787A40E0"
|
||||
},
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 900000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"signatures": [
|
||||
{
|
||||
"Sig": {
|
||||
"type": "ed25519",
|
||||
"data": "F6FE3053F1E6C236F886A0D525C1AF840F7831B6E50F7E1108C345AA524303920F09945DA110AD5184B3F45717D7114E368B12AFE027FECECC2FC193D4906A0C"
|
||||
},
|
||||
"Pubkey": {
|
||||
"type": "ed25519",
|
||||
"data": "0D8D19E527BAE9D1256A3D03009E2708171CDCB71CCDEDA2DC52DD9AD23AEE25"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Create a role
|
||||
```shell
|
||||
$ curl -X POST $URL/build/create_role --data \
|
||||
'{
|
||||
"role": "deadbeef",
|
||||
"signers": [{
|
||||
"addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9",
|
||||
"app": "role"
|
||||
}],
|
||||
"min_sigs": 1,
|
||||
"seq": 1
|
||||
}'
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "chain/tx",
|
||||
"data": {
|
||||
"chain_id": "test_chain_id",
|
||||
"expires_at": 0,
|
||||
"tx": {
|
||||
"type": "role/create",
|
||||
"data": {
|
||||
"role": "DEADBEEF",
|
||||
"min_sigs": 1,
|
||||
"signers": [
|
||||
{
|
||||
"chain": "",
|
||||
"app": "role",
|
||||
"addr": "4FF759D47C81754D8F553DCCAC8651D0AF74C7F9"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/commands"
|
||||
rest "github.com/cosmos/cosmos-sdk/client/rest"
|
||||
coinrest "github.com/cosmos/cosmos-sdk/modules/coin/rest"
|
||||
noncerest "github.com/cosmos/cosmos-sdk/modules/nonce/rest"
|
||||
rolerest "github.com/cosmos/cosmos-sdk/modules/roles/rest"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
)
|
||||
|
||||
var srvCli = &cobra.Command{
|
||||
Use: "baseserver",
|
||||
Short: "Light REST client for tendermint",
|
||||
Long: `Baseserver presents a nice (not raw hex) interface to the basecoin blockchain structure.`,
|
||||
}
|
||||
|
||||
var serveCmd = &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Serve the light REST client for tendermint",
|
||||
Long: "Access basecoin via REST",
|
||||
RunE: serve,
|
||||
}
|
||||
|
||||
const (
|
||||
envPortFlag = "port"
|
||||
defaultAlgo = "ed25519"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = serveCmd.PersistentFlags().Int(envPortFlag, 8998, "the port to run the server on")
|
||||
}
|
||||
|
||||
func serve(cmd *cobra.Command, args []string) error {
|
||||
router := mux.NewRouter()
|
||||
|
||||
routeRegistrars := []func(*mux.Router) error{
|
||||
// rest.Keys handlers
|
||||
rest.NewDefaultKeysManager(defaultAlgo).RegisterAllCRUD,
|
||||
|
||||
// Coin send handler
|
||||
coinrest.RegisterCoinSend,
|
||||
// Coin query account handler
|
||||
coinrest.RegisterQueryAccount,
|
||||
|
||||
// Roles createRole handler
|
||||
rolerest.RegisterCreateRole,
|
||||
|
||||
// Basecoin sign transactions handler
|
||||
rest.RegisterSignTx,
|
||||
// Basecoin post transaction handler
|
||||
rest.RegisterPostTx,
|
||||
|
||||
// Nonce query handler
|
||||
noncerest.RegisterQueryNonce,
|
||||
}
|
||||
|
||||
for _, routeRegistrar := range routeRegistrars {
|
||||
if err := routeRegistrar(router); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
port := viper.GetInt(envPortFlag)
|
||||
addr := fmt.Sprintf(":%d", port)
|
||||
|
||||
log.Printf("Serving on %q", addr)
|
||||
return http.ListenAndServe(addr, router)
|
||||
}
|
||||
|
||||
func main() {
|
||||
commands.AddBasicFlags(srvCli)
|
||||
|
||||
srvCli.AddCommand(
|
||||
commands.InitCmd,
|
||||
commands.VersionCmd,
|
||||
serveCmd,
|
||||
)
|
||||
|
||||
// this should share the dir with basecli, so you can use the cli and
|
||||
// the api interchangeably
|
||||
cmd := cli.PrepareMainCmd(srvCli, "BC", os.ExpandEnv("$HOME/.basecli"))
|
||||
if err := cmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user