Malleable keys: remove version byte
[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 vchAddress = key.GetPubKey().GetID();
66     {
67         LOCK2(cs_main, pwalletMain->cs_wallet);
68
69         pwalletMain->MarkDirty();
70         pwalletMain->SetAddressBookName(vchAddress, strLabel);
71
72         // Don't throw error in case a key is already there
73         if (pwalletMain->HaveKey(vchAddress))
74             return Value::null;
75
76         pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
77
78         if (!pwalletMain->AddKey(key))
79             throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
80
81         // whenever a key is imported, we need to scan the whole chain
82         pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
83
84         if (fRescan) 
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         script.SetDestination(address.Get());
105     } else if (IsHex(params[0].get_str())) {
106         std::vector<unsigned char> data(ParseHex(params[0].get_str()));
107         script = CScript(data.begin(), data.end());
108     } else {
109         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Novacoin address or script");
110     }
111
112     string strLabel = "";
113     if (params.size() > 1)
114         strLabel = params[1].get_str();
115
116     // Whether to perform rescan after import
117     bool fRescan = true;
118     if (params.size() > 2)
119         fRescan = params[2].get_bool();
120
121     {
122         LOCK2(cs_main, pwalletMain->cs_wallet);
123         if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE)
124             throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
125
126         // Don't throw error in case an address is already there
127         if (pwalletMain->HaveWatchOnly(script))
128             return Value::null;
129
130         pwalletMain->MarkDirty();
131
132         if (address.IsValid())
133             pwalletMain->SetAddressBookName(address.Get(), strLabel);
134
135         if (!pwalletMain->AddWatchOnly(script))
136             throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
137
138         if (fRescan)
139         {
140             pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
141             pwalletMain->ReacceptWalletTransactions();
142         }
143     }
144
145     return Value::null;
146 }
147
148 Value removeaddress(const Array& params, bool fHelp)
149 {
150     if (fHelp || params.size() != 1)
151         throw runtime_error(
152             "removeaddress 'address'\n"
153             "\nRemoves watch-only address or script (in hex) added by importaddress.\n"
154             "\nArguments:\n"
155             "1. 'address' (string, required) The address\n"
156             "\nExamples:\n"
157             "\nremoveaddress 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n"
158             "\nRemove watch-only address 4EqHMPgEAf56CQmU6ZWS8Ug4d7N3gsQVQA\n");
159
160     CScript script;
161
162     CBitcoinAddress address(params[0].get_str());
163     if (address.IsValid()) {
164         script.SetDestination(address.Get());
165     } else if (IsHex(params[0].get_str())) {
166         std::vector<unsigned char> data(ParseHex(params[0].get_str()));
167         script = CScript(data.begin(), data.end());
168     } else {
169         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
170     }
171
172     if (::IsMine(*pwalletMain, script) == MINE_SPENDABLE)
173         throw JSONRPCError(RPC_WALLET_ERROR, "The wallet contains the private key for this address or script - can't remove it");
174
175     if (!pwalletMain->HaveWatchOnly(script))
176         throw JSONRPCError(RPC_WALLET_ERROR, "The wallet does not contain this address or script");
177
178     LOCK2(cs_main, pwalletMain->cs_wallet);
179
180     pwalletMain->MarkDirty();
181
182     if (!pwalletMain->RemoveWatchOnly(script))
183         throw JSONRPCError(RPC_WALLET_ERROR, "Error removing address from wallet");
184
185     return Value::null;
186 }
187
188 Value importwallet(const Array& params, bool fHelp)
189 {
190     if (fHelp || params.size() != 1)
191         throw runtime_error(
192             "importwallet <filename>\n"
193             "Imports keys from a wallet dump file (see dumpwallet)."
194             + HelpRequiringPassphrase());
195
196     EnsureWalletIsUnlocked();
197
198     if(!ImportWallet(pwalletMain, params[0].get_str().c_str()))
199        throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
200
201     return Value::null;
202 }
203
204 Value dumpprivkey(const Array& params, bool fHelp)
205 {
206     if (fHelp || params.size() != 1)
207         throw runtime_error(
208             "dumpprivkey <novacoinaddress>\n"
209             "Reveals the private key corresponding to <novacoinaddress>.");
210
211     EnsureWalletIsUnlocked();
212
213     string strAddress = params[0].get_str();
214     CBitcoinAddress address;
215     if (!address.SetString(strAddress))
216         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address");
217     if (fWalletUnlockMintOnly) // ppcoin: no dumpprivkey in mint-only mode
218         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only.");
219     CKeyID keyID;
220     if (!address.GetKeyID(keyID))
221         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
222     CSecret vchSecret;
223     bool fCompressed;
224     if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
225         throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
226     return CBitcoinSecret(vchSecret, fCompressed).ToString();
227 }
228
229 Value dumpwallet(const Array& params, bool fHelp)
230 {
231     if (fHelp || params.size() != 1)
232         throw runtime_error(
233             "dumpwallet <filename>\n"
234             "Dumps all wallet keys in a human-readable format."
235             + HelpRequiringPassphrase());
236
237     EnsureWalletIsUnlocked();
238
239     if(!DumpWallet(pwalletMain, params[0].get_str().c_str() ))
240       throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping wallet keys to file");
241
242     return Value::null;
243 }
244
245 Value dumpmalleablekey(const Array& params, bool fHelp)
246 {
247     if (fHelp || params.size() != 1)
248         throw runtime_error (
249             "dumpmalleablekey <Key view>\n"
250             "Dump the private and public key pairs, which correspond to provided key view.\n");
251
252     EnsureWalletIsUnlocked();
253
254     CMalleableKey mKey;
255     CMalleableKeyView keyView;
256     keyView.SetString(params[0].get_str());
257
258     if (!pwalletMain->GetMalleableKey(keyView, mKey))
259         throw runtime_error("There is no such item in the wallet");
260
261     Object result;
262     result.push_back(Pair("PrivatePair", mKey.ToString()));
263     result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
264
265     return result;
266 }
267
268 Value importmalleablekey(const Array& params, bool fHelp)
269 {
270     if (fHelp || params.size() != 1)
271         throw runtime_error (
272             "importmalleablekey <Key data>\n"
273             "Imports the private key pair into your wallet.\n");
274
275
276     EnsureWalletIsUnlocked();
277
278     CMalleableKey mKey;
279     bool fSuccess = mKey.SetString(params[0].get_str());
280
281     Object result;
282
283     if (fSuccess)
284     {
285         fSuccess = pwalletMain->AddMalleableKey(mKey);
286         result.push_back(Pair("Successful", fSuccess));
287         result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString()));
288         result.push_back(Pair("KeyView", CMalleableKeyView(mKey).ToString()));
289     }
290     else
291         result.push_back(Pair("Successful", false));
292
293     return result;
294 }