第三章 比特币的运行机制
本章详细介绍如何建立货币系统、如何奖励矿工
3.1 比特币的交易
比特币交易的过程就是不停地创造区块地过程。
简单模式的账簿
建立一个以账户为核心的系统,可以创造新的币并放入某人的账号,然后可以转给他人。
缺点:任何人如果想要确认一笔交易是否真实,就必须跟踪每一个账户的余额。虽然可以增加数据字段来更新交易后的账户余额,但这增加了记账的工作量。
与比特币类似的基于交易的账本
类似于:财奴币。
每个交易都有一个输入值和输出值。
输入值可看成将被消耗掉的币(这些币是前一个交易创造出来的)
输出值看成是在本次交易中创造出来的币。
铸造新币时,只会创造新币,不会消费旧币。(只有输出,没有输入)
每个交易都有一个独一无二的ID。
地址转换
类似于财奴币,一个交易中输出的币,不存在只消费部分情况,要么在另一个交易中被完全消费掉,要么一个都不被消费。比如:该转换中Alice的8个币可以转换到另一个由Alice所有的地址,即地址转换。
有效验证
使用哈希指针,比如核查Alice引用的交易输出,从Alice所引用的交易开始核查到账本上最新记录的交易即可(不需从账本建立之初的交易开始核查),不需增加额外的数据结构。
资金合并
发起一个交易,交易里有多个输入和一个输出,输出的地址为发起人地址。
共同支付
发起一个交易,交易里有多个输入和一个输出,输出的地址为收款方的地址,多个输入所引用的“上一笔交易”的输出地址不同,需要多个签名:比如1的签名和2的签名。
交易语法
比特币在网络上传输的数据结构都是一串字符。一个比特币交易分成三部分:元数据、一系列的输入、一系列的输出。
元数据 存放一些内部处理的信息:包含这笔交易的规模、输入的数量、输出的数量、此笔交易的哈希值(即交易的独一无二的ID)。
我们可用哈希指针指向ID。锁定时间lock_time。
输入 所有输入排成一个序列,每个输入的格式都一样。输入需要明确说明之前一笔交易的某个输出:
包括之前那笔交易的哈希值,让其称为指向那个特定交易的哈希指针
包括之前交易输出的索引和一个签名(我们必须有签名证明我们有资格去支配这笔比特币
输出 所有输出排成一个序列,每个输出的内容分成两部分:
所有输出的金额之和必须 <= 输入的金额之和
输出的总金额 < 输入的总金额 时, 输入的总金额-输出的总金额=交易费(支付给这笔交易记账的矿工)
每个输出都要和一个特定的公钥(地址)对应,故scriptPubkey是个比特币脚本(公钥的哈希值,指令集合)。
3.2 比特币的脚本
每个交易输出确定了一个公钥,同时指定了一个脚本。
交易输出描述:凭借哈希值为X的公钥,以及这个公钥所有者的签名,才可以获得这笔资金
谁来执行这个脚本?交易的输入包括了脚本,只有把交易的输入脚本和上一笔交易的输出脚本串联起来,串联脚本必须被成功地执行后才可获取资金。
比特币脚本语言
为比特币开发的,在比特币中叫做”脚本“。
比特币脚本语言内生地支持加密操作,有目的性地指令用来计算哈希值和检验签名。
脚本语言是堆栈式地,每个指令只被执行一次,线性无法循环。
不是图灵完备的,不能随意运行强大函数功能。
注:图灵完备即语言有能力随意地执行强大的函数。
详情参见75页。
脚本执行只有两个结果:成功或者失败。
执行一个脚本
指令有两种:数据指令(把数据推到堆栈的最上面)和工作码指令(OP开头 用堆栈顶部的数据作为输入值)。
在比特币中,我们只对整个交易进行签名。
销毁证明
销毁证明 proof of burn 用于销毁比特币(防止资金被赎回)。使用OP_RETURN脚本抛出错误,其后指令都不会执行
支付给脚本的哈希值
比特币的工作机制要求币的发送者必须在交易时明确指定脚本。但是日常生活中会显得很复杂,如何解决?比特币使用:收款方告诉付款方请把比特币支付给某个脚本地址,脚本的哈希值是XX,取款时候我会提供上述哈希值对应的脚本,同时提供数据通过脚本的验证。付款方通过P2SH即可实现简单付款。
注:P2SH脚本只是对堆栈最顶层的数据进行哈希计算,检验与给定哈希值一致时再执行特殊核验:将堆栈最顶层的数据重新解读为一系列指令,然后将其作为脚本运行一次,同时,堆栈中的其他数据作为脚本的输入值。
3.3 比特币脚本的应用
第三方支付交易
利用MULTISIG(多重签名)来实现。三个人之中只有两个签名之后,资金才可被支走。但是涉及到情况便是发生纠纷时,由第三方判断完成支付还是撤销支付。
绿色地址
绿色地址:green addresses
问题描述:Alice想要转账给Bob(不在线),故Bob无法通过查看区块链的更新来确认转账是否完成。一般一个交易需要获得6次确认,时间约为1h,这对于买卖东西或者不在线不实用。
解决:第三方银行(可能是个交易所or其他的金融媒介)。银行保证它不会双重支付这个比特币,Bob相信,但是这是现实世界中银行的保证,故Bob只要相信银行即可。但是,如果银行出现双重支付事件,则人们不会相信他。现在,人们认为过分信任”银行“是由风险的。
高效小额支付
高效小额支付efficient micro-payments
例子:Alice先发起一个MULTISIG交易,把可能花费的最大金额转到MULTISIG地址。爱丽丝用流量时候,每隔一分钟签名一次,向Bob支付这分钟产生的费用,剩下的钱转给自己,直到挂机为止(目前这些交易只有Alice签名)。挂机之后,Alice不再支付费用,Bob在Alice的最后一个交易签名,把它放入区块链,而,最后一个交易会一次性向Bob支付所有的流量费,把剩余的币还给Alice(Alice单独签名的交易不会进入区块链,会被丢弃)。这些都是”双重支付“,但是运转正常情况下,Bob只会在最后一个交易上签名。
假如Bob没有在最后一个交易签名,那么Alice将会失去所有转入的比特币。可利用锁定时间来解决这个问题。
锁定时间
小额支付协议开始之前,须约定退全款(但是退款行为被锁定,锁定时间到了为止)锁定时间t到了,Bob还没在最后一个交易上签名的话,Alice可以通过退款收回所有的比特币。(t就是lock_time:告知矿工,需等待t时间之后才能把这笔交易记入区块链)
智能合约
智能合约 smart contracts 即不同于需要通过法律或者仲裁机构来保护执行的普通合约,是比特币系统里可以用技术手段来强制执行的合约。
3.4 比特币的区块
把大量交易组织起来放入一个区块,得到的哈希链更短,极大提高了验证区块链数据结构的效率。
区块链将两个基于哈希值的数据结构结合起来:
⑴是区块的哈希链,每一个区块都有一个区块头部,里面有一个哈希指针指向上一个区块。
⑵是树状数据结构,以树状结构把所有交易的哈希值进行排列存储即梅克尔树。为了证明某个交易在某个区块内,可以通过树内路径来进行搜索,树的长度就是区块内所包含的交易数目。
区块头部
区块头部还包含了相关挖矿谜题相关的信息
区块头部的哈希函数必须以一大堆0开头才有效
区块头部还包含:一个矿工可以修改的临时随机数,一个时间戳,一个点数(用来表示找到这个区块的难度)
区块头部是挖矿过程中唯一哈希值化的要验证一个区块的链,只要检查区块头部即可。
区块头部唯一的交易数据就是交易树的树根”mrkl_root“
每个区块的梅克尔树上都有一个币基交易,类似于财奴币中的造币交易。币基交易创造新的比特币,特点是:
①永远只有一个单一的输入和单一的输出
②交易不消耗之前交易输出的比特币,故没有指针指向”上一个交易“
③输出值目前是:25个币多点点 = 矿工的挖矿收入=奖励的25个币+所有交易的交易手续费。
3.5 比特币网络
比特币网络是一个点对点网络,所有节点都平等,运行在TCP网络上,有一个随意的拓扑结构,每个节点和其他的随机节点相连。只要一个节点由3h没有音讯,则会慢慢被其他节点忘记。
加入网络的好处是为了维护区块链,发起交易时候,通过泛洪flooding算法完成的(或者称为八卦gossip协议)。
例子:Alice转账给Bob,客户端发起一个交易,把这笔交易告诉所有与她客户端节点相连的节点。节点接收到一个交易信息后,会把交易放入交易池(交易池里的交易还未被打包进区块链),如果交易池中已经存在(通过交易的哈希值查询)该交易就不会将它再次传播(确保泛洪协议会自动终结)。
如何核验节点接收到的新交易信息?①交易验证(验证交易在当前的区块链中是有效的,节点会针对每个前序交易的输出运行核验脚本,确保脚本的返回值都为真)②检查是否有双重支付③检查这笔交易信息是不是已经被本节点接收过④节点只会接收和传递在白名单上的标准脚本。
竞态条件race condition:网络延迟会导致当有双重攻击时候,众多节点会对哪一个交易应该被纳入区块链产生分歧。对于比特币,打包下一个区块的矿工会打破这个僵局(决定哪个交易会最终打包进这个区块)。
零验证交易和费用替代策略replace-by-free
零验证交易:一旦交易在网络中广播,接收方就立即接收交易。该交易不是用来预防重复支付的,由于矿工的缺省行为是把最先接收到的交易放入交易池,故零验证交易很难实现重复交易。
费用替代策略:13年矿工的缺省行为变成了费用替代策略。节点遇到有冲突的交易时,会把交易手续费更高的交易放进自己的交易池,把手续费更低的替换出去。
存储空间需求
完全有效的节点必须永久在线,这样才能接收到所有的交易数据。
完全有效节点必须维护在交易中产生的交易的输出,未被消费掉的比特币的完整列表。
轻量节点
轻量节点neightweight nodes:除完全有效节点之外的另一种节点。也叫轻客户端或简单付款验证simple payment verification SPV。
一个SPV节点的安全等级远不如全节点。
详情参加92页。
3.6 限制与优化
比特币的总体数量与记账奖励很可能永远都不会改变。
关于比特币系统的交易处理能力,区块大小有硬性规定,每个区块大小限定在1MB,每个交易大约是250字节,故每块最多容纳4000个交易。平均每隔10min,有一个矿工获得记账权利,故每秒钟稚只能处理7个交易。
限制二是比特币用的密码算法。比特币使用的签名算法是ESDSA(一种secp256k1的椭圆曲线数字签名算法)。
修订协议
如何修订比特币协议并引入一些新特性呢?发布新版本,但我们无法假定所有的节点都会更新版本。协议修订会产生两种类型结果:硬分叉和软分叉。
硬分叉:运行新协议的节点认定为有效的区块,会被运行旧版协议的节点认定为无效。导致最长的区块链分支包含的某些区块会被老节点认定为无效区块,从而老节点会认为其他才是最长有效的区块链分支,并一直扩展直到它们有新版本。硬分叉导致原先链分裂为2个,并且不会再合并,只要老节点不更新版本,就永远的被排除在另一条链外。
软分叉:加入新的特性,让现有的核验规则更加严格。老的节点会接收所有的区块,新的节点会拒绝一些。
现在假定绝大部分节点都更新了新版协议并执行新的规则(老节点不会执行新规则,新节点数量要足够多才能够竞争最长的链)。老节点可能会挖到一些包含一些在新规则下无法核验通过的交易的无效区块,因此老节点知道它们核验有效的区块不被别的节点接收,故老节点的矿工会去更新协议。若新节点用它们区块扩展了老节点的分支,则老节点也会转而扩展这个分支。
比如:P2SH就是软分叉经典例子。(一个有效的P2SH交易也可核验通过因为它只验证这个哈希值跟前一笔交易输出哈希值是不是一样而已,并不知道还要进一步检验脚本是否合法)依赖新节点进行核验:脚本本身真的可以获取到前一个交易输出的币。
写于2018.5.23 17:26