比特币入门

2018-09-04  本文已影响186人  neo已经被使用

这篇笔记主要讨论一下一些话题

1.什么是比特币?

比特币的概念可以从多个方面来说明:
1.比特币是一个点对点的电子现金系统,它能够传输电子货币(可以把它比喻成一个只能追加的分布式账本(区块链)
2.这个系统使用的电子货币也叫比特币
3.比特币也可以说是一种协议,这个协议包含许多内置的算法,比如动态调节挖矿难度(平均十分钟出一个区块(Block))、总量固定约2100w个、每四年挖矿奖励的比特币数量减半(09年开始初始50个)等

概述:比特币作为电子货币,是矿工通过工作量证明POW找到合适的"解"后作为奖励产生的,我们称之为挖到了比特币,此时(12.5+交易费)个比特币会直接发送给该矿工填写的地址,地址是公钥生成的,公钥是私钥生成的,所以拥有私钥代表着你拥有这些比特币。所以私钥是非常重要并且隐私的,但是如何在不展示该私钥的情况下证明你拥有该私钥呢?(零知识证明)这是通过数字签名实现的,提供了该私钥生成的数字签名,别人就能认可你拥有该私钥,就可以进行交易。交易在比特币网络中传播和验证,并被矿工收集到候选区块中,当矿工挖到比特币后,就会把该候选区块指向上一个区块,从创世区块到如今已经有54多w个区块了,这样形成的一个链式结构称之为区块链。区块链经常被视为一个垂直的栈,区块不断的堆叠,这样利用"高度"来识别一个区块,同一个高度有可能会有不同的区块,这样的现象我们称之为分叉。一个交易所在的区块在被堆到栈顶的时候,称为该交易一次确认,每在往其上堆一个区块的时候,也称为一次确认,一般来说经过6次确认之后,就会确保这笔交易不会被二次消费。

2.Bitcoin Core编译
git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin
./autogen.sh
make
sudo make install

检测是否安装成功命令bitcoind -version,正确输出版本号则安装正常
启动比特币节点命令:bitcoind ,节点运行后就会自动下载本地没有的区块数据,和网络保持同步,至今为止大概有220多G。第一次运行可能会需要提示你设置rpcpassword 在~/.bitcoin/bitcoin.conf 中,我的配置如下

rpcuser=bitcoinrpc
rpcpassword=2XA4DuKNCbtZXsBQRRNDEwEY2nM6M4H9Tx5dFjoAVVbk    
txindex=1//构建完整的交易索引

bitcoind --help 可以查看所有的可配置项如

 alertnotify//运行指定的命令或脚本,通常通过电子邮件将紧急警报发送给该节点的所有者
 datadir//选择要放入所有块链数据的目录和文件系统
 maxmempool//将交易内存池限制在几兆字节。 使用它来减少节点的内存使用
 maxconnections//设置接受连接的最大节点数

bitcoin-cli help 查看比特币JSON-RPC命令(返回json数据格式)
常见的命令有:

 bitcoin-cli getblockhash //参数为整数代表区块高度  eg bitcoin-cli getblockhash 100,获取第100个区块的hash值
 bitcoin-cli getblock //参数为区块hash值,获取区块数据
 bitcoin-cli getrawtransaction//参数为 txid 获取交易数据返回格式是编码后的
 bitcoin-cli decoderawtransaction //解码
 bitcoin-cli -getinfo//获取比特币网络节点、钱包、区块链数据库状态的基础信息

使用其他方式调用比特币JSON-RPC
http:

curl --user bitcoinrpc:2XA4DuKNCbtZXsBQRRNDEwEY2nM6M4H9Tx5dFjoAVVbk //用户名:密码  在配置文件中配置
--data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblockhash", "params": [100] }' 
-H 'content-type: text/plain;' http://127.0.0.1:8332/

python:

    from bitcoin.rpc import RawProxy
    # Create a connection to local Bitcoin Core node
    p = RawProxy()
    # Run the getblockchaininfo command, store the resulting data in info
    info = p.getblockchaininfo()
    # Retrieve the 'blocks' element from the info
    print(info['blocks'])

第三方工具调用:python-bitcoinlibbitcoinj

2.密钥和地址

私钥可⽤于交易时数字签名,公钥生成的地址⽤于接收⽐特币,公钥能验证私钥签名的内容

signature = sign(sk, msg) //sk: secret key
isValid = verify(pk, msg, signature) // pk: public key

下图表示公钥、私钥、地址之间的关系:


公钥、私钥、地址之间的关系.png

1.私钥
私钥(256位)可以是1和n-1之间的任何数字,其中n是一个常数(n=1.158 * 10^77 略小于2^256)生成规则:一般是由一大串随机数字,经过SHA256哈希算法生成长度为256位的数字,如果这个数字小于n,则可以作为合适的私钥,否则更换随机数重复一次直到满足条件
可以使用Bitcoin Core 生成私钥bitcoin-cli getnewaddress,这个命令只会显示公钥,可使用bitcoin-cli dumpprivkey显示私钥

  $ bitcoin-cli getnewaddress 
    1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy 
  $ bitcoin-cli dumpprivkey 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy 
    KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ

2.公钥
通过椭圆曲线乘法(比特币使用secp256k1标准)可以从私钥计算得到公钥,这是不可逆转的过程:K = k * G (k是私钥、 G 被称为⽣成点、*是椭圆曲线乘法)
公钥是椭圆曲线上的

椭圆曲线.png

椭圆曲线乘法过程:
在椭圆曲线上面有一个常数点G叫做生成点


生成点.png

整数数字2*G的过程如下


2*G.png
以私钥的十进制形式 * G
private_key = ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2//16进制
private_key = 108165236279178312660610114131826512483935470542850824183737259708197206310322//十进制

public_key  = 108165236279178312660610114131826512483935470542850824183737259708197206310322 * G

最终得出的在椭圆曲线上的一个点就是公钥,eg:

public_key (x) = b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737
public_key (y) = 8ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4

public_key (x,y) = b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4
前面加上04(代表非压缩格式,后面有详细介绍):
  04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4

3.地址
比特币地址是由公钥两次Hash生成的

   address = RIPEMD160(SHA256(K))//生成的是160位的地址,经过Base58Check编码后得到最终的地址

4.Base58Check编码
Base64使用了26个小写字母、26个大写字母、10个数字以及两个符号(“+”和“/”),通常用于编码邮件中的附件。
Base58是Base64编码格式的子集(不包括(0,O,l,I))
Base58Check增加了检验和,校验和是从编码的数据的哈希值中得到,并且添加到后面额外4个字节。解码时会计算数据的校验和并和编码中自带的校验和进行对比。二者不匹配则表明有错误产生,那么这个Base58Check的数据就是无效的
Base58Check转换过程:

1.先给数据添加一个version前缀(比特币地址的version前缀是0(十六进制是0x00))
2.计算校验和checksum = SHA256(SHA256(prefix+data))(生成32个字节数据)
3.取校验和前4个字节 作为数据的后缀
Base58Check编码过程.png

Base58Check版本前缀和编码后的结果:


Base58Check版本前缀和编码后.png

Pay-to-Script-Hash : 合成地址,三对公私钥,可以生成一个合成地址。在生成过程时指定n of 3中的n,n范围是[1, 3],若n=1,则仅需一个私钥签名即可花费该地址的币,若n=3,则需要三把私钥依次签名才可以
5.密钥的格式
私钥的格式有 Hex十六进制、WIF(Wallet Import Format)、WIF-compressed(在16进制数据后添加0x01,表示推导出的公钥需要压缩)


私钥格式.png 私钥格式举例.png
通过libbitcoin-explorer中的wif-to-ec(Elliptic Curve椭圆曲线)命令,来显示两个WIF键代表相同的私钥
  $ bx wif-to-ec 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
    1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
  $ bx wif-to-ec KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
    1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd

使用base58check-decode命令解码未压缩的密钥(WIF):

    $ bx base58check-decode 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
    wrapper
    {
    checksum 4286807748 //校验和
    payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd //原始私钥数据
    version 128 //版本前缀
    }

解码压缩的密钥(WIF-compressed):原始数据带有01后缀,表示该私钥生成的公钥需要压缩

  $ bx base58check-decode KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
    wrapper {
    checksum 2339607926
    payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01
    version 128
    }

把原始私钥转换成WIF

  bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd --version 128
  5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn

把原始私钥转换成WIF-compressed

  $ bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01 --version 128
  KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ

公钥的格式:
公钥由前缀+x+y构成,格式有压缩格式的公钥(前缀是02或03)和非压缩格式的公钥(前缀是04)x、y都是256位,是在椭圆曲线上(y2 mod p = (x3 + 7) mod p,p是很大的素数)的一个点

压缩格式公钥前缀是02或03,因为公式左边是y2,所以对于同一x,y有可能为正数或者负数,y坐标可能是奇数(03前缀)或者偶数(02前缀),分别对应于正负号,这样就可以根据公钥中给定的x值,正确推导出对应的y坐标,所以只需要存储x,减少了32个字节的大小。此时公钥的大小是264位(33个字节、66个十六进制数字),在将公钥双Hash生成地址后,由于公钥格式的不同,所以同一个私钥可能产生两个不同的比特币地址

总结:如果一个比特币钱包实现了压缩格式公钥,那么它将会在所有交易中使用该压格式缩公钥。钱包中的私钥将会被用来在曲线上生成公钥点,这个公钥点将会被压缩。压缩格式公钥然后被用来生成交易中使用的比特币地址。当从一个实现了压缩格式公钥的新的比特币钱包导出私钥时,钱包导入格式(WIF)将会被修改为WIF压缩格式,该格式将会在私钥的后面附加一个字节大小的后缀01。最 终的Base58Check编码格式的私钥被称作WIF(“压缩”)私钥,以字母“K”或“L”开头。而以“5”开头的是从较老的钱包中 以WIF(非压缩)格式导出的私钥


利用libbitcoin python库生成密钥地址.png
3.交易Transaction

Transaction是构成比特币的最基本的数据结构,交易d交易输出。UTXO(Unspent Transaction Outputs),未消费的输出(比特币),也就是可以消费的比特币,比特币全节点会跟踪所有的UTXO集合。
比特币钱包的余额是指钱包检测到该地址可用的UTXO的总和,它们可能分散在很多个交易和区块中。1BTC=100000000satoshi(1亿聪),一个UTXO可以是1聪的任意倍数(整数倍),一旦被创建出来是不可被分割的(整体被消耗)。
例如,你有 一个价值20BTC的 UTXO并且想支付1BTC,那么你的交易必须消耗掉整个20BTC的UTXO,并产生两个输出:一个支付了1BTC给接收人,另一个支付了19BTC的找零到你的钱包
Transaction结构
Alice给Bob转了0.015BTC,交易id为0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2
通过bitcoin-cli getrawtransaction,decoderawtransaction得到的最终的Transaction的样子如下

    {
        "txid": "0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2",//交易id,一般和Transaction hash一致
        "version": 1,//版本号
        "size": 258,//交易字节大小
        "locktime": 0,//一般为0,代表立即发送,< 500000000 含义为Block高度,处于该Block之前为锁定; >= 500000000  含义为Unix,处于该时刻之前为锁定 
        "vin": [{
            //指向正在被消费的UTXO所在的交易
            "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            "vout": 0,//UTXO索引
            "scriptSig": {//unlock scrip 解锁脚本,用于解锁UTXO,第一段是数字签名(DER编码 、[ALL]代表签名类型,表示对所有输入输出都签名)、第二段是公钥(04开头代表未压缩)
                        //解锁脚本由Alice的钱包通过检索引用的UTXO及其锁定脚本构建
                "asm": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 
                        0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
            },
        }],
        "vout": [{ //UTXO
                "value": 0.01500000,//输出的数量
                "n": 0,//UTXO索引
                "scriptPubKey": {//Locking Scrip 锁定脚本,需要解锁才能使用
                    //下面中间一段是Bob的地址(未经过Base58Check编码)                    
                    "asm": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG",
                }
            },
            {//找零
                "value": 0.08450000,
                "n": 1,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
                }
            }
        ]
    }

从该交易是看不到输入数量是多少,需要查找输入指向的UTXO所在的交易,从而计算手续费(输出总和-输入总和),验证节点也会验证是否有足够的UTXO
我们再次通过bitcoin-cli getrawtransaction,decoderawtransaction得到该输入指向的UTXO所在的交易,如下

    "vout": [//7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18的UTXO
        {
          "value": 0.10000000,
          "n": 0,
          "scriptPubKey": {
            "asm": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
          }
        }
      ]

锁定脚本如何解锁?(验证过程)
比特币使用内置的脚本语言,该脚本语言是基于栈的,要验证输入是有效的会把把解锁脚本和锁定脚本组合起来并执行,如果返回True则有效,否则无效


组合.png

比特币脚本语言执行过程:每读到一个数据就把数据入栈、每读到一个内置命令就把栈顶数据作为命令的输入去执行,执行结果再次入栈。大概过程如下:


脚本执行过程.png 脚本执行过程.png

创币交易是没有解锁脚本的,有一个coinbase字段,该字段的值由挖出此Block的人填写,如下是创世区块的创币交易,由中本聪写入coinbase字段,将该段16进制转换为ASCII码,就是那段著名的创世块留言:The Times 03/Jan/2009 Chancellor on brink of second bailout for banks:

    {
        "txid" : "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
        "version" : 1,
        "locktime" : 0,
        "vin" : [
            {
                "coinbase" : "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73",
                "sequence" : 4294967295
            }
        ],
        "vout" : [
            {
                "value" : 50.00000000,
                "n" : 0,
                "scriptPubKey" : {
                    "asm" : "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG",
                    "hex" : "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac",
                    "reqSigs" : 1,
                    "type" : "pubkey",
                    "addresses" : [
                        "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
                    ]
                }
            }
        ]
    }
4.数字签名

数字签名可以在不展示私钥的情况下证明,该公钥是由该私钥生成的(零知识证明)
所以在解锁脚本中只提供数字签名就可以确认该输出的所有权
比特币中使用的数字签名算法是椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm)或ECDSA

(Sig = sig(hash(m), sk))//m是签名的内容,一般是交易(或其部分)、sk是私钥
Sig = (R, S)//签名会产生两个值

签名会产生两个值,使用DER分辨编码规则(Distinguished Encoding Rules)表示,例如上面Alice的交易的签名为

30450221//DER编码规则部分
00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb//R
0220//DER编码规则部分
4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813//S
01 //最后两位01代表签名类型ALL

签名由两个部分组成:随机数部分(R)、签名部分(S:私钥+要签名的内容 ))
R的生成和公钥生成过程一样,也是一个随机数M*G并取最终结果的x坐标
S的生成:(私钥 *R+交易的Hash值(要签名的内容))/M
在前面我们知道,解锁脚本里面包含的签名,是和锁定脚本中的公钥使用的是相同的私钥,才能解锁成功。如何验证?

1.找到椭圆曲线上第一个点:(S*要签名的内容)*G//第一个普通乘法、第二个椭圆曲线乘法
第一个点.png
2.找到椭圆曲线上第二个点:R*S*公钥//第一个普通乘法、第二个椭圆曲线乘法
第二个点.png
3.两个点相加:连接这两个点,找到穿过曲线的第三个点,比较这个点的x坐标是否和R一致,如果是则成功、否则失败
两个点相加结果.png

数字签名的三种类型:

  1. SIGHASH_ALL(0x01):对所有输入、输出签名,相当于认可且只认可的这些输入、输出,并同意花费我的那笔输入
    2.SIGHASH_NONE(0x02):仅对输入签名,不对输出签名,相当于不在乎输出地址,可以任意更改输出地址,我同意花费我的那笔钱,至于给谁,我不关心
  2. SIGHASH_SINGLE(0x03):仅对自己的输入、输出签名,其他输入输出不关心
5.比特币网络

比特币采用了P2P的网络架构,各个节点是平等的,是实现去中心化的基础。根据节点的功能,可以划分为以下几个类型:
1.标准客户端(Bitcoin Core):钱包、挖矿、完整区块链数据库、网络路由
2.全节点:完整区块链数据库、网络路由
3.个人矿工:挖矿、完整区块链数据库、网络路由
4.SPV钱包(Simple Payment Verification):钱包、网络路由,是指不包含完整区块链数据库,验证方式是SPV,只下载区块头,属于轻量级的节点。
5.挖矿节点:挖矿、Stratum服务或者 其他矿池挖矿协议

一个全节点要检查第300,000号区块中的某个交易,它会把从该区块开始一直回溯到创世区块的300,000个区块全部都链接起来,并建立一个完整的UTXO数据库,通过确认该UTXO是否还未被支付来证实交易的有效性。
SPV钱包节点使用Merkle路径验证:
SPV钱包节点想知道它是否收到比特币,该节点会在相连节点间通信链接建立一个过滤器,限制只接受含有钱包比特币地址的交易。当相连的节点检测到符合条件的交易,它会发送包含区块头和Merkle认证路径的消息。
SPV节点Merkle认证路径验证该交易是否存在区块中。通过区块头证明区块存在于区块链,等待6个区块后,就可以认定该交易不是双重支付。

6.区块链

每个区块指向前一个区块形成区块链,“高度”来表示区块与创世区块之间的个数。
区块的结构:区块头+一系列交易
通过命令bitcoin-cli getblockhash 、getblock获取区块的内容

bitcoin-cli getblockhash 100
000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a
bitcoin-cli getblock 000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a
{
  "hash": "000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a",//是对区块头经过2次SHA256
  "merkleroot": "2d05f0c9c3e1c226e63b5fac240137687544cf631cd616fd34fd188fc9020866",//Merkle 树根
  "version": 1,
  "tx": [//包含的交易、早期区块交易很少
    "2d05f0c9c3e1c226e63b5fac240137687544cf631cd616fd34fd188fc9020866"
  ],
  "time": 1231660825,
  "nonce": 1573057331,
  "difficulty": 1,//time、nonce、difficulty用于挖矿
  "previousblockhash": "00000000cd9b12643e6854cb25939b39cd7a1ad0af31a9bd8b2efe67854b1995",
  "nextblockhash": "00000000b69bd8e4dc60580117617a466d5c76ada85fb7b87e9baea01f9d9984"
}

区块头(80字节)包含父区块头哈希值、难度、时间戳和nonce、merkeroot树根等元数据(不包含交易)
区块的哈希值实际上并不包含在区块的数据结构里,都是计算出来的。也可以通过区块高度来区分区块,不过同一高度可能会有多个区块(分叉)

Merkle 树:
Merkle树是一种哈希二叉树,带有hash指针,保存的是hash值(通常是double-SHA256)


Merkle树.png

如何证明某一笔交易存在在树中?


证明存在性.png
通过提供认证路径HL、HIJ、HMNOP和HABCDEFGH,就能验证HK存在于树中,而且随着交易数量的变大,所需提供的认证路径长度以logn增长

SPV节点会收到少于1KB的有关区块头和Merkle路径的数据,其数据量比一个完整的区块(目前大约有1MB)少了一千多倍

7. 挖矿

通过算力的竞争(POW),最终的获胜者会得到"记账权",把已经打包好交易的区块,添加到区块链的最后一个,并且获得新生成的比特币作为奖励,这个过程称为挖矿。
挖矿使得比特币的发行没有任何中心化机构,是支撑比特币安全的去中心化的共识机制
比特币总共有20,999,999,980个,09年开始初始挖矿奖励是50个,每210,000个区块产量减半(平均十分钟出一个区块(与分叉概率有关),约4年减半),2140年会挖完,挖完后矿工的唯一收益就是手续费了,所以到时候手续费会越来越多。
每个节点在比特币网络中都会收集、验证并传递新的交易,在收集后会对交易进行独立验证,验证规则很多,例如检查语法、输入输出等等,当验证通过后,会把交易放到节点自己的内存池里面,等待打包确认,此时交易处于未确认的状态。如果这个节点是挖矿节点,那么节点会一直计算工作量证明的解,同时也会从内存池里面取出未确认的交易打包构造成一个区块,称为候选区块(还未经过有效工作量证明)。在经过足够的工作量证明后找到了解,然后把这个解写进区块头(nonce字段),此时会立刻将这个区块发给它的所有相邻节点,并立即开始计算区块链中下一个区块的工作。这些节点在接收并验证这个新区块后,进行验证,验证成功后也会继续传播此区块,如果收到这个新区块在本地没有发现该父区块Hash值,则称为这个区块为孤块,放在孤块池,当收到该父区块后,就会从孤块池中取出,连接上,这种情况可能会发生在两个区块在很短的时间间隔内被挖出来。
构造区块头:


区块头结构.png

1.Version:挖矿节点遵循的协议版本
2.Previous Block Hash:前一个区块头Hash,挖矿节点会接收到挖出的最新的区块(一般是最长的共识链)中的Hash作为此值(投票、一般会选择最长的共识链)
3.Merkle Root:需要将所有的交易构建成一个Merkle树,最终得到的树根
4.Timestamp:Unix时间戳,自1970年1月1日0点到当下总共的秒数
5.Target:工作量证明的难度目标值,这个值会根据整个网络算力动态调节(2016 个区块调整一次、约2周)
6.Nounce:工作量证明的解,初始为0
工作量证明:
找到一个使区块头哈希值小于难度目标的 nonce,重复计算区块头的哈希值,不断修改nounce值(一般+1),直到与哈希值小于Target值(Target越小、难度越大)。由于哈希算法的特性,得到哈希值的唯一方法是不断的尝试,这就是工作量证明。
Target:在区块277,316中,它的值为 0x1903a30c。前两位十六进制数字为幂(exponent),后面六位为系数(coefficient),公式如下:

target = coefficient * 2^(8 * (exponent – 3))
0x1903a30c最终表示的值为0x0000000000000003A30C00000000000000000000000000000000000000000000
难度调整:New Difficulty = Old Difficulty * (Actual Time of Last 2016 Blocks / 20160 minutes),调整的幅度不能过大,大于4倍,则按4倍调整

挖矿硬件发展:CPU->GPU->FGPA->ASIC
比特币网络算力(难度也会一样指数增长):(MH/s(百万)->GH/s(10亿)->TH/s(万亿)->PH/s(千万亿)-> EH/s(百亿亿))


比特币网络算力的指数增长.png

51%攻击:最多能影响不久的过去几个区块的共识(最多影响 过去10个块),并且影响整个区块链未来的共识,能让以后得到所有以后新挖的区块的奖励、能够双重支付自己的币(多次支付),不能偷走现有比特币(需要私钥)、不能双重支付老区块中的交易(需要签名)

其他
bitcoind -testnet 开启测试网(其他人也能加入,包含隔离见证)
bitcoind -regtest 开启本地区块链(只是在本地)
bitcoin-cli -regtest generate 500 生成500个区块
bitcoin-cli -regtest getbalance 查看比特币余额

coinbase字段值.png

参考文献:
1.精通比特币
2.区块链技术驱动金融
3.learn me a bitcoin

上一篇下一篇

猜你喜欢

热点阅读