Fix importprivkey issues.
[novacoin.git] / src / rpcdump.cpp
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.
4
5 #include "init.h" // for pwalletMain
6 #include "bitcoinrpc.h"
7 #include "ui_interface.h"
8 #include "base58.h"
9
10 #define printf OutputDebugStringF
11
12 using namespace json_spirit;
13 using namespace std;
14
15 void EnsureWalletIsUnlocked();
16
17 class CTxDump
18 {
19 public:
20     CBlockIndex *pindex;
21     int64_t nValue;
22     bool fSpent;
23     CWalletTx* ptx;
24     int nOut;
25     CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
26     {
27         pindex = NULL;
28         nValue = 0;
29         fSpent = false;
30         this->ptx = ptx;
31         this->nOut = nOut;
32     }
33 };
34
35 Value importprivkey(const Array& params, bool fHelp)
36 {
37     if (fHelp || params.size() < 1 || params.size() > 3)
38         throw runtime_error(
39             "importprivkey <novacoinprivkey> [label] [rescan=true]\n"
40             "Adds a private key (as returned by dumpprivkey) to your wallet.");
41
42     EnsureWalletIsUnlocked();
43
44     string strSecret = params[0].get_str();
45     string strLabel = "";
46     if (params.size() > 1)
47         strLabel = params[1].get_str();
48
49     // Whether to perform rescan after import
50     bool fRescan = true;
51     if (params.size() > 2)
52         fRescan = params[2].get_bool();
53
54     CBitcoinSecret vchSecret;
55     bool fGood = vchSecret.SetString(strSecret);
56
57     if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
58     if (fWalletUnlockMintOnly) // ppcoin: no importprivkey in mint-only mode
59         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
60
61     CKey key;
62     bool fCompressed;
63     CSecret secret = vchSecret.GetSecret(fCompressed);
64     key.SetSecret(secret, fCompressed);
65     CKeyID keyid = key.GetPubKey().GetID();
66     CBitcoinAddress addr = CBitcoinAddress(keyid);
67     {
68         LOCK2(cs_main, pwalletMain->cs_wallet);
69
70         // Don't throw error in case a key is already there
71         if (pwalletMain->HaveKey(keyid))
72             return Value::null;
73
74         pwalletMain->mapKeyMetadata[addr].nCreateTime = 1;
75         if (!pwalletMain->AddKey(key))
76             throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
77
78         pwalletMain->MarkDirty();
79         pwalletMain->SetAddressBookName(addr, strLabel);
80
81         if (fRescan)
82         {
83             // whenever a key is imported, we need to scan the whole chain
84             pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
85
86             pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
87             pwalletMain->ReacceptWalletTransactions();
88         }
89     }
90
91     return Value::null;
92 }
93
94 Value importaddress(const Array& params, bool fHelp)
95 {
96     if (fHelp || params.size() < 1 || params.size() > 3)
97         throw runtime_error(
98             "importaddress <address> [label] [rescan=true]\n"
99             "Adds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.");
100
101     CScript script;
102     CBitcoinAddress address(params[0].get_str());
103     if (address.IsValid()) {
104         if (address.IsPair())
105             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "It's senseless to import pubkey pair address.");
106         script.SetAddress(address);
107     } else if (IsHex(params[0].get_str())) {
108         std::vector<unsigned char> data(ParseHex(params[0].get_str()));
109         script = CScript(data.begin(), data.end());
110     } else
111         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Novacoin address or script");
112
113     string strLabel = "";
114     if (params.size() > 1)
115         strLabel = params[1].get_str();
116
117     // Whether to perform rescan after import
118     bool fRescan = true;
119     if (params.size() > 2)
120         fRescan = params[2].get_bool();
121
122     {
123         LOCK2(cs_main, pwalletMain->cs_wallet);
124         if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE)
125             throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
126
127         // Don't throw error in case an address is already there
128         if (pwalletMain->HaveWatchOnly(script))
129             return Value::null;
130
131         pwalletMain->MarkDirty();
132
133         if (address.IsValid())
134             pwalletMain->SetAddressBookName(address, strLabel);
135
136         if (!pwalletMain->AddWatchOnly(script))
137             throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
138
139         if (fRescan)
140         {
141             pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
142             pwalletMain->ReacceptWalletTransactions();
143         }
144     }
145
146     return Value::null;
147 }
148
149 Value removeaddress(const Array& params, bool fHelp)
150 {
151     if (fHelp || params.size() != 1)
152         throw runtime_error(
153             "removeaddress 'address'\n"
154             "\nRemoves watch-only address or script (in hex) added by importaddress.\n"
155             "\nArguments:\n"
156             "1. 'address' (string, required) The address\n"
157             "\nExamples:\n"
158             "\nremoveaddress 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n"
159             "\nRemove watch-only address 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n");
160
161     CScript script;
162
163     CBitcoinAddress address(params[0].get_str());
164     if (address.IsValid()) {
165         if (address.IsPair())
166             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey pair addresses aren't supported.");
167         script.SetAddress(address);
168     } else if (IsHex(params[0].get_str())) {
169         std::vector<unsigned char> data(ParseHex(params[0].get_str()));
170         script = CScript(data.begin(), data.end());
171     } else
172         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
173
174     if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE)
175         throw JSONRPCError(RPC_WALLET_ERROR, "The wallet contains the private key for this address or script - can't remove it");
176
177     if (!pwalletMain->HaveWatchOnly(script))
178         throw JSONRPCError(RPC_WALLET_ERROR, "The wallet does not contain this address or script");
179
180     LOCK2(cs_main, pwalletMain->cs_wallet);
181
182     pwalletMain->MarkDirty();
183
184     if (!pwalletMain->RemoveWatchOnly(script))
185         throw JSONRPCError(RPC_WALLET_ERROR, "Error removing address from wallet");
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             "Imports keys from a wallet dump file (see dumpwallet)."
196             + HelpRequiringPassphrase());
197
198     EnsureWalletIsUnlocked();
199
200     if(!ImportWallet(pwalletMain, params[0].get_str().c_str()))
201        throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
202
203     return Value::null;
204 }
205
206 Value dumpprivkey(const Array& params, bool fHelp)
207 {
208     if (fHelp || params.size() != 1)
209         throw runtime_error(
210             "dumpprivkey <novacoinaddress>\n"
211             "Reveals the private key corresponding to <novacoinaddress>.");
212
213     EnsureWalletIsUnlocked();
214
215     string strAddress = params[0].get_str();
216     CBitcoinAddress address;
217     if (!address.SetString(strAddress))
218         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
219     if (fWalletUnlockMintOnly)
220         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
221     CKeyID keyID;
222     if (!address.GetKeyID(keyID))
223         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
224     CSecret vchSecret;
225     bool fCompressed;
226     if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
227         throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
228     return CBitcoinSecret(vchSecret, fCompressed).ToString();
229 }
230
231 Value dumppem(const Array& params, bool fHelp)
232 {
233     if (fHelp || params.size() != 3)
234         throw runtime_error(
235             "dumppem <novacoinaddress> <filename> <passphrase>\n"
236             "Dump the key pair corresponding to <novacoinaddress> and store it as encrypted PEM file."
237             + HelpRequiringPassphrase());
238
239     EnsureWalletIsUnlocked();
240
241     string strAddress = params[0].get_str();
242     SecureString strPassKey;
243     strPassKey.reserve(100);
244     strPassKey = params[2].get_str().c_str();
245
246     CBitcoinAddress address;
247     if (!address.SetString(strAddress))
248         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
249     if (fWalletUnlockMintOnly)
250         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
251     CKeyID keyID;
252     if (!address.GetKeyID(keyID))
253         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
254     if (!pwalletMain->GetPEM(keyID, params[1].get_str(), strPassKey))
255         throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping key pair to file");
256
257     return Value::null;
258 }
259
260 Value dumpwallet(const Array& params, bool fHelp)
261 {
262     if (fHelp || params.size() != 1)
263         throw runtime_error(
264             "dumpwallet <filename>\n"
265             "Dumps all wallet keys in a human-readable format."
266             + HelpRequiringPassphrase());
267
268     EnsureWalletIsUnlocked();
269
270     if(!DumpWallet(pwalletMain, params[0].get_str().c_str() ))
271       throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping wallet keys to file");
272
273     return Value::null;
274 }
275
276 Value dumpmalleablekey(const Array& params, bool fHelp)
277 {
278     if (fHelp || params.size() != 1)
279         throw runtime_error (
280             "dumpmalleablekey <Key view>\n"
281             "Dump the private and public key pairs, which correspond to provided key view.\n");
282
283     EnsureWalletIsUnlocked();
284
285     CMalleableKey mKey;
286     CMalleableKeyView keyView;
287     keyView.SetString(params[0].get_str());
288
289     if (!pwalletMain->GetMalleableKey(keyView, mKey))
290         throw runtime_error("There is no such item in the wallet");
291
292     Object result;
293     result.push_back(Pair("PrivatePair", mKey.ToString()));
294     result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString()));
295
296     return result;
297 }
298
299 Value importmalleablekey(const Array& params, bool fHelp)
300 {
301     if (fHelp || params.size() != 1)
302         throw runtime_error (
303             "importmalleablekey <Key data>\n"
304             "Imports the private key pair into your wallet.\n");
305
306
307     EnsureWalletIsUnlocked();
308
309     CMalleableKey mKey;
310     bool fSuccess = mKey.SetString(params[0].get_str());
311
312     Object result;
313
314     if (fSuccess)
315     {
316         fSuccess = pwalletMain->AddKey(mKey);
317         result.push_back(Pair("Successful", fSuccess));
318         result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString()));
319         result.push_back(Pair("KeyView", CMalleableKeyView(mKey).ToString()));
320     }
321     else
322         result.push_back(Pair("Successful", false));
323
324     return result;
325 }