比特币源码阅读(0.16)(二十二)
Pay-to-Script-Hash
BIP-16改进方案在2012年引入了首字符是“3”的P2SH(Pay-to-Script-Hash)地址。P2SH的灵活性来自于它巧妙的设计——交易的输出并不像P2PKH那样直接保存上锁脚本,而是记录20字节的脚本哈希,形式是这样的:1
HASH160 PUSHDATA(目标脚本哈希) EQUAL
光根据脚本哈希,外人无从推断出解锁的逻辑。等我们转账时才需要出示与该哈希对应的原始脚本,并且保证脚本的运行结果为真。
P2SH最常用于M-of-N多重签名,也就是在预定的N个公钥中,给出M个相应的签名就能通过验证(1 ≤ M ≤ N)。我们来看个2-of-3 multisig的具体例子。
先生成三组私钥和压缩形式的公钥。这个过程通常由三个人私下完成,各自保管自己的私钥:
私钥A:
L2iQ55QcE6otmfUZPLYU2Qf5SP41HhCtPEKu2v3r16vHZ19MT7Sn
公钥A:
020FA7BED1B89DF218A2ED2C94EBBF872A7BDA0F48D231EB8CB6F16B87D9BB5211
私钥B:
L37gNgdvmLJuLNre3EASs2ETkEvrUn8AShviJTD2TfNaqWiEgwRT
公钥B:
02D7E287092457F2BEA226CD7537C5EE99AF50CCA923795A2EA65CF249F783C5D1
私钥C:
Kwd8QPXS1LZAGmqJDvb5emRtEPJuVjzXX2FRUZrYERMTt5uz58Vr
公钥C:
02E8B48F3C0A7C452792FA96CDCF2FC6A23298F4D6512BD8AA9A25210B66A1D450
用这三个公钥就能组合成2-of-3上锁脚本:
2 PUSHDATA(公钥A) PUSHDATA(公钥B) PUSHDATA(公钥C) 3 CHECKMULTISIG
其中的2和3分别表示向堆栈压入数字2和3的操作。CHECKMULTISIG用于检查堆栈上的两个签名是否对应三个公钥中的两个。
以上脚本编译后的结果共计105字节,十六进制表示如下:
5221020fa7bed1b89df218a2ed2c94ebbf872a7bda0f48d231eb8cb6f16b87d9
bb52112102d7e287092457f2bea226cd7537c5ee99af50cca923795a2ea65cf2
49f783c5d12102e8b48f3c0a7c452792fa96cdcf2fc6a23298f4d6512bd8aa9a
25210b66a1d45053ae
对它先求SHA256,得到32字节的哈希:
6feec0468378f4a1f0c8dbccfd41f6041eaf0185d22d029d2dea4603ed8c94bf
再对以上结果做RIPEMD160,得到20字节的哈希:
c19ba54b40598eab41f636b4b5c3fe6493dddd64
这就是P2SH上锁脚本中PUSHDATA里的目标脚本哈希。加上固定前缀0x05后作Base58Check编码便得到了最终的、首字符是“3”的P2SH地址:
3KLio22Epg8nrXfzFBuoHWwxFPCkpFzYFo
转账时需要提供两个签名和原始脚本,解锁形式如下:1
0 PUSHDATA(签名D) PUSHDATA(签名E) PUSHDATA(脚本)
使用scrapy爬数据
这两周在尝试使用scrapy爬数据,总结一下遇到的几个坎:
xpath使用
1、xpath().extract()返回的结果是数组,如果需要取第一个,就用extract_first(),否则就用下标取extract()[0];
2、xpath(‘//‘)表示从根搜索,xpath(‘.//‘)从当前节点搜索;
3、浏览器中查看xpath时要禁止javascript,防止数据是被javascript修改过的。
多层爬数据
1、先在parse中获取到下一层的链接detail_url
2、yield Request(url=detail_url, callback=self.parse_detail)进入下一层,其中parse_detal是下一层处理函数
3、如果还需要传递Item到下一层,就用Request(url=detail_url, meta:{“item”: item}, callback=self.parse_detail),获取时用response.meta[“item”]。
反反爬
1、将COOKIES_ENABLED设置为False;
2、将AUTOTHROTTLE全部打开。
爬火星网资讯
1 | from scrapy.spider import CrawlSpider |
莱特币Scrypt算法
Scrypt是一种KDF算法,KDF是密钥导出功能的意思,主要适用于生成密钥,目的是为了避免黑客低成本地大量产生密钥去试探密码,而Scrypt的这个效果正好被用在莱特币nonce碰撞中,避免了矿厂矿池低成本挖矿。
Scrypt算法会产生一个p个块元素的数组,p的值大概比2^31(42亿)小几个数量级,实际使用中可能是十万~百万级别吧?对于每个块元素,都是进行一系列复杂运算生成的哈希值,最后对整个数组再进行PBKDF2-HMAC-SHA256运算得到最终结果。
Scrypt算法保证只有将每个元素都存放在内存中,最后才能算出正确的结果,从算法层面保证了对大量内存空间的硬需求,从而提高了运算成本。
比特币源码阅读(0.16)(二十一)
mining.cpp::generatetoaddress
挖nblocks个区块,并将挖矿收入存入address指定的地址中。可以用来CPU挖矿,不过目前比特币的计算量,已经不可能挖出来了。
参数:
- nblocks (numeric, required) How many blocks are generated immediately.
- address (string, required) The address to send the newly generated bitcoin to.
- maxtries (numeric, optional) How many iterations to try (default = 1000000).
结果:
区块的hash值
样例:
挖11个区块到myaddress中1
> bitcoin-cli generatetoaddress 11 "myaddress"
顺序图
比特币源码阅读(0.16)(二十)
CScript
比特币的交易验证引擎依赖于两类脚本来验证比特币交易:锁定脚本和解锁脚本。
锁定脚本是一个放置在输出上面的花费条件:它指定了今后花费这笔输出必须要满足的条件。 由于锁定脚本往往含有一个公钥或比特币地址(公钥哈希值),在历史上它曾被称为脚本公钥(scriptPubKey)。
解锁脚本是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,它将允许输出被消费。解锁脚本是每一笔比特币交易输入的一部分,而且往往含有一个由用户的比特币钱包(通过用户的私钥)生成的数字签名。由于解锁脚本常常包含一个数字签名,因此它曾被称作ScriptSig。
P2PKH脚本
比特币网络处理的大多数交易花费的都是由“付款至公钥哈希”(或P2PKH)脚本锁定的输出。
锁定脚本 scriptPubKey1
OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
解锁脚本 ScriptSig1
<Signature> <Public Key>
将解锁脚本和锁定脚本组成组合脚本:1
<Signature> <Public Key> OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
解锁步骤:1
2
3
4
5
6
7将<Signature>入栈
将<Public Key> 入栈
复制<Public Key>
对<Public Key>执行HASH160计算,使用计算结果<Public Key Hash Result>替换<Public Key>
将<Public Key Hash>入栈
比较<Public Key Hash Result>和<Public Key Hash>是否相同,相同继续下一步,不相同则失败
用<Public Key>对<Signature>进行验证,通过则允许付款
类图
比特币源码阅读(0.16)(十九)
net_processing.cpp::ProcessMessage
一、发送version消息,对端也会发version消息,双方将自己的版本信息告诉对方。
如果对端支持(兼容)相关版本的话,会回复verack消息。verack只是空消息。
二、发送getaddr消息,以向对端询问有哪些活跃的网络节点。对端会将其认为是活跃的节点的信息发送给钱包,通常3小时内有消息收发的节点算作活跃的。
三、发送sendheaders消息,表示自己支持最新的headers命令,后续对端可以通过headers消息宣告新区块。
四、发送两次sendcmpct消息,告知对端自己支持接收哪些后续消息,如cmpctblock或invs或headers。
五、定期发送ping消息,用来检测对端TCP连接是否OK,并期待对端响应pong消息。
六、发送getheaders消息,该消息指示只下载区块的header,不需要下载交易内容。有很多交易与我们无关,所以我们只需要下载自己关心的交易,对于绝大多数不关心的交易所在的区块,只需要下载区块header即可。
七、发送feefilter消息,用于设置费率,避免无效消息的重放攻击。费率单位是每1000字节多少聪,聪是比特币最小单位即一亿分之一比特币。