Anoncoin  0.9.4
P2P Digital Currency
rpcdump.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2014 The Bitcoin developers
2 // Copyright (c) 2013-2014 The Anoncoin Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "base58.h"
7 #include "rpcserver.h"
8 #include "init.h"
9 #include "main.h"
10 #include "sync.h"
11 #include "wallet.h"
12 
13 #include <fstream>
14 #include <stdint.h>
15 
16 #include <boost/algorithm/string.hpp>
17 #include <boost/date_time/posix_time/posix_time.hpp>
18 #include "json/json_spirit_value.h"
19 
20 using namespace json_spirit;
21 using namespace std;
22 
24 
25 std::string static EncodeDumpTime(int64_t nTime) {
26  return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
27 }
28 
29 int64_t static DecodeDumpTime(const std::string &str) {
30  static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
31  static const std::locale loc(std::locale::classic(),
32  new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
33  std::istringstream iss(str);
34  iss.imbue(loc);
35  boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
36  iss >> ptime;
37  if (ptime.is_not_a_date_time())
38  return 0;
39  return (ptime - epoch).total_seconds();
40 }
41 
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);
47  } else {
48  ret << c;
49  }
50  }
51  return ret.str();
52 }
53 
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));
61  pos += 2;
62  }
63  ret << c;
64  }
65  return ret.str();
66 }
67 
68 Value importprivkey(const Array& params, bool fHelp)
69 {
70  if (fHelp || params.size() < 1 || params.size() > 3)
71  throw runtime_error(
72  "importprivkey \"anoncoinprivkey\" ( \"label\" rescan )\n"
73  "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
74  "\nArguments:\n"
75  "1. \"anoncoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
76  "2. \"label\" (string, optional) an optional label\n"
77  "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
78  "\nExamples:\n"
79  "\nDump a private key\n"
80  + HelpExampleCli("dumpprivkey", "\"myaddress\"") +
81  "\nImport the private key\n"
82  + HelpExampleCli("importprivkey", "\"mykey\"") +
83  "\nImport using a label\n"
84  + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
85  "\nAs a json rpc call\n"
86  + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
87  );
88 
90 
91  string strSecret = params[0].get_str();
92  string strLabel = "";
93  if (params.size() > 1)
94  strLabel = params[1].get_str();
95 
96  // Whether to perform rescan after import
97  bool fRescan = true;
98  if (params.size() > 2)
99  fRescan = params[2].get_bool();
100 
101  CAnoncoinSecret vchSecret;
102  bool fGood = vchSecret.SetString(strSecret);
103 
104  if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
105 
106  CKey key = vchSecret.GetKey();
107  if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
108 
109  CPubKey pubkey = key.GetPubKey();
110  CKeyID vchAddress = pubkey.GetID();
111  {
113  pwalletMain->SetAddressBook(vchAddress, strLabel, "receive");
114 
115  // Don't throw error in case a key is already there
116  if (pwalletMain->HaveKey(vchAddress))
117  return Value::null;
118 
119  pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
120 
121  if (!pwalletMain->AddKeyPubKey(key, pubkey))
122  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
123 
124  // whenever a key is imported, we need to scan the whole chain
125  pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
126 
127  if (fRescan) {
129  }
130  }
131 
132  return Value::null;
133 }
134 
135 Value importaddress(const Array& params, bool fHelp)
136 {
137  if (fHelp || params.size() < 1 || params.size() > 3)
138  throw runtime_error(
139  "importaddress <address> [label] [rescan=true]\n"
140  "Adds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.");
141 
142  CScript script;
143 
144  CAnoncoinAddress address(params[0].get_str());
145  if (address.IsValid()) {
146  script.SetDestination(address.Get());
147  } else if (IsHex(params[0].get_str())) {
148  std::vector<unsigned char> data(ParseHex(params[0].get_str()));
149  script = CScript(data.begin(), data.end());
150  } else {
151  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Anoncoin address or script");
152  }
153 
154  string strLabel = "";
155  if (params.size() > 1)
156  strLabel = params[1].get_str();
157 
158  // Whether to perform rescan after import
159  bool fRescan = true;
160  if (params.size() > 2)
161  fRescan = params[2].get_bool();
162 
163  {
164  if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
165  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
166 
167  // add to address book or update label
168  if (address.IsValid())
169  pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
170 
171  // Don't throw error in case an address is already there
172  if (pwalletMain->HaveWatchOnly(script))
173  return Value::null;
174 
176 
177  if (!pwalletMain->AddWatchOnly(script))
178  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
179 
180  if (fRescan)
181  {
184  }
185  }
186 
187  return Value::null;
188 }
189 
190 Value importwallet(const Array& params, bool fHelp)
191 {
192  if (fHelp || params.size() != 1)
193  throw runtime_error(
194  "importwallet \"filename\"\n"
195  "\nImports keys from a wallet dump file (see dumpwallet).\n"
196  "\nArguments:\n"
197  "1. \"filename\" (string, required) The wallet file\n"
198  "\nExamples:\n"
199  "\nDump the wallet\n"
200  + HelpExampleCli("dumpwallet", "\"test\"") +
201  "\nImport the wallet\n"
202  + HelpExampleCli("importwallet", "\"test\"") +
203  "\nImport using the json rpc call\n"
204  + HelpExampleRpc("importwallet", "\"test\"")
205  );
206 
208 
209  ifstream file;
210  file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate);
211  if (!file.is_open())
212  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
213 
214  int64_t nTimeBegin = chainActive.Tip()->nTime;
215 
216  bool fGood = true;
217 
218  int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
219  file.seekg(0, file.beg);
220 
221  pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
222  while (file.good()) {
223  pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
224  std::string line;
225  std::getline(file, line);
226  if (line.empty() || line[0] == '#')
227  continue;
228 
229  std::vector<std::string> vstr;
230  boost::split(vstr, line, boost::is_any_of(" "));
231  if (vstr.size() < 2)
232  continue;
233  CAnoncoinSecret vchSecret;
234  if (!vchSecret.SetString(vstr[0]))
235  continue;
236  CKey key = vchSecret.GetKey();
237  CPubKey pubkey = key.GetPubKey();
238  CKeyID keyid = pubkey.GetID();
239  if (pwalletMain->HaveKey(keyid)) {
240  LogPrintf("Skipping import of %s (key already present)\n", CAnoncoinAddress(keyid).ToString());
241  continue;
242  }
243  int64_t nTime = DecodeDumpTime(vstr[1]);
244  std::string strLabel;
245  bool fLabel = true;
246  for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
247  if (boost::algorithm::starts_with(vstr[nStr], "#"))
248  break;
249  if (vstr[nStr] == "change=1")
250  fLabel = false;
251  if (vstr[nStr] == "reserve=1")
252  fLabel = false;
253  if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
254  strLabel = DecodeDumpString(vstr[nStr].substr(6));
255  fLabel = true;
256  }
257  }
258  LogPrintf("Importing %s...\n", CAnoncoinAddress(keyid).ToString());
259  if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
260  fGood = false;
261  continue;
262  }
263  pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
264  if (fLabel)
265  pwalletMain->SetAddressBook(keyid, strLabel, "receive");
266  nTimeBegin = std::min(nTimeBegin, nTime);
267  }
268  file.close();
269  pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI
270 
271  CBlockIndex *pindex = chainActive.Tip();
272  while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
273  pindex = pindex->pprev;
274 
275  if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
276  pwalletMain->nTimeFirstKey = nTimeBegin;
277 
278  LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
281 
282  if (!fGood)
283  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
284 
285  return Value::null;
286 }
287 
288 Value dumpprivkey(const Array& params, bool fHelp)
289 {
290  if (fHelp || params.size() != 1)
291  throw runtime_error(
292  "dumpprivkey \"anoncoinaddress\"\n"
293  "\nReveals the private key corresponding to 'anoncoinaddress'.\n"
294  "Then the importprivkey can be used with this output\n"
295  "\nArguments:\n"
296  "1. \"anoncoinaddress\" (string, required) The anoncoin address for the private key\n"
297  "\nResult:\n"
298  "\"key\" (string) The private key\n"
299  "\nExamples:\n"
300  + HelpExampleCli("dumpprivkey", "\"myaddress\"")
301  + HelpExampleCli("importprivkey", "\"mykey\"")
302  + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
303  );
304 
306 
307  string strAddress = params[0].get_str();
308  CAnoncoinAddress address;
309  if (!address.SetString(strAddress))
310  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Anoncoin address");
311  CKeyID keyID;
312  if (!address.GetKeyID(keyID))
313  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
314  CKey vchSecret;
315  if (!pwalletMain->GetKey(keyID, vchSecret))
316  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
317  return CAnoncoinSecret(vchSecret).ToString();
318 }
319 
320 
321 Value dumpwallet(const Array& params, bool fHelp)
322 {
323  if (fHelp || params.size() != 1)
324  throw runtime_error(
325  "dumpwallet \"filename\"\n"
326  "\nDumps all wallet keys in a human-readable format.\n"
327  "\nArguments:\n"
328  "1. \"filename\" (string, required) The filename\n"
329  "\nExamples:\n"
330  + HelpExampleCli("dumpwallet", "\"test\"")
331  + HelpExampleRpc("dumpwallet", "\"test\"")
332  );
333 
335 
336  ofstream file;
337  file.open(params[0].get_str().c_str());
338  if (!file.is_open())
339  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
340 
341  std::map<CKeyID, int64_t> mapKeyBirth;
342  std::set<CKeyID> setKeyPool;
343  pwalletMain->GetKeyBirthTimes(mapKeyBirth);
344  pwalletMain->GetAllReserveKeys(setKeyPool);
345 
346  // sort time/key pairs
347  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
348  for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
349  vKeyBirth.push_back(std::make_pair(it->second, it->first));
350  }
351  mapKeyBirth.clear();
352  std::sort(vKeyBirth.begin(), vKeyBirth.end());
353 
354  // produce output
355  file << strprintf("# Wallet dump created by Anoncoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
356  file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
357  file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
358  file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->nTime));
359  file << "\n";
360  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
361  const CKeyID &keyid = it->second;
362  std::string strTime = EncodeDumpTime(it->first);
363  std::string strAddr = CAnoncoinAddress(keyid).ToString();
364  CKey key;
365  if (pwalletMain->GetKey(keyid, key)) {
366  if (pwalletMain->mapAddressBook.count(keyid)) {
367  file << strprintf("%s %s label=%s # addr=%s\n", CAnoncoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
368  } else if (setKeyPool.count(keyid)) {
369  file << strprintf("%s %s reserve=1 # addr=%s\n", CAnoncoinSecret(key).ToString(), strTime, strAddr);
370  } else {
371  file << strprintf("%s %s change=1 # addr=%s\n", CAnoncoinSecret(key).ToString(), strTime, strAddr);
372  }
373  }
374  }
375  file << "\n";
376  file << "# End of dump\n";
377  file.close();
378  return Value::null;
379 }
std::string DecodeDumpString(const std::string &str)
Definition: rpcdump.cpp:54
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey)
Definition: wallet.cpp:72
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:1638
bool HaveKey(const CKeyID &address) const
Definition: crypter.h:159
CBlockIndex * pprev
Definition: main.h:705
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:174
#define strprintf
Definition: tinyformat.h:1011
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
Definition: script.cpp:1450
std::string HelpExampleRpc(string methodname, string args)
Definition: rpcserver.cpp:903
CTxDestination Get() const
Definition: base58.cpp:223
Value importwallet(const Array &params, bool fHelp)
Definition: rpcdump.cpp:190
bool GetKeyID(CKeyID &keyID) const
Definition: base58.cpp:236
int64_t nTimeFirstKey
Definition: wallet.h:180
void GetAllReserveKeys(std::set< CKeyID > &setAddress) const
Definition: wallet.cpp:2030
bool IsHex(const string &str)
Definition: util.cpp:409
Value dumpwallet(const Array &params, bool fHelp)
Definition: rpcdump.cpp:321
virtual bool HaveWatchOnly(const CScript &dest) const
Definition: keystore.cpp:77
Object JSONRPCError(int code, const string &message)
bool AddWatchOnly(const CScript &dest)
Definition: wallet.cpp:155
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const
Definition: wallet.cpp:2097
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: util.cpp:1411
void ReacceptWalletTransactions()
Definition: wallet.cpp:926
bool GetKey(const CKeyID &address, CKey &keyOut) const
Definition: crypter.cpp:212
CChain chainActive
The currently-connected chain of blocks.
Definition: main.cpp:43
Value importprivkey(const Array &params, bool fHelp)
Definition: rpcdump.cpp:68
bool IsValid() const
Definition: base58.cpp:216
void MarkDirty()
Definition: wallet.cpp:512
bool IsValid() const
Definition: key.h:239
void SetDestination(const CTxDestination &address)
Definition: script.cpp:1945
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or NULL if none.
Definition: main.h:1024
int Height() const
Return the maximal height in the chain.
Definition: main.h:1055
unsigned int nTime
Definition: main.h:735
#define LogPrintf(...)
Definition: util.h:118
void EnsureWalletIsUnlocked()
Definition: rpcwallet.cpp:37
CPubKey GetPubKey() const
Definition: key.cpp:397
A base58-encoded secret key.
Definition: base58.h:122
An encapsulated public key.
Definition: key.h:43
base58-encoded Anoncoin addresses.
Definition: base58.h:102
bool SetString(const char *pszSecret)
Definition: base58.cpp:268
std::string ToString() const
Definition: base58.cpp:175
int64_t GetTime()
Definition: util.cpp:1220
const std::string CLIENT_DATE
bool SetString(const char *psz, unsigned int nVersionBytes=1)
Definition: base58.cpp:155
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or NULL if none.
Definition: main.h:1019
int ScanForWalletTransactions(CBlockIndex *pindexStart, bool fUpdate=false)
Definition: wallet.cpp:886
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: main.h:698
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
std::string ToString() const
Definition: uint256.h:341
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: ui_interface.h:125
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:27
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
Definition: wallet.h:139
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
Definition: wallet.h:408
std::string HelpExampleCli(string methodname, string args)
Definition: rpcserver.cpp:899
An encapsulated private key.
Definition: key.h:180
int nHeight
Definition: main.h:708
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
Definition: util.h:256
CKeyID GetID() const
Definition: key.h:132
CKey GetKey()
Definition: base58.cpp:256
vector< unsigned char > ParseHex(const char *psz)
Definition: util.cpp:419
const std::string CLIENT_BUILD
Value importaddress(const Array &params, bool fHelp)
Definition: rpcdump.cpp:135
CWallet * pwalletMain
uint256 GetBlockHash() const
Definition: main.h:815
Value dumpprivkey(const Array &params, bool fHelp)
Definition: rpcdump.cpp:288