$ bitcoin-cli help dumpprivkey
dumpprivkey "bitcoinaddress"

显示 'bitcoinaddress' 对应的私钥。
然后 importprivkey 可以使用这个输出

参数:
1. "bitcoinaddress"(字符串,必备)私钥对应的比特币地址

结果:
"key"(字符串)私钥

例子:
> bitcoin-cli dumpprivkey "myaddress"
> bitcoin-cli importprivkey "mykey"
> curl --user myusername:mypassword --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "dumpprivkey", "params": ["myaddress"] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

源码剖析

dumpprivkey 对应的函数在文件 rpcserver.h 中被引用。

extern UniValue dumpprivkey(const UniValue& params, bool fHelp);

实现在文件 wallet/rpcdump.cpp 中。

UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
    if (!EnsureWalletIsAvailable(fHelp)) // 1. 确保钱包可用
        return NullUniValue;
    
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "dumpprivkey \"bitcoinaddress\"\n"
            "\nReveals the private key corresponding to 'bitcoinaddress'.\n"
            "Then the importprivkey can be used with this output\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"   (string, required) The bitcoin address for the private key\n"
            "\nResult:\n"
            "\"key\"                (string) The private key\n"
            "\nExamples:\n"
            + HelpExampleCli("dumpprivkey", "\"myaddress\"")
            + HelpExampleCli("importprivkey", "\"mykey\"")
            + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
        ); // 2. 帮助内容

    LOCK2(cs_main, pwalletMain->cs_wallet);

    EnsureWalletIsUnlocked(); // 3. 确保钱包解锁

    string strAddress = params[0].get_str(); // 4. 获取地址对应的私钥
    CBitcoinAddress address;
    if (!address.SetString(strAddress)) // 初始化一个比特币地址对象
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
    CKeyID keyID;
    if (!address.GetKeyID(keyID)) // 获取该地址的索引
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
    CKey vchSecret;
    if (!pwalletMain->GetKey(keyID, vchSecret)) // 通过索引获取对应的私钥
        throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
    return CBitcoinSecret(vchSecret).ToString(); // 对私钥进行 Base58 编码并返回结果
}

1. 确保钱包可用

参考比特币 RPC 命令「fundrawtransaction」1. 确保钱包可用

2. 帮助内容

参考比特币 RPC 命令「getbestblockhash」1. 帮助内容

3. 确保钱包解锁

4. 获取地址对应的私钥

函数 address.SetString(strAddress) 声明在文件 base58.h 的比特币地址类 CBitcoinAddress 中。

/**
 * Base class for all base58-encoded data
 */
class CBase58Data // 所有 base58 编码数据的基类
{
protected:
    //! the version byte(s)
    std::vector<unsigned char> vchVersion; // 对于公钥地址,对应公钥地址前缀

    //! the actually encoded data
    typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
    vector_uchar vchData; // 实际编码后的数据
    ...
    bool SetString(const char* psz, unsigned int nVersionBytes = 1); // 使用 C 风格字符串初始化数据
    bool SetString(const std::string& str); // 调用上面的重载函数
    ...
};

实现在文件 base58.cpp 中。

bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
{
    std::vector<unsigned char> vchTemp;
    bool rc58 = DecodeBase58Check(psz, vchTemp); // 解码 Base58 编码
    if ((!rc58) || (vchTemp.size() < nVersionBytes)) { // 解码失败 或 解码后的数据小于 1 个字节
        vchData.clear(); // 清空数据
        vchVersion.clear(); // 清空版本号
        return false; // 设置失败
    }
    vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); // 验证版本号
    vchData.resize(vchTemp.size() - nVersionBytes); // 重置大小为数据总大小 - 1 个字节的版本号,并初始化为 0
    if (!vchData.empty()) // 非空(全为 0)
        memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); // 复制除版本号的数据
    memory_cleanse(&vchTemp[0], vchData.size()); // 清空数据(保留了最后一个字节?)
    return true;
}

bool CBase58Data::SetString(const std::string& str)
{
    return SetString(str.c_str()); // 转调上面的重载函数
}

获取密钥索引函数 address.GetKeyID(keyID) 定义在文件 base58.cpp 中。

bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
{
    if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) // 地址有效 且 版本号正确
        return false;
    uint160 id;
    memcpy(&id, &vchData[0], 20); // 获取前 20 个字节
    keyID = CKeyID(id); // 初始化公钥索引对象
    return true;
}

参考链接