1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #include <boost/assign/list_of.hpp>
9 #include "bitcoinrpc.h"
17 using namespace boost;
18 using namespace boost::assign;
19 using namespace json_spirit;
21 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
24 vector<CTxDestination> addresses;
27 out.push_back(Pair("asm", scriptPubKey.ToString()));
30 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
32 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
34 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
38 if (type != TX_NULL_DATA)
40 out.push_back(Pair("reqSigs", nRequired));
41 out.push_back(Pair("type", GetTxnOutputType(type)));
43 if (type == TX_PUBKEY_DROP)
45 vector<valtype> vSolutions;
46 Solver(scriptPubKey, type, vSolutions);
47 out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
48 out.push_back(Pair("R", HexStr(vSolutions[1])));
50 CMalleableKeyView view;
51 if (pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view))
52 out.push_back(Pair("pubkeyPair", CBitcoinAddress(view.GetMalleablePubKey()).ToString()));
57 BOOST_FOREACH(const CTxDestination& addr, addresses)
58 a.push_back(CBitcoinAddress(addr).ToString());
59 out.push_back(Pair("addresses", a));
64 out.push_back(Pair("type", GetTxnOutputType(type)));
68 void TxToJSON(const CTransaction& tx, const uint256& hashBlock, Object& entry)
70 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
71 entry.push_back(Pair("version", tx.nVersion));
72 entry.push_back(Pair("time", (int64_t)tx.nTime));
73 entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
75 BOOST_FOREACH(const CTxIn& txin, tx.vin)
79 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
82 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
83 in.push_back(Pair("vout", (int64_t)txin.prevout.n));
85 o.push_back(Pair("asm", txin.scriptSig.ToString()));
86 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
87 in.push_back(Pair("scriptSig", o));
89 in.push_back(Pair("sequence", (int64_t)txin.nSequence));
92 entry.push_back(Pair("vin", vin));
94 for (unsigned int i = 0; i < tx.vout.size(); i++)
96 const CTxOut& txout = tx.vout[i];
98 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
99 out.push_back(Pair("n", (int64_t)i));
101 ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
102 out.push_back(Pair("scriptPubKey", o));
105 entry.push_back(Pair("vout", vout));
109 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
110 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
111 if (mi != mapBlockIndex.end() && (*mi).second)
113 CBlockIndex* pindex = (*mi).second;
114 if (pindex->IsInMainChain())
116 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
117 entry.push_back(Pair("time", (int64_t)pindex->nTime));
118 entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
121 entry.push_back(Pair("confirmations", 0));
126 Value getrawtransaction(const Array& params, bool fHelp)
128 if (fHelp || params.size() < 1 || params.size() > 2)
130 "getrawtransaction <txid> [verbose=0]\n"
131 "If verbose=0, returns a string that is\n"
132 "serialized, hex-encoded data for <txid>.\n"
133 "If verbose is non-zero, returns an Object\n"
134 "with information about <txid>.");
137 hash.SetHex(params[0].get_str());
139 bool fVerbose = false;
140 if (params.size() > 1)
141 fVerbose = (params[1].get_int() != 0);
144 uint256 hashBlock = 0;
145 if (!GetTransaction(hash, tx, hashBlock))
146 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
148 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
150 string strHex = HexStr(ssTx.begin(), ssTx.end());
156 result.push_back(Pair("hex", strHex));
157 TxToJSON(tx, hashBlock, result);
161 Value listunspent(const Array& params, bool fHelp)
163 if (fHelp || params.size() > 3)
165 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
166 "Returns array of unspent transaction outputs\n"
167 "with between minconf and maxconf (inclusive) confirmations.\n"
168 "Optionally filtered to only include txouts paid to specified addresses.\n"
169 "Results are an array of Objects, each of which has:\n"
170 "{txid, vout, scriptPubKey, amount, confirmations}");
172 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
175 if (params.size() > 0)
176 nMinDepth = params[0].get_int();
178 int nMaxDepth = 9999999;
179 if (params.size() > 1)
180 nMaxDepth = params[1].get_int();
182 set<CBitcoinAddress> setAddress;
183 if (params.size() > 2)
185 Array inputs = params[2].get_array();
186 BOOST_FOREACH(Value& input, inputs)
188 CBitcoinAddress address(input.get_str());
189 if (!address.IsValid())
190 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
191 if (setAddress.count(address))
192 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
193 setAddress.insert(address);
198 vector<COutput> vecOutputs;
199 pwalletMain->AvailableCoins(vecOutputs, false);
200 BOOST_FOREACH(const COutput& out, vecOutputs)
202 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
205 if(setAddress.size())
207 CTxDestination address;
208 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
211 if (!setAddress.count(address))
215 int64_t nValue = out.tx->vout[out.i].nValue;
216 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
218 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
219 entry.push_back(Pair("vout", out.i));
220 CTxDestination address;
221 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
223 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
224 if (pwalletMain->mapAddressBook.count(address))
225 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
227 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
228 if (pk.IsPayToScriptHash())
230 CTxDestination address;
231 if (ExtractDestination(pk, address))
233 const CScriptID& hash = boost::get<CScriptID>(address);
234 CScript redeemScript;
235 if (pwalletMain->GetCScript(hash, redeemScript))
236 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
239 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
240 entry.push_back(Pair("confirmations",out.nDepth));
241 entry.push_back(Pair("spendable", out.fSpendable));
242 results.push_back(entry);
248 Value createrawtransaction(const Array& params, bool fHelp)
250 if (fHelp || params.size() > 3 || params.size() < 2)
252 "createrawtransaction <'[{\"txid\":txid,\"vout\":n},...]'> <'{address:amount,...}'> [hex data]\n"
253 "Create a transaction spending given inputs\n"
254 "(array of objects containing transaction id and output number),\n"
255 "sending to given address(es),\n"
256 "optional data to add into data-carrying output.\n"
257 "Returns hex-encoded raw transaction.\n"
258 "Note that the transaction's inputs are not signed, and\n"
259 "it is not stored in the wallet or transmitted to the network.");
261 RPCTypeCheck(params, list_of(array_type)(obj_type));
263 Array inputs = params[0].get_array();
264 Object sendTo = params[1].get_obj();
268 BOOST_FOREACH(Value& input, inputs)
270 const Object& o = input.get_obj();
272 const Value& txid_v = find_value(o, "txid");
273 if (txid_v.type() != str_type)
274 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
275 string txid = txid_v.get_str();
277 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
279 const Value& vout_v = find_value(o, "vout");
280 if (vout_v.type() != int_type)
281 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
282 int nOutput = vout_v.get_int();
284 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
286 CTxIn in(COutPoint(uint256(txid), nOutput));
287 rawTx.vin.push_back(in);
290 set<CBitcoinAddress> setAddress;
291 BOOST_FOREACH(const Pair& s, sendTo)
293 // Create output destination script
294 CScript scriptPubKey;
295 CBitcoinAddress address(s.name_);
297 if (address.IsValid())
299 if (!address.IsPair())
301 scriptPubKey.SetDestination(address.Get());
302 if (setAddress.count(address))
303 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
304 setAddress.insert(address);
308 CMalleablePubKey mpk;
309 if (!mpk.setvch(address.GetData()))
310 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
312 CPubKey R, pubKeyVariant;
313 mpk.GetVariant(R, pubKeyVariant);
314 scriptPubKey.SetDestination(R, pubKeyVariant);
318 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
320 int64_t nAmount = AmountFromValue(s.value_);
322 CTxOut out(nAmount, scriptPubKey);
323 rawTx.vout.push_back(out);
326 if (params.size() == 3)
328 // Data carrying output
329 CScript scriptPubKey;
330 scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
331 CTxOut out(0, scriptPubKey);
332 rawTx.vout.push_back(out);
335 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
337 return HexStr(ss.begin(), ss.end());
340 Value decoderawtransaction(const Array& params, bool fHelp)
342 if (fHelp || params.size() != 1)
344 "decoderawtransaction <hex string>\n"
345 "Return a JSON object representing the serialized, hex-encoded transaction.");
347 RPCTypeCheck(params, list_of(str_type));
349 vector<unsigned char> txData(ParseHex(params[0].get_str()));
350 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
355 catch (const std::exception&) {
356 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
360 TxToJSON(tx, 0, result);
365 Value decodescript(const Array& params, bool fHelp)
367 if (fHelp || params.size() != 1)
369 "decodescript <hex string>\n"
370 "Decode a hex-encoded script.");
372 RPCTypeCheck(params, list_of(str_type));
376 if (params[0].get_str().size() > 0){
377 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
378 script = CScript(scriptData.begin(), scriptData.end());
380 // Empty scripts are valid
382 ScriptPubKeyToJSON(script, r, false);
384 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
388 Value signrawtransaction(const Array& params, bool fHelp)
390 if (fHelp || params.size() < 1 || params.size() > 4)
392 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
393 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
394 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
395 "this transaction depends on but may not yet be in the blockchain.\n"
396 "Third optional argument (may be null) is an array of base58-encoded private\n"
397 "keys that, if given, will be the only keys used to sign the transaction.\n"
398 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
399 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
400 "Returns json object with keys:\n"
401 " hex : raw transaction with signature(s) (hex-encoded string)\n"
402 " complete : 1 if transaction has a complete set of signature (0 if not)"
403 + HelpRequiringPassphrase());
405 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
407 vector<unsigned char> txData(ParseHex(params[0].get_str()));
408 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
409 vector<CTransaction> txVariants;
410 while (!ssData.empty())
415 txVariants.push_back(tx);
417 catch (const std::exception&) {
418 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
422 if (txVariants.empty())
423 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
425 // mergedTx will end up with all the signatures; it
426 // starts as a clone of the rawtx:
427 CTransaction mergedTx(txVariants[0]);
428 bool fComplete = true;
430 // Fetch previous transactions (inputs):
431 map<COutPoint, CScript> mapPrevOut;
432 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
437 map<uint256, CTxIndex> unused;
440 // FetchInputs aborts on failure, so we go one at a time.
441 tempTx.vin.push_back(mergedTx.vin[i]);
442 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
444 // Copy results into mapPrevOut:
445 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
447 const uint256& prevHash = txin.prevout.hash;
448 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
449 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
453 bool fGivenKeys = false;
454 CBasicKeyStore tempKeystore;
455 if (params.size() > 2 && params[2].type() != null_type)
458 Array keys = params[2].get_array();
459 BOOST_FOREACH(Value k, keys)
461 CBitcoinSecret vchSecret;
462 bool fGood = vchSecret.SetString(k.get_str());
464 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
467 CSecret secret = vchSecret.GetSecret(fCompressed);
468 key.SetSecret(secret, fCompressed);
469 tempKeystore.AddKey(key);
473 EnsureWalletIsUnlocked();
475 // Add previous txouts given in the RPC call:
476 if (params.size() > 1 && params[1].type() != null_type)
478 Array prevTxs = params[1].get_array();
479 BOOST_FOREACH(Value& p, prevTxs)
481 if (p.type() != obj_type)
482 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
484 Object prevOut = p.get_obj();
486 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
488 string txidHex = find_value(prevOut, "txid").get_str();
490 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
492 txid.SetHex(txidHex);
494 int nOut = find_value(prevOut, "vout").get_int();
496 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
498 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
500 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
501 vector<unsigned char> pkData(ParseHex(pkHex));
502 CScript scriptPubKey(pkData.begin(), pkData.end());
504 COutPoint outpoint(txid, nOut);
505 if (mapPrevOut.count(outpoint))
507 // Complain if scriptPubKey doesn't match
508 if (mapPrevOut[outpoint] != scriptPubKey)
510 string err("Previous output scriptPubKey mismatch:\n");
511 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
512 scriptPubKey.ToString();
513 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
517 mapPrevOut[outpoint] = scriptPubKey;
519 // if redeemScript given and not using the local wallet (private keys
520 // given), add redeemScript to the tempKeystore so it can be signed:
521 Value v = find_value(prevOut, "redeemScript");
522 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
524 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
525 Value v = find_value(prevOut, "redeemScript");
526 if (!(v == Value::null))
528 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
529 CScript redeemScript(rsData.begin(), rsData.end());
530 tempKeystore.AddCScript(redeemScript);
536 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
538 int nHashType = SIGHASH_ALL;
539 if (params.size() > 3 && params[3].type() != null_type)
541 static map<string, int> mapSigHashValues =
542 boost::assign::map_list_of
543 (string("ALL"), int(SIGHASH_ALL))
544 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
545 (string("NONE"), int(SIGHASH_NONE))
546 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
547 (string("SINGLE"), int(SIGHASH_SINGLE))
548 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
550 string strHashType = params[3].get_str();
551 if (mapSigHashValues.count(strHashType))
552 nHashType = mapSigHashValues[strHashType];
554 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
557 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
560 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
562 CTxIn& txin = mergedTx.vin[i];
563 if (mapPrevOut.count(txin.prevout) == 0)
568 const CScript& prevPubKey = mapPrevOut[txin.prevout];
570 txin.scriptSig.clear();
571 // Only sign SIGHASH_SINGLE if there's a corresponding output:
572 if (!fHashSingle || (i < mergedTx.vout.size()))
573 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
575 // ... and merge in other signatures:
576 BOOST_FOREACH(const CTransaction& txv, txVariants)
578 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
580 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
585 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
587 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
588 result.push_back(Pair("complete", fComplete));
593 Value sendrawtransaction(const Array& params, bool fHelp)
595 if (fHelp || params.size() < 1 || params.size() > 1)
597 "sendrawtransaction <hex string>\n"
598 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
600 RPCTypeCheck(params, list_of(str_type));
602 // parse hex string from parameter
603 vector<unsigned char> txData(ParseHex(params[0].get_str()));
604 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
607 // deserialize binary data stream
611 catch (const std::exception&) {
612 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
614 uint256 hashTx = tx.GetHash();
616 // See if the transaction is already in a block
617 // or in the memory pool:
618 CTransaction existingTx;
619 uint256 hashBlock = 0;
620 if (GetTransaction(hashTx, existingTx, hashBlock))
623 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
624 // Not in block, but already in the memory pool; will drop
625 // through to re-relay it.
629 // push to local node
631 if (!tx.AcceptToMemoryPool(txdb))
632 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
634 SyncWithWallets(tx, NULL, true);
636 RelayTransaction(tx, hashTx);
638 return hashTx.GetHex();
641 Value createmultisig(const Array& params, bool fHelp)
643 if (fHelp || params.size() < 2 || params.size() > 3)
645 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
646 "\nCreates a multi-signature address with n signature of m keys required.\n"
647 "It returns a json object with the address and redeemScript.";
648 throw runtime_error(msg);
651 int nRequired = params[0].get_int();
652 const Array& keys = params[1].get_array();
654 // Gather public keys
656 throw runtime_error("a multisignature address must require at least one key to redeem");
657 if ((int)keys.size() < nRequired)
659 strprintf("not enough keys supplied "
660 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
661 if (keys.size() > 16)
662 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
663 std::vector<CKey> pubkeys;
664 pubkeys.resize(keys.size());
665 for (unsigned int i = 0; i < keys.size(); i++)
667 const std::string& ks = keys[i].get_str();
669 // Case 1: Bitcoin address and we have full public key:
670 CBitcoinAddress address(ks);
671 if (address.IsValid())
674 if (!address.GetKeyID(keyID))
676 strprintf("%s does not refer to a key",ks.c_str()));
678 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
680 strprintf("no full public key for address %s",ks.c_str()));
681 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
682 throw runtime_error(" Invalid public key: "+ks);
685 // Case 2: hex public key
688 CPubKey vchPubKey(ParseHex(ks));
689 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
690 throw runtime_error(" Invalid public key: "+ks);
694 throw runtime_error(" Invalid public key: "+ks);
698 // Construct using pay-to-script-hash:
700 inner.SetMultisig(nRequired, pubkeys);
702 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
704 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
706 CScriptID innerID = inner.GetID();
707 CBitcoinAddress address(innerID);
710 result.push_back(Pair("address", address.ToString()));
711 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));