Merge branch 'develop' into sunny/IAVLsubspace
This commit is contained in:
commit
348e28a4b5
|
@ -1,23 +1,23 @@
|
|||
# OS
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
.vscode
|
||||
|
||||
# Build
|
||||
vendor
|
||||
merkleeyes.db
|
||||
build
|
||||
docs/guide/*.sh
|
||||
tools/bin/*
|
||||
examples/build/*
|
||||
examples/basecoin/glide.lock
|
||||
docs/_build
|
||||
|
||||
# Data - ideally these don't exist
|
||||
examples/basecoin/app/data
|
||||
baseapp/data/*
|
||||
docs/_build
|
||||
.DS_Store
|
||||
|
||||
# Testing
|
||||
coverage.txt
|
||||
profile.out
|
||||
.vscode
|
||||
coverage.txt
|
||||
profile.out
|
||||
client/lcd/keys.db/
|
||||
|
||||
### Vagrant ###
|
||||
.vagrant/
|
||||
|
|
51
CHANGELOG.md
51
CHANGELOG.md
|
@ -1,5 +1,44 @@
|
|||
# Changelog
|
||||
|
||||
## 0.13.1 (April 3, 2018)
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* [x/ibc] Fix CLI and relay for IBC txs
|
||||
* [x/stake] Various fixes/improvements
|
||||
|
||||
## 0.13.0 (April 2, 2018)
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
* [basecoin] Remove cool/sketchy modules -> moved to new `democoin`
|
||||
* [basecoin] NewBasecoinApp takes a `map[string]dbm.DB` as temporary measure
|
||||
to allow mounting multiple stores with their own DB until they can share one
|
||||
* [x/staking] Renamed to `simplestake`
|
||||
* [builder] Functions don't take `passphrase` as argument
|
||||
* [server] GenAppState returns generated seed and address
|
||||
* [basecoind] `init` command outputs JSON of everything necessary for testnet
|
||||
* [basecoind] `basecoin.db -> data/basecoin.db`
|
||||
* [basecli] `data/keys.db -> keys/keys.db`
|
||||
|
||||
FEATURES
|
||||
|
||||
* [types] `Coin` supports direct arithmetic operations
|
||||
* [basecoind] Add `show_validator` and `show_node_id` commands
|
||||
* [x/stake] Initial merge of full staking module!
|
||||
* [democoin] New example application to demo custom modules
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
* [makefile] `make install`
|
||||
* [testing] Use `/tmp` for directories so they don't get left in the repo
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* [basecoin] Allow app to be restarted
|
||||
* [makefile] Fix build on Windows
|
||||
* [basecli] Get confirmation before overriding key with same name
|
||||
|
||||
## 0.12.0 (March 27 2018)
|
||||
|
||||
BREAKING CHANGES
|
||||
|
@ -10,9 +49,9 @@ BREAKING CHANGES
|
|||
* [types] Replace tx.GetFeePayer with FeePayer(tx) - returns the first signer
|
||||
* [types] NewStdTx takes the Fee
|
||||
* [types] ParseAccount -> AccountDecoder; ErrTxParse -> ErrTxDecoder
|
||||
* [auth] AnteHandler deducts fees
|
||||
* [bank] Move some errors to `types`
|
||||
* [bank] Remove sequence and signature from Input
|
||||
* [x/auth] AnteHandler deducts fees
|
||||
* [x/bank] Move some errors to `types`
|
||||
* [x/bank] Remove sequence and signature from Input
|
||||
|
||||
FEATURES
|
||||
|
||||
|
@ -26,7 +65,7 @@ FEATURES
|
|||
* [types] StdFee, and StdTx takes the StdFee
|
||||
* [specs] Progression of MVPs for IBC
|
||||
* [x/ibc] Initial shell of IBC functionality (no proofs)
|
||||
* [x/staking] Simple staking module with bonding/unbonding
|
||||
* [x/simplestake] Simple staking module with bonding/unbonding
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
|
@ -36,8 +75,8 @@ IMPROVEMENTS
|
|||
* [specs] Staking
|
||||
|
||||
BUG FIXES
|
||||
* [auth] Fix setting pubkey on new account
|
||||
* [auth] Require signatures to include the sequences
|
||||
* [x/auth] Fix setting pubkey on new account
|
||||
* [x/auth] Require signatures to include the sequences
|
||||
* [baseapp] Dont panic on nil handler
|
||||
* [basecoin] Check for empty bytes in account and tx
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
"json/scanner",
|
||||
"json/token"
|
||||
]
|
||||
revision = "f40e974e75af4e271d97ce0fc917af5898ae7bda"
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -191,8 +191,8 @@
|
|||
".",
|
||||
"mem"
|
||||
]
|
||||
revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c"
|
||||
version = "v1.0.2"
|
||||
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cast"
|
||||
|
@ -203,8 +203,8 @@
|
|||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
|
||||
version = "v0.0.1"
|
||||
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -250,7 +250,7 @@
|
|||
"leveldb/table",
|
||||
"leveldb/util"
|
||||
]
|
||||
revision = "169b1b37be738edb2813dab48c97a549bcf99bb5"
|
||||
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/abci"
|
||||
|
@ -341,8 +341,8 @@
|
|||
"version",
|
||||
"wire"
|
||||
]
|
||||
revision = "6f9956990c444d53f62f2a3905ed410cfe9afe77"
|
||||
version = "v0.17.1"
|
||||
revision = "a1dd329d72e78d4770e602359bad5b7b1e8b72a3"
|
||||
version = "v0.18.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
|
@ -359,8 +359,8 @@
|
|||
"pubsub",
|
||||
"pubsub/query"
|
||||
]
|
||||
revision = "24da7009c3d8c019b40ba4287495749e3160caca"
|
||||
version = "v0.7.1"
|
||||
revision = "2e24b64fc121dcdf1cabceab8dc2f7257675483c"
|
||||
version = "0.8.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -376,7 +376,7 @@
|
|||
"ripemd160",
|
||||
"salsa20/salsa"
|
||||
]
|
||||
revision = "88942b9c40a4c9d203b82b3731787b672d6e809b"
|
||||
revision = "b2aa35443fbc700ab74c586ae79b81c171851023"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -390,13 +390,13 @@
|
|||
"lex/httplex",
|
||||
"trace"
|
||||
]
|
||||
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
||||
revision = "b3c676e531a6dc479fa1b35ac961c13f5e2b4d2e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
|
||||
revision = "1d206c9fa8975fb4cf00df1dc8bf3283dc24ba0e"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
|
@ -423,7 +423,7 @@
|
|||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "ab0870e398d5dd054b868c0db1481ab029b9a9f2"
|
||||
revision = "35de2414665fc36f56b72d982c5af480d86de5ab"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
|
@ -452,8 +452,8 @@
|
|||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "86f5ed62f8a0ee96bd888d2efdfd6d4fb100a4eb"
|
||||
version = "v2.2.0"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
|
|
|
@ -70,11 +70,11 @@
|
|||
name = "github.com/tendermint/iavl"
|
||||
|
||||
[[constraint]]
|
||||
version = "~0.17.1"
|
||||
version = "~0.18.0-rc1"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
|
||||
[[constraint]]
|
||||
version = "~0.7.1"
|
||||
[[override]]
|
||||
version = "~0.8.1"
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
|
||||
[prune]
|
||||
|
|
36
Makefile
36
Makefile
|
@ -2,7 +2,7 @@ PACKAGES=$(shell go list ./... | grep -v '/vendor/')
|
|||
COMMIT_HASH := $(shell git rev-parse --short HEAD)
|
||||
BUILD_FLAGS = -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}"
|
||||
|
||||
all: check_tools get_vendor_deps build test
|
||||
all: check_tools get_vendor_deps build build_examples test
|
||||
|
||||
########################################
|
||||
### CI
|
||||
|
@ -13,20 +13,38 @@ ci: get_tools get_vendor_deps build test_cover
|
|||
### Build
|
||||
|
||||
# This can be unified later, here for easy demos
|
||||
gaia:
|
||||
go build $(BUILD_FLAGS) -o build/gaiad ./examples/gaia/gaiad
|
||||
go build $(BUILD_FLAGS) -o build/gaiacli ./examples/gaia/gaiacli
|
||||
|
||||
build:
|
||||
@rm -rf $(shell pwd)/examples/basecoin/vendor/
|
||||
ifeq ($(OS),Windows_NT)
|
||||
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaiad
|
||||
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaiacli
|
||||
else
|
||||
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaiad
|
||||
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaiacli
|
||||
endif
|
||||
|
||||
build_examples:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
go build $(BUILD_FLAGS) -o build/basecoind.exe ./examples/basecoin/cmd/basecoind
|
||||
go build $(BUILD_FLAGS) -o build/basecli.exe ./examples/basecoin/cmd/basecli
|
||||
go build $(BUILD_FLAGS) -o build/democoind.exe ./examples/democoin/cmd/democoind
|
||||
go build $(BUILD_FLAGS) -o build/democli.exe ./examples/democoin/cmd/democli
|
||||
else
|
||||
go build $(BUILD_FLAGS) -o build/basecoind ./examples/basecoin/cmd/basecoind
|
||||
go build $(BUILD_FLAGS) -o build/basecli ./examples/basecoin/cmd/basecli
|
||||
go build $(BUILD_FLAGS) -o build/democoind ./examples/democoin/cmd/democoind
|
||||
go build $(BUILD_FLAGS) -o build/democli ./examples/democoin/cmd/democli
|
||||
endif
|
||||
|
||||
install:
|
||||
go install $(BUILD_FLAGS) ./cmd/gaiad
|
||||
go install $(BUILD_FLAGS) ./cmd/gaiacli
|
||||
|
||||
install_examples:
|
||||
go install $(BUILD_FLAGS) ./examples/basecoin/cmd/basecoind
|
||||
go install $(BUILD_FLAGS) ./examples/basecoin/cmd/basecli
|
||||
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democoind
|
||||
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democli
|
||||
|
||||
dist:
|
||||
@bash publish/dist.sh
|
||||
@bash publish/publish.sh
|
||||
|
@ -73,14 +91,10 @@ test: test_unit # test_cli
|
|||
# go test -coverprofile=c.out && go tool cover -html=c.out
|
||||
|
||||
test_unit:
|
||||
@rm -rf examples/basecoin/vendor/
|
||||
@go test $(PACKAGES)
|
||||
|
||||
test_cover:
|
||||
@rm -rf examples/basecoin/vendor/
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
@bash tests/test_cover.sh
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
|
||||
benchmark:
|
||||
@go test -bench=. $(PACKAGES)
|
||||
|
@ -113,4 +127,4 @@ devdoc_update:
|
|||
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||
# unless there is a reason not to.
|
||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||
.PHONY: build dist check_tools get_tools get_vendor_deps draw_deps test test_unit test_tutorial benchmark devdoc_init devdoc devdoc_save devdoc_update
|
||||
.PHONY: build build_examples install install_examples dist check_tools get_tools get_vendor_deps draw_deps test test_unit test_tutorial benchmark devdoc_init devdoc devdoc_save devdoc_update
|
||||
|
|
|
@ -55,6 +55,7 @@ type BaseApp struct {
|
|||
var _ abci.Application = (*BaseApp)(nil)
|
||||
|
||||
// Create and name new BaseApp
|
||||
// NOTE: The db is used to store the version number for now.
|
||||
func NewBaseApp(name string, logger log.Logger, db dbm.DB) *BaseApp {
|
||||
return &BaseApp{
|
||||
Logger: logger,
|
||||
|
@ -71,12 +72,18 @@ func (app *BaseApp) Name() string {
|
|||
}
|
||||
|
||||
// Mount a store to the provided key in the BaseApp multistore
|
||||
// Broken until #532 is implemented.
|
||||
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
|
||||
for _, key := range keys {
|
||||
app.MountStore(key, sdk.StoreTypeIAVL)
|
||||
}
|
||||
}
|
||||
|
||||
// Mount a store to the provided key in the BaseApp multistore
|
||||
func (app *BaseApp) MountStoreWithDB(key sdk.StoreKey, typ sdk.StoreType, db dbm.DB) {
|
||||
app.cms.MountStoreWithDB(key, typ, db)
|
||||
}
|
||||
|
||||
// Mount a store to the provided key in the BaseApp multistore
|
||||
func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
|
||||
app.cms.MountStoreWithDB(key, typ, app.db)
|
||||
|
@ -241,11 +248,6 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC
|
|||
// TODO Return something intelligent
|
||||
panic(err)
|
||||
}
|
||||
err = app.Router().InitGenesis(app.deliverState.ctx, *genesisState)
|
||||
if err != nil {
|
||||
// TODO Return something intelligent
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// NOTE: we don't commit, but BeginBlock for block 1
|
||||
// starts from this deliverState
|
||||
|
@ -259,7 +261,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
|||
queryable, ok := app.cms.(sdk.Queryable)
|
||||
if !ok {
|
||||
msg := "application doesn't support queries"
|
||||
return sdk.ErrUnknownRequest(msg).Result().ToQuery()
|
||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
return queryable.Query(req)
|
||||
}
|
||||
|
|
|
@ -35,12 +35,15 @@ func TestMountStores(t *testing.T) {
|
|||
|
||||
// make some cap keys
|
||||
capKey1 := sdk.NewKVStoreKey("key1")
|
||||
db1 := dbm.NewMemDB()
|
||||
capKey2 := sdk.NewKVStoreKey("key2")
|
||||
db2 := dbm.NewMemDB()
|
||||
|
||||
// no stores are mounted
|
||||
assert.Panics(t, func() { app.LoadLatestVersion(capKey1) })
|
||||
|
||||
app.MountStoresIAVL(capKey1, capKey2)
|
||||
app.MountStoreWithDB(capKey1, sdk.StoreTypeIAVL, db1)
|
||||
app.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db2)
|
||||
|
||||
// stores are mounted
|
||||
err := app.LoadLatestVersion(capKey1)
|
||||
|
@ -126,7 +129,6 @@ func TestTxDecoder(t *testing.T) {
|
|||
|
||||
// Test that Info returns the latest committed state.
|
||||
func TestInfo(t *testing.T) {
|
||||
|
||||
app := newBaseApp(t.Name())
|
||||
|
||||
// ----- test an empty response -------
|
||||
|
@ -145,17 +147,19 @@ func TestInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInitChainer(t *testing.T) {
|
||||
logger := defaultLogger()
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
db := dbm.NewMemDB()
|
||||
logger := defaultLogger()
|
||||
app := NewBaseApp(name, logger, db)
|
||||
|
||||
// make cap keys and mount the stores
|
||||
// NOTE/TODO: mounting multiple stores is broken
|
||||
// see https://github.com/cosmos/cosmos-sdk/issues/532
|
||||
capKey := sdk.NewKVStoreKey("main")
|
||||
// capKey2 := sdk.NewKVStoreKey("key2")
|
||||
app.MountStoresIAVL(capKey) // , capKey2)
|
||||
db1 := dbm.NewMemDB()
|
||||
capKey2 := sdk.NewKVStoreKey("key2")
|
||||
db2 := dbm.NewMemDB()
|
||||
app.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db1)
|
||||
app.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db2)
|
||||
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
@ -187,9 +191,8 @@ func TestInitChainer(t *testing.T) {
|
|||
|
||||
// reload app
|
||||
app = NewBaseApp(name, logger, db)
|
||||
capKey = sdk.NewKVStoreKey("main")
|
||||
// capKey2 = sdk.NewKVStoreKey("key2") // TODO
|
||||
app.MountStoresIAVL(capKey) //, capKey2)
|
||||
app.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db1)
|
||||
app.MountStoreWithDB(capKey2, sdk.StoreTypeIAVL, db2)
|
||||
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
assert.Nil(t, err)
|
||||
app.SetInitChainer(initChainer)
|
||||
|
@ -246,7 +249,7 @@ func TestDeliverTx(t *testing.T) {
|
|||
|
||||
counter += 1
|
||||
return sdk.Result{}
|
||||
}, nil)
|
||||
})
|
||||
|
||||
tx := testUpdatePowerTx{} // doesn't matter
|
||||
header := abci.Header{AppHash: []byte("apphash")}
|
||||
|
@ -281,7 +284,7 @@ func TestQuery(t *testing.T) {
|
|||
store := ctx.KVStore(capKey)
|
||||
store.Set(key, value)
|
||||
return sdk.Result{}
|
||||
}, nil)
|
||||
})
|
||||
|
||||
query := abci.RequestQuery{
|
||||
Path: "/main/key",
|
||||
|
@ -346,7 +349,7 @@ func TestValidatorChange(t *testing.T) {
|
|||
app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
// TODO
|
||||
return sdk.Result{}
|
||||
}, nil)
|
||||
})
|
||||
|
||||
// Load latest state, which should be empty.
|
||||
err := app.LoadLatestVersion(capKey)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package baseapp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -10,16 +8,14 @@ import (
|
|||
|
||||
// Router provides handlers for each transaction type.
|
||||
type Router interface {
|
||||
AddRoute(r string, h sdk.Handler, i sdk.InitGenesis) (rtr Router)
|
||||
AddRoute(r string, h sdk.Handler) (rtr Router)
|
||||
Route(path string) (h sdk.Handler)
|
||||
InitGenesis(ctx sdk.Context, data map[string]json.RawMessage) error
|
||||
}
|
||||
|
||||
// map a transaction type to a handler and an initgenesis function
|
||||
type route struct {
|
||||
r string
|
||||
h sdk.Handler
|
||||
i sdk.InitGenesis
|
||||
}
|
||||
|
||||
type router struct {
|
||||
|
@ -38,11 +34,11 @@ func NewRouter() *router {
|
|||
var isAlpha = regexp.MustCompile(`^[a-zA-Z]+$`).MatchString
|
||||
|
||||
// AddRoute - TODO add description
|
||||
func (rtr *router) AddRoute(r string, h sdk.Handler, i sdk.InitGenesis) Router {
|
||||
func (rtr *router) AddRoute(r string, h sdk.Handler) Router {
|
||||
if !isAlpha(r) {
|
||||
panic("route expressions can only contain alphanumeric characters")
|
||||
}
|
||||
rtr.routes = append(rtr.routes, route{r, h, i})
|
||||
rtr.routes = append(rtr.routes, route{r, h})
|
||||
|
||||
return rtr
|
||||
}
|
||||
|
@ -57,20 +53,3 @@ func (rtr *router) Route(path string) (h sdk.Handler) {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitGenesis - call `InitGenesis`, where specified, for all routes
|
||||
// Return the first error if any, otherwise nil
|
||||
func (rtr *router) InitGenesis(ctx sdk.Context, data map[string]json.RawMessage) error {
|
||||
for _, route := range rtr.routes {
|
||||
if route.i != nil {
|
||||
encoded, found := data[route.r]
|
||||
if !found {
|
||||
return sdk.ErrGenesisParse(fmt.Sprintf("Expected module genesis information for module %s but it was not present", route.r))
|
||||
}
|
||||
if err := route.i(ctx, encoded); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"github.com/spf13/viper"
|
||||
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/core"
|
||||
)
|
||||
|
||||
func NewCoreContextFromViper() core.CoreContext {
|
||||
nodeURI := viper.GetString(client.FlagNode)
|
||||
var rpc rpcclient.Client
|
||||
if nodeURI != "" {
|
||||
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
|
||||
}
|
||||
return core.CoreContext{
|
||||
ChainID: viper.GetString(client.FlagChainID),
|
||||
Height: viper.GetInt64(client.FlagHeight),
|
||||
TrustNode: viper.GetBool(client.FlagTrustNode),
|
||||
FromAddressName: viper.GetString(client.FlagName),
|
||||
NodeURI: nodeURI,
|
||||
Sequence: viper.GetInt64(client.FlagSequence),
|
||||
Client: rpc,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
)
|
||||
|
||||
type CoreContext struct {
|
||||
ChainID string
|
||||
Height int64
|
||||
TrustNode bool
|
||||
NodeURI string
|
||||
FromAddressName string
|
||||
Sequence int64
|
||||
Client rpcclient.Client
|
||||
}
|
||||
|
||||
func (c CoreContext) WithChainID(chainID string) CoreContext {
|
||||
c.ChainID = chainID
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithHeight(height int64) CoreContext {
|
||||
c.Height = height
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithTrustNode(trustNode bool) CoreContext {
|
||||
c.TrustNode = trustNode
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithNodeURI(nodeURI string) CoreContext {
|
||||
c.NodeURI = nodeURI
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithFromAddressName(fromAddressName string) CoreContext {
|
||||
c.FromAddressName = fromAddressName
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithSequence(sequence int64) CoreContext {
|
||||
c.Sequence = sequence
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CoreContext) WithClient(client rpcclient.Client) CoreContext {
|
||||
c.Client = client
|
||||
return c
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package builder
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
|
@ -17,9 +16,9 @@ import (
|
|||
)
|
||||
|
||||
// Broadcast the transaction bytes to Tendermint
|
||||
func BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
|
||||
node, err := client.GetNode()
|
||||
node, err := ctx.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -43,17 +42,17 @@ func BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
|
|||
}
|
||||
|
||||
// Query from Tendermint with the provided key and storename
|
||||
func Query(key cmn.HexBytes, storeName string) (res []byte, err error) {
|
||||
func (ctx CoreContext) Query(key cmn.HexBytes, storeName string) (res []byte, err error) {
|
||||
|
||||
path := fmt.Sprintf("/%s/key", storeName)
|
||||
node, err := client.GetNode()
|
||||
node, err := ctx.GetNode()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
opts := rpcclient.ABCIQueryOptions{
|
||||
Height: viper.GetInt64(client.FlagHeight),
|
||||
Trusted: viper.GetBool(client.FlagTrustNode),
|
||||
Height: ctx.Height,
|
||||
Trusted: ctx.TrustNode,
|
||||
}
|
||||
result, err := node.ABCIQueryWithOptions(path, key, opts)
|
||||
if err != nil {
|
||||
|
@ -67,16 +66,16 @@ func Query(key cmn.HexBytes, storeName string) (res []byte, err error) {
|
|||
}
|
||||
|
||||
// Get the from address from the name flag
|
||||
func GetFromAddress() (from sdk.Address, err error) {
|
||||
func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) {
|
||||
|
||||
keybase, err := keys.GetKeyBase()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
name := ctx.FromAddressName
|
||||
if name == "" {
|
||||
return nil, errors.Errorf("must provide a name using --name")
|
||||
return nil, errors.Errorf("must provide a from address name")
|
||||
}
|
||||
|
||||
info, err := keybase.Get(name)
|
||||
|
@ -88,11 +87,11 @@ func GetFromAddress() (from sdk.Address, err error) {
|
|||
}
|
||||
|
||||
// sign and build the transaction from the msg
|
||||
func SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *wire.Codec) ([]byte, error) {
|
||||
func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *wire.Codec) ([]byte, error) {
|
||||
|
||||
// build the Sign Messsage from the Standard Message
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
sequence := int64(viper.GetInt(client.FlagSequence))
|
||||
chainID := ctx.ChainID
|
||||
sequence := ctx.Sequence
|
||||
signMsg := sdk.StdSignMsg{
|
||||
ChainID: chainID,
|
||||
Sequences: []int64{sequence},
|
||||
|
@ -114,7 +113,7 @@ func SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *wire.Codec) ([]byte
|
|||
sigs := []sdk.StdSignature{{
|
||||
PubKey: pubkey,
|
||||
Signature: sig,
|
||||
Sequence: viper.GetInt64(client.FlagSequence),
|
||||
Sequence: sequence,
|
||||
}}
|
||||
|
||||
// marshal bytes
|
||||
|
@ -124,23 +123,31 @@ func SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *wire.Codec) ([]byte
|
|||
}
|
||||
|
||||
// sign and build the transaction from the msg
|
||||
func SignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
passphrase, err := GetPassphraseFromStdin(name)
|
||||
func (ctx CoreContext) SignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
passphrase, err := ctx.GetPassphraseFromStdin(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txBytes, err := SignAndBuild(name, passphrase, msg, cdc)
|
||||
txBytes, err := ctx.SignAndBuild(name, passphrase, msg, cdc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return BroadcastTx(txBytes)
|
||||
return ctx.BroadcastTx(txBytes)
|
||||
}
|
||||
|
||||
// get passphrase from std input
|
||||
func GetPassphraseFromStdin(name string) (pass string, err error) {
|
||||
func (ctx CoreContext) GetPassphraseFromStdin(name string) (pass string, err error) {
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password to sign with '%s':", name)
|
||||
return client.GetPassword(prompt, buf)
|
||||
}
|
||||
|
||||
// GetNode prepares a simple rpc.Client
|
||||
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
|
||||
if ctx.Client == nil {
|
||||
return nil, errors.New("Must define node URI")
|
||||
}
|
||||
return ctx.Client, nil
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
)
|
||||
|
||||
// GetNode prepares a simple rpc.Client from the flags
|
||||
func GetNode() (rpcclient.Client, error) {
|
||||
uri := viper.GetString(FlagNode)
|
||||
if uri == "" {
|
||||
return nil, errors.New("Must define node using --node")
|
||||
}
|
||||
return rpcclient.NewHTTP(uri, "/websocket"), nil
|
||||
}
|
|
@ -2,6 +2,7 @@ package keys
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
@ -32,7 +33,7 @@ type KeyOutput struct {
|
|||
func GetKeyBase() (keys.Keybase, error) {
|
||||
if keybase == nil {
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
db, err := dbm.NewGoLevelDB(KeyDBName, rootDir)
|
||||
db, err := dbm.NewGoLevelDB(KeyDBName, filepath.Join(rootDir, "keys"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
tmp-base*
|
|
@ -25,6 +25,7 @@ import (
|
|||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
|
@ -157,7 +158,7 @@ func TestNodeStatus(t *testing.T) {
|
|||
|
||||
func TestBlock(t *testing.T) {
|
||||
|
||||
time.Sleep(time.Second * 2) // TODO: LOL -> wait for blocks
|
||||
waitForHeight(2)
|
||||
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
|
@ -221,8 +222,7 @@ func TestCoinSend(t *testing.T) {
|
|||
|
||||
// create TX
|
||||
receiveAddr, resultTx := doSend(t, port, seed)
|
||||
|
||||
time.Sleep(time.Second * 2) // T
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
|
||||
// check if tx was commited
|
||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
|
@ -252,6 +252,32 @@ func TestCoinSend(t *testing.T) {
|
|||
assert.Equal(t, int64(1), mycoins.Amount)
|
||||
}
|
||||
|
||||
func TestIBCTransfer(t *testing.T) {
|
||||
|
||||
// create TX
|
||||
resultTx := doIBCTransfer(t, port, seed)
|
||||
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
|
||||
// check if tx was commited
|
||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
|
||||
// query sender
|
||||
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var m auth.BaseAccount
|
||||
err := json.Unmarshal([]byte(body), &m)
|
||||
require.Nil(t, err)
|
||||
coins := m.Coins
|
||||
mycoins := coins[0]
|
||||
assert.Equal(t, coinDenom, mycoins.Denom)
|
||||
assert.Equal(t, coinAmount-2, mycoins.Amount)
|
||||
|
||||
// TODO: query ibc egress packet state
|
||||
}
|
||||
|
||||
func TestTxs(t *testing.T) {
|
||||
|
||||
// TODO: re-enable once we can get txs by tag
|
||||
|
@ -269,7 +295,7 @@ func TestTxs(t *testing.T) {
|
|||
// create TX
|
||||
_, resultTx := doSend(t, port, seed)
|
||||
|
||||
time.Sleep(time.Second * 2) // TO
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
|
||||
// check if tx is findable
|
||||
res, body := request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
|
||||
|
@ -294,6 +320,7 @@ func TestTxs(t *testing.T) {
|
|||
// strt TM and the LCD in process, listening on their respective sockets
|
||||
func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
||||
|
||||
viper.Set(cli.HomeFlag, os.TempDir())
|
||||
kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -315,7 +342,13 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
logger = log.NewFilter(logger, log.AllowError())
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
privVal := tmtypes.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
app := bapp.NewBasecoinApp(logger, dbm.NewMemDB())
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbm.NewMemDB(),
|
||||
"acc": dbm.NewMemDB(),
|
||||
"ibc": dbm.NewMemDB(),
|
||||
"staking": dbm.NewMemDB(),
|
||||
}
|
||||
app := bapp.NewBasecoinApp(logger, dbs)
|
||||
|
||||
genesisFile := config.GenesisFile()
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||
|
@ -332,9 +365,6 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
Coins: coins,
|
||||
},
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.Marshal(appState)
|
||||
if err != nil {
|
||||
|
@ -361,7 +391,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
waitForStart()
|
||||
|
||||
return node, lcd, nil
|
||||
}
|
||||
|
@ -411,6 +441,7 @@ func request(t *testing.T, port, method, path string, payload []byte) (*http.Res
|
|||
require.Nil(t, err)
|
||||
|
||||
output, err := ioutil.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
require.Nil(t, err)
|
||||
|
||||
return res, string(output)
|
||||
|
@ -430,8 +461,6 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
|||
acc := auth.BaseAccount{}
|
||||
err = json.Unmarshal([]byte(body), &acc)
|
||||
require.Nil(t, err)
|
||||
fmt.Println("BODY", body)
|
||||
fmt.Println("ACC", acc)
|
||||
sequence := acc.Sequence
|
||||
|
||||
// send
|
||||
|
@ -444,3 +473,99 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
|||
|
||||
return receiveAddr, resultTx
|
||||
}
|
||||
|
||||
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||
require.Nil(t, err)
|
||||
receiveAddr := receiveInfo.PubKey.Address().String()
|
||||
|
||||
// get the account to get the sequence
|
||||
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
|
||||
// require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
acc := auth.BaseAccount{}
|
||||
err = json.Unmarshal([]byte(body), &acc)
|
||||
require.Nil(t, err)
|
||||
sequence := acc.Sequence
|
||||
|
||||
// send
|
||||
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
|
||||
res, body = request(t, port, "POST", "/ibc/testchain/"+receiveAddr+"/send", jsonStr)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err = json.Unmarshal([]byte(body), &resultTx)
|
||||
require.Nil(t, err)
|
||||
|
||||
return resultTx
|
||||
}
|
||||
|
||||
func waitForHeight(height int64) {
|
||||
for {
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
err = json.Unmarshal([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= height {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 2 blocks
|
||||
func waitForStart() {
|
||||
waitHeight := int64(2)
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// waiting for server to start ...
|
||||
if res.StatusCode != http.StatusOK {
|
||||
res.Body.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
err = json.Unmarshal([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= waitHeight {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/rest"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/rest"
|
||||
ibc "github.com/cosmos/cosmos-sdk/x/ibc/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -78,5 +79,6 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
|||
tx.RegisterRoutes(r, cdc)
|
||||
auth.RegisterRoutes(r, cdc, "main")
|
||||
bank.RegisterRoutes(r, cdc, kb)
|
||||
ibc.RegisterRoutes(r, cdc, kb)
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -31,7 +32,8 @@ func blockCommand() *cobra.Command {
|
|||
|
||||
func getBlock(height *int64) ([]byte, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
node, err := ctx.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ func getBlock(height *int64) ([]byte, error) {
|
|||
}
|
||||
|
||||
func GetChainHeight() (int64, error) {
|
||||
node, err := client.GetNode()
|
||||
node, err := context.NewCoreContextFromViper().GetNode()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,7 @@ func statusCommand() *cobra.Command {
|
|||
|
||||
func getNodeStatus() (*ctypes.ResultStatus, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
node, err := context.NewCoreContextFromViper().GetNode()
|
||||
if err != nil {
|
||||
return &ctypes.ResultStatus{}, err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
)
|
||||
|
||||
func validatorCommand() *cobra.Command {
|
||||
|
@ -26,7 +27,7 @@ func validatorCommand() *cobra.Command {
|
|||
|
||||
func GetValidators(height *int64) ([]byte, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
node, err := context.NewCoreContextFromViper().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
)
|
||||
|
||||
type BroadcastTxBody struct {
|
||||
|
@ -22,7 +22,7 @@ func BroadcastTxRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
res, err := builder.BroadcastTx([]byte(m.TxBytes))
|
||||
res, err := context.NewCoreContextFromViper().BroadcastTx([]byte(m.TxBytes))
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
@ -39,7 +40,7 @@ func (c commander) queryTx(hashHexStr string, trustNode bool) ([]byte, error) {
|
|||
}
|
||||
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
node, err := context.NewCoreContextFromViper().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
|
@ -43,7 +44,7 @@ func (c commander) searchTx(tags []string) ([]byte, error) {
|
|||
query := strings.Join(tags, " AND ")
|
||||
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
node, err := context.NewCoreContextFromViper().GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ const (
|
|||
flagFee = "fee"
|
||||
)
|
||||
|
||||
// gaiacliCmd is the entry point for this binary
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
gaiacliCmd = &cobra.Command{
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "gaiacli",
|
||||
Short: "Gaia light-client",
|
||||
}
|
||||
|
@ -54,16 +54,16 @@ func main() {
|
|||
cobra.EnableCommandSorting = false
|
||||
|
||||
// generic client commands
|
||||
AddClientCommands(gaiacliCmd)
|
||||
AddClientCommands(rootCmd)
|
||||
// query commands (custom to binary)
|
||||
gaiacliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
GetCommands(getAccountCmd)...)
|
||||
// post tx commands (custom to binary)
|
||||
gaiacliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
PostCommands(postSendCommand())...)
|
||||
|
||||
// add proxy, version and key info
|
||||
gaiacliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
lineBreak,
|
||||
serveCommand(),
|
||||
KeyCommands(),
|
||||
|
@ -72,6 +72,6 @@ func main() {
|
|||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(gaiacliCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
|
||||
executor.Execute()
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "gaiad",
|
||||
Short: "Gaia Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: distinguish from basecoin
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
dbMain, err := dbm.NewGoLevelDB("gaia", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbAcc, err := dbm.NewGoLevelDB("gaia-acc", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbIBC, err := dbm.NewGoLevelDB("gaia-ibc", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbStaking, err := dbm.NewGoLevelDB("gaia-staking", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbMain,
|
||||
"acc": dbAcc,
|
||||
"ibc": dbIBC,
|
||||
"staking": dbStaking,
|
||||
}
|
||||
bapp := app.NewBasecoinApp(logger, dbs)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiad"))
|
||||
executor.Execute()
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
Cosmos-SDK Basecoin (template)
|
||||
License: Apache2.0
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 All in Bits, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,22 +0,0 @@
|
|||
PACKAGES=$(shell go list ./... | grep -v '/vendor/')
|
||||
BUILD_FLAGS = -ldflags "-X github.com/cosmos/cosmos-sdk/examples/basecoin/version.GitCommit=`git rev-parse --short HEAD`"
|
||||
|
||||
all: get_tools get_vendor_deps build test
|
||||
|
||||
get_tools:
|
||||
go get github.com/golang/dep/cmd/dep
|
||||
|
||||
build:
|
||||
go build $(BUILD_FLAGS) -o build/basecoin ./cmd/...
|
||||
|
||||
get_vendor_deps:
|
||||
@rm -rf vendor/
|
||||
@dep ensure
|
||||
|
||||
test:
|
||||
@go test $(PACKAGES)
|
||||
|
||||
benchmark:
|
||||
@go test -bench=. $(PACKAGES)
|
||||
|
||||
.PHONY: all build test benchmark
|
|
@ -1,70 +0,0 @@
|
|||
# Basecoin
|
||||
|
||||
This is the "Basecoin" example application built on the Cosmos-Sdk. This
|
||||
"Basecoin" is not affiliated with [Coinbase](http://www.getbasecoin.com/), nor
|
||||
the [stable coin](http://www.getbasecoin.com/).
|
||||
|
||||
Assuming you've run `make get_tools && make get_vendor_deps` from the root of
|
||||
this repository, run `make build` here to build the `basecoind` and `basecli`
|
||||
binaries.
|
||||
|
||||
If you want to create a new application, start by copying the Basecoin app.
|
||||
|
||||
|
||||
# Building your own Blockchain
|
||||
|
||||
Basecoin is the equivalent of an ERC20 token contract for blockchains. In order
|
||||
to deploy your own application all you need to do is clone `examples/basecoin`
|
||||
and run it. Now you are already running your own blockchain. In the following
|
||||
I will explain how to add functionality to your blockchain. This is akin to
|
||||
defining your own vesting schedule within a contract or setting a specific
|
||||
multisig. You are just extending the base layer with extra functionality here
|
||||
and there.
|
||||
|
||||
## Structure of Basecoin
|
||||
|
||||
Basecoin is build with the cosmos-sdk. It is a sample application that works
|
||||
with any engine that implements the ABCI protocol. Basecoin defines multiple
|
||||
unique modules as well as uses modules directly from the sdk. If you want
|
||||
to modify Basecoin, you either remove or add modules according to your wishes.
|
||||
|
||||
|
||||
## Modules
|
||||
|
||||
A module is a fundamental unit in the cosmos-sdk. A module defines its own
|
||||
transaction, handles its own state as well as its own state transition logic.
|
||||
Globally, in the `app/app.go` file you just have to define a key for that
|
||||
module to access some parts of the state, as well as initialise the module
|
||||
object and finally add it to the transaction router. The router ensures that
|
||||
every module only gets its own messages.
|
||||
|
||||
|
||||
## Transactions
|
||||
|
||||
A user can send a transaction to the running blockchain application. This
|
||||
transaction can be of any of the ones that are supported by any of the
|
||||
registered modules.
|
||||
|
||||
### CheckTx
|
||||
|
||||
Once a user has submitted their transaction to the engine,
|
||||
the engine will first run `checkTx` to confirm that it is a valid transaction.
|
||||
The module has to define a handler that knows how to handle every transaction
|
||||
type. The corresponding handler gets invoked with the checkTx flag set to true.
|
||||
This means that the handler shouldn't do any expensive operations, but it can
|
||||
and should write to the checkTx state.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
The engine calls `deliverTx` when a new block has been agreed upon in
|
||||
consensus. Again, the corresponding module will have its handler invoked
|
||||
and the state and context is passed in. During deliverTx execution the
|
||||
transaction needs to be processed fully and the results are written to the
|
||||
application state.
|
||||
|
||||
|
||||
## CLI
|
||||
|
||||
The cosmos-sdk contains a number of helper libraries in `clients/` to build cli
|
||||
and RPC interfaces for your specific application.
|
||||
|
|
@ -15,11 +15,9 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/simplestake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/sketchy"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -33,6 +31,7 @@ type BasecoinApp struct {
|
|||
|
||||
// keys to access the substores
|
||||
capKeyMainStore *sdk.KVStoreKey
|
||||
capKeyAccountStore *sdk.KVStoreKey
|
||||
capKeyIBCStore *sdk.KVStoreKey
|
||||
capKeyStakingStore *sdk.KVStoreKey
|
||||
|
||||
|
@ -40,14 +39,15 @@ type BasecoinApp struct {
|
|||
accountMapper sdk.AccountMapper
|
||||
}
|
||||
|
||||
func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||
func NewBasecoinApp(logger log.Logger, dbs map[string]dbm.DB) *BasecoinApp {
|
||||
// create your application object
|
||||
var app = &BasecoinApp{
|
||||
BaseApp: bam.NewBaseApp(appName, logger, db),
|
||||
BaseApp: bam.NewBaseApp(appName, logger, dbs["main"]),
|
||||
cdc: MakeCodec(),
|
||||
capKeyMainStore: sdk.NewKVStoreKey("main"),
|
||||
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
|
||||
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
|
||||
capKeyStakingStore: sdk.NewKVStoreKey("staking"),
|
||||
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
|
@ -58,20 +58,22 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
|||
|
||||
// add handlers
|
||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper)
|
||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||
stakeKeeper := staking.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper), nil).
|
||||
AddRoute("cool", cool.NewHandler(coolKeeper), coolKeeper.InitGenesis).
|
||||
AddRoute("sketchy", sketchy.NewHandler(), nil).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper), nil).
|
||||
AddRoute("staking", staking.NewHandler(stakeKeeper), nil)
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper)).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
|
||||
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper))
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetTxDecoder(app.txDecoder)
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.MountStoreWithDB(app.capKeyMainStore, sdk.StoreTypeIAVL, dbs["main"])
|
||||
app.MountStoreWithDB(app.capKeyAccountStore, sdk.StoreTypeIAVL, dbs["acc"])
|
||||
app.MountStoreWithDB(app.capKeyIBCStore, sdk.StoreTypeIAVL, dbs["ibc"])
|
||||
app.MountStoreWithDB(app.capKeyStakingStore, sdk.StoreTypeIAVL, dbs["staking"])
|
||||
// NOTE: Broken until #532 lands
|
||||
//app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
err := app.LoadLatestVersion(app.capKeyMainStore)
|
||||
if err != nil {
|
||||
|
@ -96,12 +98,10 @@ func MakeCodec() *wire.Codec {
|
|||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
oldwire.ConcreteType{staking.BondMsg{}, msgTypeBondMsg},
|
||||
oldwire.ConcreteType{staking.UnbondMsg{}, msgTypeUnbondMsg},
|
||||
oldwire.ConcreteType{simplestake.BondMsg{}, msgTypeBondMsg},
|
||||
oldwire.ConcreteType{simplestake.UnbondMsg{}, msgTypeUnbondMsg},
|
||||
)
|
||||
|
||||
const accTypeApp = 0x1
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
@ -26,50 +25,103 @@ import (
|
|||
var (
|
||||
chainID = "" // TODO
|
||||
|
||||
accName = "foobart"
|
||||
|
||||
priv1 = crypto.GenPrivKeyEd25519()
|
||||
addr1 = priv1.PubKey().Address()
|
||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
priv2 = crypto.GenPrivKeyEd25519()
|
||||
addr2 = priv2.PubKey().Address()
|
||||
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
priv4 = crypto.GenPrivKeyEd25519()
|
||||
addr4 = priv4.PubKey().Address()
|
||||
coins = sdk.Coins{{"foocoin", 10}}
|
||||
halfCoins = sdk.Coins{{"foocoin", 5}}
|
||||
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
||||
fee = sdk.StdFee{
|
||||
sdk.Coins{{"foocoin", 0}},
|
||||
0,
|
||||
}
|
||||
|
||||
sendMsg = bank.SendMsg{
|
||||
sendMsg1 = bank.SendMsg{
|
||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
||||
}
|
||||
|
||||
quizMsg1 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "icecold",
|
||||
sendMsg2 = bank.SendMsg{
|
||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
Outputs: []bank.Output{
|
||||
bank.NewOutput(addr2, halfCoins),
|
||||
bank.NewOutput(addr3, halfCoins),
|
||||
},
|
||||
}
|
||||
|
||||
quizMsg2 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "badvibesonly",
|
||||
sendMsg3 = bank.SendMsg{
|
||||
Inputs: []bank.Input{
|
||||
bank.NewInput(addr1, coins),
|
||||
bank.NewInput(addr4, coins),
|
||||
},
|
||||
Outputs: []bank.Output{
|
||||
bank.NewOutput(addr2, coins),
|
||||
bank.NewOutput(addr3, coins),
|
||||
},
|
||||
}
|
||||
|
||||
setTrendMsg1 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "icecold",
|
||||
sendMsg4 = bank.SendMsg{
|
||||
Inputs: []bank.Input{
|
||||
bank.NewInput(addr2, coins),
|
||||
},
|
||||
Outputs: []bank.Output{
|
||||
bank.NewOutput(addr1, coins),
|
||||
},
|
||||
}
|
||||
|
||||
setTrendMsg2 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg3 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "warmandkind",
|
||||
sendMsg5 = bank.SendMsg{
|
||||
Inputs: []bank.Input{
|
||||
bank.NewInput(addr1, manyCoins),
|
||||
},
|
||||
Outputs: []bank.Output{
|
||||
bank.NewOutput(addr2, manyCoins),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func newBasecoinApp() *BasecoinApp {
|
||||
func loggerAndDBs() (log.Logger, map[string]dbm.DB) {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||
db := dbm.NewMemDB()
|
||||
return NewBasecoinApp(logger, db)
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbm.NewMemDB(),
|
||||
"acc": dbm.NewMemDB(),
|
||||
"ibc": dbm.NewMemDB(),
|
||||
"staking": dbm.NewMemDB(),
|
||||
}
|
||||
return logger, dbs
|
||||
}
|
||||
|
||||
func newBasecoinApp() *BasecoinApp {
|
||||
logger, dbs := loggerAndDBs()
|
||||
return NewBasecoinApp(logger, dbs)
|
||||
}
|
||||
|
||||
func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
|
||||
genaccs := make([]*types.GenesisAccount, len(accs))
|
||||
for i, acc := range accs {
|
||||
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName})
|
||||
}
|
||||
|
||||
genesisState := types.GenesisState{
|
||||
Accounts: genaccs,
|
||||
}
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
@ -80,41 +132,60 @@ func TestMsgs(t *testing.T) {
|
|||
msgs := []struct {
|
||||
msg sdk.Msg
|
||||
}{
|
||||
{sendMsg},
|
||||
{quizMsg1},
|
||||
{setTrendMsg1},
|
||||
{sendMsg1},
|
||||
}
|
||||
|
||||
sequences := []int64{0}
|
||||
for i, m := range msgs {
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, m.msg))
|
||||
tx := sdk.NewStdTx(m.msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// just marshal/unmarshal!
|
||||
cdc := MakeCodec()
|
||||
txBytes, err := cdc.MarshalBinary(tx)
|
||||
require.NoError(t, err, "i: %v", i)
|
||||
|
||||
// Run a Check
|
||||
cres := bapp.CheckTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(cres.Code), "i: %v, log: %v", i, cres.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
dres := bapp.DeliverTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(dres.Code), "i: %v, log: %v", i, dres.Log)
|
||||
// Run a CheckDeliver
|
||||
SignCheckDeliver(t, bapp, m.msg, []int64{int64(i)}, false, priv1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortGenesis(t *testing.T) {
|
||||
logger, dbs := loggerAndDBs()
|
||||
bapp := NewBasecoinApp(logger, dbs)
|
||||
|
||||
// Note the order: the coins are unsorted!
|
||||
coinDenom1, coinDenom2 := "foocoin", "barcoin"
|
||||
|
||||
genState := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "%s",
|
||||
"amount": 10
|
||||
},
|
||||
{
|
||||
"denom": "%s",
|
||||
"amount": 20
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr1.String(), coinDenom1, coinDenom2)
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)})
|
||||
bapp.Commit()
|
||||
|
||||
// Unsorted coins means invalid
|
||||
err := sendMsg5.ValidateBasic()
|
||||
require.Equal(t, sdk.CodeInvalidCoins, err.ABCICode(), err.ABCILog())
|
||||
|
||||
// Sort coins, should be valid
|
||||
sendMsg5.Inputs[0].Coins.Sort()
|
||||
sendMsg5.Outputs[0].Coins.Sort()
|
||||
err = sendMsg5.ValidateBasic()
|
||||
require.Nil(t, err)
|
||||
|
||||
// Ensure we can send
|
||||
SignCheckDeliver(t, bapp, sendMsg5, []int64{0}, true, priv1)
|
||||
}
|
||||
|
||||
func TestGenesis(t *testing.T) {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||
db := dbm.NewMemDB()
|
||||
bapp := NewBasecoinApp(logger, db)
|
||||
logger, dbs := loggerAndDBs()
|
||||
bapp := NewBasecoinApp(logger, dbs)
|
||||
|
||||
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
||||
pk := crypto.GenPrivKeyEd25519().PubKey()
|
||||
|
@ -127,31 +198,19 @@ func TestGenesis(t *testing.T) {
|
|||
}
|
||||
acc := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
err = setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// A checkTx context
|
||||
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
/*
|
||||
|
||||
// reload app and ensure the account is still there
|
||||
bapp = NewBasecoinApp(logger, db)
|
||||
bapp = NewBasecoinApp(logger, dbs)
|
||||
ctx = bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
*/
|
||||
}
|
||||
|
||||
func TestSendMsgWithAccounts(t *testing.T) {
|
||||
|
@ -165,69 +224,124 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
|||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
err = setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
|
||||
|
||||
// Sign the tx
|
||||
sequences := []int64{0}
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, sendMsg))
|
||||
tx := sdk.NewStdTx(sendMsg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
// Run a CheckDeliver
|
||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
||||
|
||||
// Check balances
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
||||
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
||||
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
||||
CheckBalance(t, bapp, addr1, "67foocoin")
|
||||
CheckBalance(t, bapp, addr2, "10foocoin")
|
||||
|
||||
// Delivering again should cause replay error
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log)
|
||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, false, priv1)
|
||||
|
||||
// bumping the txnonce number without resigning should be an auth error
|
||||
tx := genTx(sendMsg1, []int64{0}, priv1)
|
||||
tx.Signatures[0].Sequence = 1
|
||||
res = bapp.Deliver(tx)
|
||||
res := bapp.Deliver(tx)
|
||||
|
||||
assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log)
|
||||
|
||||
// resigning the tx with the bumped sequence should work
|
||||
sequences = []int64{1}
|
||||
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg))
|
||||
tx.Signatures[0].Signature = sig
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1)
|
||||
}
|
||||
|
||||
func TestSendMsgMultipleOut(t *testing.T) {
|
||||
bapp := newBasecoinApp()
|
||||
|
||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
||||
require.Nil(t, err)
|
||||
|
||||
acc1 := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
acc2 := auth.BaseAccount{
|
||||
Address: addr2,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
err = setGenesisAccounts(bapp, acc1, acc2)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Simulate a Block
|
||||
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
|
||||
|
||||
// Check balances
|
||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
||||
CheckBalance(t, bapp, addr2, "47foocoin")
|
||||
CheckBalance(t, bapp, addr3, "5foocoin")
|
||||
}
|
||||
|
||||
func TestSengMsgMultipleInOut(t *testing.T) {
|
||||
bapp := newBasecoinApp()
|
||||
|
||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
||||
require.Nil(t, err)
|
||||
|
||||
acc1 := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
acc2 := auth.BaseAccount{
|
||||
Address: addr2,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
acc4 := auth.BaseAccount{
|
||||
Address: addr4,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
err = setGenesisAccounts(bapp, acc1, acc2, acc4)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// CheckDeliver
|
||||
SignCheckDeliver(t, bapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
|
||||
|
||||
// Check balances
|
||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
||||
CheckBalance(t, bapp, addr4, "32foocoin")
|
||||
CheckBalance(t, bapp, addr2, "52foocoin")
|
||||
CheckBalance(t, bapp, addr3, "10foocoin")
|
||||
}
|
||||
|
||||
func TestSendMsgDependent(t *testing.T) {
|
||||
bapp := newBasecoinApp()
|
||||
|
||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
||||
require.Nil(t, err)
|
||||
|
||||
acc1 := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: genCoins,
|
||||
}
|
||||
|
||||
err = setGenesisAccounts(bapp, acc1)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// CheckDeliver
|
||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
||||
|
||||
// Check balances
|
||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
||||
CheckBalance(t, bapp, addr2, "10foocoin")
|
||||
|
||||
// Simulate a Block
|
||||
SignCheckDeliver(t, bapp, sendMsg4, []int64{0}, true, priv2)
|
||||
|
||||
// Check balances
|
||||
CheckBalance(t, bapp, addr1, "42foocoin")
|
||||
}
|
||||
|
||||
func TestQuizMsg(t *testing.T) {
|
||||
|
@ -247,9 +361,6 @@ func TestQuizMsg(t *testing.T) {
|
|||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
@ -264,48 +375,22 @@ func TestQuizMsg(t *testing.T) {
|
|||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Set the trend, submit a really cool quiz and check for reward
|
||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
|
||||
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
func TestIBCMsgs(t *testing.T) {
|
||||
bapp := newBasecoinApp()
|
||||
|
||||
sourceChain := "source-chain"
|
||||
destChain := "dest-chain"
|
||||
|
||||
vals := []abci.Validator{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
err := setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
|
@ -329,24 +414,32 @@ func TestHandler(t *testing.T) {
|
|||
Sequence: 0,
|
||||
}
|
||||
|
||||
SignCheckDeliver(t, bapp, transferMsg, 0, true)
|
||||
CheckBalance(t, bapp, "")
|
||||
SignCheckDeliver(t, bapp, transferMsg, 1, false)
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 2, true)
|
||||
CheckBalance(t, bapp, "10foocoin")
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
||||
SignCheckDeliver(t, bapp, transferMsg, []int64{0}, true, priv1)
|
||||
CheckBalance(t, bapp, addr1, "")
|
||||
SignCheckDeliver(t, bapp, transferMsg, []int64{1}, false, priv1)
|
||||
SignCheckDeliver(t, bapp, receiveMsg, []int64{2}, true, priv1)
|
||||
CheckBalance(t, bapp, addr1, "10foocoin")
|
||||
SignCheckDeliver(t, bapp, receiveMsg, []int64{3}, false, priv1)
|
||||
}
|
||||
|
||||
// TODO describe the use of this function
|
||||
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
||||
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.StdTx {
|
||||
sigs := make([]sdk.StdSignature, len(priv))
|
||||
for i, p := range priv {
|
||||
sigs[i] = sdk.StdSignature{
|
||||
PubKey: p.PubKey(),
|
||||
Signature: p.Sign(sdk.StdSignBytes(chainID, seq, fee, msg)),
|
||||
Sequence: seq[i],
|
||||
}
|
||||
}
|
||||
|
||||
return sdk.NewStdTx(msg, fee, sigs)
|
||||
|
||||
}
|
||||
|
||||
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
|
||||
|
||||
// Sign the tx
|
||||
tx := sdk.NewStdTx(msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, fee, msg)),
|
||||
Sequence: seq,
|
||||
}})
|
||||
|
||||
tx := genTx(msg, seq, priv...)
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
if expPass {
|
||||
|
@ -367,8 +460,8 @@ func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, e
|
|||
//bapp.Commit()
|
||||
}
|
||||
|
||||
func CheckBalance(t *testing.T, bapp *BasecoinApp, balExpected string) {
|
||||
func CheckBalance(t *testing.T, bapp *BasecoinApp, addr sdk.Address, balExpected string) {
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr)
|
||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
|
@ -13,29 +13,24 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
coolcmd "github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool/commands"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/commands"
|
||||
stakingcmd "github.com/cosmos/cosmos-sdk/x/staking/commands"
|
||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/x/simplestake/commands"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
)
|
||||
|
||||
// gaiacliCmd is the entry point for this binary
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
basecliCmd = &cobra.Command{
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "basecli",
|
||||
Short: "Basecoin light-client",
|
||||
}
|
||||
)
|
||||
|
||||
func todoNotImplemented(_ *cobra.Command, _ []string) error {
|
||||
return errors.New("TODO: Command not yet implemented")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// disable sorting
|
||||
cobra.EnableCommandSorting = false
|
||||
|
@ -48,44 +43,36 @@ func main() {
|
|||
// with the cdc
|
||||
|
||||
// add standard rpc, and tx commands
|
||||
rpc.AddCommands(basecliCmd)
|
||||
basecliCmd.AddCommand(client.LineBreak)
|
||||
tx.AddCommands(basecliCmd, cdc)
|
||||
basecliCmd.AddCommand(client.LineBreak)
|
||||
rpc.AddCommands(rootCmd)
|
||||
rootCmd.AddCommand(client.LineBreak)
|
||||
tx.AddCommands(rootCmd, cdc)
|
||||
rootCmd.AddCommand(client.LineBreak)
|
||||
|
||||
// add query/post commands (custom to binary)
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
coolcmd.QuizTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
coolcmd.SetTrendTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
stakingcmd.BondTxCmd(cdc),
|
||||
simplestakingcmd.BondTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
stakingcmd.UnbondTxCmd(cdc),
|
||||
simplestakingcmd.UnbondTxCmd(cdc),
|
||||
)...)
|
||||
|
||||
// add proxy, version and key info
|
||||
basecliCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
keys.Commands(),
|
||||
|
@ -94,6 +81,6 @@ func main() {
|
|||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(basecliCmd, "BC", os.ExpandEnv("$HOME/.basecli"))
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli"))
|
||||
executor.Execute()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -15,66 +13,51 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
// basecoindCmd is the entry point for this binary
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
basecoindCmd = &cobra.Command{
|
||||
Use: "gaiad",
|
||||
Short: "Gaia Daemon (server)",
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "basecoind",
|
||||
Short: "Basecoin Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
}
|
||||
)
|
||||
|
||||
// defaultOptions sets up the app_options for the
|
||||
// default genesis file
|
||||
func defaultOptions(args []string) (json.RawMessage, error) {
|
||||
addr, secret, err := server.GenerateCoinKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("Secret phrase to access coins:")
|
||||
fmt.Println(secret)
|
||||
|
||||
opts := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr)
|
||||
return json.RawMessage(opts), nil
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
db, err := dbm.NewGoLevelDB("basecoin", filepath.Join(rootDir, "data"))
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
dbMain, err := dbm.NewGoLevelDB("basecoin", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bapp := app.NewBasecoinApp(logger, db)
|
||||
dbAcc, err := dbm.NewGoLevelDB("basecoin-acc", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbIBC, err := dbm.NewGoLevelDB("basecoin-ibc", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbStaking, err := dbm.NewGoLevelDB("basecoin-staking", dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbMain,
|
||||
"acc": dbAcc,
|
||||
"ibc": dbIBC,
|
||||
"staking": dbStaking,
|
||||
}
|
||||
bapp := app.NewBasecoinApp(logger, dbs)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// TODO: set logger through CLI
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
||||
With("module", "main")
|
||||
|
||||
basecoindCmd.AddCommand(
|
||||
server.InitCmd(defaultOptions, logger),
|
||||
server.StartCmd(generateApp, logger),
|
||||
server.UnsafeResetAllCmd(logger),
|
||||
server.ShowNodeIdCmd(logger),
|
||||
server.ShowValidatorCmd(logger),
|
||||
version.VersionCmd,
|
||||
)
|
||||
server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||
executor := cli.PrepareBaseCmd(basecoindCmd, "BC", rootDir)
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
|
||||
executor.Execute()
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
|
|||
return &GenesisAccount{
|
||||
Name: aa.Name,
|
||||
Address: aa.Address,
|
||||
Coins: aa.Coins,
|
||||
Coins: aa.Coins.Sort(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
|
|||
func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) {
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins,
|
||||
Coins: ga.Coins.Sort(),
|
||||
}
|
||||
return &AppAccount{
|
||||
BaseAccount: baseAcc,
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
oldwire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/simplestake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/sketchy"
|
||||
)
|
||||
|
||||
const (
|
||||
appName = "DemocoinApp"
|
||||
)
|
||||
|
||||
// Extended ABCI application
|
||||
type DemocoinApp struct {
|
||||
*bam.BaseApp
|
||||
cdc *wire.Codec
|
||||
|
||||
// keys to access the substores
|
||||
capKeyMainStore *sdk.KVStoreKey
|
||||
capKeyAccountStore *sdk.KVStoreKey
|
||||
capKeyPowStore *sdk.KVStoreKey
|
||||
capKeyIBCStore *sdk.KVStoreKey
|
||||
capKeyStakingStore *sdk.KVStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper sdk.AccountMapper
|
||||
}
|
||||
|
||||
func NewDemocoinApp(logger log.Logger, dbs map[string]dbm.DB) *DemocoinApp {
|
||||
// create your application object
|
||||
var app = &DemocoinApp{
|
||||
BaseApp: bam.NewBaseApp(appName, logger, dbs["main"]),
|
||||
cdc: MakeCodec(),
|
||||
capKeyMainStore: sdk.NewKVStoreKey("main"),
|
||||
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
|
||||
capKeyPowStore: sdk.NewKVStoreKey("pow"),
|
||||
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
|
||||
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
app.accountMapper = auth.NewAccountMapperSealed(
|
||||
app.capKeyMainStore, // target store
|
||||
&types.AppAccount{}, // prototype
|
||||
)
|
||||
|
||||
// add handlers
|
||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper)
|
||||
powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewPowConfig("pow", int64(1)), coinKeeper)
|
||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper)).
|
||||
AddRoute("cool", cool.NewHandler(coolKeeper)).
|
||||
AddRoute("pow", powKeeper.Handler).
|
||||
AddRoute("sketchy", sketchy.NewHandler()).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
|
||||
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper))
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetTxDecoder(app.txDecoder)
|
||||
app.SetInitChainer(app.initChainerFn(coolKeeper, powKeeper))
|
||||
app.MountStoreWithDB(app.capKeyMainStore, sdk.StoreTypeIAVL, dbs["main"])
|
||||
app.MountStoreWithDB(app.capKeyAccountStore, sdk.StoreTypeIAVL, dbs["acc"])
|
||||
app.MountStoreWithDB(app.capKeyPowStore, sdk.StoreTypeIAVL, dbs["pow"])
|
||||
app.MountStoreWithDB(app.capKeyIBCStore, sdk.StoreTypeIAVL, dbs["ibc"])
|
||||
app.MountStoreWithDB(app.capKeyStakingStore, sdk.StoreTypeIAVL, dbs["staking"])
|
||||
// NOTE: Broken until #532 lands
|
||||
//app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
err := app.LoadLatestVersion(app.capKeyMainStore)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// custom tx codec
|
||||
// TODO: use new go-wire
|
||||
func MakeCodec() *wire.Codec {
|
||||
const msgTypeSend = 0x1
|
||||
const msgTypeIssue = 0x2
|
||||
const msgTypeQuiz = 0x3
|
||||
const msgTypeSetTrend = 0x4
|
||||
const msgTypeMine = 0x5
|
||||
const msgTypeIBCTransferMsg = 0x6
|
||||
const msgTypeIBCReceiveMsg = 0x7
|
||||
const msgTypeBondMsg = 0x8
|
||||
const msgTypeUnbondMsg = 0x9
|
||||
var _ = oldwire.RegisterInterface(
|
||||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{pow.MineMsg{}, msgTypeMine},
|
||||
oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
oldwire.ConcreteType{simplestake.BondMsg{}, msgTypeBondMsg},
|
||||
oldwire.ConcreteType{simplestake.UnbondMsg{}, msgTypeUnbondMsg},
|
||||
)
|
||||
|
||||
const accTypeApp = 0x1
|
||||
var _ = oldwire.RegisterInterface(
|
||||
struct{ sdk.Account }{},
|
||||
oldwire.ConcreteType{&types.AppAccount{}, accTypeApp},
|
||||
)
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
// cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
||||
// bank.RegisterWire(cdc) // Register bank.[SendMsg,IssueMsg] types.
|
||||
// crypto.RegisterWire(cdc) // Register crypto.[PubKey,PrivKey,Signature] types.
|
||||
// ibc.RegisterWire(cdc) // Register ibc.[IBCTransferMsg, IBCReceiveMsg] types.
|
||||
return cdc
|
||||
}
|
||||
|
||||
// custom logic for transaction decoding
|
||||
func (app *DemocoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx = sdk.StdTx{}
|
||||
|
||||
if len(txBytes) == 0 {
|
||||
return nil, sdk.ErrTxDecode("txBytes are empty")
|
||||
}
|
||||
|
||||
// StdTx.Msg is an interface. The concrete types
|
||||
// are registered by MakeTxCodec in bank.RegisterWire.
|
||||
err := app.cdc.UnmarshalBinary(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode("").TraceCause(err, "")
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// custom logic for democoin initialization
|
||||
func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(types.GenesisState)
|
||||
err := json.Unmarshal(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc, err := gacc.ToAppAccount()
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
app.accountMapper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
// Application specific genesis handling
|
||||
err = coolKeeper.InitGenesis(ctx, genesisState.CoolGenesis)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
err = powKeeper.InitGenesis(ctx, genesisState.PowGenesis)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,436 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// Construct some global addrs and txs for tests.
|
||||
var (
|
||||
chainID = "" // TODO
|
||||
|
||||
priv1 = crypto.GenPrivKeyEd25519()
|
||||
addr1 = priv1.PubKey().Address()
|
||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
coins = sdk.Coins{{"foocoin", 10}}
|
||||
fee = sdk.StdFee{
|
||||
sdk.Coins{{"foocoin", 0}},
|
||||
0,
|
||||
}
|
||||
|
||||
sendMsg = bank.SendMsg{
|
||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
||||
}
|
||||
|
||||
quizMsg1 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "icecold",
|
||||
}
|
||||
|
||||
quizMsg2 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg1 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "icecold",
|
||||
}
|
||||
|
||||
setTrendMsg2 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg3 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "warmandkind",
|
||||
}
|
||||
)
|
||||
|
||||
func loggerAndDBs() (log.Logger, map[string]dbm.DB) {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbm.NewMemDB(),
|
||||
"acc": dbm.NewMemDB(),
|
||||
"pow": dbm.NewMemDB(),
|
||||
"ibc": dbm.NewMemDB(),
|
||||
"staking": dbm.NewMemDB(),
|
||||
}
|
||||
return logger, dbs
|
||||
}
|
||||
|
||||
func newDemocoinApp() *DemocoinApp {
|
||||
logger, dbs := loggerAndDBs()
|
||||
return NewDemocoinApp(logger, dbs)
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
||||
func TestMsgs(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
msgs := []struct {
|
||||
msg sdk.Msg
|
||||
}{
|
||||
{sendMsg},
|
||||
{quizMsg1},
|
||||
{setTrendMsg1},
|
||||
}
|
||||
|
||||
sequences := []int64{0}
|
||||
for i, m := range msgs {
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, m.msg))
|
||||
tx := sdk.NewStdTx(m.msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// just marshal/unmarshal!
|
||||
cdc := MakeCodec()
|
||||
txBytes, err := cdc.MarshalBinary(tx)
|
||||
require.NoError(t, err, "i: %v", i)
|
||||
|
||||
// Run a Check
|
||||
cres := bapp.CheckTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(cres.Code), "i: %v, log: %v", i, cres.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
dres := bapp.DeliverTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(dres.Code), "i: %v, log: %v", i, dres.Log)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesis(t *testing.T) {
|
||||
logger, dbs := loggerAndDBs()
|
||||
bapp := NewDemocoinApp(logger, dbs)
|
||||
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
pk := crypto.GenPrivKeyEd25519().PubKey()
|
||||
addr := pk.Address()
|
||||
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
|
||||
require.Nil(t, err)
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr,
|
||||
Coins: coins,
|
||||
}
|
||||
acc := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context
|
||||
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
|
||||
// reload app and ensure the account is still there
|
||||
bapp = NewDemocoinApp(logger, dbs)
|
||||
ctx = bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
}
|
||||
|
||||
func TestSendMsgWithAccounts(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
// Give 77 foocoin to the first key
|
||||
coins, err := sdk.ParseCoins("77foocoin")
|
||||
require.Nil(t, err)
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Sign the tx
|
||||
sequences := []int64{0}
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, sendMsg))
|
||||
tx := sdk.NewStdTx(sendMsg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
|
||||
// Check balances
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
||||
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
||||
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
||||
|
||||
// Delivering again should cause replay error
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log)
|
||||
|
||||
// bumping the txnonce number without resigning should be an auth error
|
||||
tx.Signatures[0].Sequence = 1
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log)
|
||||
|
||||
// resigning the tx with the bumped sequence should work
|
||||
sequences = []int64{1}
|
||||
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg))
|
||||
tx.Signatures[0].Signature = sig
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
|
||||
func TestMineMsg(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
// Construct genesis state
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
coins := sdk.Coins{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
"pow": map[string]uint64{
|
||||
"difficulty": 1,
|
||||
"count": 0,
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Mine and check for reward
|
||||
mineMsg1 := pow.GenerateMineMsg(addr1, 1, 2)
|
||||
SignCheckDeliver(t, bapp, mineMsg1, 0, true)
|
||||
CheckBalance(t, bapp, "1pow")
|
||||
// Mine again and check for reward
|
||||
mineMsg2 := pow.GenerateMineMsg(addr1, 2, 3)
|
||||
SignCheckDeliver(t, bapp, mineMsg2, 1, true)
|
||||
CheckBalance(t, bapp, "2pow")
|
||||
// Mine again - should be invalid
|
||||
SignCheckDeliver(t, bapp, mineMsg2, 1, false)
|
||||
CheckBalance(t, bapp, "2pow")
|
||||
|
||||
}
|
||||
|
||||
func TestQuizMsg(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
// Construct genesis state
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
coins := sdk.Coins{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Set the trend, submit a really cool quiz and check for reward
|
||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
|
||||
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
sourceChain := "source-chain"
|
||||
destChain := "dest-chain"
|
||||
|
||||
vals := []abci.Validator{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
packet := ibc.IBCPacket{
|
||||
SrcAddr: addr1,
|
||||
DestAddr: addr1,
|
||||
Coins: coins,
|
||||
SrcChain: sourceChain,
|
||||
DestChain: destChain,
|
||||
}
|
||||
|
||||
transferMsg := ibc.IBCTransferMsg{
|
||||
IBCPacket: packet,
|
||||
}
|
||||
|
||||
receiveMsg := ibc.IBCReceiveMsg{
|
||||
IBCPacket: packet,
|
||||
Relayer: addr1,
|
||||
Sequence: 0,
|
||||
}
|
||||
|
||||
SignCheckDeliver(t, bapp, transferMsg, 0, true)
|
||||
CheckBalance(t, bapp, "")
|
||||
SignCheckDeliver(t, bapp, transferMsg, 1, false)
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 2, true)
|
||||
CheckBalance(t, bapp, "10foocoin")
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
||||
}
|
||||
|
||||
// TODO describe the use of this function
|
||||
func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
||||
|
||||
// Sign the tx
|
||||
tx := sdk.NewStdTx(msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, fee, msg)),
|
||||
Sequence: seq,
|
||||
}})
|
||||
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
if expPass {
|
||||
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
res = bapp.Deliver(tx)
|
||||
if expPass {
|
||||
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
bapp.EndBlock(abci.RequestEndBlock{})
|
||||
//bapp.Commit()
|
||||
}
|
||||
|
||||
func CheckBalance(t *testing.T, bapp *DemocoinApp, balExpected string) {
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/commands"
|
||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/x/simplestake/commands"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "democli",
|
||||
Short: "Democoin light-client",
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
// disable sorting
|
||||
cobra.EnableCommandSorting = false
|
||||
|
||||
// get the codec
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
// TODO: setup keybase, viper object, etc. to be passed into
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
||||
// add standard rpc, and tx commands
|
||||
rpc.AddCommands(rootCmd)
|
||||
rootCmd.AddCommand(client.LineBreak)
|
||||
tx.AddCommands(rootCmd, cdc)
|
||||
rootCmd.AddCommand(client.LineBreak)
|
||||
|
||||
// add query/post commands (custom to binary)
|
||||
rootCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
simplestakingcmd.BondTxCmd(cdc),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
simplestakingcmd.UnbondTxCmd(cdc),
|
||||
)...)
|
||||
|
||||
// add proxy, version and key info
|
||||
rootCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.democli"))
|
||||
executor.Execute()
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "democoind",
|
||||
Short: "Democoin Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
}
|
||||
)
|
||||
|
||||
// defaultAppState sets up the app_state for the
|
||||
// default genesis file
|
||||
func defaultAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
baseJSON, err := server.DefaultGenAppState(args, addr, coinDenom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var jsonMap map[string]json.RawMessage
|
||||
err = json.Unmarshal(baseJSON, &jsonMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonMap["cool"] = json.RawMessage(`{
|
||||
"trend": "ice-cold"
|
||||
}`)
|
||||
bz, err := json.Marshal(jsonMap)
|
||||
return json.RawMessage(bz), err
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
dbMain, err := dbm.NewGoLevelDB("democoin", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbAcc, err := dbm.NewGoLevelDB("democoin-acc", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbPow, err := dbm.NewGoLevelDB("democoin-pow", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbIBC, err := dbm.NewGoLevelDB("democoin-ibc", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbStaking, err := dbm.NewGoLevelDB("democoin-staking", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbMain,
|
||||
"acc": dbAcc,
|
||||
"pow": dbPow,
|
||||
"ibc": dbIBC,
|
||||
"staking": dbStaking,
|
||||
}
|
||||
bapp := app.NewDemocoinApp(logger, dbs)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
server.AddCommands(rootCmd, defaultAppState, generateApp, context)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
|
||||
executor.Execute()
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
|
||||
)
|
||||
|
||||
var _ sdk.Account = (*AppAccount)(nil)
|
||||
|
||||
// Custom extensions for this application. This is just an example of
|
||||
// extending auth.BaseAccount with custom fields.
|
||||
//
|
||||
// This is compatible with the stock auth.AccountStore, since
|
||||
// auth.AccountStore uses the flexible go-wire library.
|
||||
type AppAccount struct {
|
||||
auth.BaseAccount
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (acc AppAccount) GetName() string { return acc.Name }
|
||||
func (acc *AppAccount) SetName(name string) { acc.Name = name }
|
||||
|
||||
// Get the AccountDecoder function for the custom AppAccount
|
||||
func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder {
|
||||
return func(accBytes []byte) (res sdk.Account, err error) {
|
||||
if len(accBytes) == 0 {
|
||||
return nil, sdk.ErrTxDecode("accBytes are empty")
|
||||
}
|
||||
acct := new(AppAccount)
|
||||
err = cdc.UnmarshalBinary(accBytes, &acct)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return acct, err
|
||||
}
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []*GenesisAccount `json:"accounts"`
|
||||
PowGenesis pow.PowGenesis `json:"pow"`
|
||||
CoolGenesis cool.CoolGenesis `json:"cool"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
type GenesisAccount struct {
|
||||
Name string `json:"name"`
|
||||
Address sdk.Address `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
|
||||
return &GenesisAccount{
|
||||
Name: aa.Name,
|
||||
Address: aa.Address,
|
||||
Coins: aa.Coins.Sort(),
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to AppAccount
|
||||
func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) {
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
}
|
||||
return &AppAccount{
|
||||
BaseAccount: baseAcc,
|
||||
Name: ga.Name,
|
||||
}, nil
|
||||
}
|
|
@ -8,10 +8,10 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
)
|
||||
|
||||
// take the coolness quiz transaction
|
||||
|
@ -24,8 +24,10 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
return errors.New("You must provide an answer")
|
||||
}
|
||||
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
// get the from address from the name flag
|
||||
from, err := builder.GetFromAddress()
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -37,7 +39,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
name := viper.GetString(client.FlagName)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,8 +60,10 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
return errors.New("You must provide an answer")
|
||||
}
|
||||
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
// get the from address from the name flag
|
||||
from, err := builder.GetFromAddress()
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -71,7 +75,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
msg := cool.NewSetTrendMsg(from, args[0])
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -1,17 +1,10 @@
|
|||
package cool
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
// Cool genesis state, containing the genesis trend
|
||||
type GenesisState struct {
|
||||
trend string
|
||||
}
|
||||
|
||||
// Keeper - handlers sets/gets of custom variables for your module
|
||||
type Keeper struct {
|
||||
ck bank.CoinKeeper
|
||||
|
@ -49,11 +42,7 @@ func (k Keeper) CheckTrend(ctx sdk.Context, guessedTrend string) bool {
|
|||
}
|
||||
|
||||
// InitGenesis - store the genesis trend
|
||||
func (k Keeper) InitGenesis(ctx sdk.Context, data json.RawMessage) error {
|
||||
var state GenesisState
|
||||
if err := json.Unmarshal(data, &state); err != nil {
|
||||
return err
|
||||
}
|
||||
k.setTrend(ctx, state.trend)
|
||||
func (k Keeper) InitGenesis(ctx sdk.Context, data CoolGenesis) error {
|
||||
k.setTrend(ctx, data.Trend)
|
||||
return nil
|
||||
}
|
|
@ -15,6 +15,11 @@ type SetTrendMsg struct {
|
|||
Cool string
|
||||
}
|
||||
|
||||
// Genesis state - specify genesis trend
|
||||
type CoolGenesis struct {
|
||||
Trend string `json:"trend"`
|
||||
}
|
||||
|
||||
// New cool message
|
||||
func NewSetTrendMsg(sender sdk.Address, cool string) SetTrendMsg {
|
||||
return SetTrendMsg{
|
|
@ -0,0 +1,66 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
func MineCmd(cdc *wire.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "mine [difficulty] [count] [nonce] [solution]",
|
||||
Short: "Mine some coins with proof-of-work!",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 4 {
|
||||
return errors.New("You must provide a difficulty, a solution, and a nonce (in that order)")
|
||||
}
|
||||
|
||||
// get from address and parse arguments
|
||||
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
difficulty, err := strconv.ParseUint(args[0], 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count, err := strconv.ParseUint(args[1], 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nonce, err := strconv.ParseUint(args[2], 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
solution := []byte(args[3])
|
||||
|
||||
msg := pow.NewMineMsg(from, difficulty, count, nonce, solution)
|
||||
|
||||
// get account name
|
||||
name := ctx.FromAddressName
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
type CodeType = sdk.CodeType
|
||||
|
||||
const (
|
||||
CodeInvalidDifficulty CodeType = 201
|
||||
CodeNonexistentDifficulty CodeType = 202
|
||||
CodeNonexistentReward CodeType = 203
|
||||
CodeNonexistentCount CodeType = 204
|
||||
CodeInvalidProof CodeType = 205
|
||||
CodeNotBelowTarget CodeType = 206
|
||||
CodeInvalidCount CodeType = 207
|
||||
CodeUnknownRequest CodeType = sdk.CodeUnknownRequest
|
||||
)
|
||||
|
||||
func codeToDefaultMsg(code CodeType) string {
|
||||
switch code {
|
||||
case CodeInvalidDifficulty:
|
||||
return "Insuffient difficulty"
|
||||
case CodeNonexistentDifficulty:
|
||||
return "Nonexistent difficulty"
|
||||
case CodeNonexistentReward:
|
||||
return "Nonexistent reward"
|
||||
case CodeNonexistentCount:
|
||||
return "Nonexistent count"
|
||||
case CodeInvalidProof:
|
||||
return "Invalid proof"
|
||||
case CodeNotBelowTarget:
|
||||
return "Not below target"
|
||||
case CodeInvalidCount:
|
||||
return "Invalid count"
|
||||
case CodeUnknownRequest:
|
||||
return "Unknown request"
|
||||
default:
|
||||
return sdk.CodeToDefaultMsg(code)
|
||||
}
|
||||
}
|
||||
|
||||
func ErrInvalidDifficulty(msg string) sdk.Error {
|
||||
return newError(CodeInvalidDifficulty, msg)
|
||||
}
|
||||
|
||||
func ErrNonexistentDifficulty() sdk.Error {
|
||||
return newError(CodeNonexistentDifficulty, "")
|
||||
}
|
||||
|
||||
func ErrNonexistentReward() sdk.Error {
|
||||
return newError(CodeNonexistentReward, "")
|
||||
}
|
||||
|
||||
func ErrNonexistentCount() sdk.Error {
|
||||
return newError(CodeNonexistentCount, "")
|
||||
}
|
||||
|
||||
func ErrInvalidProof(msg string) sdk.Error {
|
||||
return newError(CodeInvalidProof, msg)
|
||||
}
|
||||
|
||||
func ErrNotBelowTarget(msg string) sdk.Error {
|
||||
return newError(CodeNotBelowTarget, msg)
|
||||
}
|
||||
|
||||
func ErrInvalidCount(msg string) sdk.Error {
|
||||
return newError(CodeInvalidCount, msg)
|
||||
}
|
||||
|
||||
func msgOrDefaultMsg(msg string, code CodeType) string {
|
||||
if msg != "" {
|
||||
return msg
|
||||
} else {
|
||||
return codeToDefaultMsg(code)
|
||||
}
|
||||
}
|
||||
|
||||
func newError(code CodeType, msg string) sdk.Error {
|
||||
msg = msgOrDefaultMsg(msg, code)
|
||||
return sdk.NewError(code, msg)
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func (pk Keeper) Handler(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
switch msg := msg.(type) {
|
||||
case MineMsg:
|
||||
return handleMineMsg(ctx, pk, msg)
|
||||
default:
|
||||
errMsg := "Unrecognized pow Msg type: " + reflect.TypeOf(msg).Name()
|
||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||
}
|
||||
}
|
||||
|
||||
func handleMineMsg(ctx sdk.Context, pk Keeper, msg MineMsg) sdk.Result {
|
||||
|
||||
// precondition: msg has passed ValidateBasic
|
||||
|
||||
newDiff, newCount, err := pk.CheckValid(ctx, msg.Difficulty, msg.Count)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
// commented for now, makes testing difficult
|
||||
// TODO figure out a better test method that allows early CheckTx return
|
||||
/*
|
||||
if ctx.IsCheckTx() {
|
||||
return sdk.Result{} // TODO
|
||||
}
|
||||
*/
|
||||
|
||||
err = pk.ApplyValid(ctx, msg.Sender, newDiff, newCount)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
return sdk.Result{}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
func TestPowHandler(t *testing.T) {
|
||||
ms, capKey := setupMultiStore()
|
||||
|
||||
am := auth.NewAccountMapper(capKey, &auth.BaseAccount{})
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||
config := NewPowConfig("pow", int64(1))
|
||||
ck := bank.NewCoinKeeper(am)
|
||||
keeper := NewKeeper(capKey, config, ck)
|
||||
|
||||
handler := keeper.Handler
|
||||
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
count := uint64(1)
|
||||
difficulty := uint64(2)
|
||||
|
||||
err := keeper.InitGenesis(ctx, PowGenesis{uint64(1), uint64(0)})
|
||||
assert.Nil(t, err)
|
||||
|
||||
nonce, proof := mine(addr, count, difficulty)
|
||||
msg := NewMineMsg(addr, difficulty, count, nonce, proof)
|
||||
|
||||
result := handler(ctx, msg)
|
||||
assert.Equal(t, result, sdk.Result{})
|
||||
|
||||
newDiff, err := keeper.GetLastDifficulty(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, newDiff, uint64(2))
|
||||
|
||||
newCount, err := keeper.GetLastCount(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, newCount, uint64(1))
|
||||
|
||||
// todo assert correct coin change, awaiting https://github.com/cosmos/cosmos-sdk/pull/691
|
||||
|
||||
difficulty = uint64(4)
|
||||
nonce, proof = mine(addr, count, difficulty)
|
||||
msg = NewMineMsg(addr, difficulty, count, nonce, proof)
|
||||
|
||||
result = handler(ctx, msg)
|
||||
assert.NotEqual(t, result, sdk.Result{})
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
// module users must specify coin denomination and reward (constant) per PoW solution
|
||||
type PowConfig struct {
|
||||
Denomination string
|
||||
Reward int64
|
||||
}
|
||||
|
||||
// genesis info must specify starting difficulty and starting count
|
||||
type PowGenesis struct {
|
||||
Difficulty uint64 `json:"difficulty"`
|
||||
Count uint64 `json:"count"`
|
||||
}
|
||||
|
||||
type Keeper struct {
|
||||
key sdk.StoreKey
|
||||
config PowConfig
|
||||
ck bank.CoinKeeper
|
||||
}
|
||||
|
||||
func NewPowConfig(denomination string, reward int64) PowConfig {
|
||||
return PowConfig{denomination, reward}
|
||||
}
|
||||
|
||||
func NewKeeper(key sdk.StoreKey, config PowConfig, ck bank.CoinKeeper) Keeper {
|
||||
return Keeper{key, config, ck}
|
||||
}
|
||||
|
||||
func (pk Keeper) InitGenesis(ctx sdk.Context, genesis PowGenesis) error {
|
||||
pk.SetLastDifficulty(ctx, genesis.Difficulty)
|
||||
pk.SetLastCount(ctx, genesis.Count)
|
||||
return nil
|
||||
}
|
||||
|
||||
var lastDifficultyKey = []byte("lastDifficultyKey")
|
||||
|
||||
func (pk Keeper) GetLastDifficulty(ctx sdk.Context) (uint64, error) {
|
||||
store := ctx.KVStore(pk.key)
|
||||
stored := store.Get(lastDifficultyKey)
|
||||
if stored == nil {
|
||||
panic("no stored difficulty")
|
||||
} else {
|
||||
return strconv.ParseUint(string(stored), 0, 64)
|
||||
}
|
||||
}
|
||||
|
||||
func (pk Keeper) SetLastDifficulty(ctx sdk.Context, diff uint64) {
|
||||
store := ctx.KVStore(pk.key)
|
||||
store.Set(lastDifficultyKey, []byte(strconv.FormatUint(diff, 16)))
|
||||
}
|
||||
|
||||
var countKey = []byte("count")
|
||||
|
||||
func (pk Keeper) GetLastCount(ctx sdk.Context) (uint64, error) {
|
||||
store := ctx.KVStore(pk.key)
|
||||
stored := store.Get(countKey)
|
||||
if stored == nil {
|
||||
panic("no stored count")
|
||||
} else {
|
||||
return strconv.ParseUint(string(stored), 0, 64)
|
||||
}
|
||||
}
|
||||
|
||||
func (pk Keeper) SetLastCount(ctx sdk.Context, count uint64) {
|
||||
store := ctx.KVStore(pk.key)
|
||||
store.Set(countKey, []byte(strconv.FormatUint(count, 16)))
|
||||
}
|
||||
|
||||
func (pk Keeper) CheckValid(ctx sdk.Context, difficulty uint64, count uint64) (uint64, uint64, sdk.Error) {
|
||||
|
||||
lastDifficulty, err := pk.GetLastDifficulty(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, ErrNonexistentDifficulty()
|
||||
}
|
||||
|
||||
newDifficulty := lastDifficulty + 1
|
||||
|
||||
lastCount, err := pk.GetLastCount(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, ErrNonexistentCount()
|
||||
}
|
||||
|
||||
newCount := lastCount + 1
|
||||
|
||||
if count != newCount {
|
||||
return 0, 0, ErrInvalidCount(fmt.Sprintf("invalid count: was %d, should have been %d", count, newCount))
|
||||
}
|
||||
|
||||
if difficulty != newDifficulty {
|
||||
return 0, 0, ErrInvalidDifficulty(fmt.Sprintf("invalid difficulty: was %d, should have been %d", difficulty, newDifficulty))
|
||||
}
|
||||
|
||||
return newDifficulty, newCount, nil
|
||||
|
||||
}
|
||||
|
||||
func (pk Keeper) ApplyValid(ctx sdk.Context, sender sdk.Address, newDifficulty uint64, newCount uint64) sdk.Error {
|
||||
_, ckErr := pk.ck.AddCoins(ctx, sender, []sdk.Coin{sdk.Coin{pk.config.Denomination, pk.config.Reward}})
|
||||
if ckErr != nil {
|
||||
return ckErr
|
||||
}
|
||||
pk.SetLastDifficulty(ctx, newDifficulty)
|
||||
pk.SetLastCount(ctx, newCount)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
// possibly share this kind of setup functionality between module testsuites?
|
||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
|
||||
db := dbm.NewMemDB()
|
||||
capKey := sdk.NewKVStoreKey("capkey")
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
||||
ms.LoadLatestVersion()
|
||||
|
||||
return ms, capKey
|
||||
}
|
||||
|
||||
func TestPowKeeperGetSet(t *testing.T) {
|
||||
ms, capKey := setupMultiStore()
|
||||
|
||||
am := auth.NewAccountMapper(capKey, &auth.BaseAccount{})
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||
config := NewPowConfig("pow", int64(1))
|
||||
ck := bank.NewCoinKeeper(am)
|
||||
keeper := NewKeeper(capKey, config, ck)
|
||||
|
||||
err := keeper.InitGenesis(ctx, PowGenesis{uint64(1), uint64(0)})
|
||||
assert.Nil(t, err)
|
||||
|
||||
res, err := keeper.GetLastDifficulty(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, res, uint64(1))
|
||||
|
||||
keeper.SetLastDifficulty(ctx, 2)
|
||||
|
||||
res, err = keeper.GetLastDifficulty(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, res, uint64(2))
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
func GenerateMineMsg(sender sdk.Address, count uint64, difficulty uint64) MineMsg {
|
||||
nonce, hash := mine(sender, count, difficulty)
|
||||
return NewMineMsg(sender, difficulty, count, nonce, hash)
|
||||
}
|
||||
|
||||
func hash(sender sdk.Address, count uint64, nonce uint64) []byte {
|
||||
var bytes []byte
|
||||
bytes = append(bytes, []byte(sender)...)
|
||||
countBytes := strconv.FormatUint(count, 16)
|
||||
bytes = append(bytes, countBytes...)
|
||||
nonceBytes := strconv.FormatUint(nonce, 16)
|
||||
bytes = append(bytes, nonceBytes...)
|
||||
hash := crypto.Sha256(bytes)
|
||||
// uint64, so we just use the first 8 bytes of the hash
|
||||
// this limits the range of possible difficulty values (as compared to uint256), but fine for proof-of-concept
|
||||
ret := make([]byte, hex.EncodedLen(len(hash)))
|
||||
hex.Encode(ret, hash)
|
||||
return ret[:16]
|
||||
}
|
||||
|
||||
func mine(sender sdk.Address, count uint64, difficulty uint64) (uint64, []byte) {
|
||||
target := math.MaxUint64 / difficulty
|
||||
for nonce := uint64(0); ; nonce++ {
|
||||
hash := hash(sender, count, nonce)
|
||||
hashuint, err := strconv.ParseUint(string(hash), 16, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if hashuint < target {
|
||||
return nonce, hash
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// MineMsg - mine some coins with PoW
|
||||
type MineMsg struct {
|
||||
Sender sdk.Address `json:"sender"`
|
||||
Difficulty uint64 `json:"difficulty"`
|
||||
Count uint64 `json:"count"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Proof []byte `json:"proof"`
|
||||
}
|
||||
|
||||
// enforce the msg type at compile time
|
||||
var _ sdk.Msg = MineMsg{}
|
||||
|
||||
// NewMineMsg - construct mine message
|
||||
func NewMineMsg(sender sdk.Address, difficulty uint64, count uint64, nonce uint64, proof []byte) MineMsg {
|
||||
return MineMsg{sender, difficulty, count, nonce, proof}
|
||||
}
|
||||
|
||||
func (msg MineMsg) Type() string { return "pow" }
|
||||
func (msg MineMsg) Get(key interface{}) (value interface{}) { return nil }
|
||||
func (msg MineMsg) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
|
||||
func (msg MineMsg) String() string {
|
||||
return fmt.Sprintf("MineMsg{Sender: %v, Difficulty: %d, Count: %d, Nonce: %d, Proof: %s}", msg.Sender, msg.Difficulty, msg.Count, msg.Nonce, msg.Proof)
|
||||
}
|
||||
|
||||
func (msg MineMsg) ValidateBasic() sdk.Error {
|
||||
// check hash
|
||||
var data []byte
|
||||
// hash must include sender, so no other users can race the tx
|
||||
data = append(data, []byte(msg.Sender)...)
|
||||
countBytes := strconv.FormatUint(msg.Count, 16)
|
||||
// hash must include count so proof-of-work solutions cannot be replayed
|
||||
data = append(data, countBytes...)
|
||||
nonceBytes := strconv.FormatUint(msg.Nonce, 16)
|
||||
data = append(data, nonceBytes...)
|
||||
hash := crypto.Sha256(data)
|
||||
hashHex := make([]byte, hex.EncodedLen(len(hash)))
|
||||
hex.Encode(hashHex, hash)
|
||||
hashHex = hashHex[:16]
|
||||
if !bytes.Equal(hashHex, msg.Proof) {
|
||||
return ErrInvalidProof(fmt.Sprintf("hashHex: %s, proof: %s", hashHex, msg.Proof))
|
||||
}
|
||||
|
||||
// check proof below difficulty
|
||||
// difficulty is linear - 1 = all hashes, 2 = half of hashes, 3 = third of hashes, etc
|
||||
target := math.MaxUint64 / msg.Difficulty
|
||||
hashUint, err := strconv.ParseUint(string(msg.Proof), 16, 64)
|
||||
if err != nil {
|
||||
return ErrInvalidProof(fmt.Sprintf("proof: %s", msg.Proof))
|
||||
}
|
||||
if hashUint >= target {
|
||||
return ErrNotBelowTarget(fmt.Sprintf("hashuint: %d, target: %d", hashUint, target))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg MineMsg) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package pow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func TestNewMineMsg(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 0, 0, 0, []byte("")}
|
||||
equiv := NewMineMsg(addr, 0, 0, 0, []byte(""))
|
||||
assert.Equal(t, msg, equiv, "%s != %s", msg, equiv)
|
||||
}
|
||||
|
||||
func TestMineMsgType(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 0, 0, 0, []byte("")}
|
||||
assert.Equal(t, msg.Type(), "pow")
|
||||
}
|
||||
|
||||
func TestMineMsgValidation(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
otherAddr := sdk.Address([]byte("another"))
|
||||
count := uint64(0)
|
||||
for difficulty := uint64(1); difficulty < 1000; difficulty += 100 {
|
||||
count += 1
|
||||
nonce, proof := mine(addr, count, difficulty)
|
||||
msg := MineMsg{addr, difficulty, count, nonce, proof}
|
||||
err := msg.ValidateBasic()
|
||||
assert.Nil(t, err, "error with difficulty %d - %+v", difficulty, err)
|
||||
|
||||
msg.Count += 1
|
||||
err = msg.ValidateBasic()
|
||||
assert.NotNil(t, err, "count was wrong, should have thrown error with msg %s", msg)
|
||||
|
||||
msg.Count -= 1
|
||||
msg.Nonce += 1
|
||||
err = msg.ValidateBasic()
|
||||
assert.NotNil(t, err, "nonce was wrong, should have thrown error with msg %s", msg)
|
||||
|
||||
msg.Nonce -= 1
|
||||
msg.Sender = otherAddr
|
||||
err = msg.ValidateBasic()
|
||||
assert.NotNil(t, err, "sender was wrong, should have thrown error with msg %s", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMineMsgString(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 0, 0, 0, []byte("abc")}
|
||||
res := msg.String()
|
||||
assert.Equal(t, res, "MineMsg{Sender: 73656E646572, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}")
|
||||
}
|
||||
|
||||
func TestMineMsgGet(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 0, 0, 0, []byte("")}
|
||||
res := msg.Get(nil)
|
||||
assert.Nil(t, res)
|
||||
}
|
||||
|
||||
func TestMineMsgGetSignBytes(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 1, 1, 1, []byte("abc")}
|
||||
res := msg.GetSignBytes()
|
||||
assert.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`)
|
||||
}
|
||||
|
||||
func TestMineMsgGetSigners(t *testing.T) {
|
||||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MineMsg{addr, 1, 1, 1, []byte("abc")}
|
||||
res := msg.GetSigners()
|
||||
assert.Equal(t, fmt.Sprintf("%v", res), "[73656E646572]")
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
Gaiad is the abci application, which can be run stand-alone, or in-process with tendermint.
|
||||
|
||||
Gaiacli is a client application, which connects to tendermint rpc, and sends transactions and queries the state. It uses light-client proofs to guarantee the results even if it doesn't have 100% trust in the node it connects to.
|
|
@ -1,71 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
// gaiadCmd is the entry point for this binary
|
||||
var (
|
||||
gaiadCmd = &cobra.Command{
|
||||
Use: "gaiad",
|
||||
Short: "Gaia Daemon (server)",
|
||||
}
|
||||
)
|
||||
|
||||
// defaultOptions sets up the app_options for the
|
||||
// default genesis file
|
||||
func defaultOptions(args []string) (json.RawMessage, error) {
|
||||
addr, secret, err := server.GenerateCoinKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("Secret phrase to access coins:")
|
||||
fmt.Println(secret)
|
||||
|
||||
opts := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr)
|
||||
return json.RawMessage(opts), nil
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
// TODO: set this to something real
|
||||
app := new(baseapp.BaseApp)
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
||||
With("module", "main")
|
||||
|
||||
gaiadCmd.AddCommand(
|
||||
server.InitCmd(defaultOptions, logger),
|
||||
server.StartCmd(generateApp, logger),
|
||||
server.UnsafeResetAllCmd(logger),
|
||||
version.VersionCmd,
|
||||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(gaiadCmd, "GA", os.ExpandEnv("$HOME/.gaiad"))
|
||||
executor.Execute()
|
||||
}
|
|
@ -3,8 +3,12 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/abci/server"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -17,7 +21,8 @@ func main() {
|
|||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "main")
|
||||
|
||||
db, err := dbm.NewGoLevelDB("basecoind", "data")
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
db, err := dbm.NewGoLevelDB("basecoind", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
|
@ -30,13 +35,13 @@ func main() {
|
|||
var baseApp = bam.NewBaseApp("kvstore", logger, db)
|
||||
|
||||
// Set mounts for BaseApp's MultiStore.
|
||||
baseApp.MountStore(capKeyMainStore, sdk.StoreTypeIAVL)
|
||||
baseApp.MountStoresIAVL(capKeyMainStore)
|
||||
|
||||
// Set Tx decoder
|
||||
baseApp.SetTxDecoder(decodeTx)
|
||||
|
||||
// Set a handler Route.
|
||||
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore), nil)
|
||||
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore))
|
||||
|
||||
// Load latest version.
|
||||
if err := baseApp.LoadLatestVersion(capKeyMainStore); err != nil {
|
||||
|
|
|
@ -38,7 +38,7 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
|||
baseApp.SetInitChainer(InitChainer(capKeyMainStore))
|
||||
|
||||
// Set a handler Route.
|
||||
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore), nil)
|
||||
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore))
|
||||
|
||||
// Load latest version.
|
||||
if err := baseApp.LoadLatestVersion(capKeyMainStore); err != nil {
|
||||
|
@ -106,7 +106,7 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci
|
|||
// GenInitOptions can be passed into InitCmd,
|
||||
// returns a static string of a few key-values that can be parsed
|
||||
// by InitChainer
|
||||
func GenInitOptions(args []string) (json.RawMessage, error) {
|
||||
func GenInitOptions(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
opts := []byte(`{
|
||||
"values": [
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestInitApp(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// initialize it future-way
|
||||
opts, err := GenInitOptions(nil)
|
||||
opts, err := GenInitOptions(nil, nil, "")
|
||||
require.NoError(t, err)
|
||||
req := abci.RequestInitChain{AppStateBytes: opts}
|
||||
app.InitChain(req)
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
// +build scripts
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/tendermint/go-wire"
|
||||
_ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
|
||||
"github.com/tendermint/tendermint/rpc/lib/client"
|
||||
"github.com/tendermint/tendermint/rpc/lib/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ws := rpcclient.NewWSClient(os.Args[1]+":46657", "/websocket")
|
||||
|
||||
_, err := ws.Start()
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
|
||||
// Read a bunch of responses
|
||||
go func() {
|
||||
for {
|
||||
res, ok := <-ws.ResultsCh
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
//fmt.Println(counter, "res:", Blue(string(res)))
|
||||
var result []interface{}
|
||||
err := json.Unmarshal([]byte(string(res)), &result)
|
||||
if err != nil {
|
||||
Exit("Error unmarshalling block: " + err.Error())
|
||||
}
|
||||
height := result[1].(map[string]interface{})["block"].(map[string]interface{})["header"].(map[string]interface{})["height"]
|
||||
txs := result[1].(map[string]interface{})["block"].(map[string]interface{})["data"].(map[string]interface{})["txs"]
|
||||
if len(txs.([]interface{})) > 0 {
|
||||
fmt.Println(">>", height, txs)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 100000; i++ {
|
||||
request := rpctypes.NewRPCRequest("fakeid", "block", Arr(i))
|
||||
reqBytes := wire.JSONBytes(request)
|
||||
err = ws.WriteMessage(websocket.TextMessage, reqBytes)
|
||||
if err != nil {
|
||||
cmn.Exit("writing websocket request: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 1000)
|
||||
|
||||
ws.Stop()
|
||||
}
|
||||
*/
|
163
server/init.go
163
server/init.go
|
@ -2,53 +2,63 @@ package server
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
"github.com/tendermint/go-crypto/keys/words"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
)
|
||||
|
||||
// testnetInformation contains the info necessary
|
||||
// to setup a testnet including this account and validator.
|
||||
type testnetInformation struct {
|
||||
Secret string `json:"secret"`
|
||||
|
||||
ChainID string `json:"chain_id"`
|
||||
Account string `json:"account"`
|
||||
Validator tmtypes.GenesisValidator `json:"validator"`
|
||||
NodeID p2p.ID `json:"node_id"`
|
||||
}
|
||||
|
||||
type initCmd struct {
|
||||
genAppState GenAppState
|
||||
context *Context
|
||||
}
|
||||
|
||||
// InitCmd will initialize all files for tendermint,
|
||||
// along with proper app_state.
|
||||
// The application can pass in a function to generate
|
||||
// proper state. And may want to use GenerateCoinKey
|
||||
// to create default account(s).
|
||||
func InitCmd(gen GenAppState, logger log.Logger) *cobra.Command {
|
||||
func InitCmd(gen GenAppState, ctx *Context) *cobra.Command {
|
||||
cmd := initCmd{
|
||||
genAppState: gen,
|
||||
logger: logger,
|
||||
context: ctx,
|
||||
}
|
||||
return &cobra.Command{
|
||||
cobraCmd := cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis files",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
// GenAppState can parse command-line and flag to
|
||||
// generate default app_state for the genesis file.
|
||||
// This is application-specific
|
||||
type GenAppState func(args []string) (json.RawMessage, error)
|
||||
|
||||
type initCmd struct {
|
||||
genAppState GenAppState
|
||||
logger log.Logger
|
||||
return &cobraCmd
|
||||
}
|
||||
|
||||
func (c initCmd) run(cmd *cobra.Command, args []string) error {
|
||||
// Store testnet information as we go
|
||||
var testnetInfo testnetInformation
|
||||
|
||||
// Run the basic tendermint initialization,
|
||||
// set up a default genesis with no app_options
|
||||
config, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.initTendermintFiles(config)
|
||||
config := c.context.Config
|
||||
err := c.initTendermintFiles(config, &testnetInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,36 +68,61 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Now, we want to add the custom app_state
|
||||
appState, err := c.genAppState(args)
|
||||
// generate secrete and address
|
||||
addr, secret, err := GenerateCoinKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var DEFAULT_DENOM = "mycoin"
|
||||
|
||||
// Now, we want to add the custom app_state
|
||||
appState, err := c.genAppState(args, addr, DEFAULT_DENOM)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
testnetInfo.Secret = secret
|
||||
testnetInfo.Account = addr.String()
|
||||
|
||||
// And add them to the genesis file
|
||||
genFile := config.GenesisFile()
|
||||
return addGenesisState(genFile, appState)
|
||||
if err := addGenesisState(genFile, appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
testnetInfo.NodeID = nodeKey.ID()
|
||||
out, err := json.MarshalIndent(testnetInfo, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
// This was copied from tendermint/cmd/tendermint/commands/init.go
|
||||
// so we could pass in the config and the logger.
|
||||
func (c initCmd) initTendermintFiles(config *cfg.Config) error {
|
||||
func (c initCmd) initTendermintFiles(config *cfg.Config, info *testnetInformation) error {
|
||||
// private validator
|
||||
privValFile := config.PrivValidatorFile()
|
||||
var privValidator *tmtypes.PrivValidatorFS
|
||||
if cmn.FileExists(privValFile) {
|
||||
privValidator = tmtypes.LoadPrivValidatorFS(privValFile)
|
||||
c.logger.Info("Found private validator", "path", privValFile)
|
||||
c.context.Logger.Info("Found private validator", "path", privValFile)
|
||||
} else {
|
||||
privValidator = tmtypes.GenPrivValidatorFS(privValFile)
|
||||
privValidator.Save()
|
||||
c.logger.Info("Generated private validator", "path", privValFile)
|
||||
c.context.Logger.Info("Generated private validator", "path", privValFile)
|
||||
}
|
||||
|
||||
// genesis file
|
||||
genFile := config.GenesisFile()
|
||||
if cmn.FileExists(genFile) {
|
||||
c.logger.Info("Found genesis file", "path", genFile)
|
||||
c.context.Logger.Info("Found genesis file", "path", genFile)
|
||||
} else {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
|
||||
|
@ -100,11 +135,52 @@ func (c initCmd) initTendermintFiles(config *cfg.Config) error {
|
|||
if err := genDoc.SaveAs(genFile); err != nil {
|
||||
return err
|
||||
}
|
||||
c.logger.Info("Generated genesis file", "path", genFile)
|
||||
c.context.Logger.Info("Generated genesis file", "path", genFile)
|
||||
}
|
||||
|
||||
// reload the config file and find our validator info
|
||||
loadedDoc, err := tmtypes.GenesisDocFromFile(genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, validator := range loadedDoc.Validators {
|
||||
if validator.PubKey == privValidator.GetPubKey() {
|
||||
info.Validator = validator
|
||||
}
|
||||
}
|
||||
info.ChainID = loadedDoc.ChainID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// GenAppState takes the command line args, as well
|
||||
// as an address and coin denomination.
|
||||
// It returns a default app_state to be included in
|
||||
// in the genesis file.
|
||||
// This is application-specific
|
||||
type GenAppState func(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error)
|
||||
|
||||
// DefaultGenAppState expects two args: an account address
|
||||
// and a coin denomination, and gives lots of coins to that address.
|
||||
func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
opts := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "%s",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr.String(), coinDenom)
|
||||
return json.RawMessage(opts), nil
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// GenesisDoc involves some tendermint-specific structures we don't
|
||||
// want to parse, so we just grab it into a raw object format,
|
||||
// so we can add one line.
|
||||
|
@ -130,3 +206,30 @@ func addGenesisState(filename string, appState json.RawMessage) error {
|
|||
|
||||
return ioutil.WriteFile(filename, out, 0600)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// GenerateCoinKey returns the address of a public key,
|
||||
// along with the secret phrase to recover the private key.
|
||||
// You can give coins to this address and return the recovery
|
||||
// phrase to the user to access them.
|
||||
func GenerateCoinKey() (sdk.Address, string, error) {
|
||||
// construct an in-memory key store
|
||||
codec, err := words.LoadCodec("english")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
keybase := keys.New(
|
||||
dbm.NewMemDB(),
|
||||
codec,
|
||||
)
|
||||
|
||||
// generate a private key, with recovery phrase
|
||||
info, secret, err := keybase.Create("name", "pass", keys.AlgoEd25519)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
addr := info.PubKey.Address()
|
||||
return addr, secret, nil
|
||||
}
|
||||
|
|
|
@ -8,13 +8,17 @@ import (
|
|||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/mock"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cmd := InitCmd(mock.GenInitOptions, logger)
|
||||
err := cmd.RunE(nil, nil)
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
"github.com/tendermint/go-crypto/keys/words"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenerateCoinKey returns the address of a public key,
|
||||
// along with the secret phrase to recover the private key.
|
||||
// You can give coins to this address and return the recovery
|
||||
// phrase to the user to access them.
|
||||
func GenerateCoinKey() (sdk.Address, string, error) {
|
||||
// construct an in-memory key store
|
||||
codec, err := words.LoadCodec("english")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
keybase := keys.New(
|
||||
dbm.NewMemDB(),
|
||||
codec,
|
||||
)
|
||||
|
||||
// generate a private key, with recovery phrase
|
||||
info, secret, err := keybase.Create("name", "pass", keys.AlgoEd25519)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
addr := info.PubKey.Address()
|
||||
return addr, secret, nil
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// UnsafeResetAllCmd - extension of the tendermint command, resets initialization
|
||||
func UnsafeResetAllCmd(logger log.Logger) *cobra.Command {
|
||||
cmd := resetAll{logger}
|
||||
return &cobra.Command{
|
||||
Use: "unsafe_reset_all",
|
||||
Short: "Reset all blockchain data",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type resetAll struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (r resetAll) run(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), r.logger)
|
||||
return nil
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// ShowNodeIdCmd - ported from Tendermint, dump node ID to stdout
|
||||
func ShowNodeIdCmd(logger log.Logger) *cobra.Command {
|
||||
cmd := showNodeId{logger}
|
||||
return &cobra.Command{
|
||||
Use: "show_node_id",
|
||||
Short: "Show this node's ID",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type showNodeId struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (s showNodeId) run(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(nodeKey.ID())
|
||||
return nil
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// ShowValidator - ported from Tendermint, show this node's validator info
|
||||
func ShowValidatorCmd(logger log.Logger) *cobra.Command {
|
||||
cmd := showValidator{logger}
|
||||
return &cobra.Command{
|
||||
Use: "show_validator",
|
||||
Short: "Show this node's validator info",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type showValidator struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (s showValidator) run(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(cfg.PrivValidatorFile())
|
||||
pubKeyJSONBytes, err := data.ToJSON(privValidator.PubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(pubKeyJSONBytes))
|
||||
return nil
|
||||
}
|
|
@ -21,16 +21,16 @@ const (
|
|||
flagAddress = "address"
|
||||
)
|
||||
|
||||
// appGenerator lets us lazily initialize app, using home dir
|
||||
// AppCreator lets us lazily initialize app, using home dir
|
||||
// and other flags (?) to start
|
||||
type appCreator func(string, log.Logger) (abci.Application, error)
|
||||
type AppCreator func(string, log.Logger) (abci.Application, error)
|
||||
|
||||
// StartCmd runs the service passed in, either
|
||||
// stand-alone, or in-process with tendermint
|
||||
func StartCmd(app appCreator, logger log.Logger) *cobra.Command {
|
||||
func StartCmd(app AppCreator, ctx *Context) *cobra.Command {
|
||||
start := startCmd{
|
||||
appCreator: app,
|
||||
logger: logger,
|
||||
context: ctx,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "start",
|
||||
|
@ -48,16 +48,16 @@ func StartCmd(app appCreator, logger log.Logger) *cobra.Command {
|
|||
}
|
||||
|
||||
type startCmd struct {
|
||||
appCreator appCreator
|
||||
logger log.Logger
|
||||
appCreator AppCreator
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (s startCmd) run(cmd *cobra.Command, args []string) error {
|
||||
if !viper.GetBool(flagWithTendermint) {
|
||||
s.logger.Info("Starting ABCI without Tendermint")
|
||||
s.context.Logger.Info("Starting ABCI without Tendermint")
|
||||
return s.startStandAlone()
|
||||
}
|
||||
s.logger.Info("Starting ABCI with Tendermint")
|
||||
s.context.Logger.Info("Starting ABCI with Tendermint")
|
||||
return s.startInProcess()
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ func (s startCmd) startStandAlone() error {
|
|||
// Generate the app in the proper dir
|
||||
addr := viper.GetString(flagAddress)
|
||||
home := viper.GetString("home")
|
||||
app, err := s.appCreator(home, s.logger)
|
||||
app, err := s.appCreator(home, s.context.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func (s startCmd) startStandAlone() error {
|
|||
if err != nil {
|
||||
return errors.Errorf("Error creating listener: %v\n", err)
|
||||
}
|
||||
svr.SetLogger(s.logger.With("module", "abci-server"))
|
||||
svr.SetLogger(s.context.Logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
// Wait forever
|
||||
|
@ -86,13 +86,9 @@ func (s startCmd) startStandAlone() error {
|
|||
}
|
||||
|
||||
func (s startCmd) startInProcess() error {
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg := s.context.Config
|
||||
home := cfg.RootDir
|
||||
app, err := s.appCreator(home, s.logger)
|
||||
app, err := s.appCreator(home, s.context.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -103,7 +99,7 @@ func (s startCmd) startInProcess() error {
|
|||
proxy.NewLocalClientCreator(app),
|
||||
node.DefaultGenesisDocProviderFunc(cfg),
|
||||
node.DefaultDBProvider,
|
||||
s.logger.With("module", "node"))
|
||||
s.context.Logger.With("module", "node"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
// "os"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -9,47 +10,56 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/mock"
|
||||
"github.com/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
func TestStartStandAlone(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
home, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
defer func() {
|
||||
os.RemoveAll(home)
|
||||
}()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
initCmd := InitCmd(mock.GenInitOptions, logger)
|
||||
err := initCmd.RunE(nil, nil)
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// set up app and start up
|
||||
viper.Set(flagWithTendermint, false)
|
||||
viper.Set(flagAddress, "localhost:11122")
|
||||
startCmd := StartCmd(mock.NewApp, logger)
|
||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
||||
timeout := time.Duration(3) * time.Second
|
||||
app, err := mock.NewApp(home, logger)
|
||||
require.Nil(t, err)
|
||||
svr, err := server.NewServer(FreeTCPAddr(t), "socket", app)
|
||||
require.Nil(t, err, "Error creating listener")
|
||||
svr.SetLogger(logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
RunOrTimeout(startCmd, timeout, t)
|
||||
timer := time.NewTimer(time.Duration(5) * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
svr.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestStartWithTendermint(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
||||
With("module", "mock-cmd")
|
||||
// logger := log.NewNopLogger()
|
||||
initCmd := InitCmd(mock.GenInitOptions, logger)
|
||||
err := initCmd.RunE(nil, nil)
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// set up app and start up
|
||||
viper.Set(flagWithTendermint, true)
|
||||
startCmd := StartCmd(mock.NewApp, logger)
|
||||
startCmd := StartCmd(mock.NewApp, ctx)
|
||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
||||
timeout := time.Duration(3) * time.Second
|
||||
timeout := time.Duration(5) * time.Second
|
||||
|
||||
//a, _ := startCmd.Flags().GetString(flagAddress)
|
||||
//panic(a)
|
||||
|
||||
RunOrTimeout(startCmd, timeout, t)
|
||||
close(RunOrTimeout(startCmd, timeout, t))
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
@ -44,14 +45,18 @@ func setupViper(t *testing.T) func() {
|
|||
func StartServer(t *testing.T) chan error {
|
||||
defer setupViper(t)()
|
||||
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
|
||||
// init server
|
||||
initCmd := InitCmd(mock.GenInitOptions, log.NewNopLogger())
|
||||
err := initCmd.RunE(nil, nil)
|
||||
ctx := NewContext(cfg, log.NewNopLogger())
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// start server
|
||||
viper.Set(flagWithTendermint, true)
|
||||
startCmd := StartCmd(mock.NewApp, log.NewNopLogger())
|
||||
startCmd := StartCmd(mock.NewApp, ctx)
|
||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
||||
startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address
|
||||
timeout := time.Duration(3) * time.Second
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout
|
||||
func ShowNodeIDCmd(ctx *Context) *cobra.Command {
|
||||
cmd := showNodeId{ctx}
|
||||
return &cobra.Command{
|
||||
Use: "show_node_id",
|
||||
Short: "Show this node's ID",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type showNodeId struct {
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (s showNodeId) run(cmd *cobra.Command, args []string) error {
|
||||
cfg := s.context.Config
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(nodeKey.ID())
|
||||
return nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// ShowValidator - ported from Tendermint, show this node's validator info
|
||||
func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
||||
cmd := showValidator{ctx}
|
||||
return &cobra.Command{
|
||||
Use: "show_validator",
|
||||
Short: "Show this node's validator info",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type showValidator struct {
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (s showValidator) run(cmd *cobra.Command, args []string) error {
|
||||
cfg := s.context.Config
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(cfg.PrivValidatorFile())
|
||||
pubKeyJSONBytes, err := data.ToJSON(privValidator.PubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(pubKeyJSONBytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// UnsafeResetAllCmd - extension of the tendermint command, resets initialization
|
||||
func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
|
||||
cmd := resetAll{ctx}
|
||||
return &cobra.Command{
|
||||
Use: "unsafe_reset_all",
|
||||
Short: "Reset all blockchain data",
|
||||
RunE: cmd.run,
|
||||
}
|
||||
}
|
||||
|
||||
type resetAll struct {
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (r resetAll) run(cmd *cobra.Command, args []string) error {
|
||||
cfg := r.context.Config
|
||||
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), r.context.Logger)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
tmflags "github.com/tendermint/tmlibs/cli/flags"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Config *cfg.Config
|
||||
Logger log.Logger
|
||||
}
|
||||
|
||||
func NewDefaultContext() *Context {
|
||||
return NewContext(
|
||||
cfg.DefaultConfig(),
|
||||
log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
|
||||
)
|
||||
}
|
||||
|
||||
func NewContext(config *cfg.Config, logger log.Logger) *Context {
|
||||
return &Context{config, logger}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// PersistentPreRunEFn returns a PersistentPreRunE function for cobra
|
||||
// that initailizes the passed in context with a properly configured
|
||||
// logger and config objecy
|
||||
func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
if cmd.Name() == version.VersionCmd.Name() {
|
||||
return nil
|
||||
}
|
||||
config, err := tcmd.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if viper.GetBool(cli.TraceFlag) {
|
||||
logger = log.NewTracingLogger(logger)
|
||||
}
|
||||
logger = logger.With("module", "main")
|
||||
context.Config = config
|
||||
context.Logger = logger
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func AddCommands(
|
||||
rootCmd *cobra.Command,
|
||||
appState GenAppState, appCreator AppCreator,
|
||||
context *Context) {
|
||||
|
||||
rootCmd.PersistentFlags().String("log_level", context.Config.LogLevel, "Log level")
|
||||
|
||||
rootCmd.AddCommand(
|
||||
InitCmd(appState, context),
|
||||
StartCmd(appCreator, context),
|
||||
UnsafeResetAllCmd(context),
|
||||
ShowNodeIDCmd(context),
|
||||
ShowValidatorCmd(context),
|
||||
version.VersionCmd,
|
||||
)
|
||||
}
|
|
@ -144,7 +144,7 @@ func (st *iavlStore) ReverseSubspaceIterator(prefix []byte) Iterator {
|
|||
func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||
if len(req.Data) == 0 {
|
||||
msg := "Query cannot be zero length"
|
||||
return sdk.ErrTxDecode(msg).Result().ToQuery()
|
||||
return sdk.ErrTxDecode(msg).QueryResult()
|
||||
}
|
||||
|
||||
tree := st.tree
|
||||
|
@ -178,7 +178,7 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
|||
|
||||
default:
|
||||
msg := fmt.Sprintf("Unexpected Query path: %v", req.Path)
|
||||
return sdk.ErrUnknownRequest(msg).Result().ToQuery()
|
||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -205,18 +205,18 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery {
|
|||
path := req.Path
|
||||
storeName, subpath, err := parsePath(path)
|
||||
if err != nil {
|
||||
return err.Result().ToQuery()
|
||||
return err.QueryResult()
|
||||
}
|
||||
|
||||
store := rs.getStoreByName(storeName)
|
||||
if store == nil {
|
||||
msg := fmt.Sprintf("no such store: %s", storeName)
|
||||
return sdk.ErrUnknownRequest(msg).Result().ToQuery()
|
||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
queryable, ok := store.(Queryable)
|
||||
if !ok {
|
||||
msg := fmt.Sprintf("store %s doesn't support queries", storeName)
|
||||
return sdk.ErrUnknownRequest(msg).Result().ToQuery()
|
||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
|
||||
// trim the path and make the query
|
||||
|
|
|
@ -257,7 +257,10 @@ func (coins Coins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i]
|
|||
var _ sort.Interface = Coins{}
|
||||
|
||||
// Sort is a helper function to sort the set of coins inplace
|
||||
func (coins Coins) Sort() { sort.Sort(coins) }
|
||||
func (coins Coins) Sort() Coins {
|
||||
sort.Sort(coins)
|
||||
return coins
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Parsing
|
||||
|
|
|
@ -3,6 +3,8 @@ package types
|
|||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// ABCI Response Code
|
||||
|
@ -121,6 +123,7 @@ type Error interface {
|
|||
TraceCause(cause error, msg string) Error
|
||||
Cause() error
|
||||
Result() Result
|
||||
QueryResult() abci.ResponseQuery
|
||||
}
|
||||
|
||||
func NewError(code CodeType, msg string) Error {
|
||||
|
@ -220,3 +223,11 @@ func (err *sdkError) Result() Result {
|
|||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
||||
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
|
||||
func (err *sdkError) QueryResult() abci.ResponseQuery {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(err.ABCICode()),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,11 +38,3 @@ type Result struct {
|
|||
func (res Result) IsOK() bool {
|
||||
return res.Code.IsOK()
|
||||
}
|
||||
|
||||
// ToQuery allows us to return sdk.Error.Result() in query responses
|
||||
func (res Result) ToQuery() abci.ResponseQuery {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(res.Code),
|
||||
Log: res.Log,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ package version
|
|||
// TODO improve
|
||||
|
||||
const Maj = "0"
|
||||
const Min = "12"
|
||||
const Fix = "0"
|
||||
const Min = "13"
|
||||
const Fix = "2"
|
||||
|
||||
const Version = "0.12.0"
|
||||
const Version = "0.13.2-dev"
|
||||
|
||||
// GitCommit set by build flags
|
||||
var GitCommit = ""
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
@ -64,7 +64,9 @@ func (c commander) getAccountCmd(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
key := sdk.Address(bz)
|
||||
|
||||
res, err := builder.Query(key, c.storeName)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
res, err := ctx.Query(key, c.storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
@ -21,6 +21,7 @@ type commander struct {
|
|||
|
||||
func QueryAccountRequestHandler(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) func(http.ResponseWriter, *http.Request) {
|
||||
c := commander{storeName, cdc, decoder}
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
addr := vars["address"]
|
||||
|
@ -33,7 +34,7 @@ func QueryAccountRequestHandler(storeName string, cdc *wire.Codec, decoder sdk.A
|
|||
}
|
||||
key := sdk.Address(bz)
|
||||
|
||||
res, err := builder.Query(key, c.storeName)
|
||||
res, err := ctx.Query(key, c.storeName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
@ -38,8 +38,10 @@ type Commander struct {
|
|||
}
|
||||
|
||||
func (c Commander) sendTxCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
// get the from address
|
||||
from, err := builder.GetFromAddress()
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -59,14 +61,11 @@ func (c Commander) sendTxCmd(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
to := sdk.Address(bz)
|
||||
|
||||
// get account name
|
||||
name := viper.GetString(client.FlagName)
|
||||
|
||||
// build message
|
||||
msg := BuildMsg(from, to, coins)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
res, err := builder.SignBuildBroadcast(name, msg, c.Cdc)
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, c.Cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ func (out Output) ValidateBasic() sdk.Error {
|
|||
}
|
||||
|
||||
func (out Output) String() string {
|
||||
return fmt.Sprintf("Output{%X,%v}", out.Address, out.Coins)
|
||||
return fmt.Sprintf("Output{%v,%v}", out.Address, out.Coins)
|
||||
}
|
||||
|
||||
// NewOutput - create a transaction output, used with SendMsg
|
||||
|
|
|
@ -179,8 +179,10 @@ func TestSendMsgValidation(t *testing.T) {
|
|||
|
||||
func TestSendMsgString(t *testing.T) {
|
||||
// Construct a SendMsg
|
||||
addr1 := sdk.Address([]byte("input"))
|
||||
addr2 := sdk.Address([]byte("output"))
|
||||
addr1String := "input"
|
||||
addr2String := "output"
|
||||
addr1 := sdk.Address([]byte(addr1String))
|
||||
addr2 := sdk.Address([]byte(addr2String))
|
||||
coins := sdk.Coins{{"atom", 10}}
|
||||
var msg = SendMsg{
|
||||
Inputs: []Input{NewInput(addr1, coins)},
|
||||
|
@ -188,8 +190,9 @@ func TestSendMsgString(t *testing.T) {
|
|||
}
|
||||
|
||||
res := msg.String()
|
||||
expected := fmt.Sprintf("SendMsg{[Input{%X,10atom}]->[Output{%X,10atom}]}", addr1String, addr2String)
|
||||
// TODO some failures for bad results
|
||||
assert.Equal(t, res, "SendMsg{[Input{696E707574,10atom}]->[Output{364637353734373037353734,10atom}]}")
|
||||
assert.Equal(t, expected, res)
|
||||
}
|
||||
|
||||
func TestSendMsgGet(t *testing.T) {
|
||||
|
@ -275,16 +278,18 @@ func TestIssueMsgValidation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIssueMsgString(t *testing.T) {
|
||||
addrString := "loan-from-bank"
|
||||
bankerString := "input"
|
||||
// Construct a IssueMsg
|
||||
addr := sdk.Address([]byte("loan-from-bank"))
|
||||
addr := sdk.Address([]byte(addrString))
|
||||
coins := sdk.Coins{{"atom", 10}}
|
||||
var msg = IssueMsg{
|
||||
Banker: sdk.Address([]byte("input")),
|
||||
Banker: sdk.Address([]byte(bankerString)),
|
||||
Outputs: []Output{NewOutput(addr, coins)},
|
||||
}
|
||||
res := msg.String()
|
||||
// TODO: FIX THIS OUTPUT!
|
||||
assert.Equal(t, res, "IssueMsg{696E707574#[Output{36433646363136453244363637323646364432443632363136453642,10atom}]}")
|
||||
expected := fmt.Sprintf("IssueMsg{%X#[Output{%X,10atom}]}", bankerString, addrString)
|
||||
assert.Equal(t, expected, res)
|
||||
}
|
||||
|
||||
func TestIssueMsgGet(t *testing.T) {
|
||||
|
|
|
@ -7,11 +7,9 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
|
@ -30,6 +28,7 @@ type sendBody struct {
|
|||
// SendRequestHandler - http request handler to send coins to a address
|
||||
func SendRequestHandler(cdc *wire.Codec, kb keys.Keybase) func(http.ResponseWriter, *http.Request) {
|
||||
c := commands.Commander{cdc}
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// collect data
|
||||
vars := mux.Vars(r)
|
||||
|
@ -73,9 +72,8 @@ func SendRequestHandler(cdc *wire.Codec, kb keys.Keybase) func(http.ResponseWrit
|
|||
}
|
||||
|
||||
// sign
|
||||
// XXX: OMG
|
||||
viper.Set(client.FlagSequence, m.Sequence)
|
||||
txBytes, err := builder.SignAndBuild(m.LocalAccountName, m.Password, msg, c.Cdc)
|
||||
ctx = ctx.WithSequence(m.Sequence)
|
||||
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, c.Cdc)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -83,7 +81,7 @@ func SendRequestHandler(cdc *wire.Codec, kb keys.Keybase) func(http.ResponseWrit
|
|||
}
|
||||
|
||||
// send
|
||||
res, err := builder.BroadcastTx(txBytes)
|
||||
res, err := ctx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
|
|
@ -1,25 +1,157 @@
|
|||
# IBC CLI Usage
|
||||
# IBC Doubble Hubble
|
||||
|
||||
## initialize
|
||||
## Remove remaining data
|
||||
|
||||
```bash
|
||||
basecoind init # copy the recover key
|
||||
basecli keys add keyname --recover
|
||||
basecoind start
|
||||
```console
|
||||
> rm -r ~/.chain1
|
||||
> rm -r ~/.chain2
|
||||
> rm -r ~/.basecli
|
||||
```
|
||||
|
||||
## transfer
|
||||
## Initialize both chains
|
||||
|
||||
`transfer` sends coins from one chain to another(or itself).
|
||||
```console
|
||||
> basecoind init --home ~/.chain1
|
||||
I[04-02|14:03:33.704] Generated private validator module=main path=/home/mossid/.chain1/config/priv_validator.json
|
||||
I[04-02|14:03:33.705] Generated genesis file module=main path=/home/mossid/.chain1/config/genesis.json
|
||||
{
|
||||
"secret": "crunch ignore trigger neither differ dance cheap brick situate floor luxury citizen husband decline arrow abandon",
|
||||
"account": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "8C9917D5E982E221F5A1450103102B44BBFC1E8768126C606246CB37B5794F4D"
|
||||
},
|
||||
"power": 10,
|
||||
"name": ""
|
||||
},
|
||||
"node_id": "3ac8e6242315fd62143dc3e52c161edaaa6b1a64",
|
||||
"chain_id": "test-chain-ZajMfr"
|
||||
}
|
||||
> ADDR1=C69FEB398A29AAB1B3C4F07DE22208F35E711BCC
|
||||
> ID1=test-chain-ZajMfr
|
||||
> NODE1=tcp://0.0.0.0:36657
|
||||
> basecli keys add key1 --recover
|
||||
Enter a passphrase for your key:
|
||||
Repeat the passphrase:
|
||||
Enter your recovery seed phrase:
|
||||
crunch ignore trigger neither differ dance cheap brick situate floor luxury citizen husband decline arrow abandon
|
||||
key1 C69FEB398A29AAB1B3C4F07DE22208F35E711BCC
|
||||
|
||||
|
||||
> basecoind init --home ~/.chain2
|
||||
I[04-02|14:09:14.453] Generated private validator module=main path=/home/mossid/.chain2/config/priv_validator.json
|
||||
I[04-02|14:09:14.453] Generated genesis file module=main path=/home/mossid/.chain2/config/genesis.json
|
||||
{
|
||||
"secret": "age guide awesome month female left oxygen soccer define high grocery work desert dinner arena abandon",
|
||||
"account": "DC26002735D3AA9573707CFA6D77C12349E49868",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "A94FE4B9AD763D301F4DD5A2766009812495FB7A79F1275FB8A5AF09B44FD5F3"
|
||||
},
|
||||
"power": 10,
|
||||
"name": ""
|
||||
},
|
||||
"node_id": "ad26831330e1c72b85276d53c20f0680e6fd4cf5"
|
||||
"chain_id": "test-chain-4XHTPn"
|
||||
}
|
||||
> ADDR2=DC26002735D3AA9573707CFA6D77C12349E49868
|
||||
> ID2=test-chain-4XHTPn
|
||||
> NODE2=tcp://0.0.0.0:46657
|
||||
> basecli keys add key2 --recover
|
||||
Enter a passphrase for your key:
|
||||
Repeat the passphrase:
|
||||
Enter your recovery seed phrase:
|
||||
age guide awesome month female left oxygen soccer define high grocery work desert dinner arena abandon
|
||||
key2 DC26002735D3AA9573707CFA6D77C12349E49868
|
||||
|
||||
|
||||
> basecoind start --home ~/.chain1 --address tcp://0.0.0.0:36658 --rpc.laddr tcp://0.0.0.0:36657 --p2p.laddr tcp://0.0.0.0:36656
|
||||
...
|
||||
|
||||
> basecoind start --home ~/.chain2 # --address tcp://0.0.0.0:46658 --rpc.laddr tcp://0.0.0.0:46657 --p2p.laddr tcp://0.0.0.0:46656
|
||||
...
|
||||
```
|
||||
## Check balance
|
||||
|
||||
```console
|
||||
> basecli account $ADDR1 --node $NODE1
|
||||
{
|
||||
"address": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
],
|
||||
"public_key": null,
|
||||
"sequence": 0,
|
||||
"name": ""
|
||||
}
|
||||
|
||||
> basecli account $ADDR2 --node $NODE2
|
||||
{
|
||||
"address": "DC26002735D3AA9573707CFA6D77C12349E49868",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
],
|
||||
"public_key": null,
|
||||
"sequence": 0,
|
||||
"name": ""
|
||||
}
|
||||
|
||||
```bash
|
||||
basecli transfer --name keyname --to address_of_destination --amount 10mycoin --chain test-chain-AAAAAA --chain-id AAAAAA
|
||||
```
|
||||
|
||||
The id of the chain can be found in `$HOME/.basecoind/config/genesis.json`
|
||||
## Transfer coins (addr1:chain1 -> addr2:chain2)
|
||||
|
||||
```console
|
||||
> basecli transfer --name key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1
|
||||
Password to sign with 'key1':
|
||||
Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0
|
||||
> basecli account $ADDR1 --node $NODE1
|
||||
{
|
||||
"address": "C69FEB398A29AAB1B3C4F07DE22208F35E711BCC",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740982
|
||||
}
|
||||
],
|
||||
"public_key": {
|
||||
"type": "ed25519",
|
||||
"data": "9828FF1780A066A0D93D840737566B697035448D6C880807322BED8919348B2B"
|
||||
},
|
||||
"sequence": 1,
|
||||
"name": ""
|
||||
}
|
||||
```
|
||||
|
||||
## Relay IBC packets
|
||||
|
||||
```console
|
||||
> basecli relay --name key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2
|
||||
Password to sign with 'key2':
|
||||
I[04-03|16:18:59.984] Detected IBC packet number=0
|
||||
I[04-03|16:19:00.869] Relayed IBC packet number=0
|
||||
> basecli account $ADDR2 --node $NODE2
|
||||
{
|
||||
"address": "DC26002735D3AA9573707CFA6D77C12349E49868",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254741002
|
||||
}
|
||||
],
|
||||
"public_key": {
|
||||
"type": "ed25519",
|
||||
"data": "F52B4FA545F4E9BFE5D7AF1DD2236899FDEF905F9B3057C38D7C01BF1B8EB52E"
|
||||
},
|
||||
"sequence": 1,
|
||||
"name": ""
|
||||
}
|
||||
|
||||
## relay
|
||||
|
||||
```bash
|
||||
basecli relay --name keyname --from-chain-id test-chain-AAAAAA --from-chain-node=tcp://0.0.0.0:46657 --to-chain-id test-chain-AAAAAA --to-chain-node=tcp://0.0.0.0:46657
|
||||
```
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
|
@ -39,8 +39,10 @@ type sendCommander struct {
|
|||
}
|
||||
|
||||
func (c sendCommander) sendIBCTransfer(cmd *cobra.Command, args []string) error {
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
// get the from address
|
||||
from, err := builder.GetFromAddress()
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -52,9 +54,7 @@ func (c sendCommander) sendIBCTransfer(cmd *cobra.Command, args []string) error
|
|||
}
|
||||
|
||||
// get password
|
||||
name := viper.GetString(client.FlagName)
|
||||
|
||||
res, err := builder.SignBuildBroadcast(name, msg, c.cdc)
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, c.cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func buildMsg(from sdk.Address) (sdk.Msg, error) {
|
|||
}
|
||||
to := sdk.Address(bz)
|
||||
|
||||
packet := ibc.NewIBCPacket(from, to, coins, client.FlagChainID,
|
||||
packet := ibc.NewIBCPacket(from, to, coins, viper.GetString(client.FlagChainID),
|
||||
viper.GetString(flagChain))
|
||||
|
||||
msg := ibc.IBCTransferMsg{
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
|
@ -30,6 +31,8 @@ type relayCommander struct {
|
|||
decoder sdk.AccountDecoder
|
||||
mainStore string
|
||||
ibcStore string
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func IBCRelayCmd(cdc *wire.Codec) *cobra.Command {
|
||||
|
@ -38,6 +41,8 @@ func IBCRelayCmd(cdc *wire.Codec) *cobra.Command {
|
|||
decoder: authcmd.GetAccountDecoder(cdc),
|
||||
ibcStore: "ibc",
|
||||
mainStore: "main",
|
||||
|
||||
logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
@ -68,7 +73,7 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) {
|
|||
fromChainNode := viper.GetString(FlagFromChainNode)
|
||||
toChainID := viper.GetString(FlagToChainID)
|
||||
toChainNode := viper.GetString(FlagToChainNode)
|
||||
address, err := builder.GetFromAddress()
|
||||
address, err := context.NewCoreContextFromViper().GetFromAddress()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -78,14 +83,17 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
|
||||
func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) {
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
// get password
|
||||
name := viper.GetString(client.FlagName)
|
||||
passphrase, err := builder.GetPassphraseFromStdin(name)
|
||||
passphrase, err := ctx.GetPassphraseFromStdin(ctx.FromAddressName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ingressKey := ibc.IngressSequenceKey(fromChainID)
|
||||
OUTER:
|
||||
for {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
processedbz, err := query(toChainNode, ingressKey, c.ibcStore)
|
||||
if err != nil {
|
||||
|
@ -99,14 +107,10 @@ func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode
|
|||
panic(err)
|
||||
}
|
||||
|
||||
OUTER:
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
lengthKey := ibc.EgressLengthKey(toChainID)
|
||||
egressLengthbz, err := query(fromChainNode, lengthKey, c.ibcStore)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying outgoing packet list length: '%s'\n", err)
|
||||
c.logger.Error("Error querying outgoing packet list length", "err", err)
|
||||
continue OUTER
|
||||
}
|
||||
var egressLength int64
|
||||
|
@ -115,43 +119,37 @@ OUTER:
|
|||
} else if err = c.cdc.UnmarshalBinary(egressLengthbz, &egressLength); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("egressLength queried: %d\n", egressLength)
|
||||
if egressLength > processed {
|
||||
c.logger.Info("Detected IBC packet", "number", egressLength-1)
|
||||
}
|
||||
|
||||
seq := c.getSequence(toChainNode)
|
||||
|
||||
for i := processed; i < egressLength; i++ {
|
||||
egressbz, err := query(fromChainNode, ibc.EgressKey(toChainID, i), c.ibcStore)
|
||||
if err != nil {
|
||||
fmt.Printf("Error querying egress packet: '%s'\n", err)
|
||||
c.logger.Error("Error querying egress packet", "err", err)
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
err = c.broadcastTx(toChainNode, c.refine(egressbz, i, passphrase))
|
||||
err = c.broadcastTx(seq, toChainNode, c.refine(egressbz, i, passphrase))
|
||||
seq++
|
||||
if err != nil {
|
||||
fmt.Printf("Error broadcasting ingress packet: '%s'\n", err)
|
||||
c.logger.Error("Error broadcasting ingress packet", "err", err)
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
fmt.Printf("Relayed packet: %d\n", i)
|
||||
c.logger.Info("Relayed IBC packet", "number", i)
|
||||
}
|
||||
|
||||
processed = egressLength
|
||||
}
|
||||
}
|
||||
|
||||
func query(node string, key []byte, storeName string) (res []byte, err error) {
|
||||
orig := viper.GetString(client.FlagNode)
|
||||
viper.Set(client.FlagNode, node)
|
||||
res, err = builder.Query(key, storeName)
|
||||
viper.Set(client.FlagNode, orig)
|
||||
return res, err
|
||||
return context.NewCoreContextFromViper().WithNodeURI(node).Query(key, storeName)
|
||||
}
|
||||
|
||||
func (c relayCommander) broadcastTx(node string, tx []byte) error {
|
||||
orig := viper.GetString(client.FlagNode)
|
||||
viper.Set(client.FlagNode, node)
|
||||
seq := c.getSequence(node) + 1
|
||||
viper.Set(client.FlagSequence, seq)
|
||||
_, err := builder.BroadcastTx(tx)
|
||||
viper.Set(client.FlagNode, orig)
|
||||
func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error {
|
||||
_, err := context.NewCoreContextFromViper().WithNodeURI(node).WithSequence(seq + 1).BroadcastTx(tx)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -160,6 +158,7 @@ func (c relayCommander) getSequence(node string) int64 {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
account, err := c.decoder(res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -180,8 +179,8 @@ func (c relayCommander) refine(bz []byte, sequence int64, passphrase string) []b
|
|||
Sequence: sequence,
|
||||
}
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignAndBuild(name, passphrase, msg, c.cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignAndBuild(ctx.FromAddressName, passphrase, msg, c.cdc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
)
|
||||
|
||||
// AccountMapper(/CoinKeeper) and IBCMapper should use different StoreKey later
|
||||
|
@ -53,8 +51,6 @@ func makeCodec() *wire.Codec {
|
|||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
// RegisterRoutes - Central function to define routes that get registered by the main application
|
||||
func RegisterRoutes(r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
||||
r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandler(cdc, kb)).Methods("POST")
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
)
|
||||
|
||||
type transferBody struct {
|
||||
// Fees sdk.Coin `json="fees"`
|
||||
Amount sdk.Coins `json:"amount"`
|
||||
LocalAccountName string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
SrcChainID string `json:"src_chain_id"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
}
|
||||
|
||||
// TransferRequestHandler - http request handler to transfer coins to a address
|
||||
// on a different chain via IBC
|
||||
func TransferRequestHandler(cdc *wire.Codec, kb keys.Keybase) func(http.ResponseWriter, *http.Request) {
|
||||
c := commands.Commander{cdc}
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// collect data
|
||||
vars := mux.Vars(r)
|
||||
destChainID := vars["destchain"]
|
||||
address := vars["address"]
|
||||
|
||||
var m transferBody
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
info, err := kb.Get(m.LocalAccountName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
bz, err := hex.DecodeString(address)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
to := sdk.Address(bz)
|
||||
|
||||
// build message
|
||||
packet := ibc.NewIBCPacket(info.PubKey.Address(), to, m.Amount, m.SrcChainID, destChainID)
|
||||
msg := ibc.IBCTransferMsg{packet}
|
||||
|
||||
// sign
|
||||
ctx = ctx.WithSequence(m.Sequence)
|
||||
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, c.Cdc)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// send
|
||||
res, err := ctx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(res, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
|
@ -9,11 +9,10 @@ import (
|
|||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/simplestake"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -48,7 +47,9 @@ type commander struct {
|
|||
}
|
||||
|
||||
func (co commander) bondTxCmd(cmd *cobra.Command, args []string) error {
|
||||
from, err := builder.GetFromAddress()
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
from, err := ctx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,25 +77,25 @@ func (co commander) bondTxCmd(cmd *cobra.Command, args []string) error {
|
|||
var pubKeyEd crypto.PubKeyEd25519
|
||||
copy(pubKeyEd[:], rawPubKey)
|
||||
|
||||
msg := staking.NewBondMsg(from, stake, pubKeyEd.Wrap())
|
||||
msg := simplestake.NewBondMsg(from, stake, pubKeyEd.Wrap())
|
||||
|
||||
return co.sendMsg(msg)
|
||||
}
|
||||
|
||||
func (co commander) unbondTxCmd(cmd *cobra.Command, args []string) error {
|
||||
from, err := builder.GetFromAddress()
|
||||
from, err := context.NewCoreContextFromViper().GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := staking.NewUnbondMsg(from)
|
||||
msg := simplestake.NewUnbondMsg(from)
|
||||
|
||||
return co.sendMsg(msg)
|
||||
}
|
||||
|
||||
func (co commander) sendMsg(msg sdk.Msg) error {
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignBuildBroadcast(name, msg, co.cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, co.cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// Staking errors reserve 300 - 399.
|
||||
// simplestake errors reserve 300 - 399.
|
||||
CodeEmptyValidator sdk.CodeType = 300
|
||||
CodeInvalidUnbond sdk.CodeType = 301
|
||||
CodeEmptyStake sdk.CodeType = 302
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
@ -6,7 +6,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// NewHandler returns a handler for "bank" type messages.
|
||||
// NewHandler returns a handler for "simplestake" type messages.
|
||||
func NewHandler(k Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
switch msg := msg.(type) {
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
@ -10,6 +10,8 @@ import (
|
|||
|
||||
const stakingToken = "steak"
|
||||
|
||||
const moduleName = "simplestake"
|
||||
|
||||
type Keeper struct {
|
||||
ck bank.CoinKeeper
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -26,7 +26,7 @@ func NewBondMsg(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) BondMsg
|
|||
}
|
||||
|
||||
func (msg BondMsg) Type() string {
|
||||
return "staking"
|
||||
return moduleName
|
||||
}
|
||||
|
||||
func (msg BondMsg) ValidateBasic() sdk.Error {
|
||||
|
@ -71,7 +71,7 @@ func NewUnbondMsg(addr sdk.Address) UnbondMsg {
|
|||
}
|
||||
|
||||
func (msg UnbondMsg) Type() string {
|
||||
return "staking"
|
||||
return moduleName
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) ValidateBasic() sdk.Error {
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -1,4 +1,4 @@
|
|||
package staking
|
||||
package simplestake
|
||||
|
||||
import crypto "github.com/tendermint/go-crypto"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire" // XXX fix
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
@ -47,7 +47,8 @@ func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command {
|
|||
|
||||
key := PrefixedKey(stake.MsgType, stake.CandidatesKey)
|
||||
|
||||
res, err := builder.Query(key, storeName)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.Query(key, storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -87,7 +88,9 @@ func GetCmdQueryCandidate(cdc *wire.Codec, storeName string) *cobra.Command {
|
|||
|
||||
key := PrefixedKey(stake.MsgType, stake.GetCandidateKey(addr))
|
||||
|
||||
res, err := builder.Query(key, storeName)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
res, err := ctx.Query(key, storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -133,7 +136,9 @@ func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command
|
|||
|
||||
key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondKey(delegator, addr, cdc))
|
||||
|
||||
res, err := builder.Query(key, storeName)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
res, err := ctx.Query(key, storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -175,7 +180,9 @@ func GetCmdQueryDelegatorBonds(cdc *wire.Codec, storeName string) *cobra.Command
|
|||
|
||||
key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondsKey(delegator, cdc))
|
||||
|
||||
res, err := builder.Query(key, storeName)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
res, err := ctx.Query(key, storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
@ -92,8 +92,8 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgDeclareCandidacy(candidateAddr, pk, amount, description)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -129,8 +129,8 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgEditCandidacy(candidateAddr, description)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -165,8 +165,8 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgDelegate(delegatorAddr, candidateAddr, amount)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -212,8 +212,8 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgUnbond(delegatorAddr, candidateAddr, sharesStr)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
name := viper.GetString(client.FlagName)
|
||||
res, err := builder.SignBuildBroadcast(name, msg, cdc)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.SignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@ func ErrBadDelegatorAddr() sdk.Error {
|
|||
func ErrCandidateExistsAddr() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Candidate already exist, cannot re-declare candidacy")
|
||||
}
|
||||
func ErrCandidateRevoked() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Candidacy for this address is currently revoked")
|
||||
}
|
||||
func ErrMissingSignature() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Missing signature")
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue