mynotes/Bitcoin笔记/比特币总结最终版.html
2019-10-17 11:40:32 +08:00

19 lines
9.2 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<title>Evernote Export</title>
<basefont face="微软雅黑" size="2" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="exporter-version" content="YXBJ Windows/600388 (zh-CN, DDL); Windows/6.1.1 (Win64);"/>
<style>
body, td {
font-family: ;
font-size: 10pt;
}
</style>
</head>
<body>
<a name="975"/>
<div>
<span><div>当创建一笔交易时,首先定义交易结构,交易结构中包含三个字段:    01 id    02 input,    03 output;</div><div><br/></div><div>       id: id通过交易本身做哈希获得,保证唯一性,矿工校验时需要通过id唯一定义一笔交易,</div><div><br/></div><div>        iput: 包含该笔交易所以用的前交易的    id(因为每一笔交易的输入都是之前交易的输出),    因为一笔交易中包含多个输入输出,所以需要    output索引    来唯一的定位一笔输出,    解锁脚本,    解锁脚本中包含两部分,第一</div><div><br/></div><div>部分为 私钥签名(注意不是私钥,私钥不能再网络中传播),    公钥哈希,    私钥签名需要对三个部分签,交易输入所引用的前交易的output的中锁定脚本的公钥哈希,,新生成的output锁定脚本的公钥哈希,新生成的output的value,所以需要将本次交易整体拷贝一份,并且将input中解锁脚本的公钥清空,找到input所引用的output中锁定脚本的公钥哈希,将其数据填充到清空的位置,对这个交易本身的哈希进行签名,因为交易的id就是通过交易本身做哈希得出来的,所以气门只需要对交易的id进行签名,并且将签名得到的数据放入到原始交易的签名字段中,有几笔交易输入,急需要签几次名</div><div><br/></div><div>        output:     output中包含    转账金额,    锁定脚本,    锁定脚本采用收款人的公钥哈希进行锁定</div><div><br/></div><div>那么我怎样才能知道我所拥有的前是否够转账:比特币会通过地址来遍历区账本,账本通过key/value的形式存储在levelDB数据库的桶中,那么问题来了,如果是创世块,直接打开数据库,通过桶名找桶,发现没有就创建桶,然后将创</div><div><br/></div><div>世块直接塞进去,如果是其他区块呢?我并不知道我的前区块哈希,所以就需要维护另外一个字段,也就是key值固定为lastHashKey,value值是最后一个区块的字节流,每次添加区块都知道了前区块哈希,由此将块连接成链,通过本地的计算得出的哈希值作为key,以确保key值唯一,保证数据不被覆盖,区块的字节流作为value,(注意,区块本身的哈希值在同步账本时是没有的,区块头中也并没有某一个字段用来存储区块本身的哈希值,是我们通过本地运算得出来的,这样做可以减少不必要的字段,减小区块大小,加快网络同步的效率,并且本地运算的过程也是对账本校验的过程,)没添加一个区块不仅要将区块数据写入数据库,还要更新最后一个区块的哈希,让后来的块能够知道自己的前区块哈希,通过定义一个反向迭代器来便利账本,跟遍历切片不同,他是由后向前遍历的,首先直接找lastHashKey,拿到最后一个区块的字节流,采用gob包中的decoder.decode将字节流转化为区块数据,将此区块的区块头中的前区块哈希值赋值给迭代器指针,实现指针的前移,那么移动到什么时候才是遍历完成呢?前区块哈希值长度为零时说明遍历了所有区块,我拿到区块之后需要通过地址遍历区块,想要通过地址遍历所有的output,需要明白地址的生成过程,地址是通过公钥做sha256运算,键运算结果做RIPEMD160运算得到20字节数据,将而是字节数据与版本号拼接成21字节数据,将21字节数据拷贝出一份,连续做两次 sha256运算,并取出前四个字节与原本的21字节拼接成25字节数据,将25字节数据做base58编码得到地址,加入版本号的目的是为了区分主网和测试网络,21字节数据做两次哈希并取出前四个字节是为了生成checksum校验码,检验地址有效性,base58是为了将1和l,0和o等易混淆数据干掉,增加地址可读性,我知道了地址,将地址做一个base58解码并且将第一个和第四个字节砍掉,那么就得到了公钥的哈希,注意找到的是公钥的哈希,不是公钥,将此公钥哈希与output中锁定脚本的公钥哈希做比较,如果相同,证明这笔钱曾经属于过我,但是也有可能被我消耗掉了,所以在遍历所有改地址对应的output前,应通过地址遍历所有的input,将已经消耗掉的output过滤掉,拿到intput中的解锁脚本的公钥,做两次哈希运算(第一次sha256,第二次RIPEMD160),就可以找到已经消耗过的output,剩余的未消耗输出也叫UTXO,比特币会用这种方法找到全网所有的UTXO,并且放入到UTXO池中,也就是比特币核心中的chainstate文件,并且当比特币核心启动时,该文件会被载入内存,这样我们就省去了遍历账本的过程,当UTXO总额大于转账金额时就会将该笔交易广播到网络中,广域网想要达成1像局域网一样的环境,需要使用NAT路由穿透技术来将广域网达朝成类十余局域网的环境,并且全网广播并不是采用for循环依次广播,而是采用DAG算法取异或找到最近的节点广播,然后被广播到的节点再次采用取异或的方式广播...呈现出爆炸式的向外扩张,</div><div><br/></div><div>1.矿工在拿到交易时首先对交易进行校验,首先通过input中的id唯一定位一笔交易,通过output索引唯一定位一个交易输出,将input中解锁脚本的公钥连续做两次哈希运算得到公钥哈希,并且与output中锁定脚本中的公钥哈希作比对,如果相同,则证明该笔前确实属于李四,下面需要证明李四是李四,不是张三冒充的,所以需要将input中的公钥验证input解锁脚本中的签名,无论是否验证通过都会将交易广播,转发到全网,</div><div>2.如果通过则会放入到本地的内存中,时刻监听网络中新区块是否被广播,如果广播了,将该节点已经打包的区块放回到本地内存中,并且将新区块中已有的数据从本地删除,这样做的目的是保证本地内存中的所有交易都是未被确认过的</div><div><br/></div><div>3.按照交易的权重由高到低依次打包到区块中,交易时间越早,交易的UTXO越大,交易的费用越多,则权重越大,由于区块本身大小受限,所以在网络拥堵的情况下,权重低的交易永远不会被打包</div><div><br/></div><div>4.填充区块头数据,nonce值设置为零</div><div><br/></div><div>5.将交易的区块头做sha256哈希碰撞,并不是要碰撞出一个一模一样的哈希值,而是要碰撞出一个比难度值小的数据,比特币中会统计前2016个区块,来动态调整难度值,因为随着全网算力的增加,出块时间会越来越短,虽然货币总量不变,但是短期内货币超发会造成雷似的通货膨胀现象,比特币的难度值通过调整前导零的个数来动态调整,难度值被定义为big.Int类型,big.Int类型采用big.NewInt(1),初始化时会得到一个大数,前边63个零,后边一个1,若是要想将1由最右移动到最左,则需要调用Lsh(bigIntTmp,256)函数移动256位,假设难度值的前导零个数为4,则需要将向左移动256位的基础上调用Rsh函数向左移动16位,那么就可以得出比特币难度值的计算公式为:假设前导零个数为n,那么难度值公式将变为bigIntTmp.Lsh(bigIntTmp, 256-4n),以此生成难度值</div><div><br/></div><div>6.如果挖矿成功,将区块数据写入到levelDB数据库中,以区块本身哈希值作为key,字节流作为value,并更新lastHashKey,同时向相邻节点继续采用DAG算法向外扩散,其余节点验证通过后,将该区块加入到本地数据库,主链长度加1</div><div><br/></div><div>以上便是通过转账入手,介绍了比特币交接结构,签名,交易验证,难度值生成,地址生成,获取余额的一系列过程</div><div><br/></div><div><br/></div><div>难度值生成:目标值越小,难度值越大</div><div><span>    </span><span>    1.比特币通过难度值简介调整目标值</span><br/></div><div><span><span>    </span><span>    2.比特币2016个区块理论出块时长为 2016*10  ,实际出块时间假设变成了9分钟,那么实际上2016个区块的出块时间就变成了2016*9  (2016*10)/(2016*9)=1.11就可以体现出难度值值的变化,系数如果大于1,那么意味着难度值要提高,如果小于一,那么难度值要降低</span><br/></span></div><div><span>新的难度值为 difficulty*1.11 =new difficulty</span></div><div><span>target =targetMax/difficulty,最大目标值是在目标值为1的情况下,意味着前导零个数最多,它是固定不变的,分子不变,分母变大了,那么结果是不是就变小了,目标值变小,那么挖矿时间就变长了,由9分钟,调整到了10分钟</span></div><div><span>需要注意的是,比特币中难度值调整系数边界为4+-1次幂,也就是说在0.25-4之间,不能调的太猛</span></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></span>
</div></body></html>