From 6584cd1490e02db9b420733a1105706b7c060c20 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 10 Apr 2015 17:50:43 +0100 Subject: [PATCH] Add block sign/sig combine/etc RPC functions --- src/core_io.h | 1 + src/core_write.cpp | 7 +++ src/rpcclient.cpp | 1 + src/rpcmining.cpp | 117 +++++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 5 +- src/rpcserver.h | 3 ++ 6 files changed, 133 insertions(+), 1 deletion(-) diff --git a/src/core_io.h b/src/core_io.h index bc2eb1edd0..907aac9325 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -25,6 +25,7 @@ extern std::vector ParseHexUV(const UniValue& v, const std::strin // core_write.cpp extern std::string FormatScript(const CScript& script); extern std::string EncodeHexTx(const CTransaction& tx); +extern std::string EncodeHexBlock(const CBlock& block); extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry); diff --git a/src/core_write.cpp b/src/core_write.cpp index 760b6a71bf..c40c8962f3 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -61,6 +61,13 @@ string EncodeHexTx(const CTransaction& tx) return HexStr(ssTx.begin(), ssTx.end()); } +string EncodeHexBlock(const CBlock& block) +{ + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << block; + return HexStr(ssBlock.begin(), ssBlock.end()); +} + void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 1a06d07a9a..3df492c028 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -29,6 +29,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddednodeinfo", 0 }, { "setgenerate", 0 }, { "setgenerate", 1 }, + { "combineblocksigs", 1 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, { "sendtoaddress", 1 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 06338a5c7f..e6ac4da6fb 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -189,6 +189,123 @@ Value setgenerate(const Array& params, bool fHelp) return Value::null; } +Value getnewblockhex(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getnewblockhex\n" + "\nGets hex representation of a proposed, unmined new block\n" + "\nResult\n" + "blockhex (hex) The block hex\n" + "\nExamples:\n" + + HelpExampleCli("getnewblockhex", "") + ); + + if (pwalletMain == NULL) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + + CReserveKey reservekey(pwalletMain); + + Array blockHashes; + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + pblocktemplate->block.hashMerkleRoot = pblocktemplate->block.BuildMerkleTree(); + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << pblocktemplate->block; + return HexStr(ssBlock.begin(), ssBlock.end()); +} + + +Value combineblocksigs(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "combineblocksigs \"blockhex\" [\"signature\",...]\n" + "\nMerges signatures on a block proposal\n" + "\nArguments:\n" + "1. \"blockhex\" (string, required) The hex-encoded block from getnewblockhex\n" + "3. \"signatures\" (string) A json array of signatures\n" + " [\n" + " \"signature\" (string) A signature (in the form of a hex-encoded scriptSig)\n" + " ,...\n" + " ]\n" + "\nResult\n" + "{\n" + " \"hex\": \"value\", (string) The signed block\n" + " \"complete\": n (numeric) if block is complete \n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("combineblocksigs", "") + ); + + CBlock block; + if (!DecodeHexBlk(block, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + Object result; + Array sigs = params[1].get_array(); + BOOST_FOREACH(Value& sig, sigs) { + if (!IsHex(sig.get_str())) + continue; + std::vector vchScript = ParseHex(sig.get_str()); + block.proof.solution = CombineBlockSignatures(block, block.proof.solution, CScript(vchScript.begin(), vchScript.end())); + if (CheckProof(block)) { + result.push_back(Pair("hex", EncodeHexBlock(block))); + result.push_back(Pair("complete", true)); + return result; + } + } + + result.push_back(Pair("hex", EncodeHexBlock(block))); + result.push_back(Pair("complete", false)); + return result; +} + +Value signblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "signblock \"blockhex\"\n" + "\nSigns a block proposal, checking that it would be accepted first\n" + "\nArguments:\n" + "1. \"blockhex\" (string, required) The hex-encoded block from getnewblockhex\n" + "\nResult\n" + " sig (hex) The signature\n" + "\nExamples:\n" + + HelpExampleCli("getnewblockhex", "") + ); + + if (pwalletMain == NULL) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + + CBlock block; + if (!DecodeHexBlk(block, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + uint256 hash = block.GetHash(); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + throw JSONRPCError(RPC_VERIFY_ERROR, "already have block"); + + CBlockIndex* const pindexPrev = chainActive.Tip(); + // TestBlockValidity only supports blocks built on the current Tip + if (block.hashPrevBlock != pindexPrev->GetBlockHash()) + throw JSONRPCError(RPC_VERIFY_ERROR, "proposal was not based on our best chain"); + + CValidationState state; + if (!TestBlockValidity(state, block, pindexPrev, false, true) || !state.IsValid()) { + std::string strRejectReason = state.GetRejectReason(); + if (strRejectReason.empty()) + throw JSONRPCError(RPC_VERIFY_ERROR, state.IsInvalid() ? "Block proposal was invalid" : "Error checking block proposal"); + throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); + } + + block.proof.solution = CScript(); + GenerateProof(&block, pwalletMain); + return HexStr(block.proof.solution.begin(), block.proof.solution.end()); +} + #endif diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 773d16c2f3..3d6239458a 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -284,7 +284,10 @@ static const CRPCCommand vRPCCommands[] = #ifdef ENABLE_WALLET /* Coin generation */ { "generating", "getgenerate", &getgenerate, true, false, false }, - { "generating", "setgenerate", &setgenerate, true, true, false }, + { "generating", "setgenerate", &setgenerate, true, false, false }, + { "generating", "getnewblockhex", &getnewblockhex, true, false, false }, + { "generating", "combineblocksigs", &combineblocksigs, true, false, false }, + { "generating", "signblock", &signblock, true, false, true }, #endif /* Raw transactions */ diff --git a/src/rpcserver.h b/src/rpcserver.h index 482c6cff94..8dd979b43f 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -153,6 +153,9 @@ extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fH extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnewblockhex(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value combineblocksigs(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value signblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);