Enable RPC commands for mining aux proof of work blocks.

This commit is contained in:
Nell Hardcastle 2014-04-10 21:36:05 -07:00 committed by Patrick Lodder
parent 8808f237aa
commit 5da72d7da8
7 changed files with 346 additions and 12 deletions

View file

@ -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()

View file

@ -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());

View file

@ -7,6 +7,7 @@
#define BITCOIN_MINER_H
#include <stdint.h>
#include <vector>
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<unsigned char>& vchAux);
/** Do mining precalculation */
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
/** Check mined block */

View file

@ -7,6 +7,7 @@
#include "main.h"
#include "sync.h"
#include "checkpoints.h"
#include "auxpow.h"
#include <stdint.h>
@ -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());

View file

@ -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 <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(-9, "Dogecoin is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
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);
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);
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 [<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(-9, "Dogecoin is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
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);
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<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

View file

@ -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
};

View file

@ -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);