19 lines
9.2 KiB
HTML
19 lines
9.2 KiB
HTML
<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> |