Master Core  v0.0.9 - 49a5c0d97abf09ef2911ddfe8d9551df59f9efd3-dirty
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
rpcdump.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2014 The 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.
4 
5 #include "base58.h"
6 #include "rpcserver.h"
7 #include "init.h"
8 #include "main.h"
9 #include "sync.h"
10 #include "wallet.h"
11 
12 #include <fstream>
13 #include <stdint.h>
14 
15 #include <boost/algorithm/string.hpp>
16 #include <boost/date_time/posix_time/posix_time.hpp>
17 #include "json/json_spirit_value.h"
18 
19 using namespace json_spirit;
20 using namespace std;
21 
23 
24 std::string static EncodeDumpTime(int64_t nTime) {
25  return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
26 }
27 
28 int64_t static DecodeDumpTime(const std::string &str) {
29  static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
30  static const std::locale loc(std::locale::classic(),
31  new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
32  std::istringstream iss(str);
33  iss.imbue(loc);
34  boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
35  iss >> ptime;
36  if (ptime.is_not_a_date_time())
37  return 0;
38  return (ptime - epoch).total_seconds();
39 }
40 
41 std::string static EncodeDumpString(const std::string &str) {
42  std::stringstream ret;
43  BOOST_FOREACH(unsigned char c, str) {
44  if (c <= 32 || c >= 128 || c == '%') {
45  ret << '%' << HexStr(&c, &c + 1);
46  } else {
47  ret << c;
48  }
49  }
50  return ret.str();
51 }
52 
53 std::string DecodeDumpString(const std::string &str) {
54  std::stringstream ret;
55  for (unsigned int pos = 0; pos < str.length(); pos++) {
56  unsigned char c = str[pos];
57  if (c == '%' && pos+2 < str.length()) {
58  c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
59  ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
60  pos += 2;
61  }
62  ret << c;
63  }
64  return ret.str();
65 }
66 
67 Value importprivkey(const Array& params, bool fHelp)
68 {
69  if (fHelp || params.size() < 1 || params.size() > 3)
70  throw runtime_error(
71  "importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n"
72  "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
73  "\nArguments:\n"
74  "1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
75  "2. \"label\" (string, optional) an optional label\n"
76  "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
77  "\nExamples:\n"
78  "\nDump a private key\n"
79  + HelpExampleCli("dumpprivkey", "\"myaddress\"") +
80  "\nImport the private key\n"
81  + HelpExampleCli("importprivkey", "\"mykey\"") +
82  "\nImport using a label\n"
83  + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
84  "\nAs a json rpc call\n"
85  + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
86  );
87 
89 
90  string strSecret = params[0].get_str();
91  string strLabel = "";
92  if (params.size() > 1)
93  strLabel = params[1].get_str();
94 
95  // Whether to perform rescan after import
96  bool fRescan = true;
97  if (params.size() > 2)
98  fRescan = params[2].get_bool();
99 
100  CBitcoinSecret vchSecret;
101  bool fGood = vchSecret.SetString(strSecret);
102 
103  if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
104 
105  CKey key = vchSecret.GetKey();
106  if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
107 
108  CPubKey pubkey = key.GetPubKey();
109  CKeyID vchAddress = pubkey.GetID();
110  {
112 
114  pwalletMain->SetAddressBook(vchAddress, strLabel, "receive");
115 
116  // Don't throw error in case a key is already there
117  if (pwalletMain->HaveKey(vchAddress))
118  return Value::null;
119 
120  pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
121 
122  if (!pwalletMain->AddKeyPubKey(key, pubkey))
123  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
124 
125  // whenever a key is imported, we need to scan the whole chain
126  pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
127 
128  if (fRescan) {
130  }
131  }
132 
133  return Value::null;
134 }
135 
136 Value importwallet(const Array& params, bool fHelp)
137 {
138  if (fHelp || params.size() != 1)
139  throw runtime_error(
140  "importwallet \"filename\"\n"
141  "\nImports keys from a wallet dump file (see dumpwallet).\n"
142  "\nArguments:\n"
143  "1. \"filename\" (string, required) The wallet file\n"
144  "\nExamples:\n"
145  "\nDump the wallet\n"
146  + HelpExampleCli("dumpwallet", "\"test\"") +
147  "\nImport the wallet\n"
148  + HelpExampleCli("importwallet", "\"test\"") +
149  "\nImport using the json rpc call\n"
150  + HelpExampleRpc("importwallet", "\"test\"")
151  );
152 
154 
155  ifstream file;
156  file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate);
157  if (!file.is_open())
158  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
159 
160  int64_t nTimeBegin = chainActive.Tip()->nTime;
161 
162  bool fGood = true;
163 
164  int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
165  file.seekg(0, file.beg);
166 
167  pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
168  while (file.good()) {
169  pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
170  std::string line;
171  std::getline(file, line);
172  if (line.empty() || line[0] == '#')
173  continue;
174 
175  std::vector<std::string> vstr;
176  boost::split(vstr, line, boost::is_any_of(" "));
177  if (vstr.size() < 2)
178  continue;
179  CBitcoinSecret vchSecret;
180  if (!vchSecret.SetString(vstr[0]))
181  continue;
182  CKey key = vchSecret.GetKey();
183  CPubKey pubkey = key.GetPubKey();
184  CKeyID keyid = pubkey.GetID();
185  if (pwalletMain->HaveKey(keyid)) {
186  LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
187  continue;
188  }
189  int64_t nTime = DecodeDumpTime(vstr[1]);
190  std::string strLabel;
191  bool fLabel = true;
192  for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
193  if (boost::algorithm::starts_with(vstr[nStr], "#"))
194  break;
195  if (vstr[nStr] == "change=1")
196  fLabel = false;
197  if (vstr[nStr] == "reserve=1")
198  fLabel = false;
199  if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
200  strLabel = DecodeDumpString(vstr[nStr].substr(6));
201  fLabel = true;
202  }
203  }
204  LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
205  if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
206  fGood = false;
207  continue;
208  }
209  pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
210  if (fLabel)
211  pwalletMain->SetAddressBook(keyid, strLabel, "receive");
212  nTimeBegin = std::min(nTimeBegin, nTime);
213  }
214  file.close();
215  pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI
216 
217  CBlockIndex *pindex = chainActive.Tip();
218  while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
219  pindex = pindex->pprev;
220 
221  if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
222  pwalletMain->nTimeFirstKey = nTimeBegin;
223 
224  LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
227 
228  if (!fGood)
229  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
230 
231  return Value::null;
232 }
233 
234 Value dumpprivkey(const Array& params, bool fHelp)
235 {
236  if (fHelp || params.size() != 1)
237  throw runtime_error(
238  "dumpprivkey \"bitcoinaddress\"\n"
239  "\nReveals the private key corresponding to 'bitcoinaddress'.\n"
240  "Then the importprivkey can be used with this output\n"
241  "\nArguments:\n"
242  "1. \"bitcoinaddress\" (string, required) The bitcoin address for the private key\n"
243  "\nResult:\n"
244  "\"key\" (string) The private key\n"
245  "\nExamples:\n"
246  + HelpExampleCli("dumpprivkey", "\"myaddress\"")
247  + HelpExampleCli("importprivkey", "\"mykey\"")
248  + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
249  );
250 
252 
253  string strAddress = params[0].get_str();
254  CBitcoinAddress address;
255  if (!address.SetString(strAddress))
256  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
257  CKeyID keyID;
258  if (!address.GetKeyID(keyID))
259  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
260  CKey vchSecret;
261  if (!pwalletMain->GetKey(keyID, vchSecret))
262  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
263  return CBitcoinSecret(vchSecret).ToString();
264 }
265 
266 
267 Value dumpwallet(const Array& params, bool fHelp)
268 {
269  if (fHelp || params.size() != 1)
270  throw runtime_error(
271  "dumpwallet \"filename\"\n"
272  "\nDumps all wallet keys in a human-readable format.\n"
273  "\nArguments:\n"
274  "1. \"filename\" (string, required) The filename\n"
275  "\nExamples:\n"
276  + HelpExampleCli("dumpwallet", "\"test\"")
277  + HelpExampleRpc("dumpwallet", "\"test\"")
278  );
279 
281 
282  ofstream file;
283  file.open(params[0].get_str().c_str());
284  if (!file.is_open())
285  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
286 
287  std::map<CKeyID, int64_t> mapKeyBirth;
288  std::set<CKeyID> setKeyPool;
289  pwalletMain->GetKeyBirthTimes(mapKeyBirth);
290  pwalletMain->GetAllReserveKeys(setKeyPool);
291 
292  // sort time/key pairs
293  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
294  for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
295  vKeyBirth.push_back(std::make_pair(it->second, it->first));
296  }
297  mapKeyBirth.clear();
298  std::sort(vKeyBirth.begin(), vKeyBirth.end());
299 
300  // produce output
301  file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
302  file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
303  file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
304  file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->nTime));
305  file << "\n";
306  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
307  const CKeyID &keyid = it->second;
308  std::string strTime = EncodeDumpTime(it->first);
309  std::string strAddr = CBitcoinAddress(keyid).ToString();
310  CKey key;
311  if (pwalletMain->GetKey(keyid, key)) {
312  if (pwalletMain->mapAddressBook.count(keyid)) {
313  file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
314  } else if (setKeyPool.count(keyid)) {
315  file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
316  } else {
317  file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
318  }
319  }
320  }
321  file << "\n";
322  file << "# End of dump\n";
323  file.close();
324  return Value::null;
325 }
static std::string EncodeDumpString(const std::string &str)
Definition: rpcdump.cpp:41
std::string DecodeDumpString(const std::string &str)
Definition: rpcdump.cpp:53
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey)
Definition: wallet.cpp:71
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:1548
static int64_t DecodeDumpTime(const std::string &str)
Definition: rpcdump.cpp:28
bool HaveKey(const CKeyID &address) const
Definition: crypter.h:158
CBlockIndex * pprev
Definition: main.h:695
CKey GetKey()
Definition: base58.cpp:255
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:173
CCriticalSection cs_wallet
Main wallet lock.
Definition: wallet.h:132
std::string HelpExampleRpc(string methodname, string args)
Definition: rpcserver.cpp:923
Value importwallet(const Array &params, bool fHelp)
Definition: rpcdump.cpp:136
CCriticalSection cs_main
Definition: main.cpp:43
int64_t nTimeFirstKey
Definition: wallet.h:179
#define strprintf
Definition: util.h:116
STL namespace.
void GetAllReserveKeys(std::set< CKeyID > &setAddress) const
Definition: wallet.cpp:1940
Value dumpwallet(const Array &params, bool fHelp)
Definition: rpcdump.cpp:267
Object JSONRPCError(int code, const string &message)
base58-encoded Bitcoin addresses.
Definition: base58.h:101
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const
Definition: wallet.cpp:2007
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: util.cpp:1429
bool GetKey(const CKeyID &address, CKey &keyOut) const
Definition: crypter.cpp:211
CChain chainActive
The currently-connected chain of blocks.
Definition: main.cpp:48
Value importprivkey(const Array &params, bool fHelp)
Definition: rpcdump.cpp:67
bool GetKeyID(CKeyID &keyID) const
Definition: base58.cpp:235
void MarkDirty()
Definition: wallet.cpp:474
bool IsValid() const
Definition: key.h:238
bool SetString(const char *pszSecret)
Definition: base58.cpp:267
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or NULL if none.
Definition: main.h:1012
#define LOCK2(cs1, cs2)
Definition: sync.h:157
int Height() const
Return the maximal height in the chain.
Definition: main.h:1043
unsigned int nTime
Definition: main.h:725
#define LogPrintf(...)
Definition: util.h:117
void EnsureWalletIsUnlocked()
Definition: rpcwallet.cpp:36
CPubKey GetPubKey() const
Definition: key.cpp:388
A base58-encoded secret key.
Definition: base58.h:121
An encapsulated public key.
Definition: key.h:42
std::string ToString() const
Definition: base58.cpp:174
int64_t GetTime()
Definition: util.cpp:1215
bool SetString(const char *psz, unsigned int nVersionBytes=1)
Definition: base58.cpp:154
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or NULL if none.
Definition: main.h:1007
int ScanForWalletTransactions(CBlockIndex *pindexStart, bool fUpdate=false)
Definition: wallet.cpp:847
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: main.h:688
const std::string CLIENT_BUILD
std::string ToString() const
Definition: uint256.h:340
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: ui_interface.h:105
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:26
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
Definition: wallet.h:138
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
Definition: wallet.h:398
static std::string EncodeDumpTime(int64_t nTime)
Definition: rpcdump.cpp:24
std::string HelpExampleCli(string methodname, string args)
Definition: rpcserver.cpp:919
An encapsulated private key.
Definition: key.h:179
int nHeight
Definition: main.h:698
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
Definition: util.h:263
CKeyID GetID() const
Definition: key.h:131
const std::string CLIENT_DATE
CWallet * pwalletMain
uint256 GetBlockHash() const
Definition: main.h:805
Value dumpprivkey(const Array &params, bool fHelp)
Definition: rpcdump.cpp:234