比特币 RPC 命令「importprivkey」
importprivkey "bitcoinprivkey" ( "label" rescan ) 添加一个私钥(由 dumpprivkey 返回)到你的钱包。 参数: 1. "bitcoinprivkey"(字符串,必备)私钥(见 dumpprivkey) 2. label (字符串,可选,默认为 "")一个可选的标签 3. rescan (布尔型,可选,默认为 true)重新扫描钱包交易 注:如果 rescan 为 true 那么这个调用可能花费数分钟来完成。 结果:无返回值。 例子: 导出一个私钥 > bitcoin-cli dumpprivkey "myaddress" 导入私钥并重新扫描 > bitcoin-cli importprivkey "mykey" 用一个标签导入并不重新扫描 $ bitcoin-cli importprivkey "mykey" "testing" false 作为一个 JSON-RPC 调用 > curl --user myusername:mypassword --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "importprivkey", "params": ["mykey", "testing", false] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
源码剖析
importprivkey
对应的函数在文件 rpcserver.h
中被引用。
extern UniValue importprivkey(const UniValue& params, bool fHelp);
实现在文件 wallet/rpcdump.cpp
中。
UniValue importprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp)) // 1. 确保钱包可用
return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
"importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
"\nArguments:\n"
"1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
"\nExamples:\n"
"\nDump a private key\n"
+ HelpExampleCli("dumpprivkey", "\"myaddress\"") +
"\nImport the private key with rescan\n"
+ HelpExampleCli("importprivkey", "\"mykey\"") +
"\nImport using a label and without rescan\n"
+ HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
); // 2. 帮助内容
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked(); // 3. 确保钱包被解锁
string strSecret = params[0].get_str();
string strLabel = "";
if (params.size() > 1)
strLabel = params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true; // 4. 在导入后是否执行重新扫描
if (params.size() > 2)
fRescan = params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
CKey key = vchSecret.GetKey();
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey)); // 验证公私钥是否配对
CKeyID vchAddress = pubkey.GetID(); // 获取公钥索引
{
pwalletMain->MarkDirty(); // 标记钱包以改变
pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); // 设置地址簿并关联账户指定用途
// Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress)) // 若密钥已存在,不抛出错误
return NullUniValue;
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; // 初始化创建时间为 1
if (!pwalletMain->AddKeyPubKey(key, pubkey)) // 添加公私钥到钱包
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
// whenever a key is imported, we need to scan the whole chain // 无论何时导入密钥,我们都需要扫描整个链
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' // 0 会被当作 '没有价值'
if (fRescan) { // 若开启再扫描
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); // 再扫描整个钱包交易
}
}
return NullUniValue;
}
1. 确保钱包可用
参考比特币 RPC 命令「fundrawtransaction」1. 确保钱包可用。
2. 帮助内容
参考比特币 RPC 命令「getbestblockhash」1. 帮助内容。
4. 在导入后是否执行重新扫描
添加密钥对函数 pwalletMain->AddKeyPubKey(key, pubkey)
定义在文件 keystore.cpp
中。
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore); // 密钥库上锁
mapKeys[pubkey.GetID()] = key; // 加入公钥索引和私钥的映射列表
return true;
}
密钥映射对象 mapKeys
定义在文件 keystore.h
的基础密钥存储类 CBasicKeyStore
中。
typedef std::map<CKeyID, CKey> KeyMap; // 密钥索引和私钥的映射
...
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore // 基础密钥存储,以 address->secret 映射维持私钥
{
protected:
KeyMap mapKeys; // 密钥索引和私钥的映射列表
...
};
扫描钱包交易函数 pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true)
定义在文件 wallet.cpp
中。
/**
* 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.
*/ // 扫描区块链(从 pindexStart 开始)的交易。如果 fUpdate 为 true,在钱包中已存在的找到的交易将会升级。
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{
int ret = 0; // 只要升级了一笔,该值就会 +1
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))) // 若区块时间在钱包创建前 2h
pindex = chainActive.Next(pindex); // 跳过此区块
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) // 若该区块存在
{
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))));
CBlock block;
ReadBlockFromDisk(block, pindex, Params().GetConsensus()); // 从磁盘上读取区块信息
BOOST_FOREACH(CTransaction& tx, block.vtx) // 遍历区块交易列表
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) // 升级该交易
ret++;
}
pindex = chainActive.Next(pindex); // 指向下一块
if (GetTime() >= nNow + 60) { // 时间若超过 60s
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;
}
参考链接
- bitcoin/rpcserver.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/rpcserver.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/rpcdump.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/keystore.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/keystore.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/wallet.cpp at v0.12.1 · bitcoin/bitcoin
- bitcoin/init.h at v0.12.1 · bitcoin/bitcoin
- bitcoin/init.cpp at v0.12.1 · bitcoin/bitcoin