区块链入门 第二部分

比特币环境搭建

比特币的基本环境安装,笔者使用vmware workstations+ubuntu16.04 
首先安装ubuntu16.04操作系统。 
安装完成后更新: 
Ubuntu更新:(这一步有时候比较慢,耐心) 
12121.png-301.7kB
更新完成后安装bitcoin安装必要的软件包:

 
  
  1. sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev
  2. sudo apt-get install libboost-all-dev
  3. sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
  4. sudo apt-get install libqrencode-dev
  5. sudo apt-get install libminiupnpc-dev
  6. Sudo apt-get install libevent-dev (这个有些教程没有写,但是编译时候会报错,建议早点安装上去)

222.png-197.6kB333.png-301.5kB打包完成后,选择一个目录下载源码:git clone https://github.com/bitcoin/bitcoin.git 如果发现命令不可用(apt-get install git 可以提前安装好 git很常用) 444.png-100.8kB下载完成后下载Berkley DB 4.8

 
  
  1. wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
  2. tar -xzvf db-4.8.30.NC.tar.gz
  3. cd db-4.8.30.NC/build_unix/
  4. ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=/bitcoin/db4/
  5. make install

555.png-291.4kB

 
  
  1. Compile Bitcoin with Berkley DB 4.8
  2. cd ~/bitcoin/
  3. ./autogen.sh
  4. ./configure LDFLAGS="-L/bitcoin/db4/lib/" CPPFLAGS="-I/bitcoin/db4/include/"
  5. make --j5(这一步也很慢、耐心)

666.png-112.4kB777.png-376.3kB完成后:

 
  
  1. Run Bitcoin Daemon/QT/Client
  2. ./src/bitcoind
  3. ./src/qt/bitcoin-qt
  4. ./src/bitcoin-cli

888.png-134.4kB
999.png-81.3kB

之前代码编译完成后,可以选择NetBeansIDE 或者VIM 
这里用VIM: 
首先下载依赖:

 
  
  1. sudo apt-get install python vim exuberant-ctags git
  2. sudo pip install dbgp pep8 flake8 pyflakes isort

下载vimrv:

 
  
  1. Wget https://raw.githubusercontent.com/tao12345666333/vim/master/vimrc -O $HOME/.vimrc

打开安装插件:

 
  
  1. vim --u $HOME/.vimrc +qall

vim编辑参考:https://github.com/tao12345666333/vim/blob/master/README-zh.md


比特币笔记

比特币所有权:密钥+地址+数字签名 
密钥独立现在存储于钱包(密钥以对的形式出现,公钥、私钥)、地址用于转移接收bitcoin、数字签名用于交易见证。(比特币交易过程中通讯和交易数据不加密)

  • 公钥加密方式:采用椭圆曲线算法。私钥用户自己保存、公钥在网络中公开。交易过程中发送公钥和签名。
  • 私钥:随机生成256位二进制数字(01010101组成),一般以64位十六进制显示。
  • 公钥基于私钥生成:私钥一个随机数,通过单项加密函数生成公钥。
  • 地址:地址基于公钥。地址=RIPEMD160(SHA(公钥)),可见地址再经过Base58编码显示。
  • 查看密钥:getnewaddress生成私钥但显示公钥、dumpprivkey显示私钥。
  • 椭圆加密算法:基于离散对数问题的非对称加密算法。
  • Base58编码:不含数字0、大写字母O、小写字母i、大写字母I、+、/。
  • 版本检验码:checksum=SHA256(SHA256(prefix+data))
  • 私钥格式:私钥是256位的数字,有不同格式:Hex、WIF、WIF-compressed。
  • 公钥格式:公钥264位的数字,有不同格式:Hex、WIF、WIF-compressed。
  • 加密私钥:BIP0038通用标准,使用一个口令私钥,通过Base58check对加密私钥进行编码。具体加密方案:输入私钥,通过WIF编码吗,base58check字符串前缀5,使用长密码作为口令,那么base58check编码前缀为6P。
  • P2SH:以3开头bitcoin地址为P2SH地址,P2SH函数实现多重签名地址脚本,N个密钥需要M个签名,M-N多签名。
  • 靓号地址:通过靓号生成算法,选择私钥生成公钥,多次试验得到匹配。安全性上需要权衡。
  • 纸钱包:打印在纸上的bitcoin私钥,一种备份机制。
  • 钱包:钱包里没有bitcoin,钱包包含私钥,bitcoin实际上记录在区块链上。
  • 非确定性钱包(nondeterministic wallet),其中密钥都是随机生成,彼此无关联性。简称JBOK(just a bunch of keys)钱包。
  • 确定性钱包(deterministic wallet),密钥都是一个主密钥衍生出来。使用多种不同的密钥推导方法。
  • 非确定钱包密钥是一个松散集合,确定性钱包以一个种子来衍生其他密钥,只备份种子即可。
  • 分层确定性钱包,根据BIP-32和BIP-44生成的HD钱包,树形结构衍生各个密钥。有效建立一个公共密钥序列。
  • 种子和助记词:现在使用钱包中一般都会看到助记词选项,一系列的英文单字生成种子。

助记词生成过程(BIP-39) 
从熵源开始,增加校验、然后映射。过程: 
创建128-256随机序列(熵) 
提出SHA-256哈希前面几位(熵长/32),创建一个随机序列的校验和。 
校验和添加到随机序列末尾。 
序列划分11位不同部分。 
11位部分值和2048个单字字典做对应。 
生成单词即可 
助记词生成种子: 
PBKDF2(密钥延伸函数)熵用于导出512位种子,增加“盐”的概念,“盐”的目的一个增加暴力破解难度,另一面引入密码短语,保护种子的附加安全性。 
接上述6步:PBKDF2密钥延伸函数的第一个参数来自生成的助记词,第二个参数为“盐”,由助记词和密码字符串连接而成,PBKDF2使用HMAC-SHA512算法,使用2048次hash来延伸助记词和盐参数,生成一个512位的值的输出,即为种子。


  • 获取bitcoin代码:git clonehttps://github.com/bitcoin/bitcoin.git
  • 查看bitcoin核心版本:git tag
  • 检查版本:git status
  • 编译:新版本通过make,旧版本通过makefile
  • 安装:sudo make install 默认安装路径:/usr/local/bin
  • 检查安装状态:which bitcoin、which bitcoin-cli
  • 运行bitcoin核心:bitcoind

配置节点配置文件: 
1.在.bitcoin/bitcoin.conf文件中设置用户和密码,rpcuser=用户名、rpcpassword=密码 
2.alertnotify:电子邮件警报、conf:配置文件制定的命令和脚本、datadir:选择文件存储目录和文件系统(默认为.bitcoin目录)、prune:删除旧块、txindex:维护所有交易的索引、maxconnections:连接的最大节点数、maxmempool:内存限制、maxreceivebuffer:内存缓冲区限制(1000字节)倍数、minrelayfee:最低交易费用。

  • 查看bitcoin进程运行状态:bitcoin-cli getinfo
  • 使用JSON-RPC API接口:查看命令帮助:getblockhash RPC、bitcoin-cli help getblockhash
  • 查看客户端状态:bitcoin-cli getinfo
  • 获取相关交易信息:getrawtransaction+hash、decodeawtransaction+(十六进制解码顺序交易信息)
  • 获取区块信息:getblockhash+区块号、getblock+hash

  • HD钱包:HD钱包从根种子延伸,方便钱包的存储导入、导出。根种子输入值HMAC-SHA512算法得到一个hash值,用于创建主私钥和主链代码,主私钥通过椭圆曲线算法生成主公钥。
  • 私有子密钥:分层确定性钱包使用CKD函数从母密钥衍生子密钥。由母私钥+链码+索引合并散列后(HMAC-SHA512函数)生成子密钥。合并生成512散列,拆分256两部分,散列右边作为链码,散列左边+索引码+母私钥延伸子私钥。
  • 扩展密钥:密钥和链码结合后被称为扩展密钥(extended key),扩展密钥由256位密钥+256位链码生成的512位序列。用于衍生子私钥。扩展密钥通过Base58check编码,会出现xprv和xpub前缀。
  • Bitcoin交易:交易的本质是数据结构,数据结构中包含了bitcoin交易双方价值的转移相关信息。每一笔交易在区块链上都是一个公开的记录。
  • 交易基本单位:交易输出是bitcoin交易中最基本的交易单元。
  • UTXO(unspent transaction outputs):所有的UTXO称为UTXO集。这个大小不固定,UTXO集表示UTXO中的状态的变化。
  • 收到的bitcoin:钱包中检测到可用的UTXO,一般钱包的余额就是指可用的UTXO的总和。
  • 交易一笔任意金额都以交易输出来表示,找零对应一笔输出到交易发起者的地址。简单一笔交易消耗之前可用的UTXO,同时创建新的UTXO作为未来交易的消耗储备。通过这种输出的转移来实现bitcoin在不同所有者之间的转移。
  • 币基交易:区块中第一笔交易,作为区块产生的奖励给旷工。
  • 交易输出:bitcoin中每一笔交易都会创造输出,记录在bitcoin账本当中,简单认为即为UTXO,UTXO在全网中传播。
  • 交易输出包含:比特币(以聪为单位)、确定输出的一道加密难题(cryptographic puzzle)。
  • 加密难题:加密难题也称为锁定脚本(locking script)、见证脚本(witness script)、脚本公钥(scriptPubKey)。
  • Bitcoincore JSON编码中交易显示:位于vout的数组中,一个输出显示为一个值(value:以bitcoin显示)、一个加密难题(scriptPbuKey:显示)。
  • 交易输出序列化:在网络中传输,通过发送字节流来显示被称为序列化,在bitcoin函数库中将交易内部存储在数据结构中,交易的字节流转换为函数库的内部数据结构,称为交易解析,转换为字节流称为序列化。
  • 交易输入:UTXO标记为将被消费,通过解锁脚本提供拥有证明。
  • 对于要支付的UTXO,创建一个指向其的输入,用解锁脚本解锁。首先一个指向UTXO的指针,通过指向UTXO记录在区块链中的交易的hash和序列号来实现,再通过解锁脚本,一般解锁脚本证明bitcoin的所有权的数字签名和公钥。
  • 输入组成:交易ID+输出索引(vout)+解锁脚本(scriptSig)+序列号。
  • 单纯根据输入的组成并非直接给出UTXO的信息,必须检索整个交易来确认引用的UTXO的状态,广播至全网也需要同样检索验证。
  • 交易输入序列化:和输出序列化类似。
  • 交易费:确保系统正常运行,支付给矿工的一笔费用,也能理解为激励或安全机制。费用由minrelaytxfee来设置。交易费和参与交易的bitcoin值无关。
  • 交易脚本语言:简单称为脚本,类似forth的基于堆栈的执行语言。目前大多以P2PKH脚本来处理交易。交易不局限于支付给某人的bitcoin地址,锁定脚本可以表达各种复杂情况。
  • 图灵非完备:bitcoin脚本除了有条件的流控制外,没有循环和复杂流控制能力,故是图灵非完备性。
  • 脚本是去中心化验证,这个和bitcoin整个架构有关,脚本在网络中都会被验证。
  • 脚本的锁定和解锁:交易过程中以来锁定脚本和解锁脚本来实现:
  • 锁定脚本是一个输出上的花费条件,执行花费输出所需要的条件,一般锁定脚本中含有公钥和地址,在程序中scriptPubKey出现。
  • 解锁脚本用于解决或者满足锁定脚本在一个交易输出上设定的花费条件的脚本。一般含有用户的数字签名,在程序中以scriptSig出现。

bitcoin脚本语言基于堆栈的语言:使用堆栈数据结构。

  • 堆栈:一种数据结构,允许push、pop,push在堆栈顶添加一个项目,pop在堆栈顶删除一个项目,堆栈操作对象为堆栈最顶端的项目,理解为后进先出(last-in-first-out)。
  • 脚本语言执行顺序:从左至右执行每个项目。操作码(operators)从堆栈中推送或者弹出一个项目,处理后,将结果推送到堆栈上。
  • 条件操作码:conditional operators对一个条件进行评估,产生一个boolean结果。
  • 脚本操作:op_add一个简单的加法操作,数字相加后结果推送到堆栈,op_equal验算操作结果。在验证bitcoin资金所有权的时候,验证解锁脚本和锁定脚本之间的bool值。举例:3 op_add 5 op_equal 那么2是一个正确答案,2 3 op_add 5 op_equal.脚本验证比例中子要复杂。
  • 解锁脚本和锁定脚本的执行:现在bitcoin版本中,堆栈先执行解锁脚本,执行正常复制主堆栈,再执行锁定脚本,解锁脚本中执行的数据复制到堆栈中执行锁定脚本,结果生产一个bool值,满足条件则执行完成。理解交易上,对一个UTXO的有效授权。
  • P2PKH:pay-to-public-key-hash,在bitcoin网络中交易花费是P2PKH脚本锁定的输出,输入包括一个锁定脚本、将输入锁定为一个hash值,理解为bitcoin的地址,那么P2PKH脚本锁定的输出可以提供一个公钥和其对应私钥创建的数字签名来解锁。
  • 解锁脚本和锁定脚本匹配:在交易中,执行组合验证脚本后bool值为true,说明公钥hash值和私钥匹配。
  • 数字签名:bitcoin中使用ECDSA算法,bitcoin中数字签名三种用法:其阿明证明私钥资金所有者,授权证明不可否认,签名证明交易(保证不能被任何人修改)。

数字签名的工作模式:数字签名本质上是一种数学方案:一部分使用私钥在交易创建时创建签名,另一部分允许任何人来验证签名算法、公钥、给定的消息。数字签名通过ECDSA算法来实现,((Sig=F{sig}(F{hash}(m),dA))).dA签名私钥、m交易、F~hash~散列函数、F-sig~签名算法、Sig结果签名。 
F~sig~:Sig=(R,S)通过计算R.S值,称为序列号的字节流。


  • 签名序列化:DER:序列化格式包含9个元素:DER序列的开始、序列的长度、一个整数值、整数长度、R值、接下来的一个整数、整数的长度、S值、后缀值。
  • 签名验证:验证一个签名必须要有签名的R,S值、序列化交易、公钥。理解为:只有生成改公钥的私钥所有者,才允许在交易上产生该签名。
  • 签名hash类型:SIGHASH,在bitcoin中签名意味找承诺,sighash附加到签名的单个字节,每一个签名都有一个sighash标志。三个sighash标志:all、none、single。Sighash标志在签名和验证期间是在建立交易的副本和删除其中的某些字段,然后交易序列化,sighash标志添加到序列化交易的结尾,结果再hash,得到签名消息。交易的不同部分被删除,得到的hash值取决数据的不同子集,在hash前,sighash作为最为一部分,签名对其也进行签署,故无法更改。
  • ECDSA:签名算法想生成一对临时私钥公钥,涉及签名私钥和交易hash变换后,临时密钥用于计算R、S值。S=k-1(Hash(m)+dA*R)mod p。k临时私钥、R临时公钥x坐标、dA签名私钥、m交易数据、p椭圆曲线顺序。验证是签名生成函数的倒数,使用R\S值和公钥来计算一个P:P=s-1*Hash(m)G+s-1*R*Qa。R/S签名值、Qa公钥、m签署的交易数据、G椭圆曲线发生器点。计算点P的坐标等于R,则签名有效。(椭圆曲线算法可参考区块链解读-椭圆曲线算法)
  • 多重签名:n个公钥记录在脚本中、并且需要至少m个提供签名才能解锁资金,称为m-n方案,n是密钥总数,m是验证所需签名的数量。锁定脚本格式:M… N CHECKMULTISIG,举例: 2 3 CHECKMULTISIG。
  • P2SH:pay-to-script-hash简化复杂脚本的交易。脚本中一班包含长公钥,最终交易脚本会比最初交易脚本长达数倍。简化监本,一笔交易支付UTXO,解锁支付脚本,必须含有和hash相匹配的脚本,P2SH向该hash匹配脚本支付,但输出支付时,脚本在后续呈现。锁定脚本由hash运算后20字节的散列值取代,叫赎回脚本。
  • P2SH地址:基于Base58编码含有20字节的hash的脚本。
  • P2SH优点:交易输出过程中,有简短电子指纹取代,交易代码变短。脚本编译为地址,支付指令的发出者和只负责的bitcoin钱包简化执行P2SH。P2SH将构建脚本重担转移给接收方。P2SH将长脚本数据存储的负担重输出方转移至输入方。P2SH将长脚本数据存储重担从支付时转移至未来。P2SH将长脚本的交易成本从发送方转移到接收方,接收方在使用该资金时候必须有赎回脚本。

  • 数据记录输出:应对区块链中区块链节点存储消耗大量磁盘空间的问题,大量不能用于交易的UTXO膨胀,针对不能用于交易的UTXO,在0.9版本bitcoin核心客户端上,采用return操作符实现在交易输出上增加80字节的非交易数据,实现一种可复查的非交易型输出,该类型存储于区块链上但不存储在UTXO集,return脚本样式:return。Data部分限制为80字节,以hash方式呈现。Return不涉及可用于支付的解锁脚本的特点,不锁定资金,一般以一个金额为0的bitcoin输出,在验证时候标记交易无效,一般一笔标准的交易只有一个return的输出。最初retrun为80字节,功能释放后减少为40字节,或者少于80字节。
  • 时间锁:timelocks,时间锁允许一段时间才允许支出的交易,由nlocktime字段实现,为复杂的多级智能合同提供技术基础。
  • 交易锁定时间:在交易中设置时间锁功能,交易锁定时间在交易数据结构设定中一个字段,定义交易有效的最早时间。锁定时间了nlocktime在大多数交易中设置为0,表示即刻传播执行,超过5亿解释为unix时间戳后的秒数,并且交易在指定时间之前无效,在未来的时间或者区块中才会发送到网络中,等同一个延期支票的概念。

交易锁定时间限制和检查锁定时间验证:交易锁定时间限制一笔交易的执行前提,必须在一定的时间和区块条件成熟后才能执行,一旦为到达前提则认为是无效交易。通过check lock time verify(CLTV)检查锁定时间验证来控制。CLTV在2015年12月bitcoin软分叉升级BIP-65规范提出,脚本语言中添加一种checklocktimeverify的操作符。CLTV是每个输出时间锁定,不是每个交易的时间锁定,区别于nlocktime:nlocktime是交易级时间锁定,CLTV是基于输出的时间锁。CLTV限制特定的UTXO,结合nlocktime设置为更大或者相等的值,约定未来的一个时间才能花费。脚本示例:DUP HASH160<交易者 PUBLIC KEY HASH>EQUALVERIFY CHECKSIG、CHECKLOCKTIMEVERIFY DROP DUP HASH160 <交易者 PUBLIC KEYHASH> EQUALVERIFY CHECKSIG .CLTV以一个参数作为输入,类同nlocktime格式数字,在后缀做一个bool的判断。


  • 相对时间锁:nlocktime和CLTV都是绝对时间锁,相对时间锁是在消耗输出的条件制定为从快链接中输出确认为经过时间。作为是将两个或者多个互相依赖的交易链接在一起,对依赖从先前交易的确认所经过的时间的一个交易加一个时间约束。这个作用在闪电网络中被经常用到。脚本使用:CHECKSEQUENCEVERIFY(CSV)操作码实现。相对时间锁通过BIP-68和BIP-112规范共同实现,找2016年5月软分叉升级被激活的一个共识机制。
  • nSequence相对时间锁:在每个输入中加多一个nSequence字段。该字段设计为了让交易在内存中能修改,但未真正运行,那么输入交易的序列值小于2^32,表示为未确定的交易。这类型的交易在内存池中保存,有大于之前nSequence值后被取代,在有nlocktime和CLTV的交易中nSequence值必须小于2^32.(一般为2^32-1)。在一笔交易中nSequence值小于2^31就是一笔相对时间锁定的输入交易,一直要到相对锁定时间后才生效。
  • CSV的相对时间锁:CSV的值和相应的nSequence格式相匹配,在一个父交易传播后,消耗相对锁定时间后子交易才进行。
  • 针对费用狙击时间锁定:费用狙击矿工师徒从将来块来重写过去块,实现狙击最高费用的交易,扩大盈利。那么在节点中bitcoincore将在任何创建交易上将nlocktime设置为下一个块,那么在分叉攻击下,时间锁阻止在下一个块,矿工智能在当前有效块中重新挖矿,不产生新的费用。Bitcoin core将素有新交易的nlocktime设置,在所有输入上nSequence设置为0xFFFFFFFE启用nlocktime。
  • 中位时间过去Median-Time-Past:通过取最后11个块的时间戳并计算其中位数作为中位时间过去的值,这个中间时间值就成了共识时间,用于所有时间计算。
  • 具有流量控制的脚本:bitcoin使用if、else、endif、notif操作码实现流量控制,表达为布尔运算符。
  • 带有verify操作码的条件子句:bitcoin另一种条件以任何verify结尾的操作码,如果条件不为true那么即刻终止。

bitcoin采用P2P的网络架构。

  • P2P:在同一网络环境中节点之间彼此对等,每个节点都提供网络服务,没有所谓的“特殊”节点,网络节点以一种扁平化的拓扑互相连接,不存在传统的服务端、中心化的服务节点、网络层级结构。整个网络交付运作,协同处理。每个节点在对外提供服务,同时也使用其他网络节点的服务。P2P网络具有去中心化的特点,在互联网建立初始,P2P就是最为普遍的一种典型架构,节点之间权利和义务对等,在文件共享中最为常见(P2P下载应该都接触过)。
  • Bitcoin网络:bitcoin网络是在P2P协议下运行的一系列节点的集合,当然bitcoin网络协议中不单单P2P协议。
  • Bitcoin节点:bitcoin网络中节点之间互相对等,节点由路由、区块链数据库、挖矿、钱包的功能集合。
  • Bitcoin节点具体功能:每个节点都参与全网的路由功能。一部分节点保存一份完整的区块链数据,称为全节点,全节点可以独立自主的验证所有交易,一部分节点通过(SPV)简易支付验证,称为轻量级节点,该节点没有完整的数据拷贝。挖矿节点,一般是特殊硬件运行工作量证明(POW)算法,通过竞争方式挖矿产生新的区块,打包交易获得bitcoin奖励,挖矿节点可以是全节点也可以通过参与矿池的轻量级节点,但需要依赖矿池服务器维护全节点才能进行正常运行。钱包一般都是SPV节点。
  • Bitcoin网络扩展:bitcoin网络中运行特殊协议的网络节点,P2P主网络中连接许多矿池服务器以及协议网关。包含了多种类型的节点、网关服务器、边缘路由器、钱包客户端等相关链接协议。

网络发现:在bitcoin网络中加入一个节点,必须和其他节点互通,建立连接,一般采用8333端口和对等节点建立连接,过程如下: 
nVersion定义客户端所发布的bitcoin的P2P协议版本。 
nLocalServices一组该节点支持的本地服务列表。 
nTime当前时间。 
addrYou当前节点可见的远程节点的IP地址。 
addrMe本地节点的本机IP地址。 
Subver当前运行软件类型的子版本号。 
BaseHeight当前节点区块高度。


版本消息是节点进入网络发送给对等节点的第一条消息,确认版本时候兼容,版本确认后发送一个verack建立连接。在寻找新的对等节点的时候,使用多个DNS种子来查询DNS,DNS服务器提供bitcoin的IP地址列表。Bitcoin core客户端包含五种不同的DNS种子名称,使用DNS种子选项由switch–dnsseed控制。 
* 在连接上一个bitcoin节点的IP地址后:通过-seednode参数连接,仅用于为种子,nodea-version-nodeb、nodeb-verack-nodea、nodeb-version-nodea、nodea-verack-nodeb。当建立一个或者多个连接后,新节点将一个包含自身IP地址的addr发送给相邻节点,相邻节点依次传播其他相邻节点:nodea-addr-nodeb、nodea-getaddr-nodeb、nodeb-addr-nodea、nodeb-addr-nodea、nodeb-addr-nodea。节点连接到不同对等节点,节点主要作用:在失去已有连接时发现新节点,并在其他节点启动时提供相关信息,节点启动时候只需要一个连接,因为一个节点可以通过引荐方式到其他对等节点,不停重复该过程。当重启启动时候发现原先节点没有应答,那么可以通过使用种子节点重新启动。通过-connect=选项来指定一个或者多个IP地址。 
* 全节点:全节点的意义就是包含全部交易信息的完整的区块链的节点,完整区块链节点包含完整的信息,独立进行建立或者校验区块链,包括从创世区块到最新区块,完整区块链节点可以独立校验交易信息,但完整区块链需要永久存储来保存数据和交易信息,故对本地硬件存储资源有一定要求。 
* 库存清单:全节点接入网络,需要构建完整的区块链,那么数十万区块内容需要同步,在发送同步请求中包含一个bestheight字段标示当前区块的高度,对区块数量进行比较。然后交换一个getblocks消息,包含本地区块最顶端的hash值,通过比较验证本地的区块链时候最新。一旦不是最新区块那么需要补充,类似一种增量的概念,通过inv消息把hash值传播,缺少区块的节点通过getdata消息请求全区块信息。假设一个节点离线了一段时间,那么发送getblocks消息,收到inv响应,继而下载缺失区块。Nodea-getblocks-nodeb、nodeb-getblocks-nodea、nodeb-inv-nodea、nodea-getdata-nodeb、nodeb-block-nodea。


  • SPV节点:简化支付验证节点,不必存储完整的区块链的情况下正常工作,也称作SPV客户端或者轻量级客户端,目前钱包所采用的最常见的方式。

SPV节点工作原理:SPV节点只下载区块头,不下载区块中的交易信息,大小是完整的区块链数据的千分之一。SPV节点无法构建所有可用于消费的UTXO全貌,SPV节点在验证交易时通过依赖对等节点按需提供区块链的相关部分的局部视图。简化支付验证通过参考交易的深度来验证,在一个全节点会构建一个验证链,该链由沿着区块链按时间倒序一致追溯到创世区块的数千区块和交易组成,SPV节点验证区块的链,并把验证的链和交易相关联。SPV节点不能验证UTXO是否还未被支付,SPV节点在该交易信息和它所在区块之间用merkle路径建立链接,之后6个区块链堆叠在该交易区块之上,验证之后6个区块的有效性,保证交易正常。

SPV节点工作过程:SPV节点使用一条getheaders消息,而不是通过getblocks消息来获得区块头。响应节点发送一条headers的消息发送大量区块头,SPV节点同时在对等节点的连接上设置过滤器,用于过滤对等节点发来的区块和交易数据流,任何目标交易都是通过一个getdata的请求来读取,对等节点则生成一条包含交易信息的tx消息作为响应。过程:nodea-getheaders-nodeb、nodeb-headers-nodea、nodea-getheaders-nodeb、nodeb-headers-nodea。理论上来说SPV在需要读取特定交易而选择性的验证交易,存在一定的隐私风险,在对特定数据的请求可能投入钱包地址信息。

  • Bloom过滤器:允许用户描述特定的关键词组合而不必精确表述的基于概率的过滤方法,让用户有效搜索关键词的同时保护他们的隐私。Bloom过滤器让SPV节点制定交易的搜索模式,搜索模式可以基于准确性或私密性考虑调节,理解为:在过滤器中只包含关键词,那么更多的相应交易被搜索出来,在包含若干无关交易的同时有更高的私密性。

Bloom工作原理:实现通过一个可变长度N的二进制数组和可变数量M的一组hash函数组成,hash函数的输出值始终在1和N之间,该数值与二进制数组相对应,函数为一个确定性函数,理解为,任意一个使用bloom过滤器的节点通过该函数都能对特定输入得到同一个的结果,bloom过滤器的准确性和私密性能通过长度N和hash函数的数量M来调节。Bloom过滤器数组中每一个数的初始值为0,关键词被加到bloom过滤器中之前,依次通过每一个hash函数运算一次。通过hash函数运算后得到一个1到N之间的数,在数组中对应的位置被置为1,从而把hash函数的输出记录下来,接下来再进行下一个hash函数的运算,另一位置为1,不断重复该过程,当全部M个hash函数都运算后,一共有M个位置被置为1,这样一个关键词就被记录在bloom过滤器中。但增加第二个关键词重复之前的步骤。随着更多的关键词指向了重复的位,那么bloom过滤器随着位1的增加而饱和,准确性就相应的降低了。当将关键词逐一代入各hash函数中运算,结果和之前的原数组比较,那么所有结果都成了1,就表示这个关键词可能已经被该过滤器记录,当然这个结论是可能是的一个效果,因为这些字节的1也有可能是其他关键词运算的重叠结果。但验证一个关键词结果字段为0,那么就确定没有被匹配。

SPV节点中使用bloom过滤器:bloom过滤器用于过滤SPV节点从其对等体接收的交易,仅选择SPV节点感兴趣的交易,不泄露相关地址和密钥。SPV节点初始化将过滤器为空状态,SPV节点列出相关感兴趣的地址、密钥、散列,通过从其钱包控制的任何UTXO中提取公钥hash、脚本hash、交易ID来实现,SPV节点将其中的每一个都添加到bloom过滤器,如果这些模式存在于交易中,那么bloom过滤器则匹配,但不自动显示模式。此时,SPV节点将向对等节点发送一个过滤器加载消息,在对等节点上,针对每个传入交易检查bloom过滤器,全节点根据bloom过滤器检查交易的几个部分然后进行匹配。检查组件通过使用bloom过滤器来匹配公钥hash、脚本、OP_RETURN值、签名中的公钥或者智能合同复杂脚本的任何未来组件。建立过滤器后只有匹配交易才发送到节点,响应节点的getdata消息,对对等节点发送一个merkleblock消息,该消息仅仅包含过滤器匹配的块和每个匹配交易的merkle路径的块头,同时对等节点发送包含过滤器匹配的交易和tx消息。全节点向SPV节点发送交易,SPV节点丢弃任何误报,使用正确的匹配的交易更新UTXO集和钱包的余额,同时也修改bloom过滤器,然后全节点就可使用新的bloom过滤器来匹配性的交易。


  • 加密和认证连接:在BIP150/151中提供了比特币通讯加密:tor传输和P2P认证和加密。
  • Tor传输:Tor洋葱路由网络,提供匿名、不可追踪和隐私的随机网络路径提供数据的加密和封装。在bitcoincore中有多种配置,允许运行通过Tor网络传输节点之间的流量,也提供Tor的隐藏服务,允许各个节点通过Tor直接连接到bitcoin节点。在0.12版本,连接本地的Tor服务,节点自动提供隐藏服务,且Tor和bitcoin core进程作为有足够权限的用户访问Tor认证cookie的用户运行,则自动运行,命令如下:bitcoind --deamon –debug=tor。在日志中看到:ADD_ONION success表示已添加隐藏服务。
  • 对等认证和加密:bitc改进方案BIP150-151中在bitcoin网络P2P传输中增加了对P2P的认证和加密的支持,支持两个节点之间的所有通信的协商加密。具体如下:
  • BIP-150提供可选的对等认证,允许节点使用ECDSA和私钥对对方的身份进行身份验证。
  • BIP-151要求在认证之前,节点之间按照BIP-151建立加密通信。 
    以上两种改进方案允许节点连接到受信任的完整节点的SPV客户端,使用加密和身份验证来保护SPV客户端的隐私。使用身份验证来创建可信的bitcoin网络,防止攻击,P2P加密加强bitcoin对流量分析和隐私侵权监控的阻力。

交易池:在bitcoin中每个节点都会维护一份未确认交易的临时列表,称为内存池和交易池。节点利用这个临时的列表来追踪记录那些在网络上知晓,但为被打包进区块的交易。随着交易的接收,这些内容添加上交易池,并传播到网络中。当然有些节点还维护一个独立的交易池,一个交易的输入和一些未知交易相关,那么这个交易理解为孤立交易,暂时存储在孤立的交易池中,直到相关交易信息接收到。过程如下:一个交易添加到交易池,同时检查孤立交易池,查看是否有孤立交易引用了该交易的输出,任何相关交易进行验证,验证通过,那么孤立交易池中删除该交易,添加上交易池中,使得交易记录相关联,对于加入到交易池中的交易,不再是孤立交易,这个过程重复迭代,使得整个交易链连接起来,触发整个交易链重构。交易池和孤立交易池存储在本地内存中,注意是内存中不是存储在硬盘中,这些交易通过网络传入的消息动态填充,启动时候,交易池和孤立池都是空的,睡着新交易的接收慢慢填充。当然一般bitcoin客户端还会有一个UTXO数据库,这个之前文章有写到过,这称为UTXO池,这和交易池是两个不同的数据集合,UTXO池初始化不能为空,里面包含了数以百万级的未支付交易输出记录,这个永久性存储。最大一个区别点:UTXO池代表包含之前已确认的交易,交易池和孤立池是只包含为确认的交易。

  • 区块链数据结构:区块链的数据结构一般包含交易信息的区块通过顺序有序的链接起来,可以想象一条很长的链,串联每一个有序生成的区块,区块中包含各种交易记录和相关信息。在bitcoin客户端使用LevelDB数据库存储区块链的元数据,每一个区块通过hash指向链接前一个区块。第一个区块称为创始区块,高度表示区块和首区块之间的距离,相隔多少个区块就是高度,顶部是指最新添加或者说是生成的区块。
  • 区块头:每一个区块的区块头会进行SHA-256加密,生成一个hash值,通过这个hash值识别区块链中的区块,区块头中还有一个最重要的作用,通过该区块头的父区块hash值引用前一个区块,每个区块头都包含了父区块的hash值,用于链接,通过这个链接,区块串联成区块链。
  • 区块分叉:这里简单说下,一个区块只有一个父区块,但是会出现有多个子区块,那么这种情况称为分叉,分叉有硬分叉和软分叉之分,之后专门会对分叉作说明,有兴趣可以参考之前写的分叉内容。
  • 父区块hash值:在区块链中保障区块一致性,父区块hash值尤为关键,一旦一个区块的父区块hash值被恶意改变,那么父区块的hash值也必将变化,一次类推,一旦想要改变整个区块链,必须改变每个父区块的hash值,直到初始区块,那么这将是一个巨大的工程。这也保证了区块链的不可改变的一个特性。

  • 区块结构:区块类似公开账本中各个数据的集合,理解为一个存储数据账本记录的容器,包括:元数据的区块头和构成区块主体的一长串交易信息。区块头是80字节,交易一般来说平均为250字节,区块中包含超过500个交易,故完整的一个区块比区块头大大约1000倍。具体结构:block size(4bytes)、blockHeader(80bytes)、transactcounter(1-9bytes)、transactions。
  • 区块头:区块头有三组元素组成,一组引用父区块hash值得数据,这一组数据用于和前一区块相连,一组元数据,具体包括了难度值、时间戳、nonce,与挖矿相关,一组merkle root,用于有效总结区块中所有交易的数据结构。具体结构:version(4bytes)、previous block hash(32bytes)、merkle root(32bytes)、timestamp(4bytes)、difficulty target(4bytes)、nonce(4bytes)。
  • 区块标识符:区块链中广泛用到很多加密的hash值,那么区块的主标识即它的加密hash值,通过SHA-256算法对区块头二次hash计算得到一个数字指纹,产生一个32字节的hash值,称作区块头hash值,通过对这个区块头计算,表明唯一明确的标识一个区块,所有网络的中节点通过对区块头的hash计算来获取区块的hash值。区块的hash值不包含在区块的数据结构中,一般情况下区块hash是当区块从网络中接收的时候每个独立节点自己计算,作为区块元数据的一部分存储在独立的数据库表中,用于索引更快的从磁盘中检索区块。
  • 区块高度的概念,区块高度理解为创世区块后的一个记录值。区块高度不是区块的唯一标识符,在区块生成过程中,可能出现两个或两个以上的区块有相同的高度,当然区块高度也作为元数据存储在一个索引数据表中便于快速检索。
  • 创世区块:2009年bitcoin的出现,第一个区块被称为创世区块,所有后续的区块,追溯后最终都到达创世区块。创世区块中有一句bitcoin最为著名的话:“The Times 03/Jan/2009Chancellor on brink of second bailout forbanks.”这句话是泰晤士报当天的头版文章标题。
  • 区块链接:从区块链中全节点来看,本地保存了从创世区块开始的所有完整的副本,随着区块的产生,区块链不断扩展,每一个节点接入都会传入这些区块信息,并通过区块头hash值,父区块hash值验证,继而更新连接到最新的区块上。
  • Merkle树:merkle是一种hash二叉树,之前的文章有专门的章节写过这个内容。“树”在计算机中是一种数据结构,在bitcoin中merkle树用来归纳一个区块中的所有交易,同事生成整个交易打包后的数字指纹,提供一种校验区块是否存在的高效途径,生成一个完整的merkle树需要递归对hash节点进行hash,将新生成的hash节点插入到merkle树中,一直到只剩下一个hash节点,那即为merkle根。Bitcoin中merkle树两次用到SHA-256算法,称为double-SHA-256。从数据结构效率来算,N个数据元素加密后插入merkle树,那么最多计算为2*log~2~(N)即可检验出任意数据是否在该树中。
  • Merkle树计算:bitcoin中所有的交易不存储在merkle树中,是通过将数据hash后,然后hash值在叶子节点,叶子节点之间hash值串联进行hash,归纳到父节点,以此类推。A = SHA256(SHA256(Transaction A))、HAB =SHA256(SHA256(H~A~ + H~B~))。在merkle树种出现偶数的叶子节点,那么就通过串联,出现奇数节点,那么需要交易归纳,最后的交易复制一份构成偶数节点,这种称为平衡树。不管区块中交易有多少,交易都会归纳,产生一个32字节的数据作为merkle根。在证明一个特定的交易时候,一个节点需要计算log~2~(N)个32字节的hash值,形成一个特定的交易到树根的认证路径或者merkle路径即可。
  • Merkle树和SPV:在SPV节点中merkle被广泛使用,在SPV节点中不下载整个区块,仅保留区块头,那么使用认证路径或者merkle路径来验证交易存在于区块中。
  • Bitcoin测试:现在bitcoin区块链环境中除了bitcoin主干网以外还有:testnet、segnet、regtest。
  • Testnet:用于测试区块链、网络、货币的总称,是一个功能齐全的P2P网络,包括钱包,测试币,挖矿等功能。理解为生产bitcoin的测试环境。
  • Signet:隔离见证测试网络,用于帮助隔离见证的开发和测试。
  • Regtest:回归测试,bitcoin的一个核心功能,允许创建本地区块链进行测试。 
    (上述三个环境提供一系列的测试环境,用于钱包、客户端、交易所等应用程序的开发)

  • 挖矿:在了解bitcoin的过程中,挖矿最为常见的几个概念之一,挖矿在bitcoin被认为是一种奖励或者产生新币,但是从整个bitcoin区块链平台来看,挖矿虽然是一个创建新币的过程,作为激励挖矿这个过程的目标,但是挖矿更为重要的一个作用,巩固了去中心化的清算机制,通过这种机制保证了交易验证和清算,是一种去中心化的安全机制,一旦这种安全机制不存在,那么bitcoin的认可程度也就会崩塌。挖矿可以理解为保证了bitcoin的安全,在和现在传统中心化系统来保证安全不同,通过一种没有中心化机构的存在下,实现一个全网共识,在新币的产生和交易费的奖励将网络中矿工的挖矿行为和网络安全机制保持一致,实现货币的安全认可的发行。
  • 矿工验证:矿工验证每笔新的交易,并且记录在账本中,一般平均10分钟有一个新的区块产生,区块中包含上一个区块产生到现在时间发生的所有交易,交易依次添加到区块链上,这个过程称为交易的确认,只有确认后的交易,bitcoin转移后接受者才能真正花费交易中转移的bitcoin。
  • 矿工奖励:在挖矿过程中,会得到两种类型的奖励:一种创建新的区块的新币奖励,以及在生成区块中每一笔交易的交易费用,矿工通过计算一道基于加密hash算法的数学难题来竞争区块的生成权,那么这个难题的答案也必然存在于新的区块中,作为矿工计算数学题的工作量的一个证明,称为“工作量证明”。这种竞争模式以及区块生成矿工有权利记录交易的机制是bitcoin一个安全的基础。新的bitcoin随着新区块的产生而产生,这个过程称为挖矿,这种奖励机制递减,210000个块减少一半,目前是12.5个bitcoin,大致在2140年2100万个bitcoin会全部发行完毕。有人质疑一旦bitcoin发行完毕了,bitcoin系统是否还会存在,那么之前说到奖励是一部分,交易费是一部分,乐观来看,只要市场活跃,bitcoin还是会一直运行下去。
  • 交易费:交易费是区块中打包的所有交易的手续费,理解为一个输出和输入的差额,目前来看这个收入占比很少,0.5%甚至更少,大部分的收益还是新币,目前12.5bitcoin。

bitcoin经济学:2009年bitcoin开始发行为50个bitcoin的奖励、2012年每个区块的奖励是25个bitcoin、2016年7月每个区块的奖励是12.5个bitcoin。在大致2020年区块高度630000时候会下降到6.25个bitcoin,32次等分后,大致在6720000区块高度会到极限1聪bitcoin,最终在6930000区块高度时候全部bitcoin发行完毕。总量固定且发行速度递减创造一种抗通常的供应模式。当然假设有人忘记了私钥,那么bitcoin总量事实上是在一直减少的。 
通货紧缩:bitcoin的发行模式认为会导致货币通货紧缩,通缩是一种由于货币的供应和需求不匹配导致的货币增值的现象,和我们经常听到的通货膨胀相反,这就意味着货币随着时间有更强的购买力。 
经济学家观点:通缩经济是一种需要避免的灾难型经济,在快速通缩期,意味着商品价格下跌,人们不可避免的会去储存货币,尽量不去花费掉。那么整个经济就因为在需求崩塌后导致了滞涨状态。 
Bitcoin观点:法币、货币有可能会被无限制的印刷,除非遇到需求完全崩塌并且毫无发行货币的情况下,因此经济很难进入滞涨期,bitcoin的通缩是本身特性, 并不是需求崩塌引起,所以认为是一种预定且有节制的货币供应模型。


去中心化:在bitcoin网络中所有节点都接受区块链,区块链作为一本证明所有权的权威记录存在。去中心化的机制,使得所有节点达成共识,和传统的中心化认证机构权威认证的模式完全不同。在bitcoin中,所有的全节点都有一份完整的数据的副本,这个副本就认为是权威,权威是所有节点的认可,记账是通过独立竞争再广播认可,所以认为bitcoin是一种去中心化自发共识机制,没有中心节点、没有完成点。众多独立节点遵守规则异步交互自发形成。产生4种独立过程且有相互作用: 
每一个全节点依据综合标准对每个交易进行独立验证。 
工作量证明算法的验算,挖矿节点将交易记录独立打包到新的区块中。 
每个节点独立对新区块进行校验,并完成区块的链接。 
每个节点对区块链独立选择,在工作量证明机制下选择累计工作量最大的区块链。


交易独立验证:在钱包软件中,通过收集UTXO,提供正确的解锁脚本,新建一个支出给接收者来创建交易,随后交易广播到网络中。在节点收到交易的时候,首先验证该交易,检验正常则传播,检验不正常则在第一个节点就废弃。校验列表: 
交易的语法和数据结构正确。 
输出和输入列表不为空。 
交易字节大小 输出的总量在2100万个(bitcoin的最大值)。 
没有hash值为0,N等于-1的输出。 
Nlocktime是小于或等于INT_MAX,或者nlocktime and nSequence的值满足Median TimePast。(Median Time是这个块的前面11个块按照block time排序后的中间时间) 
交易字节大小是大于或等于100. 
交易中签名数量小于签名操作数量上限。 
解锁脚本只能将数字压入栈中,锁定脚本必须符合isStandard格式。 
池中或者位于主分区区块中的一个匹配交易必须是存在的。 
对于每一个输入,引用的输出必须存在,且没有被花费掉。 
对于每一个输入,引用的输出存在于池中任何别的交易中则交易被拒绝。 
对于每一个输入,主分支和交易池中寻找引用的输出交易,如检查缺少该输出交易中任何一个输出,该交易成为一个孤立交易,且其匹配的交易为出现在池中,那么加入到孤立交易池。 
对于每一个输入,如果引用的输出交易是一个coinbase输出,那么该输入至少获得COINBASE_MATURITY(100)个确认。 
使用引用的输出交易获得输入值,检查每一个输入值的总值是否在规定范围内,小于2100个bitcoin,大于0. 
输入值的总和小于输出值的总和,交易中止。 
交易费太低无法进入一个空区块,交易中止。 
每一个输入的解锁脚本必须依据相应输出的锁定脚本验证。

以上交易验证在bitcoin客户端的AcceptToMemoryPool、CheckTransaction、CheckInputs函数中执行操作。

交易打包:在验证交易后,bitcoin节点会将这些交易添加到自己的内存池中(交易池),用来暂时存储未添加到区块的交易记录,验证这些交易,挖矿节点把这些交易整合到一个候选区块中。每一个挖矿节点维护本地的区块链数据副本,同时一直在网络上监听网络中的交易,本地区块高度和网络上区块高度对比,一旦收到信的高度的区块信息,那么就是下一个区块生成的竞争开始,在整个过程中,挖矿节点在计算新区块的数学难题的同事,也同时收集交易记录为再下一个区块做准备,这些交易存放在内存池,验证新区块产生后,检查区块中的交易同时移除自己内存池中在区块中生成的交易记录,剩余的等候在下一个区块生成。挖矿节点通过竞争机制,构建的区块是一个候选区块,只有在完成工作量证明解后,这个区块才生效。该命令索引区块信息:bitcoin-cli get blockhash 区块高度。


  • 创币交易:区块中的第一个交易是一个特殊的交易,作为矿工的奖励,称为创币交易或者coinbase交易,这个交易发送到竞争胜利矿工的钱包。这个创币交易没有输入,不消耗UTXO,就称为coinbase输入。
  • Coinbase奖励、矿工费:矿工的奖励除了创币还有区块中交易的交易费。Total fees=Sum(Inputs)-Sum(Outputs)。Coinbase奖励:变量Subsidy表示初始奖励,值为COIN常量(100000000聪和50的乘积),奖励减半通过变量halvings来控制,halvings最大值64,然后这个函数二进制右移操作一位、等同于除2的操作。来实现减半。
  • 创币交易结构:Transaction Hash(32bytes)、Output index(4bytes)、coinbase data size(1-9bytes)、coinbase data(variable)、sequence number(4bytes)。
  • Coinbase数据:创币交易中不含解锁脚本,这个字段被coinbase数据替代,长度2字节最大100字节,矿工可以使用其他部分填充任何数据。一段coinbase16进制字符串中,第一个字节,执行后面字节压入脚本栈,接下来三个字节翻转十进制为区块高度,接下来介个16进制是随机值,求解一个适当的工作量证明,coinbase数据结尾ASCII编码字符P2SH。
  • 区块头构造:构造区块头的过程中,挖矿需要填充6个字段。Version(4bytes)、Previous block hash(32bytes)、Merkle root(32bytes)、timestamp(4bytes)、target(4bytes)、nonce(bytes)。
  • 构建区块:挖矿最为简单理解就是不停的计算区块头的hash值,不断尝试,直到匹配。

  • hash函数:hash函数的概念就是输入一个任意长度的数据,输出一个长度固定的但不相同的值,很多人都理解为数字指纹。加密hash函数的特征,不同的输入几乎不可能出现相同的输出,特意用一个输入去生成一个想要的hash输出,几乎也不可能,改变输入中任何一个字母、数字、标点都会产生不同的hash输出。
  • SHA-256函数:不论输入的大小是多少,SHA-256函数的输出长度为256bit。 
    难度值:挖矿过程中,竞争计算最后的nonce值,通过不断尝试。Hash值为16进制表示,那么第一位以0开头,理论上期望每16次得到一个以0开头的hash值。那么target的目标阈值就是0x1 63位0.
  • 工作量证明:挖矿找到一个小于target目标阈值的hash值,那么把目标值减小,相应找到这个hash就越来越难。估计从实现目标难度取得成功所需的工作量,bitcoin中算法是SHA-256这种确定性函数,那么输入本身就能成为一个证据,必须要有一定的工作量才能产生低于目标的结果。尽管在每一次尝试会产生一个随机的结果,但是任何可能的结果概率通过事先预支计算,指定了特定难度的结果构成了一个具体的工作量证明。矿工在解到nonce值后,把nonce这个值发布出去,节点值需要hash计算一次就可验证,但是解题的矿工由于目标值的大小,需要经过很多次的计算才能得到这个解,任何节点知道目标值和nonce值后,根据统计学来估算难度。工作量证明必须小于目标hash值,这理解为更高的目标找到低于目标的hash不太困难,较低的目标以为找在目标下方找到hash更难,目标和难度成反比。矿工用交易构建一个候选区块,矿工计算这个区块头的信息的hash值,检验是否小于当前的目标值,如果这个hash不小于目标值,矿工会修改这个nonce,再次尝试,最终找到一个合适的nonce使得区块头信息hash足够小。
  • 难度说明:在bitcoin中,区块难度目标成为难度位,标记为系数/指数各自。计算难度的目标公式:target = coefficient * 2^(8 * (exponent – 3)) 
    难度目标和调整:目标决定难度,从而影响求解工作量证明算法的时间。Bitcoin区块平均没10分钟生成一个,注意这个是一个平均时间,这个时间在很长一段时间内保持不变,随着计算机计算能力的提升,那么保持平均10分钟生成一个区块就需要对难度值进行一定调整。难度的调整在每个完整节点中独立自动发生。美国2016个区块,大概20160分钟时间,进行一个比较,区块生成快于10分钟就增加难度,慢于10分钟就降低难度。调整公式为:New Difficulty = Old Difficulty * (Actual Time of Last 2016 Blocks / 20160 minutes)。

校验区块:区块生成后广播后,其余节点需要独立校验每个区块,当一个节点接收到一个新的区块,需要进行以下校验: 
区块的数据结构语法有效。 
区块头的hash值小于目标难度。确保足够的工作量证明。 
区块时间戳早于验证时刻未来两个小时。 
区块大小在长度限制之内。 
第一个交易为coinbase交易。 
验证区块内的交易确保他们的有效性。


  • 区块的组装和选择:节点一般维护三种区块,第一种是连接到主链上,第二种是从主链上产生的分支(备链),第三种在已知链中未能找到父区块,则拒绝。一般主链是累计了最多难度的区块链,主链也是包含最多区块的链,除非两个等长的链并且有一个有更多的工作量证明。分叉中的区块和主链中的区块是兄弟区块,但不是主链的一部分,除非出现了分叉延长并有固定的矿工在其上挖矿。

  • 区块链副本一致性原则:区块链是去中心化的数据结构,网络中众多节点,那么不可能要求所有的区块链副本都保持一致。节点选择并尝试延长代表累计了最大工作量证明的区块链,称为最大累计工作的链。节点计算链上累加的每个区块的工作量,得到建立这个链所要付出的工作量证明的总量。那么在区块链网络中,所有的节点选择最长累计工作的区块链,理论上区块链中节点就最终会达到一个一致的状态。分叉会出现,但是更多的区块链接到其中一个链上,保持其中一个为最长链。那么也就保持了上述的原则。
  • 区块链中分叉:bitcon网络中节点分布错杂,当有两个候选区块同时想延长最大区块链的时候,分叉就会产生。理论上正常情况下,在一个较短时间内,同时有两名矿工都各自算得了工作量证明的解,即可加入自己的区块广播。那么广播过程中先传给了邻近的节点,然后在传播到整个网络。那么对这些接收的节点来说,他们接收了可能是其中一个矿工的,并非同一矿工的区块,在验证区块的时候,父区块验证通过,那么这样网络中就出现了两个不同版本的区块链副本。被两名矿工生成的两个区块都是有效的,可能包含着一样的交易(排序不同)。网络中节点收到A矿工区块,延长区块链,之后收到B矿工区块,由于是第二次收到当前的区块,故先认为是无效区块,当然这个区块不会丢弃,形成备用链。同样先接收B矿工区块的也会出现同样情况。这时候A.B矿工的区块无法定义那个是正确,那个是不正确。各自接收区块的节点由各自的立场,所有矿工接下来开始在各自立场上挖掘区块,竞争再一次开始,拥有A和B区块的各个矿工节点在下一轮竞争中那一部分率先发现工作量证明并将其传播,那么区块将再扩展一个块,另一部分竞争失败的节点就会发现对方的链更长,那么这些失败节点将选择长的链为主链,网络中节点再一次达成一个新的共识。之前的非最长链的最后一个区块就成为了一个孤立的状态。理论上来考虑,两个区块的分叉也有可能,因为第一次分叉对立的两拨矿工又同时再一次发现了不同的区块的解,相对来说这种几率较低,单个区块的分叉每周都会发生,双区块分叉则比较少见,bitcoin将区块间隔设计为10分钟,为了在更快速的交易确认和更低的分叉概率之间作了一个妥协。理解为,更短的区块产生间隔会让交易清算更快完成,但是也频繁导致分叉,相反更长时间的间隔会减少分叉的数量,但是影响到了清算的时间。
  • 挖矿、算力:挖矿经过一个过程,2010到2011矿工使用cpu升级到gpu,进而到FGPA挖矿,2013年ASIC挖矿引入,把SHA-256算法直接固化在挖矿专用的硅芯片上。近几年来挖矿算力爆炸性增长,难度也相应增加。
  • 随机值升位方案:在bitcoin初期,矿工可以通过遍历随机数(nonce)获得一个符合要求的hash值来生成一个区块,但是难度增长后,矿工在尝试了40亿次后还是没有生成区块,那么通过读取块的时间戳并计算经过的时间来解决。因为时间戳是区块头一部分,它的变化可以让矿工用不同的随机值再次遍历,但是矿工硬件的速度达到4GH每秒的时候,这种办法也变得困难,随机数的取值一秒内就被用尽了。随着ASIC矿机出现后,ASIC矿机达到TH每秒的hash速率后,挖矿软件为了找到有效的区块,需要更多的存储空间来存储nonce值,当然同时可以延后一点时间戳,问题是延后太多时间,又会导致区块无效。最终的解决方案:使用coinbase交易作为额外的随机值来源。之前也提到过coinbase可以存储2-100字节,矿工使用这个空间作为额外随机值的来源,允许去探索一个较大的区块头值范围来找到有效的块,这个coinbase交易包含在merkle树种,这样任何coinbase脚本的变化会导致merkle根的变化。8个字节额外随机数和4个字节的标准随机数,允许矿工每秒尝试2的96次方的可能性,且不需要修改时间戳。同时coinbase脚本中更多额外空间为将来随机数扩展作准备。

矿池:现在bitcoin环境中,矿工算力竞争激烈,那么个体solo挖矿几乎没有什么机会,综合电力和硬件成本,solo挖矿意义着实不大,就算通过最快的ASIC也无法和巨大机房里数万芯片集成的矿产竞争。综合经济利益考虑加入矿池,通过专门的协议协调矿工。个人矿工在建立了矿池账号之后,设置自己的挖矿服务器连接到矿池服务器,矿工的挖矿设备在挖矿时保持和矿池服务器的连接,和其他矿工同步各自的工作,分享挖矿任务,分享奖励。当然每个区块被挖出来之后,bitcoin奖励是发送到矿池的bitcoin地址,当奖励到一定的阈值,矿池服务器定期支付奖励给参与的矿工。一般情况下,矿池服务器为提供矿池服务收取一个百分比的费用,参加的矿池的矿工把去挖掘区块的任务分割,根据其挖矿的贡献值来或者相应份额的分红,矿池赚取一个份额设置一个低难度的目标,通常难度低于1000倍以上。 
当矿池中有人成功挖出一块,矿池获得奖励,并和所有矿工按照他们做出的贡献份额的比例分配。矿池中几乎每个参与矿工都能分得奖励,这就激励了每个人为矿池做出贡献,一般通过设置一个较低的取得份额的难度,矿池计算出每个矿工的工作量,每当矿工发现一个小于矿池难度的区块头hash,就证明已经完成了寻找结果所需的hash计算,同时为取得这份份额,能使用一个统计学上可衡量的方法,整体寻找一个bitcoin网络的目标散列值,众多矿工尝试较小区间的hash值,最终找到符合要求的结果。


  • 托管矿池:大部分的矿池都是托管的,简单理解,一个公司或者一个个人用户经营一个矿池服务器,这个服务器的所有者称为矿池管理员,他通过收取矿工收入的一个百分比费用来实现盈利,矿池服务器运行专业软件以及协调矿池中矿工们活动的矿池采矿协议,同时这个服务器也会连接到bitcoin全节点访问完整的bitcoin区块链完整副本,这样使得矿池服务器可以替代矿工验证区块和交易同时缓解运行一个完整节点负担。和一般的运行系统一样,完整bitcoin节点需要监控、维护、升级,对于矿工来说这样频繁操作可能会导致宕机或者一定程度损害矿工的利益,故加入矿池能部分避免这些问题。矿工连接到矿池服务器采用一个采矿协议(STM、GBT),这些协议都创建包含候选区块头模板的区块模板,矿池服务器通过打包交易,添加coinbase交易,计算merkle根、并连接到上一个区块hash来建立一个候选区块,这个候选区块作为模板分发给每个矿工,矿工用这个模块在bitcoin网络的难度下采矿,发送成功结果给矿池服务器来获取利益份额。
  • P2P矿池:互联网上是一个活性群体,不排除作弊可能,故托管矿池也存在这样的一个问题,管理人可以利用矿池进行双重攻击导致区块无效,矿池也存在一个中心化的概念,一旦发生中心化矿池的故障,那么就意味着单点故障,拒绝服务或者服务器宕机,那么就直接影响到了矿工的采矿,2011年避免中心化矿池的问题,提出P2Pool矿池,这是一个点对点矿池,没有中心管理节点,P2Pool通过将矿池服务器的功能去中心化,实现一个矿池区块链的系统,这里称为份额链(sharechain)。一个份额链是一个难度低于bitcoin的区块链系统,份额链允许矿工在一个去中心化的池中合作,每30秒一个份额区块出块,并获得份额,份额链上的区块记录了贡献工作和矿工的份额,并且继承之前的区块份额记录,当一个份额区块上实现bitcoin网络的难度目标时,那么就被广播到bitcoin区块链上,奖励份额链中的矿工。简单理解,份额链就是一个记录矿工份额和奖励的区块链系统,通过类似bitcoin的去中心化共识机制来保存所有份额记录。P2Pool采矿方式比之前中心化矿池要复杂,至少需要矿工硬件,网络带宽能支持一个bitcoin完整节点和P2Pool节点软件。P2Pool矿工加入到份额链,通过类似solo的挖矿模式,但是在份额链上合作采矿。P2Pool是一种比solo有效的挖矿方式,同时也兼顾了托管矿池给于管理人太多的权利,一种众合的方案,一种多样化采矿生态系统,使得P2Pool整体比bitcoin更为强大。

  • 共识机制:共识在区块链中来确定区块的和交易的有效性。保证网络中各个节点达成一致性的区块链副本,共识机制在一定时期内是不变的,但是互联网系统中,由于互联网的本性是一个共同参与活性系统,各个节点自制的特点,导致不确定性和未知性,故长期来看区块链的共识机制会发生一定的变化,变化是为了自适应,更好的迎合新功能、完善改进系统缺陷,以致更好的维护整个系统的正常运行。

硬分叉:在bitcoin系统中,我们现在听到最多的就是分叉,之前说到过bitcoin系统的短暂的分叉,在系统中一直存在,结合共识机制的变化,这时候区块链的分叉会出现一种硬分叉,硬分叉后,网络中区块链节点不会重新收敛到一个单独的链,分叉出来的两个子链接会各自发展,在bitcoin网络中一部分的节点不按照网络中其他节点的一致性新规则运行,这时候就产生了硬分叉。 
硬分叉具体说明:官方定义:A permanent divergence in the the block chain, commonly occurs whennon-upgraded nodes can’t validate blocks created byupgraded nodes that follow newer consensus rules.(区块链发生永久性分歧,在新共识规则发布后,部分没有升级的节点无法验证已经升级的节点生产的区块,通常硬分叉就会发生。)简单理解,网络中节点可能故意、可能是错误故障导致共识机制规则发生了一些变化,硬分叉需要系统中所有参与者之间进行协商,没有升级到新的共识机制下的参与节点都不能参与共识机制,硬分叉那一个区块高度,会强制分叉到另一个单独的链上。硬分叉引起的变化认为是不向前兼容,没有升级的节点无法处理升级后的共识机制,区块链出现了两个分叉,在另外一条分叉的链上重新收敛,达成另一种先前共识的链。举例:新的共识机制一般是出现了新的客户端版本,一部分矿工运行新的共识机制生成区块,区块中使用新的数字签名包含的交易,那么未升级客户端版本的会认为新的数字签名的交易无效,在区块中不接受这类型的交易,如果有一定数量的矿工未升级客户端那么他们不接受升级客户端后的交易,故产生单独两条链。备注说明:硬分叉是软件引起的一种分叉,但是软件的升级本身不产生分叉,升级默认认为是所有节点都升级,使用新的共识机制,分叉的引起是矿工的竞争,矿工之间对共识的认同与否产生新的一条链。一般硬分叉四个阶段:软分叉、网络分叉、挖矿分叉、区块链分叉。

  • 分叉难度:分叉后,区块链中产生两条不同的链,那么两条链上的hash算力也产生了分裂,挖矿能力也随之分裂。挖矿能力的分裂在各自接受链上的难度,认可的矿工比例开确定两个链上各自的挖矿能力。少数挖矿能力的链,因为算力的减少,生成区块难度加大,整个交易生成确认速度也会大幅减少。

软分叉:官方定义:A temporary fork in the block chain which commonly occurs whenminers using non-upgraded nodes violate a new consensus rule their nodes don’t know about.(当新共识规则发布后,没有升级的节点会因为不知道新共识规则下,而生产不合法的区块,就会产生临时性分叉。)当然不是所有的共识机制都会导致硬分叉,那么只有前向不兼容的共识规则才会导致分叉,结合硬分叉和乱分叉,和我们传统软件的向下版本兼容有个不同的理解。共识机制的改变能按照先前的共识机制来处理交易和生成区块,那么理解为在不进行分叉的情况下实现共识机制的修改,这个称为软分叉,事实上有人理解为软分叉不是真正意义上的分叉,软分叉允许老版本的软件和新版本的规则共同工作。软分叉增加共识机制的约束,不是共识机制的扩展,故向前兼容,新的规则下的交易老的规则下同样有效,故软分叉不要求所有节点强制升级。


  • 共识机制开发:区块链作为一个去中心化的系统,共识机制是一个去中心的制度,共识机制的开发没有完美的方案,对于上述的软硬分叉都需要权衡。

  • bitcoin的安全:互联网上的系统,稳定运行、安全性保障,一直以来都是最为关注的两方面。只有保障系统的安全性,才能使得用户对应用系统有足够的信心。Bitcoin是互联网上去中心化系统,和传统的中心化系统对比,在单点故障和单点数据中心出现灾难或者恶意攻击情况下,理论上做到了数据的冗余和应用系统业务连续性的保障。这一点对于安全来说有着重要的意义。
  • 去中心系统的安全:传统的中心化系统,在中心化数据中心,需要依赖大量的访问控制设备,防火墙设备等一系列安全设备保障系统的安全性,同时系统内部还需要健全的管理和审计措施来对一些恶意行为进行监控和处理,从而保证系统对用户的访问有良好的安全性保障。对比bitcoin,去中心化系统将系统维护责任和控制权放手给用户,bitcoin使用基于工作量证明来保证区块生成和数据的写入,整个系统对网络完全开放。整个系统类似生物学中的活性系统,每个节点自治,但整体又存在制约保障。
  • 交易安全性:传统支付系统,终端获得加密标签后开放,传输过程端对端加密,保证中间传输过程中不被截取转移,但是一旦终端加密标签被破解,恶意操作者即获得终端控制权,转移资金,在获得终端控制权后,相应的个人信息也被获取,那么针对该终端将获得更大的操作空间。Bitcoin中交易支付授权到指定用户,指定数额,通过数学加密算法保证,不可修改和伪造,同时不透露用户的身份,也无法获取权限外的操作,故理论上bitcoin的支付在网络中广播无需加密和防窃听保护,这一层对于安全性上来说不需过多考虑。
  • 密钥的安全性:当然bitcoin中最为关键重要的是每个用户节点的私钥,由于身份信息的隐秘性,故用户手上的私钥尤为重要,一旦对于私钥的保管出现问题,那么就以为账户资金出现了风险,甚至再也找不回来账户中的资金。去中心化系统把系统权力最大程度的赋予到个人用户手中。
  • Bitcoin开发安全:bitcoin去中心化的原则,是其根本,对于大多数的开发者来说,只要有分布式系统经验,对于去中心化的模型都会比较熟悉,这是一个两面性的问题,一方面有利于开发者介入,另一外面也对于系统安全性上是一个考验,大多数人熟悉也就造成了恶意攻击的可能性。Bitcoin的安全上面提及,密钥的安全是其根本,那么bitcoin就依赖密钥的分散性的控制,矿工需要独立去验证交易,那么矿工就必须确保自己在bitcoin的安全模型里面,就是密钥要有效控制,不接受区块链外的非正常交易。之前bitcoin会把资金密钥在一个“热钱包”里,在线进行交易验证,那么这就会导致容易被黑客攻击。为此现在一般都采用“冷钱包”即线下钱包。另一方面,区块链接收离线交易,离线交易即系统将交易数据记录在一个内部中心化账本上,偶尔同步到区块中,这样的好处是为了加快交易速度降低交易费用,但是这种内部中心化账本也就产生了中心化的概念,和去中心模型不一致,离线交易的中心化账本会出现伪造、恶意更改的情况。所以在开发过程中需要权衡中心化优劣结合bitcoin去中心化的本质,实现一个权衡。
  • 信任根:传统的安全基于一个信任根的概念,简单理解为一个总体的系统的安全核心,外围围绕这个信任根来进行开发,层层依赖,但是随着软件系统的发展,层层依赖越来越复杂,维护安全也变得更加繁琐。Bitcoin的安全系统是通过共识机制创建一个可信任的去中心化的公开账本,每一个区块都使用创世区块作为信任根,区块链接起来形成可信任区块链,所以整个区块链就是一个信任根。
  • 硬件钱包:之前提到热钱包、冷钱包,现在越来越多采用硬件防篡改钱包,硬件钱包采用有限的硬件接口,提供更高等级的安全策略来存储资金私钥。
  • 多重签名:顾名思义通过多重签名bitcoin地址需要多重签名才能支付,从而保证资金安全。

你可能感兴趣的:(区块链)