forked from dogecoin/dogecoin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
4 changed files
with
867 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.