比特币

比特币交易流程简述

场景: 地址A向地址B支付了一个比特币

交易记录如下:

{
"付款地址":"A"
"收款地址":"B"
"金额":"1btc"
}

1. Hash与签名

首先本地节点系统对该笔交易进行Hash 计算得到以该交易记录为基础的Hash值 (即该笔交易的摘要信息) 接着使用私钥 (生成比特币账户时获得的) 对交易摘要进行签名得到签名信息.

过程如下:

Sign( "私钥", 
    Hash({ "付款地址":"A",
            "收款地址":"B",
            "金额":"1btc"
          }));  -> "签名信息"

2. 广播

接下来把该签名信息进行全网广播,让其他节点确认这笔交易(广播过程实际上是发信息到邻近的其他节点,其他节点在验证通过后再转发到与之相邻的节点,这样的扩散过程,类似于水滴在水面像波纹一样荡漾开的过程)

※疑问:为何使用这种设计?

3. 验证

当网络上的其他节点收到广播后, 先判断付款地址的余额是否足够支付该笔交易, 接着通过 ”签名信息” 与 “付款地址” 这两个参数可以计算出交易记录的Hash 值, 再把原始交易记录做Hash计算, 接着把得到的两个Hash值比较后如果一致则验证成功, 之后把该笔交易记入账本数据. 当某一节点记录成功后再发送广播通知全网节点.
过程如下:

if(checkBalance()){
    if(Hash("签名信息","付款地址")
         == Hash({ "付款地址" : "A", 
            "收款地址" : "B",
            "金额" : "1btc"
            }) 
        ){
            // 计入账本数据
            ...
    } else {
        ...
    }
}

补充: 比特币系统使用椭圆曲线签名算法, 算法的私钥由32个字节随机数组成, 通过私钥可计算出公钥, 公钥经过Hash和编码计算可得到比特币地址, 地址可看作公钥的摘要.

记账的原理

记账即挖矿, 比特币系统在生成下一区块时, 会把上一区块的Hash值, 序号, 时间戳, 随机数, Merkle根等信息使用Hash 算法生成一个Hash 值, 之后把这个Hash值作为新的区块的一个属性存放在生成的新区块中, 当下一区块生成时会继续把这个区块的Hash值作为参数计算得到下一个Hash值, 这样做的优点是防篡改, 因为每一区块的Hash值都与上一区块有关联, 如果某一区块数据被改动会导致Hash值不一致, 被区块链系统发现.

随机数的作用

增加记账的难度.

比特币系统设计在记账过程中Hash前一区块时必须把随机数作为参数做计算, 使得最终Hash出的结果是在原来的Hash值前加18个0.

举例: 如果在没有随机数作为参数下Hash出来的值是 ”12345” 那么在加入随机数作为参数后Hash出来的值必须符合 “000000..012345” 这样的格式.

补充: 挖矿的这一说法就是因为有随机数的加入大大增加了算出新区块Hash值的难度所以人们就形象的称呼这种试出一个符合条件的Hash值的过程为挖矿.

矿池的概念

比特币系统在Hash前一区块信息生成的Hash值需要符合在原Hash值前以18个0开头的条件, 一个Hash值是由0-9,a-z,A-Z 共62个字符所组成的字符串, 在Hash值中的每一个位都会有62种可能, 而以18个0开头为例, 理论上需要尝试62的18次方次才能算出该符合条件的Hash值, 这个计算量非常庞大. 区块链发展到现今已经很少有单独的节点会去独自计算如此庞大的任务. 所以参与记账的各个节点就组成矿池, 联合起来进行记账, 最终的收益再按照算力百分比进行分成.

区块的结构

总的分为 区块头 + 区块体 两个部分

区块头包含: 当前比特币系统版本号, 前一区块Hash值, 序号, 随机数, 时间戳, Merkle根…

区块体包含: 区块创建过程中生成的所有交易记录. 把这些交易记录两两之间进行Hash计算,得到的值再两两Hash如此循环最终就会得到一个唯一的根Hash值, 这个值就是Merkle根. 这个过程描绘出来的结构图就叫Merkle Tree

过程如下:

主链的概念

累计最多工作量的区块链被称为主链, 也叫最长链. 各个节点总是选择并尝试延长主链.

分叉

区块链在加入新区块的时候, 有可能会有2个 (或多个) 节点同时算得符合条件的Hash值并生成区块的情况. 这种情况就会导致分叉.

由于比特币网络中的广播机制是类似水波一般持续向临近周围扩散的过程, 在这个过程中当这两个同时生成的区块在广播时, 有的节点首先收到区块A, 有的节点首先收到区块B, 这两个区块都是主链的延伸,分叉就会产生,这时分叉出有竞争关系的两条链,如图:

两个块都收到的节点,会把其中有更多工作量的一条会继续作为主链,另一条作为备用链保存(保存是因为备用链将来可能会超过主链成为新主链)。

补充 : 比特币系统将区块生成间隔时间定为10分钟是在更快速的交易确认与更低的分叉几率之间作出的妥协, 更短的区块生成间隔会让交易更快确认完成但也会导致分叉出现的概率更高, 相对的如果选择更长的间隔则会导致更长的交易确认时间, 但分叉的概率也会减少.

※疑问: 生成区块的速度理论上取决于节点的算力, 比特币系统是如何让这个时间固定在十分钟的?  

https://blog.csdn.net/ipenx/article/details/77951801
https://bitcoin.stackexchange.com/a/857

根据这两篇文章得出的结论说:
在比特币系统计算生成新区块的算法中利用一个属性 “难度值” 来影响了区块生成的速度,
此 “难度值” 会在每隔 2016的倍数个区块生成时(按照每个区块10分钟计算大约是14天)触发调整,
计算公式为 : 旧的难度值 * 14天 / 生成之前2015个区块的总时常

SPV节点(Simplified Payment Verification简单支付验证)

通过SPV钱包接入比特币网络的节点称为SPV节点, 他们的特点是不必同步储存完整的区块链数据也可以对交易进行验证. SPV节点只下载区块头的数据, 大小只有完整区块链数据的几千分之一.

SPV节点如何验证交易?

SPV节点收到广播后会向邻近节点索要 (通过MerkleBlock消息的方式) 该笔交易以及参与该笔交易的Hash计算的其他交易并上溯至Merkle根的序列来确认验证.
举例如下:

若SPV节点要验证交易 ”4” , 则首先向邻近节点索取( 3, 4, 12, 34, 1234, 5678, Merkle Root) 这些Hash值, 也称为认证路径. 如此即可确认该笔交易的正确有效.

补充: 在N个交易组成的区块中确认某笔交易是否正确只需要计算log2(N)个字节的Hash值即可.

节点是如何加入比特币网络的?

参考 : https://en.bitcoin.it/wiki/Satoshi_Client_Node_Discovery

  1. 比特币的代码里写死了几个域名,客户端启动时向这几个地址请求通过DNS得到其他节点ip。
  2. 客户端会通过接收IRC网络广播获取到节点并连接.
  3. 手动设置节点地址, 可通过命令行或者使用本地配置文件的方式写入.

拜占庭将军问题

参考 : https://learnblockchain.cn/2018/02/05/bitcoin-byzantine/

本质上叫 分布式系统一致性问题

简单的解释就是说在比特币网络上的各个节点互不统属, 那么如何使区块取得一致性, 被各个节点所认同呢?
在比特币系统中引入了 ”工作量证明” 这一概念解决此问题, 通过工作量证明增加了发送信息的成本,降低节点发送消息速率,这样就保证在一个时间只有一个节点(或是很少)在进行广播,同时在广播时会附上自己的签名。

补充: 工作量证明即是挖矿的过程. 准确的说法是抢夺记账权, 也就是只有节点利用穷举试出某一个值符合生成区块的特定条件Hash值才有权力记账, 一旦节点完成记账后即通知其他节点不再对这一区块做计算而是接收并验证该节点发出的区块正解.

比特币脚本

https://learnblockchain.cn/2017/11/10/bitcoin-script/

未花费的交易输出(UTXO(Unspent Transaction Output))

比特币的交易都是基于UTXO上的,即交易的输入是之前交易未花费的输出,这笔交易的输出可以被当做下一笔新交易的输入.

补充:

挖矿奖励属于一个特殊的交易(称为coinbase交易),可以没有输入。

UTXO是交易的基本单元,不能再分割。

在比特币没有余额概念,只有分散到区块链里的UTXO.

比特币交易流程:

首先提供一个用于解锁UTXO(用私钥去匹配锁定脚本)的脚本(称为解锁脚本:Signature script), 这叫交易输入, 交易的输出则是指向一个脚本(称为锁定脚本:PubKey script),这个脚本表达了:谁的签名(签名是常见形式, 并不一定必须是签名)能匹配这个输出地址,钱就支付给谁。

节点通过同时执行 “解锁脚本” 和 ”上一个交易的锁定脚本” 来验证交易, 结果为真即为有效交易.

以太坊

以太坊(Ethereum)是一个建立在区块链技术之上, 去中心化应用平台。它允许任何人在平台中建立和使用通过区块链技术运行的去中心化应用。

智能合约

如果把以太坊理解为一个类似于Android系统平台的话, 那么在以太坊上开发的可以自动执行(由消息驱动的)、以代码形式编写的合同(特殊交易)或者说程序, 就称为智能合约.

补充: 智能合约非常适合对信任、安全和持久性要求较高的应用场景,比如:数字货币、数字资产、投票、保险、金融应用、预测市场、产权所有权管理、物联网、点对点交易等等。

智能合约的官方推荐的编程语言是Solidity,文件扩展名以.sol结尾。

运行环境:EVM

EVM(Ethereum Virtual Machine)以太坊虚拟机是以太坊中智能合约的运行环境。可以理解为Java的JVM虚拟机的概念.

以太坊客户端(钱包)Geth / Mist

Geth (go-ethereum) 是典型的开发以太坊时使用的客户端,基于Go语言开发。它提供账户管理、挖矿、转账、智能合约的部署和执行等等功能。可以说即是客户端, 也是开发工具.

而相对于Geth,Mist则是图形化操作界面的以太坊客户端.

补充: 另外, 以太坊官方还有另一个轻量的客户端钱包Ethereum Wallet, 没有带开发功能只是一个单独的钱包以及DAPP浏览器.