diff options
author | Luke Dashjr <luke-jr+git@utopios.org> | 2012-05-12 14:31:32 +0000 |
---|---|---|
committer | Luke Dashjr <luke-jr+git@utopios.org> | 2012-08-03 01:02:51 +0000 |
commit | 3390014fd0d91b0148425e794ac01c10b646a682 (patch) | |
tree | e5ed1c8f1b6fc2072874b25b469113aa704339eb /src/bitcoinrpc.cpp | |
parent | a1c3d8f14dca6a86fa103d86ef125e95372f860c (diff) |
Minimal BIP 22 (getblocktemplate) support
- Replaces getmemorypool with new getblocktemplate
- Add missing keys: coinbaseaux, target, mutable, noncerange, sigoplimit, sizelimit, and height
- Accept and send parameter Objects, checking "mode" key if present
- Return rejection reason "rejected" for submit mode
Diffstat (limited to 'src/bitcoinrpc.cpp')
-rw-r--r-- | src/bitcoinrpc.cpp | 115 |
1 files changed, 95 insertions, 20 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index d8b9782e3e..94d46b69de 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1862,24 +1862,43 @@ Value getwork(const Array& params, bool fHelp) } -Value getmemorypool(const Array& params, bool fHelp) +Value getblocktemplate(const Array& params, bool fHelp) { - if (fHelp || params.size() > 1) + if (fHelp || params.size() != 1) throw runtime_error( - "getmemorypool [data]\n" - "If [data] is not specified, returns data needed to construct a block to work on:\n" + "getblocktemplate [params]\n" + "If [params] does not contain a \"data\" key, returns data needed to construct a block to work on:\n" " \"version\" : block version\n" " \"previousblockhash\" : hash of current highest block\n" " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" + " \"coinbaseaux\" : data that should be included in coinbase\n" " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" - " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n" - " \"time\" : timestamp appropriate for next block\n" + " \"target\" : hash target\n" " \"mintime\" : minimum timestamp appropriate for next block\n" " \"curtime\" : current timestamp\n" + " \"mutable\" : list of ways the block template may be changed\n" + " \"noncerange\" : range of valid nonces\n" + " \"sigoplimit\" : limit of sigops in blocks\n" + " \"sizelimit\" : limit of block size\n" " \"bits\" : compressed target of next block\n" - "If [data] is specified, tries to solve the block and returns true if it was successful."); + " \"height\" : height of the next block\n" + "If [params] does contain a \"data\" key, tries to solve the block and returns null if it was successful (and \"rejected\" if not)\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); - if (params.size() == 0) + const Object& oparam = params[0].get_obj(); + std::string strMode; + { + const Value& modeval = find_value(oparam, "mode"); + if (modeval.type() == str_type) + strMode = modeval.get_str(); + else + if (find_value(oparam, "data").type() == null_type) + strMode = "template"; + else + strMode = "submit"; + } + + if (strMode == "template") { if (vNodes.empty()) throw JSONRPCError(-9, "Bitcoin is not connected!"); @@ -1914,38 +1933,93 @@ Value getmemorypool(const Array& params, bool fHelp) pblock->nNonce = 0; Array transactions; - BOOST_FOREACH(CTransaction tx, pblock->vtx) { - if(tx.IsCoinBase()) + map<uint256, int64_t> setTxIndex; + int i = 0; + CTxDB txdb("r"); + BOOST_FOREACH (CTransaction& tx, pblock->vtx) + { + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase()) continue; - CDataStream ssTx; + Object entry; + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << tx; + entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); - transactions.push_back(HexStr(ssTx.begin(), ssTx.end())); + entry.push_back(Pair("hash", txHash.GetHex())); + + MapPrevTx mapInputs; + map<uint256, CTxIndex> mapUnused; + bool fInvalid = false; + if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + { + entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); + + Array deps; + BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) + { + if (setTxIndex.count(inp.first)) + deps.push_back(setTxIndex[inp.first]); + } + entry.push_back(Pair("depends", deps)); + + int64_t nSigOps = tx.GetLegacySigOpCount(); + nSigOps += tx.GetP2SHSigOpCount(mapInputs); + entry.push_back(Pair("sigops", nSigOps)); + } + + transactions.push_back(entry); + } + + Object aux; + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + static Array aMutable; + if (aMutable.empty()) + { + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); } Object result; result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); - result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - result.push_back(Pair("time", (int64_t)pblock->nTime)); + result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); - result.push_back(Pair("curtime", (int64_t)GetAdjustedTime())); + result.push_back(Pair("mutable", aMutable)); + result.push_back(Pair("noncerange", "00000000ffffffff")); + result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); + result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); + result.push_back(Pair("curtime", (int64_t)pblock->nTime)); result.push_back(Pair("bits", HexBits(pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); return result; } else + if (strMode == "submit") { // Parse parameters - CDataStream ssBlock(ParseHex(params[0].get_str())); + CDataStream ssBlock(ParseHex(find_value(oparam, "data").get_str()), SER_NETWORK, PROTOCOL_VERSION); CBlock pblock; ssBlock >> pblock; - return ProcessBlock(NULL, &pblock); + bool fAccepted = ProcessBlock(NULL, &pblock); + + return fAccepted ? Value::null : "rejected"; } + + throw JSONRPCError(-8, "Invalid mode"); } Value getblockhash(const Array& params, bool fHelp) @@ -2044,7 +2118,7 @@ pair<string, rpcfn_type> pCallTable[] = make_pair("getwork", &getwork), make_pair("listaccounts", &listaccounts), make_pair("settxfee", &settxfee), - make_pair("getmemorypool", &getmemorypool), + make_pair("getblocktemplate", &getblocktemplate), make_pair("listsinceblock", &listsinceblock), make_pair("dumpprivkey", &dumpprivkey), make_pair("importprivkey", &importprivkey) @@ -2074,7 +2148,7 @@ string pAllowInSafeMode[] = "walletlock", "validateaddress", "getwork", - "getmemorypool", + "getblocktemplate", }; set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0])); @@ -2499,7 +2573,7 @@ void ThreadRPCServer2(void* parg) if (valMethod.type() != str_type) throw JSONRPCError(-32600, "Method must be a string"); string strMethod = valMethod.get_str(); - if (strMethod != "getwork" && strMethod != "getmemorypool") + if (strMethod != "getwork" && strMethod != "getblocktemplate") printf("ThreadRPCServer method=%s\n", strMethod.c_str()); // Parse params @@ -2681,6 +2755,7 @@ int CommandLineRPC(int argc, char *argv[]) if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]); if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]); if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]); + if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]); if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "sendmany" && n > 1) { |