aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoinrpc.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2012-05-12 14:31:32 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2012-08-03 01:02:51 +0000
commit3390014fd0d91b0148425e794ac01c10b646a682 (patch)
treee5ed1c8f1b6fc2072874b25b469113aa704339eb /src/bitcoinrpc.cpp
parenta1c3d8f14dca6a86fa103d86ef125e95372f860c (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.cpp115
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)
{