Skip to content

Commit

Permalink
consensus: AuxPoW header
Browse files Browse the repository at this point in the history
Add the AuxPoW header to block storage, without yet adding code to mine or validate mined AuxPoW blocks.
  • Loading branch information
Ross Nicoll committed Nov 26, 2021
1 parent 80243b0 commit 5c8ebea
Show file tree
Hide file tree
Showing 4 changed files with 867 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ BITCOIN_TESTS =\
test/addrman_tests.cpp \
test/amount_tests.cpp \
test/allocator_tests.cpp \
test/auxpow_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
Expand Down
154 changes: 154 additions & 0 deletions src/rpc/auxpow_miner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright(c) 2018-2020 Daniel Kraft
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <rpc/auxpow_miner.h>

#include <arith_uint256.h>
#include <auxpow.h>
#include <chainparams.h>
#include <net.h>
#include <node/context.h>
#include <rpc/blockchain.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <util/time.h>
#include <validation.h>

const CBlock*
AuxpowMiner::getCurrentBlock(const CTxMemPool& mempool,
const CScript& scriptPubKey, uint256& target) EXCLUSIVE_LOCKS_REQUIRED(cs)
{
AssertLockHeld(cs);
const CBlock* pblockCur = nullptr;

{
LOCK(cs_main);
CScriptID scriptID(scriptPubKey);
auto iter = curBlocks.find(scriptID);
if (iter != curBlocks.end())
pblockCur = iter->second;

if (pblockCur == nullptr
|| pindexPrev != ::ChainActive().Tip()
||(mempool.GetTransactionsUpdated() != txUpdatedLast
&& GetTime() - startTime > MAX_BLOCK_TEMPLATE_AGE_SECONDS))
{
if (pindexPrev != ::ChainActive().Tip())
{
/* Clear old blocks since they're obsolete now. */
blocks.clear();
templates.clear();
curBlocks.clear();
}

/* Create new block with nonce = 0 and extraNonce = 1. */
std::unique_ptr<CBlockTemplate> newBlock
= BlockAssembler(mempool, Params()).CreateNewBlock(scriptPubKey);
if (newBlock == nullptr)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "out of memory");

/* Update state only when CreateNewBlock succeeded. */
txUpdatedLast = mempool.GetTransactionsUpdated();
pindexPrev = ::ChainActive().Tip();
startTime = GetTime();

/* Finalise it by setting the version and building the merkle root. */
IncrementExtraNonce(&newBlock->block, pindexPrev, extraNonce);
newBlock->block.SetAuxpowFlag(true);

/* Save in our map of constructed blocks. */
pblockCur = &newBlock->block;
curBlocks.emplace(scriptID, pblockCur);
blocks[pblockCur->GetHash()] = pblockCur;
templates.push_back(std::move(newBlock));
}
}

/* At this point, pblockCur is always initialised: If we make it here
without creating a new block above, it means that, in particular,
pindexPrev == ::ChainActive().Tip(). But for that to happen, we must
already have created a pblockCur in a previous call, as pindexPrev is
initialised only when pblockCur is. */
CHECK_NONFATAL(pblockCur);

arith_uint256 arithTarget;
bool fNegative, fOverflow;
arithTarget.SetCompact(pblockCur->nBits, &fNegative, &fOverflow);
if (fNegative || fOverflow || arithTarget == 0)
throw std::runtime_error("invalid difficulty bits in block");
target = ArithToUint256(arithTarget);

return pblockCur;
}

const CBlock*
AuxpowMiner::lookupSavedBlock(const uint256 hash) const EXCLUSIVE_LOCKS_REQUIRED(cs)
{
AssertLockHeld(cs);

const auto iter = blocks.find(hash);
if (iter == blocks.end())
throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");

return iter->second;
}

UniValue
AuxpowMiner::createAuxBlock(const CTxMemPool& mempool,
const CScript& scriptPubKey)
{
LOCK(cs);

uint256 target;
const CBlock* pblock = getCurrentBlock(mempool, scriptPubKey, target);

UniValue result(UniValue::VOBJ);
result.pushKV("hash", pblock->GetHash().GetHex());
result.pushKV("chainid", pblock->GetChainId());
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
result.pushKV("coinbasevalue",
static_cast<int64_t>(pblock->vtx[0]->vout[0].nValue));
result.pushKV("bits", strprintf("%08x", pblock->nBits));
result.pushKV("height", static_cast<int64_t>(pindexPrev->nHeight + 1));
result.pushKV("_target", HexStr(target));

return result;
}

bool
AuxpowMiner::submitAuxBlock(ChainstateManager& chainman,
const uint256 hash,
const std::string& auxpowHex) const
{
std::shared_ptr<CBlock> shared_block;
{
LOCK(cs);
const CBlock* pblock = lookupSavedBlock(hash);
shared_block = std::make_shared<CBlock>(*pblock);
}

const std::vector<unsigned char> vchAuxPow = ParseHex(auxpowHex);
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
std::unique_ptr<CAuxPow> pow(new CAuxPow());
ss >> *pow;
shared_block->SetAuxpow(std::move(pow));
CHECK_NONFATAL(shared_block->GetHash() == hash);

return chainman.ProcessNewBlock(Params(), shared_block, true, nullptr);
}

AuxpowMiner&
AuxpowMiner::get()
{
static AuxpowMiner* instance = nullptr;
static RecursiveMutex lock;

LOCK(lock);
if (instance == nullptr)
instance = new AuxpowMiner();

return *instance;
}
107 changes: 107 additions & 0 deletions src/rpc/auxpow_miner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2018-2020 Daniel Kraft
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_RPC_AUXPOW_MINER_H
#define BITCOIN_RPC_AUXPOW_MINER_H

#include <miner.h>
#include <rpc/request.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

/** The maximum time to retain a built block template for, before forcing replacement. */
// Dogecoin: This is a guesstimate, and may need refinement. Namecoin used 60 seconds (1/10th block interval).
static const unsigned int MAX_BLOCK_TEMPLATE_AGE_SECONDS = 10;

namespace auxpow_tests
{
class AuxpowMinerForTest;
}

/**
* This class holds "global" state used to construct blocks for the auxpow
* mining RPCs and the map of already constructed blocks to look them up
* in the submitauxblock RPC.
*
* It is used as a singleton that is initialised during startup, taking the
* place of the previously real global and static variables.
*/
class AuxpowMiner
{

private:

/** The lock used for state in this object. */
mutable RecursiveMutex cs;
/** All currently "active" block templates. */
std::vector<std::unique_ptr<CBlockTemplate>> templates;
/** Maps block hashes to pointers in vTemplates. Does not own the memory. */
std::map<uint256, const CBlock*> blocks;
/** Maps coinbase script hashes to pointers in vTemplates. Does not own the memory. */
std::map<CScriptID, const CBlock*> curBlocks;

/** The current extra nonce for block creation. */
unsigned extraNonce = 0;

/* Some data about when the current block (pblock) was constructed. */
unsigned txUpdatedLast;
const CBlockIndex* pindexPrev = nullptr;
uint64_t startTime;

/**
* Constructs a new current block if necessary (checking the current state to
* see if "enough changed" for this), and returns a pointer to the block
* that should be returned to a miner for working on at the moment. Also
* fills in the difficulty target value.
*/
const CBlock* getCurrentBlock(const CTxMemPool& mempool,
const CScript& scriptPubKey, uint256& target);

/**
* Looks up a previously constructed block by its (hex-encoded) hash. If the
* block is found, it is returned. Otherwise, a JSONRPCError is thrown.
*/
const CBlock* lookupSavedBlock(const uint256 hash) const;

friend class auxpow_tests::AuxpowMinerForTest;

public:

AuxpowMiner () = default;

/**
* Performs the main work for the "createauxblock" RPC: Construct a new block
* to work on with the given address for the block reward and return the
* necessary information for the miner to construct an auxpow for it.
*/
UniValue createAuxBlock(const CTxMemPool& mempool,
const CScript& scriptPubKey);

/**
* Performs the main work for the "submitauxblock" RPC: Look up the block
* previously created for the given hash, attach the given auxpow to it
* and try to submit it. Returns true if all was successful and the block
* was accepted.
*/
bool submitAuxBlock(ChainstateManager& chainman,
const uint256 hash,
const std::string& auxpowHex) const;

/**
* Returns the singleton instance of AuxpowMiner that is used for RPCs.
*/
static AuxpowMiner& get ();

};

#endif // BITCOIN_RPC_AUXPOW_MINER_H
Loading

0 comments on commit 5c8ebea

Please sign in to comment.