aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Maxwell <greg@xiph.org>2012-08-13 10:21:33 -0700
committerGregory Maxwell <greg@xiph.org>2012-08-13 10:21:33 -0700
commit14486dc0e2099762a9e703cf749699ca08cb71f0 (patch)
tree7a304d811eb79ec0279786e60737a348f52f1d0a
parentb2ce93fe1605c77ea5970e3ddac38bca50d7d1a7 (diff)
parent44427fa8332b2ae090256345ec5f9e6e78e04dba (diff)
Merge pull request #936 from luke-jr/gmp_bip
BIP22: getblocktemplate
-rw-r--r--src/bitcoinrpc.cpp111
1 files changed, 93 insertions, 18 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 2e3f8a8e5b..208c830aa9 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -1923,24 +1923,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!");
@@ -1985,38 +2004,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;
+ 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()), SER_NETWORK, PROTOCOL_VERSION);
+ 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 getrawmempool(const Array& params, bool fHelp)
@@ -2128,7 +2202,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getwork", &getwork, true },
{ "listaccounts", &listaccounts, false },
{ "settxfee", &settxfee, false },
- { "getmemorypool", &getmemorypool, true },
+ { "getblocktemplate", &getblocktemplate, true },
{ "listsinceblock", &listsinceblock, false },
{ "dumpprivkey", &dumpprivkey, false },
{ "importprivkey", &importprivkey, false },
@@ -2736,7 +2810,7 @@ void JSONRequest::parse(const Value& valRequest)
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a 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
@@ -3015,6 +3089,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
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) ConvertTo<Object>(params[1]);
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);