implement importelectrumwallet (#1377)

Imports keys from an Electrum wallet export file (.csv or .json)
This commit is contained in:
UdjinM6 2017-03-12 17:42:00 +03:00 committed by Holger Schinzel
parent fb3db0a57e
commit c523205386
4 changed files with 137 additions and 0 deletions

View File

@ -99,6 +99,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "lockunspent", 0 }, { "lockunspent", 0 },
{ "lockunspent", 1 }, { "lockunspent", 1 },
{ "importprivkey", 2 }, { "importprivkey", 2 },
{ "importelectrumwallet", 1 },
{ "importaddress", 2 }, { "importaddress", 2 },
{ "importaddress", 3 }, { "importaddress", 3 },
{ "importpubkey", 2 }, { "importpubkey", 2 },

View File

@ -378,6 +378,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "getwalletinfo", &getwalletinfo, false }, { "wallet", "getwalletinfo", &getwalletinfo, false },
{ "wallet", "importprivkey", &importprivkey, true }, { "wallet", "importprivkey", &importprivkey, true },
{ "wallet", "importwallet", &importwallet, true }, { "wallet", "importwallet", &importwallet, true },
{ "wallet", "importelectrumwallet", &importelectrumwallet, true },
{ "wallet", "importaddress", &importaddress, true }, { "wallet", "importaddress", &importaddress, true },
{ "wallet", "importpubkey", &importpubkey, true }, { "wallet", "importpubkey", &importpubkey, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true }, { "wallet", "keypoolrefill", &keypoolrefill, true },

View File

@ -194,6 +194,7 @@ extern UniValue importaddress(const UniValue& params, bool fHelp);
extern UniValue importpubkey(const UniValue& params, bool fHelp); extern UniValue importpubkey(const UniValue& params, bool fHelp);
extern UniValue dumpwallet(const UniValue& params, bool fHelp); extern UniValue dumpwallet(const UniValue& params, bool fHelp);
extern UniValue importwallet(const UniValue& params, bool fHelp); extern UniValue importwallet(const UniValue& params, bool fHelp);
extern UniValue importelectrumwallet(const UniValue& params, bool fHelp);
extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp
extern UniValue setgenerate(const UniValue& params, bool fHelp); extern UniValue setgenerate(const UniValue& params, bool fHelp);

View File

@ -409,6 +409,140 @@ UniValue importwallet(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
} }
UniValue importelectrumwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"importelectrumwallet \"filename\" index\n"
"\nImports keys from an Electrum wallet export file (.csv or .json)\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The Electrum wallet export file, should be in csv or json format\n"
"2. index (numeric, optional, default=0) Rescan the wallet for transactions starting from this block index\n"
"\nExamples:\n"
"\nImport the wallet\n"
+ HelpExampleCli("importelectrumwallet", "\"test.csv\"")
+ HelpExampleCli("importelectrumwallet", "\"test.json\"") +
"\nImport using the json rpc call\n"
+ HelpExampleRpc("importelectrumwallet", "\"test.csv\"")
+ HelpExampleRpc("importelectrumwallet", "\"test.json\"")
);
if (fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
ifstream file;
std::string strFileName = params[0].get_str();
size_t nDotPos = strFileName.find_last_of(".");
if(nDotPos == string::npos)
throw JSONRPCError(RPC_INVALID_PARAMETER, "File has no extension, should be .json or .csv");
std::string strFileExt = strFileName.substr(nDotPos+1);
if(strFileExt != "json" && strFileExt != "csv")
throw JSONRPCError(RPC_INVALID_PARAMETER, "File has wrong extension, should be .json or .csv");
file.open(strFileName.c_str(), std::ios::in | std::ios::ate);
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open Electrum wallet export file");
bool fGood = true;
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
file.seekg(0, file.beg);
pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
if(strFileExt == "csv") {
while (file.good()) {
pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
std::string line;
std::getline(file, line);
if (line.empty() || line == "address,private_key")
continue;
std::vector<std::string> vstr;
boost::split(vstr, line, boost::is_any_of(","));
if (vstr.size() < 2)
continue;
CBitcoinSecret vchSecret;
if (!vchSecret.SetString(vstr[1]))
continue;
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwalletMain->HaveKey(keyid)) {
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
continue;
}
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
}
}
} else {
// json
char* buffer = new char [nFilesize];
file.read(buffer, nFilesize);
UniValue data(UniValue::VOBJ);
if(!data.read(buffer))
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot parse Electrum wallet export file");
delete[] buffer;
std::vector<std::string> vKeys = data.getKeys();
for (size_t i = 0; i < data.size(); i++) {
pwalletMain->ShowProgress("", std::max(1, std::min(99, int(i*100/data.size()))));
if(!data[vKeys[i]].isStr())
continue;
CBitcoinSecret vchSecret;
if (!vchSecret.SetString(data[vKeys[i]].get_str()))
continue;
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwalletMain->HaveKey(keyid)) {
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
continue;
}
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
}
}
}
file.close();
pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI
// Whether to perform rescan after import
int nStartHeight = 0;
if (params.size() > 1)
nStartHeight = params[1].get_int();
if (chainActive.Height() < nStartHeight)
nStartHeight = chainActive.Height();
// Assume that electrum wallet was created at that block
int nTimeBegin = chainActive[nStartHeight]->GetBlockTime();
if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
pwalletMain->nTimeFirstKey = nTimeBegin;
LogPrintf("Rescanning %i blocks\n", chainActive.Height() - nStartHeight + 1);
pwalletMain->ScanForWalletTransactions(chainActive[nStartHeight], true);
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
return NullUniValue;
}
UniValue dumpprivkey(const UniValue& params, bool fHelp) UniValue dumpprivkey(const UniValue& params, bool fHelp)
{ {
if (!EnsureWalletIsAvailable(fHelp)) if (!EnsureWalletIsAvailable(fHelp))