比特币源码研读之二C++预备知识
本文由【区块链研习社】优质内容计划支持,更多关于区块链的深度好文,请点击【区块链研习社】
本文作者:区块链研习比特币源码研读班 韬声依旧在路上
从读经典开始 - 图片来自网络在正式为大家分享比特币源码研读之前,请允许我为大家介绍一下研读源码之前的最少C++预备知识,当然如果你对这些知识很熟悉的话,那么你可以忽略这篇文章,也可以继续关注我的文章。
编程步骤
- 源代码
- 编译器
- 目标代码
- 链接程序
- 启动代码
- 库代码
- 可执行代码
宏定义
#define
命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。比如在种子生成文件bitcoin/src/random.h
中可以看到如下代码
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
#include <crypto/chacha20.h>
#include <crypto/common.h>
#include <uint256.h>
** 省略部分代码 */
#endif // BITCOIN_RANDOM_H
从上面的代码可以看到宏定义的写法,比如#ifndef
、#define
的使用,也就是说C++在编译期间就知道了程序引用了哪些库和函数。
简单的宏定义
#define <宏名> <字符串>
带参数的宏定义
#define <宏名> (<参数表>) <宏体>
一个标识符被宏定义后,该标识符便是一个宏名。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。
文件包含
文件包含格式如下:
#include <库名称>
#include "库名称"
第一种的写法是指从函数库从引入相关函数,而第二种写法一般用于引入自定义的函数。
类的声明
比如种子生成的bitcoin/src/random.h
文件中FastRandomContext类的声明如下:
class FastRandomContext {
private:
bool requires_seed;
ChaCha20 rng;
unsigned char bytebuf[64];
int bytebuf_size;
uint64_t bitbuf;
int bitbuf_size;
void RandomSeed();
void FillByteBuffer()
{
if (requires_seed) {
RandomSeed();
}
rng.Output(bytebuf, sizeof(bytebuf));
bytebuf_size = sizeof(bytebuf);
}
void FillBitBuffer()
{
bitbuf = rand64();
bitbuf_size = 64;
}
public:
explicit FastRandomContext(bool fDeterministic = false);
/** Initialize with explicit seed (only for testing) */
explicit FastRandomContext(const uint256& seed);
/** Generate a random 64-bit integer. */
uint64_t rand64()
{
if (bytebuf_size < 8) FillByteBuffer();
uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
bytebuf_size -= 8;
return ret;
}
/** Generate a random (bits)-bit integer. */
uint64_t randbits(int bits) {
if (bits == 0) {
return 0;
} else if (bits > 32) {
return rand64() >> (64 - bits);
} else {
if (bitbuf_size < bits) FillBitBuffer();
uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
bitbuf >>= bits;
bitbuf_size -= bits;
return ret;
}
}
/** Generate a random integer in the range [0..range). */
uint64_t randrange(uint64_t range)
{
--range;
int bits = CountBits(range);
while (true) {
uint64_t ret = randbits(bits);
if (ret <= range) return ret;
}
}
/** Generate random bytes. */
std::vector<unsigned char> randbytes(size_t len);
/** Generate a random 32-bit integer. */
uint32_t rand32() { return randbits(32); }
/** generate a random uint256. */
uint256 rand256();
/** Generate a random boolean. */
bool randbool() { return randbits(1); }
};
这个类中使用private
关键字声明了布尔类型的种子导入、ChaCha20
类型的rng变量,也有填充字节缓冲的方法,也有使用public
关键字的std::vector<unsigned char> randbytes(size_t len);
方法,当然也少不了explicit
关键字声明的构造方法。
第三方库的使用
使用方法
在bitcoin/src/httprpc.cpp
文件中我们看到使用了boost库,那么具体的写法可以参考如下代码。
#include <boost/algorithm/string.hpp> // boost::trim
static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
return false;
if (strAuth.substr(0, 6) != "Basic ")
return false;
std::string strUserPass64 = strAuth.substr(6);
boost::trim(strUserPass64);
std::string strUserPass = DecodeBase64(strUserPass64);
if (strUserPass.find(':') != std::string::npos)
strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
//Check if authorized under single-user field
if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
return true;
}
return multiUserAuthorized(strUserPass);
}
使用步骤
- 引入库声明 - 使用
#include
指令 - 调用库 - 使用
库名称::方法名(参数列表)
总结
当然这些预备知识不足以应对比特币源码研读的需要,但是随着C++基础知识的不断强化和深入理解,我相信我会深刻了解C++作为比特币开发的基础语言的重要性和特殊地位,正是由于这些优秀的语言特性才使得比特币诞生这么多年以来没有出现过大的系统漏洞和安全事故,我也相信凭借互联网技术的不断发展,也会出现更多类型的编程语言来不断冲击C++的地位,我也知道C++不是一朝一夕就能学会的,我有耐心,我也希望和大家一起探索C++语言的奥秘,为接下来的源码研读注入更多的信心和力量。