This commit is contained in:
myriadcoin
2015-07-08 20:47:42 +02:00
parent e0eb59aa50
commit 92ebd5be96
15 changed files with 544 additions and 43 deletions
+287
View File
@@ -633,3 +633,290 @@ Value submitblock(const Array& params, bool fHelp)
return Value::null;
}
#ifdef ENABLE_WALLET
Value getworkaux(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1)
throw runtime_error(
"getworkaux <aux>\n"
"getworkaux '' <data>\n"
"getworkaux 'submit' <data>\n"
"getworkaux '' <data> <chain-index> <branch>*\n"
" get work with auxiliary data in coinbase, for multichain mining\n"
"<aux> is the merkle root of the auxiliary chain block hashes, concatenated with the aux chain merkle tree size and a nonce\n"
"<chain-index> is the aux chain index in the aux chain merkle tree\n"
"<branch> is the optional merkle branch of the aux chain\n"
"If <data> is not specified, returns formatted hash data to work on:\n"
" \"midstate\" : precomputed hash state after hashing the first half of the data\n"
" \"data\" : block data\n"
" \"hash1\" : formatted hash buffer for second hash\n"
" \"target\" : little endian hash target\n"
"If <data> is specified and 'submit', tries to solve the block for this (parent) chain and returns true if it was successful."
"If <data> is specified and empty first argument, returns the aux merkle root, with size and nonce."
"If <data> and <chain-index> are specified, creates an auxiliary proof of work for the chain specified and returns:\n"
" \"aux\" : merkle root of auxiliary chain block hashes\n"
" \"auxpow\" : aux proof of work to submit to aux chain\n"
);
if (vNodes.empty())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Unitus is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Unitus is downloading blocks...");
// We use height plus one because we're testing the next block
if ((chainActive.Tip()->nHeight+1) < GetAuxPowStartBlock()) {
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "getworkaux method is not available until switch-over block.");
}
static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
static vector<CBlockTemplate*> vNewBlockTemplate;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 1)
{
static vector<unsigned char> vchAuxPrev;
vector<unsigned char> vchAux = ParseHex(params[0].get_str());
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
static uint64_t nStart;
static CBlockTemplate* pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
if (pindexPrev != chainActive.Tip())
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
delete pblocktemplate;
vNewBlockTemplate.clear();
}
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
pindexPrev = chainActive.Tip();
vchAuxPrev = vchAux;
nStart = GetTime();
// Create new block
pblocktemplate = CreateNewBlockWithKey(*pMiningKey, miningAlgo);
if (!pblocktemplate)
throw JSONRPCError(-7, "Out of memory");
vNewBlockTemplate.push_back(pblocktemplate);
}
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nNonce = 0;
// Update nExtraNonce
static unsigned int nExtraNonce = 0;
IncrementExtraNonceWithAux(pblock, pindexPrev, nExtraNonce, vchAux);
// Save
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
// Prebuild hash buffers
char pmidstate[32];
char pdata[128];
char phash1[64];
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
return result;
}
else
{
if (params[0].get_str() != "submit" && params[0].get_str() != "")
throw JSONRPCError(-8, "<aux> must be the empty string or 'submit' if work is being submitted");
// Parse parameters
vector<unsigned char> vchData = ParseHex(params[1].get_str());
if (vchData.size() != 128)
throw JSONRPCError(-8, "Invalid parameter");
CBlock* pdata = (CBlock*)&vchData[0];
// Byte reverse
for (int i = 0; i < 128/4; i++)
((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
// Get the aux merkle root from the coinbase
CScript script = pblock->vtx[0].vin[0].scriptSig;
opcodetype opcode;
CScript::const_iterator pc = script.begin();
script.GetOp(pc, opcode);
script.GetOp(pc, opcode);
script.GetOp(pc, opcode);
if (opcode != OP_2)
throw runtime_error("invalid aux pow script");
vector<unsigned char> vchAux;
script.GetOp(pc, opcode, vchAux);
RemoveMergedMiningHeader(vchAux);
unsigned int nHeight = chainActive.Tip()->nHeight+1; // Height first in coinbase required for block.version=2
pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(nHeight, nExtraNonce, vchAux);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
if (params.size() > 2)
{
// Requested aux proof of work
int nChainIndex = params[2].get_int();
CAuxPow pow(pblock->vtx[0]);
for (unsigned int i = 3 ; i < params.size() ; i++)
{
uint256 nHash;
nHash.SetHex(params[i].get_str());
pow.vChainMerkleBranch.push_back(nHash);
}
pow.SetMerkleBranch(pblock);
pow.nChainIndex = nChainIndex;
pow.parentBlockHeader = *pblock;
CDataStream ss(SER_GETHASH, PROTOCOL_VERSION);
ss << pow;
Object result;
result.push_back(Pair("auxpow", HexStr(ss.begin(), ss.end())));
return result;
}
else
{
if (params[0].get_str() == "submit")
{
return CheckWork(pblock, *pwalletMain, reservekey);
}
else
{
Object result;
result.push_back(Pair("aux", HexStr(vchAux.begin(), vchAux.end())));
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
return result;
}
}
}
}
Value getauxblock(const Array& params, bool fHelp)
{
if (fHelp || (params.size() != 0 && params.size() != 2))
throw runtime_error(
"getauxblock [<hash> <auxpow>]\n"
" create a new block"
"If <hash>, <auxpow> is not specified, returns a new block hash.\n"
"If <hash>, <auxpow> is specified, tries to solve the block based on "
"the aux proof of work and returns true if it was successful.");
if (vNodes.empty())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Unitus is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Unitus is downloading blocks...");
// We use height plus one because we're testing the next block
if ((chainActive.Tip()->nHeight+1) < GetAuxPowStartBlock()) {
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "getauxblock method is not available until switch-over block.");
}
static map<uint256, CBlock*> mapNewBlock;
static vector<CBlockTemplate*> vNewBlockTemplate;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
{
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
static uint64_t nStart;
static CBlock* pblock;
static CBlockTemplate* pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
if (pindexPrev != chainActive.Tip())
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
delete pblocktemplate;
vNewBlockTemplate.clear();
}
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
pindexPrev = chainActive.Tip();
nStart = GetTime();
// Create new block with nonce = 0 and extraNonce = 1
pblocktemplate = CreateNewBlockWithKey(*pMiningKey, miningAlgo);
if (!pblocktemplate)
throw JSONRPCError(-7, "Out of memory");
pblock = &pblocktemplate->block;
// Update nTime
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nNonce = 0;
// Update nExtraNonce
static unsigned int nExtraNonce = 0;
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
// Sets the version
pblock->SetAuxPow(new CAuxPow());
// Save
mapNewBlock[pblock->GetHash()] = pblock;
vNewBlockTemplate.push_back(pblocktemplate);
}
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
result.push_back(Pair("chainid", pblock->GetChainID()));
return result;
}
else
{
uint256 hash;
hash.SetHex(params[0].get_str());
vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str());
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
CAuxPow* pow = new CAuxPow();
ss >> *pow;
if (!mapNewBlock.count(hash))
return ::error("getauxblock() : block not found");
CBlock* pblock = mapNewBlock[hash];
pblock->SetAuxPow(pow);
if (!CheckWork(pblock, *pwalletMain, reservekey))
{
return false;
}
else
{
return true;
}
}
}
#endif