Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chinese translation for address.md and blockchain.md #209

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions address_ch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Nebulas 地址设计

Nebulas 地址系统是精心设计的。正如你将在下面看到的,账户和智能合约地址都是 “n” 开头的字符串,可以认为它们就是我们信仰的 Nebulas(NAS)。

## 账户地址

与比特币和以太坊类似,Nebulas 也采用了椭圆曲线算法作为 Nebulas 账户的加密算法。Nebulas 账户的地址是通过**公钥**计算出来的,而公钥则通过用户**密码短语**进行加密的**私钥**计算而来。此外,我们也有校验设计,旨在防止用户因为输入几个错误字符而将 _Nas_ 意外发送给错误的用户账户。

具体的计算公式如下:
```
1. content = ripemd160(sha3_256(public key))
length: 20 bytes
+--------+--------+------------------+
2. checksum = sha3_256( | 0x19 + 0x57 | content | )[:4]
+--------+--------+------------------+
length: 4 bytes

+--------+---------+-----------------+------------+
3. address = base58( | 0x19 | 0x57 | content | checksum | )
+--------+---------+-----------------+------------+
length: 35 chars
```

**0x57** 是一个单字节“类型码”,表示账户地址,**0x19** 则是一个固定的单字节“填充”。

在这个阶段,Nebulas 只采用了普通的比特币 [base58](https://en.wikipedia.org/wiki/Base58) 编码模式。一个有效的地址示例:_n1TV3sU6jyzR4rJ1D7jCAmtVGSntJagXZHC_

## 智能合约地址

计算合约地址和计算账户地址略有不同,合约发送方的密码短语不是必需的,地址和 nonce 才是必需。有关更多信息,请查看 [smart contract](https://github.com/nebulasio/wiki/blob/master/tutorials/%5BEnglish%5D%20Nebulas%20101%20-%2003%20Smart%20Contracts%20JavaScript.md) 和 [rpc.sendTransaction](https://github.com/nebulasio/wiki/blob/master/rpc.md#sendtransaction)。计算公式如下:

```
1. content = ripemd160(sha3_256(tx.from, tx.nonce))
length: 20 bytes
+--------+--------+------------------+
2. checksum = sha3_256( | 0x19 | 0x58 + content | )[:4]
+--------+--------+------------------+
length: 4 bytes

+--------+---------+-----------------+------------+
3. address = base58( | 0x19 | 0x58 | content | checksum | )
+--------+---------+-----------------+------------+
length: 35 chars
```

**0x58** 是一个单字节“类型码”,表示账户地址,**0x19** 则是一个固定的单字节“填充”。

一个有效的地址示例: _n1sLnoc7j57YfzAVP8tJ3yK5a2i56QrTDdK_
174 changes: 174 additions & 0 deletions blockchain_ch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# 区块链

## 模型

Nebulas 使用了账户模型来替代 UTXO 模型。
交易的执行将消耗 gas。

## 数据结构

``` txt
区块结构
+---------------+----------------+--------------+
| blockHeader | transactions | dependency |
+---------------+----------------+--------------+
blockHeader: 头部信息
transactions: 交易序列
dependency: 交易之间的依赖关系

区块头部结构
+-----------+--------+--------------+------------+-------------+-------+--------+
| chainid | hash | parentHash | coinbase | timestamp | alg | sign |
+-----------+--------+--------------+------------+-------------+-------+--------+
+-------------+-----------+--------------+-----------------+
| stateRoot | txsRoot | eventsRoot | consensusRoot |
+-------------+-----------+--------------+-----------------+
chainid: 该区块所属的链id
hash: 区块哈希
parentHash: 父区块哈希
coinbase: 接受挖矿奖励的账户
timestamp: 1970年1月1日以来经过的纳秒数
alg: 签名算法的类型
sign: 区块哈希的签名
stateRoot: 账户状态的根哈希
txsRoot: 交易状态的根哈希
eventsRoot: 事件状态的根哈希
consensusRoot: 共识状态,包含提议者和当前 dynasty 的验证者


交易结构
+-----------+--------+--------+------+---------+---------+-------------+
| chainid | hash | from | to | value | nonce | timestamp |
+-----------+--------+--------+------+---------+---------+-------------+
+--------+------------+------------+
| data | gasPrice | gasLimit |
+--------+------------+------------+
chainid: 该区块所属的链id
hash: 交易哈希
from: 发送者的钱包地址
to: 接收者的钱包地址
value: 转账数值
nonce: 交易nonce
timestamp: 1970年1月1日以来经过的纳秒数
alg: 签名算法的类型
sign: 交易哈希的签名
data: 交易数据,包含了交易类型(普通转账/部署智能合约/调用智能合约)和 payload
gasPrice: 交易消耗的 gas 单价
gasLimit: 交易可消耗的最大 gas
```

## 区块链更新

在我们看来,**区块链**只需要关心如何处理新区块,使其安全且高效地增长。更重要的是,**区块链**只能从下面两个渠道获取新区块。

### 来自网络的新区块

由于网络延迟不稳定,我们无法确定任何新接收的块可以直接连上到我们当前的**链**。因此,我们需要**区块池**来缓存新区块。

### 来自本地矿工的新区块

首先,我们需要**交易池**来缓存来自网络的交易。然后,我们等待本地**共识**组件创建一个新的区块,例如 DPoS。

无论新区块来自哪里,我们都使用相同的步骤来处理,如下所示:

![](resources/blockpool.png)

## 世界状态

每一个区块都包含当前的世界状态,世界状态由下列四个状态组成。它们都作为[梅克尔树](./merkle_trie.md)来进行维护。

### 账户状态

当前区块的所有账户都存储在账户状态里。
账户分为普通账户和智能合约两种。

普通账户包括:

- **钱包地址**
- **余额**
- **nonce**:账户的 nonce,它将以 1 为增量递增

智能合约账户包括:

- **合约地址**
- **余额**
- **出生地**:部署合约的交易哈希
- **变量**:包含合约中所有的变量值

### 交易状态

所有提交到链上的交易都存储在交易状态里。

### 事件状态

当执行交易的时候,会触发很多事件。
由链上交易触发的所有事件都被存储在事件状态里。

### 共识状态

共识算法的上下文存储在共识状态里。

对于 DPoS 来说,共识状态包括:

- **timestamp**:当前时间戳
- **proposer**:当前提议者
- **dynasty**:当前 dynasty 的验证者

### 序列化

考虑到以下好处,我们选择了协议缓冲技术来进行常规序列化:

- 大规模证明。
- 效率。它省略了关键字,并且使用 varints 编码。
- 多类型及多语言客户端支持。易于使用的 API。
- Schema 是良好的通信格式。
- Schema 适用于版本控制或扩展,即添加新的消息字段,或废弃一个没用的字段。

特别是,为了可读性,我们在智能合约里使用 json 进行序列化,而不是使用 protobuf。

## 同步

有时我们接收到的新区块高度会比它当前的尾部区块高很多。当这种差距发生的时候,我们就需要从对等节点那儿同步区块,从而赶上它们。

Nebulas 提供了两种方法来从对等节点同步区块:Chunks Downloader 和 Block Downloader。如果差值大于 32 个区块,我们将选择 Chunks Downloader 以块的形式来下载大量的区块。否则,我们会选择 Block Downloader 来逐个下载区块。

### Chunks Downloader

块是 32 个连续块的集合。Chunks Downloader 允许我们每次最多在当前尾部区块后面下载 10 个块。这种基于块的机制可以帮助我们减少网络包的数量,同时实现更好的安全性。

程序逻辑如下:

```txt
1. A 将其尾部区块发送给 N 个远程对等节点。
2. 远程对等节点找到包含 A 尾部区块的块 C。
然后它们将发送 10 个块的头部,包括块 C 和 9 个 C 的后续块,以及 10 个头部的哈希值 H。
3. 如果 A 收到大于 N/2 数量的相同哈希值 H,A 就将同步 H 代表的那些块。
4. 如果 A 取出了所有 H 代表的块并成功将它们上链,则跳转到 1。
```

在 1~3 的步骤里,我们使用了多数决策来确认标准链上的块。然后我们在步骤 4 里以块的形式下载这些区块。

**注意:**`ChunkHeader` 包含了 32 个区块哈希的数组和这个数组的哈希。`ChunkHeaders` 则包含了 10 个 `ChunkHeaders` 的数组和这个数组的哈希。

下面是这个同步过程的图表:

![](resources/the-diagram-of-sync-process.png)

### Block Downloader

当本地链和标准链之间的差距长度小于 32 时,我们将使用 Block Downloader 来逐个下载缺失的区块。

程序逻辑如下:

```txt
1. C 将最新的区块 B 传给 A,且 A 发现 B 的高度大于当前尾部区块高度。
2. A 将 B 区块的哈希发回 C,从而下载 B 的父区块。
3. 如果 A 成功接收了 B 的父区块 B',A 将尝试将 B' 连接到 A 当前的尾部区块上。
如果再次失败,A 将回到步骤 2 并继续下载 B' 的父区块。否则,完成。
```

这个过程将不断重复,直到 A 追赶上标准链。

下面是这个同步过程的图表:

![](resources/the-diagram-of-download-process.png)