Merge remote-tracking branch 'origin/develop' into rigel/fee-distribution

This commit is contained in:
rigelrozanski
2018-10-04 18:33:12 -04:00
149 changed files with 83721 additions and 3280 deletions
+21 -1
View File
@@ -15,7 +15,8 @@ module.exports = {
collapsable: false,
children: [
"/introduction/cosmos-hub",
"/introduction/tendermint",
"/introduction/tendermint-cosmos",
"/introduction/tendermint"
]
},
{
@@ -54,6 +55,18 @@ module.exports = {
// "/specs/icts",
// ]
// },
{
title: "SDK by Examples - Simple Governance",
collapsable: false,
children: [
["/sdk/sdk-by-examples/simple-governance/intro", "Intro"],
"/sdk/sdk-by-examples/simple-governance/setup-and-design",
"/sdk/sdk-by-examples/simple-governance/app-init",
"/sdk/sdk-by-examples/simple-governance/simple-gov-module",
"/sdk/sdk-by-examples/simple-governance/bridging-it-all",
"/sdk/sdk-by-examples/simple-governance/running-the-application"
]
},
{
title: "Lotion JS",
collapsable: false,
@@ -71,6 +84,13 @@ module.exports = {
"/validators/validator-faq"
]
},
{
title: "Clients",
collapsable: false,
children: [
["/clients/service-providers", "Service Providers"]
]
},
{
title: "Resources",
collapsable: false,
+20
View File
@@ -10,6 +10,11 @@ built from the files in this (`/docs`) directory for
and [develop](https://github.com/cosmos/cosmos-sdk/tree/develop/docs),
respectively.
Besides, gaia-lite API docs are also provided by gaia-lite. The default API docs page is:
```
https://localhost:1317/swagger-ui/
```
## How It Works
There is a Jenkins job listening for changes in the `/docs` directory, on both
@@ -93,3 +98,18 @@ then navigate to localhost:8080 in your browser.
Because the build processes are identical (as is the information contained herein), this file should be kept in sync as
much as possible with its [counterpart in the Tendermint Core repo](https://github.com/tendermint/tendermint/blob/develop/docs/DOCS_README.md).
## Update and Build the RPC docs
1. Execute the following command at the root directory to install the swagger-ui generate tool.
```
make get_tools
```
2. Edit API docs
1. Directly Edit API docs manually: `client/lcd/swagger-ui/swagger.yaml`.
2. Edit API docs within [SwaggerHub](https://app.swaggerhub.com). Please refer to this [document](https://app.swaggerhub.com/help/index) for how to use the about website to edit API docs.
3. Download `swagger.yaml` and replace the old `swagger.yaml` under fold `client/lcd/swagger-ui`.
4. Compile gaiacli
```
make install
```
+15 -46
View File
@@ -1,75 +1,44 @@
# High priority
## Fees
- Collection
- Simple flat fee set in-config by validators & full nodes - ref [#1921](https://github.com/cosmos/cosmos-sdk/issues/1921)
- @sunnya97 working on implementation
- _*BLOCKER:*_ Blocked on [tendermint/tendermint#2275](https://github.com/tendermint/tendermint/issues/2275) @ValarDragon
- Distribution
- "Piggy bank" fee distribution - ref [#1944](https://github.com/cosmos/cosmos-sdk/pull/1944) (spec)
- @rigelrozanski working on implementation
- EST TIMELINE:
- Work on fees should be completed in the `v0.25.0` release
# Post-0.25/GoS Pre-Release
## Staking/Slashing/Stability
- Unbonding state for validators (WIP) [#2163](https://github.com/cosmos/cosmos-sdk/pull/2163) @rigelrozanski
- Needs :eyes: from @chris
- Should be in `v0.25.0` release
- Slashing period PR - ref [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122)
- Needs :eyes: from @cwgoes and @jaekwon
- Should be in `v0.25.0` release
- Other slashing issues blocking for launch - [#1256](https://github.com/cosmos/cosmos-sdk/issues/1256)
- Update staking/slashing for NextValSet change
- @cwgoes to start next
- Miscellaneous minor staking issues
- [List here](https://github.com/cosmos/cosmos-sdk/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Astaking+label%3Aprelaunch)
- Need to figure out scope of work here to estimate time
- @rigelrozanski to start next
## Vesting
- Single `VestingAccount` allowing delegation/voting but no withdrawals
- Ref [#1875](https://github.com/cosmos/cosmos-sdk/pull/1875) (spec)
- @AdityaSripal working on this.
- Should be in `v0.25.0` release
- Consider "tombstone" / "prison" - double-sign and you can never validate again - https://github.com/cosmos/cosmos-sdk/issues/2363
## Multisig
- Already implemented on TM side, need simple CLI interface
- @alessio working on the SDK side of things here
- Need to schedule some time with @alessio, @ebuchman and @ValarDragon this week to finalize feature set/implementation plan
- Need to test changes in https://github.com/cosmos/cosmos-sdk/pull/2165
- Spam prevention - https://github.com/cosmos/cosmos-sdk/issues/2019
## ABCI Changes
- Need to update for new ABCI changes - error string, tags are list of lists, proposer in header (Tendermint 0.24?)
- @cwgoes has done some work here. Should be on `develop` in tendermint w/in next week.
- Include in tendermint `v0.24.0` release?
- Need to update for new ABCI changes when/if they land - error string, tags are list of lists
- Need to verify correct proposer reward semantics
- CheckEvidence/DeliverEvidence, CheckTx/DeliverTx ordering semantics
## Gas
- Simple transaction benchmarking work by @jlandrews to inform additional work here
- Integrate @alessio's simulation work into CLI and LCD
- Sanity Checks
- Charge for transaction size
- Decide what "one gas" corresponds to (standard hardware benchmarks?)
- More benchmarking
- Consider charging based on maximum depth of IAVL tree iteration
- Test out gas estimation in CLI and LCD and ensure the UX works
## LCD
- Bianje working on implementation ([#2147](https://github.com/cosmos/cosmos-sdk/pull/2147))
- ICS 0,ICS 1, ICS 20 and ICS 21 implemented in this PR :point_up:
- @fedekunze, @jackzampolin and @alexanderbez to review
- Bianje working on implementation of ICS standards
- Additional PR incoming for ICS 22 and ICS 23
- Include [#382](https://github.com/cosmos/cosmos-sdk/issues/382)
- Decide what ought to be ICS-standardized and what ought not to
# Lower priority
## Governance v2
- Simple software upgrade proposals
- Implementation described in [#1079](https://github.com/cosmos/cosmos-sdk/issues/1079)
- Agree upon a block height to switch to new version
- Another Governance proposal from @jaekwon [#2116](https://github.com/cosmos/cosmos-sdk/pull/2116)
- Circuit breaker
- Circuit breaker - https://github.com/cosmos/cosmos-sdk/issues/926
- Parameter change proposals (roughly the same implementation as circuit breaker)
## Documentation
+6
View File
@@ -8,6 +8,12 @@ The first blockchain in the Cosmos Network is the Cosmos Hub, whose native token
Cosmos can interoperate with multiple other applications and cryptocurrencies. By creating a new zone, you can plug any blockchain system into the Cosmos hub and pass tokens back and forth between those zones, without the need for an intermediary.
## Quick Start
- [Getting started with the SDK](./sdk/core/intro.md)
- [SDK Examples](../examples)
- [Join the testnet](./getting-started/join-testnet.md#run-a-full-node)
## Edit the Documentation
See [this file](./DOCS_README.md) for details of the build process and
-936
View File
@@ -1,936 +0,0 @@
swagger: '2.0'
info:
version: '1.1.0'
title: Gaia-Lite (former LCD) to interface with Cosmos BaseServer via REST
description: Specification for Gaia-lite provided by `gaiacli rest-server`
tags:
- name: keys
description: Key management to add or view local private keys
- name: send
description: Create and sign a send tx
- name: stake
description: Stake module API for staking and validation
- name: account
description: Query account balance
- name: query
description: Information about blocks and txs
- name: validator set
description: Check the state of the validator set
- name: node
description: Information of the connected node
- name: version
description: Information about the app version
securityDefinitions:
kms:
type: basic
paths:
/version:
get:
summary: Version of Gaia-lite
tags:
- version
description: Get the version of gaia-lite running locally to compare against expected
responses:
200:
description: Plaintext version i.e. "v0.5.0"
/node_version:
get:
summary: Version of the connected node
tags:
- node
description: Get the version of the SDK running on the connected node to compare against expected
responses:
200:
description: Plaintext version i.e. "v0.5.0"
/node_info:
get:
description: Information about the connected node
summary: The properties of the connected node
tags:
- node
produces:
- application/json
responses:
200:
description: Node status
schema:
type: object
properties:
pub_key:
$ref: '#/definitions/PubKey'
moniker:
type: string
example: 159.89.198.221
network:
type: string
example: gaia-2
remote_addr:
type: string
listen_addr:
type: string
example: 192.168.56.1:26656
version:
description: Tendermint version
type: string
example: 0.15.0
other:
description: more information on versions
type: array
items:
type: string
/syncing:
get:
summary: Syncing state of node
tags:
- node
description: Get if the node is currently syning with other nodes
responses:
200:
description: '"true" or "false"'
/keys:
get:
summary: List of accounts stored locally
tags:
- keys
produces:
- application/json
responses:
200:
description: Array of accounts
schema:
type: array
items:
$ref: '#/definitions/Account'
post:
summary: Create a new account locally
tags:
- keys
consumes:
- application/json
parameters:
- in: body
name: account
description: The account to create
schema:
type: object
required:
- name
- password
- seed
properties:
name:
type: string
password:
type: string
seed:
type: string
responses:
200:
description: Returns address of the account created
/keys/seed:
get:
summary: Create a new seed to create a new account with
tags:
- keys
produces:
- application/json
responses:
200:
description: 16 word Seed
schema:
type: string
/keys/{name}:
parameters:
- in: path
name: name
description: Account name
required: true
type: string
get:
summary: Get a certain locally stored account
tags:
- keys
produces:
- application/json
responses:
200:
description: Locally stored account
schema:
$ref: "#/definitions/Account"
404:
description: Account is not available
put:
summary: Update the password for this account in the KMS
tags:
- keys
consumes:
- application/json
parameters:
- in: body
name: account
description: The new and old password
schema:
type: object
required:
- new_password
- old_password
properties:
new_password:
type: string
old_password:
type: string
responses:
200:
description: Updated password
401:
description: Password is wrong
404:
description: Account is not available
delete:
summary: Remove an account
tags:
- keys
consumes:
- application/json
parameters:
- in: body
name: account
description: The password of the account to remove from the KMS
schema:
type: object
required:
- password
properties:
password:
type: string
responses:
200:
description: Removed account
401:
description: Password is wrong
404:
description: Account is not available
# /accounts/send:
# post:
# summary: Send coins (build -> sign -> send)
# security:
# - sign: []
# requestBody:
# content:
# application/json:
# schema:
# type: object
# properties:
# fees:
# $ref: "#/definitions/Coins"
# outputs:
# type: array
# items:
# type: object
# properties:
# pub_key:
# $ref: "#/definitions/PubKey"
# amount:
# type: array
# items:
# $ref: "#/definitions/Coins"
# responses:
# 202:
# description: Tx was send and will probably be added to the next block
# 400:
# description: The Tx was malformated
/accounts/{address}:
parameters:
- in: path
name: address
description: Account address in bech32 format
required: true
type: string
get:
summary: Get the account balances
tags:
- account
produces:
- application/json
responses:
200:
description: Account balances
schema:
$ref: "#/definitions/Balance"
204:
description: There is no data for the requested account. This is not a 404 as the account might exist, just does not hold data.
/accounts/{address}/send:
parameters:
- in: path
name: address
description: Account address in bech32 format
required: true
type: string
post:
summary: Send coins (build -> sign -> send)
tags:
- send
security:
- kms: []
consumes:
- application/json
parameters:
- in: body
name: account
description: The password of the account to remove from the KMS
schema:
type: object
properties:
name:
type: string
password:
type: string
amount:
type: array
items:
$ref: "#/definitions/Coins"
chain_id:
type: string
squence:
type: number
responses:
202:
description: Tx was send and will probably be added to the next block
400:
description: The Tx was malformated
/blocks/latest:
get:
summary: Get the latest block
tags:
- query
produces:
- application/json
responses:
200:
description: The latest block
schema:
$ref: "#/definitions/Block"
/blocks/{height}:
parameters:
- in: path
name: height
description: Block height
required: true
type: number
get:
summary: Get a block at a certain height
tags:
- query
produces:
- application/json
responses:
200:
description: The block at a specific height
schema:
$ref: "#/definitions/Block"
404:
description: Block at height is not available
/validatorsets/latest:
get:
summary: Get the latest validator set
tags:
- validator set
produces:
- application/json
responses:
200:
description: The validator set at the latest block height
schema:
type: object
properties:
block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
/validatorsets/{height}:
parameters:
- in: path
name: height
description: Block height
required: true
type: number
get:
summary: Get a validator set a certain height
tags:
- validator set
produces:
- application/json
responses:
200:
description: The validator set at a specific block height
schema:
type: object
properties:
block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
404:
description: Block at height not available
# /txs:
# parameters:
# - in: query
# name: tag
# schema:
# type: string
# example: "coin.sender=EE5F3404034C524501629B56E0DDC38FAD651F04"
# required: true
# - in: query
# name: page
# description: Pagination page
# schema:
# type: number
# default: 0
# - in: query
# name: size
# description: Pagination size
# schema:
# type: number
# default: 50
# get:
# summary: Query Tx
# responses:
# 200:
# description: All Tx matching the provided tags
# content:
# application/json:
# schema:
# type: array
# items:
# $ref: "#/definitions/Tx"
# 404:
# description: Pagination is out of bounds
# /txs/sign:
# post:
# summary: Sign a Tx
# description: Sign a Tx providing locally stored account and according password
# security:
# - sign: []
# requestBody:
# content:
# application/json:
# schema:
# $ref: "#/definitions/TxBuild"
# responses:
# 200:
# description: The signed Tx
# content:
# application/json:
# schema:
# $ref: "#/definitions/TxSigned"
# 401:
# description: Account name and/or password where wrong
# /txs/broadcast:
# post:
# summary: Send signed Tx
# requestBody:
# content:
# application/json:
# schema:
# $ref: "#/definitions/TxSigned"
# responses:
# 202:
# description: Tx was send and will probably be added to the next block
# 400:
# description: The Tx was malformated
/txs/{hash}:
parameters:
- in: path
name: hash
description: Tx hash
required: true
type: string
get:
summary: Get a Tx by hash
tags:
- query
produces:
- application/json
responses:
200:
description: Tx with the provided hash
schema:
$ref: "#/definitions/Tx"
404:
description: Tx not available for provided hash
# ================== Staking Module # ==================
# TODO create D
/stake/delegators/{delegatorAddr}:
parameters:
- in: path
name: delegatorAddr
description: AccAddress of Delegator
required: true
type: string
get:
summary: Get all delegations (delegation, undelegation) from a delegator
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/validators:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
get:
summary: Query all validators that a delegator is bonded to
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
/stake/delegators/{delegatorAddr}/validators/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
- in: path
name: validatorAddr
description: Bech32 ValAddress of Delegator
required: true
type: string
get:
summary: Query a validator that a delegator is bonded to
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
/stake/delegators/{delegatorAddr}/txs:
parameters:
- in: path
name: delegatorAddr
description: AccAddress of Delegator
required: true
type: string
get:
summary: Get all staking txs (i.e msgs) from a delegator
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
schema:
$ref: "#/definitions/Tx"
404:
description: Not Found
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/delegations:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
post:
summary: Submit delegation
parameters:
- in: body
name: delegation
description: The password of the account to remove from the KMS
schema:
type: object
properties:
name:
type: string
password:
type: string
account_number:
type: number
delegations:
type: array
items:
type: string
begin_unbondings:
type: array
items:
type: string
complete_unbondings:
type: array
items:
type: string
begin_redelegates:
type: array
items:
type: string
complete_redelegates:
type: array
items:
type: string
chain_id:
type: string
gas:
type: number
sequence:
type: number
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
schema:
$ref: "#/definitions/Tx"
404:
description: Not Found
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/delegations/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
- in: path
name: validatorAddr
description: Bech32 ValAddress of Delegator
required: true
type: string
get:
summary: Query the current delegation status between a delegator and a validator
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
/stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
- in: path
name: validatorAddr
description: Bech32 ValAddress of Delegator
required: true
type: string
get:
summary: Query all unbonding delegations between a delegator and a validator
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
500:
description: Internal Server Error
/stake/validators:
get:
summary: Get all validator candidates
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
500:
description: Internal Server Error
/stake/validators/{validatorAddr}:
parameters:
- in: path
name: validatorAddr
description: Bech32 ValAddress of Delegator
required: true
type: string
get:
summary: Query the information from a single validator
tags:
- stake
produces:
- application/json
responses:
200:
description: OK
404:
description: Not Found
500:
description: Internal Server Error
# TODO Add staking definitions
definitions:
Address:
type: string
description: bech32 encoded addres
example: cosmos:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorAddress:
type: string
description: bech32 encoded addres
example: cosmosvaloper:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
PubKey:
type: string
description: bech32 encoded public key
example: cosmospub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorPubKey:
type: string
description: bech32 encoded public key
example: cosmosvalconspub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
Coins:
type: object
properties:
denom:
type: string
example: steak
amount:
type: number
example: 50
Hash:
type: string
example: EE5F3404034C524501629B56E0DDC38FAD651F04
Tx:
type: object
properties:
type:
type: string
enum:
- stake/delegate
data:
type: object
TxChain:
type: object
properties:
type:
type: string
default: chain/tx
data:
type: object
properties:
chain_id:
type: string
example: gaia-2
expires_at:
type: number
example: 0
tx:
type: object
properties:
type:
type: string
default: nonce
data:
type: object
properties:
sequence:
type: number
example: 0
signers:
type: array
items:
type: object
properties:
chain:
type: string
example: ''
app:
type: string
default: sigs
addr:
$ref: "#/definitions/Address"
tx:
$ref: "#/definitions/Tx"
TxBuild:
type: object
properties:
type:
type: string
default: sigs/one
data:
type: object
properties:
tx:
$ref: "#/definitions/Tx"
signature:
type: object
properties:
Sig:
type: string
default: ''
Pubkey:
type: string
default: ''
TxSigned:
type: object
properties:
type:
type: string
default: sigs/one
data:
type: object
properties:
tx:
$ref: "#/definitions/Tx"
signature:
type: object
properties:
Sig:
type: string
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
Pubkey:
$ref: "#/definitions/PubKey"
Account:
type: object
properties:
name:
type: string
example: Main Account
address:
$ref: "#/definitions/Address"
pub_key:
$ref: "#/definitions/PubKey"
Balance:
type: object
properties:
height:
type: number
example: 123456
coins:
type: array
items:
$ref: "#/definitions/Coins"
credit:
type: array
items:
type: object
BlockID:
type: object
properties:
hash:
$ref: "#/definitions/Hash"
parts:
type: object
properties:
total:
type: number
example: 0
hash:
$ref: "#/definitions/Hash"
Block:
type: object
properties:
header:
type: object
properties:
chain_id:
type: string
example: gaia-2
height:
type: number
example: 1
time:
type: string
example: '2017-12-30T05:53:09.287+01:00'
num_txs:
type: number
example: 0
last_block_id:
$ref: "#/definitions/BlockID"
total_txs:
type: number
example: 35
last_commit_hash:
$ref: "#/definitions/Hash"
data_hash:
$ref: "#/definitions/Hash"
validators_hash:
$ref: "#/definitions/Hash"
consensus_hash:
$ref: "#/definitions/Hash"
app_hash:
$ref: "#/definitions/Hash"
last_results_hash:
$ref: "#/definitions/Hash"
evidence_hash:
$ref: "#/definitions/Hash"
txs:
type: array
items:
$ref: "#/definitions/Tx"
evidence:
type: array
items:
type: object
last_commit:
type: object
properties:
blockID:
$ref: "#/definitions/BlockID"
precommits:
type: array
items:
type: object
Validator:
type: object
properties:
address:
$ref: '#/definitions/ValidatorAddress'
pub_key:
$ref: "#/definitions/ValidatorPubKey"
power:
type: number
example: 1000
accum:
type: number
example: 1000
# Added by API Auto Mocking Plugin
host: virtserver.swaggerhub.com
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
schemes:
- https
+1 -1
View File
@@ -1,6 +1,6 @@
# Install the SDK
This guide will explain how to install the [Cosmos SDK](/sdk/overview.md) onto your system. With the SDK installed on a server, you can participate in the latest testnet as either a [Full Node](full-node.md) or a [Validator](/validators/validator-setup.md).
This guide will explain how to install the [Cosmos SDK](/sdk/overview.md) onto your system. With the SDK installed on a server, you can participate in the latest testnet as either a [Full Node](./join-testnet.md#run-a-full-node) or a [Validator](/validators/validator-setup.md).
## Install Go
+1 -1
View File
@@ -9,7 +9,7 @@ From the [networks/local directory](https://github.com/cosmos/cosmos-sdk/tree/de
### Requirements
- [Install gaia](https://cosmos.network/docs/getting-started/installation.html)
- [Install gaia](./installation.md)
- [Install docker](https://docs.docker.com/engine/installation/)
- [Install docker-compose](https://docs.docker.com/compose/install/)
+1 -1
View File
@@ -1,4 +1,4 @@
## Tendermint and Cosmos
# Tendermint and Cosmos
Blockchains can be divided into three conceptual layers:
+1 -1
View File
@@ -10,7 +10,7 @@ The ability to tolerate machines failing in arbitrary ways, including becoming m
## Application Blockchain Interface
Tendermint consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine, called Tendermint Core, ensures that the same transactions are recorded on every machine in the same order. The application interface, called the Application Blockchain Interface (ABCI), enables the transactions to be processed in any programming language. Unlike other blockchain and consensus solutions developers can use Tendermint for BFT state machine replication in any programming language or development environment. Visit the [Tendermint docs](https://tendermint.readthedocs.io/projects/tools/en/master/introduction.html#abci-overview) for a deep dive into the ABCI.
Tendermint consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine, called Tendermint Core, ensures that the same transactions are recorded on every machine in the same order. The application interface, called the Application Blockchain Interface (ABCI), enables the transactions to be processed in any programming language. Unlike other blockchain and consensus solutions developers can use Tendermint for BFT state machine replication in any programming language or development environment. Visit the [Tendermint docs](https://tendermint.com/docs/introduction/introduction.html#abci-overview) for a deep dive into the ABCI.
## Understanding the roles of the different layers
+1
View File
@@ -20,6 +20,7 @@ LCD will be used in the Cosmos Hub, the first Hub in the Cosmos network.
2. [**Get Started**](getting_started.md)
3. [**API**](api.md)
4. [**Specifications**](specification.md)
4. [**Update API docs To Swagger-UI**](update_API_docs.md)
## Overview
+1 -1
View File
@@ -169,7 +169,7 @@ gaiacli tx broadcast --node=<node> signedSendTx.json
#### Set up a Validator
Please refer to the [Validator Setup](https://cosmos.network/docs/validators/validator-setup.html) section for a more complete guide on how to set up a validator-candidate.
Please refer to the [Validator Setup](../validators/validator-setup.md) section for a more complete guide on how to set up a validator-candidate.
#### Delegate to a Validator
@@ -1,23 +0,0 @@
## Application CLI
**File: [`cmd/simplegovcli/maing.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/cmd/simplegovcli/main.go)**
To interact with our application, let us add the commands from the `simple_governance` module to our `simpleGov` application, as well as the pre-built SDK commands:
```go
// cmd/simplegovcli/main.go
...
rootCmd.AddCommand(
client.GetCommands(
simplegovcmd.GetCmdQueryProposal("proposals", cdc),
simplegovcmd.GetCmdQueryProposals("proposals", cdc),
simplegovcmd.GetCmdQueryProposalVotes("proposals", cdc),
simplegovcmd.GetCmdQueryProposalVote("proposals", cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
simplegovcmd.PostCmdPropose(cdc),
simplegovcmd.PostCmdVote(cdc),
)...)
...
```
@@ -1,21 +0,0 @@
## Application codec
**File: [`app/app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go)**
Finally, we need to define the `MakeCodec()` function and register the concrete types and interface from the various modules.
```go
func MakeCodec() *codec.Codec {
var cdc = codec.New()
codec.RegisterCrypto(cdc) // Register crypto.
sdk.RegisterCodec(cdc) // Register Msgs
bank.RegisterCodec(cdc)
simplestake.RegisterCodec(cdc)
simpleGov.RegisterCodec(cdc)
// Register AppAccount
cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "simpleGov/Account", nil)
return cdc
}
```
@@ -1,9 +0,0 @@
## App commands
We will need to add the newly created commands to our application. To do so, go to the `cmd` folder inside your root directory:
```bash
// At root level of directory
cd cmd
```
`simplegovd` is the folder that stores the command for running the server daemon, whereas `simplegovcli` defines the commands of your application.
@@ -1,61 +0,0 @@
## Application constructor
**File: [`app/app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go)**
Now, we need to define the constructor for our application.
```go
func NewSimpleGovApp(logger log.Logger, db dbm.DB) *SimpleGovApp
```
In this function, we will:
- Create the codec
```go
var cdc = MakeCodec()
```
- Instantiate our application. This includes creating the keys to access each of the substores.
```go
// Create your application object.
var app = &SimpleGovApp{
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
capKeySimpleGovStore: sdk.NewKVStoreKey("simpleGov"),
}
```
- Instantiate the keepers. Note that keepers generally need access to other module's keepers. In this case, make sure you only pass an instance of the keeper for the functionality that is needed. If a keeper only needs to read in another module's store, a read-only keeper should be passed to it.
```go
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper,app.RegisterCodespace(simplestake.DefaultCodespace))
app.simpleGovKeeper = simpleGov.NewKeeper(app.capKeySimpleGovStore, app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(simpleGov.DefaultCodespace))
```
- Declare the handlers.
```go
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper)).
AddRoute("simpleGov", simpleGov.NewHandler(app.simpleGovKeeper))
```
- Initialize the application.
```go
// Initialize BaseApp.
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeySimpleGovStore, app.capKeyStakingStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
err := app.LoadLatestVersion(app.capKeyMainStore)
if err != nil {
cmn.Exit(err.Error())
}
return app
```
@@ -1,4 +1,4 @@
## Application initialization
# Application Initialization
In the root of your fork of the SDK, create an `app` and `cmd` folder. In this folder, we will create the main file for our application, `app.go` and the repository to handle REST and CLI commands for our app.
@@ -1,22 +0,0 @@
## Makefile
The [Makefile](https://en.wikipedia.org/wiki/Makefile) compiles the Go program by defining a set of rules with targets and recipes. We'll need to add our application commands to it:
```
// Makefile
build_examples:
ifeq ($(OS),Windows_NT)
...
go build $(BUILD_FLAGS) -o build/simplegovd.exe ./examples/simpleGov/cmd/simplegovd
go build $(BUILD_FLAGS) -o build/simplegovcli.exe ./examples/simpleGov/cmd/simplegovcli
else
...
go build $(BUILD_FLAGS) -o build/simplegovd ./examples/simpleGov/cmd/simplegovd
go build $(BUILD_FLAGS) -o build/simplegovcli ./examples/simpleGov/cmd/simplegovcli
endif
...
install_examples:
...
go install $(BUILD_FLAGS) ./examples/simpleGov/cmd/simplegovd
go install $(BUILD_FLAGS) ./examples/simpleGov/cmd/simplegovcli
```
@@ -1,57 +0,0 @@
##### Rest server
**File: [`cmd/simplegovd/main.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/cmd/simplegovd/main.go)**
The `simplegovd` command will run the daemon server as a background process. First, let us create some `utils` functions:
```go
// cmd/simplegovd/main.go
// SimpleGovAppInit initial parameters
var SimpleGovAppInit = server.AppInit{
AppGenState: SimpleGovAppGenState,
AppGenTx: server.SimpleAppGenTx,
}
// SimpleGovAppGenState sets up the app_state and appends the simpleGov app state
func SimpleGovAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
appState, err = server.SimpleAppGenState(cdc, appGenTxs)
if err != nil {
return
}
return
}
func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewSimpleGovApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
dapp := app.NewSimpleGovApp(logger, db)
return dapp.ExportAppStateJSON()
}
```
Now, let us define the command for the daemon server within the `main()` function:
```go
// cmd/simplegovd/main.go
func main() {
cdc := app.MakeCodec()
ctx := server.NewDefaultContext()
rootCmd := &cobra.Command{
Use: "simplegovd",
Short: "Simple Governance Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
server.AddCommands(ctx, cdc, rootCmd, SimpleGovAppInit,
server.ConstructAppCreator(newApp, "simplegov"),
server.ConstructAppExporter(exportAppState, "simplegov"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.simplegovd")
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
executor.Execute()
}
```
@@ -1,55 +0,0 @@
## Application structure
Now, that we have built all the pieces we need, it is time to integrate them into the application. Let us exit the `/x` director go back at the root of the SDK directory.
```bash
// At root level of directory
cd app
```
We are ready to create our simple governance application!
*Note: You can check the full file (with comments!) [here](link)*
The `app.go` file is the main file that defines your application. In it, you will declare all the modules you need, their keepers, handlers, stores, etc. Let us take a look at each section of this file to see how the application is constructed.
Secondly, we need to define the name of our application.
```go
const (
appName = "SimpleGovApp"
)
```
Then, let us define the structure of our application.
```go
// Extended ABCI application
type SimpleGovApp struct {
*bam.BaseApp
cdc *codec.Codec
// keys to access the substores
capKeyMainStore *sdk.KVStoreKey
capKeyAccountStore *sdk.KVStoreKey
capKeyStakingStore *sdk.KVStoreKey
capKeySimpleGovStore *sdk.KVStoreKey
// keepers
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakeKeeper simplestake.Keeper
simpleGovKeeper simpleGov.Keeper
// Manage getting and setting accounts
accountMapper auth.AccountMapper
}
```
- Each application builds on top of the `BaseApp` template, hence the pointer.
- `cdc` is the codec used in our application.
- Then come the keys to the stores we need in our application. For our simple governance app, we need 3 stores + the main store.
- Then come the keepers and mappers.
Let us do a quick reminder so that it is clear why we need these stores and keepers. Our application is primarily based on the `simple_governance` module. However, we have established in section [Keepers for our app](module-keeper.md) that our module needs access to two other modules: the `bank` module and the `stake` module. We also need the `auth` module for basic account functionalities. Finally, we need access to the main multistore to declare the stores of each of the module we use.
@@ -0,0 +1,256 @@
# From Module To Application
## Application structure
Now, that we have built all the pieces we need, it is time to integrate them into the application. Let us exit the `/x` director go back at the root of the SDK directory.
```bash
// At root level of directory
cd app
```
We are ready to create our simple governance application!
*Note: You can check the full file (with comments!) [here](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go)*
The `app.go` file is the main file that defines your application. In it, you will declare all the modules you need, their keepers, handlers, stores, etc. Let us take a look at each section of this file to see how the application is constructed.
Secondly, we need to define the name of our application.
```go
const (
appName = "SimpleGovApp"
)
```
Then, let us define the structure of our application.
```go
// Extended ABCI application
type SimpleGovApp struct {
*bam.BaseApp
cdc *codec.Codec
// keys to access the substores
capKeyMainStore *sdk.KVStoreKey
capKeyAccountStore *sdk.KVStoreKey
capKeyStakingStore *sdk.KVStoreKey
capKeySimpleGovStore *sdk.KVStoreKey
// keepers
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakeKeeper simplestake.Keeper
simpleGovKeeper simpleGov.Keeper
// Manage getting and setting accounts
accountMapper auth.AccountMapper
}
```
- Each application builds on top of the `BaseApp` template, hence the pointer.
- `cdc` is the codec used in our application.
- Then come the keys to the stores we need in our application. For our simple governance app, we need 3 stores + the main store.
- Then come the keepers and mappers.
Let us do a quick reminder so that it is clear why we need these stores and keepers. Our application is primarily based on the `simple_governance` module. However, we have established in section [Keepers for our app](module-keeper.md) that our module needs access to two other modules: the `bank` module and the `stake` module. We also need the `auth` module for basic account functionalities. Finally, we need access to the main multistore to declare the stores of each of the module we use.
## CLI and Rest server
We will need to add the newly created commands to our application. To do so, go to the `cmd` folder inside your root directory:
```bash
// At root level of directory
cd cmd
```
`simplegovd` is the folder that stores the command for running the server daemon, whereas `simplegovcli` defines the commands of your application.
### Application CLI
**File: [`cmd/simplegovcli/maing.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/cmd/simplegovcli/main.go)**
To interact with our application, let us add the commands from the `simple_governance` module to our `simpleGov` application, as well as the pre-built SDK commands:
```go
// cmd/simplegovcli/main.go
...
rootCmd.AddCommand(
client.GetCommands(
simplegovcmd.GetCmdQueryProposal("proposals", cdc),
simplegovcmd.GetCmdQueryProposals("proposals", cdc),
simplegovcmd.GetCmdQueryProposalVotes("proposals", cdc),
simplegovcmd.GetCmdQueryProposalVote("proposals", cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
simplegovcmd.PostCmdPropose(cdc),
simplegovcmd.PostCmdVote(cdc),
)...)
...
```
### Rest server
**File: [`cmd/simplegovd/main.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/cmd/simplegovd/main.go)**
The `simplegovd` command will run the daemon server as a background process. First, let us create some `utils` functions:
```go
// cmd/simplegovd/main.go
// SimpleGovAppInit initial parameters
var SimpleGovAppInit = server.AppInit{
AppGenState: SimpleGovAppGenState,
AppGenTx: server.SimpleAppGenTx,
}
// SimpleGovAppGenState sets up the app_state and appends the simpleGov app state
func SimpleGovAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
appState, err = server.SimpleAppGenState(cdc, appGenTxs)
if err != nil {
return
}
return
}
func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewSimpleGovApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
dapp := app.NewSimpleGovApp(logger, db)
return dapp.ExportAppStateJSON()
}
```
Now, let us define the command for the daemon server within the `main()` function:
```go
// cmd/simplegovd/main.go
func main() {
cdc := app.MakeCodec()
ctx := server.NewDefaultContext()
rootCmd := &cobra.Command{
Use: "simplegovd",
Short: "Simple Governance Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
server.AddCommands(ctx, cdc, rootCmd, SimpleGovAppInit,
server.ConstructAppCreator(newApp, "simplegov"),
server.ConstructAppExporter(exportAppState, "simplegov"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.simplegovd")
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
executor.Execute()
}
```
## Makefile
The [Makefile](https://en.wikipedia.org/wiki/Makefile) compiles the Go program by defining a set of rules with targets and recipes. We'll need to add our application commands to it:
```
// Makefile
build_examples:
ifeq ($(OS),Windows_NT)
...
go build $(BUILD_FLAGS) -o build/simplegovd.exe ./examples/simpleGov/cmd/simplegovd
go build $(BUILD_FLAGS) -o build/simplegovcli.exe ./examples/simpleGov/cmd/simplegovcli
else
...
go build $(BUILD_FLAGS) -o build/simplegovd ./examples/simpleGov/cmd/simplegovd
go build $(BUILD_FLAGS) -o build/simplegovcli ./examples/simpleGov/cmd/simplegovcli
endif
...
install_examples:
...
go install $(BUILD_FLAGS) ./examples/simpleGov/cmd/simplegovd
go install $(BUILD_FLAGS) ./examples/simpleGov/cmd/simplegovcli
```
## Application constructor
**File: [`app/app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go)**
Now, we need to define the constructor for our application.
```go
func NewSimpleGovApp(logger log.Logger, db dbm.DB) *SimpleGovApp
```
In this function, we will:
- Create the codec
```go
var cdc = MakeCodec()
```
- Instantiate our application. This includes creating the keys to access each of the substores.
```go
// Create your application object.
var app = &SimpleGovApp{
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
capKeySimpleGovStore: sdk.NewKVStoreKey("simpleGov"),
}
```
- Instantiate the keepers. Note that keepers generally need access to other module's keepers. In this case, make sure you only pass an instance of the keeper for the functionality that is needed. If a keeper only needs to read in another module's store, a read-only keeper should be passed to it.
```go
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper,app.RegisterCodespace(simplestake.DefaultCodespace))
app.simpleGovKeeper = simpleGov.NewKeeper(app.capKeySimpleGovStore, app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(simpleGov.DefaultCodespace))
```
- Declare the handlers.
```go
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper)).
AddRoute("simpleGov", simpleGov.NewHandler(app.simpleGovKeeper))
```
- Initialize the application.
```go
// Initialize BaseApp.
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeySimpleGovStore, app.capKeyStakingStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
err := app.LoadLatestVersion(app.capKeyMainStore)
if err != nil {
cmn.Exit(err.Error())
}
return app
```
## Application codec
**File: [`app/app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go)**
Finally, we need to define the `MakeCodec()` function and register the concrete types and interface from the various modules.
```go
func MakeCodec() *codec.Codec {
var cdc = codec.New()
codec.RegisterCrypto(cdc) // Register crypto.
sdk.RegisterCodec(cdc) // Register Msgs
bank.RegisterCodec(cdc)
simplestake.RegisterCodec(cdc)
simpleGov.RegisterCodec(cdc)
// Register AppAccount
cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "simpleGov/Account", nil)
return cdc
}
```
@@ -1,19 +0,0 @@
## Cast a vote to an existing proposal
Let's cast a vote on the created proposal:
```bash
simplegovcli vote --proposal-id=1 --option="No"
```
Get the value of the option from your casted vote :
```bash
simplegovcli proposal-vote 1 <your_address>
```
You can also check all the casted votes of a proposal:
```bash
simplegovcli proposals-votes 1
```
@@ -6,45 +6,43 @@ Before getting in the bulk of the code, we will start by some introductory conte
## Table of contents:
### Introduction - Prerequsite reading
### Introduction - Prerequisite reading
- [Intro to Tendermint and Cosmos](../../../introduction/tendermint-cosmos.md)
- [Tendermint Core and ABCI](../../../introduction/tendermint.md)
- [Intro to Cosmos-SDK](../../overview.md)
- [Starting your own project](start.md)
- [Intro to Tendermint and Cosmos](/introduction/tendermint-cosmos.md)
- [Tendermint Core and ABCI](/introduction/tendermint.md)
- [Intro to Cosmos-SDK](/sdk/overview.md)
### Setup and design phase
- [Setup](setup.md)
- [Application design](app-design.md)
### [Setup and design](setup-and-design.md)
- [Starting your own project](setup-and-design.md#get-started)
- [Setup](setup-and-design.md#setup)
- [Application design](setup-and-design.md#application-design)
### Implementation of the application
**Important note: All the code for this application can be found [here](https://github.com/cosmos/cosmos-sdk/tree/fedekunze/module_tutorial/examples/simpleGov). Snippets will be provided throughout the tutorial, but please refer to the provided link for the full implementation details**
- [Application initialization](app-init.md)
- Simple Governance module
+ [Module initialization](module-init.md)
+ [Types](module-types.md)
+ [Keeper](module-keeper.md)
+ [Handler](module-handler.md)
+ [Wire](module-codec.md)
+ [Errors](module-errors.md)
+ Command-Line Interface and Rest API
* [Command-Line Interface](module-cli.md)
* [Rest API](module-rest.md)
- Bridging it all together
+ [Application structure](app-structure.md)
+ [Application CLI and Rest Server](app-commands.md)
* [Application CLI](app-cli.md)
* [Rest Server](app-rest.md)
+ [Makefile](app-makefile.md)
+ [Application constructor](app-constructor.md)
+ [Application codec](app-codec.md)
- Running the application
+ [Installation](run-install.md)
+ [Submit a proposal](submit-proposal.md)
+ [Cast a vote](cast-vote.md)
- [Simple Governance module](simple-gov-module.md)
+ [Module initialization](simple-gov-module.md#module-initialization)
+ [Types](simple-gov-module.md#types)
+ [Keeper](simple-gov-module.md#keeper)
+ [Handler](simple-gov-module.md#handler)
+ [Wire](simple-gov-module.md#codec)
+ [Errors](simple-gov-module.md#errors)
+ [Command-Line Interface](simple-gov-module.md#command-line-interface)
+ [Rest API](simple-gov-module.md#rest-api)
- [Bridging it all together](bridging-it-all.md)
+ [Application structure](bridging-it-all.md#application-structure)
+ [Application CLI and Rest Server](bridging-it-all.md#cli-and-rest-server)
+ [Makefile](bridging-it-all.md#makefile)
+ [Application constructor](bridging-it-all.md#application-constructor)
+ [Application codec](bridging-it-all.md#application-codec)
- [Running the application](running-the-application.md)
+ [Installation](running-the-application.md#installation)
+ [Submit a proposal](running-the-application.md#submit-a-proposal)
+ [Cast a vote](running-the-application.md#cast-a-vote)
## Useful links
@@ -1,33 +0,0 @@
## Command-Line Interface (CLI)
**File: [`x/simple_governance/client/cli/simple_governance.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/client/cli/simple_governance.go)**
Go in the `cli` folder and create a `simple_governance.go` file. This is where we will define the commands for our module.
The CLI builds on top of [Cobra](https://github.com/spf13/cobra). Here is the schema to build a command on top of Cobra:
```go
// Declare flags
const(
Flag = "flag"
...
)
// Main command function. One function for each command.
func Command(codec *codec.Codec) *cobra.Command {
// Create the command to return
command := &cobra.Command{
Use: "actual command",
Short: "Short description",
Run: func(cmd *cobra.Command, args []string) error {
// Actual function to run when command is used
},
}
// Add flags to the command
command.Flags().<Type>(FlagNameConstant, <example_value>, "<Description>")
return command
}
```
@@ -1,13 +0,0 @@
## Codec
**File: [`x/simple_governance/codec.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/codec.go)**
The `codec.go` file allows developers to register the concrete message types of their module into the codec. In our case, we have two messages to declare:
```go
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(SubmitProposalMsg{}, "simple_governance/SubmitProposalMsg", nil)
cdc.RegisterConcrete(VoteMsg{}, "simple_governance/VoteMsg", nil)
}
```
Don't forget to call this function in `app.go` (see [Application - Bridging it all together](app-structure.md)) for more).
@@ -1,7 +0,0 @@
## Errors
**File: [`x/simple_governance/errors.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/errors.go)**
The `error.go` file allows us to define custom error messages for our module. Declaring errors should be relatively similar in all modules. You can look in the `error.go` file directly for a concrete example. The code is self-explanatory.
Note that the errors of our module inherit from the `sdk.Error` interface and therefore possess the method `Result()`. This method is useful when there is an error in the `handler` and an error has to be returned in place of an actual result.
@@ -1,73 +0,0 @@
## Handler
**File: [`x/simple_governance/handler.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/handler.go)**
### Constructor and core handlers
Handlers implement the core logic of the state-machine. When a transaction is routed from the app to the module, it is run by the `handler` function.
In practice, one `handler` will be implemented for each message of the module. In our case, we have two message types. We will therefore need two `handler` functions. We will also need a constructor function to route the message to the correct `handler`:
```go
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case SubmitProposalMsg:
return handleSubmitProposalMsg(ctx, k, msg)
case VoteMsg:
return handleVoteMsg(ctx, k, msg)
default:
errMsg := "Unrecognized gov Msg type: " + msg.Name()
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
```
The messages are routed to the appropriate `handler` depending on their type. For our simple governance module, we only have two `handlers`, that correspond to our two message types. They have similar signatures:
```go
func handleSubmitProposalMsg(ctx sdk.Context, k Keeper, msg SubmitProposalMsg) sdk.Result
```
Let us take a look at the parameters of this function:
- The context `ctx` to access the stores.
- The keeper `k` allows the handler to read and write from the different stores, including the module's store (`SimpleGovernance` in our case) and all the stores from other modules that the keeper `k` has been granted an access to (`stake` and `bank` in our case).
- The message `msg` that holds all the information provided by the sender of the transaction.
The function returns a `Result` that is returned to the application. It contains several useful information such as the amount of `Gas` for this transaction and wether the message was succesfully processed or not. At this point, we exit the boundaries of our simple governance module and go back to root application level. The `Result` will differ from application to application. You can check the `sdk.Result` type directly [here](https://github.com/cosmos/cosmos-sdk/blob/develop/types/result.go) for more info.
### BeginBlocker and EndBlocker
In contrast to most smart-contracts platform, it is possible to perform automatic (i.e. not triggered by a transaction sent by an end-user) execution of logic in Cosmos-SDK applications.
This automatic execution of code takes place in the `BeginBlock` and `EndBlock` functions that are called at the beginning and at the end of every block. They are powerful tools, but it is important for application developers to be careful with them. For example, it is crutial that developers control the amount of computing that happens in these functions, as expensive computation could delay the block time, and never-ending loop freeze the chain altogether.
`BeginBlock` and `EndBlock` are composable functions, meaning that each module can implement its own `BeginBlock` and `EndBlock` logic. When needed, `BeginBlock` and `EndBlock` logic is implemented in the module's `handler`. Here is the standard way to proceed for `EndBlock` (`BeginBlock` follows the exact same pattern):
```go
func NewEndBlocker(k Keeper) sdk.EndBlocker {
return func(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
err := checkProposal(ctx, k)
if err != nil {
panic(err)
}
return
}
}
```
Do not forget that each module need to declare its `BeginBlock` and `EndBlock` constructors at application level. See the [Application - Bridging it all together](app-structure.md).
For the purpose of our simple governance application, we will use `EndBlock` to automatically tally the results of the vote. Here are the different steps that will be performed:
1. Get the oldest proposal from the `ProposalProcessingQueue`
2. Check if the `CurrentBlock` is the block at which the voting period for this proposal ends. If Yes, go to 3.. If no, exit.
3. Check if proposal is accepted or rejected. Update the proposal status.
4. Pop the proposal from the `ProposalProcessingQueue` and go back to 1.
Let us perform a quick safety analysis on this process.
- The loop will not run forever because the number of proposals in `ProposalProcessingQueue` is finite
- The computation should not be too expensive because tallying of individual proposals is not expensive and the number of proposals is expected be relatively low. That is because proposals require a `Deposit` to be accepted. `MinDeposit` should be high enough so that we don't have too many `Proposals` in the queue.
- In the eventuality that the application becomes so successful that the `ProposalProcessingQueue` ends up containing so many proposals that the blockchain starts slowing down, the module should be modified to mitigate the situation. One clever way of doing it is to cap the number of iteration per individual `EndBlock` at `MaxIteration`. This way, tallying will be spread over many blocks if the number of proposals is too important and block time should remain stable. This would require to modify the current check `if (CurrentBlock == Proposal.SubmitBlock + VotingPeriod)` to `if (CurrentBlock > Proposal.SubmitBlock + VotingPeriod) AND (Proposal.Status == ProposalStatusActive)`.
@@ -1,31 +0,0 @@
## Module initialization
First, let us go into the module's folder and create a folder for our module.
```bash
cd x/
mkdir simple_governance
cd simple_governance
mkdir -p client/cli client/rest
touch client/cli/simple_governance.go client/rest/simple_governance.go errors.go handler.go handler_test.go keeper_keys.go keeper_test.go keeper.go test_common.go test_types.go types.go codec.go
```
Let us start by adding the files we will need. Your module's folder should look something like that:
```
x
└─── simple_governance
├─── client
│ ├─── cli
│ │ └─── simple_governance.go
│ └─── rest
│ └─── simple_governance.go
├─── errors.go
├─── handler.go
├─── keeper_keys.go
├─── keeper.go
├─── types.go
└─── codec.go
```
Let us go into the detail of each of these files.
@@ -1,96 +0,0 @@
## Keeper
**File: [`x/simple_governance/keeper.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/keeper.go)**
### Short intro to keepers
`Keepers` are a module abstraction that handle reading/writing to the module store. This is a practical implementation of the **Object Capability Model** for Cosmos.
As module developers, we have to define keepers to interact with our module's store(s) not only from within our module, but also from other modules. When another module wants to access one of our module's store(s), a keeper for this store has to be passed to it at the application level. In practice, it will look like that:
```go
// in app.go
// instanciate keepers
keeperA = moduleA.newKeeper(app.moduleAStoreKey)
keeperB = moduleB.newKeeper(app.moduleBStoreKey)
// pass instance of keeperA to handler of module B
app.Router().
AddRoute("moduleA", moduleA.NewHandler(keeperA)).
AddRoute("moduleB", moduleB.NewHandler(keeperB, keeperA)) // Here module B can access one of module A's store via the keeperA instance
```
`KeeperA` grants a set of capabilities to the handler of module B. When developing a module, it is good practice to think about the sensitivity of the different capabilities that can be granted through keepers. For example, some module may need to read and write to module A's main store, while others only need to read it. If a module has multiple stores, then some keepers could grant access to all of them, while others would only grant access to specific sub-stores. It is the job of the module developer to make sure it is easy for application developers to instanciate a keeper with the right capabilities. Of course, the handler of a module will most likely get an unrestricted instance of that module's keeper.
### Store for our app
Before we delve into the keeper itself, let us see what objects we need to store in our governance sub-store, and how to index them.
- `Proposals` will be indexed by `'proposals'|<proposalID>`.
- `Votes` (`Yes`, `No`, `Abstain`) will be indexed by `'proposals'|<proposalID>|'votes'|<voterAddress>`.
Notice the quote mark on `'proposals'` and `'votes'`. They indicate that these are constant keywords. So, for example, the option casted by voter with address `0x01` on proposal `0101` will be stored at index `'proposals'|0101|'votes'|0x01`.
These keywords are used to faciliate range queries. Range queries (TODO: Link to formal spec) allow developer to query a subspace of the store, and return an iterator. They are made possible by the nice properties of the [IAVL+ tree](https://github.com/tendermint/iavl) that is used in the background. In practice, this means that it is possible to store and query a Key-Value pair in O(1), while still being able to iterate over a given subspace of Key-Value pairs. For example, we can query all the addresses that voted on a given proposal, along with their votes, by calling `rangeQuery(SimpleGovStore, <proposalID|'addresses'>)`.
### Keepers for our app
In our case, we only have one store to access, the `SimpleGov` store. We will need to set and get values inside this store via our keeper. However, these two actions do not have the same impact in terms of security. While there should no problem in granting read access to our store to other modules, write access is way more sensitive. So ideally application developers should be able to create either a governance mapper that can only get values from the store, or one that can both get and set values. To this end, we will introduce two keepers: `Keeper` and `KeeperRead`. When application developers create their application, they will be able to decide which of our module's keeper to use.
Now, let us try to think about which keeper from **external** modules our module's keepers need access to.
Each proposal requires a deposit. This means our module needs to be able to both read and write to the module that handles tokens, which is the `bank` module. We also need to be able to determine the voting power of each voter based on their stake. To this end, we need read access to the store of the `staking` module. However, we don't need write access to this store. We should therefore indicate that in our module, and the application developer should be careful to only pass a read-only keeper of the `staking` module to our module's handler.
With all that in mind, we can define the structure of our `Keeper`:
```go
type Keeper struct {
SimpleGov sdk.StoreKey // Key to our module's store
cdc *codec.Codec // Codec to encore/decode structs
ck bank.Keeper // Needed to handle deposits. This module onlyl requires read/writes to Atom balance
sm stake.Keeper // Needed to compute voting power. This module only needs read access to the staking store.
codespace sdk.CodespaceType // Reserves space for error codes
}
```
And the structure of our `KeeperRead`:
```go
type KeeperRead struct {
Keeper
}
```
`KeeperRead` will inherit all methods from `Keeper`, except those that we override. These will be the methods that perform writes to the store.
### Functions and Methods
The first function we have to create is the constructor.
```go
func NewKeeper(SimpleGov sdk.StoreKey, ck bank.Keeper, sm stake.Keeper, codespace sdk.CodespaceType) Keeper
```
This function is called from the main [`app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go) file to instanciate a new `Keeper`. A similar function exits for `KeeperRead`.
```go
func NewKeeperRead(SimpleGov sdk.StoreKey, ck bank.Keeper, sm stake.Keeper, codespace sdk.CodespaceType) KeeperRead
```
Depending on the needs of the application and its modules, either `Keeper`, `KeeperRead`, or both, will be instanciated at application level.
*Note: Both the `Keeper` type name and `NewKeeper()` function's name are standard names used in every module. It is no requirement to follow this standard, but doing so can facilitate the life of application developers*
Now, let us describe the methods we need for our module's `Keeper`. For the full implementation, please refer to `keeper.go`.
- `GetProposal`: Get a `Proposal` given a `proposalID`. Proposals need to be decoded from `byte` before they can be read.
- `SetProposal`: Set a `Proposal` at index `'proposals'|<proposalID>`. Proposals need to be encoded to `byte` before they can be stored.
- `NewProposalID`: A function to generate a new unique `proposalID`.
- `GetVote`: Get a vote `Option` given a `proposalID` and a `voterAddress`.
- `SetVote`: Set a vote `Option` given a `proposalID` and a `voterAddress`.
- Proposal Queue methods: These methods implement a standard proposal queue to store `Proposals` on a First-In First-Out basis. It is used to tally the votes at the end of the voting period.
The last thing that needs to be done is to override certain methods for the `KeeperRead` type. `KeeperRead` should not have write access to the stores. Therefore, we will override the methods `SetProposal()`, `SetVote()` and `NewProposalID()`, as well as `setProposalQueue()` from the Proposal Queue's methods. For `KeeperRead`, these methods will just throw an error.
*Note: If you look at the code, you'll notice that the context `ctx` is a parameter of many of the methods. The context `ctx` provides useful information on the current state such as the current block height and allows the keeper `k` to access the `KVStore`. You can check all the methods of `ctx` [here](https://github.com/cosmos/cosmos-sdk/blob/develop/types/context.go#L144-L168)*.
@@ -1,32 +0,0 @@
## Rest API
**File: [`x/simple_governance/client/rest/simple_governance.goo`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/client/rest/simple_governance.go)**
The Rest Server, also called [Light-Client Daemon (LCD)](https://github.com/cosmos/cosmos-sdk/tree/master/client/lcd), provides support for **HTTP queries**.
________________________________________________________
USER INTERFACE <=======> REST SERVER <=======> FULL-NODE
________________________________________________________
It allows end-users that do not want to run full-nodes themselves to interract with the chain. The LCD can be configured to perform **Light-Client verification** via the flag `--trust-node`, which can be set to `true` or `false`.
- If *light-client verification* is enabled, the Rest Server acts as a light-client and needs to be run on the end-user's machine. It allows them to interract with the chain in a trustless way without having to store the whole chain locally.
- If *light-client verification* is disabled, the Rest Server acts as a simple relayer for HTTP calls. In this setting, the Rest server needs not be run on the end-user's machine. Instead, it will probably be run by the same entity that operates the full-node the server connects to. This mode is useful if end-users trust the full-node operator and do not want to store anything locally.
Now, let us define endpoints that will be available for users to query through HTTP requests. These endpoints will be defined in a `simple_governance.go` file stored in the `rest` folder.
| Method | URL | Description |
|--------|---------------------------------|-------------------------------------------------------------|
| GET | /proposals | Range query to get all submitted proposals |
| POST | /proposals | Submit a new proposal |
| GET | /proposals/{id} | Returns a proposal given its ID |
| GET | /proposals/{id}/votes | Range query to get all the votes casted on a given proposal |
| POST | /proposals/{id}/votes | Cast a vote on a given proposal |
| GET | /proposals/{id}/votes/{address} | Returns the vote of a given address on a given proposal |
It is the job of module developers to provide sensible endpoints so that front-end developers and service providers can properly interact with it.
Additionaly, here is a [link](https://hackernoon.com/restful-api-designing-guidelines-the-best-practices-60e1d954e7c9) for REST APIs best practices.
@@ -1,23 +0,0 @@
## Types
**File: [`x/simple_governance/types.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/types.go)**
In this file, we define the custom types for our module. This includes the types from the [State](app-design.md#State) section and the custom message types defined in the [Messages](app-design#Messages) section.
For each new type that is not a message, it is possible to add methods that make sense in the context of the application. In our case, we will implement an `updateTally` function to easily update the tally of a given proposal as vote messages come in.
Messages are a bit different. They implement the `Message` interface defined in the SDK's `types` folder. Here are the methods you need to implement when you define a custom message type:
- `Type()`: This function returns the name of our module's route. When messages are processed by the application, they are routed using the string returned by the `Type()` method.
- `GetSignBytes()`: Returns the byte representation of the message. It is used to sign the message.
- `GetSigners()`: Returns address(es) of the signer(s).
- `ValidateBasic()`: This function is used to discard obviously invalid messages. It is called at the beginning of `runTx()` in the baseapp file. If `ValidateBasic()` does not return `nil`, the app stops running the transaction.
- `Get()`: A basic getter, returns some property of the message.
- `String()`: Returns a human-readable version of the message
For our simple governance messages, this means:
- `Type()` will return `"simpleGov"`
- For `SubmitProposalMsg`, we need to make sure that the attributes are not empty and that the deposit is both valid and positive. Note that this is only basic validation, we will therefore not check in this method that the sender has sufficient funds to pay for the deposit
- For `VoteMsg`, we check that the address and option are valid and that the proposalID is not negative.
- As for other methods, less customization is required. You can check the code to see a standard way of implementing these.
@@ -1,18 +0,0 @@
## Installation
Once you have finallized your application, install it using `go get`. The following commands will install the pre-built modules and examples of the SDK as well as your `simpleGov` application:
```bash
go get github.com/<your_username>/cosmos-sdk
cd $GOPATH/src/github.com/<your_username>/cosmos-sdk
make get_vendor_deps
make install
make install_examples
```
Check that the app is correctly installed by typing:
```bash
simplegovcli -h
simplegovd -h
```
@@ -0,0 +1,77 @@
# Running The Application
## Installation
Once you have finallized your application, install it using `go get`. The following commands will install the pre-built modules and examples of the SDK as well as your `simpleGov` application:
```bash
go get github.com/<your_username>/cosmos-sdk
cd $GOPATH/src/github.com/<your_username>/cosmos-sdk
make get_vendor_deps
make install
make install_examples
```
Check that the app is correctly installed by typing:
```bash
simplegovcli -h
simplegovd -h
```
## Submit a proposal
Uuse the CLI to create a new proposal:
```bash
simplegovcli propose --title="Voting Period update" --description="Should we change the proposal voting period to 3 weeks?" --deposit=300Atoms
```
Or, via a json file:
```bash
simplegovcli propose --proposal="path/to/proposal.json"
```
Where proposal.json contains:
```json
{
"title": "Voting Period Update",
"description": "Should we change the proposal voting period to 3 weeks?",
"type": "Text",
"deposit": "300Atoms"
}
```
Get the details of your newly created proposal:
```bash
simplegovcli proposal 1
```
You can also check all the existing open proposals:
```bash
simplegovcli proposals --active=true
```
## Cast a vote
Let's cast a vote on the created proposal:
```bash
simplegovcli vote --proposal-id=1 --option="No"
```
Get the value of the option from your casted vote :
```bash
simplegovcli proposal-vote 1 <your_address>
```
You can also check all the casted votes of a proposal:
```bash
simplegovcli proposals-votes 1
```
@@ -1,3 +1,47 @@
# Setup And Design
## Get started
To get started, you just have to follow these simple steps:
1. Clone the [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk/tree/develop)repo
2. Code the modules needed by your application that do not already exist.
3. Create your app directory. In the app main file, import the module you need and instantiate the different stores.
4. Launch your blockchain.
## Setup
### Prerequisites
- Have [go](https://golang.org/dl/) and [git](https://git-scm.com/downloads) installed
- Don't forget to set your `PATH` and `GOPATH`
### Setup work environment
Go to the [Cosmos-SDK repo](https://githum.com/cosmos/cosmos-sdk) and fork it. Then open a terminal and:
```bash
cd $GOPATH/src/github.com/your_username
git clone github.com/your_username/cosmos-sdk
cd cosmos-sdk
```
Now we'll add the origin Cosmos-SDK as upstream in case some cool feature or module gets merged:
```bash
git remote add upstream github.com/cosmos/cosmos-sdk
git fetch upstream
git rebase upstream/master
```
We will also create a branch dedicated to our module:
```bash
git checkout -b my_new_application
```
We are all set!
## Application design
### Application description
@@ -1,32 +0,0 @@
## Setup
### Prerequisites
- Have [go](https://golang.org/dl/) and [git](https://git-scm.com/downloads) installed
- Don't forget to set your `PATH` and `GOPATH`
### Setup work environment
Go to the [Cosmos-SDK repo](https://githum.com/cosmos/cosmos-sdk) and fork it. Then open a terminal and:
```bash
cd $GOPATH/src/github.com/your_username
git clone github.com/your_username/cosmos-sdk
cd cosmos-sdk
```
Now we'll add the origin Cosmos-SDK as upstream in case some cool feature or module gets merged:
```bash
git remote add upstream github.com/cosmos/cosmos-sdk
git fetch upstream
git rebase upstream/master
```
We will also create a branch dedicated to our module:
```bash
git checkout -b my_new_application
```
We are all set!
@@ -0,0 +1,316 @@
# Simple Governance Module
## Module initialization
First, let us go into the module's folder and create a folder for our module.
```bash
cd x/
mkdir simple_governance
cd simple_governance
mkdir -p client/cli client/rest
touch client/cli/simple_governance.go client/rest/simple_governance.go errors.go handler.go handler_test.go keeper_keys.go keeper_test.go keeper.go test_common.go test_types.go types.go codec.go
```
Let us start by adding the files we will need. Your module's folder should look something like that:
```
x
└─── simple_governance
├─── client
│ ├─── cli
│ │ └─── simple_governance.go
│ └─── rest
│ └─── simple_governance.go
├─── errors.go
├─── handler.go
├─── keeper_keys.go
├─── keeper.go
├─── types.go
└─── codec.go
```
Let us go into the detail of each of these files.
## Types
**File: [`x/simple_governance/types.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/types.go)**
In this file, we define the custom types for our module. This includes the types from the [State](app-design.md#State) section and the custom message types defined in the [Messages](app-design#Messages) section.
For each new type that is not a message, it is possible to add methods that make sense in the context of the application. In our case, we will implement an `updateTally` function to easily update the tally of a given proposal as vote messages come in.
Messages are a bit different. They implement the `Message` interface defined in the SDK's `types` folder. Here are the methods you need to implement when you define a custom message type:
- `Type()`: This function returns the name of our module's route. When messages are processed by the application, they are routed using the string returned by the `Type()` method.
- `GetSignBytes()`: Returns the byte representation of the message. It is used to sign the message.
- `GetSigners()`: Returns address(es) of the signer(s).
- `ValidateBasic()`: This function is used to discard obviously invalid messages. It is called at the beginning of `runTx()` in the baseapp file. If `ValidateBasic()` does not return `nil`, the app stops running the transaction.
- `Get()`: A basic getter, returns some property of the message.
- `String()`: Returns a human-readable version of the message
For our simple governance messages, this means:
- `Type()` will return `"simpleGov"`
- For `SubmitProposalMsg`, we need to make sure that the attributes are not empty and that the deposit is both valid and positive. Note that this is only basic validation, we will therefore not check in this method that the sender has sufficient funds to pay for the deposit
- For `VoteMsg`, we check that the address and option are valid and that the proposalID is not negative.
- As for other methods, less customization is required. You can check the code to see a standard way of implementing these.
## Keeper
**File: [`x/simple_governance/keeper.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/keeper.go)**
### Short intro to keepers
`Keepers` are a module abstraction that handle reading/writing to the module store. This is a practical implementation of the **Object Capability Model** for Cosmos.
As module developers, we have to define keepers to interact with our module's store(s) not only from within our module, but also from other modules. When another module wants to access one of our module's store(s), a keeper for this store has to be passed to it at the application level. In practice, it will look like that:
```go
// in app.go
// instanciate keepers
keeperA = moduleA.newKeeper(app.moduleAStoreKey)
keeperB = moduleB.newKeeper(app.moduleBStoreKey)
// pass instance of keeperA to handler of module B
app.Router().
AddRoute("moduleA", moduleA.NewHandler(keeperA)).
AddRoute("moduleB", moduleB.NewHandler(keeperB, keeperA)) // Here module B can access one of module A's store via the keeperA instance
```
`KeeperA` grants a set of capabilities to the handler of module B. When developing a module, it is good practice to think about the sensitivity of the different capabilities that can be granted through keepers. For example, some module may need to read and write to module A's main store, while others only need to read it. If a module has multiple stores, then some keepers could grant access to all of them, while others would only grant access to specific sub-stores. It is the job of the module developer to make sure it is easy for application developers to instanciate a keeper with the right capabilities. Of course, the handler of a module will most likely get an unrestricted instance of that module's keeper.
### Store for our app
Before we delve into the keeper itself, let us see what objects we need to store in our governance sub-store, and how to index them.
- `Proposals` will be indexed by `'proposals'|<proposalID>`.
- `Votes` (`Yes`, `No`, `Abstain`) will be indexed by `'proposals'|<proposalID>|'votes'|<voterAddress>`.
Notice the quote mark on `'proposals'` and `'votes'`. They indicate that these are constant keywords. So, for example, the option casted by voter with address `0x01` on proposal `0101` will be stored at index `'proposals'|0101|'votes'|0x01`.
These keywords are used to faciliate range queries. Range queries (TODO: Link to formal spec) allow developer to query a subspace of the store, and return an iterator. They are made possible by the nice properties of the [IAVL+ tree](https://github.com/tendermint/iavl) that is used in the background. In practice, this means that it is possible to store and query a Key-Value pair in O(1), while still being able to iterate over a given subspace of Key-Value pairs. For example, we can query all the addresses that voted on a given proposal, along with their votes, by calling `rangeQuery(SimpleGovStore, <proposalID|'addresses'>)`.
### Keepers for our app
In our case, we only have one store to access, the `SimpleGov` store. We will need to set and get values inside this store via our keeper. However, these two actions do not have the same impact in terms of security. While there should no problem in granting read access to our store to other modules, write access is way more sensitive. So ideally application developers should be able to create either a governance mapper that can only get values from the store, or one that can both get and set values. To this end, we will introduce two keepers: `Keeper` and `KeeperRead`. When application developers create their application, they will be able to decide which of our module's keeper to use.
Now, let us try to think about which keeper from **external** modules our module's keepers need access to.
Each proposal requires a deposit. This means our module needs to be able to both read and write to the module that handles tokens, which is the `bank` module. We also need to be able to determine the voting power of each voter based on their stake. To this end, we need read access to the store of the `staking` module. However, we don't need write access to this store. We should therefore indicate that in our module, and the application developer should be careful to only pass a read-only keeper of the `staking` module to our module's handler.
With all that in mind, we can define the structure of our `Keeper`:
```go
type Keeper struct {
SimpleGov sdk.StoreKey // Key to our module's store
cdc *codec.Codec // Codec to encore/decode structs
ck bank.Keeper // Needed to handle deposits. This module onlyl requires read/writes to Atom balance
sm stake.Keeper // Needed to compute voting power. This module only needs read access to the staking store.
codespace sdk.CodespaceType // Reserves space for error codes
}
```
And the structure of our `KeeperRead`:
```go
type KeeperRead struct {
Keeper
}
```
`KeeperRead` will inherit all methods from `Keeper`, except those that we override. These will be the methods that perform writes to the store.
### Functions and Methods
The first function we have to create is the constructor.
```go
func NewKeeper(SimpleGov sdk.StoreKey, ck bank.Keeper, sm stake.Keeper, codespace sdk.CodespaceType) Keeper
```
This function is called from the main [`app.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/app/app.go) file to instanciate a new `Keeper`. A similar function exits for `KeeperRead`.
```go
func NewKeeperRead(SimpleGov sdk.StoreKey, ck bank.Keeper, sm stake.Keeper, codespace sdk.CodespaceType) KeeperRead
```
Depending on the needs of the application and its modules, either `Keeper`, `KeeperRead`, or both, will be instanciated at application level.
*Note: Both the `Keeper` type name and `NewKeeper()` function's name are standard names used in every module. It is no requirement to follow this standard, but doing so can facilitate the life of application developers*
Now, let us describe the methods we need for our module's `Keeper`. For the full implementation, please refer to `keeper.go`.
- `GetProposal`: Get a `Proposal` given a `proposalID`. Proposals need to be decoded from `byte` before they can be read.
- `SetProposal`: Set a `Proposal` at index `'proposals'|<proposalID>`. Proposals need to be encoded to `byte` before they can be stored.
- `NewProposalID`: A function to generate a new unique `proposalID`.
- `GetVote`: Get a vote `Option` given a `proposalID` and a `voterAddress`.
- `SetVote`: Set a vote `Option` given a `proposalID` and a `voterAddress`.
- Proposal Queue methods: These methods implement a standard proposal queue to store `Proposals` on a First-In First-Out basis. It is used to tally the votes at the end of the voting period.
The last thing that needs to be done is to override certain methods for the `KeeperRead` type. `KeeperRead` should not have write access to the stores. Therefore, we will override the methods `SetProposal()`, `SetVote()` and `NewProposalID()`, as well as `setProposalQueue()` from the Proposal Queue's methods. For `KeeperRead`, these methods will just throw an error.
*Note: If you look at the code, you'll notice that the context `ctx` is a parameter of many of the methods. The context `ctx` provides useful information on the current state such as the current block height and allows the keeper `k` to access the `KVStore`. You can check all the methods of `ctx` [here](https://github.com/cosmos/cosmos-sdk/blob/develop/types/context.go#L144-L168)*.
## Handler
**File: [`x/simple_governance/handler.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/handler.go)**
### Constructor and core handlers
Handlers implement the core logic of the state-machine. When a transaction is routed from the app to the module, it is run by the `handler` function.
In practice, one `handler` will be implemented for each message of the module. In our case, we have two message types. We will therefore need two `handler` functions. We will also need a constructor function to route the message to the correct `handler`:
```go
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case SubmitProposalMsg:
return handleSubmitProposalMsg(ctx, k, msg)
case VoteMsg:
return handleVoteMsg(ctx, k, msg)
default:
errMsg := "Unrecognized gov Msg type: " + reflect.TypeOf(msg).Name()
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
```
The messages are routed to the appropriate `handler` depending on their type. For our simple governance module, we only have two `handlers`, that correspond to our two message types. They have similar signatures:
```go
func handleSubmitProposalMsg(ctx sdk.Context, k Keeper, msg SubmitProposalMsg) sdk.Result
```
Let us take a look at the parameters of this function:
- The context `ctx` to access the stores.
- The keeper `k` allows the handler to read and write from the different stores, including the module's store (`SimpleGovernance` in our case) and all the stores from other modules that the keeper `k` has been granted an access to (`stake` and `bank` in our case).
- The message `msg` that holds all the information provided by the sender of the transaction.
The function returns a `Result` that is returned to the application. It contains several useful information such as the amount of `Gas` for this transaction and wether the message was succesfully processed or not. At this point, we exit the boundaries of our simple governance module and go back to root application level. The `Result` will differ from application to application. You can check the `sdk.Result` type directly [here](https://github.com/cosmos/cosmos-sdk/blob/develop/types/result.go) for more info.
### BeginBlocker and EndBlocker
In contrast to most smart-contracts platform, it is possible to perform automatic (i.e. not triggered by a transaction sent by an end-user) execution of logic in Cosmos-SDK applications.
This automatic execution of code takes place in the `BeginBlock` and `EndBlock` functions that are called at the beginning and at the end of every block. They are powerful tools, but it is important for application developers to be careful with them. For example, it is crutial that developers control the amount of computing that happens in these functions, as expensive computation could delay the block time, and never-ending loop freeze the chain altogether.
`BeginBlock` and `EndBlock` are composable functions, meaning that each module can implement its own `BeginBlock` and `EndBlock` logic. When needed, `BeginBlock` and `EndBlock` logic is implemented in the module's `handler`. Here is the standard way to proceed for `EndBlock` (`BeginBlock` follows the exact same pattern):
```go
func NewEndBlocker(k Keeper) sdk.EndBlocker {
return func(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
err := checkProposal(ctx, k)
if err != nil {
panic(err)
}
return
}
}
```
Do not forget that each module need to declare its `BeginBlock` and `EndBlock` constructors at application level. See the [Application - Bridging it all together](app-structure.md).
For the purpose of our simple governance application, we will use `EndBlock` to automatically tally the results of the vote. Here are the different steps that will be performed:
1. Get the oldest proposal from the `ProposalProcessingQueue`
2. Check if the `CurrentBlock` is the block at which the voting period for this proposal ends. If Yes, go to 3.. If no, exit.
3. Check if proposal is accepted or rejected. Update the proposal status.
4. Pop the proposal from the `ProposalProcessingQueue` and go back to 1.
Let us perform a quick safety analysis on this process.
- The loop will not run forever because the number of proposals in `ProposalProcessingQueue` is finite
- The computation should not be too expensive because tallying of individual proposals is not expensive and the number of proposals is expected be relatively low. That is because proposals require a `Deposit` to be accepted. `MinDeposit` should be high enough so that we don't have too many `Proposals` in the queue.
- In the eventuality that the application becomes so successful that the `ProposalProcessingQueue` ends up containing so many proposals that the blockchain starts slowing down, the module should be modified to mitigate the situation. One clever way of doing it is to cap the number of iteration per individual `EndBlock` at `MaxIteration`. This way, tallying will be spread over many blocks if the number of proposals is too important and block time should remain stable. This would require to modify the current check `if (CurrentBlock == Proposal.SubmitBlock + VotingPeriod)` to `if (CurrentBlock > Proposal.SubmitBlock + VotingPeriod) AND (Proposal.Status == ProposalStatusActive)`.
## Codec
**File: [`x/simple_governance/codec.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/codec.go)**
The `codec.go` file allows developers to register the concrete message types of their module into the codec. In our case, we have two messages to declare:
```go
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(SubmitProposalMsg{}, "simple_governance/SubmitProposalMsg", nil)
cdc.RegisterConcrete(VoteMsg{}, "simple_governance/VoteMsg", nil)
}
```
Don't forget to call this function in `app.go` (see [Application - Bridging it all together](app-structure.md)) for more).
## Errors
**File: [`x/simple_governance/errors.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/errors.go)**
The `error.go` file allows us to define custom error messages for our module. Declaring errors should be relatively similar in all modules. You can look in the `error.go` file directly for a concrete example. The code is self-explanatory.
Note that the errors of our module inherit from the `sdk.Error` interface and therefore possess the method `Result()`. This method is useful when there is an error in the `handler` and an error has to be returned in place of an actual result.
## Command-Line Interface
**File: [`x/simple_governance/client/cli/simple_governance.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/client/cli/simple_governance.go)**
Go in the `cli` folder and create a `simple_governance.go` file. This is where we will define the commands for our module.
The CLI builds on top of [Cobra](https://github.com/spf13/cobra). Here is the schema to build a command on top of Cobra:
```go
// Declare flags
const(
Flag = "flag"
...
)
// Main command function. One function for each command.
func Command(codec *codec.Codec) *cobra.Command {
// Create the command to return
command := &cobra.Command{
Use: "actual command",
Short: "Short description",
Run: func(cmd *cobra.Command, args []string) error {
// Actual function to run when command is used
},
}
// Add flags to the command
command.Flags().<Type>(FlagNameConstant, <example_value>, "<Description>")
return command
}
```
## Rest API
**File: [`x/simple_governance/client/rest/simple_governance.goo`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/x/simple_governance/client/rest/simple_governance.go)**
The Rest Server, also called [Light-Client Daemon (LCD)](https://github.com/cosmos/cosmos-sdk/tree/master/client/lcd), provides support for **HTTP queries**.
________________________________________________________
USER INTERFACE <=======> REST SERVER <=======> FULL-NODE
________________________________________________________
It allows end-users that do not want to run full-nodes themselves to interract with the chain. The LCD can be configured to perform **Light-Client verification** via the flag `--trust-node`, which can be set to `true` or `false`.
- If *light-client verification* is enabled, the Rest Server acts as a light-client and needs to be run on the end-user's machine. It allows them to interract with the chain in a trustless way without having to store the whole chain locally.
- If *light-client verification* is disabled, the Rest Server acts as a simple relayer for HTTP calls. In this setting, the Rest server needs not be run on the end-user's machine. Instead, it will probably be run by the same entity that operates the full-node the server connects to. This mode is useful if end-users trust the full-node operator and do not want to store anything locally.
Now, let us define endpoints that will be available for users to query through HTTP requests. These endpoints will be defined in a `simple_governance.go` file stored in the `rest` folder.
| Method | URL | Description |
|--------|---------------------------------|-------------------------------------------------------------|
| GET | /proposals | Range query to get all submitted proposals |
| POST | /proposals | Submit a new proposal |
| GET | /proposals/{id} | Returns a proposal given its ID |
| GET | /proposals/{id}/votes | Range query to get all the votes casted on a given proposal |
| POST | /proposals/{id}/votes | Cast a vote on a given proposal |
| GET | /proposals/{id}/votes/{address} | Returns the vote of a given address on a given proposal |
It is the job of module developers to provide sensible endpoints so that front-end developers and service providers can properly interact with it.
Additionaly, here is a [link](https://hackernoon.com/restful-api-designing-guidelines-the-best-practices-60e1d954e7c9) for REST APIs best practices.
@@ -1,10 +0,0 @@
## Starting your own project
To get started, you just have to follow these simple steps:
1. Clone the [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk/tree/develop)repo
2. Code the modules needed by your application that do not already exist.
3. Create your app directory. In the app main file, import the module you need and instantiate the different stores.
4. Launch your blockchain.
Easy as pie! With the introduction over, let us delve into practice and learn how to code a SDK application with an example.
@@ -1,36 +0,0 @@
## Submit a proposal
Uuse the CLI to create a new proposal:
```bash
simplegovcli propose --title="Voting Period update" --description="Should we change the proposal voting period to 3 weeks?" --deposit=300Atoms
```
Or, via a json file:
```bash
simplegovcli propose --proposal="path/to/proposal.json"
```
Where proposal.json contains:
```json
{
"title": "Voting Period Update",
"description": "Should we change the proposal voting period to 3 weeks?",
"type": "Text",
"deposit": "300Atoms"
}
```
Get the details of your newly created proposal:
```bash
simplegovcli proposal 1
```
You can also check all the existing open proposals:
```bash
simplegovcli proposals --active=true
```
+2 -2
View File
@@ -216,12 +216,12 @@ We have to solve this simple equation to find the reward R for each validator:
* For the proposer validator:
* The pool obtains `R + R * 5%`: 105 Atoms
* Commission: `105 * 80% * 1%` = 0.84 Atoms
* Validator's reward: `100 * 20% + Commission` = 21.84 Atoms
* Validator's reward: `105 * 20% + Commission` = 21.84 Atoms
* Delegators' rewards: `105 * 80% - Commission` = 83.16 Atoms (each delegator will be able to claim its portion of these rewards in proportion to their stake)
* For each non-proposer validator:
* The pool obtains R: 100 Atoms
* Commission: `100 * 80% * 1%` = 0.8 Atoms
* Validator's reward: `105 * 20% + Commission` = 20.8 Atoms
* Validator's reward: `100 * 20% + Commission` = 20.8 Atoms
* Delegators' rewards: `100 * 80% - Commission` = 79.2 Atoms (each delegator will be able to claim its portion of these rewards in proportion to their stake)
### What are the slashing conditions?