分析完了第七步,下面我们继续来看第八步的内容。
// ********************************************************* Step 8: start indexers
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex);
g_txindex->Start();
}
首先是关于-txindex
参数的解释:
-txindex
:Maintain a full transaction index, used by the getrawtransaction rpc call (default: false)维护所有的交易索引,提供给getrawtransaction这个rpc调用来使用。
其中,TxIndex
这个类的构造函数在txindex.cpp line 226
,
TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
: m_db(MakeUnique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{
}
参数表示的含义分别为,
* @param[in] nCacheSize Configures various leveldb cache settings.
* @param[in] fMemory If true, use leveldb's memory environment.
* @param[in] fWipe If true, remove all existing data.
接下来开始挑中TxIndex
中的Start()
函数,但是这个类中并没有直接实现Start
函数,而是继承了BaseIndex
中的Start
函数。而该函数的实现如下,
// base.cpp line 257
void BaseIndex::Start()
{
// Need to register this ValidationInterface before running Init(), so that
// callbacks are not missed if Init sets m_synced to true.
RegisterValidationInterface(this);
if (!Init()) {
FatalError("%s: %s failed to initialize", __func__, GetName());
return;
}
m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(),
std::bind(&BaseIndex::ThreadSync, this));
}
先来看Init()
这个函数,该函数的调用在base.cpp line 55
,实现如下,
bool BaseIndex::Init()
{
CBlockLocator locator;
if (!GetDB().ReadBestBlock(locator)) {
locatorSetNull();
}
LOCK(cs_main);
m_best_block_index = FindForkInGlobalIndex(chainActive, locator);
m_synced = m_best_block_index.load() == chainActive.Tip();
return true;
}
主要是设置了两个变量的值,第一个是m_best_block_index
表示主链的最后一个区块的索引,第二个参数是m_synced
表示当前的索引是否和主链同步。再来看第一个函数RegisterValidationInterface()
,这个函数的实现在validationinterface.cpp line 74
,主要是绑定了一些函数指针,以便在新的事件发生时进行回调,但是并不是此函数中所有涉及到的指针都是有效的,从base.cpp
中关于类BaseIndex
的实现中我们可以看出只实现了BlockConnected
和ChainStateFlushed
这两个函数,其他没有实现的函数对应的指针为空。而在代码中先调用RegisterValidationInterface
的原因是,避免在Init
执行的过程中有新的事件发生,但是没有调用对应的回调函数,m_synced
的状态也就没有更新,但是Init
最后还是将此值设置为true
,所以就导致了状态的不一致。
在Start
函数的最后一步,创建了一个线程,去执行TraceThread
这个函数,但这个函数中主要还是执行了参数中的ThreadSync
函数,而这个函数的主要功能就是从当前主链中同步索引信息到索引文件中,实现中就是通过一个while
循环,从当前的m_best_block_index
开始,直到主链中最新的区块。
// ********************************************************* Step 9: load wallet
if (!g_wallet_init_interface.Open()) return false;
接下来开始第九步,其中有两个地方定义了g_wallet_init_interface
变量,第一个是在init.cpp line 101
,也就是在此文件的开头,通过一个宏定义ENABLE_WALLET
来判断是否启用wallet,如果没有定义该变量,那么就直接使用该文件中的DummyWalletInit
来代替,该类中几乎所有函数的实现都为空;而如果定义了宏ENABLE_WALLET
那么就使用wallet/init.cpp line 52
中的g_wallet_init_interface
,该对象实现了WalletInitInterface
中定义的所有接口,而其中的Open()
的实现是在223行,如下
// wallet/init.cpp line 223
bool WalletInit::Open() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
return true;
}
for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
if (!pwallet) {
return false;
}
AddWallet(pwallet);
}
return true;
}
主要是从命令行中读取-wallet
变量,也就是代表着钱包的路径,然后创建对应的钱包,最后通过AddWallet()
函数将创建的钱包添加到wallet/wallet.cpp
中的静态变量vpwallets
中去,用来将所有的钱包作统一的维护。
// if pruning, unset the service bit and perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (fPruneMode) {
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
uiInterface.InitMessage(_("Pruning blockstore..."));
PruneAndFlush();
}
}
if (chainparams.GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
// Only advertise witness capabilities if they have a reasonable start time.
// This allows us to have the code merged without a defined softfork, by setting its
// end time to 0.
// Note that setting NODE_WITNESS is never required: the only downside from not
// doing so is that after activation, no upgraded nodes will fetch from you.
nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
}
在第10步当中,首先判断是否处于剪枝模式,如果是,那么就去掉nLocalServices
中的NODE_NETWORK
符号位,关于这个符号位的解释为(位于protocol.h line 250
)
NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
如果设置了该符号位,那么表示该节点可以向外提供完整的区块链服务,目前所有的Bitcoin core节点在非剪枝模式下都会设置该符号位,而SPV节点或者其他轻量级节点则不会设置该符号位。
解释也很明显,如果设置了剪枝,那么就相当于删除了区块链中的一些数据,自然也就无法作为全节点向外提供服务。
继续往下看,如果在剪枝模式下,并且没有设置重建索引,那么就根据参数执行剪枝操作并更新索引,也就是对应PruneAndFlush()
这个函数。而最后一个条件语句则比较明显,判断是否启用了隔离见证,如果启用了,那么就在nLocalServices
对应的位置设置标记。