比特币源码解析(9)

来源:互联网 发布:c语言字符串最前面是0 编辑:程序博客网 时间:2024/05/18 03:01

0x00 摘要

我使用的是Ubuntu 16.04 系统所以直接按照https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md 编译就可以成功,编译完成之后,生成了一下几个可执行文件:

  • bench_bitcoin:根据https://github.com/bitcoin/bitcoin/issues/829 解释,作用是编译系统更新,也就是检查系统使用的一些加密算法是否有新的更新。
  • bitcoin-cli:是Bitcoind的一个功能完备的RPC客户端,包括查询区块,交易信息等等,具体将在相应章节介绍。
  • bitcoind:是比特币运行的核心程序俗称bitcoin core,也是我们分析的重点。
  • bitcoin-qt:比特币钱包。
  • bitcoin-tx:比特币交易处理模块,支持交易的查询和创建。
  • test_bitcoin:运行各个模块的测试代码。
  • test_bitcoin-qt:运行钱包的模块测试代码。

我们首先从最核心的bitcoind开始分析,然后再看其他的,因为其他部分的代码使用的很多类、很多函数都是bitcoind中使用过的,所以分析完bitcoind,其他部分也就轻而易举。

另外提及一下代码的查看软件,我用的是Sublime Text,能快速的找到函数的定义和实现的位置,并且还支持在项目内查找,一个好的编辑器对于代码的分析也是很有帮助的。

0x01 Main

对于c++代码,整个程序都是从main函数开始执行的,所以我们首先寻找bitcoind的main函数。而一般编译出来的可执行程序都是有对应文件名的cpp文件,所以我们找到了src/bitcoind.cpp,代码拉到最后就找到了我们的main函数。

// src/bitcoind.cpp line 188int main(int argc, char* argv[]){    SetupEnvironment();    // Connect bitcoind signal handlers    noui_connect();    return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);}

0x02 SetupEnvironment

找到SetupEnvironment的实现位置,位于src/util.cpp中,sublime中直接右键Goto Definition即可。

// src/util.cpp line 834void SetupEnvironment(){#ifdef HAVE_MALLOPT_ARENA_MAX    if (sizeof(void*) == 4) {   //判断是否为32位系统        mallopt(M_ARENA_MAX, 1);     }#endif#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)    try {        std::locale(""); // Raises a runtime error if current locale is invalid    } catch (const std::runtime_error&) {        setenv("LC_ALL", "C", 1);    }#endif    std::locale loc = fs::path::imbue(std::locale::classic());    fs::path::imbue(loc);}

函数首先通过sizeof(void*) == 4来判断当前系统是否是32位,如果是64位的话那么sizeof(void*)值就为8。mallopt函数是用来控制malloc内存分配时的行为的(具体请参考http://man7.org/linux/man-pages/man3/mallopt.3.html),而M_ARENA_MAX参数是值最多能创建的arena数,一个arena是指malloc在分内内存时的一个内存池,而这个arena是线程安全的,也就是说多线程访问时是互斥访问的,既然是互斥访问的,那么很明显,当arena数量越多时,线程的竞争就越小,但是需要的内存也就越多(因为arena就相当于一次性申请大量内存,然后在malloc时慢慢分配出去)。通过代码中的注释,我们发现glibc库会为每个核创建2个arena,而这会对32为系统造成虚拟地址空间不足的问题,所以这里设为1.

下面是locale()是设置系统区域,这将决定程序所使用的当前语言编码、日期格式、数字格式及其它与区域有关的设置。最后两行是文件路径的本地化设置,主要设计宽字符(Wide char)和多字节(Multi bytes)之间的转换问题。

0x03 noui_connect

// src/noui.cpp line 52void noui_connect(){    // Connect bitcoind signal handlers    uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);    uiInterface.ThreadSafeQuestion.connect(noui_ThreadSafeQuestion);    uiInterface.InitMessage.connect(noui_InitMessage);}

这里涉及到我们之前讲到的Boost信号/插槽机制(http://blog.csdn.net/pure_lady/article/details/77675915)。首先看变量的定义,

// src/ui_interface.h // line 74-81    /** Show message box. */    boost::signals2::signal<bool (const std::string& message,                                   const std::string& caption,                                   unsigned int style),         boost::signals2::last_value<bool>> ThreadSafeMessageBox;    /** If possible, ask the user a question.     * If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */    boost::signals2::signal<bool (const std::string& message,                                   const std::string& noninteractive_message,                                   const std::string& caption, unsigned int style), boost::signals2::last_value<bool> > ThreadSafeQuestion;    /** Progress message during initialization. */    boost::signals2::signal<void (const std::string &message)> InitMessage;extern CClientUIInterface uiInterface;  // line 123

这里在CClientUIInterface类中定义了一些信号,其中三个分别是ThreadSafeMessageBoxThreadSafeQuestionInitMessage。再看前面的noui_connect中的变量,我们发现通过connect连接的插槽函数定义和信号中的定义完全一致,所以当信号触发的时候,这些连接的函数都会被调用。

原创粉丝点击