从这里开始就我自己瞎写了
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
if (fDisableWallet) {
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
} else {
CWallet::InitLoadWallet();
if (!pwalletMain)
return false;
}
#else // ENABLE_WALLET
LogPrintf("No wallet support compiled in!\n");
#endif // !ENABLE_WALLET
如果未启用宏定义或者禁用钱包,则不加载钱包功能。CWallet是密钥库的扩展,它还维护一组交易和余额,并提供创建新事务的能力。
//src/wallet/wallet.h
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static bool InitLoadWallet();
InitLoadWallet()
的具体实现在wallet.cpp
,比较长分段来说
如果设置了zapwallettxes那么需要恢复钱包交易的元数据
bool CWallet::InitLoadWallet()
{
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
CWallet *tempWallet = new CWallet(walletFile);
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
}
delete tempWallet;
tempWallet = NULL;
}
这里使用到函数ZapWalletTx
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
if (!fFileBacked)
return DB_LOAD_OK;
DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
{
LOCK(cs_wallet);
setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
if (nZapWalletTxRet != DB_LOAD_OK)
return nZapWalletTxRet;
return DB_LOAD_OK;
}
可以看到这个函数是通过CWalletDB
类对象的ZapWalletTx()
清除交易的。CWalletDB
类是对钱包数据进行封装的操作类,继承自CDB,CDB是对berkeley数据库操作的封装
Berkeley DB (DB)是一个高性能的,嵌入数据库编程库,和C语言,C++,Java,Perl,Python,PHP,Tcl以及其他很多语言都有绑定。Berkeley DB可以保存任意类型的键/值对,而且可以为一个键保存多个数据。Berkeley DB可以支持数千的并发线程同时操作数据库,支持最大256TB的数据,广泛用于各种操作系统包括大多数Unix类操作系统和Windows操作系统以及实时操作系统。
继续去看CWalletDB.ZapWalletTx()
DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
vector<uint256> vTxHash;
DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
if (err != DB_LOAD_OK)
return err;
// erase each wallet TX
BOOST_FOREACH (uint256& hash, vTxHash) {
if (!EraseTx(hash))
return DB_CORRUPT;
}
return DB_LOAD_OK;
}
这个函数调用FindWalletTx()
查找钱包的交易的数据并存储在vTxHash
中,最后调用EraseTx()
函数清除了所有的交易。
new CWallet新建一个钱包对象,通过调用LoadWallet下载钱包数据,如果加载失败则报相应错误。
uiInterface.InitMessage(_("Loading wallet..."));
int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
CWallet *walletInstance = new CWallet(walletFile);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."),
walletFile));
}
else if (nLoadWalletRet == DB_TOO_NEW)
return InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"),
walletFile, _(PACKAGE_NAME)));
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
return InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
}
else
return InitError(strprintf(_("Error loading %s"), walletFile));
}
if (GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = CLIENT_VERSION;
walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
}
else
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion())
{
return InitError(_("Cannot downgrade wallet"));
}
walletInstance->SetMaxVersion(nMaxVersion);
}
根据是否设置-upgradewallet
这个参数进行钱包升级,代码逻辑为首先获取-upgradewallet
设置的版本参数,如果没有设置(0),那么版本设置为当前版本,低于当前版本则打印提示信息,通过调用SetMaxVersion升级。这里了解下版本号
//clientversion.h
static const int CLIENT_VERSION =
1000000 * CLIENT_VERSION_MAJOR
+ 10000 * CLIENT_VERSION_MINOR
+ 100 * CLIENT_VERSION_REVISION
+ 1 * CLIENT_VERSION_BUILD;
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0 //主版本号
#define CLIENT_VERSION_MINOR 13 //次版本号
#define CLIENT_VERSION_REVISION 2 //修订版本号
#define CLIENT_VERSION_BUILD 0 //构建版本号
if (fFirstRun)
{
// Create new keyUser and set as default key
if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) {
// generate a new master key
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
if (!walletInstance->SetHDMasterKey(masterPubKey))
throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
}
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
walletInstance->SetDefaultKey(newDefaultKey);
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
return InitError(_("Cannot write default address") += "\n");
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
else if (mapArgs.count("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
if (!walletInstance->hdChain.masterKeyID.IsNull() && !useHD)
return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
if (walletInstance->hdChain.masterKeyID.IsNull() && useHD)
return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
}
-usehd:Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start
-usehd
参数代表使用BIP32
之后的分层确定性密钥生成(HD)。 仅在钱包创建/首次启动时有效
如果设置了-usehd
,那么会调用GenerateNewHDMasterKey来生成master key,返回类型为公钥
CPubKey CWallet::GenerateNewHDMasterKey()
{
CKey key;
key.MakeNewKey(true);
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// calculate the pubkey
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
// set the hd keypath to "m" -> Master, refers the masterkeyid to itself
metadata.hdKeypath = "m";
metadata.hdMasterKeyID = pubkey.GetID();
{
LOCK(cs_wallet);
// mem store the metadata
mapKeyMetadata[pubkey.GetID()] = metadata;
// write the key&metadata to the database
if (!AddKeyPubKey(key, pubkey))
throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
}
return pubkey;
}
这个函数是调用CKey
类的MakeNewKey
来生成公钥,关于MakeNewKey()函数之前的代码有介绍过,后面是给这个公钥标记为Master
,添加到CKey
中。
若未设置分层确定性密钥方式,则从密钥池中得到一个公钥,并设置为默认的公钥,最后通过CPubkey
对象的GetID()
生成比特币地址并调用SetAddressBook()
函数记录下来。
//! Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const
{
return CKeyID(Hash160(vch, vch + size()));
}
比特币地址是使用hash160加密算法得到,hash160就是我们说的双哈希,也就是RIPEMD160(SHA256),关于这两个单向散列函数的具体介绍参考书籍。
//注册钱包接口,是signal对象实现对钱包数据的各种侦听处理
RegisterValidationInterface(walletInstance);
//如果用户设置了rescan参数,则从创世区块开始获取需要重新更新钱包数据的位置
CBlockIndex *pindexRescan = chainActive.Tip();
if (GetBoolArg("-rescan", false))
pindexRescan = chainActive.Genesis();
else
{
CWalletDB walletdb(walletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
else
pindexRescan = chainActive.Genesis();
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
//this might happen if a user uses a old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
/*我们无法重新扫描超出非修剪的块,如果用户在修剪的节点中使用旧钱包 *或者如果他运行-disablewallet更长时间,然后决定重新启用,则可能会发生此错误*/
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();
while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
block = block->pprev;
if (pindexRescan != block)
return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
}
//开始Rescan钱包交易
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
对钱包进行Rescan
处理调用的具体函数是ScanForWalletTransactions
/** * Scan the block chain (starting in pindexStart) for transactions * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. */
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{//1.设置开始查找的区块
int ret = 0;
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
CBlockIndex* pindex = pindexStart;
{
LOCK2(cs_main, cs_wallet);
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);//chainActive存储区块位置信息链
//2.开始区块和结束区块,用于计算进度
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false);
while (pindex)
{//3.计算扫描进度
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
//4.根据pindex读取一个区块的数据放入block中
CBlock block;
ReadBlockFromDisk(block, pindex, Params().GetConsensus());
//5.遍历区块的交易数据
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
//获取下一个区块
if (GetTime() >= nNow + 60) {
nNow = GetTime();
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex));
}
}
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
}
return ret;
}
这个函数的最后还是zapwallettxes参数,恢复钱包交易元数据,前面是删除了内容
// Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
{
CWalletDB walletdb(walletFile);
BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
{
uint256 hash = wtxOld.GetHash();
std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
if (mi != walletInstance->mapWallet.end())
{
const CWalletTx* copyFrom = &wtxOld;
CWalletTx* copyTo = &mi->second;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
copyTo->nTimeReceived = copyFrom->nTimeReceived;
copyTo->nTimeSmart = copyFrom->nTimeSmart;
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
copyTo->nOrderPos = copyFrom->nOrderPos;
walletdb.WriteTx(*copyTo);
}
}
}
}
walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
pwalletMain = walletInstance;
return true;
最后给pwalletMain
赋值为钱包实例,并返回true
.
云里雾里的。。。