X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Frpcdump.cpp;h=756863c9c8f19d04be4703e0698e7724e3d110d2;hp=a5a2dad218ce495ad764e9ea2a36dd4cd1af3f37;hb=7124035567b03ca15027318b75f3a398ae7b4d89;hpb=ac92f740d9fe40de422e8446aa514a254f250f27 diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index a5a2dad..756863c 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -2,19 +2,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - #include "init.h" // for pwalletMain #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" -#include -#include -#include -#include - #define printf OutputDebugStringF using namespace json_spirit; @@ -22,54 +14,11 @@ using namespace std; void EnsureWalletIsUnlocked(); -std::string static EncodeDumpTime(int64 nTime) { - return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); -} - -int64 static DecodeDumpTime(const std::string &str) { - static const boost::posix_time::time_input_facet facet("%Y-%m-%dT%H:%M:%SZ"); - static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0); - const std::locale loc(std::locale::classic(), &facet); - std::istringstream iss(str); - iss.imbue(loc); - boost::posix_time::ptime ptime(boost::date_time::not_a_date_time); - iss >> ptime; - if (ptime.is_not_a_date_time()) - return 0; - return (ptime - epoch).total_seconds(); -} - -std::string static EncodeDumpString(const std::string &str) { - std::stringstream ret; - BOOST_FOREACH(unsigned char c, str) { - if (c <= 32 || c >= 128 || c == '%') { - ret << '%' << HexStr(&c, &c + 1); - } else { - ret << c; - } - } - return ret.str(); -} - -std::string DecodeDumpString(const std::string &str) { - std::stringstream ret; - for (unsigned int pos = 0; pos < str.length(); pos++) { - unsigned char c = str[pos]; - if (c == '%' && pos+2 < str.length()) { - c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | - ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15)); - pos += 2; - } - ret << c; - } - return ret.str(); -} - class CTxDump { public: CBlockIndex *pindex; - int64 nValue; + int64_t nValue; bool fSpent; CWalletTx* ptx; int nOut; @@ -85,15 +34,23 @@ public: Value importprivkey(const Array& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( - "importprivkey [label]\n" + "importprivkey [label] [rescan=true]\n" "Adds a private key (as returned by dumpprivkey) to your wallet."); + EnsureWalletIsUnlocked(); + 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; + if (params.size() > 2) + fRescan = params[2].get_bool(); + CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(strSecret); @@ -105,106 +62,146 @@ Value importprivkey(const Array& params, bool fHelp) bool fCompressed; CSecret secret = vchSecret.GetSecret(fCompressed); key.SetSecret(secret, fCompressed); - CKeyID vchAddress = key.GetPubKey().GetID(); + CKeyID keyid = key.GetPubKey().GetID(); + CBitcoinAddress addr = CBitcoinAddress(keyid); { LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBookName(vchAddress, strLabel); + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(keyid)) + return Value::null; + pwalletMain->mapKeyMetadata[addr].nCreateTime = 1; if (!pwalletMain->AddKey(key)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); - pwalletMain->ReacceptWalletTransactions(); + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBookName(addr, strLabel); + + if (fRescan) + { + // whenever a key is imported, we need to scan the whole chain + pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' + + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); + } } return Value::null; } -Value importwallet(const Array& params, bool fHelp) +Value importaddress(const Array& params, bool fHelp) { - if (fHelp || params.size() != 1) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( - "importwallet \n" - "Imports keys from a wallet dump file (see dumpwallet)."); + "importaddress
[label] [rescan=true]\n" + "Adds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend."); + + CScript script; + CBitcoinAddress address(params[0].get_str()); + if (address.IsValid()) { + if (address.IsPair()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "It's senseless to import pubkey pair address."); + script.SetAddress(address); + } else if (IsHex(params[0].get_str())) { + std::vector data(ParseHex(params[0].get_str())); + script = CScript(data.begin(), data.end()); + } else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Novacoin address or script"); - EnsureWalletIsUnlocked(); + string strLabel = ""; + if (params.size() > 1) + strLabel = params[1].get_str(); - ifstream file; - file.open(params[0].get_str().c_str()); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - - int64 nTimeBegin = pindexBest->nTime; - - bool fGood = true; - - while (file.good()) { - std::string line; - std::getline(file, line); - if (line.empty() || line[0] == '#') - continue; - - std::vector vstr; - boost::split(vstr, line, boost::is_any_of(" ")); - if (vstr.size() < 2) - continue; - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) - continue; - bool isCompressed; - CKey key; - CSecret secret = vchSecret.GetSecret(isCompressed); - key.SetSecret(secret, isCompressed); - CPubKey pubkey = key.GetPubKey(); - CKeyID keyid = pubkey.GetID(); - if (pwalletMain->HaveKey(keyid)) { - printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str()); - continue; - } - int64 nTime = DecodeDumpTime(vstr[1]); - std::string strLabel; - bool fLabel = true; - for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { - if (boost::algorithm::starts_with(vstr[nStr], "#")) - break; - if (vstr[nStr] == "change=1") - fLabel = false; - if (vstr[nStr] == "reserve=1") - fLabel = false; - if (boost::algorithm::starts_with(vstr[nStr], "label=")) { - strLabel = DecodeDumpString(vstr[nStr].substr(6)); - fLabel = true; - } - } - printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str()); - if (!pwalletMain->AddKey(key)) { - fGood = false; - continue; + // Whether to perform rescan after import + bool fRescan = true; + if (params.size() > 2) + fRescan = params[2].get_bool(); + + { + LOCK2(cs_main, pwalletMain->cs_wallet); + if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); + + // Don't throw error in case an address is already there + if (pwalletMain->HaveWatchOnly(script)) + return Value::null; + + pwalletMain->MarkDirty(); + + if (address.IsValid()) + pwalletMain->SetAddressBookName(address, strLabel); + + if (!pwalletMain->AddWatchOnly(script)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + + if (fRescan) + { + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwalletMain->SetAddressBookName(keyid, strLabel); - nTimeBegin = std::min(nTimeBegin, nTime); } - file.close(); - CBlockIndex *pindex = pindexBest; - while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) - pindex = pindex->pprev; + return Value::null; +} + +Value removeaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "removeaddress 'address'\n" + "\nRemoves watch-only address or script (in hex) added by importaddress.\n" + "\nArguments:\n" + "1. 'address' (string, required) The address\n" + "\nExamples:\n" + "\nremoveaddress 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n" + "\nRemove watch-only address 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n"); + + CScript script; + + CBitcoinAddress address(params[0].get_str()); + if (address.IsValid()) { + if (address.IsPair()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey pair addresses aren't supported."); + script.SetAddress(address); + } else if (IsHex(params[0].get_str())) { + std::vector data(ParseHex(params[0].get_str())); + script = CScript(data.begin(), data.end()); + } else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); + + if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet contains the private key for this address or script - can't remove it"); + + if (!pwalletMain->HaveWatchOnly(script)) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet does not contain this address or script"); + + LOCK2(cs_main, pwalletMain->cs_wallet); - printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1); - pwalletMain->ScanForWalletTransactions(pindex); - pwalletMain->ReacceptWalletTransactions(); pwalletMain->MarkDirty(); - if (!fGood) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + if (!pwalletMain->RemoveWatchOnly(script)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error removing address from wallet"); return Value::null; } +Value importwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "importwallet \n" + "Imports keys from a wallet dump file (see dumpwallet)." + + HelpRequiringPassphrase()); + + EnsureWalletIsUnlocked(); + + if(!ImportWallet(pwalletMain, params[0].get_str().c_str())) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + + return Value::null; +} Value dumpprivkey(const Array& params, bool fHelp) { @@ -213,11 +210,13 @@ Value dumpprivkey(const Array& params, bool fHelp) "dumpprivkey \n" "Reveals the private key corresponding to ."); + EnsureWalletIsUnlocked(); + string strAddress = params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - if (fWalletUnlockMintOnly) // ppcoin: no dumpprivkey in mint-only mode + if (fWalletUnlockMintOnly) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); CKeyID keyID; if (!address.GetKeyID(keyID)) @@ -229,64 +228,98 @@ Value dumpprivkey(const Array& params, bool fHelp) return CBitcoinSecret(vchSecret, fCompressed).ToString(); } +Value dumppem(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "dumppem \n" + "Dump the key pair corresponding to and store it as encrypted PEM file." + + HelpRequiringPassphrase()); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + SecureString strPassKey; + strPassKey.reserve(100); + strPassKey = params[2].get_str().c_str(); + + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); + if (fWalletUnlockMintOnly) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + if (!pwalletMain->GetPEM(keyID, params[1].get_str(), strPassKey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping key pair to file"); + + return Value::null; +} + Value dumpwallet(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( "dumpwallet \n" - "Dumps all wallet keys in a human-readable format."); + "Dumps all wallet keys in a human-readable format." + + HelpRequiringPassphrase()); EnsureWalletIsUnlocked(); - ofstream file; - file.open(params[0].get_str().c_str()); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + if(!DumpWallet(pwalletMain, params[0].get_str().c_str() )) + throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping wallet keys to file"); - std::map mapKeyBirth; + return Value::null; +} - std::set setKeyPool; +Value dumpmalleablekey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error ( + "dumpmalleablekey \n" + "Dump the private and public key pairs, which correspond to provided key view.\n"); - pwalletMain->GetKeyBirthTimes(mapKeyBirth); + EnsureWalletIsUnlocked(); - pwalletMain->GetAllReserveKeys(setKeyPool); + CMalleableKey mKey; + CMalleableKeyView keyView; + keyView.SetString(params[0].get_str()); - // sort time/key pairs - std::vector > vKeyBirth; - for (std::map::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { - vKeyBirth.push_back(std::make_pair(it->second, it->first)); - } - mapKeyBirth.clear(); - std::sort(vKeyBirth.begin(), vKeyBirth.end()); - - // produce output - file << strprintf("# Wallet dump created by NovaCoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str()); - file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str()); - file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str()); - file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str()); - file << "\n"; - for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { - const CKeyID &keyid = it->second; - std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); - bool IsCompressed; - - CKey key; - if (pwalletMain->GetKey(keyid, key)) { - if (pwalletMain->mapAddressBook.count(keyid)) { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), EncodeDumpString(pwalletMain->mapAddressBook[keyid]).c_str(), strAddr.c_str()); - } else if (setKeyPool.count(keyid)) { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str()); - } else { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str()); - } - } + if (!pwalletMain->GetMalleableKey(keyView, mKey)) + throw runtime_error("There is no such item in the wallet"); + + Object result; + result.push_back(Pair("PrivatePair", mKey.ToString())); + result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString())); + + return result; +} + +Value importmalleablekey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error ( + "importmalleablekey \n" + "Imports the private key pair into your wallet.\n"); + + + EnsureWalletIsUnlocked(); + + CMalleableKey mKey; + bool fSuccess = mKey.SetString(params[0].get_str()); + + Object result; + + if (fSuccess) + { + fSuccess = pwalletMain->AddKey(mKey); + result.push_back(Pair("Successful", fSuccess)); + result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString())); + result.push_back(Pair("KeyView", CMalleableKeyView(mKey).ToString())); } - file << "\n"; - file << "# End of dump\n"; - file.close(); - return Value::null; + else + result.push_back(Pair("Successful", false)); + + return result; }