merge from develop

This commit is contained in:
mossid 2018-04-25 14:15:34 +02:00
commit 8ff316c99e
146 changed files with 3420 additions and 1855 deletions

View File

@ -27,11 +27,17 @@ jobs:
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- run:
name: linter
command: |
export PATH="$GOBIN:$PATH"
go get -u github.com/tendermint/lint/golint
go get -u github.com/alecthomas/gometalinter
- run:
name: binaries
command: |
export PATH="$GOBIN:$PATH"
make build
make install
- persist_to_workspace:
root: /tmp/workspace
paths:
@ -46,6 +52,22 @@ jobs:
paths:
- /go/src/github.com/cosmos/cosmos-sdk
lint:
<<: *defaults
parallelism: 4
steps:
- attach_workspace:
at: /tmp/workspace
- restore_cache:
key: v1-pkg-cache
- restore_cache:
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: Lint source
command: |
export PATH="$GOBIN:$PATH"
gometalinter --disable-all --enable='golint' --vendor ./...
test_cover:
<<: *defaults
parallelism: 4
@ -59,7 +81,9 @@ jobs:
- run:
name: Run tests
command: |
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | circleci tests split --split-by=timings); do
export PATH="$GOBIN:$PATH"
make install
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do
id=$(basename "$pkg")
go test -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg"
@ -94,10 +118,12 @@ workflows:
test-suite:
jobs:
- setup_dependencies
- lint:
requires:
- setup_dependencies
- test_cover:
requires:
- setup_dependencies
- upload_coverage:
requires:
- test_cover

View File

@ -7,16 +7,26 @@ FEATURES:
* Add CacheContext
* Add auto sequencing to client
* Add FeeHandler to ante handler
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
* MountStoreWithDB without providing a custom store works.
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
* Better key output, pubkey go-amino hex bytes now output by default
BREAKING CHANGES
* Remove go-wire, use go-amino
* Gaia simple-staking bond and unbond functions replaced
* [stake] Delegator bonds now store the height at which they were updated
* [store] Add `SubspaceIterator` and `ReverseSubspaceIterator` to `KVStore` interface
* [basecoin] NewBasecoinApp takes a `dbm.DB` and uses namespaced DBs for substores
* All module keepers now require a codespace, see basecoin or democoin for usage
* Many changes to names throughout
* Type as a prefix naming convention applied (ex. BondMsg -> MsgBond)
* Removed redundancy in names (ex. stake.StakeKeeper -> stake.Keeper)
* Removed SealedAccountMapper
BUG FIXES
* MountStoreWithDB without providing a custom store works.
* Gaia now uses stake, ported from github.com/cosmos/gaia
## 0.14.1 (April 9, 2018)

9
Gopkg.lock generated
View File

@ -342,7 +342,7 @@
"types/priv_validator",
"version"
]
revision = "d0beaba7e8a5652506a34b5fab299cc2dc274c02"
revision = "a2930cd7233f04f5a651020669289296545e70dc"
version = "v0.19.0"
[[projects]]
@ -384,6 +384,7 @@
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
@ -391,13 +392,13 @@
"lex/httplex",
"trace"
]
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
revision = "8d16fa6dc9a85c1cd3ed24ad08ff21cf94f10888"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "3b87a42e500a6dc65dae1a55d0b641295971163e"
revision = "b126b21c05a91c856b027c16779c12e3bf236954"
[[projects]]
name = "golang.org/x/text"
@ -424,7 +425,7 @@
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "51d0944304c3cbce4afe9e5247e21100037bff78"
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
[[projects]]
name = "google.golang.org/grpc"

View File

@ -2,12 +2,12 @@ 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 build_examples test
all: check_tools get_vendor_deps build build_examples install install_examples test
########################################
### CI
ci: get_tools get_vendor_deps build test_cover
ci: get_tools get_vendor_deps install test_cover
########################################
### Build
@ -15,11 +15,11 @@ ci: get_tools get_vendor_deps build test_cover
# This can be unified later, here for easy demos
build:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
else
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
endif
build_examples:
@ -36,8 +36,8 @@ else
endif
install:
go install $(BUILD_FLAGS) ./cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaiacli
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
install_examples:
go install $(BUILD_FLAGS) ./examples/basecoin/cmd/basecoind

View File

@ -29,6 +29,7 @@ type BaseApp struct {
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
router Router // handle any kind of message
codespacer *sdk.Codespacer // handle module codespacing
// must be set
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
@ -56,13 +57,18 @@ 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{
app := &BaseApp{
Logger: logger,
name: name,
db: db,
cms: store.NewCommitMultiStore(db),
router: NewRouter(),
codespacer: sdk.NewCodespacer(),
}
// Register the undefined & root codespaces, which should not be used by any modules
app.codespacer.RegisterOrPanic(sdk.CodespaceUndefined)
app.codespacer.RegisterOrPanic(sdk.CodespaceRoot)
return app
}
// BaseApp Name
@ -70,6 +76,11 @@ func (app *BaseApp) Name() string {
return app.name
}
// Register the next available codespace through the baseapp's codespacer, starting from a default
func (app *BaseApp) RegisterCodespace(codespace sdk.CodespaceType) sdk.CodespaceType {
return app.codespacer.RegisterNext(codespace)
}
// Mount a store to the provided key in the BaseApp multistore
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
for _, key := range keys {
@ -103,7 +114,6 @@ func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) {
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
app.anteHandler = ah
}
func (app *BaseApp) Router() Router { return app.router }
// load latest application version
@ -311,9 +321,8 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
if result.IsOK() {
app.valUpdates = append(app.valUpdates, result.ValidatorUpdates...)
} else {
// Even though the Code is not OK, there will be some side
// effects, like those caused by fee deductions or sequence
// incrementations.
// Even though the Result.Code is not OK, there are still effects,
// namely fee deductions and sequence incrementing.
}
// Tell the blockchain engine (i.e. Tendermint).
@ -327,7 +336,7 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
}
}
// Mostly for testing
// nolint- Mostly for testing
func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) {
return app.runTx(true, nil, tx)
}
@ -355,6 +364,7 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk
// Validate the Msg.
err := msg.ValidateBasic()
if err != nil {
err = err.WithDefaultCodespace(sdk.CodespaceRoot)
return err.Result()
}
@ -441,7 +451,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {
// Use the header from this latest block.
app.setCheckState(header)
// Emtpy the Deliver state
// Empty the Deliver state
app.deliverState = nil
return abci.ResponseCommit{

View File

@ -240,7 +240,7 @@ func TestDeliverTx(t *testing.T) {
height := int64((counter / txPerHeight) + 1)
assert.Equal(t, height, thisHeader.Height)
counter += 1
counter++
return sdk.Result{}
})

View File

@ -1,4 +1,4 @@
package core
package context
import (
"fmt"
@ -126,7 +126,14 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
}
// sign and build the transaction from the msg
func (ctx CoreContext) SignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (*ctypes.ResultBroadcastTxCommit, error) {
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) {
// default to next sequence number if none provided
ctx, err = EnsureSequence(ctx)
if err != nil {
return nil, err
}
passphrase, err := ctx.GetPassphraseFromStdin(name)
if err != nil {
return nil, err
@ -141,17 +148,17 @@ func (ctx CoreContext) SignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Co
}
// get the next sequence for the account address
func (c CoreContext) NextSequence(address []byte) (int64, error) {
if c.Decoder == nil {
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("AccountDecoder required but not provided")
}
res, err := c.Query(address, c.AccountStore)
res, err := ctx.Query(address, ctx.AccountStore)
if err != nil {
return 0, err
}
account, err := c.Decoder(res)
account, err := ctx.Decoder(res)
if err != nil {
panic(err)
}

View File

@ -1,4 +1,4 @@
package core
package context
import (
rpcclient "github.com/tendermint/tendermint/rpc/client"
@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// typical context created in sdk modules for transactions/queries
type CoreContext struct {
ChainID string
Height int64

View File

@ -2,6 +2,7 @@ package context
import (
"fmt"
"github.com/spf13/viper"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
@ -9,11 +10,10 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/core"
)
// NewCoreContextFromViper - return a new context with parameters from the command line
func NewCoreContextFromViper() core.CoreContext {
func NewCoreContextFromViper() CoreContext {
nodeURI := viper.GetString(client.FlagNode)
var rpc rpcclient.Client
if nodeURI != "" {
@ -27,7 +27,7 @@ func NewCoreContextFromViper() core.CoreContext {
chainID = def
}
}
return core.CoreContext{
return CoreContext{
ChainID: chainID,
Height: viper.GetInt64(client.FlagHeight),
TrustNode: viper.GetBool(client.FlagTrustNode),
@ -54,7 +54,7 @@ func defaultChainID() (string, error) {
}
// EnsureSequence - automatically set sequence number if none provided
func EnsureSequence(ctx core.CoreContext) (core.CoreContext, error) {
func EnsureSequence(ctx CoreContext) (CoreContext, error) {
if viper.IsSet(client.FlagSequence) {
return ctx, nil
}

View File

@ -135,14 +135,17 @@ func printCreate(info keys.Info, seed string) {
}
}
/////////////////////////////
// REST
// new key request REST body
type NewKeyBody struct {
Name string `json:"name"`
Password string `json:"password"`
Seed string `json:"seed"`
}
// add new key REST handler
func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m NewKeyBody
@ -208,6 +211,7 @@ func getSeed(algo keys.CryptoAlgo) string {
return seed
}
// Seed REST request handler
func SeedRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
algoType := vars["type"]

View File

@ -48,12 +48,15 @@ func runDeleteCmd(cmd *cobra.Command, args []string) error {
return nil
}
////////////////////////
// REST
// delete key request REST body
type DeleteKeyBody struct {
Password string `json:"password"`
}
// delete key REST handler
func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]

View File

@ -31,8 +31,10 @@ func runListCmd(cmd *cobra.Command, args []string) error {
return err
}
/////////////////////////
// REST
// query key list REST handler
func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
kb, err := GetKeyBase()
if err != nil {

View File

@ -29,6 +29,7 @@ func Commands() *cobra.Command {
return cmd
}
// resgister REST routes
func RegisterRoutes(r *mux.Router) {
r.HandleFunc("/keys", QueryKeysRequestHandler).Methods("GET")
r.HandleFunc("/keys", AddNewKeyRequestHandler).Methods("POST")

View File

@ -42,8 +42,10 @@ func runShowCmd(cmd *cobra.Command, args []string) error {
return err
}
///////////////////////////
// REST
// get key REST handler
func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]

View File

@ -53,13 +53,16 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error {
return nil
}
///////////////////////
// REST
// update key request REST body
type UpdateKeyBody struct {
NewPassword string `json:"new_password"`
OldPassword string `json:"old_password"`
}
// update key REST handler
func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]

View File

@ -1,8 +1,11 @@
package keys
import (
"encoding/hex"
"encoding/json"
"fmt"
"path/filepath"
"strings"
"github.com/spf13/viper"
@ -16,20 +19,10 @@ import (
// KeyDBName is the directory under root where we store the keys
const KeyDBName = "keys"
var (
// keybase is used to make GetKeyBase a singleton
keybase keys.Keybase
)
var keybase keys.Keybase
// used for outputting keys.Info over REST
type KeyOutput struct {
Name string `json:"name"`
Address string `json:"address"`
// TODO add pubkey?
// Pubkey string `json:"pubkey"`
}
// GetKeyBase initializes a keybase based on the configuration
// initialize a keybase based on the configuration
func GetKeyBase() (keys.Keybase, error) {
if keybase == nil {
rootDir := viper.GetString(cli.HomeFlag)
@ -47,36 +40,57 @@ func SetKeyBase(kb keys.Keybase) {
keybase = kb
}
// used for outputting keys.Info over REST
type KeyOutput struct {
Name string `json:"name"`
Address string `json:"address"`
PubKey string `json:"pub_key"`
}
func NewKeyOutput(info keys.Info) KeyOutput {
return KeyOutput{
Name: info.Name,
Address: info.PubKey.Address().String(),
PubKey: strings.ToUpper(hex.EncodeToString(info.PubKey.Bytes())),
}
}
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
kos := make([]KeyOutput, len(infos))
for i, info := range infos {
kos[i] = NewKeyOutput(info)
}
return kos
}
func printInfo(info keys.Info) {
ko := NewKeyOutput(info)
switch viper.Get(cli.OutputFlag) {
case "text":
addr := info.PubKey.Address().String()
sep := "\t\t"
if len(info.Name) > 7 {
sep = "\t"
}
fmt.Printf("%s%s%s\n", info.Name, sep, addr)
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\tPUBKEY:\n")
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
case "json":
json, err := MarshalJSON(info)
out, err := json.MarshalIndent(ko, "", "\t")
if err != nil {
panic(err) // really shouldn't happen...
panic(err)
}
fmt.Println(string(json))
fmt.Println(string(out))
}
}
func printInfos(infos []keys.Info) {
kos := NewKeyOutputs(infos)
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Println("All keys:")
for _, i := range infos {
printInfo(i)
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\tPUBKEY:\n")
for _, ko := range kos {
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
}
case "json":
json, err := MarshalJSON(infos)
out, err := json.MarshalIndent(kos, "", "\t")
if err != nil {
panic(err) // really shouldn't happen...
panic(err)
}
fmt.Println(string(json))
fmt.Println(string(out))
}
}

View File

@ -11,6 +11,12 @@ func init() {
wire.RegisterCrypto(cdc)
}
// marshal keys
func MarshalJSON(o interface{}) ([]byte, error) {
return cdc.MarshalJSON(o)
}
// unmarshal json
func UnmarshalJSON(bz []byte, ptr interface{}) error {
return cdc.UnmarshalJSON(bz, ptr)
}

View File

@ -28,12 +28,11 @@ func waitForRPC() {
_, err := client.Call("status", map[string]interface{}{}, result)
if err == nil {
return
} else {
}
fmt.Println("error", err)
time.Sleep(time.Millisecond)
}
}
}
// f**ing long, but unique for each test
func makePathname() string {

View File

@ -42,9 +42,9 @@ var (
coinAmount = int64(10000000)
// XXX bad globals
name = "test"
password = "0123456789"
port string // XXX: but it's the int ...
name string = "test"
password string = "0123456789"
seed string
sendAddr string
)
@ -80,7 +80,7 @@ func TestKeys(t *testing.T) {
jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed))
res, body = request(t, port, "POST", "/keys", jsonStr)
assert.Equal(t, http.StatusOK, res.StatusCode, body)
require.Equal(t, http.StatusOK, res.StatusCode, body)
addr := body
assert.Len(t, addr, 40, "Returned address has wrong format", addr)
@ -311,7 +311,11 @@ 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())
dir, err := ioutil.TempDir("", "lcd_test")
if err != nil {
return nil, nil, err
}
viper.Set(cli.HomeFlag, dir)
kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
if err != nil {
return nil, nil, err

View File

@ -66,7 +66,7 @@ func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string)
func createHandler(cdc *wire.Codec) http.Handler {
r := mux.NewRouter()
r.HandleFunc("/version", version.VersionRequestHandler).Methods("GET")
r.HandleFunc("/version", version.RequestHandler).Methods("GET")
kb, err := keys.GetKeyBase() //XXX
if err != nil {

View File

@ -55,6 +55,7 @@ func getBlock(height *int64) ([]byte, error) {
return output, nil
}
// get the current blockchain height
func GetChainHeight() (int64, error) {
node, err := context.NewCoreContextFromViper().GetNode()
if err != nil {
@ -94,6 +95,7 @@ func printBlock(cmd *cobra.Command, args []string) error {
// REST
// REST handler to get a block
func BlockRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
height, err := strconv.ParseInt(vars["height"], 10, 64)
@ -117,6 +119,7 @@ func BlockRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write(output)
}
// REST handler to get the latest block
func LatestBlockRequestHandler(w http.ResponseWriter, r *http.Request) {
height, err := GetChainHeight()
if err != nil {

View File

@ -44,11 +44,12 @@ func initClientCommand() *cobra.Command {
return cmd
}
// Register REST endpoints
func RegisterRoutes(r *mux.Router) {
r.HandleFunc("/node_info", NodeInfoRequestHandler).Methods("GET")
r.HandleFunc("/syncing", NodeSyncingRequestHandler).Methods("GET")
r.HandleFunc("/blocks/latest", LatestBlockRequestHandler).Methods("GET")
r.HandleFunc("/blocks/{height}", BlockRequestHandler).Methods("GET")
r.HandleFunc("/validatorsets/latest", LatestValidatorsetRequestHandler).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorsetRequestHandler).Methods("GET")
r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandler).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandler).Methods("GET")
}

View File

@ -51,6 +51,7 @@ func printNodeStatus(cmd *cobra.Command, args []string) error {
// REST
// REST handler for node info
func NodeInfoRequestHandler(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus()
if err != nil {
@ -69,6 +70,7 @@ func NodeInfoRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write(output)
}
// REST handler for node syncing
func NodeSyncingRequestHandler(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus()
if err != nil {

View File

@ -12,6 +12,8 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
)
// TODO these next two functions feel kinda hacky based on their placement
func validatorCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "validatorset <height>",
@ -24,7 +26,7 @@ func validatorCommand() *cobra.Command {
return cmd
}
func GetValidators(height *int64) ([]byte, error) {
func getValidators(height *int64) ([]byte, error) {
// get the node
node, err := context.NewCoreContextFromViper().GetNode()
if err != nil {
@ -59,7 +61,7 @@ func printValidators(cmd *cobra.Command, args []string) error {
}
}
output, err := GetValidators(height)
output, err := getValidators(height)
if err != nil {
return err
}
@ -70,7 +72,8 @@ func printValidators(cmd *cobra.Command, args []string) error {
// REST
func ValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
// Validator Set at a height REST handler
func ValidatorSetRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
height, err := strconv.ParseInt(vars["height"], 10, 64)
if err != nil {
@ -84,7 +87,7 @@ func ValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
return
}
output, err := GetValidators(&height)
output, err := getValidators(&height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@ -93,14 +96,15 @@ func ValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write(output)
}
func LatestValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
// Latest Validator Set REST handler
func LatestValidatorSetRequestHandler(w http.ResponseWriter, r *http.Request) {
height, err := GetChainHeight()
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := GetValidators(&height)
output, err := getValidators(&height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -7,10 +7,12 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
)
// Tx Broadcast Body
type BroadcastTxBody struct {
TxBytes string `json="tx"`
}
// BroadcastTx REST Handler
func BroadcastTxRequestHandler(w http.ResponseWriter, r *http.Request) {
var m BroadcastTxBody

View File

@ -21,19 +21,37 @@ import (
)
// Get the default command for a tx query
func QueryTxCmd(cmdr commander) *cobra.Command {
func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "tx [hash]",
Short: "Matches this txhash over all committed blocks",
RunE: cmdr.queryAndPrintTx,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a tx hash")
}
// find the key to look up the account
hashHexStr := args[0]
trustNode := viper.GetBool(client.FlagTrustNode)
output, err := queryTx(cdc, hashHexStr, trustNode)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
return cmd
}
func (c commander) queryTx(hashHexStr string, trustNode bool) ([]byte, error) {
func queryTx(cdc *wire.Codec, hashHexStr string, trustNode bool) ([]byte, error) {
hash, err := hex.DecodeString(hashHexStr)
if err != nil {
return nil, err
@ -49,7 +67,7 @@ func (c commander) queryTx(hashHexStr string, trustNode bool) ([]byte, error) {
if err != nil {
return nil, err
}
info, err := formatTxResult(c.cdc, res)
info, err := formatTxResult(cdc, res)
if err != nil {
return nil, err
}
@ -88,31 +106,10 @@ func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) {
return tx, nil
}
// CMD
// command to query for a transaction
func (c commander) queryAndPrintTx(cmd *cobra.Command, args []string) error {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("You must provide a tx hash")
}
// find the key to look up the account
hashHexStr := args[0]
trustNode := viper.GetBool(client.FlagTrustNode)
output, err := c.queryTx(hashHexStr, trustNode)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
// REST
// transaction query REST handler
func QueryTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Request) {
c := commander{cdc}
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
hashHexStr := vars["hash"]
@ -122,7 +119,7 @@ func QueryTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Requ
trustNode = true
}
output, err := c.queryTx(hashHexStr, trustNode)
output, err := queryTx(cdc, hashHexStr, trustNode)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -7,23 +7,18 @@ import (
"github.com/cosmos/cosmos-sdk/wire"
)
// type used to pass around the provided cdc
type commander struct {
cdc *wire.Codec
}
// AddCommands adds a number of tx-query related subcommands
func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
cmdr := commander{cdc}
cmd.AddCommand(
SearchTxCmd(cmdr),
QueryTxCmd(cmdr),
SearchTxCmd(cdc),
QueryTxCmd(cdc),
)
}
// register REST routes
func RegisterRoutes(r *mux.Router, cdc *wire.Codec) {
// r.HandleFunc("/txs", SearchTxRequestHandler(cdc)).Methods("GET")
r.HandleFunc("/txs/{hash}", QueryTxRequestHandler(cdc)).Methods("GET")
// r.HandleFunc("/txs", SearchTxRequestHandler(cdc)).Methods("GET")
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
// r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST")
}

View File

@ -22,13 +22,24 @@ const (
)
// default client command to search through tagged transactions
func SearchTxCmd(cmdr commander) *cobra.Command {
func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "txs",
Short: "Search for all transactions that match the given tags",
RunE: cmdr.searchAndPrintTx,
RunE: func(cmd *cobra.Command, args []string) error {
tags := viper.GetStringSlice(flagTags)
output, err := searchTx(cdc, tags)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
// TODO: change this to false once proofs built in
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().StringSlice(flagTags, nil, "Tags that must match (may provide multiple)")
@ -36,7 +47,7 @@ func SearchTxCmd(cmdr commander) *cobra.Command {
return cmd
}
func (c commander) searchTx(tags []string) ([]byte, error) {
func searchTx(cdc *wire.Codec, tags []string) ([]byte, error) {
if len(tags) == 0 {
return nil, errors.New("Must declare at least one tag to search")
}
@ -55,12 +66,12 @@ func (c commander) searchTx(tags []string) ([]byte, error) {
return nil, err
}
info, err := formatTxResults(c.cdc, res)
info, err := formatTxResults(cdc, res)
if err != nil {
return nil, err
}
output, err := c.cdc.MarshalJSON(info)
output, err := cdc.MarshalJSON(info)
if err != nil {
return nil, err
}
@ -79,24 +90,11 @@ func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error)
return out, nil
}
// CMD
func (c commander) searchAndPrintTx(cmd *cobra.Command, args []string) error {
tags := viper.GetStringSlice(flagTags)
output, err := c.searchTx(tags)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
/////////////////////////////////////////
// REST
// Search Tx REST Handler
func SearchTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Request) {
c := commander{cdc}
return func(w http.ResponseWriter, r *http.Request) {
tag := r.FormValue("tag")
if tag == "" {
@ -106,7 +104,7 @@ func SearchTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Req
}
tags := []string{tag}
output, err := c.searchTx(tags)
output, err := searchTx(cdc, tags)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -8,12 +8,15 @@ import (
keys "github.com/tendermint/go-crypto/keys"
)
// REST request body
// TODO does this need to be exposed?
type SignTxBody struct {
Name string `json="name"`
Password string `json="password"`
TxBytes string `json="tx"`
}
// sign transaction REST Handler
func SignTxRequstHandler(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m SignTxBody

200
cmd/gaia/app/app.go Normal file
View File

@ -0,0 +1,200 @@
package app
import (
"encoding/json"
abci "github.com/tendermint/abci/types"
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/stake"
)
const (
appName = "GaiaApp"
)
// Extended ABCI application
type GaiaApp struct {
*bam.BaseApp
cdc *wire.Codec
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyIBC *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper sdk.AccountMapper
coinKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
// Handle fees
feeHandler sdk.FeeHandler
}
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
// create your application object
var app = &GaiaApp{
BaseApp: bam.NewBaseApp(appName, logger, db),
cdc: MakeCodec(),
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),
keyStake: sdk.NewKVStoreKey("stake"),
}
// define the accountMapper
app.accountMapper = auth.NewAccountMapper(
app.cdc,
app.keyMain, // target store
&auth.BaseAccount{}, // prototype
)
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
// Define the feeHandler.
app.feeHandler = auth.BurnFeeHandler
// initialize BaseApp
app.SetTxDecoder(app.txDecoder)
app.SetInitChainer(app.initChainer)
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeHandler))
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
return app
}
// custom tx codec
func MakeCodec() *wire.Codec {
var cdc = wire.NewCodec()
// Register Msgs
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
ibc.RegisterWire(cdc)
bank.RegisterWire(cdc)
stake.RegisterWire(cdc)
// Register AppAccount
cdc.RegisterInterface((*sdk.Account)(nil), nil)
cdc.RegisterConcrete(&auth.BaseAccount{}, "gaia/Account", nil)
// Register crypto.
wire.RegisterCrypto(cdc)
return cdc
}
// custom logic for transaction decoding
func (app *GaiaApp) 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
err := app.cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").Trace(err.Error())
}
return tx, nil
}
// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
genesisState := new(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, "")
}
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
app.accountMapper.SetAccount(ctx, acc)
}
// load the initial stake information
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
return abci.ResponseInitChain{}
}
//__________________________________________________________
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
}
// GenesisAccount doesn't need pubkey or sequence
type GenesisAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
}
}
// convert GenesisAccount to GaiaAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
}
}
// 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) {
accAuth := auth.NewBaseAccountWithAddress(addr)
accAuth.Coins = sdk.Coins{{"fermion", 100000}}
acc := NewGenesisAccount(&accAuth)
genaccs := []GenesisAccount{acc}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return nil, err
}
return stateBytes, nil
}

518
cmd/gaia/app/app_test.go Normal file
View File

@ -0,0 +1,518 @@
package app
import (
"encoding/json"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
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"
"github.com/cosmos/cosmos-sdk/x/stake"
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
accName = "foobart"
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.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,
}
sendMsg1 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
sendMsg2 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{
bank.NewOutput(addr2, halfCoins),
bank.NewOutput(addr3, halfCoins),
},
}
sendMsg3 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, coins),
bank.NewInput(addr4, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, coins),
bank.NewOutput(addr3, coins),
},
}
sendMsg4 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr2, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr1, coins),
},
}
sendMsg5 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, manyCoins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, manyCoins),
},
}
)
func loggerAndDB() (log.Logger, dbm.DB) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
return logger, db
}
func newGaiaApp() *GaiaApp {
logger, db := loggerAndDB()
return NewGaiaApp(logger, db)
}
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = NewGenesisAccount(acc)
}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return err
}
// Initialize the chain
vals := []abci.Validator{}
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
gapp.Commit()
return nil
}
//_______________________________________________________________________
func TestMsgs(t *testing.T) {
gapp := newGaiaApp()
require.Nil(t, setGenesis(gapp))
msgs := []struct {
msg sdk.Msg
}{
{sendMsg1},
}
for i, m := range msgs {
// Run a CheckDeliver
SignCheckDeliver(t, gapp, m.msg, []int64{int64(i)}, false, priv1)
}
}
func setGenesisAccounts(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = NewGenesisAccount(acc)
}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return err
}
// Initialize the chain
vals := []abci.Validator{}
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
gapp.Commit()
return nil
}
func TestGenesis(t *testing.T) {
logger, dbs := loggerAndDB()
gapp := NewGaiaApp(logger, dbs)
// Construct some genesis bytes to reflect GaiaAccount
pk := crypto.GenPrivKeyEd25519().PubKey()
addr := pk.Address()
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr,
Coins: coins,
}
err = setGenesis(gapp, baseAcc)
assert.Nil(t, err)
// A checkTx context
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
// reload app and ensure the account is still there
gapp = NewGaiaApp(logger, dbs)
ctx = gapp.BaseApp.NewContext(true, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
}
func TestMsgSendWithAccounts(t *testing.T) {
gapp := newGaiaApp()
// Construct some genesis bytes to reflect GaiaAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
// Construct genesis state
err = setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1.(*auth.BaseAccount))
// Run a CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "67foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Delivering again should cause replay error
SignCheckDeliver(t, gapp, 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 := gapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
SignCheckDeliver(t, gapp, sendMsg1, []int64{1}, true, priv1)
}
func TestMsgSendMultipleOut(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg2, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "47foocoin")
CheckBalance(t, gapp, addr3, "5foocoin")
}
func TestSengMsgMultipleInOut(t *testing.T) {
gapp := newGaiaApp()
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 = setGenesis(gapp, acc1, acc2, acc4)
assert.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr4, "32foocoin")
CheckBalance(t, gapp, addr2, "52foocoin")
CheckBalance(t, gapp, addr3, "10foocoin")
}
func TestMsgSendDependent(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
err = setGenesis(gapp, acc1)
require.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg4, []int64{0}, true, priv2)
// Check balances
CheckBalance(t, gapp, addr1, "42foocoin")
}
func TestIBCMsgs(t *testing.T) {
gapp := newGaiaApp()
sourceChain := "source-chain"
destChain := "dest-chain"
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
err := setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, 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, gapp, transferMsg, []int64{0}, true, priv1)
CheckBalance(t, gapp, addr1, "")
SignCheckDeliver(t, gapp, transferMsg, []int64{1}, false, priv1)
SignCheckDeliver(t, gapp, receiveMsg, []int64{2}, true, priv1)
CheckBalance(t, gapp, addr1, "10foocoin")
SignCheckDeliver(t, gapp, receiveMsg, []int64{3}, false, priv1)
}
func TestStakeMsgs(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42fermion")
require.Nil(t, err)
bondCoin, err := sdk.ParseCoin("10fermion")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
res2 := gapp.accountMapper.GetAccount(ctxCheck, addr2)
require.Equal(t, acc1, res1)
require.Equal(t, acc2, res2)
// Declare Candidacy
description := stake.NewDescription("foo_moniker", "", "", "")
declareCandidacyMsg := stake.NewMsgDeclareCandidacy(
addr1, priv1.PubKey(), bondCoin, description,
)
SignCheckDeliver(t, gapp, declareCandidacyMsg, []int64{0}, true, priv1)
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res1.GetCoins())
candidate, found := gapp.stakeKeeper.GetCandidate(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, candidate.Address, addr1)
// Edit Candidacy
description = stake.NewDescription("bar_moniker", "", "", "")
editCandidacyMsg := stake.NewMsgEditCandidacy(
addr1, description,
)
SignDeliver(t, gapp, editCandidacyMsg, []int64{1}, true, priv1)
candidate, found = gapp.stakeKeeper.GetCandidate(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, candidate.Description, description)
// Delegate
delegateMsg := stake.NewMsgDelegate(
addr2, addr1, bondCoin,
)
SignDeliver(t, gapp, delegateMsg, []int64{0}, true, priv2)
ctxDeliver = gapp.BaseApp.NewContext(false, abci.Header{})
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res2.GetCoins())
bond, found := gapp.stakeKeeper.GetDelegatorBond(ctxDeliver, addr2, addr1)
require.True(t, found)
require.Equal(t, bond.DelegatorAddr, addr2)
// Unbond
unbondMsg := stake.NewMsgUnbond(
addr2, addr1, "MAX",
)
SignDeliver(t, gapp, unbondMsg, []int64{1}, true, priv2)
ctxDeliver = gapp.BaseApp.NewContext(false, abci.Header{})
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins, res2.GetCoins())
_, found = gapp.stakeKeeper.GetDelegatorBond(ctxDeliver, addr2, addr1)
require.False(t, found)
}
//____________________________________________________________________________________
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res2 := gapp.accountMapper.GetAccount(ctxDeliver, addr)
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
}
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, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Run a Check
res := gapp.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res = gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
// XXX fix code or add explaination as to why using commit breaks a bunch of these tests
//gapp.Commit()
}
// XXX the only reason we are using Sign Deliver here is because the tests
// break on check tx the second time you use SignCheckDeliver in a test because
// the checktx state has not been updated likely because commit is not being
// called!
func SignDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res := gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
}

View File

@ -0,0 +1,172 @@
package clitest
import (
"encoding/json"
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
)
func TestGaiaCLISend(t *testing.T) {
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
executeWrite(t, "gaiacli keys delete bar", pass)
masterKey, chainID := executeInit(t, "gaiad init")
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill()
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
executeWrite(t, "gaiacli keys add bar", pass)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion"))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99990), fooAcc.GetCoins().AmountOf("fermion"))
}
func TestGaiaCLIDeclareCandidacy(t *testing.T) {
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
masterKey, chainID := executeInit(t, "gaiad init")
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill()
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
// declare candidacy
declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags)
declStr += fmt.Sprintf(" --name=%v", "foo")
declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey)
declStr += fmt.Sprintf(" --amount=%v", "3fermion")
declStr += fmt.Sprintf(" --moniker=%v", "foo-vally")
fmt.Printf("debug declStr: %v\n", declStr)
executeWrite(t, declStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion"))
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
assert.Equal(t, candidate.Address.String(), fooAddr)
assert.Equal(t, int64(3), candidate.Assets.Evaluate())
// TODO timeout issues if not connected to the internet
// unbond a single share
unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
unbondStr += fmt.Sprintf(" --name=%v", "foo")
unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr)
unbondStr += fmt.Sprintf(" --shares=%v", "1")
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
fmt.Printf("debug unbondStr: %v\n", unbondStr)
executeWrite(t, unbondStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion"))
candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
assert.Equal(t, int64(2), candidate.Assets.Evaluate())
}
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
cmd, wc, _ := tests.GoExecuteT(t, cmdStr)
for _, write := range writes {
_, err := wc.Write([]byte(write + "\n"))
require.NoError(t, err)
}
cmd.Wait()
}
func executeWritePrint(t *testing.T, cmdStr string, writes ...string) {
cmd, wc, rc := tests.GoExecuteT(t, cmdStr)
for _, write := range writes {
_, err := wc.Write([]byte(write + "\n"))
require.NoError(t, err)
}
cmd.Wait()
bz := make([]byte, 100000)
rc.Read(bz)
fmt.Printf("debug read: %v\n", string(bz))
}
func executeInit(t *testing.T, cmdStr string) (masterKey, chainID string) {
out := tests.ExecuteT(t, cmdStr, 1)
outCut := "{" + strings.SplitN(out, "{", 2)[1] // weird I'm sorry
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(outCut), &initRes)
require.NoError(t, err)
err = json.Unmarshal(initRes["secret"], &masterKey)
require.NoError(t, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(t, err)
return
}
func executeGetAddrPK(t *testing.T, cmdStr string) (addr, pubKey string) {
out := tests.ExecuteT(t, cmdStr, 2)
var ko keys.KeyOutput
keys.UnmarshalJSON([]byte(out), &ko)
return ko.Address, ko.PubKey
}
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
out := tests.ExecuteT(t, cmdStr, 2)
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
require.NoError(t, err, "out %v, err %v", out, err)
value := initRes["value"]
var acc auth.BaseAccount
_ = json.Unmarshal(value, &acc) //XXX pubkey can't be decoded go amino issue
require.NoError(t, err, "value %v, err %v", string(value), err)
return acc
}
func executeGetCandidate(t *testing.T, cmdStr string) stake.Candidate {
out := tests.ExecuteT(t, cmdStr, 2)
var candidate stake.Candidate
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &candidate)
require.NoError(t, err, "out %v, err %v", out, err)
return candidate
}

View File

@ -12,19 +12,15 @@ import (
"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"
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/commands"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
)
// TODO: distinguish from basecli
// rootCmd is the entry point for this binary
var (
rootCmd = &cobra.Command{
@ -34,10 +30,7 @@ var (
)
func main() {
// disable sorting
cobra.EnableCommandSorting = false
// get the codec
cdc := app.MakeCodec()
// TODO: setup keybase, viper object, etc. to be passed into
@ -53,24 +46,21 @@ func main() {
// add query/post commands (custom to binary)
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
authcmd.GetAccountCmd("main", cdc, authcmd.GetAccountDecoder(cdc)),
stakecmd.GetCmdQueryCandidate("stake", cdc),
//stakecmd.GetCmdQueryCandidates("stake", cdc),
stakecmd.GetCmdQueryDelegatorBond("stake", cdc),
//stakecmd.GetCmdQueryDelegatorBonds("stake", 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),
stakecmd.GetCmdDeclareCandidacy(cdc),
stakecmd.GetCmdEditCandidacy(cdc),
stakecmd.GetCmdDelegate(cdc),
stakecmd.GetCmdUnbond(cdc),
)...)
// add proxy, version and key info
@ -83,6 +73,6 @@ func main() {
)
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.gaiacli"))
executor := cli.PrepareMainCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
executor.Execute()
}

View File

@ -11,7 +11,7 @@ import (
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
)
@ -25,21 +25,21 @@ var (
}
)
// TODO: distinguish from basecoin
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB("gaia", dataDir)
if err != nil {
return nil, err
}
bapp := app.NewBasecoinApp(logger, db)
bapp := app.NewGaiaApp(logger, db)
return bapp, nil
}
func main() {
server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context)
server.AddCommands(rootCmd, app.DefaultGenAppState, generateApp, context)
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiad"))
rootDir := os.ExpandEnv("$HOME/.gaiad")
executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir)
executor.Execute()
}

View File

@ -47,7 +47,7 @@ master_doc = 'index'
# General information about the project.
project = u'Cosmos-SDK'
copyright = u'2017, The Authors'
copyright = u'2018, The Authors'
author = u'The Authors'
# The version info for the project you're documenting, acts as replacement for
@ -69,7 +69,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'old']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

View File

@ -69,12 +69,12 @@ but this is mostly for convenience and not type-safe.
For instance, the `Basecoin` message types are defined in `x/bank/tx.go`:
```go
type SendMsg struct {
type MsgSend struct {
Inputs []Input `json:"inputs"`
Outputs []Output `json:"outputs"`
}
type IssueMsg struct {
type MsgIssue struct {
Banker sdk.Address `json:"banker"`
Outputs []Output `json:"outputs"`
}
@ -83,7 +83,7 @@ type IssueMsg struct {
Each specifies the addresses that must sign the message:
```go
func (msg SendMsg) GetSigners() []sdk.Address {
func (msg MsgSend) GetSigners() []sdk.Address {
addrs := make([]sdk.Address, len(msg.Inputs))
for i, in := range msg.Inputs {
addrs[i] = in.Address
@ -91,7 +91,7 @@ func (msg SendMsg) GetSigners() []sdk.Address {
return addrs
}
func (msg IssueMsg) GetSigners() []sdk.Address {
func (msg MsgIssue) GetSigners() []sdk.Address {
return []sdk.Address{msg.Banker}
}
```
@ -174,13 +174,13 @@ property that it can unmarshal into interface types, but it requires the
relevant types to be registered ahead of type. Registration happens on a
`Codec` object, so as not to taint the global name space.
For instance, in `Basecoin`, we wish to register the `SendMsg` and `IssueMsg`
For instance, in `Basecoin`, we wish to register the `MsgSend` and `MsgIssue`
types:
```go
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
cdc.RegisterConcrete(bank.SendMsg{}, "cosmos-sdk/SendMsg", nil)
cdc.RegisterConcrete(bank.IssueMsg{}, "cosmos-sdk/IssueMsg", nil)
cdc.RegisterConcrete(bank.MsgSend{}, "cosmos-sdk/MsgSend", nil)
cdc.RegisterConcrete(bank.MsgIssue{}, "cosmos-sdk/MsgIssue", nil)
```
Note how each concrete type is given a name - these name determine the type's
@ -319,8 +319,8 @@ func NewHandler(am sdk.AccountMapper) sdk.Handler {
The quintessential SDK application is Basecoin - a simple
multi-asset cryptocurrency. Basecoin consists of a set of
accounts stored in a Merkle tree, where each account may have
many coins. There are two message types: SendMsg and IssueMsg.
SendMsg allows coins to be sent around, while IssueMsg allows a
many coins. There are two message types: MsgSend and MsgIssue.
MsgSend allows coins to be sent around, while MsgIssue allows a
set of predefined users to issue new coins.
## Conclusion

View File

@ -14,14 +14,13 @@ Welcome to the Cosmos SDK!
SDK
---
.. One maxdepth for now
.. toctree::
:maxdepth: 1
sdk/overview.rst
sdk/install.rst
sdk/glossary.rst
sdk/key-management.rst
.. sdk/overview.rst # needs to be updated
.. old/glossary.rst # not completely up to date but has good content
.. Basecoin
.. --------
@ -29,19 +28,17 @@ SDK
.. .. toctree::
:maxdepth: 2
.. basecoin/basics.rst
.. basecoin/extensions.rst
.. old/basecoin/basics.rst # has a decent getting-start tutorial that's relatively up to date, should be consolidated with the other getting started doc
Extensions
----------
.. Extensions
.. ----------
Replay Protection
~~~~~~~~~~~~~~~~~
.. old/basecoin/extensions.rst # probably not worth salvaging
.. toctree::
:maxdepth: 1
.. Replay Protection
.. ~~~~~~~~~~~~~~~~~
x/replay-protection.rst
.. old/replay-protection.rst # not sure if worth salvaging
Staking
@ -50,17 +47,13 @@ Staking
.. toctree::
:maxdepth: 1
staking/intro.rst
staking/key-management.rst
staking/local-testnet.rst
staking/public-testnet.rst
staking/testnet.rst
.. staking/intro.rst
.. staking/key-management.rst
.. staking/local-testnet.rst
.. staking/public-testnet.rst
Extras
------
.. IBC
.. ---
.. One maxdepth for now
.. toctree::
:maxdepth: 1
ibc.rst
.. old/ibc.rst # needs to be updated

View File

@ -15,7 +15,7 @@ while defining as little about that state machine as possible (staying true to t
BaseApp requires stores to be mounted via capabilities keys - handlers can only access
stores they're given the key for. The BaseApp ensures all stores are properly loaded, cached, and committed.
One mounted store is considered the "main" - it holds the latest block header, from which we can find and load the
most recent state.
most recent state ([TODO](https://github.com/cosmos/cosmos-sdk/issues/522)).
BaseApp distinguishes between two handler types - the `AnteHandler` and the `MsgHandler`.
The former is a global validity check (checking nonces, sigs and sufficient balances to pay fees,

View File

@ -1,16 +1,12 @@
Install
=======
If you aren't used to compile go programs and just want the released
version of the code, please head to our
`downloads <https://tendermint.com/download>`__ page to get a
pre-compiled binary for your platform.
Usually, Cosmos SDK can be installed like a normal Go program:
Cosmos SDK can be installed to
``$GOPATH/src/github.com/cosmos/cosmos-sdk`` like a normal Go program:
::
go get -u github.com/cosmos/cosmos-sdk
go get github.com/cosmos/cosmos-sdk
If the dependencies have been updated with breaking changes, or if
another branch is required, ``dep`` is used for dependency management.
@ -20,16 +16,33 @@ repo, the correct way to install is:
::
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
git pull origin master
make all
make get_vendor_deps
make install
make install_examples
This will create the ``basecoin`` binary in ``$GOPATH/bin``.
``make all`` implies ``make get_vendor_deps`` and uses ``dep`` to
install the correct version of all dependencies. It also tests the code,
including some cli tests to make sure your binary behaves properly.
This will install ``gaiad`` and ``gaiacli`` and four example binaries:
``basecoind``, ``basecli``, ``democoind``, and ``democli``.
If you need another branch, make sure to run ``git checkout <branch>``
before ``make all``. And if you switch branches a lot, especially
touching other tendermint repos, you may need to ``make fresh``
sometimes so dep doesn't get confused with all the branches and
versions lying around.
Verify that everything is OK by running:
::
gaiad version
you should see:
::
0.15.0-rc1-9d90c6b
then with:
::
gaiacli version
you should see:
::
0.15.0-rc1-9d90c6b

View File

@ -0,0 +1,18 @@
Key Management
==============
Here we cover many aspects of handling keys within the Cosmos SDK framework.
Pseudo Code
-----------
Generating an address for an ed25519 public key (in pseudo code):
::
const TypeDistinguisher = HexToBytes("1624de6220")
// prepend the TypeDistinguisher as Bytes
SerializedBytes = TypeDistinguisher ++ PubKey.asBytes()
Address = ripemd160(SerializedBytes)

View File

@ -1,10 +1,17 @@
# IBC Specification
IBC(Inter-Blockchain Communication) protocol is used by multiple zones on Cosmos. Using IBC, the zones can send coins or arbitrary data to other zones.
The IBC (Inter Blockchain Communication) protocol specifies how tokens,
non-fungible assets and complex objects can be moved securely between different
zones (independent blockchains). IBC is conceptually similar to TCP/IP in the
sense that anyone can implement it in order to be able to establish IBC
connections with willing clients.
## Terms
How IBC module treats incoming IBC packets is simillar with how BaseApp treats incoming transactions. Therefore, the components of IBC module have their corresponding pair in BaseApp.
How IBC module treats incoming IBC packets is similar to how BaseApp treats
incoming transactions. Therefore, the components of IBC module have their
corresponding pair in BaseApp.
| BaseApp Terms | IBC Terms |
| ------------- | ---------- |
@ -12,20 +19,27 @@ How IBC module treats incoming IBC packets is simillar with how BaseApp treats i
| Tx | Packet |
| Msg | Payload |
## MVP Specifications
### [MVP1](./mvp1.md)
MVP1 will contain the basic functionalities, including packet generation and packet receivement. There will be no security check for incoming packets.
MVP1 will contain the basic functionalities, including packet generation and
incoming packet processing. There will be no security check for incoming
packets.
### [MVP2](./mvp2.md)
IBC module will be more modular in MVP2. Indivisual modules can register custom handlers to IBC module.
The IBC module will be more modular in MVP2. Individual modules can register
custom handlers on the IBC module.
### [MVP3](./mvp3.md)
Light client verification is added to verify the message from the other chain. Registering chains with their ROT(Root Of Trust) is needed.
Light client verification is added to verify an IBC packet from another chain.
Registering chains with their RoT(Root of Trust) is added as well.
### [MVP4](./mvp4.md)
ACK verification / timeout handler helper functions and messaging queue are implemented to make it failsafe. Callbacks will be registered to the dispatcher to handle failure when they register handlers.
ACK verification / timeout handler helper functions and messaging queues are
implemented to make it safe. Callbacks will be registered to the dispatcher to
handle failure when they register handlers.

View File

@ -1,77 +1,205 @@
Using Gaia
==========
Using The Staking Module
========================
This project is a demonstration of the Cosmos Hub with staking functionality; it is
designed to get validator acquianted with staking concepts and procedure.
This project is a demonstration of the Cosmos Hub staking functionality; it is
designed to get validator acquianted with staking concepts and procedures.
Potential validators will be declaring their candidacy, after which users can
delegate and, if they so wish, unbond. This can be practiced using a local or
public testnet.
This example covers initial setup of a two-node testnet between a server in the cloud and a local machine. Begin this tutorial from a cloud machine that you've ``ssh``'d into.
Install
-------
The ``gaia`` tooling is an extension of the Cosmos-SDK; to install:
The ``gaiad`` and ``gaiacli`` binaries:
::
go get github.com/cosmos/gaia
cd $GOPATH/src/github.com/cosmos/gaia
go get github.com/cosmos/cosmos-sdk
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
make get_vendor_deps
make install
It has three primary commands:
Let's jump right into it. First, we initialize some default files:
::
Available Commands:
node The Cosmos Network delegation-game blockchain test
rest-server REST client for gaia commands
client Gaia light client
gaiad init
version Show version info
help Help about any command
which will output:
and a handful of flags that are highlighted only as necessary.
::
The ``gaia node`` command is a proxt for running a tendermint node. You'll be using
this command to either initialize a new node, or - using existing files - joining
the testnet.
I[03-30|11:20:13.365] Found private validator module=main path=/root/.gaiad/config/priv_validator.json
I[03-30|11:20:13.365] Found genesis file module=main path=/root/.gaiad/config/genesis.json
Secret phrase to access coins:
citizen hungry tennis noise park hire glory exercise link glow dolphin labor design grit apple abandon
The ``gaia rest-server`` command is used by the `cosmos UI <https://github.com/cosmos/cosmos-ui>`__.
This tell us we have a ``priv_validator.json`` and ``genesis.json`` in the ``~/.gaiad/config`` directory. A ``config.toml`` was also created in the same directory. It is a good idea to get familiar with those files. Write down the seed.
Lastly, the ``gaia client`` command is the workhorse of the staking module. It allows
for sending various transactions and other types of interaction with a running chain.
that you've setup or joined a testnet.
The next thing we'll need to is add the key from ``priv_validator.json`` to the ``gaiacli`` key manager. For this we need a seed and a password:
Generating Keys
---------------
::
Review the `key management tutorial <../key-management.html>`__ and create one key
if you'll be joining the public testnet, and three keys if you'll be trying out a local
testnet.
gaiacli keys add alice --recover
which will give you three prompts:
::
Enter a passphrase for your key:
Repeat the passphrase:
Enter your recovery seed phrase:
create a password and copy in your seed phrase. The name and address of the key will be output:
::
NAME: ADDRESS: PUBKEY:
alice 67997DD03D527EB439B7193F2B813B05B219CC02 1624DE6220BB89786C1D597050438C728202436552C6226AB67453CDB2A4D2703402FB52B6
You can see all available keys with:
::
gaiacli keys list
Setup Testnet
-------------
The first thing you'll want to do is either `create a local testnet <./local-testnet.html>`__ or
join a `public testnet <./public-testnet.html>`__. Either step is required before proceeding.
Next, we start the daemon (do this in another window):
The rest of this tutorial will assume a local testnet with three participants: ``alice`` will be
the initial validator, ``bob`` will first receives tokens from ``alice`` then declare candidacy
as a validator, and ``charlie`` will bond then unbond to ``bob``. If you're joining the public
testnet, the token amounts will need to be adjusted.
::
gaiad start
and you'll see blocks start streaming through.
For this example, we're doing the above on a cloud machine. The next steps should be done on your local machine or another server in the cloud, which will join the running testnet then bond/unbond.
Accounts
--------
We have:
- ``alice`` the initial validator (in the cloud)
- ``bob`` receives tokens from ``alice`` then declares candidacy (from local machine)
- ``charlie`` will bond and unbond to ``bob`` (from local machine)
Remember that ``alice`` was already created. On your second machine, install the binaries and create two new keys:
::
gaiacli keys add bob
gaiacli keys add charlie
both of which will prompt you for a password. Now we need to copy the ``genesis.json`` and ``config.toml`` from the first machine (with ``alice``) to the second machine. This is a good time to look at both these files.
The ``genesis.json`` should look something like:
::
{
"app_state": {
"accounts": [
{
"address": "1D9B2356CAADF46D3EE3488E3CCE3028B4283DEE",
"coins": [
{
"denom": "fermion",
"amount": 100000
}
]
}
],
"stake": {
"pool": {
"total_supply": 0,
"bonded_shares": {
"num": 0,
"denom": 1
},
"unbonded_shares": {
"num": 0,
"denom": 1
},
"bonded_pool": 0,
"unbonded_pool": 0,
"inflation_last_time": 0,
"inflation": {
"num": 7,
"denom": 100
}
},
"params": {
"inflation_rate_change": {
"num": 13,
"denom": 100
},
"inflation_max": {
"num": 20,
"denom": 100
},
"inflation_min": {
"num": 7,
"denom": 100
},
"goal_bonded": {
"num": 67,
"denom": 100
},
"max_validators": 100,
"bond_denom": "fermion"
}
}
},
"validators": [
{
"pub_key": {
"type": "AC26791624DE60",
"value": "rgpc/ctVld6RpSfwN5yxGBF17R1PwMTdhQ9gKVUZp5g="
},
"power": 10,
"name": ""
}
],
"app_hash": "",
"genesis_time": "0001-01-01T00:00:00Z",
"chain_id": "test-chain-Uv1EVU"
}
To notice is that the ``accounts`` field has a an address and a whole bunch of "mycoin". This is ``alice``'s address (todo: dbl check). Under ``validators`` we see the ``pub_key.data`` field, which will match the same field in the ``priv_validator.json`` file.
The ``config.toml`` is long so let's focus on one field:
::
# Comma separated list of seed nodes to connect to
seeds = ""
On the ``alice`` cloud machine, we don't need to do anything here. Instead, we need its IP address. After copying this file (and the ``genesis.json`` to your local machine, you'll want to put the IP in the ``seeds = "138.197.161.74"`` field, in this case, we have a made-up IP. For joining testnets with many nodes, you can add more comma-seperated IPs to the list.
Now that your files are all setup, it's time to join the network. On your local machine, run:
::
gaiad start
and your new node will connect to the running validator (``alice``).
Sending Tokens
--------------
We'll have ``alice`` who is currently quite rich, send some ``fermions`` to ``bob``:
We'll have ``alice`` send some ``mycoin`` to ``bob``, who has now joined the network:
::
gaia client tx send --amount=1000fermion --sequence=1 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6
gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU
where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag names the sender, and the ``--to`` flag takes ``bob``'s address. You'll see something like:
where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like:
::
@ -101,19 +229,25 @@ where the ``--sequence`` flag is to be incremented for each transaction, the ``-
"height": 2963
}
Check out ``bob``'s account, which should now have 992 fermions:
TODO: check the above with current actual output.
Check out ``bob``'s account, which should now have 1000 mycoin:
::
gaia client query account 5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6
gaiacli account 5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6
Adding a Second Validator
-------------------------
**This section is wrong/needs to be updated**
Next, let's add the second node as a validator.
First, we need the pub_key data:
** need to make bob a priv_Val above?
::
cat $HOME/.gaia2/priv_validator.json
@ -130,7 +264,7 @@ Now ``bob`` can declare candidacy to that pubkey:
::
gaia client tx declare-candidacy --amount=10fermion --name=bob --pubkey=<pub_key data> --moniker=bobby
gaiacli declare-candidacy --amount=10mycoin --name=bob --pubkey=<pub_key data> --moniker=bobby
with an output like:
@ -147,11 +281,11 @@ with an output like:
}
We should see ``bob``'s account balance decrease by 10 fermions:
We should see ``bob``'s account balance decrease by 10 mycoin:
::
gaia client query account 5D93A6059B6592833CBC8FA3DA90EE0382198985
gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985
To confirm for certain the new validator is active, ask the tendermint node:
@ -163,7 +297,7 @@ If you now kill either node, blocks will stop streaming in, because
there aren't enough validators online. Turn it back on and they will
start streaming again.
Now that ``bob`` has declared candidacy, which essentially bonded 10 fermions and made him a validator, we're going to get ``charlie`` to delegate some coins to ``bob``.
Now that ``bob`` has declared candidacy, which essentially bonded 10 mycoin and made him a validator, we're going to get ``charlie`` to delegate some coins to ``bob``.
Delegating
----------
@ -172,13 +306,13 @@ First let's have ``alice`` send some coins to ``charlie``:
::
gaia client tx send --amount=1000fermion --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF
gaiacli tx --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF
Then ``charlie`` will delegate some fermions to ``bob``:
Then ``charlie`` will delegate some mycoin to ``bob``:
::
gaia client tx delegate --amount=10fermion --name=charlie --pubkey=<pub_key data>
gaiacli tx delegate --amount=10mycoin --name=charlie --pubkey=<pub_key data>
You'll see output like:
@ -194,13 +328,13 @@ You'll see output like:
"height": 51585
}
And that's it. You can query ``charlie``'s account to see the decrease in fermions.
And that's it. You can query ``charlie``'s account to see the decrease in mycoin.
To get more information about the candidate, try:
::
gaia client query candidate --pubkey=<pub_key data>
gaiacli query candidate --pubkey=<pub_key data>
and you'll see output similar to:
@ -233,7 +367,7 @@ It's also possible the query the delegator's bond like so:
::
gaia client query delegator-bond --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B
gaiacli query delegator-bond --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B
with an output similar to:
@ -262,9 +396,7 @@ your VotingPower reduce and your account balance increase.
::
gaia client tx unbond --amount=5fermion --name=charlie --pubkey=<pub_key data>
gaia client query account 48F74F48281C89E5E4BE9092F735EA519768E8EF
gaiacli unbond --amount=5mycoin --name=charlie --pubkey=<pub_key data>
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF
See the bond decrease with ``gaia client query delegator-bond`` like above.
That concludes an overview of the ``gaia`` tooling for local testing.
See the bond decrease with ``gaiacli query delegator-bond`` like above.

193
docs/staking/testnet.rst Normal file
View File

@ -0,0 +1,193 @@
Testnet Setup
=============
See the `installation guide <../sdk/install.html>`__ for details on installation.
Here is a quick example to get you off your feet:
First, generate a new key with a name, and save the address:
::
MYNAME=<your name>
gaiacli keys new $MYNAME
gaiacli keys list
MYADDR=<your newly generated address>
Now initialize a gaia chain:
::
gaiad init --home=$HOME/.gaiad1
you should see seed phrase for genesis account in the output & config & data folder in the home directory.
In the config folder, there will be the following files: ``config.toml``, ``genesis.json``, ``node_key.json``, and ``priv_validator.json``.
The genesis file should look like this:
::
{
"genesis_time": "0001-01-01T00:00:00Z",
"chain_id": "test-chain-0TRiTa",
"validators": [
{
"pub_key": {
"type": "AC26791624DE60",
"value": "<value>"
},
"power": 10,
"name": ""
}
],
"app_hash": "",
"app_state": {
"accounts": [
{
"address": "<ADDR>",
"coins": [
{
"denom": "steak",
"amount": 9007199254740992
}
]
}
]
}
}
**Note:** We need to change the denomination of token from default to ``steak`` in the genesis file.
Then, recover the genesis account with ``gaiacli``:
::
gaiacli keys add <name> --recover
By now, you have set up the first node. This is great!
We can add a second node on our local machine by initiating a node in a new directory, and copying in the ``genesis.json``:
::
gaiad init --home=$HOME/.gaiad2
and replace the ``genesis.json`` and ``config.toml`` files:
::
cp $HOME/.gaiad/config/genesis.json $HOME/.gaiad2/config
cp $HOME/.gaiad/config/config.toml $HOME/.gaiad2/config
then, get the node id of first node:
::
gaiad show_node_id --home=$HOME/.gaiad1
We need to also modify $HOME/.gaiad2/config.toml to set new seeds and ports. It should look like:
::
proxy_app = "tcp://127.0.0.1:46668"
moniker = "anonymous"
fast_sync = true
db_backend = "leveldb"
log_level = "state:info,*:error"
[rpc]
laddr = "tcp://0.0.0.0:46667"
[p2p]
laddr = "tcp://0.0.0.0:46666"
persistent_peers = "<node1-ID>@0.0.0.0:46656"
Great, now that we've initialized the chains, we can start both nodes in the background:
::
gaiad start --home=$HOME/.gaiad1 &> gaia1.log &
NODE1_PID=$!
gaia start --home=$HOME/.gaiad2 &> gaia2.log &
NODE2_PID=$!
Note that we save the PID so we can later kill the processes. You can peak at your logs with ``tail gaia1.log``, or follow them for a bit with ``tail -f gaia1.log``.
Nice. We can also lookup the validator set:
::
gaiacli validatorset
There is only **one** validator now. Let's add another one!
First, we need to create a new account:
::
gaiacli keys new <NAME>
Check that we now have two accounts:
::
gaiacli keys list
Then, we try to transfer some ``steak`` to another account:
::
gaiacli send --amount=1000steak --to=$MYADDR2 --name=$NAME --chain-id=<CHAIN-ID> --node=tcp://localhost:46657 --sequence=0
**Note:** We need to be careful with the ``chain-id`` and ``sequence``
Check the balance & sequence with:
::
gaiacli account $MYADDR
We can see the balance of ``$MYADDR2`` is 1000 now.
Finally, let's bond the validator in ``$HOME/gaiad2``. Get the pubkey first:
::
cat $HOME/.gaiad2/config/priv_validator.json | jq .pub_key.value
Go to `this website <http://tomeko.net/online_tools/base64.php?lang=en>`__ to change pubkey from base64 to Hex.
Ok, now we can bond some coins to that pubkey:
::
gaiacli bond --stake=1steak --validator=<validator-pubkey-hex> --sequence=0 --chain-id=<chain-id> --name=test
Nice. We can see there are now two validators:
::
gaiacli validatorset
Check the balance of ``$MYADDR2`` to see the difference: it has 1 less ``steak``!
::
gaiacli account $MYADDR2
To confirm for certain the new validator is active, check tendermint:
::
curl localhost:46657/validators
Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase.
::
gaiacli unbond --sequence=# --chain-id=<chain-id> --name=test
That's it!

View File

@ -61,12 +61,12 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
cdc,
app.capKeyMainStore, // target store
&types.AppAccount{}, // prototype
).Seal()
)
// Add handlers.
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper)
coinKeeper := bank.NewKeeper(app.accountMapper)
ibcMapper := ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(coinKeeper)).
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
@ -94,12 +94,12 @@ func MakeCodec() *wire.Codec {
// Register Msgs
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
cdc.RegisterConcrete(bank.SendMsg{}, "basecoin/Send", nil)
cdc.RegisterConcrete(bank.IssueMsg{}, "basecoin/Issue", nil)
cdc.RegisterConcrete(bank.MsgSend{}, "basecoin/Send", nil)
cdc.RegisterConcrete(bank.MsgIssue{}, "basecoin/Issue", nil)
cdc.RegisterConcrete(ibc.IBCTransferMsg{}, "basecoin/IBCTransferMsg", nil)
cdc.RegisterConcrete(ibc.IBCReceiveMsg{}, "basecoin/IBCReceiveMsg", nil)
cdc.RegisterConcrete(simplestake.BondMsg{}, "basecoin/BondMsg", nil)
cdc.RegisterConcrete(simplestake.UnbondMsg{}, "basecoin/UnbondMsg", nil)
cdc.RegisterConcrete(simplestake.MsgBond{}, "basecoin/BondMsg", nil)
cdc.RegisterConcrete(simplestake.MsgUnbond{}, "basecoin/UnbondMsg", nil)
// Register AppAccount
cdc.RegisterInterface((*sdk.Account)(nil), nil)
@ -123,7 +123,7 @@ func (app *BasecoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
// are registered by MakeTxCodec in bank.RegisterAmino.
err := app.cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").TraceCause(err, "")
return nil, sdk.ErrTxDecode("").Trace(err.Error())
}
return tx, nil
}

View File

@ -42,12 +42,12 @@ var (
0,
}
sendMsg1 = bank.SendMsg{
sendMsg1 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
sendMsg2 = bank.SendMsg{
sendMsg2 = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{
bank.NewOutput(addr2, halfCoins),
@ -55,7 +55,7 @@ var (
},
}
sendMsg3 = bank.SendMsg{
sendMsg3 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, coins),
bank.NewInput(addr4, coins),
@ -66,7 +66,7 @@ var (
},
}
sendMsg4 = bank.SendMsg{
sendMsg4 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr2, coins),
},
@ -75,7 +75,7 @@ var (
},
}
sendMsg5 = bank.SendMsg{
sendMsg5 = bank.MsgSend{
Inputs: []bank.Input{
bank.NewInput(addr1, manyCoins),
},
@ -166,7 +166,7 @@ func TestSortGenesis(t *testing.T) {
// Unsorted coins means invalid
err := sendMsg5.ValidateBasic()
require.Equal(t, sdk.CodeInvalidCoins, err.ABCICode(), err.ABCILog())
require.Equal(t, sdk.CodeInvalidCoins, err.Code(), err.ABCILog())
// Sort coins, should be valid
sendMsg5.Inputs[0].Coins.Sort()
@ -208,7 +208,7 @@ func TestGenesis(t *testing.T) {
assert.Equal(t, acc, res1)
}
func TestSendMsgWithAccounts(t *testing.T) {
func TestMsgSendWithAccounts(t *testing.T) {
bapp := newBasecoinApp()
// Construct some genesis bytes to reflect basecoin/types/AppAccount
@ -243,13 +243,13 @@ func TestSendMsgWithAccounts(t *testing.T) {
tx.Signatures[0].Sequence = 1
res := bapp.Deliver(tx)
assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1)
}
func TestSendMsgMultipleOut(t *testing.T) {
func TestMsgSendMultipleOut(t *testing.T) {
bapp := newBasecoinApp()
genCoins, err := sdk.ParseCoins("42foocoin")
@ -311,7 +311,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
CheckBalance(t, bapp, addr3, "10foocoin")
}
func TestSendMsgDependent(t *testing.T) {
func TestMsgSendDependent(t *testing.T) {
bapp := newBasecoinApp()
genCoins, err := sdk.ParseCoins("42foocoin")
@ -339,7 +339,7 @@ func TestSendMsgDependent(t *testing.T) {
CheckBalance(t, bapp, addr1, "42foocoin")
}
func TestQuizMsg(t *testing.T) {
func TestMsgQuiz(t *testing.T) {
bapp := newBasecoinApp()
// Construct genesis state
@ -437,18 +437,18 @@ func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64,
// Run a Check
res := bapp.Check(tx)
if expPass {
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
require.NotEqual(t, sdk.ABCICodeOK, 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)
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
bapp.EndBlock(abci.RequestEndBlock{})
//bapp.Commit()

View File

@ -66,14 +66,14 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
cdc,
app.capKeyMainStore, // target store
&types.AppAccount{}, // prototype
).Seal()
)
// 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)
coinKeeper := bank.NewKeeper(app.accountMapper)
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper, app.RegisterCodespace(cool.DefaultCodespace))
powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), coinKeeper, app.RegisterCodespace(pow.DefaultCodespace))
ibcMapper := ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(coinKeeper)).
AddRoute("cool", cool.NewHandler(coolKeeper)).
@ -104,15 +104,15 @@ func MakeCodec() *wire.Codec {
// Register Msgs
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
cdc.RegisterConcrete(bank.SendMsg{}, "democoin/Send", nil)
cdc.RegisterConcrete(bank.IssueMsg{}, "democoin/Issue", nil)
cdc.RegisterConcrete(cool.QuizMsg{}, "democoin/Quiz", nil)
cdc.RegisterConcrete(cool.SetTrendMsg{}, "democoin/SetTrend", nil)
cdc.RegisterConcrete(pow.MineMsg{}, "democoin/Mine", nil)
cdc.RegisterConcrete(bank.MsgSend{}, "democoin/Send", nil)
cdc.RegisterConcrete(bank.MsgIssue{}, "democoin/Issue", nil)
cdc.RegisterConcrete(cool.MsgQuiz{}, "democoin/Quiz", nil)
cdc.RegisterConcrete(cool.MsgSetTrend{}, "democoin/SetTrend", nil)
cdc.RegisterConcrete(pow.MsgMine{}, "democoin/Mine", nil)
cdc.RegisterConcrete(ibc.IBCTransferMsg{}, "democoin/IBCTransferMsg", nil)
cdc.RegisterConcrete(ibc.IBCReceiveMsg{}, "democoin/IBCReceiveMsg", nil)
cdc.RegisterConcrete(simplestake.BondMsg{}, "democoin/BondMsg", nil)
cdc.RegisterConcrete(simplestake.UnbondMsg{}, "democoin/UnbondMsg", nil)
cdc.RegisterConcrete(simplestake.MsgBond{}, "democoin/BondMsg", nil)
cdc.RegisterConcrete(simplestake.MsgUnbond{}, "democoin/UnbondMsg", nil)
// Register AppAccount
cdc.RegisterInterface((*sdk.Account)(nil), nil)
@ -136,7 +136,7 @@ func (app *DemocoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
// are registered by MakeTxCodec in bank.RegisterWire.
err := app.cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").TraceCause(err, "")
return nil, sdk.ErrTxDecode("").Trace(err.Error())
}
return tx, nil
}
@ -169,7 +169,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
err = powKeeper.InitGenesis(ctx, genesisState.PowGenesis)
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, "")

View File

@ -36,32 +36,32 @@ var (
0,
}
sendMsg = bank.SendMsg{
sendMsg = bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
quizMsg1 = cool.QuizMsg{
quizMsg1 = cool.MsgQuiz{
Sender: addr1,
CoolAnswer: "icecold",
}
quizMsg2 = cool.QuizMsg{
quizMsg2 = cool.MsgQuiz{
Sender: addr1,
CoolAnswer: "badvibesonly",
}
setTrendMsg1 = cool.SetTrendMsg{
setTrendMsg1 = cool.MsgSetTrend{
Sender: addr1,
Cool: "icecold",
}
setTrendMsg2 = cool.SetTrendMsg{
setTrendMsg2 = cool.MsgSetTrend{
Sender: addr1,
Cool: "badvibesonly",
}
setTrendMsg3 = cool.SetTrendMsg{
setTrendMsg3 = cool.MsgSetTrend{
Sender: addr1,
Cool: "warmandkind",
}
@ -157,7 +157,7 @@ func TestGenesis(t *testing.T) {
assert.Equal(t, acc, res1)
}
func TestSendMsgWithAccounts(t *testing.T) {
func TestMsgSendWithAccounts(t *testing.T) {
bapp := newDemocoinApp()
// Construct some genesis bytes to reflect democoin/types/AppAccount
@ -202,12 +202,12 @@ func TestSendMsgWithAccounts(t *testing.T) {
// Run a Check
res := bapp.Check(tx)
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
// Simulate a Block
bapp.BeginBlock(abci.RequestBeginBlock{})
res = bapp.Deliver(tx)
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
// Check balances
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
@ -218,22 +218,22 @@ func TestSendMsgWithAccounts(t *testing.T) {
// Delivering again should cause replay error
res = bapp.Deliver(tx)
assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInvalidSequence), sdk.ABCICodeType(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)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), sdk.ABCICodeType(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)
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
}
func TestMineMsg(t *testing.T) {
func TestMsgMine(t *testing.T) {
bapp := newDemocoinApp()
// Construct genesis state
@ -271,11 +271,11 @@ func TestMineMsg(t *testing.T) {
assert.Equal(t, acc1, res1)
// Mine and check for reward
mineMsg1 := pow.GenerateMineMsg(addr1, 1, 2)
mineMsg1 := pow.GenerateMsgMine(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)
mineMsg2 := pow.GenerateMsgMine(addr1, 2, 3)
SignCheckDeliver(t, bapp, mineMsg2, 1, true)
CheckBalance(t, bapp, "2pow")
// Mine again - should be invalid
@ -284,7 +284,7 @@ func TestMineMsg(t *testing.T) {
}
func TestQuizMsg(t *testing.T) {
func TestMsgQuiz(t *testing.T) {
bapp := newDemocoinApp()
// Construct genesis state
@ -403,18 +403,18 @@ func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, e
// Run a Check
res := bapp.Check(tx)
if expPass {
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
require.NotEqual(t, sdk.ABCICodeOK, 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)
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
bapp.EndBlock(abci.RequestEndBlock{})
//bapp.Commit()

View File

@ -45,8 +45,8 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder {
// State to Unmarshal
type GenesisState struct {
Accounts []*GenesisAccount `json:"accounts"`
PowGenesis pow.PowGenesis `json:"pow"`
CoolGenesis cool.CoolGenesis `json:"cool"`
POWGenesis pow.Genesis `json:"pow"`
CoolGenesis cool.Genesis `json:"cool"`
}
// GenesisAccount doesn't need pubkey or sequence

View File

@ -34,19 +34,13 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
}
// create the message
msg := cool.NewQuizMsg(from, args[0])
msg := cool.NewMsgQuiz(from, args[0])
// get account name
name := viper.GetString(client.FlagName)
// default to next sequence number if none provided
ctx, err = context.EnsureSequence(ctx)
if err != nil {
return err
}
// build and sign the transaction, then broadcast to Tendermint
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
res, err := ctx.EnsureSignBuildBroadcast(name, msg, cdc)
if err != nil {
return err
}
@ -78,17 +72,11 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
// get account name
name := viper.GetString(client.FlagName)
// default to next sequence number if none provided
ctx, err = context.EnsureSequence(ctx)
if err != nil {
return err
}
// create the message
msg := cool.NewSetTrendMsg(from, args[0])
msg := cool.NewMsgSetTrend(from, args[0])
// build and sign the transaction, then broadcast to Tendermint
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
res, err := ctx.EnsureSignBuildBroadcast(name, msg, cdc)
if err != nil {
return err
}

View File

@ -6,12 +6,15 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Cool errors reserve 400 ~ 499.
const (
DefaultCodespace sdk.CodespaceType = 6
// Cool module reserves error 400-499 lawl
CodeIncorrectCoolAnswer sdk.CodeType = 400
)
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
func ErrIncorrectCoolAnswer(answer string) sdk.Error {
return sdk.NewError(CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer))
func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error {
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer))
}

View File

@ -21,10 +21,10 @@ import (
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case SetTrendMsg:
return handleSetTrendMsg(ctx, k, msg)
case QuizMsg:
return handleQuizMsg(ctx, k, msg)
case MsgSetTrend:
return handleMsgSetTrend(ctx, k, msg)
case MsgQuiz:
return handleMsgQuiz(ctx, k, msg)
default:
errMsg := fmt.Sprintf("Unrecognized cool Msg type: %v", reflect.TypeOf(msg).Name())
return sdk.ErrUnknownRequest(errMsg).Result()
@ -32,19 +32,19 @@ func NewHandler(k Keeper) sdk.Handler {
}
}
// Handle QuizMsg This is the engine of your module
func handleSetTrendMsg(ctx sdk.Context, k Keeper, msg SetTrendMsg) sdk.Result {
// Handle MsgQuiz This is the engine of your module
func handleMsgSetTrend(ctx sdk.Context, k Keeper, msg MsgSetTrend) sdk.Result {
k.setTrend(ctx, msg.Cool)
return sdk.Result{}
}
// Handle QuizMsg This is the engine of your module
func handleQuizMsg(ctx sdk.Context, k Keeper, msg QuizMsg) sdk.Result {
// Handle MsgQuiz This is the engine of your module
func handleMsgQuiz(ctx sdk.Context, k Keeper, msg MsgQuiz) sdk.Result {
correct := k.CheckTrend(ctx, msg.CoolAnswer)
if !correct {
return ErrIncorrectCoolAnswer(msg.CoolAnswer).Result()
return ErrIncorrectCoolAnswer(k.codespace, msg.CoolAnswer).Result()
}
if ctx.IsCheckTx() {

View File

@ -7,14 +7,16 @@ import (
// Keeper - handlers sets/gets of custom variables for your module
type Keeper struct {
ck bank.CoinKeeper
ck bank.Keeper
storeKey sdk.StoreKey // The (unexposed) key used to access the store from the Context.
codespace sdk.CodespaceType
}
// NewKeeper - Returns the Keeper
func NewKeeper(key sdk.StoreKey, bankKeeper bank.CoinKeeper) Keeper {
return Keeper{bankKeeper, key}
func NewKeeper(key sdk.StoreKey, bankKeeper bank.Keeper, codespace sdk.CodespaceType) Keeper {
return Keeper{bankKeeper, key, codespace}
}
// Key to knowing the trend on the streets!
@ -42,7 +44,7 @@ func (k Keeper) CheckTrend(ctx sdk.Context, guessedTrend string) bool {
}
// InitGenesis - store the genesis trend
func (k Keeper) InitGenesis(ctx sdk.Context, data CoolGenesis) error {
func (k Keeper) InitGenesis(ctx sdk.Context, data Genesis) error {
k.setTrend(ctx, data.Trend)
return nil
}

View File

@ -8,39 +8,39 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// A really cool msg type, these fields are can be entirely arbitrary and
// a really cool msg type, these fields are can be entirely arbitrary and
// custom to your message
type SetTrendMsg struct {
type MsgSetTrend struct {
Sender sdk.Address
Cool string
}
// Genesis state - specify genesis trend
type CoolGenesis struct {
// genesis state - specify genesis trend
type Genesis struct {
Trend string `json:"trend"`
}
// New cool message
func NewSetTrendMsg(sender sdk.Address, cool string) SetTrendMsg {
return SetTrendMsg{
// new cool message
func NewMsgSetTrend(sender sdk.Address, cool string) MsgSetTrend {
return MsgSetTrend{
Sender: sender,
Cool: cool,
}
}
// enforce the msg type at compile time
var _ sdk.Msg = SetTrendMsg{}
var _ sdk.Msg = MsgSetTrend{}
// nolint
func (msg SetTrendMsg) Type() string { return "cool" }
func (msg SetTrendMsg) Get(key interface{}) (value interface{}) { return nil }
func (msg SetTrendMsg) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
func (msg SetTrendMsg) String() string {
return fmt.Sprintf("SetTrendMsg{Sender: %v, Cool: %v}", msg.Sender, msg.Cool)
func (msg MsgSetTrend) Type() string { return "cool" }
func (msg MsgSetTrend) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgSetTrend) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
func (msg MsgSetTrend) String() string {
return fmt.Sprintf("MsgSetTrend{Sender: %v, Cool: %v}", msg.Sender, msg.Cool)
}
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
func (msg SetTrendMsg) ValidateBasic() sdk.Error {
func (msg MsgSetTrend) ValidateBasic() sdk.Error {
if len(msg.Sender) == 0 {
return sdk.ErrUnknownAddress(msg.Sender.String()).Trace("")
}
@ -54,7 +54,7 @@ func (msg SetTrendMsg) ValidateBasic() sdk.Error {
}
// Get the bytes for the message signer to sign on
func (msg SetTrendMsg) GetSignBytes() []byte {
func (msg MsgSetTrend) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)
@ -66,32 +66,32 @@ func (msg SetTrendMsg) GetSignBytes() []byte {
// A message type to quiz how cool you are. these fields are can be entirely
// arbitrary and custom to your message
type QuizMsg struct {
type MsgQuiz struct {
Sender sdk.Address
CoolAnswer string
}
// New cool message
func NewQuizMsg(sender sdk.Address, coolerthancool string) QuizMsg {
return QuizMsg{
func NewMsgQuiz(sender sdk.Address, coolerthancool string) MsgQuiz {
return MsgQuiz{
Sender: sender,
CoolAnswer: coolerthancool,
}
}
// enforce the msg type at compile time
var _ sdk.Msg = QuizMsg{}
var _ sdk.Msg = MsgQuiz{}
// nolint
func (msg QuizMsg) Type() string { return "cool" }
func (msg QuizMsg) Get(key interface{}) (value interface{}) { return nil }
func (msg QuizMsg) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
func (msg QuizMsg) String() string {
return fmt.Sprintf("QuizMsg{Sender: %v, CoolAnswer: %v}", msg.Sender, msg.CoolAnswer)
func (msg MsgQuiz) Type() string { return "cool" }
func (msg MsgQuiz) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgQuiz) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
func (msg MsgQuiz) String() string {
return fmt.Sprintf("MsgQuiz{Sender: %v, CoolAnswer: %v}", msg.Sender, msg.CoolAnswer)
}
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
func (msg QuizMsg) ValidateBasic() sdk.Error {
func (msg MsgQuiz) ValidateBasic() sdk.Error {
if len(msg.Sender) == 0 {
return sdk.ErrUnknownAddress(msg.Sender.String()).Trace("")
}
@ -99,7 +99,7 @@ func (msg QuizMsg) ValidateBasic() sdk.Error {
}
// Get the bytes for the message signer to sign on
func (msg QuizMsg) GetSignBytes() []byte {
func (msg MsgQuiz) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)

View File

@ -14,6 +14,7 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
)
// command to mine some pow!
func MineCmd(cdc *wire.Codec) *cobra.Command {
return &cobra.Command{
Use: "mine [difficulty] [count] [nonce] [solution]",
@ -36,12 +37,10 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
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
@ -49,19 +48,13 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
solution := []byte(args[3])
msg := pow.NewMineMsg(from, difficulty, count, nonce, solution)
msg := pow.NewMsgMine(from, difficulty, count, nonce, solution)
// get account name
name := ctx.FromAddressName
// default to next sequence number if none provided
ctx, err = context.EnsureSequence(ctx)
if err != nil {
return err
}
// build and sign the transaction, then broadcast to Tendermint
res, err := ctx.SignBuildBroadcast(name, msg, cdc)
res, err := ctx.EnsureSignBuildBroadcast(name, msg, cdc)
if err != nil {
return err
}

View File

@ -4,9 +4,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// TODO remove, seems hacky
type CodeType = sdk.CodeType
// POW errors reserve 200 ~ 299
const (
DefaultCodespace sdk.CodespaceType = 5
CodeInvalidDifficulty CodeType = 201
CodeNonexistentDifficulty CodeType = 202
CodeNonexistentReward CodeType = 203
@ -40,43 +43,37 @@ func codeToDefaultMsg(code CodeType) string {
}
}
func ErrInvalidDifficulty(msg string) sdk.Error {
return newError(CodeInvalidDifficulty, msg)
// nolint
func ErrInvalidDifficulty(codespace sdk.CodespaceType, msg string) sdk.Error {
return newError(codespace, CodeInvalidDifficulty, msg)
}
func ErrNonexistentDifficulty() sdk.Error {
return newError(CodeNonexistentDifficulty, "")
func ErrNonexistentDifficulty(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeNonexistentDifficulty, "")
}
func ErrNonexistentReward() sdk.Error {
return newError(CodeNonexistentReward, "")
func ErrNonexistentReward(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeNonexistentReward, "")
}
func ErrNonexistentCount() sdk.Error {
return newError(CodeNonexistentCount, "")
func ErrNonexistentCount(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeNonexistentCount, "")
}
func ErrInvalidProof(msg string) sdk.Error {
return newError(CodeInvalidProof, msg)
func ErrInvalidProof(codespace sdk.CodespaceType, msg string) sdk.Error {
return newError(codespace, CodeInvalidProof, msg)
}
func ErrNotBelowTarget(msg string) sdk.Error {
return newError(CodeNotBelowTarget, msg)
func ErrNotBelowTarget(codespace sdk.CodespaceType, msg string) sdk.Error {
return newError(codespace, CodeNotBelowTarget, msg)
}
func ErrInvalidCount(msg string) sdk.Error {
return newError(CodeInvalidCount, msg)
func ErrInvalidCount(codespace sdk.CodespaceType, msg string) sdk.Error {
return newError(codespace, 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 {
func newError(codespace sdk.CodespaceType, code CodeType, msg string) sdk.Error {
msg = msgOrDefaultMsg(msg, code)
return sdk.NewError(code, msg)
return sdk.NewError(codespace, code, msg)
}

View File

@ -6,17 +6,18 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// POW handler
func (pk Keeper) Handler(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MineMsg:
return handleMineMsg(ctx, pk, msg)
case MsgMine:
return handleMsgMine(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 {
func handleMsgMine(ctx sdk.Context, pk Keeper, msg MsgMine) sdk.Result {
// precondition: msg has passed ValidateBasic

View File

@ -20,9 +20,9 @@ func TestPowHandler(t *testing.T) {
am := auth.NewAccountMapper(cdc, 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)
config := NewConfig("pow", int64(1))
ck := bank.NewKeeper(am)
keeper := NewKeeper(capKey, config, ck, DefaultCodespace)
handler := keeper.Handler
@ -30,11 +30,11 @@ func TestPowHandler(t *testing.T) {
count := uint64(1)
difficulty := uint64(2)
err := keeper.InitGenesis(ctx, PowGenesis{uint64(1), uint64(0)})
err := keeper.InitGenesis(ctx, Genesis{uint64(1), uint64(0)})
assert.Nil(t, err)
nonce, proof := mine(addr, count, difficulty)
msg := NewMineMsg(addr, difficulty, count, nonce, proof)
msg := NewMsgMine(addr, difficulty, count, nonce, proof)
result := handler(ctx, msg)
assert.Equal(t, result, sdk.Result{})
@ -51,7 +51,7 @@ func TestPowHandler(t *testing.T) {
difficulty = uint64(4)
nonce, proof = mine(addr, count, difficulty)
msg = NewMineMsg(addr, difficulty, count, nonce, proof)
msg = NewMsgMine(addr, difficulty, count, nonce, proof)
result = handler(ctx, msg)
assert.NotEqual(t, result, sdk.Result{})

View File

@ -9,41 +9,45 @@ import (
)
// module users must specify coin denomination and reward (constant) per PoW solution
type PowConfig struct {
type Config struct {
Denomination string
Reward int64
}
// genesis info must specify starting difficulty and starting count
type PowGenesis struct {
type Genesis struct {
Difficulty uint64 `json:"difficulty"`
Count uint64 `json:"count"`
}
// POW Keeper
type Keeper struct {
key sdk.StoreKey
config PowConfig
ck bank.CoinKeeper
config Config
ck bank.Keeper
codespace sdk.CodespaceType
}
func NewPowConfig(denomination string, reward int64) PowConfig {
return PowConfig{denomination, reward}
func NewConfig(denomination string, reward int64) Config {
return Config{denomination, reward}
}
func NewKeeper(key sdk.StoreKey, config PowConfig, ck bank.CoinKeeper) Keeper {
return Keeper{key, config, ck}
func NewKeeper(key sdk.StoreKey, config Config, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
return Keeper{key, config, ck, codespace}
}
func (pk Keeper) InitGenesis(ctx sdk.Context, genesis PowGenesis) error {
pk.SetLastDifficulty(ctx, genesis.Difficulty)
pk.SetLastCount(ctx, genesis.Count)
// Init Genessis for the POW module
func (k Keeper) InitGenesis(ctx sdk.Context, genesis Genesis) error {
k.SetLastDifficulty(ctx, genesis.Difficulty)
k.SetLastCount(ctx, genesis.Count)
return nil
}
var lastDifficultyKey = []byte("lastDifficultyKey")
func (pk Keeper) GetLastDifficulty(ctx sdk.Context) (uint64, error) {
store := ctx.KVStore(pk.key)
// get the last mining difficulty
func (k Keeper) GetLastDifficulty(ctx sdk.Context) (uint64, error) {
store := ctx.KVStore(k.key)
stored := store.Get(lastDifficultyKey)
if stored == nil {
panic("no stored difficulty")
@ -52,15 +56,17 @@ func (pk Keeper) GetLastDifficulty(ctx sdk.Context) (uint64, error) {
}
}
func (pk Keeper) SetLastDifficulty(ctx sdk.Context, diff uint64) {
store := ctx.KVStore(pk.key)
// set the last mining difficulty
func (k Keeper) SetLastDifficulty(ctx sdk.Context, diff uint64) {
store := ctx.KVStore(k.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)
// get the last count
func (k Keeper) GetLastCount(ctx sdk.Context) (uint64, error) {
store := ctx.KVStore(k.key)
stored := store.Get(countKey)
if stored == nil {
panic("no stored count")
@ -69,45 +75,45 @@ func (pk Keeper) GetLastCount(ctx sdk.Context) (uint64, error) {
}
}
func (pk Keeper) SetLastCount(ctx sdk.Context, count uint64) {
store := ctx.KVStore(pk.key)
// set the last count
func (k Keeper) SetLastCount(ctx sdk.Context, count uint64) {
store := ctx.KVStore(k.key)
store.Set(countKey, []byte(strconv.FormatUint(count, 16)))
}
func (pk Keeper) CheckValid(ctx sdk.Context, difficulty uint64, count uint64) (uint64, uint64, sdk.Error) {
// Is the keeper state valid?
func (k Keeper) CheckValid(ctx sdk.Context, difficulty uint64, count uint64) (uint64, uint64, sdk.Error) {
lastDifficulty, err := pk.GetLastDifficulty(ctx)
lastDifficulty, err := k.GetLastDifficulty(ctx)
if err != nil {
return 0, 0, ErrNonexistentDifficulty()
return 0, 0, ErrNonexistentDifficulty(k.codespace)
}
newDifficulty := lastDifficulty + 1
lastCount, err := pk.GetLastCount(ctx)
lastCount, err := k.GetLastCount(ctx)
if err != nil {
return 0, 0, ErrNonexistentCount()
return 0, 0, ErrNonexistentCount(k.codespace)
}
newCount := lastCount + 1
if count != newCount {
return 0, 0, ErrInvalidCount(fmt.Sprintf("invalid count: was %d, should have been %d", count, newCount))
return 0, 0, ErrInvalidCount(k.codespace, 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 0, 0, ErrInvalidDifficulty(k.codespace, 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}})
// Add some coins for a POW well done
func (k Keeper) ApplyValid(ctx sdk.Context, sender sdk.Address, newDifficulty uint64, newCount uint64) sdk.Error {
_, ckErr := k.ck.AddCoins(ctx, sender, []sdk.Coin{sdk.Coin{k.config.Denomination, k.config.Reward}})
if ckErr != nil {
return ckErr
}
pk.SetLastDifficulty(ctx, newDifficulty)
pk.SetLastCount(ctx, newCount)
k.SetLastDifficulty(ctx, newDifficulty)
k.SetLastCount(ctx, newCount)
return nil
}

View File

@ -33,11 +33,11 @@ func TestPowKeeperGetSet(t *testing.T) {
am := auth.NewAccountMapper(cdc, 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)
config := NewConfig("pow", int64(1))
ck := bank.NewKeeper(am)
keeper := NewKeeper(capKey, config, ck, DefaultCodespace)
err := keeper.InitGenesis(ctx, PowGenesis{uint64(1), uint64(0)})
err := keeper.InitGenesis(ctx, Genesis{uint64(1), uint64(0)})
assert.Nil(t, err)
res, err := keeper.GetLastDifficulty(ctx)

View File

@ -9,9 +9,10 @@ import (
crypto "github.com/tendermint/go-crypto"
)
func GenerateMineMsg(sender sdk.Address, count uint64, difficulty uint64) MineMsg {
// generate the mine message
func GenerateMsgMine(sender sdk.Address, count uint64, difficulty uint64) MsgMine {
nonce, hash := mine(sender, count, difficulty)
return NewMineMsg(sender, difficulty, count, nonce, hash)
return NewMsgMine(sender, difficulty, count, nonce, hash)
}
func hash(sender sdk.Address, count uint64, nonce uint64) []byte {

View File

@ -13,8 +13,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// MineMsg - mine some coins with PoW
type MineMsg struct {
// MsgMine - mine some coins with PoW
type MsgMine struct {
Sender sdk.Address `json:"sender"`
Difficulty uint64 `json:"difficulty"`
Count uint64 `json:"count"`
@ -23,21 +23,23 @@ type MineMsg struct {
}
// enforce the msg type at compile time
var _ sdk.Msg = MineMsg{}
var _ sdk.Msg = MsgMine{}
// 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}
// NewMsgMine - construct mine message
func NewMsgMine(sender sdk.Address, difficulty uint64, count uint64, nonce uint64, proof []byte) MsgMine {
return MsgMine{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)
// nolint
func (msg MsgMine) Type() string { return "pow" }
func (msg MsgMine) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgMine) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} }
func (msg MsgMine) String() string {
return fmt.Sprintf("MsgMine{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 {
// validate the mine message
func (msg MsgMine) ValidateBasic() sdk.Error {
// check hash
var data []byte
// hash must include sender, so no other users can race the tx
@ -52,7 +54,7 @@ func (msg MineMsg) ValidateBasic() sdk.Error {
hex.Encode(hashHex, hash)
hashHex = hashHex[:16]
if !bytes.Equal(hashHex, msg.Proof) {
return ErrInvalidProof(fmt.Sprintf("hashHex: %s, proof: %s", hashHex, msg.Proof))
return ErrInvalidProof(DefaultCodespace, fmt.Sprintf("hashHex: %s, proof: %s", hashHex, msg.Proof))
}
// check proof below difficulty
@ -60,16 +62,17 @@ func (msg MineMsg) ValidateBasic() sdk.Error {
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))
return ErrInvalidProof(DefaultCodespace, fmt.Sprintf("proof: %s", msg.Proof))
}
if hashUint >= target {
return ErrNotBelowTarget(fmt.Sprintf("hashuint: %d, target: %d", hashUint, target))
return ErrNotBelowTarget(DefaultCodespace, fmt.Sprintf("hashuint: %d, target: %d", hashUint, target))
}
return nil
}
func (msg MineMsg) GetSignBytes() []byte {
// get the mine message sign bytes
func (msg MsgMine) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)

View File

@ -9,70 +9,72 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestNewMineMsg(t *testing.T) {
func TestNewMsgMine(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 0, 0, 0, []byte("")}
equiv := NewMineMsg(addr, 0, 0, 0, []byte(""))
msg := MsgMine{addr, 0, 0, 0, []byte("")}
equiv := NewMsgMine(addr, 0, 0, 0, []byte(""))
assert.Equal(t, msg, equiv, "%s != %s", msg, equiv)
}
func TestMineMsgType(t *testing.T) {
func TestMsgMineType(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 0, 0, 0, []byte("")}
msg := MsgMine{addr, 0, 0, 0, []byte("")}
assert.Equal(t, msg.Type(), "pow")
}
func TestMineMsgValidation(t *testing.T) {
func TestMsgMineValidation(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
count++
nonce, proof := mine(addr, count, difficulty)
msg := MineMsg{addr, difficulty, count, nonce, proof}
msg := MsgMine{addr, difficulty, count, nonce, proof}
err := msg.ValidateBasic()
assert.Nil(t, err, "error with difficulty %d - %+v", difficulty, err)
msg.Count += 1
msg.Count++
err = msg.ValidateBasic()
assert.NotNil(t, err, "count was wrong, should have thrown error with msg %s", msg)
msg.Count -= 1
msg.Nonce += 1
msg.Count--
msg.Nonce++
err = msg.ValidateBasic()
assert.NotNil(t, err, "nonce was wrong, should have thrown error with msg %s", msg)
msg.Nonce -= 1
msg.Nonce--
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) {
func TestMsgMineString(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 0, 0, 0, []byte("abc")}
msg := MsgMine{addr, 0, 0, 0, []byte("abc")}
res := msg.String()
assert.Equal(t, res, "MineMsg{Sender: 73656E646572, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}")
assert.Equal(t, res, "MsgMine{Sender: 73656E646572, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}")
}
func TestMineMsgGet(t *testing.T) {
func TestMsgMineGet(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 0, 0, 0, []byte("")}
msg := MsgMine{addr, 0, 0, 0, []byte("")}
res := msg.Get(nil)
assert.Nil(t, res)
}
func TestMineMsgGetSignBytes(t *testing.T) {
func TestMsgMineGetSignBytes(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 1, 1, 1, []byte("abc")}
msg := MsgMine{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) {
func TestMsgMineGetSigners(t *testing.T) {
addr := sdk.Address([]byte("sender"))
msg := MineMsg{addr, 1, 1, 1, []byte("abc")}
msg := MsgMine{addr, 1, 1, 1, []byte("abc")}
res := msg.GetSigners()
assert.Equal(t, fmt.Sprintf("%v", res), "[73656E646572]")
}

View File

@ -41,7 +41,7 @@ func main() {
baseApp.SetTxDecoder(decodeTx)
// Set a handler Route.
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore))
baseApp.Router().AddRoute("kvstore", Handler(capKeyMainStore))
// Load latest version.
if err := baseApp.LoadLatestVersion(capKeyMainStore); err != nil {
@ -65,11 +65,12 @@ func main() {
return
}
func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler {
// KVStore Handler
func Handler(storeKey sdk.StoreKey) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
dTx, ok := msg.(kvstoreTx)
if !ok {
panic("KVStoreHandler should only receive kvstoreTx")
panic("Handler should only receive kvstoreTx")
}
// tx is already unmarshalled

View File

@ -70,16 +70,16 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error {
return nil
}
// generate secrete and address
// generate secret and address
addr, secret, err := GenerateCoinKey()
if err != nil {
return err
}
var DEFAULT_DENOM = "mycoin"
var defaultDenom = "mycoin"
// Now, we want to add the custom app_state
appState, err := c.genAppState(args, addr, DEFAULT_DENOM)
appState, err := c.genAppState(args, addr, defaultDenom)
if err != nil {
return err
}

View File

@ -1,9 +1,12 @@
package server
import (
"encoding/hex"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/p2p"
@ -12,73 +15,59 @@ import (
// 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
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.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{
flagJSON := "json"
cmd := cobra.Command{
Use: "show_validator",
Short: "Show this node's validator info",
RunE: cmd.run,
}
}
RunE: func(cmd *cobra.Command, args []string) error {
type showValidator struct {
context *Context
}
func (s showValidator) run(cmd *cobra.Command, args []string) error {
cfg := s.context.Config
cfg := ctx.Config
privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile())
pubKeyJSONBytes, err := cdc.MarshalJSON(privValidator.PubKey)
pubKey := privValidator.PubKey
if viper.GetBool(flagJSON) {
pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey)
if err != nil {
return err
}
fmt.Println(string(pubKeyJSONBytes))
return nil
}
//------------------------------------------------------------------------------
pubKeyHex := strings.ToUpper(hex.EncodeToString(pubKey.Bytes()))
fmt.Println(pubKeyHex)
return nil
},
}
cmd.Flags().Bool(flagJSON, false, "get machine parseable output")
return &cmd
}
// 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)
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.Config
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)
return nil
},
}
}

View File

@ -14,6 +14,7 @@ import (
"github.com/tendermint/tmlibs/log"
)
// server context
type Context struct {
Config *cfg.Config
Logger log.Logger
@ -59,6 +60,7 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error
}
}
// add server commands
func AddCommands(
rootCmd *cobra.Command,
appState GenAppState, appCreator AppCreator,

View File

@ -26,13 +26,12 @@ type cacheKVStore struct {
var _ CacheKVStore = (*cacheKVStore)(nil)
// nolint
func NewCacheKVStore(parent KVStore) *cacheKVStore {
ci := &cacheKVStore{
cache: make(map[string]cValue),
parent: parent,
}
return ci
}
@ -170,9 +169,8 @@ func (ci *cacheKVStore) dirtyItems(ascending bool) []cmn.KVPair {
sort.Slice(items, func(i, j int) bool {
if ascending {
return bytes.Compare(items[i].Key, items[j].Key) < 0
} else {
return bytes.Compare(items[i].Key, items[j].Key) > 0
}
return bytes.Compare(items[i].Key, items[j].Key) > 0
})
return items
}

View File

@ -105,7 +105,7 @@ func TestCacheKVIteratorBounds(t *testing.T) {
k, v := itr.Key(), itr.Value()
assert.Equal(t, keyFmt(i), k)
assert.Equal(t, valFmt(i), v)
i += 1
i++
}
assert.Equal(t, nItems, i)
@ -113,7 +113,7 @@ func TestCacheKVIteratorBounds(t *testing.T) {
itr = st.Iterator(bz("money"), nil)
i = 0
for ; itr.Valid(); itr.Next() {
i += 1
i++
}
assert.Equal(t, 0, i)
@ -124,7 +124,7 @@ func TestCacheKVIteratorBounds(t *testing.T) {
k, v := itr.Key(), itr.Value()
assert.Equal(t, keyFmt(i), k)
assert.Equal(t, valFmt(i), v)
i += 1
i++
}
assert.Equal(t, 3, i)
@ -135,7 +135,7 @@ func TestCacheKVIteratorBounds(t *testing.T) {
k, v := itr.Key(), itr.Value()
assert.Equal(t, keyFmt(i), k)
assert.Equal(t, valFmt(i), v)
i += 1
i++
}
assert.Equal(t, 4, i)
}
@ -369,7 +369,7 @@ func assertIterateDomain(t *testing.T, st KVStore, expectedN int) {
k, v := itr.Key(), itr.Value()
assert.Equal(t, keyFmt(i), k)
assert.Equal(t, valFmt(i), v)
i += 1
i++
}
assert.Equal(t, expectedN, i)
}
@ -397,7 +397,7 @@ func assertIterateDomainCheck(t *testing.T, st KVStore, mem dbm.DB, r []keyRange
itr.Next()
itr2.Next()
i += 1
i++
}
assert.False(t, itr.Valid())
@ -479,10 +479,10 @@ func (krc *keyRangeCounter) valid() bool {
func (krc *keyRangeCounter) next() {
thisKeyRange := krc.keyRanges[krc.rangeIdx]
if krc.idx == thisKeyRange.len()-1 {
krc.rangeIdx += 1
krc.rangeIdx++
krc.idx = 0
} else {
krc.idx += 1
krc.idx++
}
}

View File

@ -151,9 +151,8 @@ func (iter *cacheMergeIterator) Close() {
func (iter *cacheMergeIterator) compare(a, b []byte) int {
if iter.ascending {
return bytes.Compare(a, b)
} else {
return bytes.Compare(a, b) * -1
}
return bytes.Compare(a, b) * -1
}
// Skip all delete-items from the cache w/ `key < until`. After this function,

View File

@ -10,7 +10,7 @@ type dbStoreAdapter struct {
}
// Implements Store.
func (_ dbStoreAdapter) GetStoreType() StoreType {
func (dbStoreAdapter) GetStoreType() StoreType {
return sdk.StoreTypeDB
}

View File

@ -2,6 +2,7 @@ package store
import (
"bytes"
cmn "github.com/tendermint/tmlibs/common"
)
@ -22,9 +23,8 @@ func Last(st KVStore, start, end []byte) (kv cmn.KVPair, ok bool) {
if !iter.Valid() {
if v := st.Get(start); v != nil {
return cmn.KVPair{cp(start), cp(v)}, true
} else {
return kv, false
}
return kv, false
}
defer iter.Close()

View File

@ -17,6 +17,7 @@ const (
defaultIAVLNumHistory = 1<<53 - 1 // DEPRECATED
)
// load the iavl store
func LoadIAVLStore(db dbm.DB, id CommitID) (CommitStore, error) {
tree := iavl.NewVersionedTree(db, defaultIAVLCacheSize)
_, err := tree.LoadVersion(id.Version)

View File

@ -80,7 +80,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -91,7 +91,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -102,7 +102,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -113,7 +113,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -124,7 +124,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -135,7 +135,7 @@ func TestIAVLIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, treeData[expectedKey])
i += 1
i++
}
assert.Equal(t, len(expected), i)
}
@ -164,7 +164,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, expectedKey)
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -179,7 +179,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, []byte("test4"))
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -194,7 +194,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, []byte("test4"))
i += 1
i++
}
assert.Equal(t, len(expected), i)
}
@ -223,7 +223,7 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, expectedKey)
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -238,7 +238,7 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, []byte("test4"))
i += 1
i++
}
assert.Equal(t, len(expected), i)
@ -253,7 +253,7 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) {
key, value := iter.Key(), iter.Value()
assert.EqualValues(t, key, expectedKey)
assert.EqualValues(t, value, []byte("test4"))
i += 1
i++
}
assert.Equal(t, len(expected), i)
}

View File

@ -33,6 +33,7 @@ type rootMultiStore struct {
var _ CommitMultiStore = (*rootMultiStore)(nil)
var _ Queryable = (*rootMultiStore)(nil)
// nolint
func NewCommitMultiStore(db dbm.DB) *rootMultiStore {
return &rootMultiStore{
db: db,
@ -267,7 +268,7 @@ func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storePar
}
func (rs *rootMultiStore) nameToKey(name string) StoreKey {
for key, _ := range rs.storesParams {
for key := range rs.storesParams {
if key.Name() == name {
return key
}

View File

@ -128,34 +128,34 @@ func TestMultiStoreQuery(t *testing.T) {
// Test bad path.
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
qres := multi.Query(query)
assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
query.Path = "h897fy32890rf63296r92"
qres = multi.Query(query)
assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
// Test invalid store name.
query.Path = "/garbage/key"
qres = multi.Query(query)
assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
// Test valid query with data.
query.Path = "/store1/key"
qres = multi.Query(query)
assert.Equal(t, uint32(sdk.CodeOK), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
assert.Equal(t, v, qres.Value)
// Test valid but empty query.
query.Path = "/store2/key"
query.Prove = true
qres = multi.Query(query)
assert.Equal(t, uint32(sdk.CodeOK), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
assert.Nil(t, qres.Value)
// Test store2 data.
query.Data = k2
qres = multi.Query(query)
assert.Equal(t, uint32(sdk.CodeOK), qres.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
assert.Equal(t, v2, qres.Value)
}

View File

@ -5,6 +5,7 @@ import (
)
// Import cosmos-sdk/types/store.go for convenience.
// nolint
type Store = types.Store
type Committer = types.Committer
type CommitStore = types.CommitStore

54
tests/gobash.go Normal file
View File

@ -0,0 +1,54 @@
package tests
import (
"fmt"
"io"
"os/exec"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func getCmd(t *testing.T, command string) *exec.Cmd {
//split command into command and args
split := strings.Split(command, " ")
require.True(t, len(split) > 0, "no command provided")
var cmd *exec.Cmd
if len(split) == 1 {
cmd = exec.Command(split[0])
} else {
cmd = exec.Command(split[0], split[1:]...)
}
return cmd
}
// Execute the command, return standard output and error, try a few times if requested
func ExecuteT(t *testing.T, command string, trials int) (out string) {
cmd := getCmd(t, command)
bz, err := cmd.CombinedOutput()
if err != nil && trials > 1 {
fmt.Printf("trial %v, retrying: %v\n", trials, command)
time.Sleep(time.Second * 10)
return ExecuteT(t, command, trials-1)
}
require.NoError(t, err, string(bz))
out = strings.Trim(string(bz), "\n") //trim any new lines
time.Sleep(time.Second)
return out
}
// Asynchronously execute the command, return standard output and error
func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteCloser, pipeOut io.ReadCloser) {
cmd = getCmd(t, command)
pipeIn, err := cmd.StdinPipe()
require.NoError(t, err)
pipeOut, err = cmd.StdoutPipe()
require.NoError(t, err)
go cmd.Start()
time.Sleep(time.Second)
return cmd, pipeIn, pipeOut
}

35
types/codespacer.go Normal file
View File

@ -0,0 +1,35 @@
package types
// Codespacer is a simple struct to track reserved codespaces
type Codespacer struct {
reserved map[CodespaceType]bool
}
// NewCodespacer generates a new Codespacer with the starting codespace
func NewCodespacer() *Codespacer {
return &Codespacer{
reserved: make(map[CodespaceType]bool),
}
}
// RegisterNext reserves and returns the next available codespace, starting from a default, and panics if the maximum codespace is reached
func (c *Codespacer) RegisterNext(codespace CodespaceType) CodespaceType {
for {
if !c.reserved[codespace] {
c.reserved[codespace] = true
return codespace
}
codespace++
if codespace == MaximumCodespace {
panic("Maximum codespace reached!")
}
}
}
// RegisterOrPanic reserved a codespace or panics if it is unavailable
func (c *Codespacer) RegisterOrPanic(codespace CodespaceType) {
if c.reserved[codespace] {
panic("Cannot register codespace, already reserved")
}
c.reserved[codespace] = true
}

47
types/codespacer_test.go Normal file
View File

@ -0,0 +1,47 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestRegisterNext(t *testing.T) {
codespacer := NewCodespacer()
// unregistered, allow
code1 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code1, CodespaceType(2))
// registered, pick next
code2 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code2, CodespaceType(3))
// pick next
code3 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code3, CodespaceType(4))
// skip 1
code4 := codespacer.RegisterNext(CodespaceType(6))
require.Equal(t, code4, CodespaceType(6))
code5 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code5, CodespaceType(5))
code6 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code6, CodespaceType(7))
// panic on maximum
defer func() {
r := recover()
require.NotNil(t, r, "Did not panic on maximum codespace")
}()
codespacer.RegisterNext(MaximumCodespace - 1)
codespacer.RegisterNext(MaximumCodespace - 1)
}
func TestRegisterOrPanic(t *testing.T) {
codespacer := NewCodespacer()
// unregistered, allow
code1 := codespacer.RegisterNext(CodespaceType(2))
require.Equal(t, code1, CodespaceType(2))
// panic on duplicate
defer func() {
r := recover()
require.NotNil(t, r, "Did not panic on duplicate codespace")
}()
codespacer.RegisterOrPanic(CodespaceType(2))
}

View File

@ -2,25 +2,44 @@ package types
import (
"fmt"
"runtime"
cmn "github.com/tendermint/tmlibs/common"
abci "github.com/tendermint/abci/types"
)
// ABCI Response Code
type CodeType uint32
// ABCICodeType - combined codetype / codespace
type ABCICodeType uint32
// is everything okay?
func (code CodeType) IsOK() bool {
if code == CodeOK {
// CodeType - code identifier within codespace
type CodeType uint16
// CodespaceType - codespace identifier
type CodespaceType uint16
// IsOK - is everything okay?
func (code ABCICodeType) IsOK() bool {
if code == ABCICodeOK {
return true
}
return false
}
// ABCI Response Codes
// Base SDK reserves 0 - 99.
// get the abci code from the local code and codespace
func ToABCICode(space CodespaceType, code CodeType) ABCICodeType {
// TODO: Make Tendermint more aware of codespaces.
if space == CodespaceRoot && code == CodeOK {
return ABCICodeOK
}
return ABCICodeType((uint32(space) << 16) | uint32(code))
}
// SDK error codes
const (
// ABCI error codes
ABCICodeOK ABCICodeType = 0
// Base error codes
CodeOK CodeType = 0
CodeInternal CodeType = 1
CodeTxDecode CodeType = 2
@ -34,7 +53,14 @@ const (
CodeInsufficientCoins CodeType = 10
CodeInvalidCoins CodeType = 11
CodeGenesisParse CodeType = 0xdead // TODO: remove ? // why remove?
// CodespaceRoot is a codespace for error codes in this file only.
// Notice that 0 is an "unset" codespace, which can be overridden with
// Error.WithDefaultCodespace().
CodespaceUndefined CodespaceType = 0
CodespaceRoot CodespaceType = 1
// Maximum reservable codespace (2^16 - 1)
MaximumCodespace CodespaceType = 65535
)
// NOTE: Don't stringer this, we'll put better messages in later.
@ -44,8 +70,6 @@ func CodeToDefaultMsg(code CodeType) string {
return "Internal error"
case CodeTxDecode:
return "Tx parse error"
case CodeGenesisParse:
return "Genesis parse error"
case CodeInvalidSequence:
return "Invalid sequence"
case CodeUnauthorized:
@ -75,40 +99,37 @@ func CodeToDefaultMsg(code CodeType) string {
// nolint
func ErrInternal(msg string) Error {
return newError(CodeInternal, msg)
return newErrorWithRootCodespace(CodeInternal, msg)
}
func ErrTxDecode(msg string) Error {
return newError(CodeTxDecode, msg)
}
func ErrGenesisParse(msg string) Error {
return newError(CodeGenesisParse, msg)
return newErrorWithRootCodespace(CodeTxDecode, msg)
}
func ErrInvalidSequence(msg string) Error {
return newError(CodeInvalidSequence, msg)
return newErrorWithRootCodespace(CodeInvalidSequence, msg)
}
func ErrUnauthorized(msg string) Error {
return newError(CodeUnauthorized, msg)
return newErrorWithRootCodespace(CodeUnauthorized, msg)
}
func ErrInsufficientFunds(msg string) Error {
return newError(CodeInsufficientFunds, msg)
return newErrorWithRootCodespace(CodeInsufficientFunds, msg)
}
func ErrUnknownRequest(msg string) Error {
return newError(CodeUnknownRequest, msg)
return newErrorWithRootCodespace(CodeUnknownRequest, msg)
}
func ErrInvalidAddress(msg string) Error {
return newError(CodeInvalidAddress, msg)
return newErrorWithRootCodespace(CodeInvalidAddress, msg)
}
func ErrUnknownAddress(msg string) Error {
return newError(CodeUnknownAddress, msg)
return newErrorWithRootCodespace(CodeUnknownAddress, msg)
}
func ErrInvalidPubKey(msg string) Error {
return newError(CodeInvalidPubKey, msg)
return newErrorWithRootCodespace(CodeInvalidPubKey, msg)
}
func ErrInsufficientCoins(msg string) Error {
return newError(CodeInsufficientCoins, msg)
return newErrorWithRootCodespace(CodeInsufficientCoins, msg)
}
func ErrInvalidCoins(msg string) Error {
return newError(CodeInvalidCoins, msg)
return newErrorWithRootCodespace(CodeInvalidCoins, msg)
}
//----------------------------------------
@ -117,104 +138,98 @@ func ErrInvalidCoins(msg string) Error {
// sdk Error type
type Error interface {
Error() string
ABCICode() CodeType
Code() CodeType
Codespace() CodespaceType
ABCILog() string
ABCICode() ABCICodeType
WithDefaultCodespace(codespace CodespaceType) Error
Trace(msg string) Error
TraceCause(cause error, msg string) Error
Cause() error
T() interface{}
Result() Result
QueryResult() abci.ResponseQuery
}
func NewError(code CodeType, msg string) Error {
return newError(code, msg)
// NewError - create an error
func NewError(codespace CodespaceType, code CodeType, msg string) Error {
return newError(codespace, code, msg)
}
type traceItem struct {
msg string
filename string
lineno int
func newErrorWithRootCodespace(code CodeType, msg string) *sdkError {
return newError(CodespaceRoot, code, msg)
}
func (ti traceItem) String() string {
return fmt.Sprintf("%v:%v %v", ti.filename, ti.lineno, ti.msg)
}
type sdkError struct {
code CodeType
msg string
cause error
traces []traceItem
}
func newError(code CodeType, msg string) *sdkError {
// TODO capture stacktrace if ENV is set.
func newError(codespace CodespaceType, code CodeType, msg string) *sdkError {
if msg == "" {
msg = CodeToDefaultMsg(code)
}
return &sdkError{
codespace: codespace,
code: code,
msg: msg,
cause: nil,
traces: nil,
err: cmn.NewErrorWithT(code, msg),
}
}
type sdkError struct {
codespace CodespaceType
code CodeType
err cmn.Error
}
// Implements ABCIError.
func (err *sdkError) Error() string {
return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.msg, err.cause, len(err.traces))
return fmt.Sprintf("Error{%d:%d,%#v}", err.codespace, err.code, err.err)
}
// Implements ABCIError.
func (err *sdkError) ABCICode() CodeType {
func (err *sdkError) ABCICode() ABCICodeType {
return ToABCICode(err.codespace, err.code)
}
// Implements Error.
func (err *sdkError) Codespace() CodespaceType {
return err.codespace
}
// Implements Error.
func (err *sdkError) Code() CodeType {
return err.code
}
// Implements ABCIError.
func (err *sdkError) ABCILog() string {
traceLog := ""
for _, ti := range err.traces {
traceLog += ti.String() + "\n"
}
return fmt.Sprintf("msg: %v\ntrace:\n%v",
err.msg,
traceLog,
)
return fmt.Sprintf(`=== ABCI Log ===
Codespace: %v
Code: %v
ABCICode: %v
Error: %#v
=== /ABCI Log ===
`, err.codespace, err.code, err.ABCICode(), err.err)
}
// Add tracing information with msg.
func (err *sdkError) Trace(msg string) Error {
return err.doTrace(msg, 2)
return &sdkError{
codespace: err.codespace,
code: err.code,
err: err.err.Trace(msg),
}
}
// Add tracing information with cause and msg.
func (err *sdkError) TraceCause(cause error, msg string) Error {
err.cause = cause
return err.doTrace(msg, 2)
// Implements Error.
func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error {
codespace := err.codespace
if codespace == CodespaceUndefined {
codespace = cs
}
return &sdkError{
codespace: codespace,
code: err.code,
err: err.err,
}
}
func (err *sdkError) doTrace(msg string, n int) Error {
_, fn, line, ok := runtime.Caller(n)
if !ok {
if fn == "" {
fn = "<unknown>"
}
if line <= 0 {
line = -1
}
}
// Include file & line number & msg.
// Do not include the whole stack trace.
err.traces = append(err.traces, traceItem{
filename: fn,
lineno: line,
msg: msg,
})
return err
}
func (err *sdkError) Cause() error {
return err.cause
func (err *sdkError) T() interface{} {
return err.err.T()
}
func (err *sdkError) Result() Result {

View File

@ -16,7 +16,6 @@ var codeTypes = []CodeType{
CodeUnknownRequest,
CodeUnknownAddress,
CodeInvalidPubKey,
CodeGenesisParse,
}
type errFn func(msg string) Error
@ -30,14 +29,12 @@ var errFns = []errFn{
ErrUnknownRequest,
ErrUnknownAddress,
ErrInvalidPubKey,
ErrGenesisParse,
}
func TestCodeType(t *testing.T) {
assert.True(t, CodeOK.IsOK())
assert.True(t, ABCICodeOK.IsOK())
for _, c := range codeTypes {
assert.False(t, c.IsOK())
msg := CodeToDefaultMsg(c)
assert.False(t, strings.HasPrefix(msg, "Unknown code"))
}
@ -47,7 +44,7 @@ func TestErrFn(t *testing.T) {
for i, errFn := range errFns {
err := errFn("")
codeType := codeTypes[i]
assert.Equal(t, err.ABCICode(), codeType)
assert.Equal(t, err.Result().Code, codeType)
assert.Equal(t, err.Code(), codeType)
assert.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType))
}
}

View File

@ -97,23 +97,23 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) {
switch len(str) {
case 1:
if len(str[0]) == 0 {
return f, NewError(CodeUnknownRequest, "not a decimal string")
return f, ErrUnknownRequest("not a decimal string")
}
numStr = str[0]
case 2:
if len(str[0]) == 0 || len(str[1]) == 0 {
return f, NewError(CodeUnknownRequest, "not a decimal string")
return f, ErrUnknownRequest("not a decimal string")
}
numStr = str[0] + str[1]
len := int64(len(str[1]))
denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64()
default:
return f, NewError(CodeUnknownRequest, "not a decimal string")
return f, ErrUnknownRequest("not a decimal string")
}
num, errConv := strconv.Atoi(numStr)
if errConv != nil {
return f, NewError(CodeUnknownRequest, errConv.Error())
return f, ErrUnknownRequest(errConv.Error())
}
if neg {

View File

@ -9,7 +9,7 @@ import (
type Result struct {
// Code is the response code, is stored back on the chain.
Code CodeType
Code ABCICodeType
// Data is any data returned from the app.
Data []byte
@ -20,7 +20,7 @@ type Result struct {
// GasWanted is the maximum units of work we allow this tx to perform.
GasWanted int64
// GasUsed is the amount of gas actually consumed. NOTE: not used.
// GasUsed is the amount of gas actually consumed. NOTE: unimplemented
GasUsed int64
// Tx fee amount and denom.

View File

@ -25,15 +25,13 @@ func getVersion() string {
}
// CMD
func printVersion(cmd *cobra.Command, args []string) {
v := getVersion()
fmt.Println(v)
}
// REST
func VersionRequestHandler(w http.ResponseWriter, r *http.Request) {
// version REST handler endpoint
func RequestHandler(w http.ResponseWriter, r *http.Request) {
v := getVersion()
w.Write([]byte(v))
}

View File

@ -8,6 +8,7 @@ import (
"github.com/tendermint/go-crypto"
)
// amino codec to marshal/unmarshal
type Codec = amino.Codec
func NewCodec() *Codec {
@ -15,10 +16,12 @@ func NewCodec() *Codec {
return cdc
}
// Register the go-crypto to the codec
func RegisterCrypto(cdc *Codec) {
crypto.RegisterAmino(cdc)
}
// attempt to make some pretty json
func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) {
bz, err := cdc.MarshalJSON(obj)
if err != nil {

View File

@ -40,7 +40,7 @@ func privAndAddr() (crypto.PrivKey, sdk.Address) {
func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx) {
_, result, abort := anteHandler(ctx, tx)
assert.False(t, abort)
assert.Equal(t, sdk.CodeOK, result.Code)
assert.Equal(t, sdk.ABCICodeOK, result.Code)
assert.True(t, result.IsOK())
}
@ -48,7 +48,7 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx
func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, code sdk.CodeType) {
_, result, abort := anteHandler(ctx, tx)
assert.True(t, abort)
assert.Equal(t, code, result.Code)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code)
}
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee) sdk.Tx {

View File

@ -17,6 +17,7 @@ func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command {
return GetAccountCmd(storeName, cdc, GetAccountDecoder(cdc))
}
// Get account decoder for auth.DefaultAccount
func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder {
return func(accBytes []byte) (acct sdk.Account, err error) {
// acct := new(auth.BaseAccount)

View File

@ -33,10 +33,12 @@ const (
contextKeySigners contextKey = iota
)
// add the signers to the context
func WithSigners(ctx types.Context, accounts []types.Account) types.Context {
return ctx.WithValue(contextKeySigners, accounts)
}
// get the signers from the context
func GetSigners(ctx types.Context) []types.Account {
v := ctx.Value(contextKeySigners)
if v == nil {

View File

@ -9,7 +9,6 @@ import (
)
var _ sdk.AccountMapper = (*accountMapper)(nil)
var _ sdk.AccountMapper = (*sealedAccountMapper)(nil)
// Implements sdk.AccountMapper.
// This AccountMapper encodes/decodes accounts using the
@ -28,6 +27,7 @@ type accountMapper struct {
// NewAccountMapper returns a new sdk.AccountMapper that
// uses go-amino to (binary) encode and decode concrete sdk.Accounts.
// nolint
func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) accountMapper {
return accountMapper{
key: key,
@ -36,21 +36,6 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) acco
}
}
// Returns the go-amino codec. You may need to register interfaces
// and concrete types here, if your app's sdk.Account
// implementation includes interface fields.
// NOTE: It is not secure to expose the codec, so check out
// .Seal().
func (am accountMapper) WireCodec() *wire.Codec {
return am.cdc
}
// Returns a "sealed" accountMapper.
// The codec is not accessible from a sealedAccountMapper.
func (am accountMapper) Seal() sealedAccountMapper {
return sealedAccountMapper{am}
}
// Implements sdk.AccountMapper.
func (am accountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account {
acc := am.clonePrototype()
@ -77,19 +62,6 @@ func (am accountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) {
store.Set(addr, bz)
}
//----------------------------------------
// sealedAccountMapper
type sealedAccountMapper struct {
accountMapper
}
// There's no way for external modules to mutate the
// sam.accountMapper.cdc from here, even with reflection.
func (sam sealedAccountMapper) WireCodec() *wire.Codec {
panic("accountMapper is sealed")
}
//----------------------------------------
// misc.
@ -107,7 +79,8 @@ func (am accountMapper) clonePrototype() sdk.Account {
panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt))
}
return clone
} else {
}
protoRv := reflect.New(protoRt).Elem()
clone, ok := protoRv.Interface().(sdk.Account)
if !ok {
@ -115,7 +88,6 @@ func (am accountMapper) clonePrototype() sdk.Account {
}
return clone
}
}
func (am accountMapper) encodeAccount(acc sdk.Account) []byte {
bz, err := am.cdc.MarshalBinaryBare(acc)

View File

@ -57,17 +57,3 @@ func TestAccountMapperGetSet(t *testing.T) {
assert.NotNil(t, acc)
assert.Equal(t, newSequence, acc.GetSequence())
}
func TestAccountMapperSealed(t *testing.T) {
_, capKey := setupMultiStore()
cdc := wire.NewCodec()
RegisterBaseAccount(cdc)
// normal mapper exposes the wire codec
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
assert.NotNil(t, mapper.WireCodec())
// seal mapper, should panic when we try to get the codec
mapperSealed := mapper.Seal()
assert.Panics(t, func() { mapperSealed.WireCodec() })
}

View File

@ -10,16 +10,19 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
auth "github.com/cosmos/cosmos-sdk/x/auth/commands"
)
type commander struct {
storeName string
cdc *wire.Codec
decoder sdk.AccountDecoder
// register REST routes
func RegisterRoutes(r *mux.Router, cdc *wire.Codec, storeName string) {
r.HandleFunc(
"/accounts/{address}",
QueryAccountRequestHandler(storeName, cdc, auth.GetAccountDecoder(cdc)),
).Methods("GET")
}
// query accountREST Handler
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)
@ -33,7 +36,7 @@ func QueryAccountRequestHandler(storeName string, cdc *wire.Codec, decoder sdk.A
}
key := sdk.Address(bz)
res, err := ctx.Query(key, c.storeName)
res, err := ctx.Query(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
@ -47,7 +50,7 @@ func QueryAccountRequestHandler(storeName string, cdc *wire.Codec, decoder sdk.A
}
// decode the value
account, err := c.decoder(res)
account, err := decoder(res)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't parse query result. Result: %s. Error: %s", res, err.Error())))

Some files were not shown because too many files have changed in this diff Show More