Merge PR #5902: update docs/cn: match newest Chinese docs in intro and basics

This commit is contained in:
Alexander Bezobchuk 2020-04-01 10:13:59 -04:00 committed by GitHub
commit a368988e17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 865 additions and 113 deletions

View File

@ -7,22 +7,28 @@ parent:
## 开始
- **[SDK 介绍](./intro/README.md)**从“高层”了解Cosmos SDK.
- **[SDK 介绍](./intro/README.md)**Cosmos SDK的总体概览
- **[快速开始](./using-the-sdk/quick-start.md)**构建一个标准的基于cosmos sdk的app并启动节点
- **[SDK 开发教程](https://github.com/cosmos/sdk-application-tutorial)**: 一个学习 SDK 的教程。它展示了如何从头开始基于 sdk 构建区块链, 并在此过程中解释了 SDK 的基本原理。
## 索引
- **[基础文档](./basics/)**cosmos sdk的基础概念文档例如应用结构、交易的生命周期、账户管理等
- **[核心文档](./core/)**: cosmos sdk的核心文档例如`baseapp``store``server`等
- **[构建模块](./building-modules/)**: 对于模块开发者来说的一些重要概念,例如`message``keeper``handler``querier`
- **[接口](./interfaces/)**: 为cosmos应用设计接口的文档
## 开发资源
- [规范](./spec/README.md): Cosmos SDK 的模块及其他规范。
- [SDK API 参考](https://godoc.org/github.com/cosmos/cosmos-sdk): Cosmos SDK Godocs 文档 。
- [REST API 规范](https://cosmos.network/rpc/): 通过 REST 与 `gaia` 全节点交互的 API 列表。
- **[模块目录](../../x/)**: 模块的实现和文档
## 创建新的 SDK 项目
若要创建新项目, 以下两个方法任选其一:
- 克隆这个 [教程](https://github.com/cosmos/sdk-application-tutorial/),如果不需要, 请不要忘记从各种文件中删除 `nameservice` 模块。
- 使用社区工具, 如 [chainkit](https://github.com/blocklayerhq/chainkit).
- **[规范](./spec/):** Cosmos SDK 的模块及其他规范。
- **[SDK API 参考](https://godoc.org/github.com/cosmos/cosmos-sdk):** Cosmos SDK Godocs 文档 。
- **[REST API 规范](https://cosmos.network/rpc/):** 通过 REST 与 `gaia` 全节点交互的 API 列表。
## Cosmos Hub
@ -35,7 +41,3 @@ Cosmos-SDK 目前是用 [Golang](https://golang.org/)编写的, 尽管该框架
## 贡献
参考 [文档说明](https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md) 了解构建细节及更新时注意事项。
## 版本
这份文档通过以下提交构建:

10
docs/cn/basics/README.md Normal file
View File

@ -0,0 +1,10 @@
# 基础文档
此目录包含对cosmos sdk的基础概念介绍
1. [SDK应用解析](./app-anatomy.md)
2. [交易的生命周期](./tx-lifecycle.md)
3. [账户系统](./accounts.md)
4. [Gas 和 Fees](./gas-fees.md)
阅读完基础文档后,可以阅读 [核心文档](../core/README.md) 进一步加深对cosmos的理解。

130
docs/cn/basics/accounts.md Normal file
View File

@ -0,0 +1,130 @@
**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/accounts.md**
# 账户系统
# 必备阅读 {hide}
- [一个SDK程序的剖析](./app-anatomy.md) {prereq}
## 账户定义
在Cosmos SDK中,一个账户是指定的一个公私钥对.公钥可以用于派生出`Addresses`,`Addresses`可以在程序里面的各个模块间区分不同的用户.`Addresses`同样可以和[消息](../building-modules/messages-and-queries.md#messages)进行关联用于确定发消息的账户.私钥一般用于生成签名来证明一个消息是被一个`Addresses`(和私钥关联的`Addresses`)所发送.
Cosmos SDK使用一套称之为 [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)的标准来生成公私钥.这个标准定义了怎么去创建一个HD钱包(钱包就是一批账户的集合).每一个账户的核心,都有一个种子,每一个种子都有一个12或24个字的助记符.使用这个助记符,使用一种单向的加密方法可以派生出任意数量的私钥.公钥可以通过私钥推导出来.当然,助记符是最敏感的信息,因为可以不停通过助记符来重新生成私钥.
```
Account 0 Account 1 Account 2
+------------------+ +------------------+ +------------------+
| | | | | |
| Address 0 | | Address 1 | | Address 2 |
| ^ | | ^ | | ^ |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| + | | + | | + |
| Public key 0 | | Public key 1 | | Public key 2 |
| ^ | | ^ | | ^ |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| + | | + | | + |
| Private key 0 | | Private key 1 | | Private key 2 |
| ^ | | ^ | | ^ |
+------------------+ +------------------+ +------------------+
| | |
| | |
| | |
+--------------------------------------------------------------------+
|
|
+---------+---------+
| |
| Master PrivKey |
| |
+-------------------+
|
|
+---------+---------+
| |
| Mnemonic (Seed) |
| |
+-------------------+
```
在Cosmos SDK中,账户可以在[`Keybase`](#keybase)中作为一个对象来储存和管理.
## Keybase
`Keybase` 是储存和管理账户的对象,在Cosmos SDK中,`Keybase`要实现以下接口
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/types.go#L13-L86
在Cosmos SDK中,`Keybase`接口的默认实现对象是`dbKeybase`.
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/keybase.go
`dbKeybase`上面对`Keybase`接口中方法实现的笔记:
- `Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)`对`message` 字节进行签名.需要做一些准备工作将`message`编码成 [] byte类型,可以参考`auth`模块`message`准备的例子.注意,SDK上面没有实现签名的验证,签名验证被推迟到[`anteHandler`](#antehandler)中进行
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/txbuilder.go#L176-L209
- `CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)`创建一个新的助记符并打印在日志里,但是**并不保存在磁盘上**
- `CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error)` 基于[`bip44 path`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)创建一个新的账户并将其保存在磁盘上.注意私钥在[保存前用密码加密](https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/mintkey/mintkey.go),**永远不会储存未加密的私钥**.在这个方法的上下文中, `account``address` 参数指的是BIP44派生路径的段(例如`0`, `1`, `2`, ...)用于从助记符派生出私钥和公钥(注意:给相同的助记符和 `account`将派生出相同的私钥,给相同的`account`和`address`也会派生出相同的公钥和`Address`).最后注意`CreateAccount` 方法使用在[Tendermint library](https://github.com/tendermint/tendermint/tree/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1)中的`secp256k1` 派生出公私钥和`Address`.总之,这个方法是用来创建用户的钥匙和地址的,并不是共识秘钥,参见[`Addresses`](#addresses) 获取更多信息
`dbKeybase`的实现是最基本的,并没有根据需求提供锁定功能.锁定功能指如果一个`dbKeybase`实例被创建,底层的`db`就被锁定意味着除了实例化它的程序其他程序无法访问它.这就是SDK程序使用另外一套`Keybase` 接口的实现`lazyKeybase`的原因
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/lazy_keybase.go
`lazyKeybase`是`dbKeybase`的一个简单包装,它仅在要执行操作时锁定数据库,并在之后立即将其解锁。使用`lazyKeybase`[命令行界面](../interfaces/cli.md)可以在 [rest server](../interfaces/rest.md)运行时创建新的账户,它也可以同时传递多个CLI命令
## 地址和公钥
`Addresses` 和`PubKey`在程序里面都是标识一个参与者的公共信息.Cosmos SDK默认提供3中类型的`Addresses`和`PubKey`
- 基于用户的`Addresses` 和`PubKey`,用于指定用户(例如`message`的发送者).它们通过 **`secp256k1`**曲线推导出来
- 基于验证节点的`Addresses` 和`PubKey`用于指定验证者的操作员,它们通过 **`secp256k1`**曲线推导出来
- 基于共识节点的`Addresses` 和`PubKey`用于指定参与共识的验证着节点,它们通过 **`ed25519`**曲线推导出来
| | Address bech32 Prefix | Pubkey bech32 Prefix | Curve | Address byte length | Pubkey byte length |
|--------------------|-----------------------|----------------------|-------------|---------------------|--------------------|
| Accounts | cosmos | cosmospub | `secp256k1` | `20` | `33` |
| Validator Operator | cosmosvaloper | cosmosvaloperpub | `secp256k1` | `20` | `33` |
| Consensus Nodes | cosmosvalcons | cosmosvalconspub | `ed25519` | `20` | `32` |
### 公钥
在Cosmos SDK里面`PubKey`遵循在 tendermint的`crypto`包中定义的`Pubkey`接口
+++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/crypto.go#L22-L27
对于`secp256k1` 类型的秘钥,具体的实现可以在[这里](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/secp256k1/secp256k1.go#L140)找到.对于`ed25519`类型的密钥,具体实现可以在[这里](https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/ed25519/ed25519.go#L135)找到.
请注意在Cosmos SDK中`Pubkeys`并非以其原始格式进行操作。它使用[`Amino`](../core/encoding.md#amino)和[`bech32`](https://en.bitcoin.it/wiki/Bech32)进行2次编码.在SDK里面,`Pubkeys`首先调用`Bytes()`方法在原始的 `Pubkey`中(这里面提供amino编码),然后使用`bech32`的`ConvertAndEncode` 方法
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L579-L729
### 地址
在Cosmos SDK默认提送3种类型的地址
- `AccAddress` 用于账户
- `ValAddress` 用于验证者操作员
- `ConsAddress` 用于验证着节点
这些地址类型都是一种长度为20的十六进制编码的`[]byte`数组的别名,这里有一种标准方法从`Pubkey pub`中获取到地址`aa`.
```go
aa := sdk.AccAddress(pub.Address().Bytes())
```
这些地址实现了 `Address` 接口
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L71-L80
值得注意的是,`Marhsal()`和`Bytes()`方法都返回相同的`[]byte`类型的地址,根据protobuff的兼容性要求我们需要前者.同样,`String()`也被用来返回`bech32`编码类型的地址,这个应该是用户看到的最终编码形式.下面是一个例子:
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L229-L243
## 接下来 {hide}
学习[gas and fees](./gas-fees.md) {hide}

View File

@ -0,0 +1,241 @@
# SDK应用程序剖析
## Node Client
全节点的核心进程是基于SDK包的。 网络中的参与者运行此过程以初始化其状态机,与其他全节点连接并在新块进入时更新其状态机。
```
^ +-------------------------------+ ^
| | | |
| | State-machine = Application | |
| | | | Built with Cosmos SDK
| | ^ + | |
| +----------- | ABCI | ----------+ v
| | + v | ^
| | | |
Blockchain Node | | Consensus | |
| | | |
| +-------------------------------+ | Tendermint Core
| | | |
| | Networking | |
| | | |
v +-------------------------------+ v
```
区块链全节点以二进制形式表示,通常以`-d`后缀表示`守护程序`(例如,`appd`表示` app`或` gaiad`表示`gaia`)。 这个二进制文件是通过编译一个简单的代码文件 main.go构建的`main.go` 通常位于`./cmd/appd/`中。 此操作通常通过用Makefile编译。
编译了二进制文件,就可以通过运行[`start`命令](https://docs.cosmos.network/master/core/node.html#start-command) 来启动节点。 此命令功能主要执行三件事:
1.[`app.go`] 创建了一个状态机实例。
2.用最新的已知状态初始化状态机,该状态机是从存储在`~/ .appd / data`文件夹中的db中提取的。 此时,状态机的高度为:`appBlockHeight`。
3.创建并启动一个新的Tendermint实例。 该节点将与对等节点进行连接交换信息。 它将从他们那里获取最新的`blockHeight`,如果它大于本地的`appBlockHeight`,则重播块以同步到该高度。 如果`appBlockHeight`为`0`则该节点从创世开始并且Tendermint通过ABCI接口向`app`发送`InitChain`初始化链命令,从而触发[`InitChainer`](https://docs.cosmos.network/master/basics/app-anatomy.html#initchainer)。
## Core Application File
通常,状态机的核心是在名为`app.go`的文件中定义的。 它主要包含“应用程序的类型定义”和“创建和初始化它”的功能。
### Type Definition of the Application
在app.go中重要的一个是应用程序的type。 它通常由以下部分组成:
- 在`app.go`中定义的自定义应用程序是`baseapp`的扩展。 当事务由Tendermint发送到应用程序时`app`使用`baseapp`的方法将它们转送到对应的模块。 baseapp为应用程序实现了大多数核心逻辑包括所有的[ABCI方法](https://tendermint.com/docs/spec/abci/abci.html#overview)和转送消息逻辑。
- 一条key链包含整个状态他是基于 Cosmos SDK 的multistore实现的。 每个模块使用multistore的一个或多个存储来存储其状态。 可以使用在“ app”类型中声明的特定键来访问这些存储。 这些密钥以及`keepers'是Cosmos SDK的 对象功能模型 的核心。
- 模块`keeper`的列表。 每个模块 都会抽象定义一个keeper该keeper 实现模块存储的读写。 一个模块的“ keeper”方法可以从其他模块如果已授权中调用这就是为什么它们在应用程序的类型中声明并作为接口导出到其他模块的原因以便后者只能访问授权的功能。
- 应用程序的`codec`用于序列化和反序列化数据结构以便存储它们,因为存储只能持久化`[]bytes`。 “编解码器”必须是确定性的。 默认编解码器为amino
- 模块管理器是一个对象,其中包含应用程序模块的列表。 它简化了与这些模块相关的操作例如注册routes操作query route操作或设置各种功能的模块之间顺序执行情况例如InitChainer操作BeginBlocke操作和EndBlocker操作
- 请参阅[gaia](https://github.com/cosmos/gaia)中的应用程序类型定义示例
+++ https://github.com/cosmos/gaia/blob/5bc422e6868d04747e50b467e8eeb31ae2fe98a3/app/app.go#L87-L115
### Constructor Function
此函数构造了以上部分中定义的类型的新应用程序。 在应用程的start命令中使用它必须具有AppCreator签名。
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/server/constructors.go#L20
以下是此功能执行的主要操作:
- 创建初始化一个新的codec实例并使用 基础模块管理器初始化每个应用程序模块的`codec`。
- 使用baseapp实例编解码器和所有适当的存储键的引用实例化一个新应用程序。
- 使用每个应用程序模块的`NewKeeper`功能实例化在应用程序的`类型`中定义的所有keeper。 注意所有keeper必须以正确的顺序实例化因为一个模块的NewKeeper可能需要引用另一个模块的`keeper`。
- 使用每个应用模块的AppModule 来实例化应用程序的模块管理器
- 使用模块管理器初始化应用程序的routes和query route。 当事务由Tendermint通过ABCI中继到应用程序时它使用此处定义的路由被路由到相应模块的 回调handler。 同样当应用程序收到查询时使用此处定义的查询路由将其路由到适当的模块的querier。
- 使用模块管理器注册应用程序的模块的invariants。 invariants是在每个块末尾评估的变量例如token的总供应量。 检查不变式的过程是通过InvariantsRegistry 的特殊模块完成的。 invariants应等于模块中定义的预测值。 如果该值与预测的值不同,则将触发不变注册表中定义的特殊逻辑(通常会中断链)。 这对于确保不会发现任何严重错误并产生难以修复的长期影响非常有用。
- 使用模块管理器,在每个应用程序的模块 的InitGenesisBegingBlocker和EndBlocker函数之间设置执行顺序。 请注意,并非所有模块都实现这些功能。
- 模块实现这些功能。
- 设置其余的应用程序参数:
+ `InitChainer`于在应用程序首次启动时对其进行初始化。
+ `BeginBlocker``EndBlocker`:在每个块的开始和结尾处调用。
+ `anteHandler`:用于处理费用和签名验证。
- 挂载存储.
- 返回应用实例.
请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从`〜/ .appd / data`文件夹中保留下来状态加载如果节点是第一次启动则从创世文件生成。See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia):
+++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L110-L222
### InitChainer
InitChainer用于根据创始文件即创始账户的代币余额初始化应用程序的状态。 当应用程序从Tendermint引擎收到`InitChain`消息时调用该消息,该消息是在节点以`appBlockHeight == 0`(即创世)启动。 应用程序必须通过[`SetInitChainer`](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetInitChainer )方法设置其[constructor](https://docs.cosmos.network/master/basics/app-anatomy.html#constructor-function)中的`Initchainer`。
通常,`InitChainer`主要由每个应用程序模块的InitGenesis函数组成。 这是通过调用模块管理器的InitGenesis函数来完成的而模块管理器的InitGenesis函数将依次调用其包含的每个模块的InitGenesis函数。 请注意必须使用模块管理器的SetOrderInitGenesis方法设置模块的InitGenesis函数的顺序。 这是在 应用程序的构造函数 application-constructor 中完成的必须在SetInitChainer之前调用SetOrderInitGenesis。
查看来自[gaia](https://github.com/cosmos/gaia)的InitChainer的示例
See an example of an `InitChainer` from [`gaia`](https://github.com/cosmos/gaia):
查看来自[`gaia`](https://github.com/cosmos/gaia)的`InitChainer`的示例:
+++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L235-L239
### BeginBlocker and EndBlocker
该SDK为开发人员提供了在其应用程序中实现自定义代码可能性。 这是通过两个名为“ BeginBlocker”和“ EndBlocker”的函数实现的。 当应用程序分别从Tendermint引擎接收到`BeginBlock`和`EndBlock`消息时,将调用它们,它们分别在每个块的开始和结尾处发生。 应用程序必须通过 [SetBeginBlocker](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp)和[SetEndBlocker](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetEndBlocker)方法在其 constructor中设置`BeginBlocker`和`EndBlocker`。
通常,`BeginBlocker`和`EndBlocker`函数主要由每个应用程序模块的`BeginBlock`和`EndBlock`函数组成。 这是通过调用模块管理器的BeginBlock和EndBlock函数来完成的而后者又会调用其包含的每个模块的BeginBLock和EndBlock函数。 请注意必须分别在模块管理器中使用SetOrderBeginBlock和SetOrderEndBlock方法来设置模块的BegingBlock和EndBlock函数必须调用的顺序。 这是通过应用程序的构造函数中的模块管理器完成的必须调用SetOrderBeginBlock和SetOrderEndBlock方法。 在SetBeginBlocker和SetEndBlocker函数之前。
附带说明,请记住特定于应用程序的区块链是确定性的,这一点很重要。 开发人员必须注意不要在BeginBlocker或EndBlocker中引入不确定性还必须注意不要使它们在计算上过于昂贵因为[gas]不会限制计算代价当调用 BeginBlocker和EndBlocker执行。
请参阅[gaia](https://github.com/cosmos/gaia)中的`BeginBlocker`和`EndBlocker`函数的示例。
+++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L224-L232
### Register Codec
MakeCodec函数是app.go文件的最后一个重要功能。 此函数的目的是使用 RegisterCodec 函数实例化 codec`cdc`例如amino初始化SDK的编解码器以及每个应用程序的模块。
为了注册应用程序的模块,`MakeCodec`函数在`ModuleBasics`上调用`RegisterCodec`。`ModuleBasics`是一个基本管理器,其中列出了应用程序的所有模块。 它在`init()`函数中得到实例化,仅用于注册应用程序模块的非依赖元素(例如编解码器)。 要了解有关基本模块管理器的更多信息,请点击[这里](https://docs.cosmos.network/master/building-modules/module-manager.html#basicmanager)。
请参阅[gaia](https://github.com/cosmos/gaia)中的`MakeCodec`示例:
+++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L64-L70
## Modules
Modules 是SDK应用程序的灵魂。 它们可以被视为状态机中的状态机。 当交易通过ABCI从底层的Tendermint引擎中继到应用程序时它由 baseapp 找到对应的模块以便进行处理。 这种范例使开发人员可以轻松构建复杂的状态机,因为他们所需的大多数模块通常已经存在。 对于开发人员而言构建SDK应用程序所涉及的大部分工作都围绕构建其应用程序尚不存在的自定义模块并将它们与已经存在的模块集成到一个统一的应用程序中。 在应用程序目录中,标准做法是将模块存储在`x/`文件夹中不要与SDK的`x/`文件夹混淆,该文件夹包含已构建的模块)。
### Application Module Interface
模块必须实现Cosmos SDK AppModuleBasic中的[interfaces](https://docs.cosmos.network/master/building-modules/module-manager.html#application-module-interfaces) 和 AppModule。 前者实现了模块的基本非依赖性元素,例如“编解码器”,而后者则处理了大部分模块方法(包括需要引用其他模块的`keeper`的方法)。 `AppModule`和`AppModuleBasic`类型都在名为`module.go`的文件中定义。
AppModule在模块上公开了一组有用的方法这些方法有助于将模块组合成一个一致的应用程序。 这些方法是从模块管理器中调用的,该模块管理应用程序的模块集合。
### Message Types
每个`module`定义[messages](https://docs.cosmos.network/master/building-modules/messages-and-queries.html#messages)接口。 每个`transaction`包含一个或多个`messages`。
当全节点接收到有效的交易块时Tendermint通过[`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx)将每个交易发到应用程序 。 然后,应用程序处理事务:
- 收到交易后,应用程序首先从`[] bytes`反序列化得到。
- 然后,在提取交易中包含的消息之前,它会验证有关交易的一些信息,例如费用支付和签名
- 使用message的Type()方法baseapp可以将其发到对应模块的 回调 handler以便对其进行处理。
- 如果消息已成功处理,则状态将更新。
有关事务生命周期的更多详细信息,请看[这里](./ tx-lifecycle.md)。
模块开发人员在构建自己的模块时会创建自定义消息类型。 通常的做法是在消息的类型声明前加上`Msg`。 例如,消息类型`MsgSend`允许用户传输tokens
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/bank/internal/types/msgs.go#L10-L15
它由`bank`模块的回调`handler`处理,最终会调用`auth`模块来写`keeper`以更新状态。
### Handler
回调`handler` 是指模块的一部分,负责处理`baseapp`传递的`message`消息。 仅当通过ABCI接口的DeliverTx 消息从Tendermint 收到事务时,才执行模块的“处理程序”功能。 如果通过CheckTx仅执行无状态检查和与费用相关的有状态检查。 为了更好地理解`DeliverTx`和`CheckTx`之间的区别以及有状态和无状态检查之间的区别,请看[这里](./ tx-lifecycle.md)。
模块的“处理程序”通常在名为`handler.go`的文件中定义,并包括:
- NewHandler 将消息发到对应的回调“ handler”。 该函数返回一个“ handler”函数此前这个函数在[AppModule`]中注册,以在应用程序的模块管理器中用于初始化应用程序的路由器。 接下来是[nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)的一个例子。
+++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/handler.go#L12-L26
- 模块定义的每种消息类型的处理函数。 开发人员在这些函数中编写消息处理逻辑。 这通常包括进行状态检查以确保消息有效,并调用[`keeper`](https://docs.cosmos.network/master/basics/app-anatomy.html#keeper)的方法来更新状态。
处理程序函数返回结果类型为sdk.Result该结果通知应用程序消息是否已成功处理
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40
### Querier
`Queriers`与`handlers`非常相似,除了它们向状态查询用户而不是处理事务。 最终用户从interface 发起query最终用户会提供`queryRoute`和一些` data`。 然后使用`queryRoute`通过baseapp`的`handleQueryCustom方法查询到正确的应用程序的`querier` 函数
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/abci.go#L395-L453
模块的Querier是在名为querier.go的文件中定义的包括
- NewQuerier将查找到对应query函数。 此函数返回一个“`querier`”函数,此前它在 AppModule中注册以在应用程序的模块管理器中用于初始化应用程序的查询路由器。 请参阅[nameservice demo]https://github.com/cosmos/sdk-tutorials/tree/master/nameservice中的此类切换示例
+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/querier.go#L19-L32
- 对于模块定义的每种需要查询的数据类型,都具有一个查询器功能。 开发人员在这些函数中编写查询处理逻辑。 这通常涉及调用[`keeper`] 的方法来查询状态并将其 序列化为JSON。
### Keeper
[`Keepers`](https://docs.cosmos.network/master/building-modules/keeper.html)是其模块存储器件。 要在模块的存储区中进行读取或写入,必须使用其`keeper`方法之一。 这是由Cosmos SDK的 object-capabilities 模型确保的。 只有持有商店密钥的对象才能访问它,只有模块的`keeper`才应持有该模块商店的密钥。
`Keepers`通常在名为`keeper.go`的文件中定义。 它包含`keeper`的类型定义和方法。
`keeper`类型定义通常包括:
- 多重存储中模块存储的“密钥”。
- 参考**其他模块的`keepers`**。 仅当`keeper`需要访问其他模块的存储(从它们读取或写入)时才需要。
- 对应用程序的“编解码器”的引用。 “ keeper”需要它在存储结构之前序列化处理或在检索它们时将反序列化处理因为存储仅接受“ [] bytes”作为值。
与类型定义一起keeper.go文件的一个重要组成部分是Keeper的构造函数NewKeeper。 该函数实例化上面定义的类型的新`keeper`,并带有`codec`,存储`keys`以及可能引用其他模块的`keeper`作为参数。 从应用程序的构造函数中调用`NewKeeper`函数。 文件的其余部分定义了`keeper`的方法主要是getter和setter。
### Command-Line and REST Interfaces
每个模块都定义了application-interfaces 向用户公开的命令行命令和REST routes。 用户可以创建模块中定义的类型的消息,或查询模块管理的状态的子集。
#### CLI
通常,与模块有关的命令在模块文件夹中名为`client / cli`的文件夹中定义。 CLI将命令分为交易和查询两类分别在`client / cli / tx.go`和`client / cli / query.go`中定义。 这两个命令基于[Cobra Library](https://github.com/spf13/cobra)之上:
- Transactions命令使用户可以生成新的事务以便可以将它们包含在块中并更新状态。 应该为模块中定义的每个消息类型message-types创建一个命令。 该命令使用户提供的参数调用消息的构造函数,并将其包装到事务中。 SDK处理签名和其他事务元数据的添加。
- 用户可以查询模块定义的状态子集。 查询命令将查询转发到应用程序的查询路由器,然后将查询路由到提供的`queryRoute`参数的相应 querier。
#### REST
模块的REST接口允许用户生成事务并通过对应用程序的 light client daemonLCD 查询状态。 REST路由在`client / rest / rest.go`文件中定义,该文件包括:
- `RegisterRoutes`函数,用于注册路由。 从主应用程序的接口 application-interfaces 中为应用程序内使用的每个模块调用此函数。 SDK中使用的路由器是 [Gorilla's mux](https://github.com/gorilla/mux)。
- 需要公开的每个查询或事务创建功能的自定义请求类型定义。 这些自定义请求类型基于Cosmos SDK的基本“请求”类型构建
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/rest/rest.go#L47-L60
- 每个请求的一个处理函数可以找到给定的模块。 这些功能实现了服务请求所需的核心逻辑。
## Application Interface
Interfaces允许用户与全节点客户端进行交互。 这意味着从全节点查询数据,或者接受全节点中包含在块中的新事务。
通过汇总在应用程序使用的每个模块中定义的 CLI命令构建SDK应用程序的CLI。 应用程序的CLI通常具有后缀-cli例如appcli并在名为`cmd / appcli / main.go`的文件中定义。 该文件包含:
- main()函数用于构建appcli接口客户端。这个函数准备每个命令并在构建它们之前将它们添加到`rootCmd`中。在appCli的根部该函数添加了通用命令例如statuskeys和config查询命令tx命令和rest-server。
- 查询命令是通过调用`queryCmd`函数添加的该函数也在appcli / main.go中定义。此函数返回一个Cobra命令其中包含在每个应用程序模块中定义的查询命令从`main()`函数作为`sdk.ModuleClients`数组传递以及一些其他较低级别的查询命令例如阻止或验证器查询。查询命令通过使用CLI的命令“ appcli query [query]”来调用。
- 通过调用`txCmd`函数来添加**交易命令**。与`queryCmd`类似该函数返回一个Cobra命令其中包含在每个应用程序模块中定义的tx命令以及较低级别的tx命令例如事务签名或广播。使用CLI的命令`appcli tx [tx]`调用Tx命令。
- registerRoutes函数在初始化 轻客户端LCD时从main()函数调用。 “ registerRoutes”调用应用程序每个模块的“ RegisterRoutes”功能从而注册该模块routes 到LCD的查询路由。可以通过运行以下命令“ appcli rest-server”来启动LCD。
从[nameservice demo](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)中查看应用程序的主要命令行文件的示例。
+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/cmd/nscli/main.go
## Dependencies and Makefile
因为开发人员可以自由选择其依赖项管理器和项目构建方法。 也就是说,当前最常用的版本控制框架是[`go.mod`](https://github.com/golang/go/wiki/Modules)。 它确保在整个应用程序中使用的每个库都以正确的版本导入。 请参阅[demo](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice)中的示例:
+++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/go.mod#L1-L18
为了构建应用程序,通常使用[Makefile](https://en.wikipedia.org/wiki/Makefile)。 Makefile主要确保在构建应用程序的两个入口点[`appd`](https://docs.cosmos.network/master/basics/app-anatomy.html#node-client)和[`appcli`](https://docs.cosmos.network/master/basics/app-anatomy.html#application-interface)之前运行`go.mod`。 请参阅 nameservice demo 中的Makefile示例
+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/Makefile
## Next
了解有关[交易生命周期](./ tx-lifecycle.md)的更多信息

View File

@ -0,0 +1,80 @@
**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/gas-fees.md**
# Gas and Fees
## 必备阅读 {hide}
- [一个SDK程序的剖析](./app-anatomy.md) {prereq}
## `Gas` and `Fees`的介绍
在Cosmos SDK中,`gas`是一种特殊的单位,用于跟踪执行期间的资源消耗.每当对储存进行读写操作的时候会消耗`gas`,如果要进行比较复杂的计算的话也会消耗`gas`.它主要有两个目的:
- 确保区块不会消耗太多资源而且能顺利完成.这个默认在SDK的 [block gas meter](#block-gas-meter)中保证
- 防止来自终端用户的垃圾邮件和滥用.为此,通常会为[`message`](../building-modules/messages-and-queries.md#messages)执行期间的消耗进行定价,并产生`fee` (`fees = gas * gas-prices`).`fees` 通常必须由`message`的发送者来支付.请注意,SDK并没有强制执行对`gas`定价,因为可能会有其他的方法来防止垃圾邮件(例如带宽方案).尽管如此,大多数应用程序仍然会使用`fee` 方式来防止垃圾邮件.这个机制通过[`AnteHandler`](#antehandler)来完成.
## Gas Meter
在Cosmos SDK中`gas`是一种简单的`uint64`类型,被称之为*gas meter*的对象进行管理,Gas meters 实现了`GasMeter`接口
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L31-L39
这里:
- `GasConsumed()`返回`GasMeter`实例中消耗的`gas`的数量
- `GasConsumedToLimit()` 返回`GasMeter`实例消耗的gas数量,如果达到上限的话就返回上限
- `Limit()`返回`GasMeter`实例的上限,如果是0则表示对`gas`的数量没有限制
- `ConsumeGas(amount Gas, descriptor string)` 消耗提供的`gas`,如果`gas`溢出了,使用`descriptor`内容进行报错,如果`gas`并不是无限的,则超过限制就会报错.
- `IsPastLimit()` 如果`gas`消耗超过了`GasMeter`的限制则返回`true`,其它返回`false`
- `IsOutOfGas()` 如果`gas`消耗大于或等于了`GasMeter`的限制则返回`true`,其它返回`false`
`GasMeter`通常保存在[`ctx`](../core/context.md)中,`gas`消耗的方式如下:
```go
ctx.GasMeter().ConsumeGas(amount, "description")
```
通常,Cosmos SDK使用两种不同的 `GasMeter`, [main gas meter](#main-gas-metter[)和 [block gas meter](#block-gas-meter).
### 主 Gas Meter
`ctx.GasMeter()` 是应用程序的主 `GasMeter`,主 `GasMeter`通过`BeginBlock`中的`setDeliverState`进行初始化,然后跟踪导致状态转换的执行序列中的`gas`消耗.也即是说它的更新由[`BeginBlock`](../core/baseapp.md#beginblock), [`DeliverTx`](../core/baseapp.md#delivertx)和[`EndBlock`](../core/baseapp.md#endblock)进行操作.主 `GasMeter`必须在 [`AnteHandler`](#antehandler)中**设置为0**,以便它能获取每个transaction的Gas消耗
`gas`消耗可以手工完成,模块开发者通常在 [`BeginBlocker`, `EndBlocker`](../building-modules/beginblock-endblock.md)或者 [`handler`](../building-modules/handler.md)上执行,但大多数情况下,只要对储存区进行了读写,它就会自动完成.这种自动消耗的逻辑在[`GasKv`](../core/store.md#gaskv-store)中完成.
### 块 Gas Meter
`ctx.BlockGasMeter()` 是跟踪每个区块`gas`消耗并保证它没有超过限制的`GasMeter`.每当[`BeginBlock`](../core/baseapp.md#beginblock)被调用的时候一个新的 `BlockGasMeter`实例将会被创建. `BlockGasMeter`的`gas`是有限的,每个块的`gas`限制应该在应用程序的共识参数中定义,Cosmos SDK应用程序使用Tendermint提供的默认共识参数
+++ https://github.com/tendermint/tendermint/blob/f323c80cb3b78e123ea6238c8e136a30ff749ccc/types/params.go#L65-L72
当通过`DeliverTx`处理新的[transaction](../core/transactions.md)的时候,`BlockGasMeter`的当前值会被校验是否超过上限,如果超过上限,`DeliverTx` 直接返回,由于`BeginBlock`会消耗`gas`,这种情况可能会在第一个`transaction`到来时发生,如果没有发生这种情况,`transaction`将会被正常的执行.在`DeliverTx`的最后,`ctx.BlockGasMeter()`会追踪`gas`消耗并将它增加到处理`transaction`的`gas`消耗中.
```go
ctx.BlockGasMeter().ConsumeGas(
ctx.GasMeter().GasConsumedToLimit(),
"block gas meter",
)
```
## AnteHandler
`AnteHandler`是一个特殊的处理程序,它在`CheckTx` 和 `DeliverTx`期间为每一个`transaction`的每个`message`处理之前执行.`AnteHandler`相比`handler`有不同的签名:
```go
// AnteHandler authenticates transactions, before their internal messages are handled.
// If newCtx.IsZero(), ctx is used instead.
type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, result Result, abort bool)
```
`AnteHandler`不是在核心SDK中实现的,而是在每一个模块中实现的,这使开发者可以使用适合其程序需求的`AnteHandler`版本,也就是说当前大多数应用程序都使用 [`auth` module](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth)中定义的默认实现.下面是`AnteHandler`在普通Cosmos SDK程序中的作用:
- 验证事务的类型正确。 事务类型在实现`anteHandler`的模块中定义,它们遵循事务接口:
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L33-L41
这使开发人员可以使用各种类型的应用程序进行交易。 在默认的auth模块中标准事务类型为StdTx
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L22-L29
- 验证交易中包含的每个[`message`](../building-modules/messages-and-queries.md#messages)的签名,每个`message`应该由一个或多个发送者签名,这些签名必须在`anteHandler`中进行验证.
- 在`CheckTx`期间,验证`transaction`提供的 `gas prices`是否大于本地配置`min-gas-prices`(提醒一下,`gas-prices`可以从以下等式中扣除`fees = gas * gas-prices` )`min-gas-prices`是每个独立节点的本地配置,在`CheckTx`期间用于丢弃未提供最低费用的交易.这确保了内存池不会被垃圾交易填充.
- 设置 `newCtx.GasMeter` 到0,限制为`GasWanted`.**这一步骤非常重要**,因为它不仅确保交易不会消耗无限的天然气,而且还会在每个`DeliverTx`重置`ctx.GasMeter`(每次 `DeliverTx` 被调用的时候都会执行`anteHandler`,`anteHandler`运行之后`ctx`将会被设置为`newCtx`)
如上所述,`anteHandler`返回`transaction`执行期间所能消耗的最大的`gas`数量,称之为`GasWanted`.最后实际`gas`消耗数量记为`GasUsed`,因此我们必须使`GasUsed =< GasWanted`.当返回时`GasWanted` `GasUsed`都会被中继到共识引擎中.

View File

@ -0,0 +1,163 @@
# Transaction的生命周期
本文档描述了Transaction从创建到提交的生命周期Transaction的定义在[其他文档](https://docs.cosmos.network/master/core/transactions.html)中有详细描述后文中Transaction将统一被称为`Tx`。
## 创建
### Transaction的创建
命令行界面是主要的应用程序界面之一,`Tx`可以由用户输入[以下命令](https://docs.cosmos.network/master/interfaces/cli.html)来创建,其中`[command]`是`Tx`的类型,`[args]`是相关参数,`[flags]`是相关配置例如gas price
```bash
[appname] tx [command] [args] [flags]
```
此命令将自动**创建**`Tx`,使用帐户的私钥对其进行**签名**,并将其**广播**到其他节点。
创建`Tx`有一些必需的和可选的参数,其中`--from`指定该`Tx`的发起[账户](https://docs.cosmos.network/master/basics/accounts.html),例如一个发送代币的`Tx`,则将从 `from`指定的账户提取资产。
#### Gas 和 Fee
此外,用户可以使用这几个[参数](https://docs.cosmos.network/master/interfaces/cli.html)来表明他们愿意支付多少[fee](https://docs.cosmos.network/master/basics/gas-fees.html)
* `--gas` 指的是[gas](https://docs.cosmos.network/master/basics/gas-fees.html)的数量gas代表`Tx`消耗的计算资源需要消耗多少gas取决于具体的`Tx`,在`Tx`执行之前无法被精确计算出来,但可以通过在`--gas`后带上参数`auto`来进行估算。
* `--gas-adjustment`(可选)可用于适当的增加 `gas` ,以避免其被低估。例如,用户可以将`gas-adjustment`设为1.5那么被指定的gas将是被估算gas的1.5倍。
* `--gas-prices` 指定用户愿意为每单位gas支付多少fee可以是一种或多种代币。例如`--gas-prices=0.025uatom, 0.025upho`就表明用户愿意为每单位的gas支付0.025uatom 和 0.025upho。
* `--fees` 指定用户总共愿意支付的fee。
所支付fee的最终价值等于gas的数量乘以gas的价格。换句话说`fees = ceil(gas * gasPrices)`。由于可以使用gas价格来计算fee也可以使用fee来计算gas价格因此用户仅指定两者之一即可。
随后,验证者通过将给定的或计算出的`gas-prices`与他们本地的`min-gas-prices`进行比较,来决定是否在其区块中写入该`Tx`。如果`gas-prices`不够高,该`Tx`将被拒绝因此鼓励用户支付更多fee。
#### CLI 示例
应用程序的用户可以在其CLI中输入以下命令用来生成一个将1000uatom从`senderAddress`发送到 `recipientAddress`的`Tx`该命令指定了用户愿意支付的gas其中gas数量为自动估算的1.5倍每单位gas价格为0.025uatom)。
```bash
appcli tx send <recipientAddress> 1000uatom --from <senderAddress> --gas auto --gas-adjustment 1.5 --gas-prices 0.025uatom
```
#### 其他的Transaction创建方法
命令行是与应用程序进行交互的一种简便方法,但是`Tx`也可以使用[REST interface](https://docs.cosmos.network/master/interfaces/rest.html)或应用程序开发人员定义的某些其他入口点来创建命令行。从用户的角度来看,交互方式取决于他们正在使用的是页面还是钱包(例如,`Tx`使用[Lunie.io](https://lunie.io/#/) 创建并使用Ledger Nano S对其进行签名
## 添加到交易池
每个全节点Tendermint节点接收到`Tx`后都会发送一个名为`CheckTx`的[ABCI message](https://tendermint.com/docs/spec/abci/abci.html#messages),用来检查`Tx`的有效性,`CheckTx`会返回`abci.ResponseCheckTx`。
如果`Tx`通过检查,则将其保留在节点的 [**交易池**](https://tendermint.com/docs/tendermint-core/mempool.html#mempool)(每个节点唯一的内存事务池)中等待出块,`Tx`如果被发现无效,诚实的节点将丢弃该`Tx`。在达成共识之前,节点会不断检查传入的`Tx`并将其广播出去。
### 检查的类型
全节点在`CheckTx`期间对`Tx`先执行无状态检查,然后进行有状态检查,目的是尽早识别并拒绝无效`Tx`,以免浪费计算资源。
***无状态检查***不需要知道节点的状态,即轻客户端或脱机节点都可以检查,因此计算开销较小。无状态检查包括确保地址不为空、强制使用非负数、以及定义中指定的其他逻辑。
***状态检查***根据提交的状态验证`Tx`和`Message`。例如,检查相关值是否存在并能够进行交易,账户是否有足够的资产,发送方是否被授权或拥有正确的交易所有权。在任何时刻,由于不同的原因,全节点通常具有应用程序内部状态的[多种版本](https://docs.cosmos.network/master/core/baseapp.html#volatile-states)。例如,节点将在验证`Tx`的过程中执行状态更改,但仍需要最后的提交状态才能响应请求,节点不能使用未提交的状态更改来响应请求。
为了验证`Tx`,全节点调用的`CheckTx`包括无状态检查和有状态检查,进一步的验证将在[`DeliverTx`](#delivertx)阶段的后期进行。其中`CheckTx`从对`Tx`进行解码开始。
### 解码
当`Tx`从应用程序底层的共识引擎如Tendermint被接收时其仍处于`[]byte`[编码](https://docs.cosmos.network/master/core/encoding.html)形式,需要将其解码才能进行操作。随后,[`runTx`](https://docs.cosmos.network/master/core/baseapp.html#runtx-and-runmsgs) 函数会被调用,并以`runTxModeCheck`模式运行,这意味着该函数将运行所有检查,但是会在执行`Message`和写入状态更改之前退出。
### ValidateBasic
[Message](https://docs.cosmos.network/master/core/transactions.html#messages)是由module的开发者实现的`Msg`接口中的一个方法。它应包括基本的**无状态**完整性检查。例如,如果`Message`是要将代币从一个账户发送到另一个账户,则`ValidateBasic`会检查账户是否存在,并确认账户中代币金额为正,但不需要了解状态,例如帐户余额。
### AnteHandler
[`AnteHandler`](https://docs.cosmos.network/master/basics/gas-fees.html#antehandler)是可选的,但每个应用程序都需要定义。`AnteHandler`使用副本为特定的`Tx`执行有限的检查,副本可以使对`Tx`进行状态检查时无需修改最后的提交状态,如果执行失败,还可以还原为原始状态。
例如, [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec)模块的`AnteHandler`检查并增加序列号,检查签名和帐号,并从`Tx`的第一个签名者中扣除费用,这个过程中所有状态更改都使用`checkState`
### Gas
[`Context`](https://docs.cosmos.network/master/core/context.html)相当于`GasMeter`,会计算出在`Tx`的执行过程中多少`gas`已被使用。用户提供的`Tx`所需的`gas`数量称为`GasWanted`。`Tx`在实际执行过程中消耗的`gas`被称为`GasConsumed`,如果`GasConsumed`超过`GasWanted`,将停止执行,并且对状态副本的修改不会被提交。否则,`CheckTx`设置`GasUsed`等于`GasConsumed`并返回结果。在计算完gas和fee后验证器节点检查用户指定的值`gas-prices`是否小于其本地定义的值`min-gas-prices`。
### 丢弃或添加到交易池
如果在`CheckTx`期间有任何失败,`Tx`将被丢弃,并且`Tx`的生命周期结束。如果`CheckTx`成功,则`Tx`将被广播到其他节点,并会被添加到交易池,以便成为待出区块中的候选`Tx`。
**交易池**保存所有全节点可见的`Tx`,全节点会将其最近的`Tx`保留在**交易池缓存**中,作为防止重放攻击的第一道防线。理想情况下,`mempool.cache_size`的大小足以容纳整个交易池中的所有`Tx`。如果交易池缓存太小而无法跟踪所有`Tx``CheckTx`会识别出并拒绝重放的`Tx`。
现有的预防措施包括fee和`序列号` 计数器,用来区分重放`Tx`和相同的`Tx`。如果攻击者尝试向某个节点发送多个相同的`Tx`,则保留交易池缓存的完整节点将拒绝相同的`Tx`,而不是在所有`Tx`上运行`CheckTx` 。如果`Tx`有不同的`序列号`,攻击者会因为需要支付费用而取消攻击。
验证器节点与全节点一样,保留一个交易池以防止重放攻击,但它也用作出块过程中未经验证的交易池。请注意,即使`Tx`在此阶段通过了所有检查,仍然可能会被发现无效,因为`CheckTx`没有完全验证`Tx``CheckTx`实际上并未执行`message`)。
## 写入区块
共识是验证者节点就接受哪些`Tx`达成协议的过程,它是**反复进行**的。每个回合都始于出块节点创建一个包含最近`Tx`的区块,并由验证者节点(具有投票权的特殊全节点)负责达成共识,同意接受该区块或出一个空块。验证者节点执行共识算法,例如[Tendermint BFT](https://tendermint.com/docs/spec/consensus/consensus.html#terms)调用ABCI请求确认`Tx`,从而达成共识。
达成共识的第一步是**区块提案**,共识算法从验证者节点中选择一个出块节点来创建和提议一个区块,用来写入`Tx``Tx`必须在该提议者的交易池中。
## 状态变更
共识的下一步是执行`Tx`以完全验证它们所有的全节点收到出块节点广播的区块并调用ABCI函数[`BeginBlock`](https://docs.cosmos.network/master/basics/app-anatomy.html#beginblocker-and-endblocker)`DeliverTx`,和[`EndBlock`](https://docs.cosmos.network/master/basics/app-anatomy.html#beginblocker-and-endblocker)。全节点在本地运行的每个过程将产生一个明确的结果,因为`message`的状态转换是确定性的,并且`Tx`在提案中有明确的顺序。
```
-----------------------------
|Receive Block Proposal|
-----------------------------
|
v
-----------------------------
| BeginBlock |
-----------------------------
|
v
-----------------------------
| DeliverTx(tx0) |
| DeliverTx(tx1) |
| DeliverTx(tx2) |
| DeliverTx(tx3) |
| . |
| . |
| . |
-----------------------------
|
v
-----------------------------
| EndBlock |
-----------------------------
|
v
-----------------------------
| Consensus |
-----------------------------
|
v
-----------------------------
| Commit |
-----------------------------
```
### DeliverTx
[`baseapp`](https://docs.cosmos.network/master/core/baseapp.html)中定义的ABCI函数`DeliverTx`会执行大部分状态转换,`DeliverTx`会针对共识中确定的顺序,对块中的每个`Tx`按顺序运行。`DeliverTx`几乎和`CheckTx`相同但是会以deliver模式调用[`runTx`](../core/baseapp.md#runtx)函数而不是check模式。全节点不使用`checkState`,而是使用`deliverState`。
* **解码:**由于`DeliverTx`是通过ABCI调用的因此`Tx`会以`[]byte`的形式被接收。节点首先会对`Tx`进行解码,然后在`runTxModeDeliver`中调用`runTx``runTx`除了会执行`CheckTx`中的检查外,还会执行`Tx`和并写入状态的变化。
* **检查:** 全节点会再次调用`validateBasicMsgs`和`AnteHandler`。之所以进行第二次检查,是因为在`Tx`进交易池的过程中,可能没有相同的`Tx`,但恶意出块节点的区块可能包括无效`Tx`。但是这次检查特殊的地方在于, `AnteHandler`不会将`gas-prices`与节点的`min-gas-prices`比较,因为每个节点的`min-gas-prices`可能都不同,这样比较的话可能会产生不确定的结果。
* **路由和Handler** `CheckTx`退出后,`DeliverTx`会继续运行 [`runMsgs`](https://docs.cosmos.network/master/core/baseapp.html#runtx-and-runmsgs) 来执行`Tx`中的每个`Msg`。由于`Tx`可能具有来自不同模块的`message`,因此`baseapp`需要知道哪个模块可以找到适当的`Handler`。因此,`路由`通过[模块管理器](https://docs.cosmos.network/master/building-modules/module-manager.html)来检索路由名称并找到对应的[`Handler`](https://docs.cosmos.network/master/building-modules/handler.html)。
* **Handler**`handler`是用来执行`Tx`中的每个`message`,并且使状态转换到从而保持`deliverTxState`。`handler`在`Msg`的模块中定义,并写入模块中的适当存储区。
* **Gas**在`Tx`被传递的过程中,`GasMeter`是用来记录有多少gas被使用如果执行完成`GasUsed`会被赋值并返回`abci.ResponseDeliverTx`。如果由于`BlockGasMeter` 或者 `GasMeter` 耗尽或其他原因导致执行中断,程序则会报出相应的错误。
如果由于`Tx`无效或`GasMeter`用尽而导致任何状态更改失败,`Tx`的处理将被终止,并且所有状态更改都将还原。区块提案中无效的`Tx`会导致验证者节点拒绝该区块并投票给空块。
### 提交
最后一步是让节点提交区块和状态更改,在重跑了区块中所有的`Tx`之后,验证者节点会验证区块的签名以最终确认它。不是验证者节点的全节点不参与共识(即无法投票),而是接受投票信息以了解是否应提交状态更改。
当收到足够的验证者票数2/3+的加权票数)时,完整的节点将提交一个新的区块,以添加到区块链网络中并最终确定应用程序层中的状态转换。此过程会生成一个新的状态根,用作状态转换的默克尔证明。应用程序使用从[Baseapp](https://docs.cosmos.network/master/core/baseapp.html)继承的ABCI方法[`Commit`](https://docs.cosmos.network/master/core/baseapp.html#commit)`Commit`通过将`deliverState`写入应用程序的内部状态来同步所有的状态转换。提交状态更改后,`checkState`从最近提交的状态重新开始,并将`deliverState`重置为空以保持一致并反映更改。
请注意,并非所有区块都具有相同数量的`Tx`,并且共识可能会导致一个空块。在公共区块链网络中,验证者可能是**拜占庭恶意**的,这可能会阻止将`Tx`提交到区块链中。可能的恶意行为包括出块节点将某个`Tx`排除在区块链之外,或者投票反对某个出块节点。
至此,`Tx`的生命周期结束,节点已验证其有效性,并提交了这些更改。`Tx`本身,以`[]byte`的形式被存储在区块上进入了区块链网络。
## 下一节
了解 [accounts](./accounts.md)

View File

@ -1,31 +1,13 @@
# SDK介绍
# 介绍
## 什么是Cosmos SDK?
此目录包含对cosmos sdk的相关介绍
[Cosmos-SDK](https://github.com/cosmos/cosmos-sdk) 是一个架构,用于构建多资产股权证明(PoS)的区块链比如Cosmos Hub以及权益证明(PoA)的区块链。使用Cosmos SDK构建的区块链通常称为**特定应用区块链**。
1. [概述](./overview.md)
Cosmos SDK的目标是允许开发者从头开始轻松创建原生就能同其他区块链相互操作的自定义区块链。我们设想SDK类似于Ruby-on-Rails框架之上构建应用一样可以很方便在[Tendermint](https://github.com/tendermint/tendermint)之上构建安全的区块链应用。 基于SDK的区块链通过可组合的模块构建出来的大部分模块是开源的并且可供任何开发人员使用。 任何人都可以为Cosmos-SDK 创建一个模块,集成已经构建的模块就像将它们导入到区块链应用程序一样简单。 更重要的是Cosmos SDK是一个基于**能力**capabilities的系统开发人员可以更好地了解模块之间交互的安全性。 要深入了解能力,请跳到[OCAP](./ocap.md)。
2. [基于特定应用的区块链](./why-app-specific.md)
## 什么是特定应用区块链?
3. [应用架构](./sdk-app-architecture.md)
4. [Cosmos SDK设计概述](./sdk-design.md)
今天区块链的一个发展模式是像以太坊这样的虚拟机区块链,开发通常围绕着在现有区块链之上通过智能合约构建一个去中心化的应用程序。 虽然智能合约对于像单用途应用程序如ICO这样的一些场景非常有用但对于构建复杂的去中心化平台往往是不够的。 更一般地说,智能合约在灵活性、主权和性能方面受到限制。
特定应用区块链提供了与虚拟机区块链截然不同的开发模式。 特定应用区块链是一个定制的区块链来服务单个应用程序:开发人员可以自由地做出应用程序运行最佳所需的设计决策。 它们还可以提供更好的主权、安全和性能。
要了解有关特定应用区块链的更多信息,可参考[这里](./why-app-specific.md)。
## 为什么是 Cosmos SDK?
Cosmos SDK 是目前用于构建自定义的特定应用区块链的最先进的框架。 以下是一些你可能需要考虑使用 Cosmos SDK 构建去中心化应用的原因:
* SDK中默认共识引擎是 [Tendermint Core](https://github.com/tendermint/tendermint) 。 Tendermint 是已存在的最成熟也是唯一的的BFT共识引擎。 它被广泛应用于行业被认为是建立股权证明系统POS的黄金标准共识引擎。
* SDK是开源的旨在使其易于从可组合模块中构建区块链。 随着开源SDK模块生态系统的发展使用它构建复杂的去中心化平台将变得越来越容易。
* SDK 受基于能力的安全性启发,及多年来解决区块链状态机的经验。 这使得 Cosmos SDK 成为构建区块链的非常安全的环境。
* 最重要的是Cosmos SDK已经被许多特定应用区块链产品所使用。 如:[Cosmos Hub](https://hub.cosmos.network), [Iris](https://irisnet.org), [Binance Chain](https://docs.binance.org/), [Terra](https://terra.money/) or [Lino](https://lino.network/) 除此之外还有很多建立在Cosmos SDK的项目。 你可以在这里查看[生态系统](https://cosmos.network/ecosystem)。
## 开始使用 Cosmos SDK
* 了解[SDK 应用体系架构](./sdk-app-architecture.md)的详细信息
* 了解如何从头构建特定应用区块链,参考[SDK教程](https://tutorials.cosmos.network/) 。
了解完成相关介绍后,可以前往 [基础文档](../basics/README.md) 了解更多。

33
docs/cn/intro/overview.md Normal file
View File

@ -0,0 +1,33 @@
# Cosmos SDK 介绍
## 什么是Cosmos SDK
[Cosmos SDK](https://github.com/cosmos/cosmos-sdk)是开源框架用于构建类似Cosmos Hub等基于POS共识算法的多元资产公有区块链以及基于权威证明共识算法的许可链。使用Cosmos SDK构建的区块链通常被称为特定应用区块链专用区块链application-specific blockchains
Cosmos SDK的目标是让开发者可以快速地构建一条能与其他区块链以源生的方式进行互操作的可定制区块链。在我们的设想中这套SDK就像Web应用框架一样可以让开发者迅速构建出基于[Tendermint](https://github.com/tendermint/tendermint)算法的安全区块链应用程序。 由Cosmos SDK的区块链由组合式[模块](https://docs.cosmos.network/master/building-modules/intro.html)构建其中大部分模块都是开源的且任何开发者均可使用。任何人都能为Cosmos SDK创建新的模块集成已经构建的模块就像将他们导入你的区块链应用程序一样简单。还有一点Cosmos SDK是基于功能capabilities的系统这允许开发者可以更好地考虑模块之间交互的安全性。更深入地了解功能请跳至[本节](https://docs.cosmos.network/master/core/ocap.html)。
##什么是特定应用区块链
目前在区块链领域中一种开发模式是通过像以太坊这样的虚拟机区块链展开即开发者在现有的区块链上通过智能合约的方式去构建去中心化应用。虽然智能合约在单用途应用场景如ICO下非常有用但在构建复杂的去中心化平台时无法达到要求。更具体地说智能合约在灵活性、所有权、性能方面会受到限制。
特定应用区块链提供了与虚拟机区块链截然不同的开发模式。特定应用区块链是面向单个具体应用程序的高度定制化区块链:开发者可以完全自由地做出让应用程序可以达到最佳运行状态的设计决策。他们也可以提供更好的主导权、安全性和性能。
了解更多可参考[特定应用区块链](https://docs.cosmos.network/master/intro/why-app-specific.html)。
## 为什么选择Cosmos SDK
Cosmos SDK是目前最先进的构建可定制化特定应用区块链的框架。以下是一些可能让你希望通过Cosmos SDK构建去中心化应用的原因
- Cosmos SDK 默认的共识引擎是[Tendermint Core](https://github.com/tendermint/tendermint). Tendermint是目前最成熟的、唯一的BFT共识引擎。它被广泛应用于行业中被认为是构建POS系统的最佳标准共识引擎。
- Cosmos SDK是开源的你可以通过组合式[modules](https://docs.cosmos.network/master/x/)轻松地构建出区块链。随着SDK生态中各种开源模块的发展通过Cosmos SDK构建复杂的去中心化平台会变得越来越容易。
- Cosmos SDK 受基于功能的安全性所启发并受益于多年来在区块链状态机领域的经验。这让Cosmos SDK成为一个非常安全的构建区块链的环境。
- 最重要的是Cosmos SDK已经构建出了多个正在运行中的特定应用区块链。例如Cosmos HUBIRIS HUBBinance Chain, Terra 和 Kava。更多机遇Cosmos SDK构建的区块链参考[这里](https://cosmos.network/ecosystem)。
## 开始使用Cosmos SDK
了解更多请参考[SDK应用架构](https://docs.cosmos.network/master/intro/sdk-app-architecture.html)。
了解如何从头建立特定应用区块链,请参考[SDK教程](https://cosmos.network/docs/tutorial)。

View File

@ -1,12 +1,12 @@
# SDK 应用程序架构
# 区块链架构
## 状态机
区块链应用的核心是[具有最终确定性的复制状态机](https://en.wikipedia.org/wiki/State_machine_replication)。
区块链的核心是[复制确定状态机](https://en.wikipedia.org/wiki/State_machine_replication)replicated deterministic state machine
状态机是计算机科学概念,一台机器可以具有多个状态,但在任何给定时间只有一个`状态`,其描述了系统的当前状态,及触发这些状态转变的交易(译者注:也对应数据库中事务的概念)
状态机是计算机科学领域的一个概念,即一台机器可以具有多个状态,但在任意给定时刻只具有一个确定的状态。我们用`state`描述系统当前状态,`transactions`触发状态转换
给定一个状态S和交易T状态机会返回一个新的状态S'。
给定一个状态S和Transaction T状态机会返回新的状态S'。
```
+--------+ +--------+
@ -16,7 +16,7 @@
+--------+ +--------+
```
实际上交易以区块的形式打包在一起以提高过程的效率。给定状态S和包含交易的区块B状态机将返回新状态S'。
在实际中Transaction集会被打包进区块中以让处理过程更加高效。给定一个状态S和一个包含Transaction集 B的区块状态机就会返回新的状态S'。
```
+--------+ +--------+
@ -26,45 +26,42 @@
+--------+ +--------+
```
在区块链上下文环境中,状态机是确定性的。这意味着如果你从一个给定的状态开始,重放相同顺序的交易,将始终以相同的最终状态结束
在区块链的上下文环境中状态机是确定的。这意味着节点从给定状态开始重放相同的Transaction序列总能得到相同的最终状态
Cosmos SDK 为你提供了最大的灵活性用以定义自身应用程序的状态、交易类型和状态转换函数。在接下来的章节中会更深入细致的描述如何使用 SDK 来构建状态机。但首先,让我们看看状态机是如何使用 **Tendermint** 进行复制的
Cosmos SDK为开发者提供了最大程度的灵活性去定义应用程序的状态Transaction类型和状态转换功能。接下来的章节中会更详细地介绍使用SDK构建状态机的过程。在此之前先让我们看看如何使用Tendermint复制状态机
### Tendermint
## Tendermint
作为一个开发者,你只需要使用 Cosmos-SDK 定义状态机,而[Tendermint](https://tendermint.com/docs/introduction/introduction.html)将会为你处理网络层的状态复制
得益于Cosmos SDK开发者只需要定义好状态机[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html)就会处理好状态复制的工作
```
^ +-------------------------------+ ^
| | | | 通过 Cosmos SDK 构建
| | 状态机 = 应用(层) | |
| | | | Built with Cosmos SDK
| | State-machine = Application | |
| | | v
| +-------------------------------+
| | | ^
链节点 | | 共识层 | |
Blockchain node | | Consensus | |
| | | |
| +-------------------------------+ | Tendermint Core
| | | |
| | 网络层 | |
| | Networking | |
| | | |
v +-------------------------------+ v
```
Tendermint是一个与应用程序无关的引擎负责处理区块链的*网络层*和*共识层*。实际上这意味着Tendermint负责传播和排序交易字节。Tendermint Core 依赖于拜占庭容错BFT算法来达成交易顺序的共识。要深入了解Tendermint可点击[这里](https://tendermint.com/docs/introduction/what-is-tendermint.html)。
Tendermint一致性算法通过一组称为*验证人*的特殊节点一起运作。验证人负责向区块链添加交易区块。对于任何给定的区块有一组验证人V。通过算法选择V中的验证人A作为下一个区块的提议人。如果超过三分之二的V签署了[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#state-machine-spec)和[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#state-machine-spec),并且区块包含的所有交易都是有效的,则该区块被认为是有效的。验证人集合可以通过状态机中编写的规则进行更改。要深入了解算法,[点击](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview)。
Cosmos SDK 应用程序的主要部分是一个区块链服务后台daemon它在每个网络节点的本地运行。如果验证人集合中三分之一以下的是拜占庭即恶意的则每个节点在同时查询状态时应获得相同的结果。
[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html) 是一个与应用程序无关的引擎负责处理区块链的网络层和共识层。这意味着Tendermint负责对Transaction字节进行传播和排序。Tendermint Core 通过同名的拜占庭容错算法来达成Transaction顺序的共识。
Tendermint[共识算法](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview)与一组被称为Validator的特殊节点共同运作。Validator负责向区块链中添加包含transaction的区块。在任何给定的区块中都有一组Validator集合V。算法会从集合V中选出一个Validator作为下一个区块的Proposer。如果一个区块被集合V中超过三分之二的Validator签署了[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)和[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r)且区块中所有Transaction都是有效的则认为该区块有效。Validator集合可以按照状态机中写定的规则更改。
## ABCI
Tendermint通过名为[ABCI](https://github.com/tendermint/tendermint/tree/master/abci)的接口将交易从网络层传递给应用程序,因此应用程序必须要实现 ABCI
Tendermint通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口向应用程序传递Transactions该接口必须由应用程序实现
```
+---------------------+
| |
| 应用 |
| Application |
| |
+--------+---+--------+
^ |
@ -79,17 +76,16 @@ Tendermint通过名为[ABCI](https://github.com/tendermint/tendermint/tree/maste
+---------------------+
```
注意Tendermint 仅处理交易字节。它不知道这些字节究竟是什么意思。Tendermint 所做的只是对交易确定性地排序。赋予这些字节意义是应用程序的工作。Tendermint通过ABCI将交易字节传递给应用程序并期望返回代码以知晓消息是否成功
需要注意的是Tendermint仅处理transaction字节它并不知道这些字节的含义。Tendermint所做的只是对transaction字节进行确定性地排序。Tendermint通过ABCI向应用程序传递字节并期望返回状态码以获知包含在transactions中的messages是否成功处理
以下是ABCI中最重要的消息类型
以下是ABCI最重要的Messages
- `CheckTx` : 当 Tendermint Core 收到交易时,如果符合一些的基本的要求会将其传递给应用程序。`Checkx` 用于保护全节点的交易池免受垃圾邮件的侵害。一个名为“Ante Handler”的特殊处理器用于执行一系列验证步骤例如检查手续费用是否足够和验证签名是否合法。如果交易有效则将交易添加到[交易池mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality)中并广播到对等节点。注意, `CheckTx` 不会处理交易(即不会对修改状态),因为它们尚未包含在区块中。
- `DeliverTx` : 当 Tendermint Core 接收到[有效区块](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation)时,块中的每条交易都将通过 `DeliverTx `传递给应用程序进行处理。正是在这一阶段发生了状态转换。“Ante Handler”也将连同实际处理交易中每条消息的handler一起再次执行。
- `BeginBlock`/`EndBlock` : 无论区块是否包含交易,这两个消息都将在每个区块的开头和结尾执行。触发自动的逻辑执行是很有用的。过程中要足够小心,因为计算成本高昂的循环运算可能会减慢区块链的速度,甚至发生无限循环引起区块链本身停滞。
`CheckTx`当Tendermint Core接收到一个Transaction时它会传递给应用程序以检查是否满足一些基本要求。`CheckTx` 用于保护全节点的内存池免受垃圾transactions攻击。`AnteHandler`这一特殊处理程序用于执行一系列验证步骤例如检查手续费是否足够以及验证签名。如果检查通过该transaction会被添加进[mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality)并广播给其他共识节点。请注意此时transactions尚未被`CheckTx`处理(即未进行状态修改),因为它们还没有被包含在区块中。
`DeliverTx`当Tendermint Core收到一个[有效区块](https://tendermint.com/docs/spec/blockchain/blockchain.html#validation)时区块中的每一个Transaction都会通过`DeliverTx`传递给应用程序以进行处理。状态转换会在这个阶段中发生。`AnteHandler`会与Transaction中每个Message的实际[`handlers`](https://docs.cosmos.network/master/building-modules/handler.html)一起再次执行。
有关 ABCI 方法和类型的详细介绍请[点击](https://tendermint.com/docs/spec/abci/abci.html#overview)
`BeginBlock/EndBlock`无论区块中是否包含transactionmessages都会在每个区块的开头和结尾处执行。触发自动执行的逻辑是很有用的。但需要谨慎使用因为计算量庞大的循环会严重降低区块链的性能而无限循环甚至会导致区块链宕机
在 Tendermint 上构建的任何应用程序都需要实现ABCI接口来同本地的底层 Tendermint 引擎进行通信。幸运的是你不用必需实现ABCI接口。Cosmos SDK以[baseapp](./sdk-design.md#baseapp)的形式提供了样板实现。
获知更多关于ABCI的详细内容可以访问[Tendermint docs](https://tendermint.com/docs/spec/abci/abci.html#overview).
### 接下来,让我们学习[SDK的高级设计原则](./sdk-design.md)
基于Tendermint构建的任何程序都需要实现ABCI接口以便和底层的本地Tendermint引擎通信。幸运的是您不需要实现ABCI接口Cosmos SDK 以 [baseapp](https://docs.cosmos.network/master/intro/sdk-design.html#baseapp) 的形式提供了样板实现。

View File

@ -1,48 +1,74 @@
# Cosmos SDK 设计概览
# Cosmos SDK的主要组件
Cosmos SDK是一个方便开发者开发基于Tendermint的安全可靠状态机的一套框架。其核心是Golang版的ABCI的实现。它附带一个`multistore`来持久化存储数据还有一个`router`来处理交易
Cosmos SDK 是一个框架可以促进基于Tendermint的安全状态机的开发。SDK的核心是一个基于Golang的[ABCI](https://docs.cosmos.network/master/intro/sdk-app-architecture.html#abci)样板实现。它带有一个用于存储数据的[`multistore`](https://docs.cosmos.network/master/core/store.html#multistore)和一个用于处理Transaction的[`router`](https://docs.cosmos.network/master/core/baseapp.html#routing)
下面一个简单的视图展示了当从Tendermint的`DeliverTx`请求(`CheckTx`的处理流程与其相同除了不会执行状态的改变中接收到一笔交易时基于Cosmos SDK构建的应用程序是如何处理交易的
下面的简化视图展示了当通过`DeliverTx`从Tendermint 转移transactions时基于Cosmos SDK构建的应用程序如何处理这些transactions。
1. 解码从Tendermint共识引擎接收到的交易记住Tendermint只处理`[]bytes`
2. 从交易中提取消息并进行基本的合理性检查。
3. 将每条消息路由至对应的模块进行处理。
4. 提交状态变更。
- 解码从Tendermint共识引擎中接收到的`transactions`Tendermint只能处理 `[]bytes` 类型的数据)
应用同样可以生成交易进行编码并传递给底层的Tendermint来进行广播
- 从`transactions`中提取`messages`并进行基本的健全性检查。
## `baseapp`
- 将每个Message路由到对应的模块中以进行相应处理。
`baseApp` 是Cosmos SDK的ABCI的实现样板。里面的 `router` 用来把交易路由到对应的模块。我们应用程序的主体文件`app.go` 将自定义`app`类型,它将嵌入`baseapp`。这样,自定义的`app`类型将自动继承`baseapp`的所有方法。阅览[SDK应用教程](https://github.com/cosmos/sdk-application-tutorial/blob/master/app.go#L27)代码示例
- 提交状态更改
`baseapp`的目的是在存储和可扩展状态机的之间提供安全接口同时尽可能少地定义该状态机保持对ABCI的真实性
## BaseApp
有关`baseapp`的更多信息,请点击[这里](../concepts/baseapp.md)。
`baseapp` 是 Cosmos SDK 应用程序的样本实现它拥有能够处理和底层共识引擎的连接的ABCI实现。通常Cosmos SDK 应用程序通过嵌入[`app.go`](https://docs.cosmos.network/master/basics/app-anatomy.html#core-application-file)来实现拓展。查看示例请参考SDK应用教程
```go
type nameServiceApp struct {
*bam.BaseApp
cdc *codec.Codec
// keys to access the substores
keys map[string]*sdk.KVStoreKey
tkeys map[string]*sdk.TransientStoreKey
// Keepers
accountKeeper auth.AccountKeeper
bankKeeper bank.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
distrKeeper distr.Keeper
supplyKeeper supply.Keeper
paramsKeeper params.Keeper
nsKeeper nameservice.Keeper
// Module Manager
mm *module.Manager
}
```
`baseapp` 的目标是在存储和可拓展状态机之间提供安全的接口同时尽可能少地定义状态机对ABCI保持不变
更多关于`baseapp`的信息,请点击[这里](https://docs.cosmos.network/master/core/baseapp.html)。
## Multistore
Cosmos SDK 为状态持久化提供了 multistore 。multistore 允许开发者声明任意数量的[`KVStores`](https://github.com/blocklayerhq/chainkit)。`KVStores`只接受`[]byte`类型作为值,因此任何自定义的类型都需要在存储之前使用[go-amino](https://github.com/tendermint/go-amino)进行编码。
Cosmos SDK 为状态持久化提供了`multistore`。Multistore允许开发者声明任意数量的`KVStores`。这些`KVStores`只接受`[]byte`类型的值,因此任何自定义的结构都需要在存储之前使用[codec](https://docs.cosmos.network/master/core/encoding.html)进行编码。
multistore 抽象用于区分不同的模块的状态,每个都由其自身模块管理。要了解更多关于 multistore 的信息,点击[这里](../concepts/store.md)
Multistore抽象用于区分不同模块的状态每个都由其自己的模块管理。更多关于multistore的信息请点击[这里](https://docs.cosmos.network/master/core/store.html#multistore)。
## Modules
Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过把一组可以互相操作的模块组合起来进行构建。每个模块定义状态子集,并包含其自己的消息/交易处理器而SDK负责将每条消息路由到其各自归属的模块。
Cosmos SDK的强大之处在于其模块化开发的理念。SDK应用程序是通过组合一系列可互操作的模块而构建的。每个模块定义了状态子集并包含其Messages与Transactions的处理器同时SDK负责将每个Message路由到对应的模块中
下面是一个简化视图, 旨在说明每个应用链的全节点是如何处理接收的有效块中交易的:
以下的简化视图展示了应用链中的每个全节点如何处理有效区块中的Transaction。
```
+
|
| 交易通过全节点的 Tendermint 引擎的DeliverTx
| 传递到应用层
| Transaction relayed from the full-node's Tendermint engine
| to the node's application via DeliverTx
|
|
|
+---------------------v--------------------------+
| 应用(层) |
| APPLICATION |
| |
| 用 baseapp 的方法: 解码 Tx, |
| 提取及路由消息 |
| Using baseapp's methods: Decode the Tx, |
| extract and route the message(s) |
| |
+---------------------+--------------------------+
|
@ -52,15 +78,16 @@ Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过
|
|
|
| 消息传给相应的模块处理
| Message routed to the correct
| module to be processed
|
|
+----------------+ +---------------+ +----------------+ +------v----------+
| | | | | | | |
| AUTH MODULE | | BANK MODULE | | STAKING MODULE | | GOV MODULE |
| | | | | | | |
| | | | | | | 处理消息, 更改状态 |
| | | | | | | |
| | | | | | | Handles message,|
| | | | | | | Updates state |
| | | | | | | |
+----------------+ +---------------+ +----------------+ +------+----------+
|
@ -69,18 +96,19 @@ Cosmos SDK 的强大之处在于其模块化开发的理念。应用程序通过
|
+--------------------------+
|
| 返回结果到 Tendermint
| Return result to Tendermint
| (0=Ok, 1=Err)
v
```
每个模块都可以看做一个小型的状态机。开发人员需要定义模块所处理的状态的子集以及修改状态的message自定义类型(*注意* : message 是由 `baseapp` 的方法从交易中提取的)。通常,每个模块在 multistore 声明它自己的`KVStore` 来持久化保存它所定义的状态子集。大多数开发者在构建自己的模块时也需要访问其他的第三方模块。鉴于Cosmos-SDK是一个开源的框架一些模块可能是恶意的这就意味着需要安全原则来合理化模块之间的交互。这些原则基于[object-capabilities](./ocap.md)。实际上,这意味着不是让每个模块保留其他模块的访问控制列表,而是每个模块都实现称作`keeper`的特殊对象,这些对象可以传递给其他模块并授予预先定义的一组能力
每个模块都可以看成是一个小的状态机。开发者需要定义由模块处理的状态子集同时自定义改变状态的Message类型注意`messages`是通过`baseapp`从`transactions`中提取的)。通常,每个模块会在`multistore`中声明自己的`KVStore`以存储自定义的状态子集。大部分开发者在构建自己的模块时需要访问其它第三方模块。由于Cosmos SDK是一个开放的框架其中的一些模块可能是恶意的这意味着需要一套安全原则去考虑模块间的交互。这些原则都基于[object-capabilities](https://docs.cosmos.network/master/core/ocap.html)。事实上,这也意味着,并不是要让每个模块都保留其他模块的访问控制列表,而是每个模块都实现了被称为`keepers`的特殊对象,它们可以被传递给其他模块,以授予一组预定义的功能
SDK模块在SDK的`x/`目录下定义。一些核心模块包括:
+ `x/auth`: 用于管理账户和签名.
+ `x/bank`: 用于实现token和token转账.
+ `x/staking` + `x/slashing`: 用于构建POS区块链.
SDK模块被定义在SDK的 `x/`文件夹中,一些核心的模块包括:
除了`x/`中已有的模块,任何人都可以在他们的应用程序中使用它们自己定义的模块。你可以查看[示例教程](https://learnblockchain.cn/docs/cosmos/tutorial/04-keeper.html)
- `x/auth`:用于管理账户和签名。
### 接下来 学习 Cosmos SDK 安全模型,[ocap](./ocap.md)
- `x/bank`:用于启动 tokens 和 token 转账。
- `x/staking` + `s/slashing`用于构建POS区块链。
除了`x/`文件夹中已经存在的任何人都可以使用的模块SDK还允许您构建自己自定义的模块您可以在[教程中查看示例](https://cosmos.network/docs/tutorial/keeper.html)。

View File

@ -0,0 +1,87 @@
# 特定应用区块链
## 概要
本文档解释了什么是特定应用区块链,以及为什么开发者更希望构建特定应用区块链,而不是开发智能合约。
## 什么是特定应用区块链?
特定应用区块链是面向单个具体应用程序的高度定制化区块链。与基于像以太坊这样的底层区块链搭建去中心化应用不同开发者需要从头构建他们自己的区块链。这意味着构建全节点客户端、轻节点客户端和所有必要的接口CLI, REST, 等等)来和节点交互。
```
^ +-------------------------------+ ^
| | | | Built with Cosmos SDK
| | State-machine = Application | |
| | | v
| +-------------------------------+
| | | ^
Blockchain node | | Consensus | |
| | | |
| +-------------------------------+ | Tendermint Core
| | | |
| | Networking | |
| | | |
v +-------------------------------+ v
```
## 智能合约的局限是什么?
早在2014年像Ethereum这样的虚拟机区块链就满足了可编程性的需求。当时开发去中心化应用的选项非常有限。许多开发者只能在复杂且有限制的比特币脚本语言上开发或者fork难以运行和定制化的比特币代码。
虚拟机区块链在当时提出了新的价值主张。他们的状态机集成了虚拟机从而能够执行被称为智能合约的图灵完备程序。虽然智能合约在一次性事件如ICO的应用场景下非常有用但在构建复杂的去中心化平台时无法达到要求。以下是原因
智能合约通常由可以被底层虚拟机解释的特定编程语言开发。这些编程语言常常并不成熟并受限于虚拟机本身。例如以太坊虚拟机并不允许开发者实现代码的自动执行。开发或者也被限制于EVM的账户体系他们只能从一组有限的功能中进行加密操作。虽然这些只是示例但它们展现了智能合约环境通常缺少灵活性。
智能合约都运行在同一台虚拟机上,这意味着它们会相互争夺资源,并严重影响执行效果。即使状态机分分成多个子集(例如通过分片技术),智能合约依然需要由虚拟机解释,比起在状态机上实现的本地应用程序,这依然限制了合约应用的性能。( 我们的基准测试表明在删除虚拟机后应用程序的性能提高了10倍。
智能合约共享底层环境带来的另一个问题是主导权的最终限制。去中心化应用是一个涉及众多参与者的生态系统如果去中心化应用建立在通用的虚拟机区块链上利益相关者stakeholders对他们的应用程序就只有非常有限的主导权并最终会被底层区块链的治理所取代。如果该应用程序还存在着漏洞那任何人都无能为力。
特定应用区块链的出现,就是要解决上述问题。
## 特定应用区块链的优势
### 灵活性
特定应用区块链赋予了开发者最大的灵活性:
- 在Cosmos区块链中状态机通常通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口和底层共识引擎连接。该接口可以被包装为任何编程语言,开发者可以自己决定用哪种编程语言来构建状态机。
- 开发者在构建状态机时有多种选择目前最常用的是Cosmos SDK但也有其他的框架如Lotion和Weave等。开发者通常都是基于他们使用的编程语言来选择使用哪一种框架Cosmos SDK和Weave基于GolangLotion则基于JavaScript
- ABCI允许开发者更换特定应用链的共识引擎。目前只有Tendermint共识可以投入使用但在未来还会有更多共识引擎可被使用。
- 即使已经选好了开发框架和共识引擎,但如果他们不能完全符合原始格式的要求,开发者依然可以对其进行调整。
- 开发者可以自由探索出最能满足实际需求的方案(如验证人数量 vs Transaction吞吐量安全性 vs 异步可用性等和链的设计选项如DB存储或IAVL树UTXO或账户模型
- 开发者可以实现代码的自动执行。在Cosmos SDK 中,每个块的开头和结尾都可以自动触发逻辑。与虚拟机区块链环境下的合约开发者不同,特定应用区块链的开发者可以自由地选择应用程序所需要的加密库,而不会受到底层环境的功能限制。
上述的列表展示了特定应用区块链给予开发者的充分灵活性。Cosmos 和 Cosmos SDK 的目标是让开发者工具尽可能的通用化、模块化,从而在保持兼容的情况下对堆栈的每个部分进行分叉、调整和优化。随着社区的不断发展,每个核心构建模块都将有更多可替代方案,为开发者提供更多选项。
### 性能
基于智能合约的去中心化应用在性能方面会天然地受到底层环境的限制。如果一个去中心化应用要进行性能优化,就需要将其构建为特定应用区块链。以下是特定应用区块链在性能方面的优势:
- 特定应用区块链开发者可以选择像 Tendermint BFT 这样的新型共识引擎。与目前被大多数虚拟机区块链使用的POW共识相比Tendermint BFT 在吞吐量方面有显著提高。
- 一个特定应用区块链只运行单个应用程序,所以该应用程序不需要和其他程序去竞争计算资源和存储资源。这与目前所有非分片虚拟机区块链正好相反,在这些区块链中的智能合约都会争夺计算和存储资源。
- 即使某种虚拟机区块链能够提供基于应用程序的分片和高效的共识算法其性能也依然会被虚拟机本身所限制。真正的吞吐量瓶颈在于状态机要求Transaction由虚拟机解释会大大增加处理它们的计算复杂度。
###安全性
安全性很难进行量化,而且不同区块链平台之间存在很大差异。以下是特定应用区块链所能带来的重要优势:
- 与不成熟的智能合约编程语言相反开发者可以在构建特定应用区块链时选择像Golang这种可靠性已被验证的编程语言。
- 开发者不会局限于底层虚拟机所提供的加密功能,他们可以使用自定义的加密技术,也可以依赖经过可靠审核的加密库。
- 开发者无需担心底层虚拟机中潜在的漏洞或可被利用的机制,从而可以更容易地确保应用程序的安全性。
### 主导权
特定应用区块链的一大好处是主导权。去中心化应用是一个涉及众多参与者的生态系统如用户、开发者、第三方服务等等。当开发者在多个去中心化应用共存的虚拟机区块链上开发应用程序时出现的一个问题是围绕应用程序所组成的社区人群和底层链的社区人群并不是一样的但后者却会在治理的过程中取代前者。如果应用程序中存在一个漏洞或者需要上线新的功能应用的stakeholders几乎没有任何办法升级代码。如果底层区块链社区拒绝执行那应用程序就无法升级。
根本问题是应用程序的治理和网络治理并不是统一的而这个问题可以通过特定应用区块链解决。因为特定应用区块链只专门运行单个应用程序所以应用的stakeholders对整条链有完全的主导权。这能确保社区在漏洞被发现时不会卡住而且有充分的自由去选择链和应用程序的演化方向。