主页 > imtoken冷钱包官方版 > 老文章转载-比特币源码学习系列一
老文章转载-比特币源码学习系列一
写在文章前
早些时候,我们报道了一篇关于比特币如何运作的文章。
文章链接:30分钟了解比特币和区块链。
这篇文章基本可以解释比特币的基本工作机制,但是老王对一些细节感到有些困惑。想了半天,老王决定用自己薄弱的代码知识带大家去研究比特币的源码。,并潜入代码世界找出答案。
比特币源码学习系列一 环境初始化
为了进一步了解比特币的工作机制,接下来我们将通过阅读其源码进一步了解比特币是如何工作的。《比特币源码学习》系列文章比较专业,面向有一定编码能力,对比特币非常感兴趣的读者。其他读者可以阅读本文开头的文章。
由于老王专业知识有限,文中如有错误,敬请指正。非常欢迎这方面的专业人士与老王洽谈。
自2009年中本聪发布比特币源代码以来,多年来比特币源代码不断改进,引入了许多重要的改进。下载的时候已经是 0.15.0 版本了,所以下面的解释也是基于这个版本的代码。
下载地址:github
代码语言:c++
源版本:0.15.0
目录结构:
有一些重要的文件夹。doc文件夹是一些描述文件,包括代码版本说明、编译文档等,src是源代码目录,也就是我们接下来要解释的文件夹比特币项目开源代码,test文件夹是一些功能测试文件夹。因为代码量很大,如果完全复制,会淹没文章主体。所以在很多情况下,我会使用更容易阅读的伪代码的形式,尽量不贴源代码。想了解具体细节的读者可以下载源码自行阅读。.
好了,第一个源码解读:比特币环境的初始化过程。
在查看代码之前,让我们考虑一下比特币程序启动时应该做什么:
初始化网络,准备接收别人发来的tx(transaction,中文称为交易)或block(中文称为block,blockchain就是中文的区块链),或者发送存储在机器中或者刚刚挖矿生成的tx块初始化我的钱包,整理账户下的比特币和每个币的使用情况
让我们看看比特币代码是如何做到的:
学过c或者c++的读者应该都知道,程序启动的入口是main函数,定义在bitcoind.cpp文件中。主函数定义如下:
int main(int argc, char* argv[])
{
设置环境();
// 连接 bitcoind 信号处理器
noui_connect();
返回(AppInit(argc,argv)?EXIT_SUCCESS:EXIT_FAILURE);
}
让我们一一看看这些方法。SetupEnvironment和noui_connect方法做了一些准备工作,比如设置程序运行环境为windows、linux等,注册日志处理,我们再来看看AppInit方法。
AppInit 方法有几个过程:
首先检查参数、文件目录等 AppInitBasicSetup 方法初始化一些基本设置 AppInitSanityChecks 检查所有依赖库是否完整 AppInitMain 方法是我们的重点
我们继续看AppInitMain方法:
InitSignatureCache 方法初始化签名缓存,每个签名都会存储在缓存中。InitScriptExecutionCache 方法初始化脚本执行缓存。AppInitServers 方法初始化 httpserverVerifyWallets 方法来检查钱包数据库的一致性。newCBlockTreeDB().writeReIndexing() 方法加载区块链并检查创世块 LoadBlockIndex 方法将一些块索引从硬盘加载到内存 StartWallets 方法启动我的钱包,我们需要了解它是如何启动的
接下来我们看一下 StartWallets 方法:
ReacceptWalletTransaction 方法将与钱包关联的 tx 加载到内存中。它如何查找 tx 并检查它?scheduler.scheduleEvery(MaybeCompactWalletDB, 500) 定义了一个定期刷新钱包的线程
我们来看一下 ReacceptWalletTransactions 的源码:
无效 CWallet::ReacceptWalletTransactions()
{
// 如果交易没有被广播,也不要让它们进入本地内存池
如果(!fBroadcastTransactions)
返回;
LOCK2(cs_main,cs_wallet);
std::map mapSorted;
// 根据初始钱包插入顺序对待处理的钱包交易进行排序
for (std::pair& item : mapWallet)
{
常量 uint256&wtxid = item.first;
CWalletTx&wtx=item.second;
断言(wtx.GetHash()== wtxid);
int nDepth =wtx.GetDepthInMainChain();
if (!wtx.IsCoinBase()&& (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos,&wtx));
}
}
// 尝试将 wallettransactions 添加到内存池
for (std::pair& item : mapSorted)
{
CWalletTx& wtx =*(item.second);
锁定(内存池.cs);
CValidationStatestate;
wtx.AcceptToMemoryPool(maxTxFee, state);
}
}
该方法先检查是否已经设置为广播,然后遍历mapWallet中的tx,检查如下:
检查 tx 的哈希值 检查 tx 在区块链中的深度。检查 tx 是否为 coinbase 以及是否处于丢弃状态。如果这些检查通过,则将这些 tx 按顺序放入内存池(内存池)
在下一篇文章继续之前,让我解释一下这里提到的几个概念:
深度 nDepth。深度是指 tx 所在区块与主链上最新区块之间的区块数。主链主链。主链是指当前比特币网络中公认的最长的区块链比特币项目开源代码,在客户端也有一条主动链chainActive。Coinbase 交易。这是一种类型的 tx。每个区块中的第一个是 coinbasetx。coinbase tx 通常不与任何输入 tx 相关联,而仅与输出相关联。最典型的例子就是挖矿获得的系统奖励币放在coinbase中。内存池。代码中用mempool表示,保存了那些还没有入块的tx,后续运行时经常遇到。
好了,这篇文章就到这里了,下一篇我们将学习如何创建一个新的tx。