比特币源码学习0.13(三)

源码0.13.2版的,在sublime中打开的


目录


默认文件在src文件夹下,ide又增加了一个vs code,跳转到静态常量比较方便。最近在看书《区块链开发指南》,建议参考https://blog.csdn.net/pure_lady/article/details/77982837#t1这个博主,写的清楚多了
在linux中bitcoin数据目录默认路径~/.bitcoin/

文件详细描述
bicoin.confbitcoin配置文件,bitcoid启动的时候会读取这个文件
debug.log调试信息文件,各种日志写入均存储在该文件中
peers.dat节点的信息
wallet.dat钱包文件,保存你的私钥和相关交易记录,非常重要
blocks区块链(blockchain)的数据存储目录
chainstate区块链(blockchain)的状态存储目录
testnets测试链的数据信息

9.AppInit2()

回到bitcoind.cpp继续后面的代码

fRet = AppInit2(threadGroup, scheduler);

那么来查看AppInit2这个函数,这个函数比较复杂,从备注来看分了12步
step 1:setup(安装网络环境,挂接事件处理器等)
step 2:parameter interactions(进一步的参数交互设置,如区块裁剪prune和txindex的冲突检查、文件描述符的限制检查等)
step 3:parameter-to-internal-flags(参数转换为内部变量,这样外部参数的设置将转换成程序内部的状态)
step 4:application initialization :dir lock,daemonize,pidfile,debug log(初始化ECC,目录锁检查,保证只有一个bitcoind运行等)
step 5:verify wallet database integrity(若启用钱包功能,则会检查钱包数据库的完整性)
step 6:network initialization(网络初始化)
step 7:load block chain(加载区块链数据,即blocks目录下的数据)
step 8:load wallet(若是启用钱包功能,则加载钱包)
step 9:data directory maintenance(若是裁剪模式,则进行blockstore的裁剪)
step 10:import blocks(导入数据块)
step 11:start node(启动节点服务,监听网络p2p请求,若启用-gen挖矿参数,则调用generatebitcoins启动数个挖矿线程bitcoinminer)
step 12:finished(完成)

//init.cpp
/** Initialize bitcoin.
 *  @pre Parameters should be parsed and config file should be read.
 */
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{

从备注来看AppInit2这个函数的作用是初始化bitcoin,这步之前需要完成参数解析与配置文件的读取。


9.1 setup
1)关闭警告消息
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
    // Turn off Microsoft heap dump noise
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif

从注释来看这段的功能是关闭微软内存堆的噪声,应该是针对微软的开发环境设置的,其他编译环境中这段不执行。
关于_MSC_VER的解释
_MSC_VER是微软的预编译控制。
_MSC_VER可以分解为:MS:Microsoft的简写;C:MSC就是Microsoft的C编译器;VER:Version的简写。_MSC_VER的意思就是:Microsoft的C编译器的版本。
微软不同时期,编译器有不同的版本:
MS VC++10.0 _MSC_VER=1600;MS VC++9.0 _MSC_VER=1500;MS VC++8.0 _MSC_VER=1400

代码中的两个函数_CrtSetReportMode_CrtSetReportFile在代码中没有找到定义,根据查询到的内容,在这段代码中是设置为报告类型为警告,报告输出方式为文件输出,但是输出文件为空,那么警告消息的输出可以理解为被关闭了。

2)abort()
#if _MSC_VER >= 1400
    // Disable confusing "helpful" text message on abort, Ctrl-C
    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif

这段是针对vc++8.0以上的处理,解决程序非正常终止时的帮助消息是否打印的问题,详细信息参考函数本身的说明_set_abort_behavior

3)DEP
#ifdef WIN32
    // Enable Data Execution Prevention (DEP)
    // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
    // A failure is non-critical and needs no further attention!
#ifndef PROCESS_DEP_ENABLE
    // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
    // which is not correct. Can be removed, when GCCs winbase.h is fixed!
#define PROCESS_DEP_ENABLE 0x00000001
#endif
    typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
    PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
    if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);
#endif

注释:启用数据执行保护(DEP),支持的最低操作系统WinXP SP3, WinVista >= SP1, Win Server 2008;由于GCCs winbase.h将该功能限制在_WIN32_WINNT >= 0x0601 (Windows 7)才能使用,这是不对的,所以有下面的强制宏定义。
代码表示通过函数指针获取Kernel32.dll中的SetProcessDEPPolicy函数对象,实现DEP功能的开启。

4)初始化网络
 if (!SetupNetworking())
        return InitError("Initializing networking failed");

调用函数SetupNetworking

//util.cpp
bool SetupNetworking()
{
#ifdef WIN32
    // Initialize Windows Sockets
    WSADATA wsadata;
    int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
    if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
        return false;
#endif
    return true;
}

根据注释来看是初始化Windows Sockets,初始化工作通过WSAStartup函数实现。

5)文件创建
#ifndef WIN32
    if (GetBoolArg("-sysperms", false)) {
#ifdef ENABLE_WALLET
        if (!GetBoolArg("-disablewallet", false))
            return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
#endif
    } else {
        umask(077);
    }

ifndef WIN32是针对非window系统,首先判断参数是否设置了-sysperms,未设置则调用umask(077)

-sysperms
Create new files with system default permissions, instead of umask 077(only effective with disabled wallet functionality)
 创建具有系统默认权限的新文件,而不是UMASK 077(仅对禁用钱包功能有效)

如果钱包未启用,则提示报错信息。umask用于设置文件与文件夹使用权限,077代表—rwxrwx,表示owner没有任何权限,group和other有所有权限。

6)进程终止信号
// Clean shutdown on SIGTERM
    struct sigaction sa;//信号处理对象
    sa.sa_handler = HandleSIGTERM;//进程终止信号处理句柄
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);//终止信号处理
    sigaction(SIGINT, &sa, NULL);//中断信号处理

句柄函数

//init.cpp
std::atomic<bool> fRequestShutdown(false);//在同一文件不同位置
void HandleSIGTERM(int)
{
    fRequestShutdown = true;
}

函数非常简单,就是将全局变量fRequestShutdown设置为true
std::atomic对int, char, bool等数据结构进行原子性封装,在多线程环境中,对std::atomic对象的访问不会造成竞争-冒险。利用std::atomic可实现数据结构的无锁设计。

7)挂起信号处理
// Reopen debug.log on SIGHUP
    struct sigaction sa_hup;//信号处理对象
    sa_hup.sa_handler = HandleSIGHUP;
    sigemptyset(&sa_hup.sa_mask);
    sa_hup.sa_flags = 0;
    sigaction(SIGHUP, &sa_hup, NULL);//挂起信号处理

和终止信号处理过程基本相同,句柄函数

std::atomic<bool> fReopenDebugLog(false);
void HandleSIGHUP(int)
{
    fReopenDebugLog = true;
}

将全局变量fReopenDebugLog设置为true,在util.cpp中LogPrintStr重新打开日志文件

 // reopen the log file, if requested
            if (fReopenDebugLog) {
                fReopenDebugLog = false;
                boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
                if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
                    setbuf(fileout, NULL); // unbuffered
            }
8)管道错误处理
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
    signal(SIGPIPE, SIG_IGN);
#endif

忽略SIGPIPE,否则如果客户端关闭,它会导致守护进程下降。


9.2parameter interactions

没有备注就在在init.cpp的

// ********************************************************* Step 2: parameter interactions
    const CChainParams& chainparams = Params();

CChainParams这个类在6.2有提到,这里就不再详细写了。

//chainparams.cpp
const CChainParams &Params() {
    assert(pCurrentParams);
    return *pCurrentParams;
}

在step3 目录9.3 9)非标准交易 中有使用

1)-prune

这个参数如果设置资源配置不足的bitcoin.conf的配置信息应该还记得,我也有写在比特币源码编译那里,作用是通过删除旧的块,将磁盘空间要求降低到这个兆字节。

// if using block pruning, then disable txindex
    if (GetArg("-prune", 0)) {
        if (GetBoolArg("-txindex", DEFAULT_TXINDEX))
            return InitError(_("Prune mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
        if (GetBoolArg("-rescan", false)) {
            return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
        }
#endif
    }

-prune是和-txindex有冲突的,这个在《精通比特币》这本书里有写

//《精通比特币》 3.2.6配置比特币核心节点
prune
通过删除旧的块,将磁盘空间要求降低到这个兆字节。 在资源受限的节点上不能 满足完整块的节点使用这个。
txindex
维护所有交易的索引。 这意味着可以通过 ID 以编程方式检索任何交易的块链的
完整副本。

由于没有完整的区块链,也就无法使用钱包,无法回溯历史区块。
不过删除旧的块是怎们删除的呢,如果整个块删除那就连不起来了,会中间断开,搜索
在白皮书中有提到

Once the latest transaction in a coin is buried under enough blocks, the spent transactions before it can be discarded to save disk space. 
To facilitate this without breaking the block's hash, transactions are hashed in a Merkle Tree [7][2][5], with only the root included in the block's hash.
 Old blocks can then be compacted by stubbing off branches of the tree. The interior hashes do not need to be stored.

作者的想法是修剪掉最新交易(已确认)之前的交易数据
这里写图片描述
也就是针对merkle tree来修剪的,有两种修剪对象,一个是所有输出被花费的的叶子节点(交易),另一是节点包含的所有子节点都已被修剪。并且是在0.11版本之后才开始实现这个功能。
根据bitcoin release note中的描述

Block pruning allows Bitcoin Core to delete the raw block and undo data once it’s been validated and used to build the databases. At that point, the raw data is used only to relay blocks to other nodes, to handle reorganizations, to look up old transactions (if -txindex is enabled or via the RPC/REST interfaces), or for rescanning the wallet. The block index continues to hold the metadata about all blocks in the blockchain.
区块修剪允许bitcoin core删除raw block和undo data,一旦这些数据已经被验证和更新过数据库。这时候的raw data只能用来转发区块到其他节点、处理区块重组、查看过去的交易(如果启用了-txindex交易索引或者通过RPC/REST接口调用)以及重新扫描钱包。区块索引依然维护所有区块的元数据。

在比特币运行的本地环境中,有四种类型的数据(查看~/.bitcoin/目录,测试网查看~/.bitcoin/teseets/blocks/目录)
这里写图片描述
raw block,从网络中接收的原始块信息,对应文件为blk*****.dat
undo data,在进行chain reorganization时使用的数据,对应的文件为rev******.dat.chain reorganization是指某一节点发现存在一条比节点当前本地维护的链更长的链,那么该节点就需要进行chain reorganization
block index,区块索引,每一个区块都有一个唯一的索引,对应文件为/index下的**.ldb就是level db数据库文件。
UTXO,未花费支出,对应文件为../chainstate/下的.ldb文件

2)确保文件描述符

关于linux的文件描述符,可以参考https://blog.csdn.net/cywosp/article/details/38965239
介绍这段代码中用到的几个宏定义

//net.h
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;

最大可维护的节点连接书,默认125

//compat.h
#define FD_SETSIZE 1024 // max number of fds in fd_set

可包含的最大文件描述符的个数,默认1024

#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
// accessing block files don't count towards the fd_set size limit
// anyway.
#define MIN_CORE_FILEDESCRIPTORS 0
#else
#define MIN_CORE_FILEDESCRIPTORS 150
#endif

最小核心文件描述符的个数,windows下为0,linux为150
具体代码就不放上来了。返回目录


9.3 parameter-to-internal-flags

内部标志的参数处理

1)不支持的内部标志

-debug/-nodebug:如果-debug=0或者-nodebug被设置,设置fDebug=false,关闭调试信息;

//util.cpp
bool fDebug = false;

-debugnet:不支持的参数,用-debug=net替代;
-socks:不支持的参数,目前只支持SOCKS5;
-tor:不支持的参数,应使用-onion;

onion=<ip:port> Use separate SOCKS5 proxy to reach peers via Tor hidden services 

-benchmark:不支持的参数,用-debug=bench替代
-whitelistalwaysrelay:不支持的参数,应使用-whitelistrelay或-whitelistforcerelay
-blockminsize:不支持的参数

2)检索

检测交易池和区块索引,这两个参数在私有网模式下默认为true

// Checkmempool and checkblockindex default to true in regtest mode
    int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
    if (ratio != 0) {
        mempool.setSanityCheck(1.0 / ratio);
    }

mempool是CTxMemPool类型

//main.cpp
CTxMemPool mempool(::minRelayTxFee);

CTxMemPool定义在txmempool.h,根据注释来看

CTxMemPool stores valid-according-to-the-current-best-chain
 * transactions that may be included in the next block.

该类是用来保存在当前最佳链下的有效交易并且这些交易也会被打包到后续的区块中。

Transactions are added when they are seen on the network
 *(or created by the local node), but not all transactions seen
 * are added to the pool: if a new transaction double-spends
 * an input of a transaction in the pool, it is dropped,
 * as are non-standard transactions.

但不是所有被发现的交易都会被添加到池里:如果一个新交易在池中花费了一个交易的输入(双花),则它被丢弃,非标准事务也是如此。所以CTxMemPool 需要对交易进行完整性检测,检测频率通过setSanityCheck来设置

//txmempool.h
 uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check
 void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }

4294967295.0=2^32-1,nCheckFrequency代表池中所有交易的检测频率,即每隔nCheckFrequency个交易检测一次。传入的dFrequency的值是1.0
再返回去看ratio的获取

int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);

CChainParams这个类在6.2选择比特币网络中有提到,要看的是DefaultConsistencyChecks()这个函数返回值

//chainparams.h CChainParams类中
    /** Default value for -checkmempool and -checkblockindex argument */
    bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
    bool fDefaultConsistencyChecks;

CChainParams类是基类,其三个子类中,CMainParams,CTestNetParams这两个类中fDefaultConsistencyChecks=false,CRegTestParams=true。也就是说只有在私有网中才默认需要进行一致性检测。
接下来看区块索引检测

fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
    fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
//main.cpp
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
//main.h
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;

私有网是默认进行区块索引的检测。参数检测点是默认为true,即默认进行检测点检查。关于检测点的作用这里不写了。检测点的具体使用后面应该会有。

3)交易池限制
// mempool limits
    int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
    int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
    if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
        return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));

首先计算最大和最小交易池size,其中的默认值

//policy.h
/** Default for -maxmempool, maximum megabytes//(MB) of mempool memory usage */
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
//main.h
/** Default for -limitdescendantsize, maximum kilobytes//(KB) of in-mempool descendants */
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;

默认最大存储容量是300MB,最小存储容量101KB。

4)脚本验证线程

-par=0意味着自动执行,但nScriptCheckThreads=0代表没有并发

// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
    nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
    if (nScriptCheckThreads <= 0)
        nScriptCheckThreads += GetNumCores();
    if (nScriptCheckThreads <= 1)
        nScriptCheckThreads = 0;
    else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
        nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
    fServer = GetBoolArg("-server", false);

在help信息中找到对-par参数的解释

-par=<n>
       Set the number of script verification threads (-2 to 16, 0 = auto, <0 =leave that many cores free, default: 0)

默认的线程验证为0=auto,<0表示释放内核,下面还定义了最大的脚本验证线程数是16

//main.h
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
/** Number of blocks that can be requested at any given time from a single peer. */
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;

接下来看对nScriptCheckThreads的逻辑判断:nScriptCheckThreads<0,通过GetNumCores()函数获取程序运行机器能提供的线程数,然后加上,再判断后面的;

//util.cpp
int GetNumCores()
{
#if BOOST_VERSION >= 105600
    return boost::thread::physical_concurrency();
#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores
    return boost::thread::hardware_concurrency();
#endif
}
//version.hpp
#define BOOST_VERSION 105800

上述代码用到了c++ boost库的boost:thread,对这两个函数不是很理解,去boost库查找
这里写图片描述
physical_concurrency()返回当前系统上可用的物理内核,与hardware_concurrency()不同,他不返回虚拟内核的数量,只计算物理内核。

5)区块修剪
 // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
    int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
    if (nSignedPruneTarget < 0) {
        return InitError(_("Prune cannot be configured with a negative value."));
    }

-prune这个参数在9.2 1)已经介绍过了,来看代码部分,首先获取数值,单位是MB,判断数值,该参数不能为负数。

nPruneTarget = (uint64_t) nSignedPruneTarget;
    if (nPruneTarget) {
        if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
            return InitError(strprintf(_("Prune configured below the minimum of %d MiB.  Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
        }
        LogPrintf("Prune configured to target %uMiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
        fPruneMode = true;
    }
//main.h
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;

最低的空间要求是550M,这点在帮助信息也有明确的提示

  -prune=<n>
       Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain.(default: 0 = disable pruning blocks, >550 = target size in MiB to use for block files)
6)注册RPC命令

在代码中就调用了一下

 RegisterAllCoreRPCCommands(tableRPC);

在src/rpc/register.h下是对该函数的定义

static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
{
    /** Register block chain RPC commands */
    RegisterBlockchainRPCCommands(tableRPC);//区块链RPC命令注册
    /** Register P2P networking RPC commands */
    RegisterNetRPCCommands(tableRPC);//P2P网络命令注册
    /** Register miscellaneous RPC commands */
    RegisterMiscRPCCommands(tableRPC);//其他工具RPC
    /** Register mining RPC commands */
    RegisterMiningRPCCommands(tableRPC);//挖矿RPC命令
    /** Register raw transaction RPC commands */
    RegisterRawTransactionRPCCommands(tableRPC);//交易RPC
}

分别来看这些命令注册实现的具体位置
I 区块链RPC命令,整个cpp文件都是对应命令的具体实现,下面是命令列表,在RegisterBlockchainRPCCommands函数中通过遍历的方式添加命令。

//src/rpc/blockchain.cpp
static const CRPCCommand commands[] =
{ //  category              name                      actor (function)         okSafeMode
  //  --------------------- ------------------------  -----------------------  ----------
    { "blockchain",         "getblockchaininfo",      &getblockchaininfo,      true  },
    { "blockchain",         "getbestblockhash",       &getbestblockhash,       true  },
    { "blockchain",         "getblockcount",          &getblockcount,          true  },
    { "blockchain",         "getblock",               &getblock,               true  },
    { "blockchain",         "getblockhash",           &getblockhash,           true  },
    { "blockchain",         "getblockheader",         &getblockheader,         true  },
    { "blockchain",         "getchaintips",           &getchaintips,           true  },
    { "blockchain",         "getdifficulty",          &getdifficulty,          true  },
    { "blockchain",         "getmempoolancestors",    &getmempoolancestors,    true  },
    { "blockchain",         "getmempooldescendants",  &getmempooldescendants,  true  },
    { "blockchain",         "getmempoolentry",        &getmempoolentry,        true  },
    { "blockchain",         "getmempoolinfo",         &getmempoolinfo,         true  },
    { "blockchain",         "getrawmempool",          &getrawmempool,          true  },
    { "blockchain",         "gettxout",               &gettxout,               true  },
    { "blockchain",         "gettxoutsetinfo",        &gettxoutsetinfo,        true  },
    { "blockchain",         "verifychain",            &verifychain,            true  },

    /* Not shown in help */
    { "hidden",             "invalidateblock",        &invalidateblock,        true  },
    { "hidden",             "reconsiderblock",        &reconsiderblock,        true  },
};

void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
{
    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
        tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}

II P2P网络RPC命令,代码结构基本相同的

//src/rpc/net.cpp
static const CRPCCommand commands[] =
{ //  category              name                      actor (function)         okSafeMode
  //  --------------------- ------------------------  -----------------------  ----------
    { "network",            "getconnectioncount",     &getconnectioncount,     true  },
    { "network",            "ping",                   &ping,                   true  },
    { "network",            "getpeerinfo",            &getpeerinfo,            true  },
    { "network",            "addnode",                &addnode,                true  },
    { "network",            "disconnectnode",         &disconnectnode,         true  },
    { "network",            "getaddednodeinfo",       &getaddednodeinfo,       true  },
    { "network",            "getnettotals",           &getnettotals,           true  },
    { "network",            "getnetworkinfo",         &getnetworkinfo,         true  },
    { "network",            "setban",                 &setban,                 true  },
    { "network",            "listbanned",             &listbanned,             true  },
    { "network",            "clearbanned",            &clearbanned,            true  },
};

void RegisterNetRPCCommands(CRPCTable &tableRPC)
{
    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
        tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}

III 其他工具RPC命令

//src/rpc/misc.cpp
static const CRPCCommand commands[] =
{ //  category              name                      actor (function)         okSafeMode
  //  --------------------- ------------------------  -----------------------  ----------
    { "control",            "getinfo",                &getinfo,                true  }, /* uses wallet if enabled */
    { "util",               "validateaddress",        &validateaddress,        true  }, /* uses wallet if enabled */
    { "util",               "createmultisig",         &createmultisig,         true  },
    { "util",               "verifymessage",          &verifymessage,          true  },
    { "util",               "signmessagewithprivkey", &signmessagewithprivkey, true  },

    /* Not shown in help */
    { "hidden",             "setmocktime",            &setmocktime,            true  },
};

IV mining rpc commands

//src/rpc/mining.cpp
static const CRPCCommand commands[] =
{ //  category              name                      actor (function)         okSafeMode
  //  --------------------- ------------------------  -----------------------  ----------
    { "mining",             "getnetworkhashps",       &getnetworkhashps,       true  },
    { "mining",             "getmininginfo",          &getmininginfo,          true  },
    { "mining",             "prioritisetransaction",  &prioritisetransaction,  true  },
    { "mining",             "getblocktemplate",       &getblocktemplate,       true  },
    { "mining",             "submitblock",            &submitblock,            true  },

    { "generating",         "generate",               &generate,               true  },
    { "generating",         "generatetoaddress",      &generatetoaddress,      true  },

    { "util",               "estimatefee",            &estimatefee,            true  },
    { "util",               "estimatepriority",       &estimatepriority,       true  },
    { "util",               "estimatesmartfee",       &estimatesmartfee,       true  },
    { "util",               "estimatesmartpriority",  &estimatesmartpriority,  true  },
};

V 交易RPC命令

//src/rpc/rawtransaction.cpp
static const CRPCCommand commands[] =
{ //  category              name                      actor (function)         okSafeMode
  //  --------------------- ------------------------  -----------------------  ----------
    { "rawtransactions",    "getrawtransaction",      &getrawtransaction,      true  },
    { "rawtransactions",    "createrawtransaction",   &createrawtransaction,   true  },
    { "rawtransactions",    "decoderawtransaction",   &decoderawtransaction,   true  },
    { "rawtransactions",    "decodescript",           &decodescript,           true  },
    { "rawtransactions",    "sendrawtransaction",     &sendrawtransaction,     false },
    { "rawtransactions",    "signrawtransaction",     &signrawtransaction,     false }, /* uses wallet if enabled */

    { "blockchain",         "gettxoutproof",          &gettxoutproof,          true  },
    { "blockchain",         "verifytxoutproof",       &verifytxoutproof,       true  },
};

这些命令的注册方式都是相似的,就不再说明了。
后面的代码,如果定义了开启钱包宏(默认开启),没有关闭钱包,就注册钱包的RPC命令。

#ifdef ENABLE_WALLET
    bool fDisableWallet = GetBoolArg("-disablewallet", false);
    if (!fDisableWallet)
        RegisterWalletRPCCommands(tableRPC);
#endif
//src/config/bitcion-config.h
/* Define to 1 to enable wallet functions */
#define ENABLE_WALLET 1

注册方式与前面的相似,在src/wallwet/rpcwallet.cpp
这些rpc命令可以在在bitcoin-cli命令行中使用,bitcoin-cli help可以获取这些帮助信息

7)节点超时参数

比特币网络中新加入的节点都回去寻找节点,加入比特币p2p网络中,与其他节点完成同步操作,不过寻找节点的时间是有限制的,默认值为5000ms,并且不能设置为负数

nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
    if (nConnectTimeout <= 0)
        nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
//netbase.h
//! -timeout default
static const int DEFAULT_CONNECT_TIMEOUT = 5000;
8)最小交易费

首先来看注释内容,该费率为没千字节所需的最小费率,这个费率值的设置对矿工来说需要谨慎设置:如果你设置为0,那么每个被挖出的块都会被交易的垃圾邮件发送者的1聪交易费的交易填满,最低交易费应高于处理交易所需的成本。

    // Fee-per-kilobyte amount considered the same as "free"
    // If you are mining, be careful setting this:
    // if you set it to zero then
    // a transaction spammer can cheaply fill blocks using
    // 1-satoshi-fee transactions. It should be set above the real
    // cost to you of processing a transaction.
    if (mapArgs.count("-minrelaytxfee"))
    {
        CAmount n = 0;
        if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
            ::minRelayTxFee = CFeeRate(n);
        else
            return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"]));
    }

如果设置了-minrelaytxfee,调用CFeeRate设置费用;若未设置,也是调用该函数,设为默认值,默认最小费率为1000聪

//main.cpp
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
//main.h
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;

接下来看一下minRelayTxFee这个全局变量的使用场所

//main.cpp
CTxMemPool mempool(::minRelayTxFee);
FeeFilterRounder filterRounder(::minRelayTxFee);

在设置矿池和费用循环过滤中用到。


比特币源码学习0.13(四)

发布了32 篇原创文章 · 获赞 7 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览