yjjnls/Notes

View on GitHub
block chain/Basic/block chain.md

Summary

Maintainability
Test Coverage
- [BitCoin](#bitcoin)
- [白皮书概念整理](#%E7%99%BD%E7%9A%AE%E4%B9%A6%E6%A6%82%E5%BF%B5%E6%95%B4%E7%90%86)
  - [1. 账户/地址](#1-%E8%B4%A6%E6%88%B7%E5%9C%B0%E5%9D%80)
  - [2. 交易](#2-%E4%BA%A4%E6%98%93)
  - [3. 交易脚本](#3-%E4%BA%A4%E6%98%93%E8%84%9A%E6%9C%AC)
  - [4. 区块](#4-%E5%8C%BA%E5%9D%97)
  - [5. 时间戳服务器(Timestamp server)](#5-%E6%97%B6%E9%97%B4%E6%88%B3%E6%9C%8D%E5%8A%A1%E5%99%A8timestamp-server)
  - [6. 工作量证明(Proof-of-Work)](#6-%E5%B7%A5%E4%BD%9C%E9%87%8F%E8%AF%81%E6%98%8Eproof-of-work)
  - [7. 运行机制](#7-%E8%BF%90%E8%A1%8C%E6%9C%BA%E5%88%B6)
- [《精通比特币》相关要点整理](#%E7%B2%BE%E9%80%9A%E6%AF%94%E7%89%B9%E5%B8%81%E7%9B%B8%E5%85%B3%E8%A6%81%E7%82%B9%E6%95%B4%E7%90%86)
  - [1. 比特币交易介绍](#1-%E6%AF%94%E7%89%B9%E5%B8%81%E4%BA%A4%E6%98%93%E4%BB%8B%E7%BB%8D)
    - [1.1 获取正确的输入](#11-%E8%8E%B7%E5%8F%96%E6%AD%A3%E7%A1%AE%E7%9A%84%E8%BE%93%E5%85%A5)
    - [1.2 创建交易输出](#12-%E5%88%9B%E5%BB%BA%E4%BA%A4%E6%98%93%E8%BE%93%E5%87%BA)
    - [1.3 将交易放到总账簿中](#13-%E5%B0%86%E4%BA%A4%E6%98%93%E6%94%BE%E5%88%B0%E6%80%BB%E8%B4%A6%E7%B0%BF%E4%B8%AD)
  - [2. 比特币地址](#2-%E6%AF%94%E7%89%B9%E5%B8%81%E5%9C%B0%E5%9D%80)
    - [2.1 私钥格式](#21-%E7%A7%81%E9%92%A5%E6%A0%BC%E5%BC%8F)
    - [2.2 公钥格式](#22-%E5%85%AC%E9%92%A5%E6%A0%BC%E5%BC%8F)
    - [**2.3 生成地址**](#23-%E7%94%9F%E6%88%90%E5%9C%B0%E5%9D%80)
  - [3. 钱包](#3-%E9%92%B1%E5%8C%85)
    - [3.1 创建助记词](#31-%E5%88%9B%E5%BB%BA%E5%8A%A9%E8%AE%B0%E8%AF%8D)
    - [3.2 从助记词生成根种子](#32-%E4%BB%8E%E5%8A%A9%E8%AE%B0%E8%AF%8D%E7%94%9F%E6%88%90%E6%A0%B9%E7%A7%8D%E5%AD%90)
    - [3.3 从根种子中创造HD钱包](#33-%E4%BB%8E%E6%A0%B9%E7%A7%8D%E5%AD%90%E4%B8%AD%E5%88%9B%E9%80%A0hd%E9%92%B1%E5%8C%85)
      - [3.3.1 主私钥和主链码](#331-%E4%B8%BB%E7%A7%81%E9%92%A5%E5%92%8C%E4%B8%BB%E9%93%BE%E7%A0%81)
      - [3.3.2 子私钥推导](#332-%E5%AD%90%E7%A7%81%E9%92%A5%E6%8E%A8%E5%AF%BC)
        - [3.3.2.1 扩展密钥](#3321-%E6%89%A9%E5%B1%95%E5%AF%86%E9%92%A5)
      - [3.3.3 子公钥推导](#333-%E5%AD%90%E5%85%AC%E9%92%A5%E6%8E%A8%E5%AF%BC)
      - [3.3.4 增强扩展密钥推导](#334-%E5%A2%9E%E5%BC%BA%E6%89%A9%E5%B1%95%E5%AF%86%E9%92%A5%E6%8E%A8%E5%AF%BC)
    - [3.4 HD 钱包密钥路径表示](#34-hd-%E9%92%B1%E5%8C%85%E5%AF%86%E9%92%A5%E8%B7%AF%E5%BE%84%E8%A1%A8%E7%A4%BA)
  - [4. 比特币交易在网络中的传播](#4-%E6%AF%94%E7%89%B9%E5%B8%81%E4%BA%A4%E6%98%93%E5%9C%A8%E7%BD%91%E7%BB%9C%E4%B8%AD%E7%9A%84%E4%BC%A0%E6%92%AD)
  - [5. 交易结构](#5-%E4%BA%A4%E6%98%93%E7%BB%93%E6%9E%84)
  - [6. **交易的输出和输入**](#6-%E4%BA%A4%E6%98%93%E7%9A%84%E8%BE%93%E5%87%BA%E5%92%8C%E8%BE%93%E5%85%A5)
    - [6.1 交易输出](#61-%E4%BA%A4%E6%98%93%E8%BE%93%E5%87%BA)
    - [6.2 交易输入](#62-%E4%BA%A4%E6%98%93%E8%BE%93%E5%85%A5)
    - [6.3 交易费](#63-%E4%BA%A4%E6%98%93%E8%B4%B9)
  - [7. 交易脚本](#7-%E4%BA%A4%E6%98%93%E8%84%9A%E6%9C%AC)
    - [7.1 特性与分类](#71-%E7%89%B9%E6%80%A7%E4%B8%8E%E5%88%86%E7%B1%BB)
    - [7.2 P2PKH(Pay-to-Public-Key-Hash)](#72-p2pkhpay-to-public-key-hash)
    - [7.2 多重签名](#72-%E5%A4%9A%E9%87%8D%E7%AD%BE%E5%90%8D)
    - [7.3 P2SH(Pay-to-Script-Hash)](#73-p2shpay-to-script-hash)
  - [8. 比特币网络](#8-%E6%AF%94%E7%89%B9%E5%B8%81%E7%BD%91%E7%BB%9C)
    - [8.1 节点类型](#81-%E8%8A%82%E7%82%B9%E7%B1%BB%E5%9E%8B)
    - [8.2 节点发现](#82-%E8%8A%82%E7%82%B9%E5%8F%91%E7%8E%B0)
      - [8.2.1 发现有效节点](#821-%E5%8F%91%E7%8E%B0%E6%9C%89%E6%95%88%E8%8A%82%E7%82%B9)
      - [8.2.2 与有效节点连接](#822-%E4%B8%8E%E6%9C%89%E6%95%88%E8%8A%82%E7%82%B9%E8%BF%9E%E6%8E%A5)
      - [8.2.3 与更多节点连接](#823-%E4%B8%8E%E6%9B%B4%E5%A4%9A%E8%8A%82%E7%82%B9%E8%BF%9E%E6%8E%A5)
      - [8.2.4 交换区块清单](#824-%E4%BA%A4%E6%8D%A2%E5%8C%BA%E5%9D%97%E6%B8%85%E5%8D%95)
    - [8.3 SPV](#83-spv)
  - [9. 隔离见证](#9-%E9%9A%94%E7%A6%BB%E8%A7%81%E8%AF%81)
- [共识机制](#%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6)
  - [POW](#pow)
  - [POS](#pos)
  - [PBFT](#pbft)
    - [流程](#%E6%B5%81%E7%A8%8B)
  - [优缺点](#%E4%BC%98%E7%BC%BA%E7%82%B9)
- [分类](#%E5%88%86%E7%B1%BB)
  - [公链](#%E5%85%AC%E9%93%BE)
  - [联盟链](#%E8%81%94%E7%9B%9F%E9%93%BE)
  - [私有链](#%E7%A7%81%E6%9C%89%E9%93%BE)
  - [侧链](#%E4%BE%A7%E9%93%BE)
- [问题](#%E9%97%AE%E9%A2%98)
  - [比特币中的区块记录的交易账单是什么?这些交易账单由谁产生?十分钟才能确认,那么十分钟内不是得等着?](#%E6%AF%94%E7%89%B9%E5%B8%81%E4%B8%AD%E7%9A%84%E5%8C%BA%E5%9D%97%E8%AE%B0%E5%BD%95%E7%9A%84%E4%BA%A4%E6%98%93%E8%B4%A6%E5%8D%95%E6%98%AF%E4%BB%80%E4%B9%88%E8%BF%99%E4%BA%9B%E4%BA%A4%E6%98%93%E8%B4%A6%E5%8D%95%E7%94%B1%E8%B0%81%E4%BA%A7%E7%94%9F%E5%8D%81%E5%88%86%E9%92%9F%E6%89%8D%E8%83%BD%E7%A1%AE%E8%AE%A4%E9%82%A3%E4%B9%88%E5%8D%81%E5%88%86%E9%92%9F%E5%86%85%E4%B8%8D%E6%98%AF%E5%BE%97%E7%AD%89%E7%9D%80)
  - [一个区块包含多少交易账单?为什么区块每十分钟产生一个,由谁控制?](#%E4%B8%80%E4%B8%AA%E5%8C%BA%E5%9D%97%E5%8C%85%E5%90%AB%E5%A4%9A%E5%B0%91%E4%BA%A4%E6%98%93%E8%B4%A6%E5%8D%95%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8C%BA%E5%9D%97%E6%AF%8F%E5%8D%81%E5%88%86%E9%92%9F%E4%BA%A7%E7%94%9F%E4%B8%80%E4%B8%AA%E7%94%B1%E8%B0%81%E6%8E%A7%E5%88%B6)
  - [当前区块没有被矿工挖出来怎么办?](#%E5%BD%93%E5%89%8D%E5%8C%BA%E5%9D%97%E6%B2%A1%E6%9C%89%E8%A2%AB%E7%9F%BF%E5%B7%A5%E6%8C%96%E5%87%BA%E6%9D%A5%E6%80%8E%E4%B9%88%E5%8A%9E)
  - [两个节点同时广播不同记录,链分叉了如何处理,具体的?](#%E4%B8%A4%E4%B8%AA%E8%8A%82%E7%82%B9%E5%90%8C%E6%97%B6%E5%B9%BF%E6%92%AD%E4%B8%8D%E5%90%8C%E8%AE%B0%E5%BD%95%E9%93%BE%E5%88%86%E5%8F%89%E4%BA%86%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%85%B7%E4%BD%93%E7%9A%84)
  - [★结点下线一段时间后再上线,如何同步数据?直接copy过来么?结点下线后是否影响算力呢?如果大部分节点下线,那么当前全网算力下降,是否更容易被攻击篡改呢?](#%E2%98%85%E7%BB%93%E7%82%B9%E4%B8%8B%E7%BA%BF%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%90%8E%E5%86%8D%E4%B8%8A%E7%BA%BF%E5%A6%82%E4%BD%95%E5%90%8C%E6%AD%A5%E6%95%B0%E6%8D%AE%E7%9B%B4%E6%8E%A5copy%E8%BF%87%E6%9D%A5%E4%B9%88%E7%BB%93%E7%82%B9%E4%B8%8B%E7%BA%BF%E5%90%8E%E6%98%AF%E5%90%A6%E5%BD%B1%E5%93%8D%E7%AE%97%E5%8A%9B%E5%91%A2%E5%A6%82%E6%9E%9C%E5%A4%A7%E9%83%A8%E5%88%86%E8%8A%82%E7%82%B9%E4%B8%8B%E7%BA%BF%E9%82%A3%E4%B9%88%E5%BD%93%E5%89%8D%E5%85%A8%E7%BD%91%E7%AE%97%E5%8A%9B%E4%B8%8B%E9%99%8D%E6%98%AF%E5%90%A6%E6%9B%B4%E5%AE%B9%E6%98%93%E8%A2%AB%E6%94%BB%E5%87%BB%E7%AF%A1%E6%94%B9%E5%91%A2)
  - [区块结构到底是什么样子的?只有merkle tree的root么? -->](#%E5%8C%BA%E5%9D%97%E7%BB%93%E6%9E%84%E5%88%B0%E5%BA%95%E6%98%AF%E4%BB%80%E4%B9%88%E6%A0%B7%E5%AD%90%E7%9A%84%E5%8F%AA%E6%9C%89merkle-tree%E7%9A%84root%E4%B9%88)

# BitCoin
![](./img/bitcoin/title.png)

比特币系统由**用户**(用户通过密钥控制钱包)、**交易**(每一笔交易都会被广播到整个比特币网络)和**矿工**(通过竞争计算生成在每个节点达成共识的区块链,区块链是一个分布式的公共权威账簿,包含了比特币网络发生的所有的交易)组成。 

下面就白皮书中的关键点和具体原理进行整理与解析。

# 白皮书概念整理
## 1. 账户/地址
比特币采用了非对称的加密算法,用户自己保留私钥,对自己发出的交易进行签名确认,并公开公钥。比特币的账户地址其实就是用户公钥经过一系列 Hash(HASH 160,或先进行 SHA256,然后进行 RIPEMD160)及编码运算后生成的 160 位(20 字节)的字符串。   

一般地,对账户地址串进行 Base58Check 编码,并添加前导字节(表明支持哪种脚本)和 4 字节校验字节,以提高可读性和准确性。

## 2. 交易
交易是完成比特币功能的核心概念,一条交易可能包括如下信息:
* 付款人地址:合法的地址,公钥经过 SHA256 和 RIPEMD160 两次 Hash,得到160位 Hash 串;
* 付款人对交易的签字确认:确保交易内容不被篡改;
* 付款人资金的来源交易 ID :哪个交易的输出作为本次交易的输入;
* 交易的金额:多少钱,与输入的差额为交易的服务费;
* 收款人地址:合法的地址;
* 收款人的公钥:收款人的公钥;
* 时间戳:交易何时能生效。

网络中节点收到交易信息后,将进行如下检查:
* 交易是否已经处理过;
* 交易是否合法,包括地址是否合法、发起交易者是否是输入地址的合法拥有者、是否是 UTXO;
* 交易的输入之和是否大于输出之和。
如果检查都通过,则将交易标记为合法的未确认交易,并在网络内进行广播。用户可以从 blockchain.info 网站查看实时的交易信息,一个示例交易的内容如下图所示。

![](http://upload-images.jianshu.io/upload_images/1785959-118bbf83fe6445b3.png?imageMogr2/auto-orient/strip|imageView2/2/w/1240)

## 3. 交易脚本
脚本(script)是保障交易完成(主要用于检验交易是否合法)的核心机制,当所依附的交易发生时被触发。通过脚本机制而非写死交易过程,比特币网络实现了一定的可扩展性。

一般每个交易都会包括两个脚本:**输出脚本(scriptPubKey)** 和 **认领脚本(scriptSig)**。**输出脚本**一般由付款方对交易设置锁定,用来对能动用这笔交易输出(例如,要花费交易的输出)的对象(收款方)进行权限控制,例如限制必须是某个公钥的拥有者才能花费这笔交易。**认领脚本**则用来证明自己可以满足交易输出脚本的锁定条件,即对某个交易的输出(比特币)的拥有权。

**输出脚本**目前支持两种类型:
* P2PKH : Pay-To-Public-Key-Hash ,允许用户将比特币发送到一个或多个典型的比特币地址上(证明拥有该公钥),前导字节一般为 OxOO;
* P2SH : Pay-To-Script-Hash ,支付者创建一个输出脚本,里边包含另一个脚本(认领脚本)的哈希,一般用于需要多人签名的场景,前导字节一般为 Ox05。

## 4. 区块
比特币区块链的一个区块主要包括如下内容:
*  4 字节的区块大小信息;
*  80 字节的区块头信息;
* 交易个数计数器: 1 ~ 9 字节;
* 所有交易的具体内容,可变长 。

其中,区块头信息十分重要,包括:
* 版本号: 4 字节;
* 上一个区块头的 SHA256 Hash 值:链接到一个合法的块上, 32 字节;
* 包含所有验证过的交易的 Merkle 树根的哈希值, 32 字节;
* 时间戳: 4 字节;
* 难度指标: 4 字节;
* Nonce: 4 字节, PoW 问题的答案 。

```cpp
class CBlock
{
public:
    // header
    int nVersion;
    uint256 hashPrevBlock;
    uint256 hashMerkleRoot;
    unsigned int nTime;
    unsigned int nBits; // 记录本区块难度
    unsigned int nNonce;

    // network and disk
    vector<CTransaction> vtx;

    // memory only
    mutable vector<uint256> vMerkleTree;

};
```

当用户发布交易后,需要有人将交易进行确认,写到区块链中,形成新的区块。     
目前,每 10 分钟左右生成一个不超过 1 MB 大小的区块(记录了这 10 分钟内发生的验证过的交易内容),串联到最长的链尾部,**每个区块的成功提交者可以得到系统 12.5 个比特币的奖励**(一定区块数后才能使用),以及用户附加到交易上的支付服务费用。

比特币协议还规定,每四年新币的开采量减半,同时限制比特币的最终开采总量为2,100万枚。这样,流通中的比特币数量非常接近一条曲线,并将在2140年比特币将达到2,100万枚。由于比特币的开采速度随时间递减,从长期来看,比特币是一种通货紧缩货币。此外,不能通过“印刷”新比特币来实现“通货膨胀”。

## 5. 时间戳服务器(Timestamp server)
* 时间戳服务器通过对`以区块(block)形式`存在的一组数据实施随机散列而加上时间戳,并将该随机散列进行广播。
* 该时间戳能够证实特定数据必然于某特定时间是的确存在的,因为只有在该时刻存在了才能获取相应的随机散列值。
* 每个时间戳应当将前一个时间戳纳入其随机散列值中,每一个随后的时间戳都对之前的一个时间戳进行增强(reinforcing),这样就形成了一个`链条(Chain)`。

## 6. 工作量证明(Proof-of-Work)
>在区块中补增一个随机数(Nonce),这个随机数要使得该给定区块的随机散列值出现了所需的那么多个0。我们通过反复尝试来找到这个随机数,直到找到为止,这样我们就构建了一个工作量证明机制。  

    SHA256(SHA256(nVersion , hashPrevBlock , hashMerkleRoot , nTime , nBits, nNonce))

区块中的随机数会影响生成的区块的hash值,而只有当这个hash值的前N位都是0时,才是有效的。需要耗费大量的cpu(随机碰撞)才能找到满足hash条件的随机数,这就是工作量。

>由于之后的区块是链接在该区块之后的,所以**想要更改该区块中的信息,就还需要重新完成之后所有区块的全部工作量**。  

工作量证明机制的本质则是`一CPU一票`。“大多数”的决定表达为最长的链,因为最长的链包含了最大的工作量。如果大多数的CPU为诚实的节点控制,那么诚实的链条将以最快的速度延长,并超越其他的竞争链条。  

比特币要使出块速率恒定保持在平均10分钟一个,而随着挖矿算力飞速增加,挖矿难度必须根据这些变化进行调整。

挖矿难度的调整是在每个完整节点中独立完成的,每过2016个区块(约2周)所有节点会检查并调整一次难度,各节点会将2016个区块的总出块时间与20160分钟比较,如果大于20160分钟则降低难度,如果小于则提升难度。

难度调整的公式为:

    New Target = Old Target * (Actual Time of Last 2016 Blocks / 20160 minutes)

为防止难度变化过大,每个周期的调整幅度不能超过4倍,如果算力变化超过4倍,多余的部分将在下一个周期调整。


## 7. 运行机制
1) 新的交易向全网进行广播;
2) 每一个节点都将收到的交易信息进行验证并纳入一个区块中;
3) 每个节点都尝试在自己的区块中找到一个具有足够难度的工作量证明;
4) **当一个节点找到了一个工作量证明,它就向全网进行广播**;
5) **当且仅当包含在该区块中的所有交易都是有效的且之前未存在过的,其他节点才认同该区块的有效性**;
6) 其他节点表示他们接受该区块,而表示接受的方法,**则是在跟随该区块的末尾,制造新的区块以延长该链条,而将被接受区块的随机散列值视为先于新区快的随机散列值**。

如果有两个节点同时广播不同版本的新区块,那么其他节点在接收到该区块的时间上将存在先后差别。  
他们将在率先收到的区块基础上进行工作,但也会保留另外一个链条。  

**该僵局的打破要等到下一个工作量证明被发现?**

如何理解这段话呢?  

例如当前主链区块编号为`#5234`,有两个节点分别打包自己的区块并找到工作量证明,于是他们向网络广播自己的区块`#5235A`和`#5235B`。

一些节点先收到`#5235A`,于是将`#5235A`作为主链,同时保留`#5235B`作为备用链;同样有些节点以`#5235B`作为主链。

每个节点在自己的主链上继续挖矿产生后续区块,并广播出去。假如以`#5235B`作为主链的节点率先挖矿成功,并广播新区块`#5236B`,当原本以`#5235A`为主链的节点收到`#5235B`,`#5236B`之后,立刻切换到以`#5236B`为主链进行挖矿。

节点也可能先收到`#5236B`,此时节点会将`#5236B`保存在孤矿池中,当收到`#5235B`时再将`#5236B`取出与`#5235B`连接。

以下为示意图

![](http://adilmoujahid.com/images/blockchain-the-longest-chain-wins.png)

# 《精通比特币》相关要点整理
- [ ] 区块链原理、设计与应用 第6章
- [ ] 第二版 http://book.8btc.com/books/6/masterbitcoin2cn/_book/ch02.html
<!-- - [ ] 第一版 http://book.8btc.com/books/1/master_bitcoin/_book/2/2.html -->


## 1. 比特币交易介绍
每一笔交易包含一个或多个“输入”,有一个或多个“输出”,这些输入和输出的总额不需要相等,当输出累加略少于输入量时,两者的差额就代表了一笔隐含的“矿工费”,这也是将交易放进账簿的矿工所收集到的一笔小额支付。

<div align="center"><img src="./img/bitcoin/2.1.png" width="450"></div>
<!-- ![](./img/bitcoin/2.1.png) -->

交易是将钱从交易输入移至输出。**输入是指钱币的来源**,通常是之前一笔交易的输出。**交易的输出**则是通过**关联一个密钥**的方式**将钱赋予一个新的所有者**。一笔交易的输出可以被当做另一笔新交易的输入,这样随着钱从一个地址被移动到另一个地址的同时形成了一条所有权链。 

<div align="center"><img src="./img/bitcoin/2.2.png" width="680"></div>

<!-- ![](./img/bitcoin/2.2.png) -->


Alice的密钥提供了解锁之前交易输出的签名,因此向比特币网络证明她拥有这笔钱。她将咖啡的支付附到Bob的地址上,实现“阻止”那笔输出,指明要求是Bob签名才能消费这笔钱。


很重要的一点是,钱包应用甚至可以在完全离线时建立交易。就像在家里写张支票,之后放到信封发给银行一样,比特币交易**建立和签名**时不用连接比特币网络。只有在 **执行交易时**才需要将交易发送到网络。

### 1.1 获取正确的输入  
完整客户端含有整个区块链中所有交易的所有未消费输出副本。这使得钱包既能拿这些输出构建交易,又能在收到新交易时很快地验证其 **输入**是否正确。然而,完整客户端占太大的硬盘空间,所以大多数钱包使用轻量级的客户端,只保存用户自己的未消费输出。
 
如果钱包客户端没有某一未消费交易输出,它可以通过不同的服务者提供的各种API或完整索引节点的JSON PRC API从比特币网络中拿到这一交易信息。

### 1.2 创建交易输出  
交易的 **输出**会被创建成为一个包含这笔数额的脚本的形式,只能被引入这个脚本的一个解答后才能兑换。简单点说就 是,Alice的交易输出会包含一个脚本,这个脚本说 “这个输出谁能拿出一个签名和Bob的公开地址匹配上,就支付给谁”。

### 1.3 将交易放到总账簿中
交易包含了确认资金所有权和分配给新所有者所需要的全部信息。现在,这个交易必须要被传送到比特币网络中以成为分布式账簿(区块链)的一部分


查看我们钱包中所有剩余的从之前交易中已确认的支出  
```shell
$ bitcoin-cli listunspent
[
    { 
        "txid" : "9ca8f969bd3ef5ec2a8685660fdbf7a8bd365524c2e1fc66c309acbae2c14ae3",
        "vout" : 0,
        "address" : "1hvzSofGwT8cjb8JU7nBsCSfEVQX5u9CL",
        "account" : "",
        "scriptPubKey" : "76a91407bdb518fa2e6089fd810235cf1100c9c13d1fd288ac",
        "amount" : 0.05000000,
        "confirmations" : 7
    } 
]
```
交易`9ca8f969bd3ef5ec2a8685660fdbf7a8bd365524c2e1fc66c309acbae2c14ae3`转移了0.05BTC到地址`1hvzSofGwT8cjb8JU7nBsCSfEVQX5u9CL`。下面把0.05BTC一部分交易到新地址`1LnfTndy3qzXGN19Jwscj1T8LR3MVe3JDb`,一部分找零。  
```shell
$ bitcoin-cli createrawtransaction '[{"txid" : "9ca8f969bd3ef5ec2a8685660fdbf7a8bd365524c2e1fc66c309acbae2c14ae3", "vout" : 0}]' '{"1LnfTndy3qzXGN19Jwscj1T8LR3MVe3JDb": 0.025, "1hvzSofGwT8cjb8JU7nBsCSfEVQX5u9CL": 0.0245}'

0100000001e34ac1e2baac09c366fce1c2245536bda8f7db0f6685862aecf53ebd69f9a89c0000000000ffffffff02a0252600000000001976a914d90d36e98f62968d2bc9bbd68107564a156a9bcf88ac50622500000000001976a91407bdb518fa2e6089fd810235cf1100c9c13d1fd288ac00000000
```
`createrawtransaction`命令产生了一个原始十六进制字符串,其中编码了这笔交易的诸多细节。以上只是**创建**了交易,还需要**签名**交易,签名用以证明**我们拥有未花费的输出的来源地址的所有权**。使用`signrawtransaction`命令签名交易后会得到另一串十六进制的字符串,签名可以让这笔交易被比特币交易网络中的任何节点验证,使他们变得可靠。

支付比特币时,比特币的当前所有者需要在交易中提交其公钥和签名(每次交易的签名都不同,但均从同一个私钥生成)。比特币网络中的所有人都可以通过所提交的公钥和签名进行验证,并确认该交易是否有效,即确认支付者在该时刻对所交易的比特币拥有所有权。

## 2. 比特币地址
比特币地址可由公钥经过单向的加密哈希算法得到,一般作为收款方。比特币地址可以代表一对公钥和私钥的所有者,也可以代表其它东西,比如付款脚本。  

### 2.1 私钥格式
*  Hex: 64 hexadecimal digits
*  WIF: Base58Check encoding: Base58 with version prefix of 128 and 32-bit checksum
*  WIF-compressed: As above, with added suffix 0x01 before encoding

私钥是非压缩的,也不能被压缩。“压缩的私钥”实际上只是表示“用于生成压缩格式公钥的私钥”,而“非压缩格式私钥”用来表明“用于生成非压缩格式公钥的私钥”。

### 2.2 公钥格式
公钥是在椭圆曲线上的一个点,由一对坐标(x,y)组成。公钥通常表示为前缀04紧接着两个256比特的数字。其中一个256比特数字是公钥的x坐标,另一个256比特数字是y坐标。前缀04是用来区分非压缩格式公钥,压缩格式公钥是以02或者03开头。


### **2.3 生成地址**
一个比特币钱包中包含一系列的密钥对,每个密钥对包括一个私钥和一个公钥。私钥(k)是一个数字,通常是随机选出的。有了私钥,我们就可以使用椭圆曲线乘法这个单向加密函数产生一个公钥(K)。有了公钥(K),我们就可以使 用一个单向加密哈希函数生成比特币地址(A)。

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-dd62f685376a57d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="680"></div>

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-dd62f685376a57d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

首先生成一个随机数作为私钥k,私钥k为起点,我们将其与曲线上预定的生成点G相乘以获得曲线上的另一点,也就是相应的公钥 K。生成点是secp256k1标准的一部分,比特币密钥的生成点都是相同的:

{K = k * G}

其中k是私钥,G是生成点,在该曲线上所得的点K是公钥。因为**所有比特币用户的生成点是相同的**,一个私钥k乘以G将 得到相同的公钥K。k和K之间的关系是固定的,但**只能单向运算,即从k得到K**。

比特币地址可由公钥经过单向的加密哈希算法得到,由数字“1”开头,例如:

`1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy`

以公钥 K 为输入,计算其SHA256哈希值,并以此结果计算RIPEMD160 哈希值,得到一个长度为160位(20字节)的数字:

    A = RIPEMD160(SHA256(K))

公式中,K是公钥,A是生成的比特币地址。
通常用户见到的比特币地址是经过“Base58Check”编码的(参见“Base58和Base58Check编码”一节),这种编码 使用了58个字符(一种Base58数字系统)和校验码,提高了可读性、避免歧义并有效防止了在地址转录和输入中产生的错误。

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-6fc43eee55666ff2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="550"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-6fc43eee55666ff2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

**由于加密计算都是单向的,所以保证了唯一性。**

Base58编码是不含校验信息的,而Base58Check是一种常用在比特币中的Base58编码格式。用来编码的源数据通常由3各部分组成:前缀、数据和校验码。前缀用来明确需要编码的数据的类型。例如,比特币地址的前缀是0(十六进制是0x00),而对私钥编码时前缀是128(十六进制是0x80)。 而校验码则采用双哈希的方式生成:

   checksum = SHA256(SHA256(prefix+data))

在产生的长32个字节的哈希值(两次哈希运算)中,只取前4个字节,这4个字节就作为校验码。
而生成的比特币地址还要经过Base58Check编码,其过程如下图所示:

<!-- ![](https://upload-images.jianshu.io/upload_images/1367447-cec18209043969fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp) -->
<div align="center"><img src="https://upload-images.jianshu.io/upload_images/1367447-cec18209043969fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" width="580"></div>

可以参考 [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address)


## 3. 钱包
    Bitcoin Address + Private key = Bitcoin Wallet

比特币钱包只含有密钥,而不是钱币。 每个用户有一个**包含多个密钥**的钱包。 钱包只包含私钥/公钥对的**密钥链**。

todo:为什么要有多个秘钥

 **用户用`密钥签名交易`,从而证明他们拥有交易输出(他们的钱币)**。 **钱币以交易输出的形式存储在区块链中**。

有两种主要类型的钱包,区别在于它们包含的多个密钥是否相互关联。

第一种类型是非确定性钱包(nondeterministic wallet),其中每个密钥都是从随机数独立生成的。密钥彼此无关。这种钱包也被称为“Just a Bunch Of Keys(一堆密钥)”,简称JBOK钱包。   
比特币钱包 (Bitcoin Core) 生成密钥对之间没有任何关联,属于不确定性钱包,这种类型的钱包如果想备份导入是比较麻烦的,用户必须逐个操作钱包中的私钥和对应地址。

第二种类型是确定性钱包(deterministic wallet),其中**所有的密钥都是从一个主密钥派生出来,这个主密钥即为种子(seed)**。该类型钱包中所有密钥都相互关联,如果有原始种子,则可以再次生成全部密钥。

确定性钱包中使用了许多不同的密钥推导方法。

最常用的推导方法是使用**树状结构,称为分级确定性钱包或HD钱包**(在`BIP32`中提出)。
*  树状结构可以被用来表达额外的组织含义。不同分支的密钥都可以被用在企业环境中,这就可以支配不同的分支部门、子公司、具体功能以及会计类别。
*  可以允许让使用者去建立一个公共密钥的序列而不需要访问相对应的私钥。这可允许HD钱包在不安全的服务器中使用或者在每笔交易中发行不同的公共钥匙。

确定性钱包由种子衍生创造。为了便于使用,**种子被编码为英文单词,也称为助记词**(在`BIP39`中提出)。


### 3.1 创建助记词
钱包从熵源开始,增加校验和,然后将熵映射到单词列表:

1.  创建一个128到256位的随机序列(熵)。

2.  提出SHA256哈希前几位(熵长/ 32),就可以创造一个随机序列的校验和。

3.  将校验和添加到随机序列的末尾。

4.  将序列划分为包含11位的不同部分。

5.  将每个包含11位部分的值与一个已经预先定义2048个单词的字典做对应。

6.  生成的有顺序的单词组就是助记码。

生成熵和编码作为助记词
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-bed496243dd75389.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="550"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-bed496243dd75389.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

熵数据的大小和助记词的长度之间的关系
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-4b5a86e421dabfe1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="680"></div>

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-4b5a86e421dabfe1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->


### 3.2 从助记词生成根种子
助记词由长度为 128 到 256 位的随机序列(熵)匹配词库而来,随后采用 PBKDF2 function 推导出更长的种子(seed)。

7.  PBKDF2密钥延伸函数的第一个参数是从步骤6生成的助记符。

8.  PBKDF2密钥延伸函数的第二个参数是盐。 由字符串常数“助记词”与可选的用户提供的密码字符串连接组成。

9.  PBKDF2使用HMAC-SHA512算法,使用2048次哈希来延伸助记符和盐参数,产生一个512位的值作为其最终输出。 这个512位的值就是种子。

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-155e604188878b39.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="550"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-155e604188878b39.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

为了从助记词中生成二进制种子,BIP39 采用 PBKDF2 函数推算种子,其参数如下:

*   助记词句子作为密码
*   "mnemonic" + passphrase 作为盐
*   2048 作为重复计算的次数
*   HMAC-SHA512 作为随机算法
*   512 位(64 字节)是期望得到的密钥长度
```
DK = PBKDF2(PRF, Password, Salt, c, dkLen)
```

### 3.3 从根种子中创造HD钱包
前文所述,**HD钱包用树状结构来存储秘钥链**,所以**从助记词来推导出整个HD钱包的过程就是不断`由父秘钥推导子秘钥`的过程**。

#### 3.3.1 主私钥和主链码  

首先是从根种子生成主密钥 (master key) 和主链码 (master chain code)
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-838fb4445a1d179c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="580"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-838fb4445a1d179c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

上图中根种子通过不可逆 HMAC-SHA512 算法推算出 512 位的哈希串,其中左 256 位是 `Master Private key(m)`, 右 256 位是 `master chain code`, 通过 m 结合推导公钥的椭圆曲线算法能推导出与之对应的 264 位 `master public Key (M)`。**而chain code 作为推导下级密钥的熵**。

#### 3.3.2 子私钥推导

HD 钱包使用 CKD(child key derivation) 函数从父密钥(parent keys)推导子密钥(child keys),CKD 由下列三个要素做单向散列哈希(one way hash function) 。

*   父密钥 (没有压缩过的椭圆曲线推导的**私钥或公钥** ECDSA uncompressed key)
*   链码作为熵 (chain code 256 bits)
*   子代索引序号 (index 32 bits)


<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-1224f8f1acd381d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="580"></div>

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-1224f8f1acd381d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

索引号个数为 2 的 32 次方,每个父级密钥能推导出该数目一半的子密钥(索引号从 0x00 到 0x7fffffff (0 to 2 的 21 次方减 1) 会生成**正常的密钥**;索引号从 0x80000000 到 0xffffffff 会生成**增强密钥**)。CKD 采用不可逆的 HMAC-SHA512 不可逆加密算法,**子密钥不能向上推导出父密钥、同时也不能水平推导出同一级的密钥**。

##### 3.3.2.1 扩展密钥

CKD 推导子密钥的三个元素中,其中**父密钥和链码结合统称为扩展密钥 (Extended keys)**。256 位的密钥和 256 位的链码串联起来的 512 位就是扩展密钥。

*   包含私钥的扩展密钥用以推导子私钥,从子私钥又可推导对应的公钥和比特币地址
*   包含公钥的扩展密钥用以推导子公钥

扩展密钥使用 Base58Check 算法加上特定的前缀编码,编码得到的包含私钥的前缀为 `xprv`,包含公钥的扩展密钥前缀为 `xpub`,相比比特币的公私钥,扩展密钥编码之后得到的长度为 512 或 513 位。

#### 3.3.3 子公钥推导

上述方法中通过推导出的私钥可推导出对应公钥,但 HD 钱包非常好用的特征之一就是**在隐藏私钥的前提下通过公钥推导出子公钥,极大加强安全性**。**在只需要生成地址接受比特币而无权消费的场景下非常有用,通过`公钥扩展密钥`能生成无穷尽的公钥和比特币地址**。

HD 钱包通过公钥推导子公钥的使用场景:在接受数字货币支付的电商系统中,Web 服务中集成了比特币扩展公钥服务,系统为客户的每笔订单生成一个接受比特币支付的地址,不涉及到私钥的 web 服务极大地减低了被盗币的可能性。**如果不采用 HD 钱包,通常都是在物理隔绝的服务器中批量生成比特币地址,然后再导入到电商系统,这种方式需要定时生成并导入地址维护防止 web 服务系统把预先导入的地址用完**。

子私钥推导流程和子公钥流程基本一样,差异之处有两点:

*   把子私钥推导过程中私钥替换为公钥。
*   子公钥推导出对应出与之的子链码。

<div align="center"><img src="https://pic2.zhimg.com/80/v2-4c3a5922678ea93a32e42500a74a17f9_hd.jpg" width="580"></div>
<!-- ![](https://pic2.zhimg.com/80/v2-4c3a5922678ea93a32e42500a74a17f9_hd.jpg) -->

#### 3.3.4 增强扩展密钥推导

密钥需加强保管以免泄漏,泄漏私钥意味着对应的地址上的币可被转走、泄漏公钥意味着 HD 钱包的隐私被泄漏。增强密钥推导 (Hardened child key derivation) 解决下述两个问题:

*   虽然泄漏公钥并不会导致丢币,但含有公钥的扩展密钥泄漏会导致以此为根节点推导出来的扩展公钥全部泄漏,一定程度上破坏了隐私性。
*   泄漏扩展公钥加上该公钥推导出的后任一代扩展公钥对应的私钥有被推导出该扩展公钥的所有后代私钥的可能性。

于此,BIP32 协议把 CKD 函数改为 HKD (hardened key derivation formula) 生成增强密钥推导函数。

CKD 函数以推导扩展密钥的序列号 ( 0x00 到 0x7fffffff)、父链码和父公钥或父私钥生成子链码和子公钥,子私钥从父私钥推导;
而 HKD 通过父私钥、父链码和推导增强扩展密钥的序列号 (0x80000000 到 0xffffffff) 增强子私钥和增强子链码。

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-da0636d43b3579ed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="580"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-da0636d43b3579ed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->


### 3.4 HD 钱包密钥路径表示
HD钱包中的密钥是用“路径”命名的,且每个级别之间用斜杠(/)字符来表示。

由主私钥衍生出的私钥起始以“m”打头。由主公钥衍生的公钥起始以“M“打头。因此,母密钥生成的第一个子私钥是m/0。第一个公钥是M/0。第一个子密钥的子密钥就是m/0/1,以此类推。

| 路径     | 含义                            |
| ------ | ----------------------------- |
| m/0    | 从主私钥(m) 推导出的第一代的第一个子私钥        |
| m/0/0  | 从第一代子密钥(m/0)推导出的第二代第一个孙私钥     |
| m/0'/0 | 从第一代增强密钥 (m/0')推导出得第二代第一个孙密钥  |
| m/1/0  | 从第一代的第二个子密钥(m/1)推导出的第二代第一个孙密钥 |



参考: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki  

todo 钱包到底如何工作?

## 4. 比特币交易在网络中的传播
一旦一笔比特币交易被发送到任意一个连接至比特币网络的节点,这笔交易将会被该节点验证。如果交易被验证有效,该节点将会将这笔交易传播到这个节点所连接的其他节点;同时,交易发起者会收到一条表示交易有效并被接受的返回信息。如果这笔交易被验证为无效,这个节点会拒绝接受这笔交易且同时返回给交易发起者一条表示交易被拒绝的信息。为了避免垃圾信息的滥发、拒绝服务攻击或其他针对比特币系统的恶意攻击,每一个节点在传播每一笔交易之前均进行独立验证。 

## 5. 交易结构
一笔比特币交易是一个含有输入值和输出值的数据结构,该数据结构植入了将一笔资金从初始点(输入值)转移至目标地址(输出值)的代码信息。比特币交易的输入值和输出值与账号或者身份信息无关。你应该将它们理解成一种被特定秘密信息锁定的一定数量的比特币。**只有拥有者或知晓这个秘密信息的人可以解锁**。

| 大小    | 字段   | 描述            |
| ----- | ---- | ------------- |
| 4字节   | 版本   | 明确这笔交易参照的规则   |
| 1-9字节 | 输入数量 | 被包含的输入的数量     |
| 1-9字节 | 输出数量 | 被包含的输出的数量     |
| 不定    | 输出   | 一个或多个交易输出     |
| 4字节   | 时钟时间 | 一个UNIX时间戳或区块号 |


>交易的锁定时间   
>锁定时间定义了能被加到区块链里的最早的交易时间。在大多数交易里,它被设置成0,用来表示立即执行。如果锁定时间不是0并且小于5亿,就被视为区块高度,意指在这个指定的区块高度之前,该交易没有被包含在区块链里。如果锁定时间大于5亿,则它被当作是一个Unix纪元时间戳(从1970年1月1日以来的秒数),并且在这个指定时点之前,该交易没有被包含在区块链里。锁定时间的使用相当于将一张纸质支票的生效时间予以后延。

## 6. **交易的输出和输入**
比特币交易的基本单位是**未经使用的一个交易输出**,简称UTXO。

UTXO是不能再分割、被所有者锁住或记录于区块链中的并被整个网络识别成货币单位的一定量的比特币货币。当一个用户接收比特币时,金额被当作UTXO记录到区块链里。这样,**一个用户的比特币会被当作UTXO分散到数百个交易和数百个区块中**。实际上,并不存在储存比特币地址或账户余额的地点,只有被所有者锁住的、分散的UTXO。**比特币钱包通过扫描区块链并聚合所有属于该用户的UTXO来计算该用户的余额**。

>在比特币的世界里既没有账户,也没有余额,只有分散到区块链里的UTXO。

尽管UTXO可以是任意值,但只要它被创造出来了,就像不能被切成两半的硬币一样不可再分了。

如果一个UTXO比一笔交易所需量大,它仍会被当作一个整体而消耗掉,但同时会在交易中生成零头(找零)。**被交易消耗的UTXO被称为交易输入,由交易创建的UTXO被称为交易输出**。

一笔比特币交易通过**使用所有者的签名来解锁UTXO**,并通过**使用新的所有者的比特币地址来锁定并创建UTXO**。给某人发送比特币实际上是创造新的UTXO,注册到那个人的地址,并且能被他用于新的支付。

### 6.1 交易输出
交易输出包含两部分:

1.  一定量的比特币,被命名为“聪”,是最小的比特币单位; 
2.  一个**锁定脚本**,也被当作是“障碍”,提出支付输出所必须被满足的条件以“锁住”这笔总额。

锁定脚本会把输出锁在一个特定的比特币地址上,从而把一定数量的比特币的所有权转移到新的所有者上。比如Alice转给Bob 0.015BTC,当Bob选择使用这笔款项进行支付时,他的交易会释放“障碍”,通过提供一个**包含Bob私钥的解锁脚本**来解锁输出。

包含两个交易输出的例子:   

```json
"vout": [
  {
    "value": 0.01500000,
    "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
  },
  {
    "value": 0.08450000,
    "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
  }
]
```

### 6.2 交易输入
交易输出包含两部分:

1.  一个指向UTXO的指针,通过指向UTXO被记录在区块链中所在的交易的哈希值和序列号来实现。
2.  解锁脚本,钱包构建它用以满足设定在UTXO中的支出条件。

若想支付UTXO,**一个交易的输入也需要包含一个解锁脚本**,用来满足UTXO的支付条件。**解锁脚本通常是一个签名,用来证明对于在锁定脚本中的比特币地址拥有所有权。**

包含一个交易输入的例子:
```json
"vin": [
  {
    "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    "vout": 0,
    "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    "sequence": 4294967295
  }
]
```
*   一个交易ID,引用包含正在使用的UTXO的交易
*   一个输出索引(vout),用于标识来自该交易的哪个UTXO被引用(第一个为零)
*   一个 scriptSig(解锁脚本),满足放置在UTXO上的条件,解锁它用于支出
*   一个序列号(稍后讨论)

仅仅看这个输入,你可能已经注意到,除了对包含它引用的交易之外,我们无从了解这个UTXO的任何内容。而为了构建合适的输入,就必须检索用户以前的交易信息。

```python
# 使用贪心算法从UTXO列表中选择输出。

from sys import argv 

class OutputInfo: 

    def __init__(self, tx_hash, tx_index, value): 
        self.tx_hash = tx_hash
        self.tx_index = tx_index
        self.value = value 

    def __repr__(self):
        return "<%s:%s with %s Satoshis>" % (self.tx_hash, self.tx_index, 
                                            self.value) 

# 为了发送,从未花费的输出列表中选出最优输出。
# 返回输出列表,并且把其他的改动发送到改变地址。
def select_outputs_greedy(unspent, min_value): 
    # 如果是空的话认为是失败了。
    if not unspent: return None 
    # 分割成两个列表。
    lessers = [utxo for utxo in unspent if utxo.value < min_value]     
    greaters = [utxo for utxo in unspent if utxo.value >= min_value] 
    key_func = lambda utxo: utxo.value
    if greaters: 
        # 非空。寻找最小的greater。
        min_greater = min(greaters)
        change = min_greater.value - min_value 
        return [min_greater], change 
    # 没有找到greaters。重新尝试若干更小的。
    # 从大到小排序。我们需要尽可能地使用最小的输入量。
    lessers.sort(key=key_func, reverse=True)
    result = []
    accum = 0
    for utxo in lessers: 
        result.append(utxo)
        accum += utxo.value
        if accum >= min_value: 
            change = accum - min_value
            return result, "Change: %d Satoshis" % change 
    # 没有找到。
    return None, 0 

def main(): 
    unspent = [ 
        OutputInfo("ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167", 1,  8000000),
        OutputInfo("6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf", 0, 16050000),
        OutputInfo("b2affea89ff82557c60d635a2a3137b8f88f12ecec85082f7d0a1f82ee203ac4", 0,  10000000),
        OutputInfo("7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1", 0, 25000000),
        OutputInfo("55ea01bd7e9afd3d3ab9790199e777d62a0709cf0725e80a7350fdb22d7b8ec6", 17, 5470541),
        OutputInfo("12b6a7934c1df821945ee9ee3b3326d07ca7a65fd6416ea44ce8c3db0c078c64", 0, 10000000),
        OutputInfo("7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818", 0, 16100000),
    ] 

    if len(argv) > 1:
        target = long(argv[1]) 
    else:
        target = 55000000 

    print "For transaction amount %d Satoshis (%f bitcoin) use: " % (target, target/ 10.0**8) 
    print select_outputs_greedy(unspent, target) 

if __name__ == "__main__": 
    main()
```

一旦UTXO被选中,钱包会为每个UTXO生成包含签名的解锁脚本,由此让它们变得可以通过满足锁定脚本的条件来被支付。钱包把这些UTXO作为参考,并且连同解锁脚本一起作为输入加到交易中。

### 6.3 交易费
    交易费即输入总和减输出总和的余量:交易费 = 求和(所有输入) - 求和(所有输出)

交易费基于交易的尺寸,用千字节来计算,而不是比特币的价值。交易费不足或者没有交易费的交易可能会被推迟,基于尽力而为的原则在几个区块之后被处理,甚至可能根本不被处理。高交易费不是因为付的钱很多,而是因为她的交易很复杂并且尺寸很大,交易费是与参加交易的比特币值无关的。

具体规则可以参考: https://zhuanlan.zhihu.com/p/38479785 

## 7. 交易脚本
比特币的交易验证引擎依赖于两类脚本来验证比特币交易:一个锁定脚本和一个解锁脚本。

*   **锁定脚本**是一个放在一个输出值上的“障碍”,同时它明确了今后花费这笔输出的条件。由于锁定脚本往往含有一个公钥(即比特币地址),在历史上它曾被称作一个脚本公钥代码。

*   **解锁脚本**是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,同时它将允许输出被消费。解锁脚本是每一笔比特币交易输出的一部分,而且往往含有一个被用户的比特币钱包(通过用户的私钥)生成的数字签名。由于解锁脚本常常包含一个数字签名,因此它曾被称作ScriptSig。

**每一个比特币客户端会通过`同时执行锁定和解锁脚本`来验证一笔交易**。对于比特币交易中的每一个输入,验证软件会先检索输入所指向的UTXO。这个UTXO包含一个定义了花费条件的锁定脚本。接下来,验证软件会读取试图花费这个UTXO中的解锁脚本,并执行这两个脚本。

### 7.1 特性与分类

比特币交易脚本具有以下特性:
1.  图灵非完备  
    比特币交易脚本故意使用一种图灵非完备的语言,没有循环或复杂流程控制,减少了灵活性,但极大的提高了安全性。

2.  无状态验证  
    比特币交易脚本是无状态的,所以一个脚本能在任何系统上以相同的方式执行,如果你的系统验证了一个脚本,可以确信的是每一个比特币网络中的其他系统也将验证这个脚本,这意味着一个有效的交易对每个人而言都是有效的,而且每一个人都知道这一点。

3.  基于堆栈的语言  
    堆栈语言极其简单,也增强了比特币的安全性。

五大标准脚本分别为**P2PKH(Pay-to-Public-Key-Hash)**、P2PK、MS(限15个密钥)、**P2SH(Pay-to-Script-Hash)**和OP_Return。

### 7.2 P2PKH(Pay-to-Public-Key-Hash)
P2PKH是最基本的交易类型,付款对象是公钥哈希。

将解锁脚本与锁定脚本拼接后组成**组合脚本**: 

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-e4060555d14bcd28.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="680"></div>

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-e4060555d14bcd28.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

    解锁脚本:<Sig> <PubKey>

解锁脚本是由签名与公钥组成,这就保证了必须拥有私钥的用户才能对某一笔交易进行解锁。

    锁定脚本:OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG

锁定脚本是由一连串**堆栈命令**和**公钥哈希**组成,公钥哈希即RIPEMD160(SHA256(公钥)),大小20字节,必须拥有该地址的私钥才能将锁定脚本解锁。

<div align="center"><img src="https://github.com/yjjnls/bitcoinbook/blob/develop/images/mbc2_0605.png" width="680"></div>
<div align="center"><img src="https://github.com/yjjnls/bitcoinbook/blob/develop/images/mbc2_0606.png" width="680"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-df262c9f279a046c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/1785959-86488f10788e53bd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->


**只有当解锁脚本与锁定脚本的设定条件相匹配时,执行组合验证脚本时才会显示结果为真(TRUE)。**


### 7.2 多重签名
它其实是一个比特币的一种脚本,这个脚本有3个条件:

*   n个公钥被记录在脚本中
*   至少有m个必须提供签名来解锁资金
*   m<=n
这也称为m-n方案,其中n是密钥的总数,m是验证所需的签名的数量。例如:

*   1/2 的多重签名, 就是2个人只要有一个人签名,就能使用资金。
*   2/3 的多重签名,是3个人至少有2个人签名才能使用资金。
*   2/2 的多重签名,就是2个人中,必须2个人签名,才能使用资金
*   5/10 的多重签名,就是10个人中,必须至少5个人签名,才能使用资金

多重签名就是这么简单,但使用场景可以有很多,比如家庭里面可以设置一个1/2多重签名的账户,每个人都掌握自己的私钥,但账户却是共用的;公司里面可以设置3/4,只有超过3个人同意才能动用一笔资金。

锁定脚本一般的形式为:  

    M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG

锁定脚本示例:2-3多重签名条件  

    2 <Public Key A> <Public Key B> <Public Key C> 3 CHECKMULTISIG

解锁脚本示例:   

    0 <Signature B> <Signature C>
第一位需要补0是因为比特币代码的一个BUG,调用时会从堆栈上多取出一个数字,取出后它被立刻丢去,并不用于之后的运算。这个数具体是什么值无关紧要,可堆栈上不能缺失它,不然无法正常执行CHECKMULTISIG。修复该代码会引起比特币分叉,所以现在通过补0的方式来规避

最终实际的解锁脚本验证如下: 

    0 <Signature B> <Signature C> 2 <Public Key A> <Public Key B> <Public Key C> 3 CHECKMULTISIG

### 7.3 P2SH(Pay-to-Script-Hash)
**多重签名会有如下问题**:

1.  交易臃肿,N个公钥都要包含在交易的输出中(锁定脚本中),增加了交易的大小同时增加了交易费用,另外还增加了矿工维护UTXO的负担。

2.  付款用户必须根据你提供的所有公钥信息对交易中的**锁定脚本进行定制**,给支付带来极大的不便利。  


* P2PKH不需要定制么?

    1.  P2PKH的锁定脚本包含的内容是公钥哈希,公钥哈希可以通过比特币地址解码得到,所以只要知道比特币地址就可以正常生成锁定脚本进行支付。

    2.  多重签名锁定脚本需要包含N个公钥,不可能从单一的地址得到所有的公钥,所以锁定脚本必须定制。

P2SH脚本的引入简化了多重签名的使用,让多重签名更加简单而实用,所以,**现在所说的多重签名技术,其实指的就是P2SH脚本方法**。

它与直接使用之前的多重脚本方式相比,P2SH具有以下特点:

*   在交易输出中,脚本由简短电子指纹取代,使得交易代码变短。由500多字节降到只有20个字节。
*   脚本能被编译为地址,支付指令的发出者和支付者的比特币钱包不需要复杂工序就可以执行P2SH。
*   P2SH将构建脚本的重担转移至接收方,而非发送方。
*   P2SH将长脚本数据存储的负担从输出方(存储于UTXO集,影响内存)转移至输入方(存储在区块链里面)。
*   P2SH将长脚本数据存储的重担从当前(支付时)转移至未来(花费时)。
*   P2SH将长脚本的交易费成本从发送方转移至接收方,接收方在使用该笔资金时必须含有赎回脚本。

要点:

*   第一,P2SH是一种实现多重签名的脚本;
*   第二,P2SH能够简化多重签名;
*   第三,一个P2SH脚本能够通过哈希作为一个地址使用;
*   第四,P2SH已经成为事实上的多重签名。

**P2SH增加赎回脚本(Redeem Script)概念**:

    赎回脚本: 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
    锁定脚本: HASH160 <20-byte hash of redeem script> EQUAL

    解锁脚本: Sig1 Sig2 <redeem script>


首先对比解锁脚本中的赎回脚本内容哈希与锁定脚本中是否一致

    Sig1 Sig2 <redeem script> HASH160 <20-byte hash of redeem script> EQUAL


如果上面的对比结果一致,则变成执行如下内容(回到了多重脚本验证的情况)

    Sig1 Sig2 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG

## 8. 比特币网络
比特币采用P2P网络架构,在P2P网络中不存在任何服务端(server)、中央化的服务、以及层级结构。P2P网络的节点之间交互运作、协同处理:每个节点在对外提供服务的同时也使用网络中其他节点所提供的服务。P2P网络也因此具有**可靠性、去中心化,以 及开放性**。
### 8.1 节点类型
尽管比特币P2P网络中的各个节点相互对等,但是根据所提供的功能不同,各节点可能具有不同的角色。每个比特币节点都是**路由、区块链数据库、挖矿、钱包服务**的功能集合。一个全节点(full node)包括如图所示的四个功能:

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-b3232e2beb8cfa6e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="280"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-b3232e2beb8cfa6e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->


另外还有一些节点只保留了区块链的一部分,它们通过一种名为“简易支付验证(SPV)”的方 式来完成交易验证。这样的节点被称为“SPV节点”,又叫“轻量级节点”。

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-5714bcf15cf8273a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="680"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-5714bcf15cf8273a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

1.  比特币核心客户端(Refernce Clent(Bitcoin Core))  
    包含钱包、矿工、完整区块、路由网络全部四种功能的节点
2.  全节点(Full Block Chain Node)  
    全节点包含完整区块链数据,并具有路由网络功能
3.  独立矿工(Solo Miner)  
    包含全部区块链数据,并具有挖矿能力的节点
4.  轻(SPV)钱包(Lightweight wallet)  
    包含钱包与路由转发功能的节点,对于资源有限的终端,如手机,平板等格外有用

    **扩展的比特币节点既运行比特币P2P网络的协议,也运行特殊协议,特别是矿池的出现,催生了这种扩展节点的诞生。**

5.  矿池协议服务器(Pool Protocol Servers)  
    矿池协议服务器通常作为比特币网络与其他矿池挖矿节点(如Stratum node)的网关路由。
6.  挖矿节点(Mining Nodes)
    包含挖矿功能,但没有区块链数据,通常是矿池挖矿节点,运行Stratum protocol或其他矿池挖矿协议。
7.  轻型Stratum钱包(Lightweight(SPV)Stratum Wallet)
    运行在Stratum协议下包含钱包功能的节点。


### 8.2 节点发现
#### 8.2.1 发现有效节点
1.  使用“DNS种子”(DNS seeds),DNS种子提供比特币节点的IP地址列表,Bitcoin Core客户端提供五种不同的DNS种子,通常默认使用即可

2.  手动通过-seednode命令指定一个比特币节点的IP地址作为比特币种子节点

#### 8.2.2 与有效节点连接
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-80dd26e54d1fe3d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="380"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-80dd26e54d1fe3d6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

节点发送一条包含基本认证内容的version消息开始“握手”通信过程,该消息包括如下内容:

*   nVersion:客户端的比特币P2P协议所采用的版本(例如:70002)。
*   nLocalServices:一组该节点支持的本地服务列表,当前仅支持NODE_NETWORK
*   nTime:当前时间
*   addrYou:当前节点可见的远程节点的IP地址(上例中NodeB IP)
*   addrMe:当前节点的IP地址(上例中NodeA IP)
*   subver:指示当前节点运行的软件类型的子版本号(例如:”/Satoshi:0.9.2.1/”)
*   BestHeight:当前节点区块链的区块高度(初始为0,即只包含创世区块)

#### 8.2.3 与更多节点连接
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-87ee55e52ccd5b68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="380"></div>

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-87ee55e52ccd5b68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

1.  发送一条包含自身IP地址的addr发送给已连接的节点,这些节点收到后将此转发给它们各自的连接节点,使网络中更多的节点接收到新节点

2.  发送一条getaddr消息,要求已连接节点返回其已知的节点IP地址列表,通过这种方式,节点可以找到更多可连接的节点。

3.  已建立连接的节点会定期发送信息维持连接,如果某个节点长达90分钟没有通信,会被认为已经断开,网络会开始寻找一个新的节点。

每个节点连接不超过1000个对等节点,超过数量的IP地址会被忽略,连接过多的节点浪费网络资源,没有必要。

用户可指定-connect选项来指定一个或多个IP地址,如果设置该选项,节点将只连接选项中的地址,不会自动发现并维护节点之间的连接。

启动完成后,节点会记住最近成功连接的节点,当重新启动后可以迅速与先前的节点重新建立连接。如果先前节点均无法连接,会重新从步骤1开始执行。

#### 8.2.4 交换区块清单
该步骤仅在全节点上会执行,全节点在连接到其他节点后,需要构建完整的区块链,如果是新节点,它仅包含静态植入客户端中的0号区块(创世区块)。
<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-e76673d0a358adfa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="380"></div>
<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-e76673d0a358adfa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

1.  通过version消息中的BestHeight字段可知双方节点的区块高度,然后节点之间交换一个getblocks消息,其中包含本地区块链顶部区块的Hash,这样节点间就可以判断谁的链更长。

2.  拥有更长链的节点识别出其他节点需要“补充”的区块后,开始分批发送区块(500个区块为一批),通过inv消息先将第一批的区块清单发送给对端节点(inv消息包含500个区块的Hash清单)。限制每次同步区块的数量,是为了减少新节点同步区块对网络造成的影响。

3.  缺少区块的节点发送getdata消息向所有已连接的节点请求全区块数据,“正在传输”的区块数量不能超过客户端MAX_BLOCKS_IN_TRANSIT_PER_PEER参数设置的值。

### 8.3 SPV
运行全节点需要消耗非常多的存储空间,并不是所有设备都有条件成为全节点。简单支付验证(SPV)即是为了再不存储完整区块链的情况下进行工作。

**SPV节点只需要下载区块头**,大小约只有全节点的1/1000。

*   全节点交易验证方式

    全节点沿着区块链按时间倒叙一直追溯到创世区块,建立一个完整的UTXO数据库,通过查询UTXO是否未被支付来验证交易的有效性。

*   SPV节点验证方式
    **简易支付验证**是通过参考交易在区块链中的深度,而不是高度,来验证它们。SPV节点通过向其他节点请求某笔交易的Merkle路径,如果路径正确无误,并且该交易之上已有6个或以上区块被确认,则证明该交易不是双重支付。

**SPV强调的是验证支付,不是验证交易。** 这两个概念是不同的。验证支付,比较简单,只需要判断用于支付的那笔交易是否被验证过,以及得到网络多少次确认(即有多少个区块叠加)。而交易验证则复杂的多,需要验证账户余额是否足够支出、是否存在双重支付、交易脚本是否通过等问题,一般这个操作是由全节点的矿工来完成。

<!-- ![](http://upload-images.jianshu.io/upload_images/1785959-817619842883f9f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -->

<div align="center"><img src="http://upload-images.jianshu.io/upload_images/1785959-817619842883f9f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="380"></div>

SPV节点使用getheaders消息替代getblocks消息,收到请求的节点将用一条headers消息发送2000个区块头给请求节点,不断循环直到区块头同步完毕。

注:SPV的通信会产生一个隐私风险,由于SPV节点总是通过广播选择性的验证交易,用户的比特币地址与钱包很容易能被关联起来,所以在使用SPV节点需要使用Bloom过滤器。Bloom过滤器作用就是每次要求发送验证信息的节点发送一批交易的信息,而不是某一个交易,再由SPV节点自己来筛选需要的信息,这样就保证了验证的具体交易无法被追踪。

    SPV的目标是为了验证某个交易支付是否存在,以及得到比特币网络多少个确认(多少个区块)。

    
1.  SPV节点如果只关心某个支付到自己比特币地址的交易,则可以通过建立布隆过滤器限制只接收含有目标比特币地址的交易。
2.  一旦比特币网络中其他当节点探测到某个交易符合SPV节点设置的布隆过滤器条件时,其它节点将以**Merkleblock消息**的形式发送该区块,**Merkleblock消息包含`区块头`和一条连接目标交易与Merkle根的`Merkle路径`**。
3.  SPV节点通过零知识证明来验证对应区块中是否存在目标交易(**Merkle Path Proof**)。
4.  SPV节点还需查询该包含目标交易的区块之后的区块个数,区块个数越多说明该区块被全网更多节点共识。一般来说,一笔交易所属区块之后的区块个数达到6个时,就说明这笔交易是被大家核准过(达成共识)的,没有重花,而且被篡改的可能性也很低。


## 9. 隔离见证
在密码学中,术语“见证”(witness)被用于形容一个加密难题的解决方案。在比特币语境中,一个**数字签名**就是一种类型的“见证”(one type of witness),它能够满足加诸于一个UTXO的条件,使UTXO解锁后可被花费。在引入“隔离见证”之前,每一个交易输入后面都跟着用来对其解锁的见证数据,见证数据作为输入的一部分被内嵌其中。

而隔离见证就是比特币的一种结构性调整,旨在将见证数据部分从一笔交易的scriptSig(解锁脚本)字段移出至一个伴随交易的单独的见证数据结构(**指将交易中的签名部分从交易的输入中隔离出来,放到交易末尾的被称为见证Witness的字段当中**)。客户端请求交易数据时可以选择要或不要该部分伴随的见证数据。

隔离见证作为比特币扩容的一种手段,有诸多[优点与缺点](https://www.8btc.com/article/84307)。

-------

<!-- 

# 共识机制
**共识机制一般用来保证分布式系统的一致性,`来对新增数据达成共识`。**    
对于要能容忍拜占庭错误的情况,一般包含PBFT系列、POW系列算法等。PBFT系列算法是确定的,一旦达成共识就不可逆转;而POW系列算法是不固定的,随着时间推移,被推翻的概率越来越小。    

在比特币中,指如何将全网交易数据客观记录并且不可篡改的过程。目前"三巨头"分别使用不同的共识算法(Consensus Algorithm),比特币使用工作量证明PoW(Proof of Work),以太坊即将转换为权益证明PoS(Proof of Stake),比特股使用授权权益证明DPoS(Delegated Proof of Stake)。    

目前常用的几种共识机制     
## POW
通过计算来猜测一个数值(nonce),得以解决规定的 hash 问题。hash 问题具有不可逆的特点,因此,目前除了暴力计算外,还没有有效的算法进行解决。反之,如果获得符合要求的 nonce,则说明在概率上是付出了对应的算力。谁的算力多,谁最先解决问题的概率就越大。  

工作量证明机制(Proof of Work - PoW)是我们最熟知的一种共识机制。就如字面的解释,PoW就是工作越多,收益越大。这里的工作就是猜数字,谁能最快的猜出这个唯一的数字,谁就能做信息公示人。

## POS
类似现实生活中的股东机制,拥有股份越多的人越容易获取记账权。   

权益证明机制(Proof of Stake-PoS)也属于一种共识证明,它类似股权凭证和投票系统,因此也叫“股权证明算法”。由持有最多(token)的人来公示最终信息。

## PBFT
拜占庭共识算法(Byzantine Fault Tolerance- BFT)也是一种常见的共识证明。它与之前两种都不相同,BFT以计算为基础,也没有代币奖励。由链上所有人参与投票,少于(N-1)/3个节点反对时就获得公示信息的权利。**失效副本的数量不超过(n-1)/3**    

>拜占庭问题之所以难解,在于任何时候系统中都可能存在多个提案(因为提案成本很低),并且要完成最终的一致性确认过程十分困难,容易受干扰。但是一旦确认,即为最终确认。比特币的区块链网络在设计时提出了创新的 PoW(Proof of Work) 算法思路。一个是限制一段时间内整个网络中出现提案的个数(增加提案成本),另外一个是放宽对最终一致性确认的需求,约定好大家都确认并沿着已知最长的链进行拓宽。系统的最终确认是概率意义上的存在。这样,即便有人试图恶意破坏,也会付出很大的经济代价(付出超过系统一半的算力)。

### 流程
PBFT是一种状态机副本复制算法,即服务作为状态机进行建模,状态机在分布式系统的不同节点进行副本复制。每个状态机的副本都保存了服务的状态,同时也实现了服务的操作。   

1. 每个副本节点都包含了服务的整体状态,节点的日志包含了结点所接受的消息,并且包含当前的视图编号v(每一轮主节点的产生都会有一个新的v,递增,类似于raft中的term)
2. 主节点p收到客户端发来的消息m,向所有副本节点进行广播,进行三阶段协议
3. 所有副本都执行请求并将结果发回客户端
4. 客户端需要等待f+1个不同副本节点发回相同的结果,作为整个操作的最终结果。

如果客户端没有在有限时间内收到回复,请求将向所有副本节点进行广播。如果请求已经在副本节点处理过了,副本就向客户端重发一遍执行结果。如果请求没有在副本节点处理过,该副本节点将把请求转发给主节点。如果主节点没有将该请求进行广播,那么就有认为主节点失效,如果有足够多的副本节点认为主节点失效,则会触发一次视图变更。   

[ref](https://www.jianshu.com/p/fb5edf031afd)

## 优缺点
**共识算法的选择与应用场景高度相关,完全可信任的环境使用paxos 或者raft,对于联盟链这种带许可机制的可使用bft,完全公开的链就用是pow,pos,ripple共识等。**


PBFT需要结点之间相互通信,通信量是O(n^2),不适合大规模,适合联盟链、私链。
PBFT还有个问题就是在运行之前节点必须固定并且互相知道。否则,就有可能有超过1/3的拜占庭节点,整个系统的安全性无法保证。这在public blockchain的环境下基本不可能做到的。

比特币共识不需要许可,而BFT算法需要许可(至少需要知道节点的数量和他们对应的公钥)

BFT算法可扩展性(scalability)差,比特币共识(包括POW,POS权益证明等)效率低且无法实现强一致性


# 分类
而根据所采用的共识机制的不同,区块链又分为不同的种类,每种链都有其特性和适用场合。

## 公链

公共链-真正的完全去中心的区块链,可以是pow或者pos
突出公平,这是我猜的~~~

用户不用注册就能匿名参与的链,无需授权就能访问网络的区块链。公链的任何区块对外公开,任何人都可以发送价值。比特币以太坊是著名公链,公链适合虚拟货币,电子商务互联网金融等领域。

## 联盟链

联盟链-行业内的可监管区块链,一般用BFT,例如fabric
突出监管和安全,这也是我猜的~~~

联盟链仅限于联盟成员参与,成员参与区块链运行需要按照规则获取读写记账的权限。成员需要注册才可使用。联盟链由机构成员共同维护,提供成员管理,认证,授权,监控,审计功能。由40多家银行参与的R3区块链联盟和Linux基金会成立的超级账本项目属于联盟链构架。联盟链适合机构间交易清算结算B2B场景,用于节省对账和清算成本,减少人为错误的发生。联盟链对安全性能要求比公链高。

## 私有链

私有链-机构内私有定制区块链

私有链仅在机构内使用,读写权,记账权由组织内自由定制。 私有链的价值主要是提供安全可追溯不可篡改自动执行的运算平台,必须先注册取得许可才可以访问和使用。 央行发行的数字货币就是私有链。

## 侧链

侧链-与比特币挂钩且能和比特币区块链交互的区块链

比特币的任何修改都会导致分叉,影响现有的比特币区块链,所以想要改进比特币比较困难。 一般来说要创建新的代币,是用比特币做基础重构一条链,然后在上面创建新的规则发行代币,并且`将代币的价格和比特币实时挂钩`。侧链是相对与比特币主链来说的,所有遵循侧链协议的区块链都是侧链。**侧链协议是指:`可以让比特币安全地从比特币主链转移到其他区块链,又可以从其他区块链安全地返回比特币主链的一种协议`。莱特币,达世币,zcash就是著名的侧链。**

侧链意味着比特币不仅可以在比特币区块链上流通,还可以在其他区块链上流通,其应用范围和应用前景会更加广泛;有创意的人们会研发出各种各样的应用以侧链协议与比特币主链对接,使得比特币这种基准自由货币的地位越加牢固。


# 问题
## 比特币中的区块记录的交易账单是什么?这些交易账单由谁产生?十分钟才能确认,那么十分钟内不是得等着?
  
## 一个区块包含多少交易账单?为什么区块每十分钟产生一个,由谁控制? 

In terms of number of transactions per block - the current average is actually close to 1500. Usually a few hundred transactions per block. Miners get to choose how many transactions are in their block.

https://bitcoin.stackexchange.com/questions/10457/what-is-the-number-of-transactions-in-a-block  
https://bitcoin.stackexchange.com/questions/30019/how-many-transactions-in-one-block  

客户端会根据区块的生成速度来控制生成难度,以便控制在平均10分钟生成一个区块,比如通过控制hash结果中0的个数。    
整个网络每产生2,106个区块后会根据之前2,106个区块的算力进行难度调整。
## 当前区块没有被矿工挖出来怎么办?  
## 两个节点同时广播不同记录,链分叉了如何处理,具体的? 
>如果有两个节点同时广播不同版本的新区块,那么其他节点在接收到该区块的时间上将存在先后差别。当此情形,他们将在率先收到的区块基础上进行工作,但也会保留另外一个链条,以防后者变成最长的链条。该僵局(tie)的打破要等到下一个工作量证明被发现,而其中的一条链条被证实为是较长的一条,那么在另一条分支链条上工作的节点将转换阵营,开始在较长的链条上工作。
问题是另一条分支链上的节点怎么转换阵营?在另一条链上已经产生的区块怎么办?
## ★结点下线一段时间后再上线,如何同步数据?直接copy过来么?结点下线后是否影响算力呢?如果大部分节点下线,那么当前全网算力下降,是否更容易被攻击篡改呢?
    如果一个节点没有收到某特定区块,那么该节点将会发现自己缺失了某个区块,也就可以提出自己下载该区块的请求。
    如果是下线情况,那么……todo
## 区块结构到底是什么样子的?只有merkle tree的root么?
```cpp
class CBlock
{
public:
    // header
    int nVersion;
    uint256 hashPrevBlock;
    uint256 hashMerkleRoot;
    unsigned int nTime;
    unsigned int nBits; // 记录本区块难度
    unsigned int nNonce;

    // network and disk
    vector<CTransaction> vtx;

    // memory only
    mutable vector<uint256> vMerkleTree;

};
``` -->