1 // Copyright (c) 2009-2012 Bitcoin Developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
8 #include "init.h" // for pwalletMain
9 #include "bitcoinrpc.h"
10 #include "ui_interface.h"
13 #include <boost/lexical_cast.hpp>
14 #include <boost/date_time/posix_time/posix_time.hpp>
15 #include <boost/variant/get.hpp>
16 #include <boost/algorithm/string.hpp>
18 #define printf OutputDebugStringF
20 using namespace json_spirit;
23 void EnsureWalletIsUnlocked();
25 std::string static EncodeDumpTime(int64 nTime) {
26 return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
29 int64 static DecodeDumpTime(const std::string &str) {
30 static const boost::posix_time::time_input_facet facet("%Y-%m-%dT%H:%M:%SZ");
31 static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
32 const std::locale loc(std::locale::classic(), &facet);
33 std::istringstream iss(str);
35 boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
37 if (ptime.is_not_a_date_time())
39 return (ptime - epoch).total_seconds();
42 std::string static EncodeDumpString(const std::string &str) {
43 std::stringstream ret;
44 BOOST_FOREACH(unsigned char c, str) {
45 if (c <= 32 || c >= 128 || c == '%') {
46 ret << '%' << HexStr(&c, &c + 1);
54 std::string DecodeDumpString(const std::string &str) {
55 std::stringstream ret;
56 for (unsigned int pos = 0; pos < str.length(); pos++) {
57 unsigned char c = str[pos];
58 if (c == '%' && pos+2 < str.length()) {
59 c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
60 ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
76 CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
86 Value importprivkey(const Array& params, bool fHelp)
88 if (fHelp || params.size() < 1 || params.size() > 2)
90 "importprivkey <novacoinprivkey> [label]\n"
91 "Adds a private key (as returned by dumpprivkey) to your wallet.");
93 string strSecret = params[0].get_str();
95 if (params.size() > 1)
96 strLabel = params[1].get_str();
97 CBitcoinSecret vchSecret;
98 bool fGood = vchSecret.SetString(strSecret);
100 if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
101 if (fWalletUnlockMintOnly) // ppcoin: no importprivkey in mint-only mode
102 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
106 CSecret secret = vchSecret.GetSecret(fCompressed);
107 key.SetSecret(secret, fCompressed);
108 CKeyID vchAddress = key.GetPubKey().GetID();
110 LOCK2(cs_main, pwalletMain->cs_wallet);
112 pwalletMain->MarkDirty();
113 pwalletMain->SetAddressBookName(vchAddress, strLabel);
115 if (!pwalletMain->AddKey(key))
116 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
118 pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
119 pwalletMain->ReacceptWalletTransactions();
125 Value importwallet(const Array& params, bool fHelp)
127 if (fHelp || params.size() != 1)
129 "importwallet <filename>\n"
130 "Imports keys from a wallet dump file (see dumpwallet).");
132 EnsureWalletIsUnlocked();
135 file.open(params[0].get_str().c_str());
137 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
139 int64 nTimeBegin = pindexBest->nTime;
143 while (file.good()) {
145 std::getline(file, line);
146 if (line.empty() || line[0] == '#')
149 std::vector<std::string> vstr;
150 boost::split(vstr, line, boost::is_any_of(" "));
153 CBitcoinSecret vchSecret;
154 if (!vchSecret.SetString(vstr[0]))
158 CSecret secret = vchSecret.GetSecret(isCompressed);
159 key.SetSecret(secret, isCompressed);
160 CPubKey pubkey = key.GetPubKey();
161 CKeyID keyid = pubkey.GetID();
162 if (pwalletMain->HaveKey(keyid)) {
163 printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str());
166 int64 nTime = DecodeDumpTime(vstr[1]);
167 std::string strLabel;
169 for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
170 if (boost::algorithm::starts_with(vstr[nStr], "#"))
172 if (vstr[nStr] == "change=1")
174 if (vstr[nStr] == "reserve=1")
176 if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
177 strLabel = DecodeDumpString(vstr[nStr].substr(6));
181 printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str());
182 if (!pwalletMain->AddKey(key)) {
186 pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
188 pwalletMain->SetAddressBookName(keyid, strLabel);
189 nTimeBegin = std::min(nTimeBegin, nTime);
193 CBlockIndex *pindex = pindexBest;
194 while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
195 pindex = pindex->pprev;
197 printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1);
198 pwalletMain->ScanForWalletTransactions(pindex);
199 pwalletMain->ReacceptWalletTransactions();
200 pwalletMain->MarkDirty();
203 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
209 Value dumpprivkey(const Array& params, bool fHelp)
211 if (fHelp || params.size() != 1)
213 "dumpprivkey <novacoinaddress>\n"
214 "Reveals the private key corresponding to <novacoinaddress>.");
216 string strAddress = params[0].get_str();
217 CBitcoinAddress address;
218 if (!address.SetString(strAddress))
219 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
220 if (fWalletUnlockMintOnly) // ppcoin: no dumpprivkey in mint-only mode
221 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
223 if (!address.GetKeyID(keyID))
224 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
227 if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
228 throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
229 return CBitcoinSecret(vchSecret, fCompressed).ToString();
232 Value dumpwallet(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 1)
236 "dumpwallet <filename>\n"
237 "Dumps all wallet keys in a human-readable format.");
239 EnsureWalletIsUnlocked();
242 file.open(params[0].get_str().c_str());
244 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
246 std::map<CKeyID, int64> mapKeyBirth;
248 std::set<CKeyID> setKeyPool;
250 pwalletMain->GetKeyBirthTimes(mapKeyBirth);
252 pwalletMain->GetAllReserveKeys(setKeyPool);
254 // sort time/key pairs
255 std::vector<std::pair<int64, CKeyID> > vKeyBirth;
256 for (std::map<CKeyID, int64>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
257 vKeyBirth.push_back(std::make_pair(it->second, it->first));
260 std::sort(vKeyBirth.begin(), vKeyBirth.end());
263 file << strprintf("# Wallet dump created by NovaCoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str());
264 file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str());
265 file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str());
266 file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str());
268 for (std::vector<std::pair<int64, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
269 const CKeyID &keyid = it->second;
270 std::string strTime = EncodeDumpTime(it->first);
271 std::string strAddr = CBitcoinAddress(keyid).ToString();
275 if (pwalletMain->GetKey(keyid, key)) {
276 if (pwalletMain->mapAddressBook.count(keyid)) {
277 CSecret secret = key.GetSecret(IsCompressed);
278 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());
279 } else if (setKeyPool.count(keyid)) {
280 CSecret secret = key.GetSecret(IsCompressed);
281 file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str());
283 CSecret secret = key.GetSecret(IsCompressed);
284 file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str());
289 file << "# End of dump\n";