diff --git a/.travis.yml b/.travis.yml index 0b197be7598..6763029af76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index df7cee91c2b..c38ef0e08ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ @@ -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 \ @@ -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) \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 4614179879b..1f5af956181 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -213,6 +213,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 \ diff --git a/src/chain.cpp b/src/chain.cpp index 7a4ce6b0959..f88b79148d4 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -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; diff --git a/src/chain.h b/src/chain.h index 663a8b40824..492ce0dce2c 100644 --- a/src/chain.h +++ b/src/chain.h @@ -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}, @@ -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 { diff --git a/src/chainparams.h b/src/chainparams.h index d8b25c72204..7f28a6912ca 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -91,6 +91,9 @@ class CChainParams const std::vector& 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() {} diff --git a/src/init.cpp b/src/init.cpp index b38f192c187..4a6fc1bd257 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -598,7 +599,7 @@ void SetupServerArgs(NodeContext& node) std::string LicenseInfo() { - const std::string URL_SOURCE_CODE = ""; + const std::string URL_SOURCE_CODE = ""; return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, COPYRIGHT_YEAR) + " ") + "\n" + "\n" + diff --git a/src/miner.h b/src/miner.h index bb7a30b1840..ae123812fd2 100644 --- a/src/miner.h +++ b/src/miner.h @@ -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; @@ -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); diff --git a/src/pow.cpp b/src/pow.cpp index de8ba9be2fd..442b49942e8 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -5,10 +5,12 @@ #include +#include #include #include #include #include +#include #include unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) @@ -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; +} diff --git a/src/pow.h b/src/pow.h index 1d802cd01e4..980f2bc46a2 100644 --- a/src/pow.h +++ b/src/pow.h @@ -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 diff --git a/src/protocol.cpp b/src/protocol.cpp index dc8f795a0cc..55261984c6d 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -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); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 9fcfb081ce4..1963639ce51 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -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())); diff --git a/src/rpc/auxpow_miner.cpp b/src/rpc/auxpow_miner.cpp new file mode 100644 index 00000000000..518736af6aa --- /dev/null +++ b/src/rpc/auxpow_miner.cpp @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(pblock->vtx[0]->vout[0].nValue)); + result.pushKV("bits", strprintf("%08x", pblock->nBits)); + result.pushKV("height", static_cast(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 shared_block; + { + LOCK(cs); + const CBlock* pblock = lookupSavedBlock(hash); + shared_block = std::make_shared(*pblock); + } + + const std::vector vchAuxPow = ParseHex(auxpowHex); + CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION); + std::unique_ptr 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; +} diff --git a/src/rpc/auxpow_miner.h b/src/rpc/auxpow_miner.h new file mode 100644 index 00000000000..553f89cf856 --- /dev/null +++ b/src/rpc/auxpow_miner.h @@ -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 +#include +#include