一文读懂比特币

1. 概述

每一笔交易可以分为 输入, 输出, 其他 
输入 >= 输出 + 其他 (奖励给矿工), 
而输入的比特币需要引用其来源 (它作为上次交易的输出), 称 UTXO.
而且每笔交易作为输入不能分割。

 

1.1. 钱包地址

新生成的钱包, 即未交易过的比特币地址对于比特币网络来说是不知道的,或者是未经注册到比特币系统中。它只是一个数字,对应于一个可以用来控制资金访问的密钥。由钱包**生成的,还没有参考或注册任何服务。 
事实上,在大多数钱包中,比特币地址和任何外部可识别的信息(包括用户的身份)之间没有关联。在该地址被引用作为比特币总帐的交易中的接收者之前,比特币地址只是在比特币中有效的大量可能的地址的一部分。只有一旦与交易相关联才能成为网络中已知地址的一部分。

 

1.2. 交易链

 

1.3. 找零

许多比特币交易都会包括新所有者的地址(买方地址)和当前所有者的地址(称为找零地址)的输出。这是因为交易输入,就像纸币那样能够,不能再分割。如果您在商店购买了 5 美元的商品,但是使用 20 美元的美金来支付商品,您预计会收到 15 美元的找零。

相同的概念适用于比特币交易输入。如果您购买了一个价格为 5 比特币但只能使用 20 比特币输入的商品,那 
么您可以将 5 个比特币的一个输出发送给商店所有者,并将一个 15 比特币的输出返回给您自己作为找零(减去任何适用的交易费用)。重要的是,找零地址不必与输入时提供的地址相同,出于隐私的原因,通常是所有者钱包中的新地址。

另外还有其他模式, 比如有一把零钱, 凑在一起, 支付一次 
还有就是一次有很大一笔钱, 分给很多人. 
如下图所示 

 

1.4. 钱包

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

 

1.5. 挖矿的作用

  • 挖矿节点通过参考比特币的共识规则验证所有交易。 因此,挖矿通过拒绝无效或畸形交易来提供比特币交易的安全性。
  • 挖矿在构建区块时会创造新的比特币,和一个中央银行印发新的纸币很类似。每个区块创造的比特币数量是固定的, 随时间会渐渐减少

 

2. bitcoin core 客户端

  • 下载
$ git clone
$ git  tag
$ git checkout  TAG
  • 检查./autogen.sh
  • 配置
./configure
--with-gui=no \
-with-incompatible-bdb \
-prefix=$HOME  \
  • 编译
make
sudo make install
  • 测试是否成功
$ which bitcoind   #/usr/local/bin/bitcoind
$ whic bitcoin-cli #/usr/local/bitcoin-cli
  • 设置 API 访问的密码 (首次运行): 
    编辑 bitcoin/bitcoin.conf 内容如下. rpc 即 remote procedure call
rpcuser=bitcoinrpc
rpcpassword=...
  • 启动守护进程后台运行 , 
    $ bitcoind -daemon
  • 监视状态 
    $ bitcoin-cli getinfo

  • RPC

$ bitcoin-cli getinfo  #return json

$ bitcoin-cli getrawtransaction txid  #return hash-cont
$ bitcoin-cli decoderawransaction   hash-cont  #ret json
$ bitcoin-cli gettransaction txid   # json

$ bitcoin-cli getblockhash   bloack-id   # ret block-hash
$ bitcoin-cli getblock  block-hash #ret json

$ bitcoin-cli getnewaddress # ret 64位 十六进制的数  addr   公钥
$ bitcoin-cli dumpprivkey addr # ret 私钥

3. 密钥与地址

3.1. 公钥加密

 

3.2. 椭圆曲线乘法

 

 
比特币使用 secp256k1 标准定义的一种特殊的椭圆曲线和一系列常数 
secp256k1: 

y2=(x3+7)mod(p)y2=(x3+7)mod(p)


其中 p=2256−232−29−28−27−26−24−1p=2256−232−29−28−27−26−24−1 为素数

 

  • 无穷远点: 对应于 加法中的 0 , x=y=0(虽然不满足曲线方程, 但可作为特殊情况进行检验)
  • 椭圆曲线加法: 两个点 p1,p2 的加法 p1+p2 得到一个点 p3, 记 p3’(x,y) 是 直线 p1p2 与椭圆曲线不同于 p1,p2 的交点, 则 p3(x,-y) 
    注意 p1=p2 时, 直线 p1p2 定义为 p1 处的切线
  • 椭圆曲线乘法: kP=P+P+…+P(k times)kP=P+P+…+P(k times) 

3.3. 生成公钥

随机数私钥 k, 
取椭圆曲线上的一点 G, 称为生成点, 
公钥 K=kGK=kG, 注意是 mod p 的域内 
{% note info %} 这个过程是不可逆的 {% endnote %}

 

3.4. 生成比特币地址

 

  增加位权减少长度 
* Base64: 26 个小写字母、26 个大写字母、10 个数字以及两个符号(例 如 “+” 和“/”), 
* Base58: 不包括(0,O,l,I)的大小写字母和数字组成。 

 

3.5. 公钥格式

一个公钥是一个椭圆曲线上的点 (x, y)。而椭圆曲线实际是一个数学方程,曲线上的点实际是该方程的一个解。因此,知道了公钥的 x 坐标, 通过解方程 

y2 mod p=(x3+7) mod p


得到 y 坐标。这种方案可以让我们只存储公钥的 x 
坐标,略去 y 坐标,从而将公钥的大小和存储空间减少了 256 比特。

 

使用二进制算术计算椭圆曲线的时候,y 坐标可能是奇数或者偶数,分别对应前面所讲的 y 值的正负符号

压缩格式公钥和非压缩格式公钥看起来不同, 但是对应着同样的一个私钥。更重要的是,如果我们使用双哈希函数 (RIPEMD160(SHA256(K))) 将压缩格式公钥转化成比特币地址,得到的地址将会不同于由非压缩格式公钥产生的地址。这种结果会让人迷惑,因为一个私钥可以生成两种不同格式的公钥——压缩格式和非压缩格式,而这两种格式的公钥可以生成两个不同的比特币地址。但是,这两个不同的比特币地址的私钥是一样的。 

 

3.6. 私钥格式

当一个私钥被使用 WIF 压缩格式导出时,不但没有压缩,而且比 “非压缩格式” 私钥长出一个字节。这个多出来的一个字节是私钥被加了后缀 01,用以表明该私钥是来自于一个较新的钱包, 只能被用来生成压缩的公钥。 
私钥是非压缩的,也不能被压缩。“压缩的私钥”实际上只是表示 “用于生成压缩格式公钥的私钥”,而“非压缩格式私钥” 用来表明“用于生成非压缩格式公钥的私钥”。
 

 

十六进制压缩私钥格式在末尾有一个额外的字节(十六进制为 01)。虽然 Base58 编码版本前缀对于 WIF 和 WIF 压缩格式都是相同的(0x80),但在数字末尾添加一个字节会导致 Base58 编码的第一个字符从 5 变为 K 或 L,考虑到对于 Base58 这是十进制编码 100 号和 99 号之间的差别。对于 100 是一个数字长于 99 的数字,它有一个前缀 1,而不是前缀 9。当长度变化,它会影响前缀。 在 Base58 中,前缀 5 改变为 K 或 L,因为数字的长度增加一个字节。

要注意的是,这些格式并不是可互换使用的。在实现了压缩格式公钥的较新的钱包中,私钥只能且永远被导出为 WIF 压 缩格式(以 K 或 L 为前缀)。对于较老的没有实现压缩格式公钥的钱包,私钥将只能被导出为 WIF 格式(以 5 为前缀)导 出。这样做的目的就是为了给导入这些私钥的钱包一个信号:是否钱包必须搜索区块链寻找压缩或非压缩公钥和地址。

最全面的比特币 Python 库是 Vitalik Buterin 写的 pybitcointools

 

3.7. 高级密钥和地址

3.7.1. 加密私钥

  • 加密标准– BIP0038: 使用一个口令加密私钥并使用 Base58Check 对加密的私钥进行编码,这样加密的私钥就可以安全地保存在备份介质里,安全地在钱包间传输,保持密钥在任何可能被暴露情况下的安全性。(使用了 AES)

  • BIP0038 加密方案:输入一个比特币私钥,通常使用 WIF 编码过,base58chek 字符串的前缀 “5”。此外 BIP0038 加密方案需要一个长密码作为口令,通常由多个单词或一段复杂的数字字母字符串组成。BIP0038 加密方案的结果是一个由 base58check 编码过的加密私钥,前缀为 6P。如果你看到一个 6P 开头的的密钥,这就意味着该密钥是被加密过,并需要一个口令来转换(解码)该密钥回到可被用在任何钱包 WIF 格式的私钥(前缀为 5)

 

3.7.2. P2SH(Pay-to-Script Hash)

以数字 3 开头的比特币地址是 P2SH 地址,有时被错误的称谓多重签名或多重签名地址。他们指定比特币交易中受益人为哈希的脚本,而不是公钥的所有者

不同于 P2PKH 交易发送资金到传统 1 开头的比特币地址,资金被发送到 3 开头的地址时,需要的不仅仅是一个公钥的哈希值和一个私钥签名作为所有者证明。在创建地址的时候,这些要求会被指定在脚本中,所有对地址的输入都会被这些要求阻隔。

一个 P2SH 地址从交易脚本中创建,它定义谁能消耗这个交易输出 
script hash =RIPEMD160(SHA256(script))

产生的脚本哈希由 Base58Check 编码前缀为 5 的版本、编码后得到开头为 3 的编码地址

P2SH 函数最常见的实现是多重签名地址脚本。顾名思义,底层脚本需要多个签名来证明所有权,此后才能消费资金。设计比特币多重签名特性是需要从总共 N 个密钥中需要 M 个签名(也被称为 “阈值”),被称为 M-N 多签名,其 中 M 是等于或小于 N。例如,第一章中提到的咖啡店主 Bob 使用多重签名地址需要 1-2 签名,一个是属于他的密钥和一个属于他同伴的密钥,以确保其中一方可以签署消费一笔锁定到这个地址的输出。这类似于传统的银行中的一个 “联合账户”,其中任何一方配偶可以单独签单消费。

 

3.8. 纸钱包

将公钥和私钥 (可以是加密过的) 打印在纸上, 这期间都没有经过网络(直接用算法计算出), 所以又被称为冷钱包.

 

4. 钱包

广义上,钱包是一个应用程序,为用户提供交互界面。钱包控制用户访问权限,管理密钥和地址,跟踪余额以及创建和签名交易。 狭义上,即从程序员的角度来看,“钱包” 是指用于存储和管理用户密钥的数据结构。

一个常见误解是,比特币钱包里含有比特币。 事实上,钱包里只含有钥匙。 “钱币” 被记录在比特币网络的区块链中。 用户通过钱包中的密钥签名交易,从而来控制网络上的钱币。 在某种意义上,比特币钱包是密钥链。

 

4.1. 钱包种类

每个用户有一个包含多个密钥的钱包。根据包含的多个密钥是否相互关联, 可以分为两类

4.1.1. 非确定性钱包(nondeterministic wallet)

其中每个密钥都是从随机数**生成的。密钥彼此无关。这种钱包也被称为 “Just a Bunch Of Keys(一堆密钥)”,简称 JBOK 钱包。

 

4.1.2. 确定性钱包(deterministic wallet)

其中所有的密钥都是从一个主密钥派生出来,这个主密钥即为种子(seed)。该类型钱包中所有密钥都相互关联,如果有原始种子,则可以再次生成全部密钥。确定性钱包中使用了许多不同的密钥推导方法。最常用的推导方法是使用树状结构,称为分级确定性钱包或 HD 钱包。

 

4.2. HD 钱包

HD 钱包包含以树状结构衍生的密钥 

 

优点: 
* 树状结构可以被用来表达额外的组织含义。比如当一个特定分支的子密钥被用来接收交易收入并且有另一个分支的子密钥用来负责支付花费。不同分支的密钥都可以被用在企业环境中,这就可以支配不同的分支部门、子公司、具体功能以及会计类别。 
* 允许使用者去建立一个公共密钥的序列而不需要访问相对应的私钥。这可允许 HD 钱包在不安全的服务器中使用或者在每笔交易中发行不同的公共钥匙。公共钥匙不需要被预先加载或者提前衍生,而在服务器中不需要可用来支付的私钥。

 

4.3. 种子和助记词

由一系列英文单词生成种子是个标准化的方 
法,这样易于在钱包中转移、导出和导入。 
这些英文单词被称为助记词,标准由 BIP-39 定义

 

4.3.1. 创建助记词

助记词是由钱包使用 BIP-39 中定义的标准化过程自动生成的。 钱包从熵源开始,增加校验和,然后将熵映射到单词列表: 
1、创建一个 128 到 256 位的随机序列(熵)。 
2、提出 SHA256 哈希前几位(熵长 / 32),就可以创造一个随机序列的校验和。 
3、将校验和添加到随机序列的末尾。 
4、将序列划分为包含 11 位的不同部分。 
5、将每个包含 11 位部分的值与一个已经预先定义 2048 个单词的字典做对应。 
6、生成的有顺序的单词组就是助记码。 

 

4.3.2. 从助记词得到种子

助记词表示长度为 128 至 256 位的熵。 通过使用密钥延伸函数 PBKDF2,熵被用于导出较长的 
(512 位)种子。将所得的种子用于构建确定性钱包并得到其密钥。 
密钥延伸函数有两个参数:助记词和盐。其中盐的目的是增加构建能够进行暴力攻击的查找 
表的困难度。

7、PBKDF2 密钥延伸函数的第一个参数是从步骤 6 生成的助记符。 
8、PBKDF2 密钥延伸函数的第二个参数是盐。 由字符串常数 “助记词” 与可选的用户提供的密码字符串连接组成。 
9、PBKDF2 使用 HMAC-SHA512 算法,使用 2048 次哈希来延伸助记符和盐参数,产生一个 512 位的值作为其最终输出。 这个 512 位的值就是种子。 

 
{% note info %} 密钥延伸函数,使用 2048 次哈希是一种非常有效的保护,可以防止对助记词或密码短语的暴力攻击。 它使得攻击尝试非常昂贵(从计算的角度),需要尝试超过几千个密码和助记符组合,而这样可能产生的种子的数量是巨大的(2^512)。{% endnote %}

 

4.4. 可选密码短语

BIP-39 标准允许在推导种子时使用可选的密码短语。 如果没有使用密码短语,助记词是用由常量字符串 “助记词” 构成的盐进行延伸,从任何给定的助记词产生一个特定的 512 位种子。 如果使用密码短语,密钥延伸函数使用同样的助记词也会产生不同的种子。

{% note info %} 
BIP-39 中没有 “错误的” 密码短语。 每个密码都会导致一些钱包,只是未使用的钱包是空的。 
{% endnote %}

 

4.4.1. 功能

  • (存储在大脑中的)密码短语成为第二个因素,使得助记词不能单独使用,避免了助记词备份盗取后被利用。
  • 起到掩人耳目的效果,把密码短语指向有小额资金的钱包,分散攻击者注意力,使其不在关注拥有大额资金的 “真实” 钱包。

 

4.4.2. 风险

如果钱包所有者无行为能力或死亡,没有人知道密码,种子是无用的,所有存储在钱包中的资金都将永远丢失。相反,如果所有者将密码短语与种子备份在相同的地方,则违反了上述第二个因素的目的。虽然密码是非常有用的,但它们只能与仔细计划的备份和恢复流程结合使用,考虑到所有者个人风险的可能性,应该允许其家人恢复加密资产。

 

4.5. 从种子中创造 HD 钱包

 

4.5.1. 私有子密钥的衍生更

分层确定性钱包使用 CKD(child key derivation) 函数去从母密钥衍生出子密钥。 
子密钥衍生函数是基于单项哈希函数。这个函数结合了: 
* 一个母私钥或者公共钥匙(ECDSA 未压缩键) 
* 一个叫做链码(256 bits)的种子 
* 一个索引号(32 bits)

链码是用来给这个过程引入确定性随机数据的,使得索引不能充分衍生其他的子密钥。因此,有了子密钥并不能让它发现自己的姊妹密钥,除非你已经有了链码。最初的链码种子(在密码树的根部)是用随机数据构成的,随后链码从各自的母链码中衍生出来。

母公共钥匙——链码——以及索引号合并在一起并且用 HMAC-SHA512 函数散列之后可以 
生 512 位的散列。所得的散列可被拆分为两部分。散列右半部分的 256 位产出可以给子链当链码。左半部分 256 位散列以及索引码被加载在母私钥上来衍生子私钥。 如上图

改变索引可以让我们延长母密钥以及创造序列中的其他子密钥。比如子 0,子 1,子 2 等等。每一个母密钥可以有 2,147,483,647 (2^31) 个子密钥。2^31 是整个 2^32 范围可用的一半,因为另一半是为特定类型的推导而保留的.

如下则是扩展母公钥来衍生子公钥的传递机制。 

 

4.5.2. 扩展密钥

密钥以及链码的结合,就叫做扩展密钥(extended key). 可以简单地被储存并且表示为简单的将 256 位密钥与 256 位链码所并联的 512 位序列。

扩展密钥通过 Base58Check 来编码,从而能轻易地在不同的 BIP-32 兼容钱包之间导入导出。扩展密钥编码用的 Base58Check 使用特殊的版本号,这导致在 Base58 编码字符中,出现前缀 “xprv” 和“xpub”。

 

4.5.3. 公共子密钥的推导

分层确定性钱包的一个很有用的特点就是可以不通过私钥而直接从公共母密钥派生出公共子密钥的能 力。所以有两种衍生子公钥的方法:通过子私钥,或者就是直接通过母公钥。

因此,扩展密钥可以在 HD 钱包结构的分支中,被用来衍生所有的公钥(且只有公钥)。

应用: 用来创造非常保密的只有公钥配置。在配置中,服务器或者应用程序不管有没有私钥,都可以有扩展公钥的副本。这种配置可以创造出无限数量的公钥以及比特币地址。但是发送到这个地址里的任何比特币都不能使用。与此同时,在另一种更保险的服务器上,扩展私钥可以衍生出所有的对应的可签署交易以及花钱的私钥。

扩展的私钥可以被储存在纸质钱包中或者硬件设备中(比如 Trezor 硬件钱包),与此同时扩展公钥可以在线保存。根据意愿创造 “接收” 地址而私钥可以安全地在线下被保存。为了支付资金,使用者可以使用扩展的私钥离线签署比特币客户或者通过硬件钱包设备(比如 Trezor)签署交易。

这种方案的常见应用是安装扩展公钥电商的网络服务器上。网络服务器可以使用这个公钥衍生函数去给每一笔交易(比如客户的购物车)创造一个新的比特币地址。但为了避免被偷,网络服务商不会有任何私钥。没有 HD 钱包的话,唯一的方法就是在不同的安全服务器上创造成千上万个比特币地址,之后就提前上传到电商服务器上。这种方法比较繁琐而且要求持续的维护来确保电商服务器不 “用光” 公钥。

 

4.5.4. 硬化子密钥的衍生

{% note warning %} 
访问扩展公钥并不能得到访问子私钥的途径。但是,因为扩展公钥包含有链码,如果子私钥被知道或者被泄漏的话,链码就可以被用来衍生所有的其他子私钥 
{% endnote %}

为了应对这种风险,HD 钱包使用一种叫做硬化衍生 (hardened derivation)的替代衍生函数。

这就 “打破” 了母公钥以及子链码之间的关系。这个硬化衍生函数使用了母私钥去推导子链码,而不是母公钥。这就在母 / 子顺序中创造了一道“防火墙”——有链码但并不能够用来推算子链码或者姊妹私钥。强化衍生函数看起来几乎与一般的衍生的子私钥相同,不同的是母私钥被用来输入散列函数中而不是母公钥, 

 

4.5.5. 索引号码

用在衍生函数中的索引号码是 32 位的整数。为了区分密钥是从正常衍生函数中衍生出来还是从强化衍生函数中产出,这个索引号被分为两个范围。索引号在 0 和 2^31–1(0x0 to0x7FFFFFFF) 之间的是只被用在常规衍生。索引号在 2^31 和 2^32– 1(0x80000000 to 0xFFFFFFFF) 之间的只被用在强化衍生。

 

4.5.6. 钱包密钥识别符(路径)

HD 钱包中的密钥是用 “路径” 命名的,且每个级别之间用斜杠(/)字符来表示。由主私钥衍生出的私钥起始以 “m” 打头。由主公钥衍生的公钥起始以“M“打头。因此,母密钥生成的第一个子私钥是 m/0。第一个公钥是 M/0。第一个子密钥的子密钥就是 m/0/1,以此类推。

 

4.5.7. HD 钱包树状结构的导航

HD 钱包树状结构提供了极大的灵活性。每一个母扩展密钥有 40 亿个子密钥:20 亿个常规子密钥和 20 亿个强化子密钥。 而每个子密钥又会有 40 亿个子密钥并且以此类推。

由此带来问题, 对无限的树状结构进行导航就变得异常困难。尤其是对于在不同的 HD 钱包之间进行转移交易,因为内部组织到内部分支以及亚分支的可能性是无穷的。

两个比特币改进建议(BIPs) 
* 通过创建几个 HD 钱包树的提议标准。BIP-43 提出使用第一个强化子索引作为特殊的标识符表示树状结构的 “purpose”。 
* 基于 BIP-43,HD 钱包应该使用且只用第一层级的树的分支,而且有索引号码去识别结构并且有命名空间来定义剩余的树的目的地。举个例子,HD 钱包只使用分支 m/i’/ 是 为了表明那个被索引号 “i” 定义的特殊为目地。

BIP-44 指定了包含 5 个预定义树状层级的结构: 
 

m / purpose' / coin_type' / account' / change / address_index

 

第一层的 purpose 总是被设定为 44’。

第二层的 “coin_type” 特指币种并且允许多元货币 HD 钱包中的货币在第二个层级下有自己的亚树状结构。 
目前有三种货币被定义:Bitcoin is m/44’/0’、Bitcoin Testnet is m/44’/1’,以及 Litecoin is m/44’/2’。

第三层级是 “account”,举个例子,一个 HD 钱包可能包含两个比特币 “账户”:m/44’/0’/0’和 m/44’/0’/1’。每个账户都是它自己亚树的根。

第四层级就是 “change”。注意无论先前的层级是否使用强化衍生,这一层级使用的都是常规衍生。这是为了允许这一层级的树可以在不安全环境下,输出扩展公钥。

被 HD 钱包衍生的可用的地址是第四层级的子级,就是第五层级的树的 “address_index”

如图

 

5. 交易

根据比特币系统的设计原理,系统中任何其他的部分都是为了确保比特币交易可以被生成、能在比特币网络中得以传播和通过验证,并最终添加入全球比特币交易总账簿(比特币区块链)。比特币交易的本质是数据结构,这些数据结构中含有比特币交易参与者价值转移的相关信息。比特币区块链是一本全球复式记账总账簿,每个比特币交易都是在比特币区块链上的一个公开记录。

5.1. UTXO

比特币交易中的基础构建单元是交易输出。 交易输出是比特币不可分割的基本组合,记录在区块上,并被整个网络识别为有效。 比特币完整节点跟踪所有可找到的和可使用的输出,称为 “未花费的交易输出”(unspent transaction outputs),即 UTXO。所有 UTXO 的集合被称为 UTXO 集。每一个交易都代表 UTXO 集的变化(状态转换)。

用户的比特币 “余额” 是指用户钱包中可用的 UTXO 总和. 比特币钱包通过扫描区块链并聚集所有属于该用户的 UTXO 来计算该用户的余额 。大多数钱包维护一个数据库或使用数据库服务来存储所有 UTXO 的快速参考集,这些 UTXO 由用户所有的密钥来控制花费行为。

一个 UTXO 只能在一次交易中作为一个整体被消耗。一定数量的比特币价值在不同所有者之间转移,并在交易链中消耗和创建 UTXO。一笔比特币交易通过使用所有者的签名来解锁 UTXO,并通过使用新的所有者的比特币地址来锁定并创建 UTXO

 

5.2. 币基交易(CoinbaseTransaction)

它是每个区块中的第一笔交易,这种交易存在的原因是作为对挖矿的奖励,创造出全新的可花费比特币用来支付给 “赢家” 矿工。

{% note info %} 
输入和输出,哪一个是先产生的呢?先有鸡还是先有蛋呢?严格来讲,先产生输出,因为可以创造新比特币的 “币基交易” 没有输入,但它可以无中生有地产生输出。 
{% endnote %}

 

5.3. 交易输出

交易输出包含两部分: 
* 一定量的比特币,面值为 “聪”(satoshis), 是最小的比特币单位; 
* 确定花费输出所需条件的加密难题(cryptographic puzzle)

这个加密难题也被称为锁定脚本 (locking script), 见证脚本 (witness script), 或脚本公钥 (scriptPubKey)。

如下面的交易包含两个输出, 
每个输出包含 比特币的值 (本身编码是以聪为单位, 以 json 解码后单位是 比特币), 以及锁定脚本

vout: [
  {
    value: 0.015,
    scriptPubKey:
      "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
  },
  {
    value: 0.0845,
    scriptPubKey:
      "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
  }
];

5.4. 交易输入

包含 
* 一个指向 UTXO 的指针,通过指向 UTXO 被记录在区块链中所在的交易的哈希值和序列号来实现。 
* 解锁脚本,钱包构建它用以满足设定在 UTXO 中的支出条件。 大多数情况下,解锁脚本是一个证明比特币所有权的数字签名和公钥,但是并不是所有的解锁脚本都包含签名。 
* 序列号。

如下面的交易包含一个输入 
* txid: 引用的 UTXO 交易, 
* vout(输出索引) : 标识来自 txid 的交易的哪个输出被引用 (0-indexed) 
* scriptSig(解锁脚本): 满足放置在 UTXO 上的条件, 解锁它用于支出 
* sequence: 序列号

"vin": [
  {
    txid: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
    vout: 0,
    scriptSig:
      "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
    sequence: 4294967295
  }
];

5.5. 交易过程

首先检索引用的 UTXO,检查其锁定脚本,然后使用它来构建所需的解锁脚本以满足此要求。

{% note info %} 
除了对包含它引用的交易之外,我们无从了解这个 UTXO 的任何内容。我们不知道它的价值(多少 satoshi 金额),我们不知道设置支出条件的锁定脚本。要找到这些信息,我们必须通过检索整个交易来检索被引用的 UTXO。请注意,由于输入的值未明确说明,因此我们还必须使用被引用的 UTXO 来计算在此交易中支付的费用 
{% endnote %}

当一笔比特币交易被验证时,每一个输入值中的解锁脚本与其对应的锁定脚本同时 (互不干扰地)执行,以确定这笔交易是否满足支付条件。

5.6. 交易费

大多数交易包含交易费(矿工费),这是为了确保网络安全而给比特币矿工的一种补偿。费用本身也作为一个安全机制,使经济上不利于攻击者通过交易来淹没网络。

大多数钱包自动计算并计入交易费。但是, 如果你以编程方式构造交易,或者使用命令行界面,你必须手动计算并计入这些费用。

任何创建交易的比特币服务,包括钱包,交易所,零售应用等,都必须实现动态收费。动态费用可以通过第三方费用估算服务或内置的费用估算算法来实现

费用估算算法根据网络能力和 “竞争” 交易提供的费用计算适当的费用。大多数服务为用户提供高、中、低优先费用的选择。高优先级意味着用户支付更高交易费.

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

{% note danger %} 
如果你忘记了在手动构造的交易中增加找零的输出,系统会把找零当作交易费来处理。“不用找了!” 也许不是你的真实意愿。 
{% endnote %}

一般交易费是根据交易的数据正相关的, 而不是交易的比特币值, 所以如果有很多个 输入 (很多个 UTXO 零钱), 或很多输出, 造成数据量很大, 而使交易费很多.

 

5.7. 交易脚本语言

5.7.1. 图灵非完备性

有条件的流控制以外,没有循环或复杂流控制能力。这限制确保该语言不被用于创造无限循环或其它类型的逻辑炸弹,这样的炸弹可以植入在一笔交易中,引起针对比特币网络的 “拒绝服务” 攻击。因为每一笔交易都会被网络中的全节点验证,受限制的语言能防止交易验证机制被作为一个漏洞而加以利用

 

5.7.2. 去中心化验证

没有任何中心主体能凌驾于脚本之上,也没有中心主体会在脚本被执行后对其进行保存。所以执行脚本所需信息都已包含在脚本中。一个脚本能在任何系统上以相同的方式执行。

 

5.7.3. 脚本构建 (锁定与解锁)

5.7.3.1. 锁定脚本 (Locking Script)

一个放置在输出上面的花费条件. 它指定了今后花费这笔输出必须要满足的条件。曾被称为脚本公钥(scriptPubKey) , 也被称为见证脚本(witness script),或者更一般地说,它是一个加密难题(cryptographic puzzle)。这些术语在不同的抽象层次上都意味着同样的东西。

5.7.3.2. 解锁脚本 (Unlocking Script)

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

每一个比特币验证节点会通过同时执行锁定和解锁脚本来验证一笔交易。每个输入都包含一个解锁脚本,并引用了之前存在的 UTXO。 验证软件将复制解锁脚本,检索输入所引用的 UTXO,并从该 UTXO 复制锁定脚本。 然后依次执行解锁和锁定脚本。如果解锁脚本满足锁定脚本条件,则输入有效。所有输入都是**验证的,作为交易总体验证的一部分。

形式上两个脚本拼接如下, 如后用栈的方式执行, 右边为栈顶. 最终结果为 TRUE 则 满足条件 

 

如 
锁定脚本: 3 OP_ADD 5 OP_EQUAL 
解锁脚本: 2 
拼接后为: 2 3 OP_ADD 5 OP_EQUAL

实际过程 
使用堆栈执行引擎执行解锁脚本。如果解锁脚本在执行过程中未报错(例如:没有 “悬挂” 操作码),则复制主堆栈(而不是备用堆栈),并执行锁定脚本。如果从解锁脚本中复制而来的堆栈数据执行锁定脚本的结果为“TRUE”,那么解锁脚本就成功地满足了锁定脚本所设条件

如 
锁定脚本: OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG 
解锁脚本: <Cafe Signature> <Cafe Public Key> 
验证过程 

 

 

5.8. 数字签名 (ECDSA)

5.8.1. 如何工作

  • 使用私钥(签名密钥)从消息(交易)创建签名
  • 给定消息和公钥允许任何人验证签名

 

5.8.2. 作用

数字签名在不揭示私钥的情况下提供私钥的所有权证明。

数字签名在比特币中的作用: 
1. 签名证明私钥的所有者,即资金所有者,已经授权支出这些资金。 
2. 授权证明是不可否认的(不可否认性)。 
3. 签名证明交易(或交易的具体部分)在签字之后没有也不能被任何人修改。

{% note info %} 
每个交易输入和它可能包含的任何签名完全**于任何其他输入或签名。多方可以协作构建交易,并各自仅签一个输入。 
{% endnote %}

 

5.8.3. 创建与验证

{% note warning %} 
公钥是一个二维数组, 图形上是一个点 
{% endnote %}

比特币中使用的数字签名算法是椭圆曲线数字签名算法(Elliptic Curve Digital SignatureAlgorithm , ECDSA)

签名算法首先生成一个 ephemeral(临时) 私钥 (即随机数 ktmp ), 记临时私钥生成的临时公钥的 x 坐标为 x, p 是椭圆曲线的主要顺序, 记用户的私钥为 k, 公钥为 K(是一个点) , G 是椭圆曲线发生器点. 
则 

y=ktmp-1(hash(trasanction)+x∗k) mod p
得到签名为 signature=(x,y)

验证过程如下, 计算 

(xverify,yverify)=y−1(hash(transaction)∗G+x∗K)
如果 xverify=x, 则签名有效

{% note danger %} 
如果在两个不同的交易中,在签名算法中使用相同的值 k,则私钥可以被计算并暴露给世界! 
{% endnote %}

重用 k 值的最常见原因是未正确初始化的随机数生成器。为了避免这个漏洞,业界最佳实践不是用熵播种的随机数生成器生成 k 值,而是使用交易数据本身播种的确定性随机进程。

5.8.4. 签名序列化 (DER)

如用 DER((Distinguished Encoding Rules)编码后的签名为 3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301 

 

5.8.5. 签名哈希类型 (SIGHASH)

SIGHASH, 指示交易数据的哪一部分. SIGHASH 标志是附加到签名的单个字节。每个签名都有一个 SIGHASH 标志,该标志在不同输入之间也可以不同。 有三个 标志 如下 

 

另外还有一个修饰符标志 SIGHASH_ANYONECANPAY,它可以与前面的每个标志组合。 当设置 ANYONECANPAY 时,只有一个输入被签名,其余的(及其序列号)打开以进行修改。ANYONECANPAY 的值为 0x80,并通过按位 OR 运算,得到如下所示的组合标志: 

 

SIGHASH 标志在签名和验证期间应用的方式是建立交易的副本和删节其中的某些字段(设置长度为零并清空),继而生成的交易被序列化,SIGHASH 标志被添加到序列化交易的结尾,并将结果哈希化 ,得到的哈希值本身即是被签名的 “消息”。 基于 SIGHASH 标志的使用,交易的不同部分被删节。 所得到的哈希值取决于交易中数据的不同子集。

例如 
* ALL | ANYONECANPAY 可以用来发起众筹 
* NONE 可用于构建特定数量的” 不记名支票” 或” 空白支票” 
* NONE | ANYONECANPAY 造可以用来建造一个 “吸尘器”。在他们的钱包中拥有微小 UTXO 的用户无法花费这些费用,因为手续费用超过了这些微小 UTXO 的价值。借助这种类型的签名,微小 UTXO 可以为任何人捐赠,以便随时随地收集和消费。

6. 高级交易和脚本

6.1. 多重签名

多重签名脚本设置了一个条件,其中 N 个公钥被记录在脚本中,并且至少有 M 个必须提供签名来解锁资金。这也称为 M-N 方案,其中 N 是密钥的总数,M 是验证所需的签名的数量。例如,2-3 的多重签名是三个公钥被列为潜在签名人,至少有 2 个有效的签名才能花费资金。

锁定脚本格式:

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

解锁脚本格式:

<Signature  i1>  <Signature i2> ... <Signature  im>

然而由于实施中 CHECKMULTISIG 的 bug: 会在弹出解锁脚本时从栈中多弹出一个, 所以 
解锁脚本规定为

0 <Signature    i1> <Signature  i2> ... <Signature  im>

 

6.2. P2SH(Pay-to-Script-Hash)

6.2.1. 多重签名的问题

P2SH 是针对 多重签名 以下问题提出的

  • 老板要在客户付款前将该脚本发送给每一位客户,而每一位顾客也必须使用特制的能产生客户交易脚本的比特币钱包软件,每位顾客还得学会如何利用脚本来完成交易。

  • 由于脚本可能包含特别长的公钥,最终的交易脚本可能是最初交易脚本长度几倍。额外长度的脚本将给客户造成费用负担。

  • 一个长的交易脚本将一直记录在所有节点的随机存储器的 UTXO 集中,直到该笔资金被使用。采用这种复杂输出脚本使得在实际交易中变得困难重重。

6.2.2. 赎回脚本

在 P2SH 支付中锁定脚本由哈希运算后的 20 字节的散列值取代,被称为赎回脚本。当一笔交易试图支付 UTXO 时,要解锁支付脚本,它必须含有与哈希相匹配的脚本。 
如下 

 

 

赎回脚本本身之后作为解锁脚本在输出花费时的一部分出现。 这使得给矿工的交易费用从发送方转移到收款方,复杂的计算工作也从发送方转移到收款方。

 

6.2.3. P2SH 地址

P2SH 旨在使复杂脚本的运用能与直接向比特币地址支付一样简单。

P2SH 能将脚本哈希编译为一个地址, 以 “3” 为前缀,该地址与一个脚本相对应而非与一个公钥相对应,但是它的效果与比特币地址支付别无二致。

 

6.2.4. 优点

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

{% note warning %} 
不能将 P2SH 植入 P2SH 赎回脚本,因为 P2SH 不能自循环。虽然在技术上可以将 RETURN 包含在赎回脚本中,但由于规则中没有策略阻止来, 因此在验证期间执行 RETURN 将导致交易被标记为无效. 
{% endnote %}

{% note danger %} 
P2SH 锁定脚本脚本对于赎回脚本本身未提供任何描述。P2SH 交易即便在赎回脚本无效的情况下也会被认为有效, 这时可能会被锁死在 P2SH 这个交易中,导致不能花费这笔比特币. 
{% endnote %}

 

6.3. 数据记录输出(RETURN 操作符)

运用比特币的区块链技术存储与比特币支付不相关数据, 例如,为文件记录电子指纹,则任何人都可以通过该机制在特定的日期建立关于文档存在性的证明。

此类交易仅将比特币地址当作自由组合的 20 个字节而使用,进而会产生不能用于交易的 UTXO。因为比特币地址只是被当作数据使用,并不与私钥相匹配,所以会导致 UTXO 不能被用于交易,因而是一种伪支付行为。因此,这些交易永远不会被花费,所以永远不会从 UTXO 集中删除,并导致 UTXO 数据库的大小永远增加或 “膨胀”

Return 允许开发者在交易输出上增加 80 字节的非交易数据。与伪交易型的 UTXO 不同,Return 创造了一种明确的可复查的非交易型输出,此类数据无需存储于 UTXO 集。Return 输出被记录在区块链上,会消耗磁盘空间,也会导致区块链规模的增加,但它们不存储在 UTXO 集中,因此也不会使得 UTXO 内存膨胀.

RETURN 不涉及可用于支付的解锁脚本的特点, RETURN 不能使用其输出中所锁定的资金,因此没有必要记录在蕴含潜在成本的 UTXO 集中,所以 RETURN 实际是没有成本的。

RETURN 常为一个金额为 0 的比特币输出, 因为任何与该输出相对应的比特币都会永久消失。假如一笔 RETURN 被作为一笔交易的输入,脚本验证引擎将会阻止验证脚本的执行,将标记交易为无效

 

6.4. 时间锁 (Timelocks)

时间锁是只允许在一段时间后才允许支出的交易, 锁定时间也称为 nLocktime. 
* nLocktime=0,即时传播和执行 
* 0

 

6.4.1. 检查锁定时间验证 Check Lock Time Verify (CLTV)

通过在输出的赎回脚本中添加 CLTV 操作码来限制输出,从而只能在指定的时间过后使用. CLTV 不会取代 nLocktime,而是限制特定的 UTXO,并通过将 nLocktim 设置为更大或相等的值,从而达到在未来才能花费这笔钱的目的。

一个 P2SH 交易的赎回脚本如下: Alice 转给 Bob 的钱, 3 个月才到

<now    +   3   months> CHECKLOCKTIMEVERIFY DROP    DUP HASH160 <Bob's  Public  Key Hash>   EQUALVERIFY CHECKSIG

 

如果 Bob 尝试引用 (花费) 这个 UTXO, 他使用他的签名和公钥在该输入的解锁脚本,并将交易 nLocktime 设置为等于或更大于 Alice 设置的 CHECKLOCKTIMEVERIFY 时间锁。然后 Bob 在比特币网络上广播交易。

矿工对交易评估如下: 
如果 Alice 设置的 CHECKLOCKTIMEVERIFY 参数小于或等于支出交易的 nLocktime,脚本执行将继续(就好像执行 “无操作” 或 NOP 操作码一样). 否则, CHECKLOCKTIMEVERIFY 失败并停止执行,标记交易无效: 
1. 堆栈是空的要么 
2. 堆栈中的顶部项小于 0; 要么 
3. 顶层堆栈项和 nLocktime 字段的锁定时间类型(高度或者时间戳)不相同; 要么 
4. 顶层堆栈项大于交易的 nLocktime 字段; 要么 
5. 输入的 nSequence 字段为 0xffffffff。

6.4.2. 相对时间锁

nLocktime 和 CLTV 都是绝对时间锁定,它们指定绝对时间点。

它们允许将两个或多个相互依赖的交易链接在一起,同时对依赖于从先前交易的确认所经过的时间的一个交易施加时间约束。换句话说,在 UTXO 被记录在块状块之前,时钟不开始计数。这个功能在双向状态通道和闪电网络中特别有用

交易级相对时间锁定是作为对每个交易输入中设置的交易字段 nSequence 的值的共识规则实现的。脚本级相对时间锁定使用 CHECKSEQUENCEVERIFY(CSV)操作码实现。

6.4.2.1. nSequence

在每个输入中加多一个 nSequence 字段来设置此类相对时间锁. ,如果输入的交易的序列值小于 2^32 (0xFFFFFFFF),就表示尚未 “确定” 的交易。

nSequence 的原始含义从未被正确实现,并且在不利用时间锁定的交易中 nSequence 的值通常设置为 232232. 对于具有 nLocktime 或 CHECKLOCKTIMEVERIFY 的交易,nSequence 值必须设置为小于 232232, 以使时间锁定器有效。通常设置为 232−1  (0xFFFFFFFE)232−1  (0xFFFFFFFE)。

一笔输入交易,当输入脚本中的 nSequence 值小于 2^31 时,就是相对时间锁定的输入交易。

交易可以包括时间锁定输入(nSequence <2^31)和没有相对时间锁定(nsequence> =2^31)的输入。 nSequence 值以块或秒为单位, 类型标志用于区分计数块和计数时间(以秒为单位)的值。类型标志设置在第 23 个最低有效位(即值 1 << 22)。如果设置了类型标志,则 nSequence 值将被解释为 512 秒的倍数。如果未设置类型标志,则 nSequence 值被解释为块数。

当将 nSequence 解释为相对时间锁定时,只考虑 16 个最低有效位。一旦评估了标志(位 32 和 23),nSequence 值通常用 16 位掩码(例如 nSequence&0x0000FFFF)“屏蔽”。 

 

6.4.2.2. CHECKSEQUENCEVERIFY(CSV)

脚本操作码, 在 UTXO 的赎回脚本中评估时,CSV 操作码仅允许在输入 nSequence 值大于或等于 CSV 参数的交易中进行消耗。

 

6.4.3. Median-Time-Past

在比特币中, 墙上时间(wall time)和共识时间之间存在微妙但非常显著的差异。比特币是一个分散的网络,这意味着每个参与者都有自己的时间观。网络上的事件不会随时随地发生。网络延迟必须考虑到每个节点的角度。最终,所有内容都被同步,以创建一个共同的分类帐。

通过取最后 11 个块的时间戳并计算其中位数作为 “中位时间过去” 的值, 作为共识时间,并被用于所有的时间计算. 通过这个方法,没有一个矿工可以利用时间戳从具有尚未成熟的时间段的交易中获取非法矿工费。

 

6.5. 条件子句 (Conditional Clauses)

可以控制流量. 
由于比特币脚本语言是一种堆栈语言, 则其条件控制如下

    condition
IF
        code    to  run when    condition   is  true
ELSE
        code    to  run when    condition   is  false
ENDIF
code    to  run in  either  case

 

另外也有带有 VERIFY 操作码的条件子句

任何以 VERIFY 结尾的操作码。 VERIFY 后缀表示如果评估的条件不为 TRUE,脚本的执行将立即终止,并且该交易被视为无效。VERIFY 后缀充当保护子句,只有在满足前提条件的情况下才会继续。 

HASH160 <expected   hash>   EQUALVERIFY <Bob's  Pubkey> CHECKSIG

等同于

HASH160 <expected   hash>   EQUAL
IF
            <Bob's  Pubkey> CHECKSIG
ENDIF

使用 IF 的脚本与使用具有 VERIFY 后缀的操作码相同; 他们都作为保护条款。 然而,VERIFY 的构造更有效率,使用较少的操作码。

{% note info %} 
诸如 EQUAL 之类的操作码会将结果(TRUE / FALSE)推送到堆栈上,留下它用于后续操作码的评估。 相比之下,操作码 EQUALVERIFY 后缀不会在堆栈上留下任何东西。 在 VERIFY 中结束的操作码不会将结果留在堆栈上。 
{% endnote %}

在多重签名, 赎回脚本中使用 
赎回脚本

IF
    <Alice's    Pubkey> CHECKSIG
ELSE
    <Bob's  Pubkey> CHECKSIG
ENDIF

而条件应该在解锁脚本中, 
Alice 用解锁脚本<Alice's Sig> 1
Bob 用解锁脚本<Bob's Sig> 0

一个复杂的例子

多重签名的计划的参与者是 Mohammed,他的两个合作伙伴 Saeed 和 Zaira,以及他们的公司律师 Abdul。三个合作伙伴根据多数规则作出决定,因此三者中的两个必须同意。然而,如果他们的钥匙有问题,他们希望他们的律师能够用三个合作伙伴签名之一收回资金。最后,如果所有的合作伙伴一段时间都不可用或无行为能力,他们希望律师能够直接管理该帐户。

具有时间锁定(Timelock)变量的多重签名

IF
        IF
                2
        ELSE
                <30 days>   CHECKSEQUENCEVERIFY DROP
                <Abdul  the Lawyer's    Pubkey> CHECKSIGVERIFY
                1
        ENDIF
        <Mohammed's Pubkey> <Saeed's    Pubkey> <Zaira's    Pubkey> 3   CHECKMULTISIG
ELSE
        <90 days>   CHECKSEQUENCEVERIFY DROP
        <Abdul  the Lawyer's    Pubkey> CHECKSIG
ENDIF

第二个执行路径只能在 UTXO 创建 30 天后才能使用。 那时候,它需要签署 Abdul(律师)和三个合作伙伴之一(三分之一)。 
解锁第二个执行路径的脚本 (Lawyer + 1-of-3)

0   <Saeed's    Sig>    <Abdul's    Sig>    FALSE   TRUE

{% note info %} 
* 此解锁脚本开头的 0 是因为 CHECKMULTISIG 中的错误从堆栈中弹出一个额外的值 
* 先 FALSE 后 TRUE, 分析栈的顺序

{% endnote %}

 

7. P2P 网络架构

P2P 是指位于同一网络中的每台计算机都彼此对等,各个节点共同提供网络服务,不存在任何 “特殊” 节点。每个网络节点以 “扁平(flat)” 的拓扑结构相互连通。 在 P2P 网络中不存在任何服务端(server)、中央化的服务、以及层级结构。P2P 网络的节点之间交互运作、协同处理:每个节点在对外提供服务的同时也使用网络中其他节点所提供的服务。P2P 网络也因此具有可靠性、去中心化,以 及开放性。

尽管比特币 P2P 网络中的各个节点相互对等,但是根据所提供的功能不同,各节点可能具有不同的角色。每个比特币节点都是路由、区块链数据库、挖矿、钱包服务的功能集合。

全节点含有 区块链的完整拷贝, 而轻量级结点只有一部分, 交易验证的方式是 简单支付验证(SPV)

常见结点类型

 

 

 

7.1. 扩展比特币网络

运行比特币 P2P 协议的比特币主网络由大约 5000-8000 个运行着不同版本比特币核心客户端(Bitcoin Core)的监听节 点、以及几百个运行着各类比特币 P2P 协议的应用(例如 BitcoinClassic, Bitcoin Unlimited, BitcoinJ, Libbitcoin, btcd, and bcoin 等)的节点组成。比特币 P2P 网络中的一小部分节点也是挖矿节点,它们竞争挖矿、验证交易、并创建新的区块。许多连接到比特币网络的大型公司运行 着基于 Bitcoin 核心客户端的全节点客户端,它们具有区块链的完整拷贝及网络节点,但不具备挖矿及钱包功能。这些节点是网络中的边缘路由器(edgerouters),通过它们可以搭建其他服务,例如交易所、钱包、区块浏览器、商家支付处理(merchant payment processing)等 

 

7.2. 网络发现

当新的网络节点启动后,为了能够参与协同运作,它必须发现网络中的其他比特币节点。新的网络节点必须发现至少一个网络中存在的节点并建立连接。由于比特币网络的拓扑结构并不基于节点间的地理位置,因此各个节点之间的地理信息完全无关。在新节点连接时,可以随机选择网络中存在的比特币节点与之相连。

节点通常采用 TCP 协议、使用 8333 端口. 。在建立连接时,该节点会通过发送一条包含基本认证内容的 version 消息开始 “握手” 通信过 程. 包括如下内容: 
* nVersion: 比特币 P2P 协议所采用的版本 
* nLocalServices: 一组该节点支持的本地服务列表,当前仅支持 NODE_NETWORK▷ 
* nTime: 当前时间 
* addrYou: 当前节点可见的远程节点的 IP 地址 
* addrMe: 本地节点所发现的本机 IP 地址 
* subver: 指示当前节点运行的软件类型的子版本号 
* BaseHeight: 当前节点区块链的区块高度

接收版本消息的本地对等体将检查远程对等体报告的 nVersion,并确定远端对等体是否兼容。 如果远程对等体兼容,则本地对等体将确认版本消息,并通过发送一个 verack 建立连接。 

 

当建立一个或多个连接后,新节点将一条包含自身 IP 地址的 addr 消息发送给其相邻节点。相邻节点再将此条 addr 消息依 次转发给它们各自的相邻节点,从而保证新节点信息被多个节点所接收、保证连接更稳定。然后,新接入的节点可以向 它的相邻节点发送 getaddr 消息,要求它们返回其已知对等节点的 IP 地址列表。

 

 

节点必须连接到若干不同的对等节点才能在比特币网络中建立通向比特币网络的种类各异的路径(path)。由于节点可以随时加入和离开,通讯路径是不可靠的。因此,节点必须持续进行两项工作:在失去已有连接时发现新节点,并在其他节点启动时为其提供帮助。节点启动时只需要一个连接,因为第一个节点可以将它引荐给它的对等节点,而这些节点又会进一步提供引荐。一个节点,如果连接到大量的其他对等节点,这既没必要,也是对网络资源的浪费。在启动完成 后,节点会记住它最近成功连接的对等节点;因此,当重新启动后它可以迅速与先前的对等节点网络重新建立连接。如果先前的网络的对等节点对连接请求无应答,该节点可以使用种子节点进行重启动。

如果已建立的连接没有数据通信,所在的节点会定期发送信息以维持连接。如果节点持续某个连接长达 90 分钟没有任何通信,它会被认为已经从网络中断开,网络将开始查找一个新的对等节点

 

7.3. 同步区块链

对于全节点, 需要同步备份整个区块链.. 
此过程从发送 version 消息开始,这是因为该消息中含有的 BestHeight 字段标示了一个节点当前的区块链高度(区块数量)。对等节点们会交换一个 getblocks 消息,其中包含他们本地区块链的顶端区块哈希值(指纹)。如果某个对等节点识别出它接收到的哈希值并不属于顶端区块,而是属于一个非顶端区块的旧区块,那么它就能推断出:其自身的本地区块链比其他对等节点的区块链更长。

拥有更长区块链的对等节点, 识别出第 一批可供分享的 500 个区块,通过使用 inv(inventory)消息把这些区块的哈希值传播出去。缺少这些区块的节点便可以 通过各自发送的 getdata 消息来请求得到全区块信息,用包含在 inv 消息中的哈希值来确认是否为正确的被请求的区块, 从而读取这些缺失的区块。 

 

7.4. 简单支付验证 (SPV)

SPV 节点只需下载区块头,而不用下载包含在每个区块中的交易信息。由此产生的不含交易信息的区块链,大小只有完整区块链的 1/1000。SPV 节点不能构建所有可用于消费的 UTXO 的全貌. SPV 节点验证交易时依赖对等节点 “按需” 提供区块链相关部分的局部视图。

如要检查第 300000 号区块的某个交易, SPV 节点会在该交易信息和它所在区块之间用 merkle 路径建立一条链接。然后 SPV 节点一直等待,直到序号从 300,001 到 300,006 的六个区块堆叠在该交易所在的区块之上,并通过确立交易的深度是在第 300,006 区块~ 第 300,001 区块之下来验证交易的有效性。

SPV 节点可以证实某个交易的存在性,但它不能验证某个交易(譬如同一个 UTXO 的双重支付)不存在,这是因为 SPV 节点没有一份关于所有交易的记录。这个漏洞会被针对 SPV 节点的拒绝服务攻击或双重支付型攻击所利用。为了防御这些攻击,SPV 节点需要随机连接到多个节点,以增加与至少一个可靠节点相连接的概率。这种随机连接的需求意味着 SPV 节 点也容易受到网络分区攻击或 Sybil 攻击。在后者情况中,SPV 节点被连接到虚假节点或虚假网络中,没有通向可靠节点或真正的比特币网络的连接。 

 

7.5. Bloom filter

SPV 节点对特定数据的请求可能无意中透露了钱包里的地址信息。例如,监控网络的第三方可以跟踪某个 SPV 节点上的钱包所请求的全部交易信息,并且利用这些交易信息把比特币地址和钱包的用户关联起来,从而损害了用户的隐私。

Bloom 过滤器通过一个采用概率而不是固定模式的过滤机制,允许 SPV 节点只接收交易信息的子集,同时不会精确泄露哪些是它们感兴趣的地址。

Bloom 过滤器可以让 SPV 节点指定交易的搜索模式,该搜索模式可以基于准确性或私密性的考虑被调节。如果过滤器只包含简单的关键词,更多相应的交易会被搜索出来,在包含若干无关交易的同时有着更高的私密性。

构成: 
一个可变长 (N) 的 二进制数组, 数组初始值为 0, . 一组数量可变 (M) 的哈希函数, 哈希函数输出为 1—N, 对应数组, 且为确定性函数.

算法如下 
记数组 arr[N] , M 个 hash 函数 hs={h1,h2,…,hM}hs={h1,h2,…,hM} 
关键字 keys={k1,k2,…,ki}keys={k1,k2,…,ki}

过滤器记录关键字过程

arr[N]={0}  # initialization
for key in keys:
    for hash  in   hs:
        arr[hash(key)] = 1

 

判断一个关键字是否被过滤器记录: 将关键字分别代入各 hash 函数 计算对比 arr 对应的值, 如果有 0, 则没有被记录, 如果全为 1, 则 可能 被记录.(基于概率)

 

7.6. SPV 节点如何使用 Bloom filter

数组置 0, 然后 SPV 节点将列出所有感兴趣的地址,密钥和散列,它将通过从其钱包控制的任何 UTXO 中提取公钥哈希和脚本哈希和交易 ID 来实现。 SPV 节点然后将其中的每一个添加到 Bloom 过滤器,以便如果这些模式存在于交易中,则 Bloom 过滤器将 “匹配”,而不会自动显示模式。

然后,SPV 节点将向对等体发送一个过滤器加载消息,其中包含在连接上使用的 bloom 过滤器。在对等体上,针对每个传入交易检查 Bloom 过滤器。完整节点根据 bloom 过滤器检查交易的几个部分,寻找匹配,

只有与过滤器匹配的交易才会发送到节点。响应于来自节点的 getdata 消息,对等体将发送一个 merkleblock 消息,该消息仅包含与过滤器匹配的块和每个匹配交易的 merkle 路径。然后,对等体还将发送包含由过滤器匹配的交易的 tx 消息。

 

7.7. 加密和认证连接

Tor 传输和 P2P 认证和加密

 

7.8. 交易池

比特币网络中几乎每个节点都会维护一份未确认交易的临时列表,被称为内存池或交易池

有些节点的实现还维护一个单独的孤立交易池。如果一个交易的输入与某未知的交易有关,如与缺失的父交易相关,该 孤立交易就会被暂时储存在孤立交易池中直到父交易的信息到达。当一个交易被添加到交易池中,会同时检查孤立交易池,看是否有某个孤立交易引用了此交易的输出(子交易)。

交易池和孤立交易池(如有实施)都是存储在本地内存中,并不是存储在永久性存储设备(如硬盘)里。

 

8. 区块链

平均每个区块至少包含超过 500 个交易 
区块头由三组区块元数据组成: 
* 引用父区块哈希值的数据,用于与前一区块相连接。 
* 难度、时间戳和 nonce, 与挖矿竞争相关 
* merkle 树根

因为创世区块被编入到比特币客户端软件里,所以每一个节点都始于至少包含一个区块的区块链,这能确保创世区块不会被改变。每一个节点都 “知道” 创世区块的哈希值、结构、被创建的时间和里面的一个交易。因此,每个节点都把该区块作为区块链的首区块,从而构建了一个安全的、可信的区块链。

在比特币网络中,Merkle树被用来归纳一个区块中的所有交易, 同时生成整个交易集合的数字指纹,且提供了一种校验区块是否存在某交易的高效途径。。如果仅有奇数个交易需要归纳,那最后的交易就会被复制一份以构成偶数个叶子节点,

不需要下载整个区块而通过 Merkle 路径去验证交易的存在, 又被称作简单支付验证.

一个 SPV 节点想知道它钱包中某个比特币地址即将到达的支付。该节点会在节点间的通信链接上建立起 bloom 过滤器,限制只接受含有目标比特币地址的交易。当对等体探测到某交易符合 bloom 过滤器,它将以 Merkleblock 消息的形式发送该区块。Merkleblock 消息包含区块头和一条连接目标交易与 Merkle 根的 Merkle 路径。SPV 节点能够使用该路径找到与该交易相关的区块,进而验证对应区块中该交易的有无。SPV 节点同时也使用区块头去关联区块和区块链中的其余区块。这两种关联,交易与区块、区块和区块链,就可以证明交易存在于区块链。简而言之,SPV 节点会收到少于 1KB 的有关区块头和 Merkle 路径的数据,其数据量比一个完整的区块(目前大约有 1MB)少了一千多倍。\

比特币的测试区块链 
* testnet–比特币的试验场: 实际上它和主网只有两个区别:testnet 币是毫无价值的,挖掘难度足够低,任何人都可以相对容易地使用 testnet 币)。 
任何打算在比特币主干网上用于生产的软件开发都应该首先在 testnet 上用测试币进行测试。免受由于软件错误而导致的金钱损失,也可以保护网络免受由于软件错误导致的意外攻击 
* regtest–本地区块链: regtest 代表回归测试, 是比特币的一中核心功能, 可以创建本地区块链以进行测试.

开发过程: 首先在 regtest 上部署每个变更,然后在 testnet 上进行测试,最后实现生产, 部署到比特币网络上。

 

9. 挖矿与共识

挖矿巩固了去中心化的清算交易机制,通过这种机制,交易得到验证和清算, 实现去中心化的安全机制,是 P2P 数字货币的基础。

矿工们在挖矿过程中会得到两种类型的奖励:创建新区块的新币奖励,以及区块中所含交易的交易费。矿工们争相完成一种基于加密哈希算法的数学难题,这些难题的答案包括在新区块中,作为矿工的计算工作量的证明,被称为”“工作量证明”。该算法的竞争机制以及获胜者有权在区块链上进行交易记录的机制,这二者是比特币安全的基石。

比特币的去中心化共识由所有网络节点的 4 种**过程相互作用而产生: 
* 每个全节点依据综合标准对每个交易进行**验证 
* 通过完成工作量证明算法的验算,挖矿节点将交易记录**打包进新区块 
* 每个节点**的对新区块进行校验并组装进区块链 
* 每个节点对区块链进行**选择,在工作量证明机制下选择累计工作量最大的区块链。

它们之间如何相互作用并达成全网的自发共识,从而使任意节点组合出 它自己的权威、可信、公开的总帐副本。

 

9.1. 交易验证

在交易传递到临近的节点前,每一个收到交易的比特币节点将会首先验证该交易,这将确保只有有效的交易才会 在网络中传播,而无效的交易将会在第一个节点处被废弃。 
* 交易的语法和数据结构必须正确。 
* 输入与输出列表都不能为空。 
* 交易的字节大小是小于 MAX_BLOCK_SIZE 的。 
* 每一个输出值,以及总量,必须在规定值的范围内 (小于 2,100 万个币,大于 0)。 
* 没有哈希等于 0,N 等于 - 1 的输入(coinbase 交易不应当被传递)。 
* nLockTime 是小于或等于 INT_MAX 的。或者 nLocktime and nSequence 的值满足 MedianTimePast 
* 交易的字节大小是大于或等于 100 的。 
* 交易中的签名数量 (SIGOPS) 应小于签名操作数量上限。 
* 解锁脚本( scriptSig )只能够将数字压入栈中,并且锁定脚本( scriptPubkey )必须要符合 isStandard 的格式 (该格式将会拒绝非标准交易)。 
* 池中或位于主分支区块中的一个匹配交易必须是存在的。 
* 对于每一个输入,引用的输出是必须存在的,并且没有被花费。 
* 对于每一个输入,如果引用的输出存在于池中任何别的交易中,该交易将被拒绝。 
* 对于每一个输入,在主分支和交易池中寻找引用的输出交易。如果输出交易缺少任何一个输入,该交易将成为一个孤 立的交易。如果与其匹配的交易还没有出现在池中,那么将被加入到孤立交易池中。 
* 对于每一个输入,如果引用的输出交易是一个 coinbase 输出,该输入必须至少获得 COINBASE_MATURITY(100) 个确认。 
* 使用引用的输出交易获得输入值,并检查每一个输入值和总值是否在规定值的范围内 (小于 2100 万个币,大于 0)。 
* 如果输入值的总和小于输出值的总和,交易将被中止。 
* 如果交易费用太低以至于无法进入一个空的区块,交易将被拒绝。 
* 每一个输入的解锁脚本必须依据相应输出的锁定脚本来验证。

验证交易后,比特币节点会将这些交易添加到自己的内存池中。内存池也称作交易池,用来暂存尚未被加入到区块的交 易记录。

例如: 
Jing 节点的区块链已经收集到了区块 277,314,并继续监听着网络上的交易,在尝试挖掘新区块的同时,也监 听着由其他节点发现的区块。这时他从比特币网络收到了区块 277,315, 标志着终结了产出区块 277,315 竞赛,与此同时也是产出区块 277,316 竞赛的开始。

在上一个 10 分钟内,当 Jing 的节点正在寻找区块 277,315 的解的同时,他也在收集交易记录为下一个区块做准备。目前 它已经收到了几百笔交易记录,并将它们放进了内存池。直到接收并验证区块 277,315 后,Jing 的节点会检查内存池中 的全部交易,并移除已经在区块 277,315 中出现过的交易记录,确保任何留在内存池中的交易都是未确认的,等待被记 录到新区块中。

Jing 的节点立刻构建一个新的空区块,做为区块 277,316 的候选区块 (过一段时间后, 最长)。称作候选区块是因为它还没有包含有效的工作量证明,不是一个有效的区块,而只有在矿工成功找到一个工作量证明解之后,这个区块才生效。现在,Jing 的节点从内存池中整合到了全部的交易,新的候选区块包含有 418 笔交易,总的矿工费为 0.09094925 个比特 币。

 

9.2. coinbase 交易 (创币交易)

每个区块中的第一笔交易是笔特殊交易,称为创币交易或者 coinbase 交易 

 

与常规交易不同,创币交易没有输入,不消耗 UTXO。它只包含一个被称作 coinbase 的输入,仅仅用来创建新的比特 币。创币交易有一个输出,支付到这个矿工的比特币地址。

为了构造创币交易,矿工节点需要计算如下 
* 矿工费的总额: 输入总额减去输出总额 
* 新区块奖励额: 是基于区块高度的,以每个区块 50 个比特币为开 始,每产生 210,000 个区块 (10 分钟一个区块, 大约 4 年) 减半一次。2016 年 7 月为 12.5 bitcoin

{% note info %} 
如果 Jing 的挖矿节点把 coinbase 交易写入区块,那么如何防止 Jing 奖励自己 100 甚至 1000 比特币? 答案是,不正确的奖励将被其他人视为无效,浪费了 Jing 用于工作证明的投入。 只有这个区块被大家认可,Jing 才能得到报酬。 
{% endnote %}

 

9.3. 构造区块头

 

  • merkle root: 将全部的交易组成一个 merkle 树。创币交易作为区块中的首个交易,后将余下的 418 笔交易添至其后,这样区块中的交易一共有 419 笔。

  • Target**(难度目标值)**: 定义了所需满足的工作量证明的难度。难度在区块中以 “尾数 - 指数” 的格式,编码并存储,这种格式称作 target-bits(难度位)。首字节表示指数 (exponent),后面的 3 字节表示尾数 (系数)(coefficient)。则 
    difficulty=cofficient∗28∗(exponent−3)
    难度是可以调整的, 以保证不论计算力如何, 总要大约每十分钟产生一个区块. 因此, 新公式为

  • nonce: 初始值为 0

构造区块 nonce 如下

nonce = 0
while 1:
    if hash(blockHead)<Target:break   # nonce in  blockHead
    else: CHANGE NONCE  # eg  nonce+=1

 

构造好之后, 挖矿节点立刻将这个区块发给它的所有相邻节点。这些节点在接收并验证这个新区块后,也会继续传播此区块。当这个新区块在网络中扩散时,每个节点都会将它加入自己的区块链副本中。其他挖矿结点就放弃之前对构建这个相 同高度区块的计算,并立即开始计算区块链中下一个区块的工作。

 

9.4. 校验新区块

前面清单列出了一些, 也可以通过 客户端的 CheckBlock, CheckBlockHead, 查看

为什么矿工不为他们自己记录一笔交易去获得数以千计的比特币?这是因为每一个节点根据相同的规则对区块进行校验。一个无效的 coinbase 交易将使整个区块无效,这将导致该区块被拒 绝,因此,该交易就不会成为总账的一部分。矿工们必须构建一个完美的区块,基于所有节点共享的规则,并且根据正 确工作量证明的解决方案进行挖矿,他们要花费大量的电力挖矿才能做到这一点。如果他们作弊,所有的电力和努力都 会浪费。这就是为什么**校验是去中心化共识的重要组成部分。

 

9.5. 构建区块

构建了一个候选区块,然后求解工作量证明算法以使这个区块有效。

每次改变 nonce, 尝试产生一个随机的结果,但是任何可能的结果的概率可以预先计算。因此,指定特定难度 (Target) 的结果构成了具体的工作量证明。

验证 nonce 哈希值只需要一次计算,而我们找到它却花了很多次。知道目标值后,任何人都可以用统计学来估算其难度,因此就能知道找到这个 nonce 需要多少工作。

按当前比特币系统的难度,矿工得试 10^15 次(10 的 15 次方)才能找到一个合适的 nonce 使区块头信息哈希值足够小。

 

9.6. 区块链的组装与选择

  • 连接到主链上的
  • 从主链上产生分支的(备用链),
  • 在已知链中没有找到已知父区块的。

在验证过程中,一旦发现有不符合标准的地方,验证就会失败,这样区块会被节点拒绝,所以也不 会加入到任何一条链中。

任何时候,主链都是累计了最多难度的区块链。在一般情况下,主链也是包含最多区块的那个链,除非有两个等长的链 并且其中一个有更多的工作量证明。主链也会有一些分支,这些分支中的区块与主链上的区块互为 “兄弟” 区块。这些区 块是有效的,但不是主链的一部分。

新区块所延长的区块链并不是主链, 节点将新的区块添加到备用链,同时比较备用链与主链的难度。如果备用链比主链积累了更多的难度,节点将收敛于备用链,意味 着节点将选择备用链作为其新的主链,而之前那个老的主链则成为了备用链。

如果节点收到了一个有效的区块,而在现有的区块链中却未找到它的父区块,那么这个区块被认为是 “孤块”。孤块会被 保存在孤块池中,直到它们的父区块被节点收到。

比特币将区块间隔设计为 10 分钟,是在更快速的交易确认和更低的分叉概率间作出的妥协。更短的区块产生间隔会让交 易清算更快地完成,也会导致更加频繁地区块链分叉。

难度增长后, nonce 值不够, 可以延后时间戳来解决, 但是如果延后太久, 可能导致区块无效, 更好的解决方案是利用 coinbase 这笔交易中的空间 (coinbase 脚本可以存储 2-100bytes 数据), 而且这笔交易会影响 merkle 根的变化.

 

9.7. 矿池

9.7.1. 矿工加入

个人矿工在建立矿池账号后,设置他们的矿机连接到矿池服务器。他们的挖矿设备在挖矿时保持和矿池服务器的连接,和其他矿工同步各自的工作。这样,矿池中的矿工分享挖矿任务,之后分享奖励。成功出块的奖励支付到矿池的比特币地址,而不是单个矿工的。一旦奖励达到一个特定的阈值,矿池服务器便会定期支 付奖励到矿工的比特币地址。

 

9.7.2. 托管矿池

大部分矿池是 “托管的”,有一个公司或者个人经营一个矿池服务器。矿池服务器的所有者叫矿池管理员,同时他 从矿工的收入中收取一个百分比的费用。矿池服务器运行专业软件以及协调池中矿工们活动的矿池采矿协议。矿池服务器同时也连接到一个或更多比特币完全节点并直接访问一个块链数据库的完整副本。这使得矿池服务器可以代替矿池中的矿工验证区块和交易,缓解他们运行一个完整节点的负担.

 

9.7.3. P2P 矿池

托管矿池存在管理人作弊的可能,管理人可以利用矿池进行双重支付或使区块无效, 此外,中 心化的矿池服务器代表着单点故障。如果因为拒绝服务攻击服务器挂了或者被减慢,池中矿工就不能采矿。

P2Pool 是一个点对点的矿池,没有中心管理 人。P2Pool 通过将矿池服务器的功能去中心化,实现一个并行的类似区块链的系统,名叫份额链(share chain)

一个份额链是一个难度低于比特币区块链的区块链系统。份额链允许池中矿工在一个去中心化的池中合作, 采矿,并获得份额。份额链上的区块记录了贡献工作的矿工的份额,并且继承了之前份额区块上的份额记录。当一 个份额区块上还实现了比特币网络的难度目标时,它将被广播并包含到比特币的区块链上,并奖励所有已经在份额链区块中取得份额的池中矿工。

 

9.8. 共识攻击

比特币的共识机制的前提: 绝大多数的矿工,出于自己利益最大化的考虑,都会通过诚实地挖矿来维持整个比特币系统。

当一个或者一群拥有了整个系统中大量算力的矿工出现, 可以通过攻击比特币的共识机制来达到破坏比特币网络的安全性和可靠性的目的。

注意, ,共识攻击只能影响整个区块链未来的共识,即最多影响 过去 10 个块。而且随着时间的推移,整个比特币块链被篡改的可能性越来越低。

共识攻击也 不能从其他的钱包那里偷到比特币、不签名地支付比特币、重新分配比特币、改变过去的交易或者改变比特币持有纪 录。共识攻击能够造成的唯一影响是影响最近的区块(最多 10 个)并且通过拒绝服务来影响未来区块的生成。

区块链分叉 / 双重支付攻击指的是攻击者通过 不承认最近的某个交易,并在这个交易之前重构新的块,从而生成新的分叉,继而实现双重支付。双重支付只能在攻击者拥有的钱包所发生的交易上进行,因为只有钱包的拥有者才能生成一个合法的签名用 于双重支付交易。攻击者在自己的交易上进行双重支付攻击,如果可以通过使交易无效而实现对于不可逆转的购买行为不予付款,这种攻击就是有利可图的。

{% note info %}

51% 攻击并不是像它的命名里说的那样,攻击者需要至少 51% 的算力才能发起,实际上,即使其拥有不到 51% 的系统算力,依然可以尝试发起这种攻击。之所以命名为 51%攻击,只是因为在攻击者的算力达到 51% 这个阈值的时候,其发起的攻击尝试几乎肯定会成功。 
{% endnote %}

 

9.9. 分叉

9.9.1. 硬分叉

导致硬分叉:共识规则中的错误,以及对共识规则的故意修改。

对于硬分叉发生,必须是由于采取相互竞争的实施方案,并且规则需要由矿工,钱包和中间节点激活。相反,有许多比特币核心的替代实现方案,甚至还有软分叉,这些没有改变共识规则,阻止发生错误,可以在网络上共存并互操作,最终并未导致硬分叉。

可以将硬分叉子看成四个阶段:软分叉,网络分叉,挖矿分叉和区块链分叉。该过程开始于开发人员创建的客户端,这个客户端对共识规则进行了修改。当这种新版本的客户端部署在网络中时,一定百分比的矿工,钱包用户和中间节点可以采用并运行该版本客户端。得到的分叉将取决于新的共识规则是否适用于区块,交易或系统其他方面。如果新的共识规则与交易有关,那么当交易被挖掘成一个块时,根据新规则创建交易的钱包可能会产生出一个网络分叉,这就是一个硬分叉。如果新规则与区块有关,那么当一个块根据新规则被挖掘时,硬分叉进程将开始。

一些开发商反对任何形式的硬叉,认为它太冒险了。另一些人认为硬分叉机制是提升共识规则的重要工具,避免了 “技术债务”,并与过去提供了一个干净的了断

 

9.9.2. 软分叉

共识规则的改变也能够让未修改的客户端仍然按照先前的规则对待交易或者区块

软分叉级只能用于增加共识规则约束,而不是扩展它们。软叉可以通过多种方式实现, 方法的共同点是不要求所有节点升级或强制非升级节点必须脱离共识。 
 
* 重新定义 NOP 操作码 
Bitcoin 脚本有 10 个操作码保留供将来使用,NOP1 到 NOP10。 根据共识规则,这些操作码在脚本中的存在被解释为无效的运算符。软叉可以修改 NOP 代码的语义给它新的含义。 
* segwit 
是一个交易结构的体系结构变化,它将解锁脚本(见证)从交易内部移动到外部数据结构(将其隔离)

对软分叉的批评 
* 技术性债务 
指由于过去的设计权衡而增加代码维护的未来成本。代码复杂性又增加了错误和安全漏洞的可能性。(因为软叉在技术上比硬叉升级更复杂) 
* 验证放松 
未经修改的客户端将交易视为有效,而不评估修改的共识规则。实际上,未经修改的客户端不会使用全面的协商一致的规则来验证,因为它们对新规则无视。这适用于基于 NOP 的升 
级,以及其他软分叉升级。 
* 不可逆转升级 
因为软分叉产生额外的共识约束的交易,所以它们在实践中成为不可逆转的升级。如果软分叉升级在被激活后被回退,根据新规则创建的任何交易都可能导致旧规则下的资金损失。因此,评论家认为,由于错误而不得不被回退的失败的软分叉几乎肯定会导致资金的流失。

 

10. 比特币安全

10.1. 安全准则

比特币的核心准则是去中心化, 将责任和控制权都移交给了用户。由于网络的安全性是基于工作量证明而非访问控制,比特币网络可以对所有人开放,也无需对比特币传输进行加密。

一笔比特币交易只授权向指定接收方发送一个指定数额,并且不能被修改或伪造。它不会透露任何个人信息,例如当事人的身份,也不能用于权限外的支付。因此,比特币的支付网络并不需要加密或防窃听保护

 

10.2. 比特币系统安全开发

比特币的安全性依赖于密钥的分散性控制,并且需要矿工们各自**地进行交易验证。如果想利用好比特币的安全性,确保自己处于比特币的安全模型里。简而言之,不要将用户的密钥控制权拿走,不要接受非区块链交易信息。一个常见的错误是接受区块链离线交易,妄图减少交易费或加速交易处理速度。一个 “区块链离线交易” 系统将交易数据记录在一个内部的中心化账本上,然后偶尔将它们同步到比特币区块链中。这种做法,再一次,用**和集中的方式取 代比特币的去中心化安全模型。当数据处于离线的区块链上的时候,保护不当的中心化账本里的资金可能会不知不觉被 伪造、被挪用、被消耗。

除非你是准备大力投资运营安全,叠加多层访问控制,或(像传统的银行那样)加强审计,否则将资金从比特币的去中心化安全场景中抽离出来这样的设计也仅仅是复制了一个脆弱不堪,深受账户盗窃威胁、贪污和挪用公款困扰的传统金融网络而已。要想充分利用比特币特有的去中心化安全模型,必须避免中心化架构的常见诱惑,因它最终将摧毁比特币的安全性。

 

10.3. 信任根(ROOT OF TRUST)

传统的安全体系的基础,它指的总体系统或应用程序中一个可信赖的安全核心。安全体系像一圈同心圆一样围绕着信任根源来进行开发,像层层包裹的洋葱一样,信任从内至外依次延伸。

免责声明:信息仅供参考,不构成投资及交易建议。投资者据此操作,风险自担。
如果觉得文章对你有用,请随意赞赏收藏
相关推荐
相关下载
登录后评论
Copyright © 2019 宽客在线