mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-01-31 02:20:53 +00:00
rpc: unify auxpow methods
1. Introduces a single cache for templated blocks CAuxBlockCache that is indexed and searchable by both coinbase script and block hash. 2. Integrates the new cache into AuxMiningCreateBlock and AuxMiningSubmitBlock rpc helper functions 3. Modifies AuxMiningSubmitBlock to return the BIP-22 response 4. Modifies getauxblockbip22 to user AuxMiningSubmitBlock Note that although we return the BIP-22 response in AuxMiningSubmitBlock and getauxblockbip22, there is currently no method or configuration that returns this over rpc. All methods return a boolean response. This remains unchanged for backward compatibility.
This commit is contained in:
parent
d7cc7f8bbb
commit
f17f58b9eb
@ -130,6 +130,7 @@ BITCOIN_CORE_H = \
|
||||
protocol.h \
|
||||
random.h \
|
||||
reverselock.h \
|
||||
rpc/auxcache.h \
|
||||
rpc/blockchain.h \
|
||||
rpc/client.h \
|
||||
rpc/mining.h \
|
||||
@ -209,6 +210,7 @@ libdogecoin_server_a_SOURCES = \
|
||||
policy/policy.cpp \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
rpc/auxcache.cpp \
|
||||
rpc/auxpow.cpp \
|
||||
rpc/blockchain.cpp \
|
||||
rpc/mining.cpp \
|
||||
|
||||
@ -82,6 +82,7 @@ BITCOIN_TESTS =\
|
||||
test/addrman_tests.cpp \
|
||||
test/amount_tests.cpp \
|
||||
test/allocator_tests.cpp \
|
||||
test/auxcache_tests.cpp \
|
||||
test/auxpow_tests.cpp \
|
||||
test/base32_tests.cpp \
|
||||
test/base58_tests.cpp \
|
||||
|
||||
135
src/rpc/auxcache.cpp
Normal file
135
src/rpc/auxcache.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2025 The Dogecoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "rpc/auxcache.h"
|
||||
|
||||
#include "script/standard.h" // for CScriptID
|
||||
#include "primitives/block.h" // for CBlock
|
||||
#include "uint256.h" // for uint256
|
||||
#include "utilmemory.h" // for MakeUnique
|
||||
#include "utiltime.h" // for GetTimeMicros
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
|
||||
#include <cstdint> // for uint64_t
|
||||
#include <memory> // for std::unique_ptr, std::shared_ptr
|
||||
#include <mutex> // for std::mutex
|
||||
#include <tuple> // for std::tuple
|
||||
|
||||
namespace {
|
||||
|
||||
//! Type that is stored in the cache
|
||||
struct AuxCacheItem {
|
||||
int64_t cache_time;
|
||||
CScriptID scriptId;
|
||||
uint256 hash;
|
||||
std::shared_ptr<CBlock> pblock;
|
||||
};
|
||||
|
||||
// The ByScriptId index sorts by CScriptID and item age
|
||||
struct ByScriptId {};
|
||||
using ByScriptIdView = std::tuple<const CScriptID&, const int64_t>;
|
||||
struct ByScriptIdExtractor
|
||||
{
|
||||
using result_type = ByScriptIdView;
|
||||
result_type operator()(const AuxCacheItem& item) const
|
||||
{
|
||||
// calculate age
|
||||
const int64_t age = GetMockableTimeMicros() - item.cache_time;
|
||||
return ByScriptIdView{item.scriptId, age};
|
||||
}
|
||||
};
|
||||
|
||||
// The ByBlockHash index sorts by blockhash (uint256)
|
||||
struct ByBlockHash {};
|
||||
struct ByBlockHashExtractor
|
||||
{
|
||||
using result_type = uint256;
|
||||
result_type operator()(const AuxCacheItem& item) const
|
||||
{
|
||||
return item.hash;
|
||||
}
|
||||
};
|
||||
|
||||
/** Data type for the main data structure (AuxCacheItem objects with ByScriptID/ByBlockHash indexes). */
|
||||
using AuxCacheIndex = boost::multi_index_container<
|
||||
AuxCacheItem,
|
||||
boost::multi_index::indexed_by<
|
||||
boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByScriptId>, ByScriptIdExtractor>,
|
||||
boost::multi_index::ordered_unique<boost::multi_index::tag<ByBlockHash>, ByBlockHashExtractor>
|
||||
>
|
||||
>;
|
||||
|
||||
} //anon namespace
|
||||
|
||||
class CAuxBlockCache::Impl {
|
||||
AuxCacheIndex m_index;
|
||||
|
||||
private:
|
||||
std::mutex mut;
|
||||
|
||||
public:
|
||||
Impl() : m_index(boost::make_tuple(
|
||||
boost::make_tuple(ByScriptIdExtractor(), std::less<ByScriptIdView>()),
|
||||
boost::make_tuple(ByBlockHashExtractor(), std::less<uint256>())
|
||||
)) {};
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
bool Add(const CScriptID scriptId, std::shared_ptr<CBlock> pblock) {
|
||||
|
||||
uint256 hash = pblock->GetHash();
|
||||
int64_t micros = GetMockableTimeMicros();
|
||||
|
||||
std::lock_guard<std::mutex> guard(mut);
|
||||
auto ret = m_index.get<ByBlockHash>().emplace(AuxCacheItem{micros, scriptId, hash, pblock});
|
||||
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
m_index.clear();
|
||||
}
|
||||
|
||||
bool Get(const CScriptID scriptId, std::shared_ptr<CBlock>& pblock) const {
|
||||
auto it = m_index.get<ByScriptId>().lower_bound(ByScriptIdView{scriptId, 0LL});
|
||||
if (it != m_index.get<ByScriptId>().end() && it->scriptId == scriptId) {
|
||||
pblock = it->pblock;
|
||||
return true;
|
||||
}
|
||||
pblock.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Get(const uint256 blockhash, std::shared_ptr<CBlock>& pblock) const {
|
||||
auto it = m_index.get<ByBlockHash>().lower_bound(blockhash);
|
||||
if (it != m_index.get<ByBlockHash>().end() && it->hash == blockhash) {
|
||||
pblock = it->pblock;
|
||||
return true;
|
||||
}
|
||||
pblock.reset();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
CAuxBlockCache::CAuxBlockCache() : m_impl(MakeUnique<CAuxBlockCache::Impl>()) {};
|
||||
CAuxBlockCache::~CAuxBlockCache() = default;
|
||||
|
||||
bool CAuxBlockCache::Add(const CScriptID scriptId, std::shared_ptr<CBlock> pblock) {
|
||||
return m_impl->Add(scriptId, pblock);
|
||||
}
|
||||
|
||||
void CAuxBlockCache::Reset() {
|
||||
m_impl->Reset();
|
||||
}
|
||||
|
||||
bool CAuxBlockCache::Get(const CScriptID scriptId, std::shared_ptr<CBlock>& pblock) {
|
||||
return m_impl->Get(scriptId, pblock);
|
||||
}
|
||||
|
||||
bool CAuxBlockCache::Get(const uint256 blockhash, std::shared_ptr<CBlock>& pblock) {
|
||||
return m_impl->Get(blockhash, pblock);
|
||||
}
|
||||
44
src/rpc/auxcache.h
Normal file
44
src/rpc/auxcache.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2025 The Dogecoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DOGECOIN_AUXCACHE_H
|
||||
#define DOGECOIN_AUXCACHE_H
|
||||
|
||||
#include "script/standard.h" // for CScriptID
|
||||
#include "primitives/block.h" // for CBlock
|
||||
#include "uint256.h" // for uint256
|
||||
|
||||
#include <memory> // for std::unique_ptr, std::shared_ptr
|
||||
|
||||
/** Cache to keep track of blocks templated for AuxPoW mining, by CScriptID
|
||||
* (coinbase output script.)
|
||||
*
|
||||
* Searchable by coinbase scriptpubkey (CScriptID) and blockhash (uint256)
|
||||
*
|
||||
*/
|
||||
class CAuxBlockCache {
|
||||
// Do not put impementation details in the header because they are
|
||||
// heavy on includes. Instead use an implementation class.
|
||||
class Impl;
|
||||
const std::unique_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
explicit CAuxBlockCache();
|
||||
~CAuxBlockCache();
|
||||
|
||||
/** Adds a block to the cache */
|
||||
bool Add(const CScriptID scriptId, std::shared_ptr<CBlock> pblock);
|
||||
|
||||
/** Resets the entire cache */
|
||||
void Reset();
|
||||
|
||||
/** Get the cached CBlock (optional) for a CScriptID */
|
||||
bool Get(const CScriptID scriptId, std::shared_ptr<CBlock>& pblock);
|
||||
|
||||
/** Get the cached CBlock (optional) by block hash */
|
||||
bool Get(const uint256 blockhash, std::shared_ptr<CBlock>& pblock);
|
||||
|
||||
};
|
||||
|
||||
#endif //DOGECOIN_AUXCACHE_H
|
||||
@ -15,6 +15,7 @@
|
||||
#include "init.h"
|
||||
#include "miner.h"
|
||||
#include "net.h"
|
||||
#include "rpc/auxcache.h"
|
||||
#include "rpc/server.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
@ -22,21 +23,15 @@
|
||||
#include "validationinterface.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
bool fUseNamecoinApi;
|
||||
|
||||
/**
|
||||
* The variables below are used to keep track of created and not yet
|
||||
* submitted auxpow blocks. Lock them to be sure even for multiple
|
||||
* RPC threads running in parallel.
|
||||
*/
|
||||
|
||||
static CCriticalSection cs_auxblockCache;
|
||||
static std::map<uint256, CBlock*> mapNewBlock;
|
||||
static CCriticalSection cs_auxpowrpc;
|
||||
static CAuxBlockCache auxBlockCache;
|
||||
static std::vector<std::unique_ptr<CBlockTemplate>> vNewBlockTemplate;
|
||||
|
||||
void AuxMiningCheck()
|
||||
@ -62,14 +57,12 @@ void AuxMiningCheck()
|
||||
|
||||
static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey)
|
||||
{
|
||||
|
||||
AuxMiningCheck();
|
||||
LOCK(cs_auxblockCache);
|
||||
LOCK(cs_auxpowrpc);
|
||||
|
||||
static unsigned nTransactionsUpdatedLast;
|
||||
static unsigned int nTransactionsUpdatedLast;
|
||||
static const CBlockIndex* pindexPrev = nullptr;
|
||||
static uint64_t nStart;
|
||||
static std::map<CScriptID, CBlock*> curBlocks;
|
||||
static unsigned nExtraNonce = 0;
|
||||
|
||||
// Dogecoin: Never mine witness tx
|
||||
@ -80,26 +73,23 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey)
|
||||
* a single dogecoind instance, for example when a pool runs multiple sub-
|
||||
* pools with different payout strategies.
|
||||
*/
|
||||
CBlock* pblock = nullptr;
|
||||
std::shared_ptr<CBlock> pblock;
|
||||
CScriptID scriptID (scriptPubKey);
|
||||
auto iter = curBlocks.find(scriptID);
|
||||
if (iter != curBlocks.end()) pblock = iter->second;
|
||||
|
||||
auxBlockCache.Get(scriptID, pblock);
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
||||
// Update block
|
||||
if (pblock == nullptr || pindexPrev != chainActive.Tip()
|
||||
if (!pblock || pindexPrev != chainActive.Tip()
|
||||
|| (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast
|
||||
&& GetTime() - nStart > 60))
|
||||
{
|
||||
if (pindexPrev != chainActive.Tip())
|
||||
{
|
||||
// Clear old blocks since they're obsolete now.
|
||||
mapNewBlock.clear();
|
||||
// Clear caches since they're obsolete now.
|
||||
auxBlockCache.Reset();
|
||||
vNewBlockTemplate.clear();
|
||||
curBlocks.clear();
|
||||
pblock = nullptr;
|
||||
pblock.reset();
|
||||
}
|
||||
|
||||
// Create new block with nonce = 0 and extraNonce = 1
|
||||
@ -118,9 +108,8 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey)
|
||||
newBlock->block.SetAuxpowFlag(true);
|
||||
|
||||
// Save
|
||||
pblock = &newBlock->block;
|
||||
curBlocks[scriptID] = pblock;
|
||||
mapNewBlock[pblock->GetHash()] = pblock;
|
||||
pblock = std::make_shared<CBlock>(newBlock->block);
|
||||
auxBlockCache.Add(scriptID, pblock);
|
||||
vNewBlockTemplate.push_back(std::move(newBlock));
|
||||
}
|
||||
}
|
||||
@ -150,19 +139,19 @@ static UniValue AuxMiningCreateBlock(const CScript& scriptPubKey)
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool AuxMiningSubmitBlock(const std::string& hashHex, const std::string& auxpowHex)
|
||||
static UniValue AuxMiningSubmitBlock(const std::string& hashHex, const std::string& auxpowHex)
|
||||
{
|
||||
|
||||
AuxMiningCheck();
|
||||
LOCK(cs_auxblockCache);
|
||||
LOCK(cs_auxpowrpc);
|
||||
|
||||
uint256 hash;
|
||||
hash.SetHex(hashHex);
|
||||
|
||||
const std::map<uint256, CBlock*>::iterator mit = mapNewBlock.find(hash);
|
||||
if (mit == mapNewBlock.end())
|
||||
std::shared_ptr<CBlock> pblock;
|
||||
if (!auxBlockCache.Get(hash, pblock)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
|
||||
CBlock& block = *mit->second;
|
||||
}
|
||||
CBlock& block = *pblock;
|
||||
|
||||
const std::vector<unsigned char> vchAuxPow = ParseHex(auxpowHex);
|
||||
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
|
||||
@ -173,12 +162,11 @@ static bool AuxMiningSubmitBlock(const std::string& hashHex, const std::string&
|
||||
|
||||
submitblock_StateCatcher sc(block.GetHash());
|
||||
RegisterValidationInterface(&sc);
|
||||
std::shared_ptr<const CBlock> shared_block
|
||||
= std::make_shared<const CBlock>(block);
|
||||
bool fAccepted = ProcessNewBlock(Params(), shared_block, true, nullptr);
|
||||
std::shared_ptr<const CBlock> shared_block = std::make_shared<const CBlock>(block);
|
||||
ProcessNewBlock(Params(), shared_block, true, nullptr);
|
||||
UnregisterValidationInterface(&sc);
|
||||
|
||||
return fAccepted;
|
||||
return BIP22ValidationResult(sc.state);
|
||||
}
|
||||
|
||||
UniValue getauxblockbip22(const JSONRPCRequest& request)
|
||||
@ -216,6 +204,8 @@ UniValue getauxblockbip22(const JSONRPCRequest& request)
|
||||
+ HelpExampleRpc("getauxblock", "")
|
||||
);
|
||||
|
||||
AuxMiningCheck();
|
||||
|
||||
std::shared_ptr<CReserveScript> coinbaseScript;
|
||||
GetMainSignals().ScriptForMining(coinbaseScript);
|
||||
|
||||
@ -227,105 +217,25 @@ UniValue getauxblockbip22(const JSONRPCRequest& request)
|
||||
if (!coinbaseScript->reserveScript.size())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
|
||||
|
||||
AuxMiningCheck();
|
||||
LOCK(cs_auxblockCache);
|
||||
|
||||
/* Create a new block? */
|
||||
if (request.params.size() == 0)
|
||||
{
|
||||
static unsigned nTransactionsUpdatedLast;
|
||||
static const CBlockIndex* pindexPrev = nullptr;
|
||||
static uint64_t nStart;
|
||||
static CBlock* pblock = nullptr;
|
||||
static unsigned nExtraNonce = 0;
|
||||
|
||||
// Update block
|
||||
// Dogecoin: Never mine witness tx
|
||||
const bool fMineWitnessTx = false;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (pindexPrev != chainActive.Tip()
|
||||
|| (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast
|
||||
&& GetTime() - nStart > 60))
|
||||
{
|
||||
if (pindexPrev != chainActive.Tip())
|
||||
{
|
||||
// Clear old blocks since they're obsolete now.
|
||||
mapNewBlock.clear();
|
||||
vNewBlockTemplate.clear();
|
||||
pblock = nullptr;
|
||||
}
|
||||
|
||||
// Create new block with nonce = 0 and extraNonce = 1
|
||||
std::unique_ptr<CBlockTemplate> newBlock(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript, fMineWitnessTx));
|
||||
if (!newBlock)
|
||||
throw JSONRPCError(RPC_OUT_OF_MEMORY, "out of memory");
|
||||
|
||||
// Update state only when CreateNewBlock succeeded
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
pindexPrev = chainActive.Tip();
|
||||
nStart = GetTime();
|
||||
|
||||
// Finalise it by setting the version and building the merkle root
|
||||
IncrementExtraNonce(&newBlock->block, pindexPrev, nExtraNonce);
|
||||
newBlock->block.SetAuxpowFlag(true);
|
||||
|
||||
// Save
|
||||
pblock = &newBlock->block;
|
||||
mapNewBlock[pblock->GetHash()] = pblock;
|
||||
vNewBlockTemplate.push_back(std::move(newBlock));
|
||||
}
|
||||
}
|
||||
|
||||
arith_uint256 target;
|
||||
bool fNegative, fOverflow;
|
||||
target.SetCompact(pblock->nBits, &fNegative, &fOverflow);
|
||||
if (fNegative || fOverflow || target == 0)
|
||||
throw std::runtime_error("invalid difficulty bits in block");
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hash", pblock->GetHash().GetHex());
|
||||
result.pushKV("chainid", pblock->GetChainId());
|
||||
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
|
||||
result.pushKV("coinbasevalue", (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(fUseNamecoinApi ? "_target" : "target", HexStr(BEGIN(target), END(target)));
|
||||
|
||||
return result;
|
||||
return AuxMiningCreateBlock(coinbaseScript->reserveScript);
|
||||
}
|
||||
|
||||
/* Submit a block instead. Note that this need not lock cs_main,
|
||||
since ProcessNewBlock below locks it instead. */
|
||||
|
||||
/* Submit a block instead. */
|
||||
assert(request.params.size() == 2);
|
||||
uint256 hash;
|
||||
hash.SetHex(request.params[0].get_str());
|
||||
|
||||
const std::map<uint256, CBlock*>::iterator mit = mapNewBlock.find(hash);
|
||||
if (mit == mapNewBlock.end())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
|
||||
CBlock& block = *mit->second;
|
||||
std::string blockHashHex = request.params[0].get_str();
|
||||
std::string auxPowHex = request.params[1].get_str();
|
||||
|
||||
const std::vector<unsigned char> vchAuxPow
|
||||
= ParseHex(request.params[1].get_str());
|
||||
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
|
||||
CAuxPow pow;
|
||||
ss >> pow;
|
||||
block.SetAuxpow(new CAuxPow(pow));
|
||||
assert(block.GetHash() == hash);
|
||||
UniValue response = AuxMiningSubmitBlock(blockHashHex, auxPowHex);
|
||||
|
||||
submitblock_StateCatcher sc(block.GetHash());
|
||||
RegisterValidationInterface(&sc);
|
||||
std::shared_ptr<const CBlock> shared_block
|
||||
= std::make_shared<const CBlock>(block);
|
||||
bool fAccepted = ProcessNewBlock(Params(), shared_block, true, nullptr);
|
||||
UnregisterValidationInterface(&sc);
|
||||
|
||||
if (fAccepted)
|
||||
if (response.isNull()) {
|
||||
coinbaseScript->KeepScript();
|
||||
}
|
||||
|
||||
return BIP22ValidationResult(sc.state);
|
||||
return response;
|
||||
}
|
||||
|
||||
UniValue createauxblock(const JSONRPCRequest& request)
|
||||
@ -381,8 +291,12 @@ UniValue submitauxblock(const JSONRPCRequest& request)
|
||||
+ HelpExampleRpc("submitauxblock", "\"hash\" \"serialised auxpow\"")
|
||||
);
|
||||
|
||||
return AuxMiningSubmitBlock(request.params[0].get_str(),
|
||||
request.params[1].get_str());
|
||||
std::string blockHashHex = request.params[0].get_str();
|
||||
std::string auxPowHex = request.params[1].get_str();
|
||||
|
||||
UniValue response = AuxMiningSubmitBlock(blockHashHex, auxPowHex);
|
||||
|
||||
return response.isNull();
|
||||
}
|
||||
|
||||
UniValue getauxblock(const JSONRPCRequest& request)
|
||||
|
||||
150
src/test/auxcache_tests.cpp
Normal file
150
src/test/auxcache_tests.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2025 The Dogecoin Core developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "amount.h"
|
||||
#include "consensus/merkle.cpp"
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "rpc/auxcache.h"
|
||||
#include "script/script.h"
|
||||
#include "utiltime.h"
|
||||
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <memory>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(auxcache_tests, TestingSetup)
|
||||
|
||||
static const std::string cb_pk_1 = "03c758272b121a3e50a1a6a25aad800a45af51486227bb8f06257df80a15120135";
|
||||
static const std::string cb_pk_2 = "020c163123e1e3b8bcf9114e2df152b5aa0bc5f69458991236746be48adce96bed";
|
||||
|
||||
// creates a bare dummy block with auxpow on
|
||||
std::shared_ptr<CBlock> CreateDummyBlock(CScript scriptPubKey, CAmount amount) {
|
||||
CMutableTransaction coinbase{};
|
||||
coinbase.nVersion = 1;
|
||||
coinbase.vin.push_back(CTxIn(uint256::ZERO, 0));
|
||||
coinbase.vout.push_back(CTxOut(amount, scriptPubKey));
|
||||
|
||||
CBlock block{};
|
||||
block.nVersion = 4;
|
||||
block.hashPrevBlock = uint256::ZERO;
|
||||
block.nTime = GetTime();
|
||||
block.nBits = 0x1e0ffff0;
|
||||
block.nNonce = 0;
|
||||
block.SetChainId(98);
|
||||
block.SetAuxpowFlag(true);
|
||||
|
||||
block.vtx.resize(1);
|
||||
block.vtx[0] = MakeTransactionRef(std::move(coinbase));
|
||||
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
||||
return std::make_shared<CBlock>(block);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(check_auxpow) {
|
||||
CAuxBlockCache cache;
|
||||
std::shared_ptr<CBlock> cached_block;
|
||||
bool res;
|
||||
|
||||
CScript cb_script_1 = CScript() << ParseHex(cb_pk_1) << OP_CHECKSIG;
|
||||
CScriptID scriptId_1(cb_script_1);
|
||||
std::shared_ptr<CBlock> created_block_1 = CreateDummyBlock(cb_script_1, CAmount(69));
|
||||
uint256 blockhash_1 = created_block_1->GetHash();
|
||||
|
||||
// add to cache
|
||||
res = cache.Add(scriptId_1, created_block_1);
|
||||
BOOST_CHECK(res);
|
||||
|
||||
// get by scriptId
|
||||
res = cache.Get(scriptId_1, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_1.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// get by hash
|
||||
res = cache.Get(blockhash_1, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_1.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// Adding the same block again fails
|
||||
res = cache.Add(scriptId_1, created_block_1);
|
||||
BOOST_CHECK(!res);
|
||||
|
||||
CScript cb_script_2 = CScript() << ParseHex(cb_pk_2) << OP_CHECKSIG;
|
||||
CScriptID scriptId_2(cb_script_2);
|
||||
std::shared_ptr<CBlock> created_block_2 = CreateDummyBlock(cb_script_2, CAmount(169));
|
||||
uint256 blockhash_2 = created_block_2->GetHash();
|
||||
|
||||
// Make sure the block hashes are different
|
||||
BOOST_CHECK_NE(blockhash_1.GetHex(), blockhash_2.GetHex());
|
||||
|
||||
// add second block to cache
|
||||
res = cache.Add(scriptId_2, created_block_2);
|
||||
BOOST_CHECK(res);
|
||||
|
||||
// get second block by scriptId
|
||||
res = cache.Get(scriptId_2, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_2.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// get second block by hash
|
||||
res = cache.Get(blockhash_2, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_2.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// get first block by scriptId
|
||||
res = cache.Get(scriptId_1, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_1.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// NOTE: since not all OS' have high precision time, we mock +1 second here
|
||||
SetMockTime(GetTime() + 1LL);
|
||||
|
||||
// create another block with the first scriptId
|
||||
std::shared_ptr<CBlock> created_block_3 = CreateDummyBlock(cb_script_1, CAmount(269));
|
||||
uint256 blockhash_3 = created_block_3->GetHash();
|
||||
|
||||
// Make sure the block hashes are different
|
||||
BOOST_CHECK_NE(blockhash_1.GetHex(), blockhash_3.GetHex());
|
||||
|
||||
// add third block to cache
|
||||
res = cache.Add(scriptId_1, created_block_3);
|
||||
BOOST_CHECK(res);
|
||||
|
||||
// get third block by scriptId
|
||||
res = cache.Get(scriptId_1, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_3.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// the first block is still available by hash
|
||||
res = cache.Get(blockhash_1, cached_block);
|
||||
BOOST_CHECK(res);
|
||||
BOOST_CHECK_EQUAL(blockhash_1.GetHex(), cached_block->GetHash().GetHex());
|
||||
|
||||
// clearing the cache removes all data
|
||||
cache.Reset();
|
||||
res = cache.Get(scriptId_1, cached_block);
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK(!cached_block);
|
||||
res = cache.Get(scriptId_2, cached_block);
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK(!cached_block);
|
||||
res = cache.Get(blockhash_1, cached_block);
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK(!cached_block);
|
||||
res = cache.Get(blockhash_2, cached_block);
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK(!cached_block);
|
||||
res = cache.Get(blockhash_3, cached_block);
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK(!cached_block);
|
||||
|
||||
// Unmock time
|
||||
SetMockTime(0LL);
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
x
Reference in New Issue
Block a user