Update cn document (#6753)
* Formatting documents * Fixing typos * Update the intro document to the latest version Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
10783f27d0
commit
f208b9b9fe
|
@ -7,30 +7,25 @@ parent:
|
|||
|
||||
## 开始
|
||||
|
||||
- **[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 的基本原理。
|
||||
|
||||
|
||||
- **[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`等
|
||||
- **[基础文档](./basics/)**:cosmos sdk 的基础概念文档,例如应用结构、交易的生命周期、账户管理等
|
||||
- **[核心文档](./core/)**: cosmos sdk 的核心文档,例如`baseapp`,`store`,`server`等
|
||||
- **[构建模块](./building-modules/)**: 对于模块开发者来说的一些重要概念,例如`message`,`keeper`,`handler`,`querier`
|
||||
- **[接口](./interfaces/)**: 为cosmos应用设计接口的文档
|
||||
|
||||
|
||||
- **[接口](./interfaces/)**: 为 cosmos 应用设计接口的文档
|
||||
|
||||
## 开发资源
|
||||
|
||||
- **[模块目录](../../x/)**: 模块的实现和文档
|
||||
|
||||
- **[规范](./spec/):** Cosmos SDK 的模块及其他规范。
|
||||
- **[模块目录](../../x/)**:模块的实现和文档
|
||||
- **[规范](./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
|
||||
## Cosmos Hub
|
||||
|
||||
Cosmos Hub (名为 `gaia`) 文档已经迁移到[这里](https://github.com/cosmos/gaia/tree/master/docs).
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# 基础文档
|
||||
|
||||
此目录包含对cosmos sdk的基础概念介绍
|
||||
此目录包含对 cosmos sdk 的基础概念介绍
|
||||
|
||||
1. [SDK应用解析](./app-anatomy.md)
|
||||
1. [SDK 应用解析](./app-anatomy.md)
|
||||
2. [交易的生命周期](./tx-lifecycle.md)
|
||||
3. [账户系统](./accounts.md)
|
||||
4. [Gas 和 Fees](./gas-fees.md)
|
||||
|
||||
阅读完基础文档后,可以阅读 [核心文档](../core/README.md) 进一步加深对cosmos的理解。
|
||||
阅读完基础文档后,可以阅读 [核心文档](../core/README.md) 进一步加深对 cosmos 的理解。
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/accounts.md**
|
||||
|
||||
|
||||
# 账户系统
|
||||
|
||||
# 必备阅读 {hide}
|
||||
|
||||
- [一个SDK程序的剖析](./app-anatomy.md) {prereq}
|
||||
- [一个 SDK 程序的剖析](./app-anatomy.md) {prereq}
|
||||
|
||||
## 账户定义
|
||||
|
||||
在Cosmos SDK中,一个账户是指定的一个公私钥对.公钥可以用于派生出`Addresses`,`Addresses`可以在程序里面的各个模块间区分不同的用户.`Addresses`同样可以和[消息](../building-modules/messages-and-queries.md#messages)进行关联用于确定发消息的账户.私钥一般用于生成签名来证明一个消息是被一个`Addresses`(和私钥关联的`Addresses`)所发送.
|
||||
在 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个字的助记符.使用这个助记符,使用一种单向的加密方法可以派生出任意数量的私钥.公钥可以通过私钥推导出来.当然,助记符是最敏感的信息,因为可以不停通过助记符来重新生成私钥.
|
||||
Cosmos SDK 使用一套称之为 [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) 的标准来生成公私钥。这个标准定义了怎么去创建一个 HD 钱包(钱包就是一批账户的集合)。每一个账户的核心,都有一个种子,每一个种子都有一个 12 或 24 个字的助记符。使用这个助记符,使用一种单向的加密方法可以派生出任意数量的私钥。公钥可以通过私钥推导出来。当然,助记符是最敏感的信息,因为可以不停通过助记符来重新生成私钥。
|
||||
|
||||
```
|
||||
Account 0 Account 1 Account 2
|
||||
|
@ -52,66 +52,66 @@ Cosmos SDK使用一套称之为 [BIP32](https://github.com/bitcoin/bips/blob/mas
|
|||
+-------------------+
|
||||
```
|
||||
|
||||
在Cosmos SDK中,账户可以在[`Keybase`](#keybase)中作为一个对象来储存和管理.
|
||||
在 Cosmos SDK 中,账户可以在 [`Keybase`](#keybase) 中作为一个对象来储存和管理。
|
||||
|
||||
## Keybase
|
||||
|
||||
`Keybase` 是储存和管理账户的对象,在Cosmos SDK中,`Keybase`要实现以下接口
|
||||
`Keybase` 是储存和管理账户的对象,在 Cosmos SDK 中,`Keybase` 要实现以下接口
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/types.go#L13-L86
|
||||
+++ https://github。com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/types.go#L13-L86
|
||||
|
||||
在Cosmos SDK中,`Keybase`接口的默认实现对象是`dbKeybase`.
|
||||
在 Cosmos SDK 中,`Keybase` 接口的默认实现对象是 `dbKeybase`。
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/crypto/keys/keybase.go
|
||||
|
||||
`dbKeybase`上面对`Keybase`接口中方法实现的笔记:
|
||||
`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) 获取更多信息
|
||||
- `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`的原因
|
||||
`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命令
|
||||
`lazyKeybase` 是 `dbKeybase` 的一个简单包装,它仅在要执行操作时锁定数据库,并在之后立即将其解锁。使用 `lazyKeybase`[命令行界面](../interfaces/cli.md) 可以在 [rest server](../interfaces/rest.md)运行时创建新的账户,它也可以同时传递多个 CLI 命令
|
||||
|
||||
## 地址和公钥
|
||||
|
||||
`Addresses` 和`PubKey`在程序里面都是标识一个参与者的公共信息.Cosmos SDK默认提供3中类型的`Addresses`和`PubKey`
|
||||
`Addresses` 和 `PubKey` 在程序里面都是标识一个参与者的公共信息。Cosmos SDK 默认提供 3 种类型的 `Addresses`和 `PubKey`
|
||||
|
||||
- 基于用户的`Addresses` 和`PubKey`,用于指定用户(例如`message`的发送者).它们通过 **`secp256k1`**曲线推导出来
|
||||
- 基于验证节点的`Addresses` 和`PubKey`用于指定验证者的操作员,它们通过 **`secp256k1`**曲线推导出来
|
||||
- 基于共识节点的`Addresses` 和`PubKey`用于指定参与共识的验证着节点,它们通过 **`ed25519`**曲线推导出来
|
||||
- 基于用户的 `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` |
|
||||
| Consensus Nodes | cosmosvalcons | cosmosvalconspub | `ed25519` | `20` | `32` |
|
||||
|
||||
### 公钥
|
||||
|
||||
在Cosmos SDK里面`PubKey`遵循在 tendermint的`crypto`包中定义的`Pubkey`接口
|
||||
在 Cosmos SDK 里面 `PubKey` 遵循在 tendermint 的 `crypto` 包中定义的 `Pubkey` 接口
|
||||
|
||||
+++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/crypto/crypto.go#L22-L27
|
||||
+++ 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)找到.
|
||||
对于 `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` 方法
|
||||
请注意,在 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种类型的地址
|
||||
在 Cosmos SDK 默认提送 3 种类型的地址
|
||||
|
||||
- `AccAddress` 用于账户
|
||||
- `ValAddress` 用于验证者操作员
|
||||
- `ConsAddress` 用于验证着节点
|
||||
- `ConsAddress` 用于验证者节点
|
||||
|
||||
这些地址类型都是一种长度为20的十六进制编码的`[]byte`数组的别名,这里有一种标准方法从`Pubkey pub`中获取到地址`aa`.
|
||||
这些地址类型都是一种长度为 20 的十六进制编码的 `[]byte` 数组的别名,这里有一种标准方法从`Pubkey pub`中获取到地址`aa`.
|
||||
|
||||
```go
|
||||
aa := sdk.AccAddress(pub.Address().Bytes())
|
||||
|
@ -121,10 +121,10 @@ aa := sdk.AccAddress(pub.Address().Bytes())
|
|||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L71-L80
|
||||
|
||||
值得注意的是,`Marhsal()`和`Bytes()`方法都返回相同的`[]byte`类型的地址,根据protobuff的兼容性要求我们需要前者.同样,`String()`也被用来返回`bech32`编码类型的地址,这个应该是用户看到的最终编码形式.下面是一个例子:
|
||||
值得注意的是,`Marhsal()` 和 `Bytes()` 方法都返回相同的 `[]byte` 类型的地址,根据 protobuf 的兼容性要求我们需要前者。同样,`String()` 也被用来返回 `bech32` 编码类型的地址,这个应该是用户看到的最终编码形式。下面是一个例子:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/address.go#L229-L243
|
||||
|
||||
## 接下来 {hide}
|
||||
|
||||
学习[gas and fees](./gas-fees.md) {hide}
|
||||
学习[gas and fees](./gas-fees.md) {hide}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
|
||||
|
||||
|
||||
|
||||
# SDK应用程序剖析
|
||||
# SDK 应用程序剖析
|
||||
|
||||
## Node Client
|
||||
|
||||
全节点的核心进程是基于SDK包的。 网络中的参与者运行此过程以初始化其状态机,与其他全节点连接并在新块进入时更新其状态机。
|
||||
全节点的核心进程是基于 SDK 包的。网络中的参与者运行此过程以初始化其状态机,与其他全节点连接并在新块进入时更新其状态机。
|
||||
|
||||
```
|
||||
^ +-------------------------------+ ^
|
||||
|
@ -26,200 +22,198 @@ Blockchain Node | | Consensus | |
|
|||
v +-------------------------------+ v
|
||||
```
|
||||
|
||||
|
||||
|
||||
区块链全节点以二进制形式表示,通常以`-d`后缀表示`守护程序`(例如,`appd`表示` app`或` gaiad`表示`gaia`)。 这个二进制文件是通过编译一个简单的代码文件 main.go构建的,`main.go` 通常位于`./cmd/appd/`中。 此操作通常通过用Makefile编译。
|
||||
区块链全节点以二进制形式表示,通常以 `-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`] 创建了一个状态机实例。
|
||||
1. [`app.go`] 创建了一个状态机实例。
|
||||
|
||||
2.用最新的已知状态初始化状态机,该状态机是从存储在`~/ .appd / data`文件夹中的db中提取的。 此时,状态机的高度为:`appBlockHeight`。
|
||||
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)。
|
||||
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`的文件中定义的。 它主要包含“应用程序的类型定义”和“创建和初始化它”的功能。
|
||||
通常,状态机的核心是在名为 `app.go` 的文件中定义的。 它主要包含“应用程序的类型定义”和“创建和初始化它”的功能。
|
||||
|
||||
### Type Definition of the Application
|
||||
|
||||
在app.go中重要的一个是应用程序的type。 它通常由以下部分组成:
|
||||
在 app.go 中重要的一个是应用程序的 type。 它通常由以下部分组成:
|
||||
|
||||
- 在`app.go`中定义的自定义应用程序是`baseapp`的扩展。 当事务由Tendermint发送到应用程序时,`app`使用`baseapp`的方法将它们转送到对应的模块。 baseapp为应用程序实现了大多数核心逻辑,包括所有的[ABCI方法](https://tendermint.com/docs/spec/abci/abci.html#overview)和转送消息逻辑。
|
||||
- 在 `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)中的应用程序类型定义示例
|
||||
- 一条 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签名。
|
||||
此函数构造了以上部分中定义的类型的新应用程序。在应用程的 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应等于模块中定义的预测值。 如果该值与预测的值不同,则将触发不变注册表中定义的特殊逻辑(通常会中断链)。 这对于确保不会发现任何严重错误并产生难以修复的长期影响非常有用。
|
||||
- 使用模块管理器,在每个应用程序的模块 的InitGenesis,BegingBlocker和EndBlocker函数之间设置执行顺序。 请注意,并非所有模块都实现这些功能。
|
||||
- 创建初始化一个新的 codec 实例,并使用基础模块管理器初始化每个应用程序模块的 `codec`。
|
||||
- 使用 baseapp 实例,编解码器和所有适当的存储键的引用实例化一个新应用程序。
|
||||
- 使用每个应用程序模块的 `NewKeeper` 功能实例化在应用程序的`类型`中定义的所有 keeper。 注意,所有 keeper 必须以正确的顺序实例化,因为一个模块的 NewKeeper 可能需要引用另一个模块的 `keeper`。
|
||||
- 使用每个应用模块的 AppModule 来实例化应用程序的模块管理器
|
||||
- 使用模块管理器,初始化应用程序的 routes 和 query route。 当事务由 Tendermint 通过 ABCI 中继到应用程序时,它使用此处定义的路由被路由到相应模块的回调 handler。 同样,当应用程序收到查询时,使用此处定义的查询路由将其路由到适当的模块的 querier。
|
||||
- 使用模块管理器,注册应用程序的模块的 invariants。 invariants 是在每个块末尾评估的变量(例如 token 的总供应量)。 检查不变式的过程是通过 InvariantsRegistry 的特殊模块完成的。 invariants 应等于模块中定义的预测值。 如果该值与预测的值不同,则将触发不变注册表中定义的特殊逻辑(通常会中断链)。这对于确保不会发现任何严重错误并产生难以修复的长期影响非常有用。
|
||||
- 使用模块管理器,在每个应用程序的模块 的 InitGenesis,BegingBlocker 和 EndBlocker 函数之间设置执行顺序。 请注意,并非所有模块都实现这些功能。
|
||||
- 模块实现这些功能。
|
||||
- 设置其余的应用程序参数:
|
||||
+ `InitChainer`于在应用程序首次启动时对其进行初始化。
|
||||
+ `BeginBlocker`,`EndBlocker`:在每个块的开始和结尾处调用。
|
||||
+ `anteHandler`:用于处理费用和签名验证。
|
||||
- 挂载存储.
|
||||
- 返回应用实例.
|
||||
- `InitChainer` 于在应用程序首次启动时对其进行初始化。
|
||||
- `BeginBlocker`,`EndBlocker`:在每个块的开始和结尾处调用。
|
||||
- `anteHandler`:用于处理费用和签名验证。
|
||||
- 挂载存储.
|
||||
- 返回应用实例.
|
||||
|
||||
请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从`〜/ .appd / data`文件夹中保留下来状态加载,如果节点是第一次启动,则从创世文件生成。See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia):
|
||||
请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从 `〜/.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 用于根据创始文件(即创始账户的代币余额)初始化应用程序的状态。 当应用程序从 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。
|
||||
通常,`InitChainer`主要由每个应用程序模块的 InitGenesis 函数组成。 这是通过调用模块管理器的 InitGenesis 函数来完成的,而模块管理器的 InitGenesis 函数将依次调用其包含的每个模块的 InitGenesis 函数。 请注意,必须使用模块管理器的 SetOrderInitGenesis 方法设置模块的 InitGenesis 函数的顺序。 这是在 应用程序的构造函数 application-constructor 中完成的,必须在 SetInitChainer 之前调用 SetOrderInitGenesis。
|
||||
|
||||
查看来自[gaia](https://github.com/cosmos/gaia)的InitChainer的示例:
|
||||
查看来自[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`的示例:
|
||||
查看来自 [`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`。
|
||||
该 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` 函数主要由每个应用程序模块的 `BeginBlock` 和 `EndBlock` 函数组成。 这是通过调用模块管理器的 BeginBlock 和 EndBlock 函数来完成的,而后者又会调用其包含的每个模块的 BeginBLock 和 EndBlock 函数。 请注意,必须分别在模块管理器中使用 SetOrderBeginBlock 和 SetOrderEndBlock 方法来设置模块的 BegingBlock 和 EndBlock 函数必须调用的顺序。这是通过应用程序的构造函数中的模块管理器完成的,必须调用 SetOrderBeginBlock 和 SetOrderEndBlock 方法。 在 SetBeginBlocker 和 SetEndBlocker 函数之前。
|
||||
|
||||
附带说明,请记住特定于应用程序的区块链是确定性的,这一点很重要。 开发人员必须注意不要在BeginBlocker或EndBlocker中引入不确定性,还必须注意不要使它们在计算上过于昂贵,因为[gas]不会限制计算代价当调用 BeginBlocker和EndBlocker执行。
|
||||
附带说明,请记住特定于应用程序的区块链是确定性的,这一点很重要。开发人员必须注意不要在 BeginBlocker 或 EndBlocker 中引入不确定性,还必须注意不要使它们在计算上过于昂贵,因为[gas]不会限制计算代价当调用 BeginBlocker 和 EndBlocker 执行。
|
||||
|
||||
请参阅[gaia](https://github.com/cosmos/gaia)中的`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 函数是 app.go 文件的最后一个重要功能。 此函数的目的是使用 RegisterCodec 函数实例化 codec`cdc`,例如 amino 初始化 SDK 的编解码器以及每个应用程序的模块。
|
||||
|
||||
为了注册应用程序的模块,`MakeCodec`函数在`ModuleBasics`上调用`RegisterCodec`。`ModuleBasics`是一个基本管理器,其中列出了应用程序的所有模块。 它在`init()`函数中得到实例化,仅用于注册应用程序模块的非依赖元素(例如编解码器)。 要了解有关基本模块管理器的更多信息,请点击[这里](https://docs.cosmos.network/master/building-modules/module-manager.html#basicmanager)。
|
||||
为了注册应用程序的模块,`MakeCodec` 函数在 `ModuleBasics` 上调用 `RegisterCodec`。`ModuleBasics` 是一个基本管理器,其中列出了应用程序的所有模块。 它在`init()`函数中得到实例化,仅用于注册应用程序模块的非依赖元素(例如编解码器)。 要了解有关基本模块管理器的更多信息,请点击[这里](https://docs.cosmos.network/master/building-modules/module-manager.html#basicmanager)。
|
||||
|
||||
请参阅[gaia](https://github.com/cosmos/gaia)中的`MakeCodec`示例:
|
||||
请参阅 [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/`文件夹混淆,该文件夹包含已构建的模块)。
|
||||
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`的文件中定义。
|
||||
模块必须实现 Cosmos SDK AppModuleBasic 中的 [interfaces](https://docs.cosmos.network/master/building-modules/module-manager.html#application-module-interfaces) 和 AppModule。 前者实现了模块的基本非依赖性元素,例如`编解码器`,而后者则处理了大部分模块方法(包括需要引用其他模块的`keeper`的方法)。`AppModule` 和 `AppModuleBasic` 类型都在名为 `module.go` 的文件中定义。
|
||||
|
||||
AppModule在模块上公开了一组有用的方法,这些方法有助于将模块组合成一个一致的应用程序。 这些方法是从模块管理器中调用的,该模块管理应用程序的模块集合。
|
||||
AppModule 在模块上公开了一组有用的方法,这些方法有助于将模块组合成一个一致的应用程序。 这些方法是从模块管理器中调用的,该模块管理应用程序的模块集合。
|
||||
|
||||
### Message Types
|
||||
|
||||
每个`module`定义[messages](https://docs.cosmos.network/master/building-modules/messages-and-queries.html#messages)接口。 每个`transaction`包含一个或多个`messages`。
|
||||
每个 `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)将每个交易发到应用程序 。 然后,应用程序处理事务:
|
||||
当全节点接收到有效的交易块时,Tendermint 通过 [`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx) 将每个交易发到应用程序。然后,应用程序处理事务:
|
||||
|
||||
- 收到交易后,应用程序首先从`[] bytes`反序列化得到。
|
||||
- 然后,在提取交易中包含的消息之前,它会验证有关交易的一些信息,例如费用支付和签名
|
||||
- 使用message的Type()方法,baseapp可以将其发到对应模块的 回调 handler以便对其进行处理。
|
||||
- 收到交易后,应用程序首先从 `[]bytes` 反序列化得到。
|
||||
- 然后,在提取交易中包含的消息之前,它会验证有关交易的一些信息,例如费用支付和签名。
|
||||
- 使用 message 的 Type()方法,baseapp 可以将其发到对应模块的回调 handler 以便对其进行处理。
|
||||
- 如果消息已成功处理,则状态将更新。
|
||||
|
||||
有关事务生命周期的更多详细信息,请看[这里](./ tx-lifecycle.md)。
|
||||
|
||||
模块开发人员在构建自己的模块时会创建自定义消息类型。 通常的做法是在消息的类型声明前加上`Msg`。 例如,消息类型`MsgSend`允许用户传输tokens:
|
||||
模块开发人员在构建自己的模块时会创建自定义消息类型。 通常的做法是在消息的类型声明前加上 `Msg`。 例如,消息类型 `MsgSend` 允许用户传输 tokens:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/bank/internal/types/msgs.go#L10-L15
|
||||
|
||||
它由`bank`模块的回调`handler`处理,最终会调用`auth`模块来写`keeper`以更新状态。
|
||||
它由 `bank` 模块的回调 `handler` 处理,最终会调用 `auth` 模块来写 `keeper` 以更新状态。
|
||||
|
||||
### Handler
|
||||
|
||||
回调`handler` 是指模块的一部分,负责处理`baseapp`传递的`message`消息。 仅当通过ABCI接口的DeliverTx 消息从Tendermint 收到事务时,才执行模块的“处理程序”功能。 如果通过CheckTx,仅执行无状态检查和与费用相关的有状态检查。 为了更好地理解`DeliverTx`和`CheckTx`之间的区别以及有状态和无状态检查之间的区别,请看[这里](./ tx-lifecycle.md)。
|
||||
回调 `handler` 是指模块的一部分,负责处理 `baseapp` 传递的 `message` 消息。 仅当通过 ABCI 接口的 DeliverTx 消息从 Tendermint 收到事务时,才执行模块的`处理程序`功能。 如果通过 CheckTx,仅执行无状态检查和与费用相关的有状态检查。为了更好地理解 `DeliverTx` 和 `CheckTx` 之间的区别以及有状态和无状态检查之间的区别,请看[这里](./tx-lifecycle.md)。
|
||||
|
||||
模块的“处理程序”通常在名为`handler.go`的文件中定义,并包括:
|
||||
模块的`处理程序`通常在名为 `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)的方法来更新状态。
|
||||
- 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
|
||||
|
||||
处理程序函数返回结果类型为sdk.Result,该结果通知应用程序消息是否已成功处理:
|
||||
- 模块定义的每种消息类型的处理函数。开发人员在这些函数中编写消息处理逻辑。这通常包括进行状态检查以确保消息有效,并调用 [`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
|
||||
### Querier
|
||||
|
||||
`Queriers`与`handlers`非常相似,除了它们向状态查询用户而不是处理事务。 最终用户从interface 发起query,最终用户会提供`queryRoute`和一些` data`。 然后使用`queryRoute`通过baseapp`的`handleQueryCustom方法查询到正确的应用程序的`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的文件中定义的,包括:
|
||||
模块的 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。
|
||||
- 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`](https://docs.cosmos.network/master/building-modules/keeper.html)是其模块存储器件。要在模块的存储区中进行读取或写入,必须使用其 `keeper` 方法之一。这是由 Cosmos SDK 的 object-capabilities 模型确保的。 只有持有存储密钥的对象才能访问它,只有模块的 `keeper` 才应持有该模块存储的密钥。
|
||||
|
||||
`Keepers`通常在名为`keeper.go`的文件中定义。 它包含`keeper`的类型定义和方法。
|
||||
`Keepers` 通常在名为 `keeper.go` 的文件中定义。 它包含 `keeper` 的类型定义和方法。
|
||||
|
||||
`keeper`类型定义通常包括:
|
||||
`keeper` 类型定义通常包括:
|
||||
|
||||
- 多重存储中模块存储的“密钥”。
|
||||
- 参考**其他模块的`keepers`**。 仅当`keeper`需要访问其他模块的存储(从它们读取或写入)时才需要。
|
||||
- 对应用程序的“编解码器”的引用。 “ keeper”需要它在存储结构之前序列化处理,或在检索它们时将反序列化处理,因为存储仅接受“ [] bytes”作为值。
|
||||
- 多重存储中模块存储的`密钥`。
|
||||
- 参考**其他模块的`keepers`**。 仅当 `keeper` 需要访问其他模块的存储(从它们读取或写入)时才需要。
|
||||
- 对应用程序的`编解码器`的引用。 `keeper` 需要它在存储结构之前序列化处理,或在检索它们时将反序列化处理,因为存储仅接受 `[]bytes` 作为值。
|
||||
|
||||
与类型定义一起,keeper.go文件的一个重要组成部分是Keeper的构造函数NewKeeper。 该函数实例化上面定义的类型的新`keeper`,并带有`codec`,存储`keys`以及可能引用其他模块的`keeper`作为参数。 从应用程序的构造函数中调用`NewKeeper`函数。 文件的其余部分定义了`keeper`的方法,主要是getter和setter。
|
||||
与类型定义一起,keeper.go 文件的一个重要组成部分是 Keeper 的构造函数 NewKeeper。 该函数实例化上面定义的类型的新 `keeper`,并带有 `codec`,存储 `keys` 以及可能引用其他模块的 `keeper` 作为参数。从应用程序的构造函数中调用 `NewKeeper` 函数。文件的其余部分定义了 `keeper` 的方法,主要是 getter 和 setter。
|
||||
|
||||
### Command-Line and REST Interfaces
|
||||
|
||||
每个模块都定义了application-interfaces 向用户公开的命令行命令和REST routes。 用户可以创建模块中定义的类型的消息,或查询模块管理的状态的子集。
|
||||
每个模块都定义了 application-interfaces 向用户公开的命令行命令和 REST routes。 用户可以创建模块中定义的类型的消息,或查询模块管理的状态的子集。
|
||||
|
||||
#### CLI
|
||||
|
||||
通常,与模块有关的命令在模块文件夹中名为`client / cli`的文件夹中定义。 CLI将命令分为交易和查询两类,分别在`client / cli / tx.go`和`client / cli / query.go`中定义。 这两个命令基于[Cobra Library](https://github.com/spf13/cobra)之上:
|
||||
通常,与模块有关的命令在模块文件夹中名为 `client/cli` 的文件夹中定义。CLI 将命令分为交易和查询两类,分别在 `client/cli/tx.go` 和 `client/cli/query.go` 中定义。这两个命令基于 [Cobra Library](https://github.com/spf13/cobra)之上:
|
||||
|
||||
- Transactions命令使用户可以生成新的事务,以便可以将它们包含在块中并更新状态。 应该为模块中定义的每个消息类型message-types创建一个命令。 该命令使用户提供的参数调用消息的构造函数,并将其包装到事务中。 SDK处理签名和其他事务元数据的添加。
|
||||
- 用户可以查询模块定义的状态子集。 查询命令将查询转发到应用程序的查询路由器,然后将查询路由到提供的`queryRoute`参数的相应 querier。
|
||||
- Transactions 命令使用户可以生成新的事务,以便可以将它们包含在块中并更新状态。应该为模块中定义的每个消息类型 message-types 创建一个命令。该命令使用户提供的参数调用消息的构造函数,并将其包装到事务中。SDK 处理签名和其他事务元数据的添加。
|
||||
- 用户可以查询模块定义的状态子集。查询命令将查询转发到应用程序的查询路由器,然后将查询路由到提供的`queryRoute`参数的相应 querier。
|
||||
|
||||
#### REST
|
||||
|
||||
模块的REST接口允许用户生成事务并通过对应用程序的 light client daemon(LCD) 查询状态。 REST路由在`client / rest / rest.go`文件中定义,该文件包括:
|
||||
模块的 REST 接口允许用户生成事务并通过对应用程序的 light client daemon(LCD) 查询状态。 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
|
||||
- `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允许用户与全节点客户端进行交互。 这意味着从全节点查询数据,或者接受全节点中包含在块中的新事务。
|
||||
Interfaces 允许用户与全节点客户端进行交互。 这意味着从全节点查询数据,或者接受全节点中包含在块中的新事务。
|
||||
|
||||
通过汇总在应用程序使用的每个模块中定义的 CLI命令构建SDK应用程序的CLI。 应用程序的CLI通常具有后缀-cli(例如appcli),并在名为`cmd / appcli / main.go`的文件中定义。 该文件包含:
|
||||
通过汇总在应用程序使用的每个模块中定义的 CLI 命令构建 SDK 应用程序的 CLI。 应用程序的 CLI 通常具有后缀-cli(例如 appcli),并在名为`cmd / appcli / main.go`的文件中定义。 该文件包含:
|
||||
|
||||
- main()函数,用于构建appcli接口客户端。这个函数准备每个命令,并在构建它们之前将它们添加到`rootCmd`中。在appCli的根部,该函数添加了通用命令,例如status,keys和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。
|
||||
- main()函数,用于构建 appcli 接口客户端。这个函数准备每个命令,并在构建它们之前将它们添加到`rootCmd`中。在 appCli 的根部,该函数添加了通用命令,例如 status,keys 和 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)中查看应用程序的主要命令行文件的示例。
|
||||
|
||||
|
@ -231,11 +225,10 @@ Interfaces允许用户与全节点客户端进行交互。 这意味着从全节
|
|||
|
||||
+++ 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示例
|
||||
为了构建应用程序,通常使用[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
|
||||
## Next
|
||||
|
||||
了解有关[交易生命周期](./ tx-lifecycle.md)的更多信息
|
||||
|
||||
|
|
|
@ -1,54 +1,54 @@
|
|||
**原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/gas-fees.md**
|
||||
|
||||
# Gas and Fees
|
||||
# Gas and Fees
|
||||
|
||||
## 必备阅读 {hide}
|
||||
|
||||
- [一个SDK程序的剖析](./app-anatomy.md) {prereq}
|
||||
- [一个 SDK 程序的剖析](./app-anatomy.md) {prereq}
|
||||
|
||||
## `Gas` and `Fees`的介绍
|
||||
|
||||
在Cosmos SDK中,`gas`是一种特殊的单位,用于跟踪执行期间的资源消耗.每当对储存进行读写操作的时候会消耗`gas`,如果要进行比较复杂的计算的话也会消耗`gas`.它主要有两个目的:
|
||||
在 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)来完成.
|
||||
- 确保区块不会消耗太多资源而且能顺利完成。这个默认在 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
|
||||
## Gas Meter
|
||||
|
||||
在Cosmos SDK中`gas`是一种简单的`uint64`类型,被称之为*gas meter*的对象进行管理,Gas meters 实现了`GasMeter`接口
|
||||
在 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`消耗的方式如下:
|
||||
- `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).
|
||||
通常,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消耗
|
||||
`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`消耗可以手工完成,模块开发者通常在 [`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提供的默认共识参数:
|
||||
`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
|
||||
+++ 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`消耗中.
|
||||
当通过 `DeliverTx` 处理新的 [transaction](../core/transactions.md) 的时候,`BlockGasMeter` 的当前值会被校验是否超过上限,如果超过上限,`DeliverTx` 直接返回,由于 `BeginBlock` 会消耗 `gas`,这种情况可能会在第一个 `transaction` 到来时发生,如果没有发生这种情况,`transaction`将会被正常的执行。在 `DeliverTx` 的最后,`ctx.BlockGasMeter()` 会追踪 `gas` 消耗并将它增加到处理 `transaction` 的 `gas` 消耗中.
|
||||
|
||||
```go
|
||||
ctx.BlockGasMeter().ConsumeGas(
|
||||
|
@ -59,7 +59,7 @@ ctx.BlockGasMeter().ConsumeGas(
|
|||
|
||||
## AnteHandler
|
||||
|
||||
`AnteHandler`是一个特殊的处理程序,它在`CheckTx` 和 `DeliverTx`期间为每一个`transaction`的每个`message`处理之前执行.`AnteHandler`相比`handler`有不同的签名:
|
||||
`AnteHandler` 是一个特殊的处理程序,它在 `CheckTx` 和 `DeliverTx` 期间为每一个 `transaction` 的每个 `message` 处理之前执行。`AnteHandler` 相比 `handler` 有不同的签名:
|
||||
|
||||
```go
|
||||
// AnteHandler authenticates transactions, before their internal messages are handled.
|
||||
|
@ -67,14 +67,18 @@ ctx.BlockGasMeter().ConsumeGas(
|
|||
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` 不是在核心 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` 的模块中定义,它们遵循事务接口:
|
||||
|
||||
如上所述,`anteHandler`返回`transaction`执行期间所能消耗的最大的`gas`数量,称之为`GasWanted`.最后实际`gas`消耗数量记为`GasUsed`,因此我们必须使`GasUsed =< GasWanted`.当返回时`GasWanted` 和 `GasUsed`都会被中继到共识引擎中.
|
||||
+++ 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` 都会被中继到共识引擎中.
|
||||
|
|
|
@ -1,98 +1,98 @@
|
|||
# Transaction的生命周期
|
||||
# Transaction 的生命周期
|
||||
|
||||
本文档描述了Transaction从创建到提交的生命周期,Transaction的定义在[其他文档](https://docs.cosmos.network/master/core/transactions.html)中有详细描述,后文中Transaction将统一被称为`Tx`。
|
||||
本文档描述了 Transaction 从创建到提交的生命周期,Transaction 的定义在[其他文档](https://docs.cosmos.network/master/core/transactions.html)中有详细描述,后文中 Transaction 将统一被称为`Tx`。
|
||||
|
||||
## 创建
|
||||
|
||||
### Transaction的创建
|
||||
### Transaction 的创建
|
||||
|
||||
命令行界面是主要的应用程序界面之一,`Tx`可以由用户输入[以下命令](https://docs.cosmos.network/master/interfaces/cli.html)来创建,其中`[command]`是`Tx`的类型,`[args]`是相关参数,`[flags]`是相关配置例如gas price:
|
||||
命令行界面是主要的应用程序界面之一,`Tx` 可以由用户输入[以下命令](https://docs.cosmos.network/master/interfaces/cli.html)来创建,其中 `[command]` 是 `Tx` 的类型,`[args]` 是相关参数,`[flags]` 是相关配置例如 gas price:
|
||||
|
||||
```bash
|
||||
[appname] tx [command] [args] [flags]
|
||||
```
|
||||
|
||||
此命令将自动**创建**`Tx`,使用帐户的私钥对其进行**签名**,并将其**广播**到其他节点。
|
||||
此命令将自动**创建** `Tx`,使用帐户的私钥对其进行**签名**,并将其**广播**到其他节点。
|
||||
|
||||
创建`Tx`有一些必需的和可选的参数,其中`--from`指定该`Tx`的发起[账户](https://docs.cosmos.network/master/basics/accounts.html),例如一个发送代币的`Tx`,则将从 `from`指定的账户提取资产。
|
||||
创建 `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):
|
||||
此外,用户可以使用这几个[参数](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。
|
||||
- `--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价格,因此用户仅指定两者之一即可。
|
||||
所支付 fee 的最终价值等于 gas 的数量乘以 gas 的价格。换句话说,`fees = ceil(gas * gasPrices)`。由于可以使用 gas 价格来计算 fee,也可以使用 fee 来计算 gas 价格,因此用户仅指定两者之一即可。
|
||||
|
||||
随后,验证者通过将给定的或计算出的`gas-prices`与他们本地的`min-gas-prices`进行比较,来决定是否在其区块中写入该`Tx`。如果`gas-prices`不够高,该`Tx`将被拒绝,因此鼓励用户支付更多fee。
|
||||
随后,验证者通过将给定的或计算出的 `gas-prices` 与他们本地的 `min-gas-prices` 进行比较,来决定是否在其区块中写入该 `Tx`。如果 `gas-prices` 不够高,该 `Tx` 将被拒绝,因此鼓励用户支付更多 fee。
|
||||
|
||||
#### CLI 示例
|
||||
|
||||
应用程序的用户可以在其CLI中输入以下命令,用来生成一个将1000uatom从`senderAddress`发送到 `recipientAddress`的`Tx`,该命令指定了用户愿意支付的gas(其中gas数量为自动估算的1.5倍,每单位gas价格为0.025uatom)。
|
||||
应用程序的用户可以在其 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创建方法
|
||||
#### 其他的 Transaction 创建方法
|
||||
|
||||
命令行是与应用程序进行交互的一种简便方法,但是`Tx`也可以使用[REST interface](https://docs.cosmos.network/master/interfaces/rest.html)或应用程序开发人员定义的某些其他入口点来创建命令行。从用户的角度来看,交互方式取决于他们正在使用的是页面还是钱包(例如,`Tx`使用[Lunie.io](https://lunie.io/#/) 创建并使用Ledger Nano S对其进行签名)。
|
||||
命令行是与应用程序进行交互的一种简便方法,但是 `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`并将其广播出去。
|
||||
每个全节点(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`,以免浪费计算资源。
|
||||
全节点在 `CheckTx` 期间对 `Tx` 先执行无状态检查,然后进行有状态检查,目的是尽早识别并拒绝无效 `Tx`,以免浪费计算资源。
|
||||
|
||||
***无状态检查***不需要知道节点的状态,即轻客户端或脱机节点都可以检查,因此计算开销较小。无状态检查包括确保地址不为空、强制使用非负数、以及定义中指定的其他逻辑。
|
||||
**_无状态检查_**不需要知道节点的状态,即轻客户端或脱机节点都可以检查,因此计算开销较小。无状态检查包括确保地址不为空、强制使用非负数、以及定义中指定的其他逻辑。
|
||||
|
||||
***状态检查***根据提交的状态验证`Tx`和`Message`。例如,检查相关值是否存在并能够进行交易,账户是否有足够的资产,发送方是否被授权或拥有正确的交易所有权。在任何时刻,由于不同的原因,全节点通常具有应用程序内部状态的[多种版本](https://docs.cosmos.network/master/core/baseapp.html#volatile-states)。例如,节点将在验证`Tx`的过程中执行状态更改,但仍需要最后的提交状态才能响应请求,节点不能使用未提交的状态更改来响应请求。
|
||||
**_状态检查_**根据提交的状态验证 `Tx` 和 `Message`。例如,检查相关值是否存在并能够进行交易,账户是否有足够的资产,发送方是否被授权或拥有正确的交易所有权。在任何时刻,由于不同的原因,全节点通常具有应用程序内部状态的[多种版本](https://docs.cosmos.network/master/core/baseapp.html#volatile-states)。例如,节点将在验证 `Tx` 的过程中执行状态更改,但仍需要最后的提交状态才能响应请求,节点不能使用未提交的状态更改来响应请求。
|
||||
|
||||
为了验证`Tx`,全节点调用的`CheckTx`包括无状态检查和有状态检查,进一步的验证将在[`DeliverTx`](#delivertx)阶段的后期进行。其中`CheckTx`从对`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`和写入状态更改之前退出。
|
||||
当 `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`会检查账户是否存在,并确认账户中代币金额为正,但不需要了解状态,例如帐户余额。
|
||||
[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`进行状态检查时无需修改最后的提交状态,如果执行失败,还可以还原为原始状态。
|
||||
[`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`
|
||||
例如,[`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`。
|
||||
[`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`。
|
||||
如果在 `CheckTx` 期间有任何失败,`Tx` 将被丢弃,并且 `Tx` 的生命周期结束。如果 `CheckTx` 成功,则 `Tx` 将被广播到其他节点,并会被添加到交易池,以便成为待出区块中的候选 `Tx`。
|
||||
|
||||
**交易池**保存所有全节点可见的`Tx`,全节点会将其最近的`Tx`保留在**交易池缓存**中,作为防止重放攻击的第一道防线。理想情况下,`mempool.cache_size`的大小足以容纳整个交易池中的所有`Tx`。如果交易池缓存太小而无法跟踪所有`Tx`,`CheckTx`会识别出并拒绝重放的`Tx`。
|
||||
**交易池**保存所有全节点可见的 `Tx`,全节点会将其最近的 `Tx` 保留在**交易池缓存**中,作为防止重放攻击的第一道防线。理想情况下,`mempool.cache_size` 的大小足以容纳整个交易池中的所有 `Tx`。如果交易池缓存太小而无法跟踪所有 `Tx`,`CheckTx` 会识别出并拒绝重放的 `Tx`。
|
||||
|
||||
现有的预防措施包括fee和`序列号` 计数器,用来区分重放`Tx`和相同的`Tx`。如果攻击者尝试向某个节点发送多个相同的`Tx`,则保留交易池缓存的完整节点将拒绝相同的`Tx`,而不是在所有`Tx`上运行`CheckTx` 。如果`Tx`有不同的`序列号`,攻击者会因为需要支付费用而取消攻击。
|
||||
现有的预防措施包括 fee 和`序列号`计数器,用来区分重放 `Tx` 和相同的 `Tx`。如果攻击者尝试向某个节点发送多个相同的 `Tx`,则保留交易池缓存的完整节点将拒绝相同的 `Tx`,而不是在所有 `Tx` 上运行 `CheckTx`。如果 `Tx` 有不同的`序列号`,攻击者会因为需要支付费用而取消攻击。
|
||||
|
||||
验证器节点与全节点一样,保留一个交易池以防止重放攻击,但它也用作出块过程中未经验证的交易池。请注意,即使`Tx`在此阶段通过了所有检查,仍然可能会被发现无效,因为`CheckTx`没有完全验证`Tx`(`CheckTx`实际上并未执行`message`)。
|
||||
验证器节点与全节点一样,保留一个交易池以防止重放攻击,但它也用作出块过程中未经验证的交易池。请注意,即使 `Tx` 在此阶段通过了所有检查,仍然可能会被发现无效,因为 `CheckTx` 没有完全验证 `Tx`(`CheckTx` 实际上并未执行 `message`)。
|
||||
|
||||
## 写入区块
|
||||
|
||||
共识是验证者节点就接受哪些`Tx`达成协议的过程,它是**反复进行**的。每个回合都始于出块节点创建一个包含最近`Tx`的区块,并由验证者节点(具有投票权的特殊全节点)负责达成共识,同意接受该区块或出一个空块。验证者节点执行共识算法,例如[Tendermint BFT](https://tendermint.com/docs/spec/consensus/consensus.html#terms),调用ABCI请求确认`Tx`,从而达成共识。
|
||||
共识是验证者节点就接受哪些 `Tx` 达成协议的过程,它是**反复进行**的。每个回合都始于出块节点创建一个包含最近 `Tx` 的区块,并由验证者节点(具有投票权的特殊全节点)负责达成共识,同意接受该区块或出一个空块。验证者节点执行共识算法,例如[Tendermint BFT](https://tendermint.com/docs/spec/consensus/consensus.html#terms),调用 ABCI 请求确认 `Tx`,从而达成共识。
|
||||
|
||||
达成共识的第一步是**区块提案**,共识算法从验证者节点中选择一个出块节点来创建和提议一个区块,用来写入`Tx`,`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`在提案中有明确的顺序。
|
||||
共识的下一步是执行 `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` 在提案中有明确的顺序。
|
||||
|
||||
```
|
||||
-----------------------------
|
||||
|
@ -133,31 +133,30 @@ appcli tx send <recipientAddress> 1000uatom --from <senderAddress> --gas auto --
|
|||
|
||||
### 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`。
|
||||
[`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` 和并写入状态的变化。
|
||||
|
||||
* **解码:**由于`DeliverTx`是通过ABCI调用的,因此`Tx`会以`[]byte`的形式被接收。节点首先会对`Tx`进行解码,然后在`runTxModeDeliver`中调用`runTx`,`runTx`除了会执行`CheckTx`中的检查外,还会执行`Tx`和并写入状态的变化。
|
||||
- **检查:** 全节点会再次调用 `validateBasicMsgs` 和 `AnteHandler`。之所以进行第二次检查,是因为在 `Tx` 进交易池的过程中,可能没有相同的 `Tx`,但恶意出块节点的区块可能包括无效 `Tx`。但是这次检查特殊的地方在于,`AnteHandler` 不会将 `gas-prices` 与节点的 `min-gas-prices` 比较,因为每个节点的 `min-gas-prices` 可能都不同,这样比较的话可能会产生不确定的结果。
|
||||
|
||||
* **检查:** 全节点会再次调用`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:** `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` 的模块中定义,并写入模块中的适当存储区。
|
||||
|
||||
* **Handler:**`handler`是用来执行`Tx`中的每个`message`,并且使状态转换到从而保持`deliverTxState`。`handler`在`Msg`的模块中定义,并写入模块中的适当存储区。
|
||||
- **Gas:** 在 `Tx` 被传递的过程中,`GasMeter` 是用来记录有多少 gas 被使用,如果执行完成,`GasUsed` 会被赋值并返回 `abci.ResponseDeliverTx`。如果由于 `BlockGasMeter` 或者 `GasMeter` 耗尽或其他原因导致执行中断,程序则会报出相应的错误。
|
||||
|
||||
* **Gas:**在`Tx`被传递的过程中,`GasMeter`是用来记录有多少gas被使用,如果执行完成,`GasUsed`会被赋值并返回`abci.ResponseDeliverTx`。如果由于`BlockGasMeter` 或者 `GasMeter` 耗尽或其他原因导致执行中断,程序则会报出相应的错误。
|
||||
|
||||
如果由于`Tx`无效或`GasMeter`用尽而导致任何状态更改失败,`Tx`的处理将被终止,并且所有状态更改都将还原。区块提案中无效的`Tx`会导致验证者节点拒绝该区块并投票给空块。
|
||||
如果由于 `Tx` 无效或 `GasMeter` 用尽而导致任何状态更改失败,`Tx` 的处理将被终止,并且所有状态更改都将还原。区块提案中无效的 `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`重置为空以保持一致并反映更改。
|
||||
当收到足够的验证者票数(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` 提交到区块链中。可能的恶意行为包括出块节点将某个 `Tx` 排除在区块链之外,或者投票反对某个出块节点。
|
||||
|
||||
至此,`Tx`的生命周期结束,节点已验证其有效性,并提交了这些更改。`Tx`本身,以`[]byte`的形式被存储在区块上进入了区块链网络。
|
||||
至此,`Tx`的生命周期结束,节点已验证其有效性,并提交了这些更改。`Tx`本身,以 `[]byte` 的形式被存储在区块上进入了区块链网络。
|
||||
|
||||
## 下一节
|
||||
|
||||
了解 [accounts](./accounts.md)
|
||||
了解 [accounts](./accounts.md)
|
||||
|
|
|
@ -2,18 +2,17 @@
|
|||
|
||||
本节说明包含区块链 SDK 的客户端的信息。
|
||||
|
||||
> *注*:此部分仍在开发中。
|
||||
> _注_:此部分仍在开发中。
|
||||
|
||||
##轻客户端
|
||||
## 轻客户端
|
||||
|
||||
轻客户端使用户能够与您的应用程序进行交互,且无需下载整个状态历史记录,但具有良好的安全性。
|
||||
轻客户端使用户能够与您的应用程序进行交互,且无需下载整个状态历史记录,并且具有良好的安全性。
|
||||
|
||||
- [轻客户端概述](./lite/README.md)
|
||||
- [启动轻客户端服务器](./lite/getting_started.md)
|
||||
- [轻客户端规范](./lite/specification.md)
|
||||
- [轻客户端概述](./lite/README.md)
|
||||
- [启动轻客户端服务器](./lite/getting_started.md)
|
||||
- [轻客户端规范](./lite/specification.md)
|
||||
|
||||
##其他客户端
|
||||
|
||||
- [区块链 SDK 的 CLI](./cli.md)
|
||||
- [服务提供商文档](./service-providers.md)
|
||||
## 其他客户端
|
||||
|
||||
- [区块链 SDK 的 CLI](./cli.md)
|
||||
- [服务提供商文档](./service-providers.md)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# CLI
|
||||
|
||||
> TODO: Rewrite this section to explain how CLI works for a generic SDK app.
|
||||
|
||||
> TODO: Rewrite this section to explain how CLI works for a generic SDK app.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 轻客户端概览
|
||||
|
||||
**点击[这里](https://cosmos.network/rpc/)查看Cosmos SDK 轻客户端 RPC 文档**
|
||||
**点击[这里](https://cosmos.network/rpc/)查看 Cosmos SDK 轻客户端 RPC 文档**
|
||||
|
||||
## 简介
|
||||
|
||||
|
@ -10,11 +10,11 @@
|
|||
|
||||
### 什么是轻节点
|
||||
|
||||
Cosmos SDK 轻节点(Gaia-lite)分为两个独立的组件。 第一个组件对于任何基于 Tendermint 的应用程序都是通用的,它处理区块头相关的安全性和连接性,并验证来自全节点的证明与本地可信验证人集合的对比。 此外,它暴露与任何Tendermint 核心节点完全相同的API。 第二个组件专用于 Cosmos Hub(`gaiad`),它作为查询端点工作,并公开特定于应用程序的功能,这些功能可以是任意的。 针对应用程序状态的所有查询都必须通过查询端点。 查询端点的优点是它可以验证应用程序返回的证据。
|
||||
Cosmos SDK 轻节点(Gaia-lite)分为两个独立的组件。 第一个组件对于任何基于 Tendermint 的应用程序都是通用的,它处理区块头相关的安全性和连接性,并验证来自全节点的证明与本地可信验证人集合的对比。 此外,它暴露与任何 Tendermint 核心节点完全相同的 API。 第二个组件专用于 Cosmos Hub(`gaiad`),它作为查询端点工作,并公开特定于应用程序的功能,这些功能可以是任意的。 针对应用程序状态的所有查询都必须通过查询端点。 查询端点的优点是它可以验证应用程序返回的证据。
|
||||
|
||||
### 高层体系结构
|
||||
|
||||
想要为 Cosmos Hub(或任何其他 zone)构建第三方客户端应用程序的应用程序开发人员,应根据其规范 API 构建。 该API 是多个部分的组合。 所有 zone 都必须暴露ICS0(TendermintAPI)。 除此之外,任何 zone 都可以自由选择模块 API的任意组合,具体取决于状态机使用的模块。 Cosmos Hub最初将支持[ICS0](https://cosmos.network/rpc/#/ICS0) (TendermintAPI)、 [ICS1](https://cosmos.network/rpc/#/ICS1) (KeyAPI)、 [ICS20](https://cosmos.network/rpc/#/ICS20) (TokenAPI)、 [ICS21](https://cosmos.network/rpc/#/ICS21) (StakingAPI)、 [ICS22](https://cosmos.network/rpc/#/ICS22) (GovernanceAPI) 和 [ICS23](https://cosmos.network/rpc/#/ICS23) (SlashingAPI)。
|
||||
想要为 Cosmos Hub(或任何其他 zone)构建第三方客户端应用程序的应用程序开发人员,应根据其规范 API 构建。 该 API 是多个部分的组合。 所有 zone 都必须暴露 ICS0(TendermintAPI)。 除此之外,任何 zone 都可以自由选择模块 API 的任意组合,具体取决于状态机使用的模块。 Cosmos Hub 最初将支持[ICS0](https://cosmos.network/rpc/#/ICS0) (TendermintAPI)、 [ICS1](https://cosmos.network/rpc/#/ICS1) (KeyAPI)、 [ICS20](https://cosmos.network/rpc/#/ICS20) (TokenAPI)、 [ICS21](https://cosmos.network/rpc/#/ICS21) (StakingAPI)、 [ICS22](https://cosmos.network/rpc/#/ICS22) (GovernanceAPI) 和 [ICS23](https://cosmos.network/rpc/#/ICS23) (SlashingAPI)。
|
||||
|
||||
![high-level](../../../kr/clients/lite/pics/high-level.png)
|
||||
|
||||
|
@ -24,17 +24,17 @@ Cosmos SDK 轻节点(Gaia-lite)分为两个独立的组件。 第一个组
|
|||
|
||||
ABCI 的全节点与其轻客户端的区别在于以下方面:
|
||||
|
||||
| | Full Node | 轻客户端 | Description |
|
||||
| ------------------------------- | --------------- | ------------- | ------------------------------------------------------------ |
|
||||
| 执行并验证交易 | Yes | No | 全节点将执行并验证所有交易,而Gaia-lite则不会 |
|
||||
| 验证和存储区块 | Yes | No | 全节点将验证并保存所有块,而Gaia-lite则不会 |
|
||||
| 参与共识 | Yes | No | 只有当全节点是验证人时,它才会参与共识。 Lite节点永远不会参与共识。 |
|
||||
| 带宽开销 | 巨大 | 很小 | 全节点将接收所有块。 如果带宽有限,它将落后于主网络。 更重要的是,如果碰巧是验证人,它将减缓共识过程。 轻客户端需要很少的带宽, 只有在提供本地请求时,才会占用带宽。 |
|
||||
| 计算资源 | 巨大 | 很小 | 全节点将执行所有交易并验证所有块,这需要大量的计算资源 |
|
||||
| 存储资源 | 巨大 | 很小 | 全节点将保存所有块和 ABCI 状态,而Gaia-lite只保存验证人集合和一些检查点。 |
|
||||
| 电力资源 | 巨大 | 很小 | 全节点必须在具有高性能并能一直运行的机器上部署,因此功耗将是巨大的。 Gaia-lite可以部署在与用户应用程序相同的机器上,也可以部署在独立但性能较差的机器上。 此外,Lite客户端可以在必要时随时关闭。所以Gaia-lite只消耗很少的功率,即使移动设备也能满足功率需求。 |
|
||||
| 提供的 APIs | 所有cosmos APIs | 部分模块 APIs | 全节点支持所有cosmos API。 Gaia-lite 根据用户的配置提供模块化API。 |
|
||||
| 安全等级 | 高 | 高 | 全节点将自行验证所有交易和块。 轻型客户端无法执行此操作,但它可以查询来自其他全节点的任何数据并独立验证数据。 因此,全节点和轻型客户端都不需要信任任何第三方节点,它们都可以实现高安全性。 |
|
||||
| | Full Node | 轻客户端 | Description |
|
||||
| -------------- | ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 执行并验证交易 | Yes | No | 全节点将执行并验证所有交易,而 Gaia-lite 则不会 |
|
||||
| 验证和存储区块 | Yes | No | 全节点将验证并保存所有块,而 Gaia-lite 则不会 |
|
||||
| 参与共识 | Yes | No | 只有当全节点是验证人时,它才会参与共识。 Lite 节点永远不会参与共识。 |
|
||||
| 带宽开销 | 巨大 | 很小 | 全节点将接收所有块。 如果带宽有限,它将落后于主网络。 更重要的是,如果碰巧是验证人,它将减缓共识过程。 轻客户端需要很少的带宽, 只有在提供本地请求时,才会占用带宽。 |
|
||||
| 计算资源 | 巨大 | 很小 | 全节点将执行所有交易并验证所有块,这需要大量的计算资源 |
|
||||
| 存储资源 | 巨大 | 很小 | 全节点将保存所有块和 ABCI 状态,而 Gaia-lite 只保存验证人集合和一些检查点。 |
|
||||
| 电力资源 | 巨大 | 很小 | 全节点必须在具有高性能并能一直运行的机器上部署,因此功耗将是巨大的。 Gaia-lite 可以部署在与用户应用程序相同的机器上,也可以部署在独立但性能较差的机器上。 此外,Lite 客户端可以在必要时随时关闭。所以 Gaia-lite 只消耗很少的功率,即使移动设备也能满足功率需求。 |
|
||||
| 提供的 APIs | 所有 cosmos APIs | 部分模块 APIs | 全节点支持所有 cosmos API。 Gaia-lite 根据用户的配置提供模块化 API。 |
|
||||
| 安全等级 | 高 | 高 | 全节点将自行验证所有交易和块。 轻型客户端无法执行此操作,但它可以查询来自其他全节点的任何数据并独立验证数据。 因此,全节点和轻型客户端都不需要信任任何第三方节点,它们都可以实现高安全性。 |
|
||||
|
||||
根据上表,Gaia-lite 可以满足所有用户的功能和安全需求,但只需要很少的带宽、计算、存储和电力资源。
|
||||
|
||||
|
@ -42,7 +42,7 @@ ABCI 的全节点与其轻客户端的区别在于以下方面:
|
|||
|
||||
### 可信验证人集合
|
||||
|
||||
Gaia-lite的基本设计理念遵循两个规则:
|
||||
Gaia-lite 的基本设计理念遵循两个规则:
|
||||
|
||||
1. **不信任任何区块链节点,包括验证人节点和其他全节点**
|
||||
2. **只信任整个验证人集合**
|
||||
|
@ -57,4 +57,4 @@ Gaia-lite的基本设计理念遵循两个规则:
|
|||
|
||||
![change-process](../../../kr/clients/lite/pics/trustPropagate.png)
|
||||
|
||||
通常,通过可信验证人集,轻客户端可以验证包含所有预提交数据和块头数据的每个提交块。 此时块哈希、数据哈希和应用哈希是可信的。 基于此和默克尔证明,所有交易数据和 ABCI 状态也可以被验证。
|
||||
通常,通过可信验证人集,轻客户端可以验证包含所有预提交数据和块头数据的每个提交块。 此时块哈希、数据哈希和应用哈希是可信的。 基于此和默克尔证明,所有交易数据和 ABCI 状态也可以被验证。
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
| node | URL | "tcp://localhost:46657" | true | 要链接全节点的地址和端口号 |
|
||||
| laddr | URL | "tcp://localhost:1317" | true | 提供 REST 服务的地址和端口号 |
|
||||
| trust-node | bool | "false" | true | 是否信任 LCD 连接的全节点 |
|
||||
| trust-store | DIRECTORY | "$HOME/.lcd" | false | 保存检查点和验证人集的目录 |
|
||||
| trust-store | DIRECTORY | "\$HOME/.lcd" | false | 保存检查点和验证人集的目录 |
|
||||
|
||||
示例:
|
||||
|
||||
|
@ -19,5 +19,4 @@ gaiacli rest-server --chain-id=test \
|
|||
--trust-node=false
|
||||
```
|
||||
|
||||
有关Gaia-Lite RPC的更多信息,请参阅 [swagger documentation](https://cosmos.network/rpc/)
|
||||
|
||||
有关 Gaia-Lite RPC 的更多信息,请参阅 [swagger documentation](https://cosmos.network/rpc/)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 规范
|
||||
|
||||
该规范描述了如何实现 LCD。 LCD 支持模块化 API。 目前,仅支持ICS0(TendermintAPI),ICS1(密钥API)和ICS20(Key API)。 如有必要,后续可以包含更多API。
|
||||
该规范描述了如何实现 LCD。 LCD 支持模块化 API。 目前,仅支持 ICS0(TendermintAPI),ICS1(密钥 API)和 ICS20(Key API)。 如有必要,后续可以包含更多 API。
|
||||
|
||||
## 构建并验证 ABCI 状态的证明
|
||||
|
||||
|
@ -8,10 +8,10 @@
|
|||
|
||||
![Simple Merkle Tree](../../../kr/clients/lite/pics/simpleMerkleTree.png)
|
||||
|
||||
正如我们在[LCD信任传播](https://github.com/irisnet/cosmos-sdk/tree/bianjie/lcd_spec/docs/spec/lcd#trust-propagation)中所讨论的那样,可以通过检查针对可信验证人集的投票权来验证 AppHash。 这里我们只需要建立从 ABCI 状态到 AppHash 的证明。 证据包含两部分:
|
||||
正如我们在[LCD 信任传播](https://github.com/irisnet/cosmos-sdk/tree/bianjie/lcd_spec/docs/spec/lcd#trust-propagation)中所讨论的那样,可以通过检查针对可信验证人集的投票权来验证 AppHash。 这里我们只需要建立从 ABCI 状态到 AppHash 的证明。 证据包含两部分:
|
||||
|
||||
* IAVL 证明
|
||||
* 子库到 AppHash 的证明
|
||||
- IAVL 证明
|
||||
- 子库到 AppHash 的证明
|
||||
|
||||
### IAVL 证明
|
||||
|
||||
|
@ -58,23 +58,23 @@ type KeyExistsProof struct {
|
|||
|
||||
构建证明的步骤:
|
||||
|
||||
* 从根节点访问IAVL树
|
||||
* 记录 InnerNodes 中的访问节点
|
||||
* 找到目标叶节点后,将叶节点版本赋值给证明版本
|
||||
* 将当前 IAVL 树高赋值给证明高度
|
||||
* 将当前 IAVL 树根哈希赋值给证明根哈希
|
||||
* 将当前的子目录名称赋值给证明 StoreName
|
||||
* 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
|
||||
- 从根节点访问 IAVL 树
|
||||
- 记录 InnerNodes 中的访问节点
|
||||
- 找到目标叶节点后,将叶节点版本赋值给证明版本
|
||||
- 将当前 IAVL 树高赋值给证明高度
|
||||
- 将当前 IAVL 树根哈希赋值给证明根哈希
|
||||
- 将当前的子目录名称赋值给证明 StoreName
|
||||
- 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
|
||||
|
||||
验证证明的步骤:
|
||||
|
||||
* 使用证明版本中的键、值构建叶节点
|
||||
* 计算叶节点哈希
|
||||
* 将哈希值分配给第一个 innerNode 的 rightHash,然后计算第一个 innerNode 哈希值
|
||||
* 传播哈希计算过程。 如果先前的 innerNode 是下一个 innerNode 的左子节点,则将先前的 innerNode 散列分配给下一个 innerNode 的左散列。否则,将先前的 innerNode 散列分配给下一个innerNode的右散列
|
||||
* 最后 innerNode 的哈希应该等于此证明的根哈希, 否则证明无效。
|
||||
- 使用证明版本中的键、值构建叶节点
|
||||
- 计算叶节点哈希
|
||||
- 将哈希值分配给第一个 innerNode 的 rightHash,然后计算第一个 innerNode 哈希值
|
||||
- 传播哈希计算过程。 如果先前的 innerNode 是下一个 innerNode 的左子节点,则将先前的 innerNode 散列分配给下一个 innerNode 的左散列。否则,将先前的 innerNode 散列分配给下一个 innerNode 的右散列
|
||||
- 最后 innerNode 的哈希应该等于此证明的根哈希, 否则证明无效。
|
||||
|
||||
### IAVL 缺席证明
|
||||
### IAVL 缺席证明
|
||||
|
||||
众所周知,所有 IAVL 叶节点都按每个叶节点的密钥排序。 因此,我们可以在 IAVL 树的整个密钥集中计算出目标密钥的位置。 如下图所示,我们可以找到左键和右键。 如果我们可以证明左键和右键肯定存在,并且它们是相邻的节点,那么目标密钥肯定不存在。
|
||||
|
||||
|
@ -108,25 +108,25 @@ type KeyAbsentProof struct {
|
|||
|
||||
以上是缺席证明的数据结构。 构建证据的步骤:
|
||||
|
||||
* 从根节点访问IAVL树
|
||||
* 获取整个密钥集中密钥的对应索引(标记为INDEX)
|
||||
* 如果返回的索引等于0,则右索引应为0,且左节点不存在
|
||||
* 如果返回的索引等于整个密钥集的大小,则左节点索引应为INDEX-1,且右节点不存在
|
||||
* 否则,右节点索引应为INDEX,左节点索引应为INDEX-1
|
||||
* 将当前 IAVL 树高赋值给证明高度
|
||||
* 将当前 IAVL 树根哈希赋值给证明根哈希
|
||||
* 将当前的子目录名称赋值给证明 StoreName
|
||||
* 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
|
||||
- 从根节点访问 IAVL 树
|
||||
- 获取整个密钥集中密钥的对应索引(标记为 INDEX)
|
||||
- 如果返回的索引等于 0,则右索引应为 0,且左节点不存在
|
||||
- 如果返回的索引等于整个密钥集的大小,则左节点索引应为 INDEX-1,且右节点不存在
|
||||
- 否则,右节点索引应为 INDEX,左节点索引应为 INDEX-1
|
||||
- 将当前 IAVL 树高赋值给证明高度
|
||||
- 将当前 IAVL 树根哈希赋值给证明根哈希
|
||||
- 将当前的子目录名称赋值给证明 StoreName
|
||||
- 从 multistore 读取指定高度的 commitInfo 并将其赋值给证明 StoreCommitInfo
|
||||
|
||||
验证证明的步骤:
|
||||
|
||||
* 如果只存在右节点,请验证其存在的证明,并验证它是否是最左侧的节点
|
||||
* 如果仅存在左节点,请验证其存在的证据,并验证它是否是最右侧的节点
|
||||
* 如果右节点和左节点都存在,请验证它们是否相邻
|
||||
- 如果只存在右节点,请验证其存在的证明,并验证它是否是最左侧的节点
|
||||
- 如果仅存在左节点,请验证其存在的证据,并验证它是否是最右侧的节点
|
||||
- 如果右节点和左节点都存在,请验证它们是否相邻
|
||||
|
||||
### Substores 到 AppHash 的证明
|
||||
|
||||
在验证了 IAVL 证明之后,我们就可以开始验证针对 AppHash 的 substore 证明。 首先,迭代 MultiStoreCommitInfo 并通过证明 StoreName 找到 substore commitID。 验证 commitID 中的哈希是否等于证明根哈希,如果不相等则证明无效。 然后通过 substore name 的哈希对 substore commitInfo 数组进行排序。 最后,使用所有 substore commitInfo 数组构建简单的 Merkle 树,并验证 Merkle 根哈希值是否等于appHash。
|
||||
在验证了 IAVL 证明之后,我们就可以开始验证针对 AppHash 的 substore 证明。 首先,迭代 MultiStoreCommitInfo 并通过证明 StoreName 找到 substore commitID。 验证 commitID 中的哈希是否等于证明根哈希,如果不相等则证明无效。 然后通过 substore name 的哈希对 substore commitInfo 数组进行排序。 最后,使用所有 substore commitInfo 数组构建简单的 Merkle 树,并验证 Merkle 根哈希值是否等于 appHash。
|
||||
|
||||
![substore proof](../../../kr/clients/lite/pics/substoreProof.png)
|
||||
|
||||
|
@ -164,20 +164,20 @@ func SimpleHashFromHashes(hashes [][]byte) []byte {
|
|||
|
||||
## 根据验证人集验证区块头
|
||||
|
||||
上面的小节中经常提到 appHash,但可信的appHash来自哪里? 实际上,appHash 存在于区块头中,因此接下来我们需要针对 LCD 可信验证人集验证特定高度的区块头。 验证流程如下所示:
|
||||
上面的小节中经常提到 appHash,但可信的 appHash 来自哪里? 实际上,appHash 存在于区块头中,因此接下来我们需要针对 LCD 可信验证人集验证特定高度的区块头。 验证流程如下所示:
|
||||
|
||||
![commit verification](../../../kr/clients/lite/pics/commitValidation.png)
|
||||
|
||||
当可信验证人集与区块头不匹配时,我们需要尝试将验证人集更新为此块的高度。 LCD 有一条规则,即每个验证人集的变化不应超过1/3投票权。 如果目标验证人集的投票权变化超过1/3,则与可信验证人集进行比较。 我们必须验证,在目标验证人集之前是否存在隐含的验证人集变更。 只有当所有验证人集变更都遵循这条规则时,才能完成验证人集的更新。
|
||||
当可信验证人集与区块头不匹配时,我们需要尝试将验证人集更新为此块的高度。 LCD 有一条规则,即每个验证人集的变化不应超过 1/3 投票权。 如果目标验证人集的投票权变化超过 1/3,则与可信验证人集进行比较。 我们必须验证,在目标验证人集之前是否存在隐含的验证人集变更。 只有当所有验证人集变更都遵循这条规则时,才能完成验证人集的更新。
|
||||
|
||||
例如:
|
||||
|
||||
![Update validator set to height](../../../kr/clients/lite/pics/updateValidatorToHeight.png)
|
||||
|
||||
* 更新到 10000,失败,变更太大
|
||||
* 更新到 5050,失败,变更太大
|
||||
* 更新至 2575,成功
|
||||
* 更新至 5050,成功
|
||||
* 更新到 10000,失败,变更太大
|
||||
* 更新至 7525,成功
|
||||
* 更新至 10000,成功
|
||||
- 更新到 10000,失败,变更太大
|
||||
- 更新到 5050,失败,变更太大
|
||||
- 更新至 2575,成功
|
||||
- 更新至 5050,成功
|
||||
- 更新到 10000,失败,变更太大
|
||||
- 更新至 7525,成功
|
||||
- 更新至 10000,成功
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 服务提供商(Service Providers)
|
||||
|
||||
我们将“服务提供商”定义为可以为最终用户提供服务的实体,这些实体涉及与基于 Cosmos-SDK 的区块链(包括Cosmos Hub)的某种形式的交互。更具体地说,本文档将集中于与 token 的交互。
|
||||
我们将“服务提供商”定义为可以为最终用户提供服务的实体,这些实体涉及与基于 Cosmos-SDK 的区块链(包括 Cosmos Hub)的某种形式的交互。更具体地说,本文档将集中于与 token 的交互。
|
||||
|
||||
本节不涉及想要提供[轻客户端](https://github.com/cosmos/cosmos-sdk/tree/master/docs/interfaces/lite)功能的钱包开发者。服务提供商将作为最终用户的区块链的可信接入点。
|
||||
|
||||
|
@ -9,12 +9,12 @@
|
|||
有三个主要部分需要考虑:
|
||||
|
||||
- 全节点:与区块链交互。
|
||||
- Rest Server:它充当 HTTP 调用的中继者。
|
||||
- Rest API:为 Rest Server 定义可用端点。
|
||||
- Rest Server:它充当 HTTP 调用的中继者。
|
||||
- Rest API:为 Rest Server 定义可用端点。
|
||||
|
||||
##运行全节点
|
||||
## 运行全节点
|
||||
|
||||
###安装和配置
|
||||
### 安装和配置
|
||||
|
||||
我们将描述为 Cosmos Hub 运行和交互全节点的步骤。对于其他基于 SDK 的区块链,该过程是类似的。
|
||||
|
||||
|
@ -28,19 +28,19 @@
|
|||
|
||||
#### 创建秘钥对
|
||||
|
||||
生成新秘钥(默认使用 secp256k1椭圆曲线算法):
|
||||
生成新秘钥(默认使用 secp256k1 椭圆曲线算法):
|
||||
|
||||
```bash
|
||||
gaiacli keys add <your_key_name>
|
||||
```
|
||||
|
||||
系统将要求您为此密钥对输入密码(至少8个字符)。该命令返回4个信息:
|
||||
系统将要求您为此密钥对输入密码(至少 8 个字符)。该命令返回 4 个信息:
|
||||
|
||||
- `NAME`: 秘钥名称。
|
||||
- `TYPE`:秘钥类型,总是`local`。
|
||||
- `ADDRESS`:您的地址,用于接收资金。
|
||||
- `PUBKEY`:您的公钥 Your public key. Useful for validators.
|
||||
- `MNEMONIC`: 由24个单词组成的助记词。 **将这个助记词保存在安全的地方**,它用于在您忘记密码时恢复您的私钥。
|
||||
- `PUBKEY`:您的公钥, 用于验证者.
|
||||
- `MNEMONIC`: 由 24 个单词组成的助记词。 **将这个助记词保存在安全的地方**,它用于在您忘记密码时恢复您的私钥。
|
||||
|
||||
您可以输入以下命令查看所有可用密钥:
|
||||
|
||||
|
@ -56,7 +56,7 @@ gaiacli keys list
|
|||
gaiacli account <YOUR_ADDRESS>
|
||||
```
|
||||
|
||||
*注意:当您查询没有 token 帐户的余额时,您将得到以下错误:找不到地址为<YOUR_ADDRESS>的帐户。这是预料之中的!我们正在努力改进我们的错误提示信息。*
|
||||
_注意:当您查询没有 token 帐户的余额时,您将得到以下错误:找不到地址为<YOUR_ADDRESS>的帐户。这是预料之中的!我们正在努力改进我们的错误提示信息。_
|
||||
|
||||
#### 通过 CLI 发送代币
|
||||
|
||||
|
@ -64,27 +64,28 @@ gaiacli account <YOUR_ADDRESS>
|
|||
|
||||
```bash
|
||||
gaiacli tx send <from_key_or_address> <to_address> <amount> \
|
||||
--chain-id=<name_of_testnet_chain>
|
||||
--chain-id=<name_of_testnet_chain>
|
||||
```
|
||||
|
||||
参数:
|
||||
|
||||
- `<from_key_or_address>`: 发送账户的名称或地址。
|
||||
- `<to_address>`: 接收者地址。
|
||||
- `<amount>`: 接受`<value|coinName>`格式的参数,例如 `10faucetToken`。
|
||||
|
||||
标识:
|
||||
|
||||
- `--chain-id`: 此标志允许您指定链的ID,不同的testnet链和主链会有不同的 id。
|
||||
- `--chain-id`: 此标志允许您指定链的 ID,不同的 testnet 链和主链会有不同的 id。
|
||||
|
||||
#### 帮助
|
||||
|
||||
如果您需要进行其他操作,最合适的命令是:
|
||||
|
||||
```bash
|
||||
gaiacli
|
||||
gaiacli
|
||||
```
|
||||
|
||||
它将显示所有可用命令。对于每个命令,您可以使用`--help`标识来获取更多信息。
|
||||
它将显示所有可用命令。对于每个命令,您可以使用`--help`标识来获取更多信息。
|
||||
|
||||
## 设置 Rest 服务器
|
||||
|
||||
|
@ -97,10 +98,10 @@ gaiacli rest-server --node=<full_node_address:full_node_port>
|
|||
```
|
||||
|
||||
Flags:
|
||||
- `--trust-node`: 布尔类型。如果为`true`,轻节点校验将被禁用。如果为`false`, 则会校验返回结果。 对于服务提供商,应将其设置为`true`。默认情况下,它设置为`true`。
|
||||
- `--node`: 全节点的IP地址和端口。格式为` <full_node_address:full_node_port>`。如果全节点在同一台机器上,则地址应为`tcp:// localhost:26657`。
|
||||
- `--laddr`: 此标识允许您指定 Rest 服务器的地址和端口(默认为“1317”)。通常只使用这个标识指定端口,此时只需输入“localhost”作为地址,格式为`<rest_server_address:port>`。
|
||||
|
||||
- `--trust-node`: 布尔类型。如果为 `true`,轻节点校验将被禁用。如果为 `false`, 则会校验返回结果。 对于服务提供商,应将其设置为 `true`。默认情况下,它设置为 `true`。
|
||||
- `--node`: 全节点的 IP 地址和端口。格式为 `<full_node_address:full_node_port>`。如果全节点在同一台机器上,则地址应为 `tcp:// localhost:26657`。
|
||||
- `--laddr`: 此标识允许您指定 Rest 服务器的地址和端口(默认为“1317”)。通常只使用这个标识指定端口,此时只需输入 “localhost” 作为地址,格式为`<rest_server_address:port>`。
|
||||
|
||||
### 监听入向交易
|
||||
|
||||
|
@ -112,11 +113,11 @@ Flags:
|
|||
|
||||
Rest API 记录了可用于与全节点交互的所有可用端点,您可以在[这里](https://cosmos.network/rpc/)查看。
|
||||
|
||||
API 针对每种类别的端点归纳为 ICS 标准。例如,[ICS20](https://cosmos.network/rpc/#/ICS20/)描述了API 与 token 的交互。
|
||||
API 针对每种类别的端点归纳为 ICS 标准。例如,[ICS20](https://cosmos.network/rpc/#/ICS20/)描述了 API 与 token 的交互。
|
||||
|
||||
为了给开发者提供更大的灵活性,我们提供了生成未签名交易、[签名](https://cosmos.network/rpc/#/ICS20/post_tx_sign)和[广播](https://cosmos.network/rpc/#/ICS20/post_tx_broadcast)等不同的 API 端点。这允许服务提供商使用他们自己的签名机制。
|
||||
|
||||
为了生成一个未签名交易(例如 [coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)),你需要在`base_req`的主体中使用`generate_only`字段。
|
||||
为了生成一个未签名交易(例如 [coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)),你需要在 `base_req` 的主体中使用 `generate_only` 字段。
|
||||
|
||||
## Cosmos SDK 交易签名
|
||||
|
||||
|
@ -144,19 +145,19 @@ Cosmos SDK 签名是一个相当简单的过程。
|
|||
交易构造接口将生成 `"fee"`、 `"msgs"` 和 `"memo"` 等字段.
|
||||
|
||||
You can load the mempool of a full node or validator with a sequence of uncommitted transactions with incrementing
|
||||
sequence numbers and it will mostly do the correct thing.
|
||||
sequence numbers and it will mostly do the correct thing.
|
||||
|
||||
`"account_number"` 和 `"sequence"` 字段可以直接从区块链或本地缓存中查询。 错误的获取了这些数值和chainId,是产生无效签名错误的常见原因。您可以通过加载全节点或验证人中的 mempool 来获取未提交交易的自增序号,这样大大增加成功概率。
|
||||
`"account_number"` 和 `"sequence"` 字段可以直接从区块链或本地缓存中查询。 错误的获取了这些数值和 chainId,是产生无效签名错误的常见原因。您可以通过加载全节点或验证人中的 mempool 来获取未提交交易的自增序号,这样大大增加成功概率。
|
||||
|
||||
您可以使用递增序列号的一系列未提交事务加载完整节点或验证器的mempool,它将主要执行正确的操作。
|
||||
您可以使用递增序列号的一系列未提交事务加载完整节点或验证器的 mempool,它将主要执行正确的操作。
|
||||
|
||||
在签名之前,所有键都要按字典顺序排序,并从 JSON 输出中删除所有空格。
|
||||
|
||||
签名编码是 ECDSArands 的 64字节连结(即`r || s`),其中`s`按字典顺序小于其反转以防止延展性。 这就像以太坊一样,但没有用户公钥恢复的额外字节,因为 Tendermint 假定公钥一定会提供。
|
||||
签名编码是 ECDSArands 的 64 字节连结(即`r || s`),其中`s`按字典顺序小于其反转以防止延展性。 这就像以太坊一样,但没有用户公钥恢复的额外字节,因为 Tendermint 假定公钥一定会提供。
|
||||
|
||||
已签名交易中的签名和公钥示例:
|
||||
|
||||
``` json
|
||||
```json
|
||||
{
|
||||
"type": "cosmos-sdk/StdTx",
|
||||
"value": {
|
||||
|
|
|
@ -6,7 +6,7 @@ Documentation has been translated for **reference use only** and may contain typ
|
|||
|
||||
Please refer to the official english version of the documentation for the latest and accurate information.
|
||||
|
||||
## Cosmos SDK文档翻译
|
||||
## Cosmos SDK 文档翻译
|
||||
|
||||
本文档跟踪官方 Cosmos SDK 文档的中文翻译进度。
|
||||
|
||||
|
@ -18,7 +18,7 @@ Please refer to the official english version of the documentation for the latest
|
|||
|
||||
### README.md
|
||||
|
||||
- Synced until commit [1c326ea5](https://github.com/cosmos/cosmos-sdk/commit/1c326ea524eade1da8771cd7e4343012203a166f) (2019-05-27)
|
||||
- Synced until commit [b18bd06a](https://github.com/cosmos/cosmos-sdk/commit/b18bd06a364e6ac15f22423e6b66a9feb3eeae93) (2019-12-10)
|
||||
|
||||
### [`concepts`](../concepts/)
|
||||
|
||||
|
@ -34,7 +34,7 @@ Please refer to the official english version of the documentation for the latest
|
|||
|
||||
### [`intro`](../intro/)
|
||||
|
||||
- Synced until commit [1c326ea5](https://github.com/cosmos/cosmos-sdk/commit/1c326ea524eade1da8771cd7e4343012203a166f) (2019-05-27)
|
||||
- Synced until commit [be194ca1](https://github.com/cosmos/cosmos-sdk/commit/be194ca1b7d159590a0147da3226b7e09eaa3f61) (2020-07-07)
|
||||
|
||||
### [`modules`](../modules/)
|
||||
|
||||
|
@ -43,4 +43,3 @@ Please refer to the official english version of the documentation for the latest
|
|||
### [`clients`](../clients/)
|
||||
|
||||
- Synced until Commit [7558f760](https://github.com/cosmos/cosmos-sdk/commit/7558f7607918b6337a8b58b8f956d6776f503138) (2019-05-13)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 介绍
|
||||
|
||||
此目录包含对cosmos sdk的相关介绍
|
||||
此目录包含对 cosmos sdk 的相关介绍
|
||||
|
||||
1. [概述](./overview.md)
|
||||
|
||||
|
@ -8,6 +8,6 @@
|
|||
|
||||
3. [应用架构](./sdk-app-architecture.md)
|
||||
|
||||
4. [Cosmos SDK设计概述](./sdk-design.md)
|
||||
4. [Cosmos SDK 设计概述](./sdk-design.md)
|
||||
|
||||
了解完成相关介绍后,可以前往 [基础文档](../basics/README.md) 了解更多。
|
||||
了解完成相关介绍后,可以前往 [基础文档](../basics/README.md) 了解更多。
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
> 我们假设蓬勃发展的 Cosmos-SDK 模块生态中会包含错误或恶意的模块。
|
||||
|
||||
Cosmos SDK旨在通过以对象能力系统作为基础来解决此威胁。
|
||||
Cosmos SDK 旨在通过以对象能力系统作为基础来解决此威胁。
|
||||
|
||||
> 对象能力系统的结构特性有利于代码设计模块化,并确保代码实现的可靠封装。
|
||||
>
|
||||
|
@ -15,21 +15,14 @@ Cosmos SDK旨在通过以对象能力系统作为基础来解决此威胁。
|
|||
> 因此,可以在存在包含未知或(可能)恶意代码的新对象的情况下建立和维护这些安全属性。
|
||||
>
|
||||
> 这些结构属性源于管理对已存在对象的访问的两个规则:
|
||||
> 1. 只有在对象A持有对象B的引用,A才可以向B发送一条消息,。
|
||||
> 2. 只有对象A收到了一条包含对象C引用的消息,A才可以获得C的引用。
|
||||
>
|
||||
> 1. 只有在对象 A 持有对象 B 的引用,A 才可以向 B 发送一条消息
|
||||
> 2. 只有对象 A 收到了一条包含对象 C 引用的消息,A 才可以获得 C 的引用
|
||||
>
|
||||
> 根据这两条规则,一个对象只有通过一条先前存在的引用链获得另一个对象的引用,简而言之,“只有连接才能产生连接”。
|
||||
|
||||
关于对象能力(object-capabilities),可以阅读这边[文章](http://habitatchronicles.com/2017/05/what-are-capabilities/)了解更多。
|
||||
|
||||
严格来说,Golang 由于几个问题没有完全实现对象能力:
|
||||
|
||||
+ 无处不在地引入原始(基础)模块(比如unsafe, os)
|
||||
+ 无处不在地重写模块变量
|
||||
+ 存在2个以上goroutine时的数据竞态漏洞可以创建非法的接口值
|
||||
|
||||
第一点很容易通过审计import和使用适当的依赖版本控制系统(如Dep)来捕获。但第二点和第三点就不容易了,需要成本进行代码审核。
|
||||
|
||||
|
||||
## 对象能力模式实践
|
||||
|
||||
想法就是只暴露完成工作所需要的部分。
|
||||
|
@ -51,14 +44,6 @@ var sumValue := externalModule.ComputeSumValue(account)
|
|||
var sumValue := externalModule.ComputeSumValue(*account)
|
||||
```
|
||||
|
||||
在Cosmos SDK中,你可以看到[gaia app](https://github.com/cosmos/cosmos-sdk/blob/master/simapp/app.go)中对该原则的实践。
|
||||
在 Cosmos SDK 中,你可以看到[gaia app](https://github.com/cosmos/cosmos-sdk/blob/master/simapp/app.go)中对该原则的实践。
|
||||
|
||||
```go
|
||||
// register message routes
|
||||
app.Router().
|
||||
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
|
||||
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
|
||||
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
|
||||
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper))
|
||||
```
|
||||
+++ https://github.com/cosmos/gaia/blob/master/app/app.go#L197-L209
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
# Cosmos SDK 介绍
|
||||
|
||||
## 什么是Cosmos SDK
|
||||
## 什么是 Cosmos SDK
|
||||
|
||||
[Cosmos SDK](https://github.com/cosmos/cosmos-sdk)是开源框架,用于构建类似Cosmos Hub等基于POS共识算法的多元资产公有区块链,以及基于权威证明共识算法的许可链。使用Cosmos SDK构建的区块链通常被称为特定应用区块链(专用区块链)(application-specific blockchains)。
|
||||
[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)。
|
||||
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)下非常有用,但在构建复杂的去中心化平台时无法达到要求。更具体地说,智能合约在灵活性、所有权、性能方面会受到限制。
|
||||
目前在区块链领域中,一种开发模式是通过像以太坊这样的虚拟机区块链展开,即开发者在现有的区块链上通过智能合约的方式去构建去中心化应用。虽然智能合约在单用途应用场景(如 ICO)下非常有用,但在构建复杂的去中心化平台时无法达到要求。更具体地说,智能合约在灵活性、所有权、性能方面会受到限制。
|
||||
|
||||
特定应用区块链提供了与虚拟机区块链截然不同的开发模式。特定应用区块链是面向单个具体应用程序的高度定制化区块链:开发者可以完全自由地做出让应用程序可以达到最佳运行状态的设计决策。他们也可以提供更好的主导权、安全性和性能。
|
||||
|
||||
了解更多可参考[特定应用区块链](https://docs.cosmos.network/master/intro/why-app-specific.html)。
|
||||
|
||||
## 为什么选择Cosmos SDK?
|
||||
## 为什么选择 Cosmos SDK?
|
||||
|
||||
Cosmos SDK是目前最先进的构建可定制化特定应用区块链的框架。以下是一些可能让你希望通过Cosmos SDK构建去中心化应用的原因:
|
||||
Cosmos SDK 是目前最先进的构建可定制化特定应用区块链的框架。以下是一些可能让你希望通过 Cosmos SDK 构建去中心化应用的原因:
|
||||
|
||||
- Cosmos SDK 默认的共识引擎是[Tendermint Core](https://github.com/tendermint/tendermint). Tendermint是目前最成熟的、唯一的BFT共识引擎。它被广泛应用于行业中,被认为是构建POS系统的最佳标准共识引擎。
|
||||
- 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 是开源的,你可以通过组合式[modules](https://docs.cosmos.network/master/x/)轻松地构建出区块链。随着 SDK 生态中各种开源模块的发展,通过 Cosmos SDK 构建复杂的去中心化平台会变得越来越容易。
|
||||
|
||||
- Cosmos SDK 受基于功能的安全性所启发,并受益于多年来在区块链状态机领域的经验。这让Cosmos SDK成为一个非常安全的构建区块链的环境。
|
||||
- Cosmos SDK 受基于功能的安全性所启发,并受益于多年来在区块链状态机领域的经验。这让 Cosmos SDK 成为一个非常安全的构建区块链的环境。
|
||||
|
||||
- 最重要的是,Cosmos SDK已经构建出了多个正在运行中的特定应用区块链。例如,Cosmos HUB,IRIS HUB,Binance Chain, Terra 和 Kava。更多机遇Cosmos SDK构建的区块链参考[这里](https://cosmos.network/ecosystem)。
|
||||
- 最重要的是,Cosmos SDK 已经构建出了多个正在运行中的特定应用区块链。例如,Cosmos HUB,IRIS HUB,Binance Chain, Terra 和 Kava。更多基于 Cosmos SDK 构建的区块链参考[这里](https://cosmos.network/ecosystem)。
|
||||
|
||||
## 开始使用Cosmos SDK
|
||||
## 开始使用 Cosmos SDK
|
||||
|
||||
了解更多请参考[SDK应用架构](https://docs.cosmos.network/master/intro/sdk-app-architecture.html)。
|
||||
了解更多请参考[SDK 应用架构](https://docs.cosmos.network/master/intro/sdk-app-architecture.html)。
|
||||
|
||||
了解如何从头建立特定应用区块链,请参考[SDK教程](https://cosmos.network/docs/tutorial)。
|
||||
了解如何从头建立特定应用区块链,请参考[SDK 教程](https://cosmos.network/docs/tutorial)。
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
区块链的核心是[复制确定状态机](https://en.wikipedia.org/wiki/State_machine_replication)(replicated deterministic state machine)。
|
||||
|
||||
状态机是计算机科学领域的一个概念,即一台机器可以具有多个状态,但在任意给定时刻只具有一个确定的状态。我们用`state`描述系统当前状态,`transactions`触发状态转换。
|
||||
状态机是计算机科学领域的一个概念,即一台机器可以具有多个状态,但在任意给定时刻只具有一个确定的状态。我们用 `state` 描述系统当前状态,`transactions` 触发状态转换。
|
||||
|
||||
给定一个状态S和Transaction T,状态机会返回新的状态S'。
|
||||
给定一个状态 S 和 Transaction T,状态机会返回新的状态 S'。
|
||||
|
||||
```
|
||||
+--------+ +--------+
|
||||
|
@ -16,7 +16,7 @@
|
|||
+--------+ +--------+
|
||||
```
|
||||
|
||||
在实际中,Transaction集会被打包进区块中,以让处理过程更加高效。给定一个状态S和一个包含Transaction集 B的区块,状态机就会返回新的状态S'。
|
||||
在实际中,Transaction 集会被打包进区块中,以让处理过程更加高效。给定一个状态 S 和一个包含 Transaction 集 B 的区块,状态机就会返回新的状态 S'。
|
||||
|
||||
```
|
||||
+--------+ +--------+
|
||||
|
@ -26,13 +26,13 @@
|
|||
+--------+ +--------+
|
||||
```
|
||||
|
||||
在区块链的上下文环境中,状态机是确定的。这意味着节点从给定状态开始,重放相同的Transaction序列,总能得到相同的最终状态。
|
||||
在区块链的上下文环境中,状态机是确定的。这意味着节点从给定状态开始,重放相同的 Transaction 序列,总能得到相同的最终状态。
|
||||
|
||||
Cosmos SDK为开发者提供了最大程度的灵活性去定义应用程序的状态,Transaction类型和状态转换功能。接下来的章节中会更详细地介绍使用SDK构建状态机的过程。在此之前,先让我们看看如何使用Tendermint复制状态机。
|
||||
Cosmos SDK 为开发者提供了最大程度的灵活性去定义应用程序的状态,Transaction 类型和状态转换功能。接下来的章节中会更详细地介绍使用 SDK 构建状态机的过程。在此之前,先让我们看看如何使用 Tendermint 复制状态机。
|
||||
|
||||
## Tendermint
|
||||
|
||||
得益于Cosmos SDK,开发者只需要定义好状态机,[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html)就会处理好状态复制的工作。
|
||||
得益于 Cosmos SDK,开发者只需要定义好状态机,[Tendermint](https://tendermint.com/docs/introduction/what-is-tendermint.html) 就会处理好状态复制的工作。
|
||||
|
||||
```
|
||||
^ +-------------------------------+ ^
|
||||
|
@ -50,13 +50,13 @@ Blockchain node | | Consensus | |
|
|||
v +-------------------------------+ v
|
||||
```
|
||||
|
||||
[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) 是一个与应用程序无关的引擎,负责处理区块链的网络层和共识层。这意味着 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集合可以按照状态机中写定的规则更改。
|
||||
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://tendermint.com/docs/spec/abci/)的接口向应用程序传递Transactions,该接口必须由应用程序实现。
|
||||
Tendermint 通过被称为 [ABCI](https://tendermint.com/docs/spec/abci/) 的接口向应用程序传递 Transactions,该接口必须由应用程序实现。
|
||||
|
||||
```
|
||||
+---------------------+
|
||||
|
@ -76,16 +76,16 @@ Tendermint通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口
|
|||
+---------------------+
|
||||
```
|
||||
|
||||
需要注意的是,Tendermint仅处理transaction字节,它并不知道这些字节的含义。Tendermint所做的只是对transaction字节进行确定性地排序。Tendermint通过ABCI向应用程序传递字节,并期望返回状态码以获知包含在transactions中的messages是否成功处理。
|
||||
需要注意的是,Tendermint 仅处理 transaction 字节,它并不知道这些字节的含义。Tendermint 所做的只是对 transaction 字节进行确定性地排序。Tendermint 通过 ABCI 向应用程序传递字节,并期望返回状态码以获知包含在 transactions 中的 messages 是否成功处理。
|
||||
|
||||
以下是ABCI最重要的Messages:
|
||||
以下是 ABCI 最重要的 Messages:
|
||||
|
||||
`CheckTx`:当Tendermint Core接收到一个Transaction时,它会传递给应用程序以检查是否满足一些基本要求。`CheckTx` 用于保护全节点的内存池免受垃圾transactions攻击。`AnteHandler`这一特殊处理程序用于执行一系列验证步骤,例如检查手续费是否足够以及验证签名。如果检查通过,该transaction会被添加进[mempool](https://tendermint.com/docs/spec/reactors/mempool/functionality.html#mempool-functionality),并广播给其他共识节点。请注意,此时transactions尚未被`CheckTx`处理(即未进行状态修改),因为它们还没有被包含在区块中。
|
||||
`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)一起再次执行。
|
||||
`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) 一起再次执行。
|
||||
|
||||
`BeginBlock/EndBlock`:无论区块中是否包含transaction,messages都会在每个区块的开头和结尾处执行。触发自动执行的逻辑是很有用的。但需要谨慎使用,因为计算量庞大的循环会严重降低区块链的性能,而无限循环甚至会导致区块链宕机。
|
||||
`BeginBlock/EndBlock`:无论区块中是否包含 transaction,messages 都会在每个区块的开头和结尾处执行。触发自动执行的逻辑是很有用的。但需要谨慎使用,因为计算量庞大的循环会严重降低区块链的性能,而无限循环甚至会导致区块链宕机。
|
||||
|
||||
获知更多关于ABCI的详细内容可以访问[Tendermint docs](https://tendermint.com/docs/spec/abci/abci.html#overview).
|
||||
获知更多关于 ABCI 的详细内容可以访问 [Tendermint docs](https://tendermint.com/docs/spec/abci/abci.html#overview).
|
||||
|
||||
基于Tendermint构建的任何程序都需要实现ABCI接口,以便和底层的本地Tendermint引擎通信。幸运的是,您不需要实现ABCI接口,Cosmos SDK 以 [baseapp](https://docs.cosmos.network/master/intro/sdk-design.html#baseapp) 的形式提供了样板实现。
|
||||
基于 Tendermint 构建的任何程序都需要实现 ABCI 接口,以便和底层的本地 Tendermint 引擎通信。幸运的是,您不需要实现 ABCI 接口,Cosmos SDK 以 [baseapp](https://docs.cosmos.network/master/intro/sdk-design.html#baseapp) 的形式提供了样板实现。
|
||||
|
|
|
@ -1,60 +1,35 @@
|
|||
# Cosmos SDK的主要组件
|
||||
# Cosmos SDK 的主要组件
|
||||
|
||||
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)。
|
||||
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)。
|
||||
|
||||
下面的简化视图展示了当通过`DeliverTx`从Tendermint 转移transactions时,基于Cosmos SDK构建的应用程序如何处理这些transactions。
|
||||
下面的简化视图展示了当通过 `DeliverTx` 从 Tendermint 转移 transactions 时,基于 Cosmos SDK 构建的应用程序如何处理这些 transactions。
|
||||
|
||||
- 解码从Tendermint共识引擎中接收到的`transactions`(Tendermint只能处理 `[]bytes` 类型的数据)
|
||||
|
||||
- 从`transactions`中提取`messages`并进行基本的健全性检查。
|
||||
|
||||
- 将每个Message路由到对应的模块中,以进行相应处理。
|
||||
|
||||
- 提交状态更改。
|
||||
1. 解码从 Tendermint 共识引擎中接收到的 `transactions`(Tendermint 只能处理 `[]bytes` 类型的数据)
|
||||
2. 从 `transactions` 中提取 `messages` 并进行基本的健全性检查。
|
||||
3. 将每个 Message 路由到对应的模块中,以进行相应处理。
|
||||
4. 提交状态更改。
|
||||
|
||||
## BaseApp
|
||||
|
||||
`baseapp` 是 Cosmos SDK 应用程序的样本实现,它拥有能够处理和底层共识引擎的连接的ABCI实现。通常,Cosmos SDK 应用程序通过嵌入[`app.go`](https://docs.cosmos.network/master/basics/app-anatomy.html#core-application-file)来实现拓展。查看示例请参考SDK应用教程:
|
||||
`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
|
||||
+++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/app.go#L72-L9
|
||||
|
||||
// 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` 的目标是在存储和可拓展状态机之间提供安全的接口,同时尽可能少地定义状态机(对 ABCI 保持不变)。
|
||||
|
||||
更多关于`baseapp`的信息,请点击[这里](https://docs.cosmos.network/master/core/baseapp.html)。
|
||||
|
||||
## Multistore
|
||||
|
||||
Cosmos SDK 为状态持久化提供了`multistore`。Multistore允许开发者声明任意数量的`KVStores`。这些`KVStores`只接受`[]byte`类型的值,因此任何自定义的结构都需要在存储之前使用[codec](https://docs.cosmos.network/master/core/encoding.html)进行编码。
|
||||
Cosmos SDK 为状态持久化提供了 `multistore`。Multistore 允许开发者声明任意数量的 `KVStores`。这些 `KVStores` 只接受 `[]byte` 类型的值,因此任何自定义的结构都需要在存储之前使用[codec](https://docs.cosmos.network/master/core/encoding.html)进行编码。
|
||||
|
||||
Multistore抽象用于区分不同模块的状态,每个都由其自己的模块管理。更多关于multistore的信息请点击[这里](https://docs.cosmos.network/master/core/store.html#multistore)。
|
||||
Multistore 抽象用于区分不同模块的状态,每个都由其自己的模块管理。更多关于 multistore 的信息请点击[这里](https://docs.cosmos.network/master/core/store.html#multistore)。
|
||||
|
||||
## Modules
|
||||
|
||||
Cosmos SDK的强大之处在于其模块化开发的理念。SDK应用程序是通过组合一系列可互操作的模块而构建的。每个模块定义了状态子集,并包含其Messages与Transactions的处理器,同时SDK负责将每个Message路由到对应的模块中。
|
||||
Cosmos SDK 的强大之处在于其模块化开发的理念。SDK 应用程序是通过组合一系列可互操作的模块而构建的。每个模块定义了状态子集,并包含其 Messages 与 Transactions 的处理器,同时 SDK 负责将每个 Message 路由到对应的模块中。
|
||||
|
||||
以下的简化视图展示了应用链中的每个全节点如何处理有效区块中的Transaction。
|
||||
以下的简化视图展示了应用链中的每个全节点如何处理有效区块中的 Transaction。
|
||||
|
||||
```
|
||||
+
|
||||
|
@ -101,14 +76,12 @@ Cosmos SDK的强大之处在于其模块化开发的理念。SDK应用程序是
|
|||
v
|
||||
```
|
||||
|
||||
每个模块都可以看成是一个小的状态机。开发者需要定义由模块处理的状态子集,同时自定义改变状态的Message类型(注意:`messages`是通过`baseapp`从`transactions`中提取的)。通常,每个模块会在`multistore`中声明自己的`KVStore`,以存储自定义的状态子集。大部分开发者在构建自己的模块时,需要访问其它第三方模块。由于Cosmos SDK是一个开放的框架,其中的一些模块可能是恶意的,这意味着需要一套安全原则去考虑模块间的交互。这些原则都基于[object-capabilities](https://docs.cosmos.network/master/core/ocap.html)。事实上,这也意味着,并不是要让每个模块都保留其他模块的访问控制列表,而是每个模块都实现了被称为`keepers`的特殊对象,它们可以被传递给其他模块,以授予一组预定义的功能。
|
||||
每个模块都可以看成是一个小的状态机。开发者需要定义由模块处理的状态子集,同时自定义改变状态的 Message 类型(注意:`messages` 是通过 `baseapp` 从 `transactions` 中提取的)。通常,每个模块会在 `multistore` 中声明自己的 `KVStore`,以存储自定义的状态子集。大部分开发者在构建自己的模块时,需要访问其它第三方模块。由于 Cosmos SDK 是一个开放的框架,其中的一些模块可能是恶意的,这意味着需要一套安全原则去考虑模块间的交互。这些原则都基于[object-capabilities](https://docs.cosmos.network/master/core/ocap.html)。事实上,这也意味着,并不是要让每个模块都保留其他模块的访问控制列表,而是每个模块都实现了被称为 `keepers` 的特殊对象,它们可以被传递给其他模块,以授予一组预定义的功能。
|
||||
|
||||
SDK模块被定义在SDK的 `x/`文件夹中,一些核心的模块包括:
|
||||
SDK 模块被定义在 SDK 的 `x/` 文件夹中,一些核心的模块包括:
|
||||
|
||||
- `x/auth`:用于管理账户和签名。
|
||||
|
||||
- `x/bank`:用于启动 tokens 和 token 转账。
|
||||
- `x/staking` + `s/slashing`:用于构建 POS 区块链。
|
||||
|
||||
- `x/staking` + `s/slashing`:用于构建POS区块链。
|
||||
|
||||
除了`x/`文件夹中已经存在的任何人都可以使用的模块,SDK还允许您构建自己自定义的模块,您可以在[教程中查看示例](https://cosmos.network/docs/tutorial/keeper.html)。
|
||||
除了 `x/` 文件夹中已经存在的任何人都可以使用的模块,SDK 还允许您构建自己自定义的模块,您可以在[教程中查看示例](https://cosmos.network/docs/tutorial/keeper.html)。
|
||||
|
|
|
@ -24,19 +24,17 @@ Blockchain node | | Consensus | |
|
|||
v +-------------------------------+ v
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 智能合约的局限是什么?
|
||||
|
||||
早在2014年,像Ethereum这样的虚拟机区块链就满足了可编程性的需求。当时,开发去中心化应用的选项非常有限。许多开发者只能在复杂且有限制的比特币脚本语言上开发,或者fork难以运行和定制化的比特币代码。
|
||||
早在 2014 年,像 Ethereum 这样的虚拟机区块链就满足了可编程性的需求。当时,开发去中心化应用的选项非常有限。许多开发者只能在复杂且有限制的比特币脚本语言上开发,或者 fork 难以运行和定制化的比特币代码。
|
||||
|
||||
虚拟机区块链在当时提出了新的价值主张。他们的状态机集成了虚拟机,从而能够执行被称为智能合约的图灵完备程序。虽然智能合约在一次性事件(如ICO)的应用场景下非常有用,但在构建复杂的去中心化平台时无法达到要求。以下是原因:
|
||||
虚拟机区块链在当时提出了新的价值主张。他们的状态机集成了虚拟机,从而能够执行被称为智能合约的图灵完备程序。虽然智能合约在一次性事件(如 ICO)的应用场景下非常有用,但在构建复杂的去中心化平台时无法达到要求。以下是原因:
|
||||
|
||||
智能合约通常由可以被底层虚拟机解释的特定编程语言开发。这些编程语言常常并不成熟,并受限于虚拟机本身。例如,以太坊虚拟机并不允许开发者实现代码的自动执行。开发或者也被限制于EVM的账户体系,他们只能从一组有限的功能中进行加密操作。虽然这些只是示例,但它们展现了智能合约环境通常缺少灵活性。
|
||||
- 智能合约通常由可以被底层虚拟机解释的特定编程语言开发。这些编程语言常常并不成熟,并受限于虚拟机本身。例如,以太坊虚拟机并不允许开发者实现代码的自动执行。开发或者也被限制于 EVM 的账户体系,他们只能从一组有限的功能中进行加密操作。虽然这些只是示例,但它们展现了智能合约环境通常缺少**灵活性**。
|
||||
|
||||
智能合约都运行在同一台虚拟机上,这意味着它们会相互争夺资源,并严重影响执行效果。即使状态机分分成多个子集(例如通过分片技术),智能合约依然需要由虚拟机解释,比起在状态机上实现的本地应用程序,这依然限制了合约应用的性能。( 我们的基准测试表明,在删除虚拟机后,应用程序的性能提高了10倍。)
|
||||
- 智能合约都运行在同一台虚拟机上,这意味着它们会相互争夺资源,并严重影响执行效果。即使状态机切分成多个子集(例如通过分片技术),智能合约依然需要由虚拟机解释,比起在状态机上实现的本地应用程序,这依然限制了合约应用的**性能**。(我们的基准测试表明,在删除虚拟机后,应用程序的性能提高了 10 倍。)
|
||||
|
||||
智能合约共享底层环境带来的另一个问题是主导权的最终限制。去中心化应用是一个涉及众多参与者的生态系统,如果去中心化应用建立在通用的虚拟机区块链上,利益相关者(stakeholders)对他们的应用程序就只有非常有限的主导权,并最终会被底层区块链的治理所取代。如果该应用程序还存在着漏洞,那任何人都无能为力。
|
||||
- 智能合约共享底层环境带来的另一个问题是**主导权**的最终限制。去中心化应用是一个涉及众多参与者的生态系统,如果去中心化应用建立在通用的虚拟机区块链上,利益相关者(stakeholders)对他们的应用程序就只有非常有限的主导权,并最终会被底层区块链的治理所取代。如果该应用程序还存在着漏洞,那任何人都无能为力。
|
||||
|
||||
特定应用区块链的出现,就是要解决上述问题。
|
||||
|
||||
|
@ -46,17 +44,17 @@ Blockchain node | | Consensus | |
|
|||
|
||||
特定应用区块链赋予了开发者最大的灵活性:
|
||||
|
||||
- 在Cosmos区块链中,状态机通常通过被称为[ABCI](https://tendermint.com/docs/spec/abci/)的接口和底层共识引擎连接。该接口可以被包装为任何编程语言,开发者可以自己决定用哪种编程语言来构建状态机。
|
||||
- 在 Cosmos 区块链中,状态机通常通过被称为 [ABCI](https://tendermint.com/docs/spec/abci/) 的接口和底层共识引擎连接。该接口可以被包装为任何编程语言,开发者可以自己决定用哪种编程语言来构建状态机。
|
||||
|
||||
- 开发者在构建状态机时有多种选择,目前最常用的是Cosmos SDK,但也有其他的框架,如Lotion和Weave等。开发者通常都是基于他们使用的编程语言来选择使用哪一种框架(Cosmos SDK和Weave基于Golang,Lotion则基于JavaScript)。
|
||||
- 开发者在构建状态机时有多种选择,目前最常用的是 Cosmos SDK,但也有其他的框架,如 [Lotion](https://github.com/nomic-io/lotion) 和 [Weave](https://github.com/iov-one/weave) 等。开发者通常都是基于他们使用的编程语言来选择使用哪一种框架(Cosmos SDK 和 Weave 基于 Golang,Lotion 则基于 JavaScript)。
|
||||
|
||||
- ABCI允许开发者更换特定应用链的共识引擎。目前只有Tendermint共识可以投入使用,但在未来还会有更多共识引擎可被使用。
|
||||
- ABCI 允许开发者更换特定应用链的共识引擎。目前只有 Tendermint 共识可以投入使用,但在未来还会有更多共识引擎可被使用。
|
||||
|
||||
- 即使已经选好了开发框架和共识引擎,但如果他们不能完全符合原始格式的要求,开发者依然可以对其进行调整。
|
||||
|
||||
- 开发者可以自由探索出最能满足实际需求的方案(如验证人数量 vs Transaction吞吐量;安全性 vs 异步可用性等)和链的设计选项(如DB存储或IAVL树;UTXO或账户模型,等)。
|
||||
- 开发者可以自由探索出最能满足实际需求的方案(如验证人数量 vs Transaction 吞吐量;安全性 vs 异步可用性等)和链的设计选项(如 DB 存储或 IAVL 树;UTXO 或账户模型,等)。
|
||||
|
||||
- 开发者可以实现代码的自动执行。在Cosmos SDK 中,每个块的开头和结尾都可以自动触发逻辑。与虚拟机区块链环境下的合约开发者不同,特定应用区块链的开发者可以自由地选择应用程序所需要的加密库,而不会受到底层环境的功能限制。
|
||||
- 开发者可以实现代码的自动执行。在 Cosmos SDK 中,每个块的开头和结尾都可以自动触发逻辑。与虚拟机区块链环境下的合约开发者不同,特定应用区块链的开发者可以自由地选择应用程序所需要的加密库,而不会受到底层环境的功能限制。
|
||||
|
||||
上述的列表展示了特定应用区块链给予开发者的充分灵活性。Cosmos 和 Cosmos SDK 的目标是让开发者工具尽可能的通用化、模块化,从而在保持兼容的情况下对堆栈的每个部分进行分叉、调整和优化。随着社区的不断发展,每个核心构建模块都将有更多可替代方案,为开发者提供更多选项。
|
||||
|
||||
|
@ -64,17 +62,17 @@ Blockchain node | | Consensus | |
|
|||
|
||||
基于智能合约的去中心化应用在性能方面会天然地受到底层环境的限制。如果一个去中心化应用要进行性能优化,就需要将其构建为特定应用区块链。以下是特定应用区块链在性能方面的优势:
|
||||
|
||||
- 特定应用区块链开发者可以选择像 Tendermint BFT 这样的新型共识引擎。与目前被大多数虚拟机区块链使用的POW共识相比,Tendermint BFT 在吞吐量方面有显著提高。
|
||||
- 特定应用区块链开发者可以选择像 Tendermint BFT 这样的新型共识引擎。与目前被大多数虚拟机区块链使用的 POW 共识相比,Tendermint BFT 在吞吐量方面有显著提高。
|
||||
|
||||
- 一个特定应用区块链只运行单个应用程序,所以该应用程序不需要和其他程序去竞争计算资源和存储资源。这与目前所有非分片虚拟机区块链正好相反,在这些区块链中的智能合约都会争夺计算和存储资源。
|
||||
|
||||
- 即使某种虚拟机区块链能够提供基于应用程序的分片和高效的共识算法,其性能也依然会被虚拟机本身所限制。真正的吞吐量瓶颈在于状态机,要求Transaction由虚拟机解释会大大增加处理它们的计算复杂度。
|
||||
- 即使某种虚拟机区块链能够提供基于应用程序的分片和高效的共识算法,其性能也依然会被虚拟机本身所限制。真正的吞吐量瓶颈在于状态机,要求 Transaction 由虚拟机解释会大大增加处理它们的计算复杂度。
|
||||
|
||||
###安全性
|
||||
### 安全性
|
||||
|
||||
安全性很难进行量化,而且不同区块链平台之间存在很大差异。以下是特定应用区块链所能带来的重要优势:
|
||||
|
||||
- 与不成熟的智能合约编程语言相反,开发者可以在构建特定应用区块链时选择像Golang这种可靠性已被验证的编程语言。
|
||||
- 与不成熟的智能合约编程语言相反,开发者可以在构建特定应用区块链时选择像 Golang 这种可靠性已被验证的编程语言。
|
||||
|
||||
- 开发者不会局限于底层虚拟机所提供的加密功能,他们可以使用自定义的加密技术,也可以依赖经过可靠审核的加密库。
|
||||
|
||||
|
@ -82,6 +80,6 @@ Blockchain node | | Consensus | |
|
|||
|
||||
### 主导权
|
||||
|
||||
特定应用区块链的一大好处是主导权。去中心化应用是一个涉及众多参与者的生态系统,如用户、开发者、第三方服务,等等。当开发者在多个去中心化应用共存的虚拟机区块链上开发应用程序时,出现的一个问题是围绕应用程序所组成的社区人群和底层链的社区人群并不是一样的,但后者却会在治理的过程中取代前者。如果应用程序中存在一个漏洞,或者需要上线新的功能,应用的stakeholders几乎没有任何办法升级代码。如果底层区块链社区拒绝执行,那应用程序就无法升级。
|
||||
特定应用区块链的一大好处是主导权。去中心化应用是一个涉及众多参与者的生态系统,如用户、开发者、第三方服务,等等。当开发者在多个去中心化应用共存的虚拟机区块链上开发应用程序时,出现的一个问题是围绕应用程序所组成的社区人群和底层链的社区人群并不是一样的,但后者却会在治理的过程中取代前者。如果应用程序中存在一个漏洞,或者需要上线新的功能,应用的 stakeholders 几乎没有任何办法升级代码。如果底层区块链社区拒绝执行,那应用程序就无法升级。
|
||||
|
||||
根本问题是应用程序的治理和网络治理并不是统一的,而这个问题可以通过特定应用区块链解决。因为特定应用区块链只专门运行单个应用程序,所以应用的stakeholders对整条链有完全的主导权。这能确保社区在漏洞被发现时不会卡住,而且有充分的自由去选择链和应用程序的演化方向。
|
||||
根本问题是应用程序的治理和网络治理并不是统一的,而这个问题可以通过特定应用区块链解决。因为特定应用区块链只专门运行单个应用程序,所以应用的 stakeholders 对整条链有完全的主导权。这能确保社区在漏洞被发现时不会卡住,而且有充分的自由去选择链和应用程序的演化方向。
|
||||
|
|
Loading…
Reference in New Issue