下载

0下载券

加入VIP
  • 专属下载券
  • 上传内容扩展
  • 资料优先审核
  • 免费资料无限下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 比特币挖矿源代码分析

比特币挖矿源代码分析.doc

比特币挖矿源代码分析

勇敢的小清新张张
2017-09-02 0人阅读 举报 0 0 0 暂无简介

简介:本文档为《比特币挖矿源代码分析doc》,可适用于初中教育领域

比特币挖矿源代码分析!比特币挖矿!挖矿命令!!块结构!!创建块!!奖励比特币!!SHA算法加密!!检验块!工作量证明!计算算力!比特币网络!!!!!页码:!!挖矿命令!!比特币客户端内嵌了挖矿模块可以使用相关的命令开始挖矿、获取挖矿参数。!!有个方式可以挖矿。!!、gen!!在配置文件(默认文件名bitcoinconf)中添加此项为时开始挖矿为时停止挖矿。!!客户端程序启动过程中初始化(AppInit)时获取此命令参数进行挖矿。!!、setgenerate命令!!命令格式是:setgenerategenerate(genproclimit)。!!generate为true时开始挖矿false时停止挖矿这个参数是必须有的。!!genproclimit表示挖矿CPU个数这个参数是可选的默认是无限制所有的CPU都运行挖矿。为时停止挖矿。!!此命令最终会修改参数映射数组mapArgs中”gen”项从而决定后续是否进行挖矿。!!如果是regtest模式此参数表示需要挖出的块个数直到挖出指定的块数量时退出。!!!!获取挖矿命令是:getgenerate。!!返回boolean值true表示正在挖矿false表示停止挖矿默认是false。!!生产比特币!!!!生产比特币是在GenerateBitcoins函数。!!在GenerateBitcoins函数中创建、停止挖矿线程挖矿线程主函数是BitcoinMiner。!!创建指定数量的线程但如果指定的线程数量为则停止挖矿。如果指定的线程数量小于则如果是测试网络则只创建个线程否则创建的线程个数为CPU个数。!!挖矿线程保存在线程组中(boost::threadgroup类型)。!!如果正在挖矿即挖矿线程正在运行则停止挖矿即中断所有的挖矿线程重新创建挖矿线程。!!!挖矿时创建线程数组创建所有的挖矿线程每个线程绑定挖矿BitcoinMiner函数绑定钱包。!!页码:!线程重命名为”bitcoinminer”。!!每个线程先创建一个基于钱包的KEY(CReserveKey类型)然后开始循环挖矿。!!如果是回归测试模式则立刻开始挖矿否则每隔秒检验一次网络直到网络节点连接上才进行挖矿如果网络节点没有连接则只能浪费时间挖过期的块。!!基于KEY创建新的块(CreateNewBlockWithKey)保存在块模版中增加线程自己的计数(IncrementExtraNonce)。!!从堆栈中申请块空间作为哈希缓冲区字节对齐然后格式化哈希缓存区(FormatHashBuffers)。!!遍历缓冲区用SHA算法加密缓存区(ScanHashCryptoPP)如果找到一些块则检验块是否有效(CheckWork)检验之时线程的优先级必须为THREADPRIORITYNORMAL。统计算力。更新块的时间。!!如果是回归测试生成个块后就停止挖矿。!!如果挖矿过程中网络连接失败则停止挖矿。!!如果是测试网络修改块的时间来修改需要的POW。!!挖矿过程中会打印日志。!!!页码:块结构!!!!每个节点都会收集新的交易信息添加到块中并且把交易信息保存到块的哈希树中通过nonce值扫描块使块的哈希值满足POW的要求。然后把块广播给每个节点添加到块链中。块的第一个交易信息是创建了块的创建者拥有的新币的交易信息。!!!块结构主要涉及到CBlockHeader、CBlock、CBlockTemplate。!!类CBlockHeader类包含了块头的基本信息如:版本、时间戳等。!classCBlockHeader!{!public:!staticconstintCURRENTVERSION=!当前版本默认是!intnVersion!!!!!!版本!uinthashPrevBlock!!!!上一个块哈希值!uinthashMerkleRoot!!!Merkle哈希树根节点!unsignedintnTime!!!!创建块时的时间!!!unsignedintnBits!!!!!下一个工作需要的POW!unsignedintnNonce!!!!Nonce值!}!!nVersion默认是。!!nNonce用于扫描块使块的hash满足POW的要求。!!!!!类CBlock继承了CBlockHeader类增加了交易信息相关的数据。!classCBlock:publicCBlockHeader!{!public:!networkanddisk!std::vectorCTransactionvtx!!!交易信息数组!!!memoryonly!mutablestd::vectoruintvMerkleTree!Merkle树!}!!vtx包含了交易信息用于网络传播、硬盘存储。!!vMerkleTree仅仅用于内存。!!!结构CBlockTemplate定义了块模版增加了交易费、签名。!structCBlockTemplate!{!CBlockblock!!!!块!页码:std::vectorinttvTxFees!std::vectorinttvTxSigOps!}!交易手续费!签名!!!创建块!!!!!!如果是挖矿创建新块则先需要从CReserveKey中获取公钥(CPubKey)然后计算出公钥脚本(CScript)再创建新块。!!创建新块的函数是CreateNewBlock函数。!!新建块模版CBlockTemplate实例。!!新建空的coinbase交易信息作为块模版的交易信息的末尾项。把新建的交易信息添加到新建的块中数组vTxFees、vTxSigOps添加值。如果指定了公钥脚本则保存到交易信息的voutscriptPubKey中。!!计算创建的块的最大值块最大值在与(MAXBLOCKSIZE())之间如果指定了参数”blockmaxsize”则块最大值设置为指定值否则设置为默认值DEFAULTBLOCKMAXSIZE()。!!计算创建的块的最小值块最小值在与块最大值之间如果指定了参数”blockminsize”则块最小值设置为指定值否则设置为默认值。!!计算块优先级值块优先级值决定了块中包含的高优先级交易信息的数量不管支付的交易费是多少。块优先级值的最大值为块最大值如果指定了参数”blockprioritysize”则设置为指定值否则设置为默认值DEFAULTBLOCKPRIORITYSIZE()。!!遍历内存池交易信息组建优先级数组不处理内存池中的CoinBase类型的交易信息、最后的交易信息。计算优先级、每千字节的手续费添加到优先级数组中。(COrphan)!!优先级计算公式:!Priority,sum(valuein*age)modiedtxsize!!每千字节的手续费计算公式:!dFeePerKb=double(nTotalIntxGetValueOut())(double(nTxSize))!!遍历优先级数组把交易信息添加到新建的块中。!!添加时注意以下几点:!!、不添加最高优先级的交易信息。!!、添加交易信息时块大小总和不能超过块的最大值块中的签名的总和不能超过最大值MAXBLOCKSIGOPS()。!页码:是指交易手续费用低于最小值(dFeePerKbCTransaction::nMinTxFee)。!!、只添加在UTXO集中的交易信息(viewHaveInputs)。!!、不添加交易信息的接收信息无效的信息(CheckInputs)。!!然后提交在UTXO集中的交易信息的结果(UpdateCoins)。把交易信息添加到CBlock的vtx中计算交易费添加到vTxFees中计算签名添加到vTxSigOps。如果porphan中含有相同的hash项则从porphan中移除添加到vecPriority中。!!计算此块得到的比特币数量、手续费。!!初始化块的成员信息。设置hashPrevBlock为上一个块的哈希索引。更新块时间nTime。设置nBits为下一个需要的POW。设置nNonce为。设置vTxSigOps为块的签名数量。!!提交UTXO集上的指定索引的块的结果(ConnectBlock)。!!!奖励比特币!!!!挖矿创建新区块后(CreateNewBlock)会获取比特币奖励。!!开始奖励个比特币每创建个区块后奖励数量减半。创建个区块大概需要年从而确保到年时比特币总量约为万个(个)比特币的奖励从BTC降为。!!计算比特币奖励是在GetBlockValue函数中。!!计算公式为:!nValue=(*COIN)=(nHeightParams()SubsidyHalvingInterval())!!COIN的值为即BTC=聪。!!nHeight是上一个块的nHeight。!!nSubsidyHalvingInterval是奖励减半的间隔。!!块的比特币奖励保存在块的blockvtxvoutnValue中以聪为单位此值为奖励的比特币数量与手续费的和。!!!!页码:格式化哈希缓冲区!!!!格式化块的数据分解成份FormatHashBuffers函数实现。!!首先定义了一个临时结构用于格式化其定义如下:!struct!{!structunnamed!{!intnVersion!!!!!与CBlock的定义相同!uinthashPrevBlock!uinthashMerkleRoot!unsignedintnTime!unsignedintnBits!unsignedintnNonce!}!block!unsignedcharpchPadding!!block的补齐位!uinthash!unsignedcharpchPadding!!hash的补齐位!}!!先用块CBlock中的相关数据初始化tmp结构再格式化tmp中的block、hash最后把tmp中的数据按字节交换。!!把tmp中的block用pSHAInitState定义的状态以SHA算法加密作为pmidstate的数据。!!tmpblock中的前字节数据作为pdata。!!tmphash中的前字节作为phash的数据。!!!调用FormatHashBlocks函数格式化tmp中的block、hash先根据len计算blocks数(((len)))把pbufferlen为开始的地址长度为(*blockslen)的数据置零把pbufferlen设置为x。然后计算pend地址(pdata*blocks)把pend~pend的数据区设置为(len*)。!!!!页码:SHA算法加密!!!!扫描nonces寻找有位的哈希值(ScanHashCryptoPP)。!!SHA加密算法用的是openssl库中的shah头文件中的sha接口函数。!!所有的输入缓冲区都是字节对齐的。此加密主要操作大编码数据。调用者进行字节交换。!!循环加密加密函数是SHATransform加密分步:!!、把pmidstate中的数据作为开始状态把pdata中的数据HASH到已经格式化的phash中。!!、用pSHAInitState中定义的状态把phash中的数据HASH到phash中。!!加密过程中如果phash中的偏移为的WORD类型的值为则加密成功找到了位的哈希。!!pdata中的偏移为的数据作为临时计数nNonce最多循环xFFFF次。当循环xFFF次后线程设置断点。当循环xFFFF次后表示加密失败重新创建块nNonce置零。!!!页码:检验块!!!!!!挖矿创建的块需要校验有效性(CheckWork)。!!首先满足个条件再进行后续校验。!!、块的哈希值不大于块nBits的压缩值(CBigNum()SetCompact)。!!、块的上一个块的哈希值(hashPrevBlock)等于活跃块链的顶端块(chainActiveTip())的哈希值。!!后续的校验与网络协议节点发送过来的块(“block”消息)的校验方式相同(ProcessBlock函数)。!!校验分以下几步:!!、检验此块是否在块索引映射mapBlockIndex、独立块映射mapOrphanBlocks中如果已经存在则此块无效。!!、检验块内容(CheckBlock)这是基本的检查。检验块的大小、POW(CheckProofOfWork)、时间戳、交易信息(CheckTransaction)、签名的有效性。块的第一个交易信息必须是coinbase必须重置。检验多重支付的id可以尽早捕获潜在的DoS攻击。构建merkle树检验merkle树根节点的有效性。!!、如果已经检验过则进行扩展检查目的是阻止假冒的块填充到内存中。!!满足以下条件的块是假冒的块。!!a、块的时间戳早于上一次检验的时间戳则是假冒的块。!!b、块需要的POW小于上一次检验的最小POW则是假冒的块。!!如果块有上一个块但块索引映射(mapBlockIndex)中没有则需要构建独立的块(COrphanBlock)把新块添加到mapOrphanBlocks、mapOrphanBlocksByPrev中。!!检验通过后把此块保存到磁盘(AcceptBlock)。!!写入磁盘时再次检查满足以下几点才能写入磁盘:!!、块索引映射(mapBlockIndex)中不含有此块的哈希值。!!、块的POW、时间戳、交易信息有效。!!、与检验点匹配。!!、版本检查当网络更新至时(测试网络更新至时)不再写入版本号为的块。coinbase中最后个块中至少含有个版本号为的块测试网络最后个块中至少含有个块。!!检查通过后寻找文件中空余位置把此块写入文件且添加到块索引中。最后添加到节点的块清单中。!!重复处理mapOrphanBlocksByPrev中依赖此块的独立块。!!页码:算法转换数据数据区中偏移为的个字节作为随机数直到运算出的哈希缓冲区中偏移为的个字节的数据值为运算过程一般需要分钟。在比特币的挖矿、确认交易中应用了工作量证明机制。!!挖矿时创建新区块平均需要分钟(inttnTargetSpacing=*)周(inttnTargetTimespan=***)内创建个块(inttnInterval=nTargetTimespannTargetSpacing)创建个块后根据这个块的难度计算新创建的块的难度保证新块的生成时间是分钟。!!块的难度保存在块头CBlockHeader的nBits中长度是个字节设置为CBigNum的压缩值GetCompact()。!!块的最大难度是最小难度保存在系统定义的变量中。!!新创建的块的哈希值不大于块的难度时(nBits的位无符号整数)才是有效块(CheckProofOfWork函数)。!!创世纪块(Genesisblock)的难度为参数定义的最小难度。!!每创建个块后计算新的难度此后的个块使用新的难度。!!在GetNextWorkRequired函数中计算新的难度保存在新块的nBits中。计算步骤:!!、找到前个块的第一个块。!!、计算生成这个块花费的时间即最后一个块的时间与第一个块的时间差。时间差在天,天之间。!!、计算前个块的难度总和即单个块的难度*时间。!!、计算新的难度即难度总和天的秒数得到每秒的难度值。!!、新的难度不能大于参数定义的最小难度。!!在测试网络中生成这个块时的难度按新的规则计算:!!、生成新块的时间比上一个块的时间晚了天则新难度定为参数定义的最小难度值。!!、在上一个块的后天之内生成了新块则新难度为在此个块组中不是参数定义的最小难度的最近的块的难度(thelastnonspecialmindifcultyrulesblock)。!页码:!比特币系统提供了一个函数计算一段时间内的最小难度用来计算某个检验点之后一段时间的最小难度。(ComputeMinWork函数)计算规则如下:!!、在测试网络中如果时间区间大于天则最小难度为参数定义的最小难度。!!、时间以天为单位递减难度倍递增循环元算计算出有效的难度值。!!、新的难度不能大于参数定义的最小难度。!!挖矿时创建新块后需要校验POW是否有效(ProcessBlock函数)先检验难度是否在有效难度范围内(CheckProofOfWork函数)。如果存在检验点再检验是否在检验点的最小工作难度内(ComputeMinWork函数计算检验点、新块之间的最小难度)。!!把块写入磁盘时要进行精确校验POW(AcceptBlock函数)计算新块的难度(GetNextWorkRequired函数)检验是否与块中的nBits相等。!!在测试网络中更新时间时重新计算块的难度(UpdateTime函数)。!!从磁盘中读取块时也要校验POW是否在有效范围内(ReadBlockFromDisk函数)。!!!页码:计算算力!!!!!算力是指每秒创建的千块数量以khashs为单位double类型。!!每秒计算一次算力统计每秒内创建的块数量。时间间隔以毫秒为单位。!!计算公式为:!!算力,块数量*((当前时间,开始时间)*)!!!每隔分钟把算力写入日志。!!比特币网络!!!!比特币系统实例定义了种网络类型分别是:!enumNetwork{!MAIN,!TESTNET,!REGTEST,!!MAXNETWORKTYPES!}!!MAIN类型用于用户交易商品、服务。!!TESTNET类型是公共测试网络重置时间。!!REGTEST类型全名是regressiontest回归测试仅仅用于个人网络。!!!!!!!!!页码:

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

评分:

/15

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利