X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Frpcdump.cpp;h=756863c9c8f19d04be4703e0698e7724e3d110d2;hp=b0284f90402b1bd1e59d784656d7d40ff5a5acf9;hb=7124035567b03ca15027318b75f3a398ae7b4d89;hpb=dfd0524d74a0970a7cbcc110b3c1b42e89deb32f diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index b0284f9..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,77 +14,11 @@ using namespace std; void EnsureWalletIsUnlocked(); -namespace bt = boost::posix_time; - -// Extended DecodeDumpTime implementation, see this page for details: -// http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost -const std::locale formats[] = { - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%dT%H:%M:%SZ")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d")) -}; - -const size_t formats_n = sizeof(formats)/sizeof(formats[0]); - -std::time_t pt_to_time_t(const bt::ptime& pt) -{ - bt::ptime timet_start(boost::gregorian::date(1970,1,1)); - bt::time_duration diff = pt - timet_start; - return diff.ticks()/bt::time_duration::rep_type::ticks_per_second; -} - -int64 DecodeDumpTime(const std::string& s) -{ - bt::ptime pt; - - for(size_t i=0; i> pt; - if(pt != bt::ptime()) break; - } - - return pt_to_time_t(pt); -} - -std::string static EncodeDumpTime(int64 nTime) { - return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); -} - -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; @@ -108,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); @@ -128,107 +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 fCompressed; - CKey key; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); - CKeyID keyid = key.GetPubKey().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) { @@ -243,7 +216,7 @@ Value dumpprivkey(const Array& params, bool fHelp) 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)) @@ -255,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"); + + return Value::null; +} + +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"); - std::map mapKeyBirth; + EnsureWalletIsUnlocked(); - std::set setKeyPool; + CMalleableKey mKey; + CMalleableKeyView keyView; + keyView.SetString(params[0].get_str()); - pwalletMain->GetKeyBirthTimes(mapKeyBirth); + if (!pwalletMain->GetMalleableKey(keyView, mKey)) + throw runtime_error("There is no such item in the wallet"); - pwalletMain->GetAllReserveKeys(setKeyPool); + Object result; + result.push_back(Pair("PrivatePair", mKey.ToString())); + result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString())); - // 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()); - } - } + 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; }