From fc462f579d392011645c7fabcfc10ec45ca44bb5 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 18 Aug 2013 20:13:38 +0400 Subject: [PATCH] P2SH related RPC improvements * New addredeemscript and decodescript RPC calls * validateaddress now provides redeem script --- src/bitcoinrpc.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/bitcoinrpc.h | 11 +++++++++++ src/rpcrawtransaction.cpp | 31 ++++++++++++++++++++++++++++--- src/rpcwallet.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index e63ec8f..5c18452 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -121,6 +121,42 @@ std::string HexBits(unsigned int nBits) } +// +// Utilities: convert hex-encoded Values +// (throws error if not hex). +// +uint256 ParseHashV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) // Note: IsHex("") is false + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + uint256 result; + result.SetHex(strHex); + return result; +} + +uint256 ParseHashO(const Object& o, string strKey) +{ + return ParseHashV(find_value(o, strKey), strKey); +} + +vector ParseHexV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + return ParseHex(strHex); +} + +vector ParseHexO(const Object& o, string strKey) +{ + return ParseHexV(find_value(o, strKey), strKey); +} + /// /// Note: This interface may still be subject to change. @@ -234,6 +270,7 @@ static const CRPCCommand vRPCCommands[] = { "sendfrom", &sendfrom, false, false }, { "sendmany", &sendmany, false, false }, { "addmultisigaddress", &addmultisigaddress, false, false }, + { "addredeemscript", &addredeemscript, false, false }, { "getrawmempool", &getrawmempool, true, false }, { "getblock", &getblock, false, false }, { "getblockbynumber", &getblockbynumber, false, false }, @@ -258,6 +295,7 @@ static const CRPCCommand vRPCCommands[] = { "getrawtransaction", &getrawtransaction, false, false }, { "createrawtransaction", &createrawtransaction, false, false }, { "decoderawtransaction", &decoderawtransaction, false, false }, + { "decodescript", &decodescript, false, false }, { "signrawtransaction", &signrawtransaction, false, false }, { "sendrawtransaction", &sendrawtransaction, false, false }, { "getcheckpoint", &getcheckpoint, true, false }, diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index f19bcde..49a2ffd 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -131,6 +131,15 @@ extern std::string HexBits(unsigned int nBits); extern std::string HelpRequiringPassphrase(); extern void EnsureWalletIsUnlocked(); +// +// Utilities: convert hex-encoded Values +// (throws error if not hex). +// +extern uint256 ParseHashV(const json_spirit::Value& v, std::string strName); +extern uint256 ParseHashO(const json_spirit::Object& o, std::string strKey); +extern std::vector ParseHexV(const json_spirit::Value& v, std::string strName); +extern std::vector ParseHexO(const json_spirit::Object& o, std::string strKey); + extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp); @@ -161,6 +170,7 @@ extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value addredeemscript(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp); @@ -188,6 +198,7 @@ extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bo extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 1c14887..4b23f42 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -18,14 +18,16 @@ using namespace boost; using namespace boost::assign; using namespace json_spirit; -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) +void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex) { txnouttype type; vector addresses; int nRequired; out.push_back(Pair("asm", scriptPubKey.ToString())); - out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + + if (fIncludeHex) + out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { @@ -75,7 +77,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) out.push_back(Pair("value", ValueFromAmount(txout.nValue))); out.push_back(Pair("n", (boost::int64_t)i)); Object o; - ScriptPubKeyToJSON(txout.scriptPubKey, o); + ScriptPubKeyToJSON(txout.scriptPubKey, o, false); out.push_back(Pair("scriptPubKey", o)); vout.push_back(out); } @@ -300,6 +302,29 @@ Value decoderawtransaction(const Array& params, bool fHelp) return result; } +Value decodescript(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "decodescript \n" + "Decode a hex-encoded script."); + + RPCTypeCheck(params, list_of(str_type)); + + Object r; + CScript script; + if (params[0].get_str().size() > 0){ + vector scriptData(ParseHexV(params[0], "argument")); + script = CScript(scriptData.begin(), scriptData.end()); + } else { + // Empty scripts are valid + } + ScriptPubKeyToJSON(script, r, false); + + r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString())); + return r; +} + Value signrawtransaction(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index e8a27d3..5a81a07 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -825,6 +825,29 @@ Value addmultisigaddress(const Array& params, bool fHelp) return CBitcoinAddress(innerID).ToString(); } +Value addredeemscript(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + { + string msg = "addredeemscript [account]\n" + "Add a P2SH address with a specified redeemScript to the wallet.\n" + "If [account] is specified, assign address to [account]."; + throw runtime_error(msg); + } + + string strAccount; + if (params.size() > 1) + strAccount = AccountFromValue(params[1]); + + // Construct using pay-to-script-hash: + vector innerData = ParseHexV(params[0], "redeemScript"); + CScript inner(innerData.begin(), innerData.end()); + CScriptID innerID = inner.GetID(); + pwalletMain->AddCScript(inner); + + pwalletMain->SetAddressBookName(innerID, strAccount); + return CBitcoinAddress(innerID).ToString(); +} struct tallyitem { @@ -1541,6 +1564,7 @@ public: int nRequired; ExtractDestinations(subscript, whichType, addresses, nRequired); obj.push_back(Pair("script", GetTxnOutputType(whichType))); + obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); Array a; BOOST_FOREACH(const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); -- 1.7.1