mirror of
https://github.com/jwinterm/myriadcoin.git
synced 2026-10-18 05:51:27 +02:00
auxpow
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user