比特币源码解析(25) - 可执行程序 - Bitcoind

0x01 Step 8:Start indexer

分析完了第七步,下面我们继续来看第八步的内容。

// ********************************************************* 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的实现中我们可以看出只实现了BlockConnectedChainStateFlushed这两个函数,其他没有实现的函数对应的指针为空。而在代码中先调用RegisterValidationInterface的原因是,避免在Init执行的过程中有新的事件发生,但是没有调用对应的回调函数,m_synced的状态也就没有更新,但是Init最后还是将此值设置为true,所以就导致了状态的不一致。

Start函数的最后一步,创建了一个线程,去执行TraceThread这个函数,但这个函数中主要还是执行了参数中的ThreadSync函数,而这个函数的主要功能就是从当前主链中同步索引信息到索引文件中,实现中就是通过一个while循环,从当前的m_best_block_index开始,直到主链中最新的区块。

0x02 Step 9: Load Wallet

// ********************************************************* 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中去,用来将所有的钱包作统一的维护。

Step 10: Data Directory Maintenance

// 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对应的位置设置标记。

你可能感兴趣的:(比特币源码分析,比特币,区块链,源码分析)