From 5da72d7da85c4feb30c9de8f88aa59daffb903d0 Mon Sep 17 00:00:00 2001 From: Nell Hardcastle Date: Thu, 10 Apr 2014 21:36:05 -0700 Subject: [PATCH] Enable RPC commands for mining aux proof of work blocks. --- src/core.h | 7 -- src/miner.cpp | 30 ++++- src/miner.h | 3 + src/rpcblockchain.cpp | 36 ++++++ src/rpcmining.cpp | 276 ++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 3 + src/rpcserver.h | 3 + 7 files changed, 346 insertions(+), 12 deletions(-) diff --git a/src/core.h b/src/core.h index 7f3b716c8..57642dcb0 100644 --- a/src/core.h +++ b/src/core.h @@ -399,13 +399,6 @@ public: return nVersion / BLOCK_VERSION_CHAIN_START; } - uint256 GetPoWHash() const - { - uint256 thash; - scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash)); - return thash; - } - void SetAuxPow(CAuxPow* pow); void SetNull() diff --git a/src/miner.cpp b/src/miner.cpp index 6a1f36872..5de11039a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,6 +12,7 @@ #include "main.h" #include "net.h" #include "scrypt.h" +#include "auxpow.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif @@ -472,12 +473,31 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) uint256 hash = pblock->GetPoWHash(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - if (hash > hashTarget) - return false; + CAuxPow *auxpow = pblock->auxpow.get(); - //// debug print - LogPrintf("DogecoinMiner:\n"); - LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + if (auxpow != NULL) { + if (!auxpow->Check(pblock->GetHash(), pblock->GetChainID())) + return error("AUX POW is not valid"); + + if (auxpow->GetParentBlockHash() > hashTarget) + return error("AUX POW parent hash %s is not under target %s", auxpow->GetParentBlockHash().GetHex().c_str(), hashTarget.GetHex().c_str()); + //// debug print + printf("DogecoinMiner:\n"); + printf("AUX proof-of-work found \n our hash: %s \n parent hash: %s \n target: %s\n", + hash.GetHex().c_str(), + auxpow->GetParentBlockHash().GetHex().c_str(), + hashTarget.GetHex().c_str()); + } + else + { + if (hash > hashTarget) + return false; + + //// debug print + printf("DogecoinMiner:\n"); + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + } + pblock->print(); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); diff --git a/src/miner.h b/src/miner.h index 26151f6cd..a174a739d 100644 --- a/src/miner.h +++ b/src/miner.h @@ -7,6 +7,7 @@ #define BITCOIN_MINER_H #include +#include class CBlock; class CBlockIndex; @@ -14,6 +15,7 @@ struct CBlockTemplate; class CReserveKey; class CScript; class CWallet; +class CAuxPow; /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); @@ -22,6 +24,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, std::vector& vchAux); /** Do mining precalculation */ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); /** Check mined block */ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 545d62134..59c72e539 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,6 +7,7 @@ #include "main.h" #include "sync.h" #include "checkpoints.h" +#include "auxpow.h" #include @@ -15,6 +16,9 @@ using namespace json_spirit; using namespace std; +// from rpcraw.cpp +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); + void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); double GetDifficulty(const CBlockIndex* blockindex) @@ -60,6 +64,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); + if (block.nVersion & BLOCK_VERSION_AUXPOW) { + // this block includes auxpow + Object auxpow; + auxpow.push_back(Pair("size", (int)::GetSerializeSize(*block.auxpow, SER_NETWORK, PROTOCOL_VERSION))); + + Object coinbasetx; + TxToJSON(*block.auxpow, 0, coinbasetx); + auxpow.push_back(Pair("coinbasetx", Value(coinbasetx))); + + Array coinbaseMerkle; + BOOST_FOREACH(const uint256 &hash, block.auxpow->vMerkleBranch) + coinbaseMerkle.push_back(hash.GetHex()); + auxpow.push_back(Pair("coinbaseMerkleBranch", coinbaseMerkle)); + auxpow.push_back(Pair("coinbaseIndex", block.auxpow->nIndex)); + + Array chainMerkle; + BOOST_FOREACH(const uint256 &hash, block.auxpow->vChainMerkleBranch) + chainMerkle.push_back(hash.GetHex()); + auxpow.push_back(Pair("chainMerkleBranch", chainMerkle)); + auxpow.push_back(Pair("chainIndex", (boost::uint64_t)block.auxpow->nChainIndex)); + + Object parent_block; + parent_block.push_back(Pair("hash", block.auxpow->parentBlockHeader.GetHash().GetHex())); + parent_block.push_back(Pair("version", (boost::uint64_t)block.auxpow->parentBlockHeader.nVersion)); + parent_block.push_back(Pair("previousblockhash", block.auxpow->parentBlockHeader.hashPrevBlock.GetHex())); + parent_block.push_back(Pair("merkleroot", block.auxpow->parentBlockHeader.hashMerkleRoot.GetHex())); + parent_block.push_back(Pair("time", (boost::int64_t)block.auxpow->parentBlockHeader.nTime)); + parent_block.push_back(Pair("bits", HexBits(block.auxpow->parentBlockHeader.nBits))); + parent_block.push_back(Pair("nonce", (boost::uint64_t)block.auxpow->parentBlockHeader.nNonce)); + auxpow.push_back(Pair("parent_block", Value(parent_block))); + result.push_back(Pair("auxpow", Value(auxpow))); + } Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 368d6d25a..07e913f53 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -5,6 +5,7 @@ #include "rpcserver.h" #include "chainparams.h" +#include "auxpow.h" #include "init.h" #include "net.h" #include "main.h" @@ -629,3 +630,278 @@ 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 \n" + "getworkaux '' \n" + "getworkaux 'submit' \n" + "getworkaux '' *\n" + " get work with auxiliary data in coinbase, for multichain mining\n" + " is the merkle root of the auxiliary chain block hashes, concatenated with the aux chain merkle tree size and a nonce\n" + " is the aux chain index in the aux chain merkle tree\n" + " is the optional merkle branch of the aux chain\n" + "If 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 is specified and 'submit', tries to solve the block for this (parent) chain and returns true if it was successful." + "If is specified and empty first argument, returns the aux merkle root, with size and nonce." + "If and 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(-9, "Dogecoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "Dogecoin is downloading blocks..."); + + static map > mapNewBlock; + static vector vNewBlockTemplate; + static CReserveKey reservekey(pwalletMain); + + if (params.size() == 1) + { + static vector vchAuxPrev; + vector 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); + 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, " must be the empty string or 'submit' if work is being submitted"); + // Parse parameters + vector 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 vchAux; + script.GetOp(pc, opcode, vchAux); + + RemoveMergedMiningHeader(vchAux); + + pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pblock->nBits, 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 [ ]\n" + " create a new block" + "If , is not specified, returns a new block hash.\n" + "If , 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(-9, "Dogecoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "Dogecoin is downloading blocks..."); + + static map mapNewBlock; + static vector 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); + if (!pblocktemplate) + throw JSONRPCError(-7, "Out of memory"); + + pblock = &pblocktemplate->block; + // Update nTime + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nNonce = 0; + + // Push OP_2 just in case we want versioning later + pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(1) << OP_2; + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + // 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 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 diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index b8a195d34..31c73b539 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -317,6 +317,9 @@ static const CRPCCommand vRPCCommands[] = { "gethashespersec", &gethashespersec, true, false, false }, { "getwork", &getwork, true, false, true }, { "setgenerate", &setgenerate, true, true, false }, + { "getwork", &getwork, true, false, true }, + { "getworkaux", &getworkaux, true, false, true }, + { "getauxblock", &getauxblock, true, false, true } #endif // ENABLE_WALLET }; diff --git a/src/rpcserver.h b/src/rpcserver.h index e8cd2cd0f..03797b7f2 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -134,6 +134,9 @@ extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getworkaux(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getauxblock(const json_spirit::Array& params, bool fHelp); + extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp);