Merge pull request #748 from cosmos/cwgoes/clean-up-basecoin
Move 'cool' and 'sketchy' modules from basecoin to democoin
This commit is contained in:
commit
15e3d47148
7
Makefile
7
Makefile
|
@ -19,12 +19,17 @@ gaia:
|
|||
|
||||
build:
|
||||
@rm -rf $(shell pwd)/examples/basecoin/vendor/
|
||||
@rm -rf $(shell pwd)/examples/democoin/vendor/
|
||||
ifeq ($(OS),Windows_NT)
|
||||
go build $(BUILD_FLAGS) -o build/basecoind.exe ./examples/basecoin/cmd/basecoind
|
||||
go build $(BUILD_FLAGS) -o build/basecli.exe ./examples/basecoin/cmd/basecli
|
||||
go build $(BUILD_FLAGS) -o build/democoind.exe ./examples/democoin/cmd/democoind
|
||||
go build $(BUILD_FLAGS) -o build/democli.exe ./examples/democoin/cmd/democli
|
||||
else
|
||||
go build $(BUILD_FLAGS) -o build/basecoind ./examples/basecoin/cmd/basecoind
|
||||
go build $(BUILD_FLAGS) -o build/basecli ./examples/basecoin/cmd/basecli
|
||||
go build $(BUILD_FLAGS) -o build/democoind ./examples/democoin/cmd/democoind
|
||||
go build $(BUILD_FLAGS) -o build/democli ./examples/democoin/cmd/democli
|
||||
endif
|
||||
|
||||
dist:
|
||||
|
@ -74,10 +79,12 @@ test: test_unit # test_cli
|
|||
|
||||
test_unit:
|
||||
@rm -rf examples/basecoin/vendor/
|
||||
@rm -rf examples/democoin/vendor/
|
||||
@go test $(PACKAGES)
|
||||
|
||||
test_cover:
|
||||
@rm -rf examples/basecoin/vendor/
|
||||
@rm -rf examples/democoin/vendor/
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
@bash tests/test_cover.sh
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
|
|
|
@ -364,9 +364,6 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
Coins: coins,
|
||||
},
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.Marshal(appState)
|
||||
if err != nil {
|
||||
|
|
|
@ -18,8 +18,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/simplestake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/sketchy"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -60,13 +58,10 @@ func NewBasecoinApp(logger log.Logger, dbs map[string]dbm.DB) *BasecoinApp {
|
|||
|
||||
// add handlers
|
||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper)
|
||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper), nil).
|
||||
AddRoute("cool", cool.NewHandler(coolKeeper), coolKeeper.InitGenesis).
|
||||
AddRoute("sketchy", sketchy.NewHandler(), nil).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper), nil).
|
||||
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper), nil)
|
||||
|
||||
|
@ -103,8 +98,6 @@ func MakeCodec() *wire.Codec {
|
|||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
oldwire.ConcreteType{simplestake.BondMsg{}, msgTypeBondMsg},
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
@ -39,31 +38,6 @@ var (
|
|||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
||||
}
|
||||
|
||||
quizMsg1 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "icecold",
|
||||
}
|
||||
|
||||
quizMsg2 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg1 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "icecold",
|
||||
}
|
||||
|
||||
setTrendMsg2 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg3 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "warmandkind",
|
||||
}
|
||||
)
|
||||
|
||||
func loggerAndDBs() (log.Logger, map[string]dbm.DB) {
|
||||
|
@ -91,8 +65,6 @@ func TestMsgs(t *testing.T) {
|
|||
msg sdk.Msg
|
||||
}{
|
||||
{sendMsg},
|
||||
{quizMsg1},
|
||||
{setTrendMsg1},
|
||||
}
|
||||
|
||||
sequences := []int64{0}
|
||||
|
@ -140,9 +112,6 @@ func TestGenesis(t *testing.T) {
|
|||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
|
||||
|
@ -180,9 +149,6 @@ func TestSendMsgWithAccounts(t *testing.T) {
|
|||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
@ -255,9 +221,6 @@ func TestQuizMsg(t *testing.T) {
|
|||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
@ -272,21 +235,6 @@ func TestQuizMsg(t *testing.T) {
|
|||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Set the trend, submit a really cool quiz and check for reward
|
||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
|
||||
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
|
@ -305,9 +253,6 @@ func TestHandler(t *testing.T) {
|
|||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
coolcmd "github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool/commands"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
|
@ -63,14 +62,6 @@ func main() {
|
|||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
coolcmd.QuizTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
coolcmd.SetTrendTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
Cosmos-SDK Democoin (template)
|
||||
License: Apache2.0
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 All in Bits, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,22 @@
|
|||
PACKAGES=$(shell go list ./... | grep -v '/vendor/')
|
||||
BUILD_FLAGS = -ldflags "-X github.com/cosmos/cosmos-sdk/examples/democoin/version.GitCommit=`git rev-parse --short HEAD`"
|
||||
|
||||
all: get_tools get_vendor_deps build test
|
||||
|
||||
get_tools:
|
||||
go get github.com/golang/dep/cmd/dep
|
||||
|
||||
build:
|
||||
go build $(BUILD_FLAGS) -o build/democoin ./cmd/...
|
||||
|
||||
get_vendor_deps:
|
||||
@rm -rf vendor/
|
||||
@dep ensure
|
||||
|
||||
test:
|
||||
@go test $(PACKAGES)
|
||||
|
||||
benchmark:
|
||||
@go test -bench=. $(PACKAGES)
|
||||
|
||||
.PHONY: all build test benchmark
|
|
@ -0,0 +1,70 @@
|
|||
# Democoin
|
||||
|
||||
This is the "Democoin" example application built on the Cosmos-Sdk. This
|
||||
"Democoin" is not affiliated with [Coinbase](http://www.getdemocoin.com/), nor
|
||||
the [stable coin](http://www.getdemocoin.com/).
|
||||
|
||||
Assuming you've run `make get_tools && make get_vendor_deps` from the root of
|
||||
this repository, run `make build` here to build the `democoind` and `basecli`
|
||||
binaries.
|
||||
|
||||
If you want to create a new application, start by copying the Democoin app.
|
||||
|
||||
|
||||
# Building your own Blockchain
|
||||
|
||||
Democoin is the equivalent of an ERC20 token contract for blockchains. In order
|
||||
to deploy your own application all you need to do is clone `examples/democoin`
|
||||
and run it. Now you are already running your own blockchain. In the following
|
||||
I will explain how to add functionality to your blockchain. This is akin to
|
||||
defining your own vesting schedule within a contract or setting a specific
|
||||
multisig. You are just extending the base layer with extra functionality here
|
||||
and there.
|
||||
|
||||
## Structure of Democoin
|
||||
|
||||
Democoin is build with the cosmos-sdk. It is a sample application that works
|
||||
with any engine that implements the ABCI protocol. Democoin defines multiple
|
||||
unique modules as well as uses modules directly from the sdk. If you want
|
||||
to modify Democoin, you either remove or add modules according to your wishes.
|
||||
|
||||
|
||||
## Modules
|
||||
|
||||
A module is a fundamental unit in the cosmos-sdk. A module defines its own
|
||||
transaction, handles its own state as well as its own state transition logic.
|
||||
Globally, in the `app/app.go` file you just have to define a key for that
|
||||
module to access some parts of the state, as well as initialise the module
|
||||
object and finally add it to the transaction router. The router ensures that
|
||||
every module only gets its own messages.
|
||||
|
||||
|
||||
## Transactions
|
||||
|
||||
A user can send a transaction to the running blockchain application. This
|
||||
transaction can be of any of the ones that are supported by any of the
|
||||
registered modules.
|
||||
|
||||
### CheckTx
|
||||
|
||||
Once a user has submitted their transaction to the engine,
|
||||
the engine will first run `checkTx` to confirm that it is a valid transaction.
|
||||
The module has to define a handler that knows how to handle every transaction
|
||||
type. The corresponding handler gets invoked with the checkTx flag set to true.
|
||||
This means that the handler shouldn't do any expensive operations, but it can
|
||||
and should write to the checkTx state.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
The engine calls `deliverTx` when a new block has been agreed upon in
|
||||
consensus. Again, the corresponding module will have its handler invoked
|
||||
and the state and context is passed in. During deliverTx execution the
|
||||
transaction needs to be processed fully and the results are written to the
|
||||
application state.
|
||||
|
||||
|
||||
## CLI
|
||||
|
||||
The cosmos-sdk contains a number of helper libraries in `clients/` to build cli
|
||||
and RPC interfaces for your specific application.
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
oldwire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/simplestake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/sketchy"
|
||||
)
|
||||
|
||||
const (
|
||||
appName = "DemocoinApp"
|
||||
)
|
||||
|
||||
// Extended ABCI application
|
||||
type DemocoinApp struct {
|
||||
*bam.BaseApp
|
||||
cdc *wire.Codec
|
||||
|
||||
// keys to access the substores
|
||||
capKeyMainStore *sdk.KVStoreKey
|
||||
capKeyAccountStore *sdk.KVStoreKey
|
||||
capKeyIBCStore *sdk.KVStoreKey
|
||||
capKeyStakingStore *sdk.KVStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper sdk.AccountMapper
|
||||
}
|
||||
|
||||
func NewDemocoinApp(logger log.Logger, dbs map[string]dbm.DB) *DemocoinApp {
|
||||
// create your application object
|
||||
var app = &DemocoinApp{
|
||||
BaseApp: bam.NewBaseApp(appName, logger, dbs["main"]),
|
||||
cdc: MakeCodec(),
|
||||
capKeyMainStore: sdk.NewKVStoreKey("main"),
|
||||
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
|
||||
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
|
||||
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
app.accountMapper = auth.NewAccountMapperSealed(
|
||||
app.capKeyMainStore, // target store
|
||||
&types.AppAccount{}, // prototype
|
||||
)
|
||||
|
||||
// add handlers
|
||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper)
|
||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper), nil).
|
||||
AddRoute("cool", cool.NewHandler(coolKeeper), coolKeeper.InitGenesis).
|
||||
AddRoute("sketchy", sketchy.NewHandler(), nil).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper), nil).
|
||||
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper), nil)
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetTxDecoder(app.txDecoder)
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.MountStoreWithDB(app.capKeyMainStore, sdk.StoreTypeIAVL, dbs["main"])
|
||||
app.MountStoreWithDB(app.capKeyAccountStore, sdk.StoreTypeIAVL, dbs["acc"])
|
||||
app.MountStoreWithDB(app.capKeyIBCStore, sdk.StoreTypeIAVL, dbs["ibc"])
|
||||
app.MountStoreWithDB(app.capKeyStakingStore, sdk.StoreTypeIAVL, dbs["staking"])
|
||||
// NOTE: Broken until #532 lands
|
||||
//app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
err := app.LoadLatestVersion(app.capKeyMainStore)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// custom tx codec
|
||||
// TODO: use new go-wire
|
||||
func MakeCodec() *wire.Codec {
|
||||
const msgTypeSend = 0x1
|
||||
const msgTypeIssue = 0x2
|
||||
const msgTypeQuiz = 0x3
|
||||
const msgTypeSetTrend = 0x4
|
||||
const msgTypeIBCTransferMsg = 0x5
|
||||
const msgTypeIBCReceiveMsg = 0x6
|
||||
const msgTypeBondMsg = 0x7
|
||||
const msgTypeUnbondMsg = 0x8
|
||||
var _ = oldwire.RegisterInterface(
|
||||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
oldwire.ConcreteType{simplestake.BondMsg{}, msgTypeBondMsg},
|
||||
oldwire.ConcreteType{simplestake.UnbondMsg{}, msgTypeUnbondMsg},
|
||||
)
|
||||
|
||||
const accTypeApp = 0x1
|
||||
var _ = oldwire.RegisterInterface(
|
||||
struct{ sdk.Account }{},
|
||||
oldwire.ConcreteType{&types.AppAccount{}, accTypeApp},
|
||||
)
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
// cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
||||
// bank.RegisterWire(cdc) // Register bank.[SendMsg,IssueMsg] types.
|
||||
// crypto.RegisterWire(cdc) // Register crypto.[PubKey,PrivKey,Signature] types.
|
||||
// ibc.RegisterWire(cdc) // Register ibc.[IBCTransferMsg, IBCReceiveMsg] types.
|
||||
return cdc
|
||||
}
|
||||
|
||||
// custom logic for transaction decoding
|
||||
func (app *DemocoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx = sdk.StdTx{}
|
||||
|
||||
if len(txBytes) == 0 {
|
||||
return nil, sdk.ErrTxDecode("txBytes are empty")
|
||||
}
|
||||
|
||||
// StdTx.Msg is an interface. The concrete types
|
||||
// are registered by MakeTxCodec in bank.RegisterWire.
|
||||
err := app.cdc.UnmarshalBinary(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode("").TraceCause(err, "")
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// custom logic for democoin initialization
|
||||
func (app *DemocoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(types.GenesisState)
|
||||
err := json.Unmarshal(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc, err := gacc.ToAppAccount()
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
app.accountMapper.SetAccount(ctx, acc)
|
||||
}
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
|
@ -0,0 +1,382 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// Construct some global addrs and txs for tests.
|
||||
var (
|
||||
chainID = "" // TODO
|
||||
|
||||
priv1 = crypto.GenPrivKeyEd25519()
|
||||
addr1 = priv1.PubKey().Address()
|
||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
coins = sdk.Coins{{"foocoin", 10}}
|
||||
fee = sdk.StdFee{
|
||||
sdk.Coins{{"foocoin", 0}},
|
||||
0,
|
||||
}
|
||||
|
||||
sendMsg = bank.SendMsg{
|
||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
||||
}
|
||||
|
||||
quizMsg1 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "icecold",
|
||||
}
|
||||
|
||||
quizMsg2 = cool.QuizMsg{
|
||||
Sender: addr1,
|
||||
CoolAnswer: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg1 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "icecold",
|
||||
}
|
||||
|
||||
setTrendMsg2 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "badvibesonly",
|
||||
}
|
||||
|
||||
setTrendMsg3 = cool.SetTrendMsg{
|
||||
Sender: addr1,
|
||||
Cool: "warmandkind",
|
||||
}
|
||||
)
|
||||
|
||||
func loggerAndDBs() (log.Logger, map[string]dbm.DB) {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbm.NewMemDB(),
|
||||
"acc": dbm.NewMemDB(),
|
||||
"ibc": dbm.NewMemDB(),
|
||||
"staking": dbm.NewMemDB(),
|
||||
}
|
||||
return logger, dbs
|
||||
}
|
||||
|
||||
func newDemocoinApp() *DemocoinApp {
|
||||
logger, dbs := loggerAndDBs()
|
||||
return NewDemocoinApp(logger, dbs)
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
||||
func TestMsgs(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
msgs := []struct {
|
||||
msg sdk.Msg
|
||||
}{
|
||||
{sendMsg},
|
||||
{quizMsg1},
|
||||
{setTrendMsg1},
|
||||
}
|
||||
|
||||
sequences := []int64{0}
|
||||
for i, m := range msgs {
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, m.msg))
|
||||
tx := sdk.NewStdTx(m.msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// just marshal/unmarshal!
|
||||
cdc := MakeCodec()
|
||||
txBytes, err := cdc.MarshalBinary(tx)
|
||||
require.NoError(t, err, "i: %v", i)
|
||||
|
||||
// Run a Check
|
||||
cres := bapp.CheckTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(cres.Code), "i: %v, log: %v", i, cres.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
dres := bapp.DeliverTx(txBytes)
|
||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
||||
sdk.CodeType(dres.Code), "i: %v, log: %v", i, dres.Log)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesis(t *testing.T) {
|
||||
logger, dbs := loggerAndDBs()
|
||||
bapp := NewDemocoinApp(logger, dbs)
|
||||
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
pk := crypto.GenPrivKeyEd25519().PubKey()
|
||||
addr := pk.Address()
|
||||
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
|
||||
require.Nil(t, err)
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr,
|
||||
Coins: coins,
|
||||
}
|
||||
acc := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context
|
||||
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
|
||||
// reload app and ensure the account is still there
|
||||
bapp = NewDemocoinApp(logger, dbs)
|
||||
ctx = bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||
assert.Equal(t, acc, res1)
|
||||
}
|
||||
|
||||
func TestSendMsgWithAccounts(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
// Give 77 foocoin to the first key
|
||||
coins, err := sdk.ParseCoins("77foocoin")
|
||||
require.Nil(t, err)
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Sign the tx
|
||||
sequences := []int64{0}
|
||||
sig := priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, sendMsg))
|
||||
tx := sdk.NewStdTx(sendMsg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: sig,
|
||||
}})
|
||||
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
|
||||
// Check balances
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
||||
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
||||
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
||||
|
||||
// Delivering again should cause replay error
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log)
|
||||
|
||||
// bumping the txnonce number without resigning should be an auth error
|
||||
tx.Signatures[0].Sequence = 1
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log)
|
||||
|
||||
// resigning the tx with the bumped sequence should work
|
||||
sequences = []int64{1}
|
||||
sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg))
|
||||
tx.Signatures[0].Signature = sig
|
||||
res = bapp.Deliver(tx)
|
||||
assert.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
|
||||
func TestQuizMsg(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
// Construct genesis state
|
||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||
coins := sdk.Coins{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
// Construct genesis state
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
// Set the trend, submit a really cool quiz and check for reward
|
||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
||||
CheckBalance(t, bapp, "69icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
||||
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
||||
CheckBalance(t, bapp, "138icecold")
|
||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
||||
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
|
||||
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
bapp := newDemocoinApp()
|
||||
|
||||
sourceChain := "source-chain"
|
||||
destChain := "dest-chain"
|
||||
|
||||
vals := []abci.Validator{}
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: coins,
|
||||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
genesisState := map[string]interface{}{
|
||||
"accounts": []*types.GenesisAccount{
|
||||
types.NewGenesisAccount(acc1),
|
||||
},
|
||||
"cool": map[string]string{
|
||||
"trend": "ice-cold",
|
||||
},
|
||||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
assert.Equal(t, acc1, res1)
|
||||
|
||||
packet := ibc.IBCPacket{
|
||||
SrcAddr: addr1,
|
||||
DestAddr: addr1,
|
||||
Coins: coins,
|
||||
SrcChain: sourceChain,
|
||||
DestChain: destChain,
|
||||
}
|
||||
|
||||
transferMsg := ibc.IBCTransferMsg{
|
||||
IBCPacket: packet,
|
||||
}
|
||||
|
||||
receiveMsg := ibc.IBCReceiveMsg{
|
||||
IBCPacket: packet,
|
||||
Relayer: addr1,
|
||||
Sequence: 0,
|
||||
}
|
||||
|
||||
SignCheckDeliver(t, bapp, transferMsg, 0, true)
|
||||
CheckBalance(t, bapp, "")
|
||||
SignCheckDeliver(t, bapp, transferMsg, 1, false)
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 2, true)
|
||||
CheckBalance(t, bapp, "10foocoin")
|
||||
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
||||
}
|
||||
|
||||
// TODO describe the use of this function
|
||||
func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
||||
|
||||
// Sign the tx
|
||||
tx := sdk.NewStdTx(msg, fee, []sdk.StdSignature{{
|
||||
PubKey: priv1.PubKey(),
|
||||
Signature: priv1.Sign(sdk.StdSignBytes(chainID, []int64{seq}, fee, msg)),
|
||||
Sequence: seq,
|
||||
}})
|
||||
|
||||
// Run a Check
|
||||
res := bapp.Check(tx)
|
||||
if expPass {
|
||||
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
|
||||
// Simulate a Block
|
||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
res = bapp.Deliver(tx)
|
||||
if expPass {
|
||||
require.Equal(t, sdk.CodeOK, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
||||
}
|
||||
bapp.EndBlock(abci.RequestEndBlock{})
|
||||
//bapp.Commit()
|
||||
}
|
||||
|
||||
func CheckBalance(t *testing.T, bapp *DemocoinApp, balExpected string) {
|
||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/commands"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/commands"
|
||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/x/simplestake/commands"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
)
|
||||
|
||||
// gaiacliCmd is the entry point for this binary
|
||||
var (
|
||||
democliCmd = &cobra.Command{
|
||||
Use: "democli",
|
||||
Short: "Democoin light-client",
|
||||
}
|
||||
)
|
||||
|
||||
func todoNotImplemented(_ *cobra.Command, _ []string) error {
|
||||
return errors.New("TODO: Command not yet implemented")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// disable sorting
|
||||
cobra.EnableCommandSorting = false
|
||||
|
||||
// get the codec
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
// TODO: setup keybase, viper object, etc. to be passed into
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
||||
// add standard rpc, and tx commands
|
||||
rpc.AddCommands(democliCmd)
|
||||
democliCmd.AddCommand(client.LineBreak)
|
||||
tx.AddCommands(democliCmd, cdc)
|
||||
democliCmd.AddCommand(client.LineBreak)
|
||||
|
||||
// add query/post commands (custom to binary)
|
||||
democliCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
democliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
)...)
|
||||
democliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
)...)
|
||||
democliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
simplestakingcmd.BondTxCmd(cdc),
|
||||
)...)
|
||||
democliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
simplestakingcmd.UnbondTxCmd(cdc),
|
||||
)...)
|
||||
|
||||
// add proxy, version and key info
|
||||
democliCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(democliCmd, "BC", os.ExpandEnv("$HOME/.democli"))
|
||||
executor.Execute()
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
// democoindCmd is the entry point for this binary
|
||||
var (
|
||||
democoindCmd = &cobra.Command{
|
||||
Use: "democoind",
|
||||
Short: "Gaia Daemon (server)",
|
||||
}
|
||||
)
|
||||
|
||||
// defaultOptions sets up the app_options for the
|
||||
// default genesis file
|
||||
func defaultOptions(args []string) (json.RawMessage, error) {
|
||||
addr, secret, err := server.GenerateCoinKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("Secret phrase to access coins:")
|
||||
fmt.Println(secret)
|
||||
|
||||
opts := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr)
|
||||
return json.RawMessage(opts), nil
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
dbMain, err := dbm.NewGoLevelDB("democoin", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbAcc, err := dbm.NewGoLevelDB("democoin-acc", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbIBC, err := dbm.NewGoLevelDB("democoin-ibc", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbStaking, err := dbm.NewGoLevelDB("democoin-staking", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbs := map[string]dbm.DB{
|
||||
"main": dbMain,
|
||||
"acc": dbAcc,
|
||||
"ibc": dbIBC,
|
||||
"staking": dbStaking,
|
||||
}
|
||||
bapp := app.NewDemocoinApp(logger, dbs)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// TODO: set logger through CLI
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
||||
With("module", "main")
|
||||
|
||||
democoindCmd.AddCommand(
|
||||
server.InitCmd(defaultOptions, logger),
|
||||
server.StartCmd(generateApp, logger),
|
||||
server.UnsafeResetAllCmd(logger),
|
||||
server.ShowNodeIdCmd(logger),
|
||||
server.ShowValidatorCmd(logger),
|
||||
version.VersionCmd,
|
||||
)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||
executor := cli.PrepareBaseCmd(democoindCmd, "BC", rootDir)
|
||||
executor.Execute()
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
)
|
||||
|
||||
var _ sdk.Account = (*AppAccount)(nil)
|
||||
|
||||
// Custom extensions for this application. This is just an example of
|
||||
// extending auth.BaseAccount with custom fields.
|
||||
//
|
||||
// This is compatible with the stock auth.AccountStore, since
|
||||
// auth.AccountStore uses the flexible go-wire library.
|
||||
type AppAccount struct {
|
||||
auth.BaseAccount
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (acc AppAccount) GetName() string { return acc.Name }
|
||||
func (acc *AppAccount) SetName(name string) { acc.Name = name }
|
||||
|
||||
// Get the AccountDecoder function for the custom AppAccount
|
||||
func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder {
|
||||
return func(accBytes []byte) (res sdk.Account, err error) {
|
||||
if len(accBytes) == 0 {
|
||||
return nil, sdk.ErrTxDecode("accBytes are empty")
|
||||
}
|
||||
acct := new(AppAccount)
|
||||
err = cdc.UnmarshalBinary(accBytes, &acct)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return acct, err
|
||||
}
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []*GenesisAccount `json:"accounts"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
type GenesisAccount struct {
|
||||
Name string `json:"name"`
|
||||
Address sdk.Address `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
|
||||
return &GenesisAccount{
|
||||
Name: aa.Name,
|
||||
Address: aa.Address,
|
||||
Coins: aa.Coins,
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to AppAccount
|
||||
func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) {
|
||||
baseAcc := auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins,
|
||||
}
|
||||
return &AppAccount{
|
||||
BaseAccount: baseAcc,
|
||||
Name: ga.Name,
|
||||
}, nil
|
||||
}
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
)
|
||||
|
||||
// take the coolness quiz transaction
|
|
@ -15,8 +15,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
)
|
||||
|
||||
// AccountMapper(/CoinKeeper) and IBCMapper should use different StoreKey later
|
||||
|
@ -53,8 +51,6 @@ func makeCodec() *wire.Codec {
|
|||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue},
|
||||
oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz},
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue