Skip to content

Commit

Permalink
Merge AuxPoW support from Namecore
Browse files Browse the repository at this point in the history
Changes are as below:

* Wrap CBlockHeader::nVersion into a new class (CBlockVersion).  This allows to take care of interpreting the field into a base version, auxpow flag and the chain ID.
* Update getauxblock.py for new 'generate' RPC call.
* Add 'auxpow' to block JSON.
* Accept auxpow as PoW verification.
* Add unit tests for auxpow verification.
* Add check for memory-layout of CBlockVersion.
* Weaken auxpow chain ID checks for the testnet.
* Allow Params() to overrule when to check the auxpow chain ID and for legacy blocks.  Use this to disable the checks on testnet.
* Split the block header part that is used by auxpow and the "real" block header (that uses auxpow) to resolve the cyclic dependency between the two.
* Differentiate between uint256 and arith_uint256.
* Add missing lock in auxpow_tests.
* Fix REST header check for auxpow headers.
  * Those can be longer, thus take that into account.  Also perform the check actually on an auxpow header.
* Correctly set the coinbase for getauxblock results.
* Call IncrementExtraNonce in getauxblock so that the coinbase is actually initialised with the stuff it should be.  (BIP30 block height and COINBASE_FLAGS.)
* Implement getauxblock plus regression test.
* Turn auxpow test into FIXTURE test.
  * This allows using of the Params() calls.
* Move CMerkleTx code to auxpow.cpp.
  * Otherwise we get linker errors when building without wallet.
* Fix rebase with BIP66.
* Update the code to handle BIP66's nVersion=3.
* Enforce that auxpow parent blocks have no auxpow block version.
  * This is for compatibility with namecoind.  See also namecoin/namecoin-legacy#199.
* Move auxpow-related parameters to Consensus::Params.
  • Loading branch information
Ross Nicoll authored and patricklodder committed May 11, 2022
1 parent a8313b8 commit 43967a0
Show file tree
Hide file tree
Showing 36 changed files with 2,246 additions and 274 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ install:
before_script:
# Temporary workaround for https://github.com/bitcoin/bitcoin/issues/16368
- for i in {1..4}; do echo "$(sleep 500)" ; done &
- set -o errexit; source ./ci/test/05_before_script.sh &> "/dev/null"
- set -o errexit; source ./ci/test/05_before_script.sh
script:
- export CONTINUE=1
- if [ $SECONDS -gt 1200 ]; then export CONTINUE=0; fi # Likely the depends build took very long
- if [ $SECONDS -gt 1800 ]; then export CONTINUE=0; fi # Likely the depends build took very long
- if [ $TRAVIS_REPO_SLUG = "bitcoin/bitcoin" ]; then export CONTINUE=1; fi # continue on repos with extended build time (90 minutes)
- if [ $CONTINUE = "1" ]; then set -o errexit; source ./ci/test/06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
- if [[ $SECONDS -gt 50*60-$EXPECTED_TESTS_DURATION_IN_SECONDS ]]; then export CONTINUE=0; fi
Expand Down
5 changes: 5 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ BITCOIN_CORE_H = \
random.h \
randomenv.h \
reverse_iterator.h \
rpc/auxpow_miner.h \
rpc/blockchain.h \
rpc/client.h \
rpc/mining.h \
rpc/protocol.h \
rpc/rawtransaction.h \
rpc/rawtransaction_util.h \
rpc/register.h \
rpc/request.h \
Expand Down Expand Up @@ -318,6 +320,7 @@ libbitcoin_server_a_SOURCES = \
policy/settings.cpp \
pow.cpp \
rest.cpp \
rpc/auxpow_miner.cpp \
rpc/blockchain.cpp \
rpc/mining.cpp \
rpc/misc.cpp \
Expand Down Expand Up @@ -590,8 +593,10 @@ if TARGET_WINDOWS
dogecoin_daemon_sources += bitcoind-res.rc
endif

# FIXME: Remove SERVER once we have cleaned up getauxblock.
dogecoin_bin_ldadd = \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBUNIVALUE) \
Expand Down
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
2 changes: 1 addition & 1 deletion src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ bool ReadBlockHeaderFromDisk(CBlockHeader& block, const CBlockIndex* pindex, con

/* Moved here from the header, because we need auxpow and the logic
becomes more involved. */
CBlockHeader CBlockIndex::GetBlockHeader(const Consensus::Params& consensusParams, bool fCheckPOW) const
CBlockHeader CBlockIndex::GetBlockHeader(const Consensus::Params& consensusParams, const bool fCheckPOW) const
{
CBlockHeader block;

Expand Down
4 changes: 2 additions & 2 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class CBlockIndex
{
}

explicit CBlockIndex(const CBlockHeader& block)
explicit CBlockIndex(const CPureBlockHeader& block)
: nVersion{block.nVersion},
hashMerkleRoot{block.hashMerkleRoot},
nTime{block.nTime},
Expand All @@ -218,7 +218,7 @@ class CBlockIndex
return ret;
}

CBlockHeader GetBlockHeader(const Consensus::Params& consensusParams, bool fCheckPOW = true) const;
CBlockHeader GetBlockHeader(const Consensus::Params& consensusParams, const bool fCheckPOW = true) const;

uint256 GetBlockHash() const
{
Expand Down
3 changes: 3 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class CChainParams
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
const ChainTxData& TxData() const { return chainTxData; }

void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);

protected:
CChainParams() {}

Expand Down
3 changes: 2 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <policy/settings.h>
#include <primitives/pureheader.h>
#include <protocol.h>
#include <rpc/auxpow_miner.h>
#include <rpc/blockchain.h>
#include <rpc/register.h>
#include <rpc/server.h>
Expand Down Expand Up @@ -600,7 +601,7 @@ void SetupServerArgs(NodeContext& node)

std::string LicenseInfo()
{
const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
const std::string URL_SOURCE_CODE = "<https://github.com/dogecoin/dogecoin>";

return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
Expand Down
3 changes: 3 additions & 0 deletions src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,12 @@ class BlockAssembler
// Configuration parameters for the block size
bool fIncludeWitness;
unsigned int nBlockMaxWeight;
bool fNeedSizeAccounting;
CFeeRate blockMinFeeRate;

// Information on the current status of the block
uint64_t nBlockWeight;
uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
CAmount nFees;
Expand Down Expand Up @@ -200,6 +202,7 @@ class BlockAssembler
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainParams);

/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
void RegenerateCommitments(CBlock& block);
Expand Down
40 changes: 40 additions & 0 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

#include <pow.h>

#include <auxpow.h>
#include <arith_uint256.h>
#include <chain.h>
#include <dogecoin.h>
#include <primitives/block.h>
#include <util/system.h>
#include <uint256.h>

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
Expand Down Expand Up @@ -114,3 +116,41 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&

return true;
}

bool CheckAuxPowProofOfWork(const CBlockHeader& block, const Consensus::Params& params)
{
/* Except for legacy blocks with full version 1, ensure that
the chain ID is correct. Legacy blocks are not allowed since
the merge-mining start, which is checked in AcceptBlockHeader
where the height is known. */
if (!block.IsLegacy() && params.fStrictChainId
&& block.GetChainId() != params.nAuxpowChainId)
return error("%s : block does not have our chain ID"
" (got %d, expected %d, full nVersion %d)",
__func__, block.GetChainId(),
params.nAuxpowChainId, block.nVersion);

/* If there is no auxpow, just check the block hash. */
if (!block.auxpow) {
if (block.IsAuxpow())
return error("%s : no auxpow on block with auxpow version",
__func__);

if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, params))
return error("%s : non-AUX proof of work failed", __func__);

return true;
}

/* We have auxpow. Check it. */

if (!block.IsAuxpow())
return error("%s : auxpow on block with non-auxpow version", __func__);

if (!block.auxpow->check(block.GetHash(), block.GetChainId(), params))
return error("%s : AUX POW is not valid", __func__);
if (!CheckProofOfWork(block.auxpow->getParentBlockPoWHash(), block.nBits, params))
return error("%s : AUX proof of work failed", __func__);

return true;
}
8 changes: 8 additions & 0 deletions src/pow.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,12 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);

/**
* Check proof-of-work of a block header, taking auxpow into account.
* @param block The block header.
* @param params Consensus parameters.
* @return True iff the PoW is correct.
*/
bool CheckAuxPowProofOfWork(const CBlockHeader& block, const Consensus::Params& params);

#endif // BITCOIN_POW_H
1 change: 0 additions & 1 deletion src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ bool CMessageHeader::IsCommandValid() const
return true;
}


ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) {
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
Expand Down
2 changes: 1 addition & 1 deletion src/qt/test/wallettests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
// QT_QPA_PLATFORM=cocoa src/qt/test/test_bitcoin-qt # macOS
void TestGUI(interfaces::Node& node)
{
// Set up wallet and chain with 105 blocks (5 mature blocks for spending).
// Set up wallet and chain with 245 blocks (5 mature blocks for spending).
TestChain240Setup test;
for (int i = 0; i < 5; ++i) {
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
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;
}
Loading

0 comments on commit 43967a0

Please sign in to comment.