]>
Commit | Line | Data |
---|---|---|
652e1569 | 1 | // Copyright (c) 2010 Satoshi Nakamoto |
57702541 | 2 | // Copyright (c) 2009-2014 The Bitcoin developers |
652e1569 WL |
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" | |
652e1569 WL |
7 | #include "init.h" |
8 | #include "main.h" | |
9 | #include "net.h" | |
10 | #include "netbase.h" | |
c037531d | 11 | #include "rpcserver.h" |
652e1569 WL |
12 | #include "util.h" |
13 | #ifdef ENABLE_WALLET | |
14 | #include "wallet.h" | |
15 | #include "walletdb.h" | |
16 | #endif | |
17 | ||
18 | #include <stdint.h> | |
19 | ||
20 | #include <boost/assign/list_of.hpp> | |
21 | #include "json/json_spirit_utils.h" | |
22 | #include "json/json_spirit_value.h" | |
23 | ||
24 | using namespace std; | |
25 | using namespace boost; | |
26 | using namespace boost::assign; | |
27 | using namespace json_spirit; | |
28 | ||
16bc9aaf WL |
29 | Value getinfo(const Array& params, bool fHelp) |
30 | { | |
31 | if (fHelp || params.size() != 0) | |
32 | throw runtime_error( | |
33 | "getinfo\n" | |
34 | "Returns an object containing various state info.\n" | |
35 | "\nResult:\n" | |
36 | "{\n" | |
37 | " \"version\": xxxxx, (numeric) the server version\n" | |
38 | " \"protocolversion\": xxxxx, (numeric) the protocol version\n" | |
39 | " \"walletversion\": xxxxx, (numeric) the wallet version\n" | |
40 | " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" | |
41 | " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" | |
42 | " \"timeoffset\": xxxxx, (numeric) the time offset\n" | |
43 | " \"connections\": xxxxx, (numeric) the number of connections\n" | |
44 | " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" | |
45 | " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" | |
46 | " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" | |
47 | " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" | |
48 | " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" | |
49 | " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc\n" | |
50 | " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" | |
51 | " \"errors\": \"...\" (string) any error messages\n" | |
52 | "}\n" | |
53 | "\nExamples:\n" | |
54 | + HelpExampleCli("getinfo", "") | |
55 | + HelpExampleRpc("getinfo", "") | |
56 | ); | |
57 | ||
58 | proxyType proxy; | |
59 | GetProxy(NET_IPV4, proxy); | |
60 | ||
61 | Object obj; | |
62 | obj.push_back(Pair("version", (int)CLIENT_VERSION)); | |
63 | obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); | |
64 | #ifdef ENABLE_WALLET | |
65 | if (pwalletMain) { | |
66 | obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); | |
67 | obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); | |
68 | } | |
69 | #endif | |
70 | obj.push_back(Pair("blocks", (int)chainActive.Height())); | |
71 | obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset())); | |
72 | obj.push_back(Pair("connections", (int)vNodes.size())); | |
73 | obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); | |
74 | obj.push_back(Pair("difficulty", (double)GetDifficulty())); | |
75 | obj.push_back(Pair("testnet", TestNet())); | |
76 | #ifdef ENABLE_WALLET | |
77 | if (pwalletMain) { | |
78 | obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); | |
79 | obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); | |
80 | } | |
16bc9aaf | 81 | obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); |
16bc9aaf WL |
82 | if (pwalletMain && pwalletMain->IsCrypted()) |
83 | obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); | |
84 | #endif | |
85 | obj.push_back(Pair("errors", GetWarnings("statusbar"))); | |
86 | return obj; | |
87 | } | |
88 | ||
452955f5 WL |
89 | #ifdef ENABLE_WALLET |
90 | class DescribeAddressVisitor : public boost::static_visitor<Object> | |
91 | { | |
92 | public: | |
93 | Object operator()(const CNoDestination &dest) const { return Object(); } | |
94 | ||
95 | Object operator()(const CKeyID &keyID) const { | |
96 | Object obj; | |
97 | CPubKey vchPubKey; | |
98 | pwalletMain->GetPubKey(keyID, vchPubKey); | |
99 | obj.push_back(Pair("isscript", false)); | |
100 | obj.push_back(Pair("pubkey", HexStr(vchPubKey))); | |
101 | obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); | |
102 | return obj; | |
103 | } | |
104 | ||
105 | Object operator()(const CScriptID &scriptID) const { | |
106 | Object obj; | |
107 | obj.push_back(Pair("isscript", true)); | |
108 | CScript subscript; | |
109 | pwalletMain->GetCScript(scriptID, subscript); | |
110 | std::vector<CTxDestination> addresses; | |
111 | txnouttype whichType; | |
112 | int nRequired; | |
113 | ExtractDestinations(subscript, whichType, addresses, nRequired); | |
114 | obj.push_back(Pair("script", GetTxnOutputType(whichType))); | |
115 | obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); | |
116 | Array a; | |
117 | BOOST_FOREACH(const CTxDestination& addr, addresses) | |
118 | a.push_back(CBitcoinAddress(addr).ToString()); | |
119 | obj.push_back(Pair("addresses", a)); | |
120 | if (whichType == TX_MULTISIG) | |
121 | obj.push_back(Pair("sigsrequired", nRequired)); | |
122 | return obj; | |
123 | } | |
124 | }; | |
125 | #endif | |
126 | ||
127 | Value validateaddress(const Array& params, bool fHelp) | |
128 | { | |
129 | if (fHelp || params.size() != 1) | |
130 | throw runtime_error( | |
131 | "validateaddress \"bitcoinaddress\"\n" | |
132 | "\nReturn information about the given bitcoin address.\n" | |
133 | "\nArguments:\n" | |
134 | "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n" | |
135 | "\nResult:\n" | |
136 | "{\n" | |
137 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
138 | " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n" | |
139 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" | |
140 | " \"isscript\" : true|false, (boolean) If the key is a script\n" | |
141 | " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" | |
142 | " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" | |
143 | " \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n" | |
144 | "}\n" | |
145 | "\nExamples:\n" | |
146 | + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
147 | + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
148 | ); | |
149 | ||
150 | CBitcoinAddress address(params[0].get_str()); | |
151 | bool isValid = address.IsValid(); | |
152 | ||
153 | Object ret; | |
154 | ret.push_back(Pair("isvalid", isValid)); | |
155 | if (isValid) | |
156 | { | |
157 | CTxDestination dest = address.Get(); | |
158 | string currentAddress = address.ToString(); | |
159 | ret.push_back(Pair("address", currentAddress)); | |
160 | #ifdef ENABLE_WALLET | |
161 | bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false; | |
162 | ret.push_back(Pair("ismine", fMine)); | |
163 | if (fMine) { | |
164 | Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); | |
165 | ret.insert(ret.end(), detail.begin(), detail.end()); | |
166 | } | |
167 | if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) | |
168 | ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); | |
169 | #endif | |
170 | } | |
171 | return ret; | |
172 | } | |
173 | ||
723a03d2 WL |
174 | // |
175 | // Used by addmultisigaddress / createmultisig: | |
176 | // | |
177 | CScript _createmultisig(const Array& params) | |
178 | { | |
179 | int nRequired = params[0].get_int(); | |
180 | const Array& keys = params[1].get_array(); | |
181 | ||
182 | // Gather public keys | |
183 | if (nRequired < 1) | |
184 | throw runtime_error("a multisignature address must require at least one key to redeem"); | |
185 | if ((int)keys.size() < nRequired) | |
186 | throw runtime_error( | |
187 | strprintf("not enough keys supplied " | |
188 | "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); | |
189 | std::vector<CPubKey> pubkeys; | |
190 | pubkeys.resize(keys.size()); | |
191 | for (unsigned int i = 0; i < keys.size(); i++) | |
192 | { | |
193 | const std::string& ks = keys[i].get_str(); | |
194 | #ifdef ENABLE_WALLET | |
195 | // Case 1: Bitcoin address and we have full public key: | |
196 | CBitcoinAddress address(ks); | |
197 | if (pwalletMain && address.IsValid()) | |
198 | { | |
199 | CKeyID keyID; | |
200 | if (!address.GetKeyID(keyID)) | |
201 | throw runtime_error( | |
7d9d134b | 202 | strprintf("%s does not refer to a key",ks)); |
723a03d2 WL |
203 | CPubKey vchPubKey; |
204 | if (!pwalletMain->GetPubKey(keyID, vchPubKey)) | |
205 | throw runtime_error( | |
7d9d134b | 206 | strprintf("no full public key for address %s",ks)); |
723a03d2 WL |
207 | if (!vchPubKey.IsFullyValid()) |
208 | throw runtime_error(" Invalid public key: "+ks); | |
209 | pubkeys[i] = vchPubKey; | |
210 | } | |
211 | ||
212 | // Case 2: hex public key | |
213 | else | |
214 | #endif | |
215 | if (IsHex(ks)) | |
216 | { | |
217 | CPubKey vchPubKey(ParseHex(ks)); | |
218 | if (!vchPubKey.IsFullyValid()) | |
219 | throw runtime_error(" Invalid public key: "+ks); | |
220 | pubkeys[i] = vchPubKey; | |
221 | } | |
222 | else | |
223 | { | |
224 | throw runtime_error(" Invalid public key: "+ks); | |
225 | } | |
226 | } | |
227 | CScript result; | |
228 | result.SetMultisig(nRequired, pubkeys); | |
229 | return result; | |
230 | } | |
231 | ||
232 | Value createmultisig(const Array& params, bool fHelp) | |
233 | { | |
234 | if (fHelp || params.size() < 2 || params.size() > 2) | |
235 | { | |
236 | string msg = "createmultisig nrequired [\"key\",...]\n" | |
237 | "\nCreates a multi-signature address with n signature of m keys required.\n" | |
238 | "It returns a json object with the address and redeemScript.\n" | |
239 | ||
240 | "\nArguments:\n" | |
241 | "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" | |
242 | "2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n" | |
243 | " [\n" | |
244 | " \"key\" (string) bitcoin address or hex-encoded public key\n" | |
245 | " ,...\n" | |
246 | " ]\n" | |
247 | ||
248 | "\nResult:\n" | |
249 | "{\n" | |
250 | " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" | |
251 | " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" | |
252 | "}\n" | |
253 | ||
254 | "\nExamples:\n" | |
255 | "\nCreate a multisig address from 2 addresses\n" | |
256 | + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + | |
257 | "\nAs a json rpc call\n" | |
258 | + HelpExampleRpc("icreatemultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") | |
259 | ; | |
260 | throw runtime_error(msg); | |
261 | } | |
262 | ||
263 | // Construct using pay-to-script-hash: | |
264 | CScript inner = _createmultisig(params); | |
265 | CScriptID innerID = inner.GetID(); | |
266 | CBitcoinAddress address(innerID); | |
267 | ||
268 | Object result; | |
269 | result.push_back(Pair("address", address.ToString())); | |
270 | result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); | |
271 | ||
272 | return result; | |
273 | } | |
274 | ||
c3a7f516 WL |
275 | Value verifymessage(const Array& params, bool fHelp) |
276 | { | |
277 | if (fHelp || params.size() != 3) | |
278 | throw runtime_error( | |
279 | "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n" | |
280 | "\nVerify a signed message\n" | |
281 | "\nArguments:\n" | |
282 | "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n" | |
283 | "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" | |
284 | "3. \"message\" (string, required) The message that was signed.\n" | |
285 | "\nResult:\n" | |
286 | "true|false (boolean) If the signature is verified or not.\n" | |
287 | "\nExamples:\n" | |
288 | "\nUnlock the wallet for 30 seconds\n" | |
289 | + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + | |
290 | "\nCreate the signature\n" | |
291 | + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") + | |
292 | "\nVerify the signature\n" | |
293 | + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") + | |
294 | "\nAs json rpc\n" | |
295 | + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"") | |
296 | ); | |
297 | ||
298 | string strAddress = params[0].get_str(); | |
299 | string strSign = params[1].get_str(); | |
300 | string strMessage = params[2].get_str(); | |
301 | ||
302 | CBitcoinAddress addr(strAddress); | |
303 | if (!addr.IsValid()) | |
304 | throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); | |
305 | ||
306 | CKeyID keyID; | |
307 | if (!addr.GetKeyID(keyID)) | |
308 | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); | |
309 | ||
310 | bool fInvalid = false; | |
311 | vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); | |
312 | ||
313 | if (fInvalid) | |
314 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); | |
315 | ||
316 | CHashWriter ss(SER_GETHASH, 0); | |
317 | ss << strMessageMagic; | |
318 | ss << strMessage; | |
319 | ||
320 | CPubKey pubkey; | |
321 | if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) | |
322 | return false; | |
323 | ||
324 | return (pubkey.GetID() == keyID); | |
325 | } |