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
This commit is contained in:
parent
a1c3d8f14d
commit
3390014fd0
1 changed files with 96 additions and 21 deletions
|
@ -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;
|
||||
ssTx << tx;
|
||||
Object entry;
|
||||
|
||||
transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << tx;
|
||||
entry.push_back(Pair("data", 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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue