Page MenuHomePhabricator

No OneTemporary

diff --git a/doc/release-notes.md b/doc/release-notes.md
index 235fca5f8..8d159de9a 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,20 +1,23 @@
Bitcoin ABC version 0.21.6 is now available from:
<https://download.bitcoinabc.org/0.21.6/>
This release includes the following features and fixes:
- The autotools build system (`autogen`, `configure`, ...) is deprecated and
will be removed in a future release. Cmake is the replacement build system,
look at the documentation for the build instructions. To continue using the
autotools build system, pass the --enable-deprecated-build-system flag to
`configure`.
- The rpcallowip option can no longer be used to automatically listen
on all network interfaces. Instead, the rpcbind parameter must also
be used to specify the IP addresses to listen on. Listening for RPC
commands over a public network connection is insecure and should be
disabled, so a warning is now printed if a user selects such a
configuration. If you need to expose RPC in order to use a tool
like Docker, ensure you only bind RPC to your localhost, e.g. docker run [...] -p 127.0.0.1:8332:8332 (this is an extra :8332 over the
normal Docker port specification).
+ - The `getmininginfo` RPC now omits `currentblocksize` and `currentblocktx`
+ when a block was never assembled via RPC on this node.
+
diff --git a/src/miner.cpp b/src/miner.cpp
index af8c171aa..b7ce0bf82 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -1,599 +1,594 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <miner.h>
#include <amount.h>
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <config.h>
#include <consensus/activation.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <hash.h>
#include <minerfund.h>
#include <net.h>
#include <policy/policy.h>
#include <pow.h>
#include <primitives/transaction.h>
#include <script/standard.h>
#include <timedata.h>
#include <txmempool.h>
#include <util/moneystr.h>
#include <util/system.h>
#include <validation.h>
#include <validationinterface.h>
#include <algorithm>
#include <queue>
#include <utility>
-// Unconfirmed transactions in the memory pool often depend on other
-// transactions in the memory pool. When we select transactions from the
-// pool, we select by highest fee rate of a transaction combined with all
-// its ancestors.
-
-uint64_t nLastBlockTx = 0;
-uint64_t nLastBlockSize = 0;
-
int64_t UpdateTime(CBlockHeader *pblock, const Consensus::Params &params,
const CBlockIndex *pindexPrev) {
int64_t nOldTime = pblock->nTime;
int64_t nNewTime =
std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
if (nOldTime < nNewTime) {
pblock->nTime = nNewTime;
}
// Updating time can change work required on testnet:
if (params.fPowAllowMinDifficultyBlocks) {
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, params);
}
return nNewTime - nOldTime;
}
uint64_t CTxMemPoolModifiedEntry::GetVirtualSizeWithAncestors() const {
return GetVirtualTransactionSize(nSizeWithAncestors,
nSigOpCountWithAncestors);
}
BlockAssembler::Options::Options()
: nExcessiveBlockSize(DEFAULT_MAX_BLOCK_SIZE),
nMaxGeneratedBlockSize(DEFAULT_MAX_GENERATED_BLOCK_SIZE),
blockMinFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB) {}
BlockAssembler::BlockAssembler(const CChainParams &params,
const CTxMemPool &_mempool,
const Options &options)
: chainparams(params), mempool(&_mempool) {
blockMinFeeRate = options.blockMinFeeRate;
// Limit size to between 1K and options.nExcessiveBlockSize -1K for sanity:
nMaxGeneratedBlockSize = std::max<uint64_t>(
1000, std::min<uint64_t>(options.nExcessiveBlockSize - 1000,
options.nMaxGeneratedBlockSize));
// Calculate the max consensus sigchecks for this block.
auto nMaxBlockSigChecks =
GetMaxBlockSigChecksCount(options.nExcessiveBlockSize);
// Allow the full amount of signature check operations in lieu of a separate
// config option. (We are mining relayed transactions with validity cached
// by everyone else, and so the block will propagate quickly, regardless of
// how many sigchecks it contains.)
nMaxGeneratedBlockSigChecks = nMaxBlockSigChecks;
}
static BlockAssembler::Options DefaultOptions(const Config &config) {
// Block resource limits
// If -blockmaxsize is not given, limit to DEFAULT_MAX_GENERATED_BLOCK_SIZE
// If only one is given, only restrict the specified resource.
// If both are given, restrict both.
BlockAssembler::Options options;
options.nExcessiveBlockSize = config.GetMaxBlockSize();
if (gArgs.IsArgSet("-blockmaxsize")) {
options.nMaxGeneratedBlockSize =
gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE);
}
Amount n = Amount::zero();
if (gArgs.IsArgSet("-blockmintxfee") &&
ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
options.blockMinFeeRate = CFeeRate(n);
}
return options;
}
BlockAssembler::BlockAssembler(const Config &config, const CTxMemPool &_mempool)
: BlockAssembler(config.GetChainParams(), _mempool,
DefaultOptions(config)) {}
void BlockAssembler::resetBlock() {
inBlock.clear();
// Reserve space for coinbase tx.
nBlockSize = 1000;
nBlockSigOps = 100;
// These counters do not include coinbase tx.
nBlockTx = 0;
nFees = Amount::zero();
}
+Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
+Optional<int64_t> BlockAssembler::m_last_block_size{nullopt};
+
std::unique_ptr<CBlockTemplate>
BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) {
int64_t nTimeStart = GetTimeMicros();
resetBlock();
pblocktemplate.reset(new CBlockTemplate());
if (!pblocktemplate.get()) {
return nullptr;
}
// Pointer for convenience.
pblock = &pblocktemplate->block;
// Add dummy coinbase tx as first transaction. It is updated at the end.
pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1);
LOCK2(cs_main, mempool->cs);
CBlockIndex *pindexPrev = ::ChainActive().Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
const Consensus::Params &consensusParams = chainparams.GetConsensus();
pblock->nVersion = ComputeBlockVersion(pindexPrev, consensusParams);
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (chainparams.MineBlocksOnDemand()) {
pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion);
}
pblock->nTime = GetAdjustedTime();
nMedianTimePast = pindexPrev->GetMedianTimePast();
nLockTimeCutoff =
(STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: pblock->GetBlockTime();
// After the sigchecks activation we repurpose the 'sigops' tracking in
// mempool/mining to actually track sigchecks instead. (Proper SigOps will
// not need to be counted any more since it's getting deactivated.)
fUseSigChecks = IsPhononEnabled(chainparams.GetConsensus(), pindexPrev);
int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
if (IsMagneticAnomalyEnabled(consensusParams, pindexPrev)) {
// If magnetic anomaly is enabled, we make sure transaction are
// canonically ordered.
std::sort(std::begin(pblocktemplate->entries) + 1,
std::end(pblocktemplate->entries),
[](const CBlockTemplateEntry &a, const CBlockTemplateEntry &b)
-> bool { return a.tx->GetId() < b.tx->GetId(); });
}
// Copy all the transactions refs into the block
pblock->vtx.reserve(pblocktemplate->entries.size());
for (const CBlockTemplateEntry &entry : pblocktemplate->entries) {
pblock->vtx.push_back(entry.tx);
}
int64_t nTime1 = GetTimeMicros();
- nLastBlockTx = nBlockTx;
- nLastBlockSize = nBlockSize;
+ m_last_block_num_txs = nBlockTx;
+ m_last_block_size = nBlockSize;
// Create coinbase transaction.
CMutableTransaction coinbaseTx;
coinbaseTx.vin.resize(1);
coinbaseTx.vin[0].prevout = COutPoint();
coinbaseTx.vout.resize(1);
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
coinbaseTx.vout[0].nValue =
nFees + GetBlockSubsidy(nHeight, consensusParams);
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
const std::vector<CTxDestination> whitelisted =
GetMinerFundWhitelist(consensusParams, pindexPrev);
if (!whitelisted.empty()) {
const Amount fund = coinbaseTx.vout[0].nValue / MINER_FUND_RATIO;
coinbaseTx.vout[0].nValue -= fund;
coinbaseTx.vout.emplace_back(fund,
GetScriptForDestination(whitelisted[0]));
}
// Make sure the coinbase is big enough.
uint64_t coinbaseSize = ::GetSerializeSize(coinbaseTx, PROTOCOL_VERSION);
if (coinbaseSize < MIN_TX_SIZE) {
coinbaseTx.vin[0].scriptSig
<< std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
}
pblocktemplate->entries[0].tx = MakeTransactionRef(coinbaseTx);
pblocktemplate->entries[0].fees = -1 * nFees;
pblock->vtx[0] = pblocktemplate->entries[0].tx;
uint64_t nSerializeSize = GetSerializeSize(*pblock, PROTOCOL_VERSION);
LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n",
nSerializeSize, nBlockTx, nFees, nBlockSigOps);
// Fill in header.
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, consensusParams, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
pblock->nNonce = 0;
pblocktemplate->entries[0].sigOpCount = GetSigOpCountWithoutP2SH(
*pblocktemplate->entries[0].tx, STANDARD_SCRIPT_VERIFY_FLAGS);
CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev,
BlockValidationOptions(nMaxGeneratedBlockSize)
.withCheckPoW(false)
.withCheckMerkleRoot(false))) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s",
__func__,
FormatStateMessage(state)));
}
int64_t nTime2 = GetTimeMicros();
LogPrint(BCLog::BENCH,
"CreateNewBlock() packages: %.2fms (%d packages, %d updated "
"descendants), validity: %.2fms (total %.2fms)\n",
0.001 * (nTime1 - nTimeStart), nPackagesSelected,
nDescendantsUpdated, 0.001 * (nTime2 - nTime1),
0.001 * (nTime2 - nTimeStart));
return std::move(pblocktemplate);
}
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) {
for (CTxMemPool::setEntries::iterator iit = testSet.begin();
iit != testSet.end();) {
// Only test txs not already in the block.
if (inBlock.count(*iit)) {
testSet.erase(iit++);
} else {
iit++;
}
}
}
uint64_t BlockAssembler::MaxBlockSigOpsCountForSize(uint64_t blockSize) const {
return fUseSigChecks ? nMaxGeneratedBlockSigChecks
: GetMaxBlockSigOpsCount(blockSize);
}
bool BlockAssembler::TestPackage(uint64_t packageSize,
int64_t packageSigOps) const {
auto blockSizeWithPackage = nBlockSize + packageSize;
if (blockSizeWithPackage >= nMaxGeneratedBlockSize) {
return false;
}
if (nBlockSigOps + packageSigOps >=
MaxBlockSigOpsCountForSize(blockSizeWithPackage)) {
return false;
}
return true;
}
/**
* Perform transaction-level checks before adding to block:
* - Transaction finality (locktime)
* - Serialized size (in case -blockmaxsize is in use)
*/
bool BlockAssembler::TestPackageTransactions(
const CTxMemPool::setEntries &package) {
uint64_t nPotentialBlockSize = nBlockSize;
for (CTxMemPool::txiter it : package) {
CValidationState state;
if (!ContextualCheckTransaction(chainparams.GetConsensus(), it->GetTx(),
state, nHeight, nLockTimeCutoff,
nMedianTimePast)) {
return false;
}
uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), PROTOCOL_VERSION);
if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) {
return false;
}
nPotentialBlockSize += nTxSize;
}
return true;
}
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) {
pblocktemplate->entries.emplace_back(iter->GetSharedTx(), iter->GetFee(),
iter->GetSigOpCount());
nBlockSize += iter->GetTxSize();
++nBlockTx;
nBlockSigOps += iter->GetSigOpCount();
nFees += iter->GetFee();
inBlock.insert(iter);
bool fPrintPriority =
gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) {
LogPrintf(
"fee %s txid %s\n",
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
iter->GetTx().GetId().ToString());
}
}
int BlockAssembler::UpdatePackagesForAdded(
const CTxMemPool::setEntries &alreadyAdded,
indexed_modified_transaction_set &mapModifiedTx) {
int nDescendantsUpdated = 0;
for (CTxMemPool::txiter it : alreadyAdded) {
CTxMemPool::setEntries descendants;
mempool->CalculateDescendants(it, descendants);
// Insert all descendants (not yet in block) into the modified set.
for (CTxMemPool::txiter desc : descendants) {
if (alreadyAdded.count(desc)) {
continue;
}
++nDescendantsUpdated;
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
modEntry.nSizeWithAncestors -= it->GetTxSize();
modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount();
mapModifiedTx.insert(modEntry);
} else {
mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
}
}
}
return nDescendantsUpdated;
}
// Skip entries in mapTx that are already in a block or are present in
// mapModifiedTx (which implies that the mapTx ancestor state is stale due to
// ancestor inclusion in the block). Also skip transactions that we've already
// failed to add. This can happen if we consider a transaction in mapModifiedTx
// and it fails: we can then potentially consider it again while walking mapTx.
// It's currently guaranteed to fail again, but as a belt-and-suspenders check
// we put it in failedTx and avoid re-evaluation, since the re-evaluation would
// be using cached size/sigops/fee values that are not actually correct.
bool BlockAssembler::SkipMapTxEntry(
CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx,
CTxMemPool::setEntries &failedTx) {
assert(it != mempool->mapTx.end());
return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);
}
void BlockAssembler::SortForBlock(
const CTxMemPool::setEntries &package,
std::vector<CTxMemPool::txiter> &sortedEntries) {
// Sort package by ancestor count. If a transaction A depends on transaction
// B, then A's ancestor count must be greater than B's. So this is
// sufficient to validly order the transactions for block inclusion.
sortedEntries.clear();
sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());
std::sort(sortedEntries.begin(), sortedEntries.end(),
CompareTxIterByAncestorCount());
}
/**
* addPackageTx includes transactions paying a fee by ensuring that
* the partial ordering of transactions is maintained. That is to say
* children come after parents, despite having a potentially larger fee.
* @param[out] nPackagesSelected How many packages were selected
* @param[out] nDescendantsUpdated Number of descendant transactions updated
*/
void BlockAssembler::addPackageTxs(int &nPackagesSelected,
int &nDescendantsUpdated) {
// selection algorithm orders the mempool based on feerate of a
// transaction including all unconfirmed ancestors. Since we don't remove
// transactions from the mempool as we select them for block inclusion, we
// need an alternate method of updating the feerate of a transaction with
// its not-yet-selected ancestors as we go. This is accomplished by
// walking the in-mempool descendants of selected transactions and storing
// a temporary modified state in mapModifiedTxs. Each time through the
// loop, we compare the best transaction in mapModifiedTxs with the next
// transaction in the mempool to decide what transaction package to work
// on next.
// mapModifiedTx will store sorted packages after they are modified because
// some of their txs are already in the block.
indexed_modified_transaction_set mapModifiedTx;
// Keep track of entries that failed inclusion, to avoid duplicate work.
CTxMemPool::setEntries failedTx;
// Start by adding all descendants of previously added txs to mapModifiedTx
// and modifying them for their already included ancestors.
UpdatePackagesForAdded(inBlock, mapModifiedTx);
CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator
mi = mempool->mapTx.get<ancestor_score>().begin();
CTxMemPool::txiter iter;
// Limit the number of attempts to add transactions to the block when it is
// close to full; this is just a simple heuristic to finish quickly if the
// mempool has a lot of entries.
const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
int64_t nConsecutiveFailed = 0;
while (mi != mempool->mapTx.get<ancestor_score>().end() ||
!mapModifiedTx.empty()) {
// First try to find a new transaction in mapTx to evaluate.
if (mi != mempool->mapTx.get<ancestor_score>().end() &&
SkipMapTxEntry(mempool->mapTx.project<0>(mi), mapModifiedTx,
failedTx)) {
++mi;
continue;
}
// Now that mi is not stale, determine which transaction to evaluate:
// the next entry from mapTx, or the best from mapModifiedTx?
bool fUsingModified = false;
modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
if (mi == mempool->mapTx.get<ancestor_score>().end()) {
// We're out of entries in mapTx; use the entry from mapModifiedTx
iter = modit->iter;
fUsingModified = true;
} else {
// Try to compare the mapTx entry to the mapModifiedTx entry.
iter = mempool->mapTx.project<0>(mi);
if (modit != mapModifiedTx.get<ancestor_score>().end() &&
CompareTxMemPoolEntryByAncestorFee()(
*modit, CTxMemPoolModifiedEntry(iter))) {
// The best entry in mapModifiedTx has higher score than the one
// from mapTx. Switch which transaction (package) to consider
iter = modit->iter;
fUsingModified = true;
} else {
// Either no entry in mapModifiedTx, or it's worse than mapTx.
// Increment mi for the next loop iteration.
++mi;
}
}
// We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
// contain anything that is inBlock.
assert(!inBlock.count(iter));
uint64_t packageSize = iter->GetSizeWithAncestors();
Amount packageFees = iter->GetModFeesWithAncestors();
int64_t packageSigOps = iter->GetSigOpCountWithAncestors();
if (fUsingModified) {
packageSize = modit->nSizeWithAncestors;
packageFees = modit->nModFeesWithAncestors;
packageSigOps = modit->nSigOpCountWithAncestors;
}
if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
// Don't include this package, but don't stop yet because something
// else we might consider may have a sufficient fee rate (since txes
// are ordered by virtualsize feerate, not actual feerate).
if (fUsingModified) {
// Since we always look at the best entry in mapModifiedTx, we
// must erase failed entries so that we can consider the next
// best entry on the next loop iteration
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
continue;
}
// The following must not use virtual size since TestPackage relies on
// having an accurate call to
// GetMaxBlockSigOpsCount(blockSizeWithPackage).
if (!TestPackage(packageSize, packageSigOps)) {
if (fUsingModified) {
// Since we always look at the best entry in mapModifiedTx, we
// must erase failed entries so that we can consider the next
// best entry on the next loop iteration
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES &&
nBlockSize > nMaxGeneratedBlockSize - 1000) {
// Give up if we're close to full and haven't succeeded in a
// while.
break;
}
continue;
}
CTxMemPool::setEntries ancestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
std::string dummy;
mempool->CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit,
nNoLimit, nNoLimit, dummy, false);
onlyUnconfirmed(ancestors);
ancestors.insert(iter);
// Test if all tx's are Final.
if (!TestPackageTransactions(ancestors)) {
if (fUsingModified) {
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
continue;
}
// This transaction will make it in; reset the failed counter.
nConsecutiveFailed = 0;
// Package can be added. Sort the entries in a valid order.
std::vector<CTxMemPool::txiter> sortedEntries;
SortForBlock(ancestors, sortedEntries);
for (auto &entry : sortedEntries) {
AddToBlock(entry);
// Erase from the modified set, if present
mapModifiedTx.erase(entry);
}
++nPackagesSelected;
// Update transactions that depend on each of these
nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
}
}
static const std::vector<uint8_t>
getExcessiveBlockSizeSig(uint64_t nExcessiveBlockSize) {
std::string cbmsg = "/EB" + getSubVersionEB(nExcessiveBlockSize) + "/";
std::vector<uint8_t> vec(cbmsg.begin(), cbmsg.end());
return vec;
}
void IncrementExtraNonce(CBlock *pblock, const CBlockIndex *pindexPrev,
uint64_t nExcessiveBlockSize,
unsigned int &nExtraNonce) {
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock) {
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
// Height first in coinbase required for block.version=2
unsigned int nHeight = pindexPrev->nHeight + 1;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig =
(CScript() << nHeight << CScriptNum(nExtraNonce)
<< getExcessiveBlockSizeSig(nExcessiveBlockSize)) +
COINBASE_FLAGS;
// Make sure the coinbase is big enough.
uint64_t coinbaseSize = ::GetSerializeSize(txCoinbase, PROTOCOL_VERSION);
if (coinbaseSize < MIN_TX_SIZE) {
txCoinbase.vin[0].scriptSig
<< std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
}
assert(txCoinbase.vin[0].scriptSig.size() <= MAX_COINBASE_SCRIPTSIG_SIZE);
assert(::GetSerializeSize(txCoinbase, PROTOCOL_VERSION) >= MIN_TX_SIZE);
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
diff --git a/src/miner.h b/src/miner.h
index 3c4a9e3d7..cd90eac59 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -1,240 +1,244 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MINER_H
#define BITCOIN_MINER_H
+#include <optional.h>
#include <primitives/block.h>
#include <txmempool.h>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index_container.hpp>
#include <cstdint>
#include <memory>
class CBlockIndex;
class CChainParams;
class Config;
class CScript;
namespace Consensus {
struct Params;
}
static const bool DEFAULT_PRINTPRIORITY = false;
struct CBlockTemplateEntry {
CTransactionRef tx;
Amount fees;
int64_t sigOpCount;
CBlockTemplateEntry(CTransactionRef _tx, Amount _fees, int64_t _sigOpCount)
: tx(_tx), fees(_fees), sigOpCount(_sigOpCount){};
};
struct CBlockTemplate {
CBlock block;
std::vector<CBlockTemplateEntry> entries;
};
// Container for tracking updates to ancestor feerate as we include (parent)
// transactions in a block
struct CTxMemPoolModifiedEntry {
explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry) {
iter = entry;
nSizeWithAncestors = entry->GetSizeWithAncestors();
nModFeesWithAncestors = entry->GetModFeesWithAncestors();
nSigOpCountWithAncestors = entry->GetSigOpCountWithAncestors();
}
Amount GetModifiedFee() const { return iter->GetModifiedFee(); }
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
uint64_t GetVirtualSizeWithAncestors() const;
Amount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
size_t GetTxSize() const { return iter->GetTxSize(); }
size_t GetTxVirtualSize() const { return iter->GetTxVirtualSize(); }
const CTransaction &GetTx() const { return iter->GetTx(); }
CTxMemPool::txiter iter;
uint64_t nSizeWithAncestors;
Amount nModFeesWithAncestors;
int64_t nSigOpCountWithAncestors;
};
/**
* Comparator for CTxMemPool::txiter objects.
* It simply compares the internal memory address of the CTxMemPoolEntry object
* pointed to. This means it has no meaning, and is only useful for using them
* as key in other indexes.
*/
struct CompareCTxMemPoolIter {
bool operator()(const CTxMemPool::txiter &a,
const CTxMemPool::txiter &b) const {
return &(*a) < &(*b);
}
};
struct modifiedentry_iter {
typedef CTxMemPool::txiter result_type;
result_type operator()(const CTxMemPoolModifiedEntry &entry) const {
return entry.iter;
}
};
// A comparator that sorts transactions based on number of ancestors.
// This is sufficient to sort an ancestor package in an order that is valid
// to appear in a block.
struct CompareTxIterByAncestorCount {
bool operator()(const CTxMemPool::txiter &a,
const CTxMemPool::txiter &b) const {
if (a->GetCountWithAncestors() != b->GetCountWithAncestors()) {
return a->GetCountWithAncestors() < b->GetCountWithAncestors();
}
return CTxMemPool::CompareIteratorById()(a, b);
}
};
typedef boost::multi_index_container<
CTxMemPoolModifiedEntry,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<modifiedentry_iter,
CompareCTxMemPoolIter>,
// sorted by modified ancestor fee rate
boost::multi_index::ordered_non_unique<
// Reuse same tag from CTxMemPool's similar index
boost::multi_index::tag<ancestor_score>,
boost::multi_index::identity<CTxMemPoolModifiedEntry>,
CompareTxMemPoolEntryByAncestorFee>>>
indexed_modified_transaction_set;
typedef indexed_modified_transaction_set::nth_index<0>::type::iterator
modtxiter;
typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator
modtxscoreiter;
struct update_for_parent_inclusion {
explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
void operator()(CTxMemPoolModifiedEntry &e) {
e.nModFeesWithAncestors -= iter->GetFee();
e.nSizeWithAncestors -= iter->GetTxSize();
e.nSigOpCountWithAncestors -= iter->GetSigOpCount();
}
CTxMemPool::txiter iter;
};
/** Generate a new block, without valid proof-of-work */
class BlockAssembler {
private:
// The constructed block template
std::unique_ptr<CBlockTemplate> pblocktemplate;
// A convenience pointer that always refers to the CBlock in pblocktemplate
CBlock *pblock;
// Configuration parameters for the block size
uint64_t nMaxGeneratedBlockSize;
uint64_t nMaxGeneratedBlockSigChecks;
CFeeRate blockMinFeeRate;
// Information on the current status of the block
uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOps;
Amount nFees;
CTxMemPool::setEntries inBlock;
// Chain context for the block
int nHeight;
int64_t nLockTimeCutoff;
int64_t nMedianTimePast;
const CChainParams &chainparams;
bool fUseSigChecks;
const CTxMemPool *mempool;
public:
struct Options {
Options();
uint64_t nExcessiveBlockSize;
uint64_t nMaxGeneratedBlockSize;
CFeeRate blockMinFeeRate;
};
BlockAssembler(const Config &config, const CTxMemPool &_mempool);
BlockAssembler(const CChainParams &params, const CTxMemPool &_mempool,
const Options &options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate>
CreateNewBlock(const CScript &scriptPubKeyIn);
uint64_t GetMaxGeneratedBlockSize() const { return nMaxGeneratedBlockSize; }
+ static Optional<int64_t> m_last_block_num_txs;
+ static Optional<int64_t> m_last_block_size;
+
private:
// utility functions
/** Clear the block's state and prepare for assembling a new block */
void resetBlock();
/** Add a tx to the block */
void AddToBlock(CTxMemPool::txiter iter);
/**
* Calculate the "SigOps" limit for a given block size (may actually be the
* SigChecks limit which is independent of blockSize, depending on
* fUseSigChecks)
*/
uint64_t MaxBlockSigOpsCountForSize(uint64_t blockSize) const;
// Methods for how to add transactions to a block.
/**
* Add transactions based on feerate including unconfirmed ancestors.
* Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics).
*/
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
EXCLUSIVE_LOCKS_REQUIRED(mempool->cs);
// helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries &testSet);
/** Test if a new package would "fit" in the block */
bool TestPackage(uint64_t packageSize, int64_t packageSigOpCount) const;
/**
* Perform checks on each transaction in a package:
* locktime, serialized size (if necessary). These checks should always
* succeed, and they're here only as an extra check in case of suboptimal
* node configuration.
*/
bool TestPackageTransactions(const CTxMemPool::setEntries &package);
/**
* Return true if given transaction from mapTx has already been evaluated,
* or if the transaction's cached data in mapTx is incorrect.
*/
bool SkipMapTxEntry(CTxMemPool::txiter it,
indexed_modified_transaction_set &mapModifiedTx,
CTxMemPool::setEntries &failedTx)
EXCLUSIVE_LOCKS_REQUIRED(mempool->cs);
/** Sort the package in an order that is valid to appear in a block */
void SortForBlock(const CTxMemPool::setEntries &package,
std::vector<CTxMemPool::txiter> &sortedEntries);
/**
* Add descendants of given transactions to mapModifiedTx with ancestor
* state updated assuming given transactions are inBlock. Returns number of
* updated descendants.
*/
int UpdatePackagesForAdded(const CTxMemPool::setEntries &alreadyAdded,
indexed_modified_transaction_set &mapModifiedTx)
EXCLUSIVE_LOCKS_REQUIRED(mempool->cs);
};
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock *pblock, const CBlockIndex *pindexPrev,
uint64_t nExcessiveBlockSize,
unsigned int &nExtraNonce);
int64_t UpdateTime(CBlockHeader *pblock, const Consensus::Params &params,
const CBlockIndex *pindexPrev);
#endif // BITCOIN_MINER_H
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 51a2d245b..47d0f58b2 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,888 +1,895 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <amount.h>
#include <blockvalidity.h>
#include <chain.h>
#include <chainparams.h>
#include <config.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <key_io.h>
#include <miner.h>
#include <net.h>
#include <policy/policy.h>
#include <pow.h>
#include <rpc/blockchain.h>
#include <rpc/mining.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <txmempool.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>
#include <validationinterface.h>
#include <warnings.h>
#include <univalue.h>
#include <cstdint>
#include <memory>
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive. If 'height' is
* nonnegative, compute the estimate at the time when a given block was found.
*/
static UniValue GetNetworkHashPS(int lookup, int height) {
CBlockIndex *pb = ::ChainActive().Tip();
if (height >= 0 && height < ::ChainActive().Height()) {
pb = ::ChainActive()[height];
}
if (pb == nullptr || !pb->nHeight) {
return 0;
}
// If lookup is -1, then use blocks since last difficulty change.
if (lookup <= 0) {
lookup = pb->nHeight %
Params().GetConsensus().DifficultyAdjustmentInterval() +
1;
}
// If lookup is larger than chain, then set it to chain length.
if (lookup > pb->nHeight) {
lookup = pb->nHeight;
}
CBlockIndex *pb0 = pb;
int64_t minTime = pb0->GetBlockTime();
int64_t maxTime = minTime;
for (int i = 0; i < lookup; i++) {
pb0 = pb0->pprev;
int64_t time = pb0->GetBlockTime();
minTime = std::min(time, minTime);
maxTime = std::max(time, maxTime);
}
// In case there's a situation where minTime == maxTime, we don't want a
// divide by zero exception.
if (minTime == maxTime) {
return 0;
}
arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
int64_t timeDiff = maxTime - minTime;
return workDiff.getdouble() / timeDiff;
}
static UniValue getnetworkhashps(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(RPCHelpMan{
"getnetworkhashps",
"\nReturns the estimated network hashes per second "
"based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies "
"since last difficulty change.\n"
"Pass in [height] to estimate the network speed at the "
"time when a certain block was found.\n",
{
{"nblocks", RPCArg::Type::NUM, /* opt */ true,
/* default_val */ "120",
"The number of blocks, or -1 for blocks since last "
"difficulty change."},
{"height", RPCArg::Type::NUM, /* opt */ true,
/* default_val */ "-1",
"To estimate at the time of the given height."},
},
RPCResult{"x (numeric) Hashes per second estimated\n"},
RPCExamples{HelpExampleCli("getnetworkhashps", "") +
HelpExampleRpc("getnetworkhashps", "")},
}
.ToStringWithResultsAndExamples());
}
LOCK(cs_main);
return GetNetworkHashPS(
!request.params[0].isNull() ? request.params[0].get_int() : 120,
!request.params[1].isNull() ? request.params[1].get_int() : -1);
}
UniValue generateBlocks(const Config &config,
std::shared_ptr<CReserveScript> coinbaseScript,
int nGenerate, uint64_t nMaxTries, bool keepScript) {
static const int nInnerLoopCount = 0x100000;
int nHeightEnd = 0;
int nHeight = 0;
{
// Don't keep cs_main locked.
LOCK(cs_main);
nHeight = ::ChainActive().Height();
nHeightEnd = nHeight + nGenerate;
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd && !ShutdownRequested()) {
std::unique_ptr<CBlockTemplate> pblocktemplate(
BlockAssembler(config, g_mempool)
.CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
}
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
IncrementExtraNonce(pblock, ::ChainActive().Tip(),
config.GetMaxBlockSize(), nExtraNonce);
}
while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount &&
!CheckProofOfWork(pblock->GetHash(), pblock->nBits,
config.GetChainParams().GetConsensus())) {
++pblock->nNonce;
--nMaxTries;
}
if (nMaxTries == 0) {
break;
}
if (pblock->nNonce == nInnerLoopCount) {
continue;
}
std::shared_ptr<const CBlock> shared_pblock =
std::make_shared<const CBlock>(*pblock);
if (!ProcessNewBlock(config, shared_pblock, true, nullptr)) {
throw JSONRPCError(RPC_INTERNAL_ERROR,
"ProcessNewBlock, block not accepted");
}
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
// Mark script as important because it was used at least for one
// coinbase output if the script came from the wallet.
if (keepScript) {
coinbaseScript->KeepScript();
}
}
return blockHashes;
}
static UniValue generatetoaddress(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() < 2 ||
request.params.size() > 3) {
throw std::runtime_error(RPCHelpMan{
"generatetoaddress",
"\nMine blocks immediately to a specified address before the "
"RPC call returns)\n",
{
{"nblocks", RPCArg::Type::NUM, /* opt */ false,
/* default_val */ "",
"How many blocks are generated immediately."},
{"address", RPCArg::Type::STR, /* opt */ false,
/* default_val */ "",
"The address to send the newly generated bitcoin to."},
{"maxtries", RPCArg::Type::NUM, /* opt */ true,
/* default_val */ "1000000", "How many iterations to try."},
},
RPCResult{
"[ blockhashes ] (array) hashes of blocks generated\n"},
RPCExamples{
"\nGenerate 11 blocks to myaddress\n" +
HelpExampleCli("generatetoaddress", "11 \"myaddress\"")},
}
.ToStringWithResultsAndExamples());
}
int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
if (!request.params[2].isNull()) {
nMaxTries = request.params[2].get_int();
}
CTxDestination destination =
DecodeDestination(request.params[1].get_str(), config.GetChainParams());
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
"Error: Invalid address");
}
std::shared_ptr<CReserveScript> coinbaseScript =
std::make_shared<CReserveScript>();
coinbaseScript->reserveScript = GetScriptForDestination(destination);
return generateBlocks(config, coinbaseScript, nGenerate, nMaxTries, false);
}
static UniValue getmininginfo(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(RPCHelpMan{
"getmininginfo",
"\nReturns a json object containing mining-related "
"information.",
{},
RPCResult{
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
- " \"currentblocksize\": nnn, (numeric) The last block size\n"
- " \"currentblocktx\": nnn, (numeric) The last block "
- "transaction\n"
+ " \"currentblocksize\": nnn, (numeric, optional) The block "
+ "size of the last assembled block (only present if a block was "
+ "ever assembled)\n"
+ " \"currentblocktx\": nnn, (numeric, optional) The number "
+ "of block transactions of the last assembled block (only "
+ "present if a block was ever assembled)\n"
" \"difficulty\": xxx.xxxxx (numeric) The current "
"difficulty\n"
" \"networkhashps\": nnn, (numeric) The network hashes "
"per second\n"
" \"pooledtx\": n (numeric) The size of the "
"mempool\n"
" \"chain\": \"xxxx\", (string) current network "
"name as defined in BIP70 (main, test, regtest)\n"
" \"warnings\": \"...\" (string) any network and "
"blockchain warnings\n"
"}\n"},
RPCExamples{HelpExampleCli("getmininginfo", "") +
HelpExampleRpc("getmininginfo", "")},
}
.ToStringWithResultsAndExamples());
}
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", int(::ChainActive().Height()));
- obj.pushKV("currentblocksize", uint64_t(nLastBlockSize));
- obj.pushKV("currentblocktx", uint64_t(nLastBlockTx));
+ if (BlockAssembler::m_last_block_size) {
+ obj.pushKV("currentblocksize", *BlockAssembler::m_last_block_size);
+ }
+ if (BlockAssembler::m_last_block_num_txs) {
+ obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
+ }
obj.pushKV("difficulty", double(GetDifficulty(::ChainActive().Tip())));
obj.pushKV("networkhashps", getnetworkhashps(config, request));
obj.pushKV("pooledtx", uint64_t(g_mempool.size()));
obj.pushKV("chain", config.GetChainParams().NetworkIDString());
obj.pushKV("warnings", GetWarnings("statusbar"));
return obj;
}
// NOTE: Unlike wallet RPC (which use BCH values), mining RPCs follow GBT (BIP
// 22) in using satoshi amounts
static UniValue prioritisetransaction(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 3) {
throw std::runtime_error(RPCHelpMan{
"prioritisetransaction",
"Accepts the transaction into mined blocks at a higher "
"(or lower) priority\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false,
/* default_val */ "", "The transaction id."},
{"dummy", RPCArg::Type::NUM, /* opt */ true,
/* default_val */ "null",
"API-Compatibility for previous API. Must be zero or "
"null.\n"
" DEPRECATED. For forward compatibility "
"use named arguments and omit this parameter."},
{"fee_delta", RPCArg::Type::NUM, /* opt */ false,
/* default_val */ "",
"The fee value (in satoshis) to add (or subtract, if "
"negative).\n"
" The fee is not actually paid, "
"only the algorithm for selecting transactions into a "
"block\n"
" considers the transaction as it would "
"have paid a higher (or lower) fee."},
},
RPCResult{"true (boolean) Returns true\n"},
RPCExamples{
HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") +
HelpExampleRpc("prioritisetransaction",
"\"txid\", 0.0, 10000")},
}
.ToStringWithResultsAndExamples());
}
LOCK(cs_main);
TxId txid(ParseHashV(request.params[0], "txid"));
Amount nAmount = request.params[2].get_int64() * SATOSHI;
if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) {
throw JSONRPCError(RPC_INVALID_PARAMETER,
"Priority is no longer supported, dummy argument to "
"prioritisetransaction must be 0.");
}
g_mempool.PrioritiseTransaction(txid, nAmount);
return true;
}
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be
// handled by caller
static UniValue BIP22ValidationResult(const Config &config,
const CValidationState &state) {
if (state.IsValid()) {
return NullUniValue;
}
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));
}
if (state.IsInvalid()) {
std::string strRejectReason = state.GetRejectReason();
if (strRejectReason.empty()) {
return "rejected";
}
return strRejectReason;
}
// Should be impossible.
return "valid?";
}
static UniValue getblocktemplate(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() > 1) {
throw std::runtime_error(RPCHelpMan{
"getblocktemplate",
"\nIf the request parameters include a 'mode' key, that is "
"used to explicitly select between the default 'template' "
"request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
"For full specification, see BIPs 22, 23, 9, and 145:\n"
" "
"https://github.com/bitcoin/bips/blob/master/"
"bip-0022.mediawiki\n"
" "
"https://github.com/bitcoin/bips/blob/master/"
"bip-0023.mediawiki\n"
" "
"https://github.com/bitcoin/bips/blob/master/"
"bip-0009.mediawiki#getblocktemplate_changes\n"
" ",
{
{"template_request",
RPCArg::Type::OBJ,
/* opt */ true,
/* default_val */ "",
"A json object in the following spec",
{
{"mode", RPCArg::Type::STR, /* opt */ true,
/* default_val */ "",
"This must be set to \"template\", \"proposal\" (see "
"BIP 23), or omitted"},
{
"capabilities",
RPCArg::Type::ARR,
/* opt */ true,
/* default_val */ "",
"A list of strings",
{
{"support", RPCArg::Type::STR, /* opt */ true,
/* default_val */ "",
"client side supported feature, 'longpoll', "
"'coinbasetxn', 'coinbasevalue', 'proposal', "
"'serverlist', 'workid'"},
},
},
},
"\"template_request\""},
},
RPCResult{
"{\n"
" \"version\" : n, (numeric) The preferred "
"block version\n"
" \"previousblockhash\" : \"xxxx\", (string) The hash of "
"current highest block\n"
" \"transactions\" : [ (array) contents of "
"non-coinbase transactions that should be included in the next "
"block\n"
" {\n"
" \"data\" : \"xxxx\", (string) "
"transaction data encoded in hexadecimal (byte-for-byte)\n"
" \"txid\" : \"xxxx\", (string) "
"transaction id encoded in little-endian hexadecimal\n"
" \"hash\" : \"xxxx\", (string) hash "
"encoded in little-endian hexadecimal (including witness "
"data)\n"
" \"depends\" : [ (array) array of "
"numbers \n"
" n (numeric) "
"transactions before this one (by 1-based index in "
"'transactions' list) that must be present in the final block "
"if this one is\n"
" ,...\n"
" ],\n"
" \"fee\": n, (numeric) difference "
"in value between transaction inputs and outputs (in "
"satoshis); for coinbase transactions, this is a negative "
"Number of the total collected block fees (ie, not including "
"the block subsidy); if key is not present, fee is unknown and "
"clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total "
"SigOps count, as counted for purposes of block limits; if key "
"is not present, sigop count is unknown and clients MUST NOT "
"assume it is zero\n"
" \"required\" : true|false (boolean) if provided "
"and true, this transaction must be in the final block\n"
" }\n"
" ,...\n"
" ],\n"
" \"coinbaseaux\" : { (json object) data that "
"should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"xx\" (string) key name "
"is to be ignored, and value included in scriptSig\n"
" },\n"
" \"coinbasevalue\" : n, (numeric) maximum "
"allowable input to coinbase transaction, including the "
"generation award and transaction fees (in satoshis)\n"
" \"coinbasetxn\" : { ... }, (json object) "
"information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash "
"target\n"
" \"mintime\" : xxx, (numeric) The minimum "
"timestamp appropriate for next block time in seconds since "
"epoch (Jan 1 1970 GMT)\n"
" \"mutable\" : [ (array of string) list "
"of ways the block template may be changed \n"
" \"value\" (string) A way the "
"block template may be changed, e.g. 'time', 'transactions', "
"'prevblock'\n"
" ,...\n"
" ],\n"
" \"noncerange\" : \"00000000ffffffff\",(string) A range of "
"valid nonces\n"
" \"sigoplimit\" : n, (numeric) limit of "
"sigops in blocks\n"
" \"sizelimit\" : n, (numeric) limit of "
"block size\n"
" \"curtime\" : ttt, (numeric) current "
"timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
" \"bits\" : \"xxxxxxxx\", (string) compressed "
"target of next block\n"
" \"height\" : n (numeric) The height of "
"the next block\n"
"}\n"},
RPCExamples{HelpExampleCli("getblocktemplate", "") +
HelpExampleRpc("getblocktemplate", "")},
}
.ToStringWithResultsAndExamples());
}
LOCK(cs_main);
std::string strMode = "template";
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
if (!request.params[0].isNull()) {
const UniValue &oparam = request.params[0].get_obj();
const UniValue &modeval = find_value(oparam, "mode");
if (modeval.isStr()) {
strMode = modeval.get_str();
} else if (modeval.isNull()) {
/* Do nothing */
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
}
lpval = find_value(oparam, "longpollid");
if (strMode == "proposal") {
const UniValue &dataval = find_value(oparam, "data");
if (!dataval.isStr()) {
throw JSONRPCError(RPC_TYPE_ERROR,
"Missing data String key for proposal");
}
CBlock block;
if (!DecodeHexBlk(block, dataval.get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
"Block decode failed");
}
const BlockHash hash = block.GetHash();
const CBlockIndex *pindex = LookupBlockIndex(hash);
if (pindex) {
if (pindex->IsValid(BlockValidity::SCRIPTS)) {
return "duplicate";
}
if (pindex->nStatus.isInvalid()) {
return "duplicate-invalid";
}
return "duplicate-inconclusive";
}
CBlockIndex *const pindexPrev = ::ChainActive().Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash()) {
return "inconclusive-not-best-prevblk";
}
CValidationState state;
TestBlockValidity(state, config.GetChainParams(), block, pindexPrev,
BlockValidationOptions(config)
.withCheckPoW(false)
.withCheckMerkleRoot(true));
return BIP22ValidationResult(config, state);
}
}
if (strMode != "template") {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
}
if (!g_connman) {
throw JSONRPCError(
RPC_CLIENT_P2P_DISABLED,
"Error: Peer-to-peer functionality missing or disabled");
}
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) {
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED,
"Bitcoin is not connected!");
}
if (IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
"Bitcoin is downloading blocks...");
}
static unsigned int nTransactionsUpdatedLast;
if (!lpval.isNull()) {
// Wait to respond until either the best block changes, OR a minute has
// passed and there are more transactions
uint256 hashWatchedChain;
std::chrono::steady_clock::time_point checktxtime;
unsigned int nTransactionsUpdatedLastLP;
if (lpval.isStr()) {
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid");
nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
} else {
// NOTE: Spec does not specify behaviour for non-string longpollid,
// but this makes testing easier
hashWatchedChain = ::ChainActive().Tip()->GetBlockHash();
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
// Release the wallet and main lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime =
std::chrono::steady_clock::now() + std::chrono::minutes(1);
WAIT_LOCK(g_best_block_mutex, lock);
while (g_best_block == hashWatchedChain && IsRPCRunning()) {
if (g_best_block_cv.wait_until(lock, checktxtime) ==
std::cv_status::timeout) {
// Timeout: Check transactions for update
if (g_mempool.GetTransactionsUpdated() !=
nTransactionsUpdatedLastLP) {
break;
}
checktxtime += std::chrono::seconds(10);
}
}
}
ENTER_CRITICAL_SECTION(cs_main);
if (!IsRPCRunning()) {
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
}
// TODO: Maybe recheck connections/IBD and (if something wrong) send an
// expires-immediately template to stop miners?
}
// Update block
static CBlockIndex *pindexPrev;
static int64_t nStart;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (pindexPrev != ::ChainActive().Tip() ||
(g_mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast &&
GetTime() - nStart > 5)) {
// Clear pindexPrev so future calls make a new block, despite any
// failures from here on
pindexPrev = nullptr;
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = g_mempool.GetTransactionsUpdated();
CBlockIndex *pindexPrevNew = ::ChainActive().Tip();
nStart = GetTime();
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptDummy);
if (!pblocktemplate) {
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
}
// Need to update only after we know CreateNewBlock succeeded
pindexPrev = pindexPrevNew;
}
assert(pindexPrev);
// pointer for convenience
CBlock *pblock = &pblocktemplate->block;
// Update nTime
UpdateTime(pblock, config.GetChainParams().GetConsensus(), pindexPrev);
pblock->nNonce = 0;
UniValue aCaps(UniValue::VARR);
aCaps.push_back("proposal");
UniValue transactions(UniValue::VARR);
int index_in_template = 0;
for (const auto &it : pblock->vtx) {
const CTransaction &tx = *it;
uint256 txId = tx.GetId();
if (tx.IsCoinBase()) {
index_in_template++;
continue;
}
UniValue entry(UniValue::VOBJ);
entry.pushKV("data", EncodeHexTx(tx));
entry.pushKV("txid", txId.GetHex());
entry.pushKV("hash", tx.GetHash().GetHex());
entry.pushKV("fee",
pblocktemplate->entries[index_in_template].fees / SATOSHI);
int64_t nTxSigOps =
pblocktemplate->entries[index_in_template].sigOpCount;
entry.pushKV("sigops", nTxSigOps);
transactions.push_back(entry);
index_in_template++;
}
UniValue aux(UniValue::VOBJ);
aux.pushKV("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()));
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
UniValue aMutable(UniValue::VARR);
aMutable.push_back("time");
aMutable.push_back("transactions");
aMutable.push_back("prevblock");
UniValue result(UniValue::VOBJ);
result.pushKV("capabilities", aCaps);
result.pushKV("version", pblock->nVersion);
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
result.pushKV("transactions", transactions);
result.pushKV("coinbaseaux", aux);
result.pushKV("coinbasevalue",
int64_t(pblock->vtx[0]->vout[0].nValue / SATOSHI));
result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() +
i64tostr(nTransactionsUpdatedLast));
result.pushKV("target", hashTarget.GetHex());
result.pushKV("mintime", int64_t(pindexPrev->GetMedianTimePast()) + 1);
result.pushKV("mutable", aMutable);
result.pushKV("noncerange", "00000000ffffffff");
// FIXME: Allow for mining block greater than 1M.
result.pushKV("sigoplimit", GetMaxBlockSigOpsCount(DEFAULT_MAX_BLOCK_SIZE));
result.pushKV("sizelimit", DEFAULT_MAX_BLOCK_SIZE);
result.pushKV("curtime", pblock->GetBlockTime());
result.pushKV("bits", strprintf("%08x", pblock->nBits));
result.pushKV("height", int64_t(pindexPrev->nHeight) + 1);
return result;
}
class submitblock_StateCatcher : public CValidationInterface {
public:
uint256 hash;
bool found;
CValidationState state;
explicit submitblock_StateCatcher(const uint256 &hashIn)
: hash(hashIn), found(false), state() {}
protected:
void BlockChecked(const CBlock &block,
const CValidationState &stateIn) override {
if (block.GetHash() != hash) {
return;
}
found = true;
state = stateIn;
}
};
static UniValue submitblock(const Config &config,
const JSONRPCRequest &request) {
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
if (request.fHelp || request.params.size() < 1 ||
request.params.size() > 2) {
throw std::runtime_error(RPCHelpMan{
"submitblock",
"\nAttempts to submit new block to network.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full "
"specification.\n",
{
{"hexdata", RPCArg::Type::STR_HEX, /* opt */ false,
/* default_val */ "", "the hex-encoded block data to submit"},
{"dummy", RPCArg::Type::STR, /* opt */ true,
/* default_val */ "",
"dummy value, for compatibility with BIP22. This "
"value is ignored."},
},
RPCResults{},
RPCExamples{HelpExampleCli("submitblock", "\"mydata\"") +
HelpExampleRpc("submitblock", "\"mydata\"")},
}
.ToStringWithResultsAndExamples());
}
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock &block = *blockptr;
if (!DecodeHexBlk(block, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
"Block does not start with a coinbase");
}
const BlockHash hash = block.GetHash();
{
LOCK(cs_main);
const CBlockIndex *pindex = LookupBlockIndex(hash);
if (pindex) {
if (pindex->IsValid(BlockValidity::SCRIPTS)) {
return "duplicate";
}
if (pindex->nStatus.isInvalid()) {
return "duplicate-invalid";
}
}
}
bool new_block;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
bool accepted =
ProcessNewBlock(config, blockptr, /* fForceProcessing */ true,
/* fNewBlock */ &new_block);
// We are only interested in BlockChecked which will have been dispatched
// in-thread, so no need to sync before unregistering.
UnregisterValidationInterface(&sc);
// Sync to ensure that the catcher's slots aren't executing when it goes out
// of scope and is deleted.
SyncWithValidationInterfaceQueue();
if (!new_block && accepted) {
return "duplicate";
}
if (!sc.found) {
return "inconclusive";
}
return BIP22ValidationResult(config, sc.state);
}
static UniValue submitheader(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(RPCHelpMan{
"submitheader",
"\nDecode the given hexdata as a header and submit it as a "
"candidate chain tip if valid."
"\nThrows when the header is invalid.\n",
{
{"hexdata", RPCArg::Type::STR_HEX, /* opt */ false,
/* default_val */ "", "the hex-encoded block header data"},
},
RPCResult{"None"},
RPCExamples{HelpExampleCli("submitheader", "\"aabbcc\"") +
HelpExampleRpc("submitheader", "\"aabbcc\"")},
}
.ToStringWithResultsAndExamples());
}
CBlockHeader h;
if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
"Block header decode failed");
}
{
LOCK(cs_main);
if (!LookupBlockIndex(h.hashPrevBlock)) {
throw JSONRPCError(RPC_VERIFY_ERROR,
"Must submit previous header (" +
h.hashPrevBlock.GetHex() + ") first");
}
}
CValidationState state;
ProcessNewBlockHeaders(config, {h}, state, /* ppindex */ nullptr,
/* first_invalid */ nullptr);
if (state.IsValid()) {
return NullUniValue;
}
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, FormatStateMessage(state));
}
throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason());
}
static UniValue estimatefee(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(RPCHelpMan{
"estimatefee",
"\nEstimates the approximate fee per kilobyte needed "
"for a transaction\n",
{},
RPCResult{"n (numeric) estimated fee-per-kilobyte\n"},
RPCExamples{HelpExampleCli("estimatefee", "")},
}
.ToStringWithResultsAndExamples());
}
return ValueFromAmount(g_mempool.estimateFee().GetFeePerK());
}
// clang-format off
static const CRPCCommand commands[] = {
// category name actor (function) argNames
// ---------- ------------------------ ---------------------- ----------
{"mining", "getnetworkhashps", getnetworkhashps, {"nblocks", "height"}},
{"mining", "getmininginfo", getmininginfo, {}},
{"mining", "prioritisetransaction", prioritisetransaction, {"txid", "dummy", "fee_delta"}},
{"mining", "getblocktemplate", getblocktemplate, {"template_request"}},
{"mining", "submitblock", submitblock, {"hexdata", "dummy"}},
{"mining", "submitheader", submitheader, {"hexdata"}},
{"generating", "generatetoaddress", generatetoaddress, {"nblocks", "address", "maxtries"}},
{"util", "estimatefee", estimatefee, {"nblocks"}},
};
// clang-format on
void RegisterMiningRPCCommands(CRPCTable &t) {
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
}
diff --git a/src/validation.h b/src/validation.h
index 36d43f56e..bfbf41d21 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -1,815 +1,813 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2017-2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_VALIDATION_H
#define BITCOIN_VALIDATION_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <amount.h>
#include <blockfileinfo.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <flatfile.h>
#include <fs.h>
#include <protocol.h> // For CMessageHeader::MessageMagic
#include <script/script_error.h>
#include <script/script_metrics.h>
#include <sync.h>
#include <versionbits.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <exception>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
class arith_uint256;
class CBlockIndex;
class CBlockTreeDB;
class CChainParams;
class CChain;
class CCoinsViewDB;
class CConnman;
class CInv;
class Config;
class CScriptCheck;
class CTxMemPool;
class CTxUndo;
class CValidationState;
struct FlatFilePos;
struct ChainTxData;
struct PrecomputedTransactionData;
struct LockPoints;
namespace Consensus {
struct Params;
}
#define MIN_TRANSACTION_SIZE \
(::GetSerializeSize(CTransaction(), PROTOCOL_VERSION))
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(1000 * SATOSHI);
/** Default for -excessutxocharge for transactions transactions */
static const Amount DEFAULT_UTXO_FEE = Amount::zero();
//! -maxtxfee default
static const Amount DEFAULT_TRANSACTION_MAXFEE(COIN / 10);
//! Discourage users to set fees higher than this amount (in satoshis) per kB
static const Amount HIGH_TX_FEE_PER_KB(COIN / 100);
/**
* -maxtxfee will warn if called with a higher fee than this amount (in satoshis
*/
static const Amount HIGH_MAX_TX_FEE(100 * HIGH_TX_FEE_PER_KB);
/**
* Default for -mempoolexpiry, expiration time for mempool transactions in
* hours.
*/
static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** Maximum number of script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
/**
* Number of blocks that can be requested at any given time from a single peer.
*/
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
/**
* Timeout in seconds during which a peer must stall block download progress
* before being disconnected.
*/
static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
/**
* Number of headers sent in one getheaders result. We rely on the assumption
* that if a peer sends less than this number, we reached its tip. Changing this
* value is a protocol upgrade.
*/
static const unsigned int MAX_HEADERS_RESULTS = 2000;
/**
* Maximum depth of blocks we're willing to serve as compact blocks to peers
* when requested. For older blocks, a regular BLOCK response will be sent.
*/
static const int MAX_CMPCTBLOCK_DEPTH = 5;
/**
* Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for.
*/
static const int MAX_BLOCKTXN_DEPTH = 10;
/**
* Size of the "block download window": how far ahead of our current height do
* we fetch ? Larger windows tolerate larger download speed differences between
* peer, but increase the potential degree of disordering of blocks on disk
* (which make reindexing and in the future perhaps pruning harder). We'll
* probably want to make this a per-peer adaptive value at some point.
*/
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
/** Time to wait (in seconds) between writing blocks/block index to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
/** Time to wait (in seconds) between flushing chainstate to disk. */
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** Block download timeout base, expressed in millionths of the block interval
* (i.e. 10 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/**
* Additional block download timeout per parallel downloading peer (i.e. 5 min)
*/
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/**
* Maximum age of our tip in seconds for us to be considered current for fee
* estimation.
*/
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
/** Default for -persistmempool */
static const bool DEFAULT_PERSIST_MEMPOOL = true;
/** Default for using fee filter */
static const bool DEFAULT_FEEFILTER = true;
/**
* Maximum number of headers to announce when relaying blocks with headers
* message.
*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
/** Maximum number of unconnecting headers announcements before DoS score */
static const int MAX_UNCONNECTING_HEADERS = 10;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
/** Default for -maxreorgdepth */
static const int DEFAULT_MAX_REORG_DEPTH = 10;
/**
* Default for -finalizationdelay
* This is the minimum time between a block header reception and the block
* finalization.
* This value should be >> block propagation and validation time
*/
static const int64_t DEFAULT_MIN_FINALIZATION_DELAY = 2 * 60 * 60;
extern CScript COINBASE_FLAGS;
extern RecursiveMutex cs_main;
extern CTxMemPool g_mempool;
-extern uint64_t nLastBlockTx;
-extern uint64_t nLastBlockSize;
extern const std::string strMessageMagic;
extern Mutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
extern uint256 g_best_block;
extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
/**
* A fee rate smaller than this is considered zero fee (for relaying, mining and
* transaction creation)
*/
extern CFeeRate minRelayTxFee;
/**
* Absolute maximum transaction fee (in satoshis) used by wallet and mempool
* (rejects high fee in sendrawtransaction)
*/
extern Amount maxTxFee;
/**
* If the tip is older than this (in seconds), the node is considered to be in
* initial block download.
*/
extern int64_t nMaxTipAge;
/**
* Block hash whose ancestors we will assume to have valid scripts without
* checking them.
*/
extern BlockHash hashAssumeValid;
/**
* Minimum work we will assume exists on some valid chain.
*/
extern arith_uint256 nMinimumChainWork;
/**
* Best header we've seen so far (used for getheaders queries' starting points).
*/
extern CBlockIndex *pindexBestHeader;
/** Pruning-related variables and constants */
/** True if any block files have ever been pruned. */
extern bool fHavePruned;
/** True if we're running in -prune mode. */
extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
extern uint64_t nPruneTarget;
/**
* Block files containing a block-height within MIN_BLOCKS_TO_KEEP of
* ::ChainActive().Tip() will not be pruned.
*/
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
/**
* Require that user allocate at least 550MB for block & undo files (blk???.dat
* and rev???.dat)
* At 1MB per block, 288 blocks = 288MB.
* Add 15% for Undo data = 331MB
* Add 20% for Orphan block rate = 397MB
* We want the low water mark after pruning to be at least 397 MB and since we
* prune in full block file chunks, we need the high water mark which triggers
* the prune to be one 128MB block file + added 15% undo data = 147MB greater
* for a total of 545MB. Setting the target to > than 550MB will make it likely
* we can respect the target.
*/
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
class BlockValidationOptions {
private:
uint64_t excessiveBlockSize;
bool checkPoW : 1;
bool checkMerkleRoot : 1;
public:
// Do full validation by default
BlockValidationOptions(const Config &config);
BlockValidationOptions(uint64_t _excessiveBlockSize, bool _checkPow = true,
bool _checkMerkleRoot = true)
: excessiveBlockSize(_excessiveBlockSize), checkPoW(_checkPow),
checkMerkleRoot(_checkMerkleRoot) {}
BlockValidationOptions withCheckPoW(bool _checkPoW = true) const {
BlockValidationOptions ret = *this;
ret.checkPoW = _checkPoW;
return ret;
}
BlockValidationOptions
withCheckMerkleRoot(bool _checkMerkleRoot = true) const {
BlockValidationOptions ret = *this;
ret.checkMerkleRoot = _checkMerkleRoot;
return ret;
}
bool shouldValidatePoW() const { return checkPoW; }
bool shouldValidateMerkleRoot() const { return checkMerkleRoot; }
uint64_t getExcessiveBlockSize() const { return excessiveBlockSize; }
};
/**
* Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
* If you want to *possibly* get feedback on whether pblock is valid, you must
* install a CValidationInterface (see validationinterface.h) - this will have
* its BlockChecked method called whenever *any* block completes validation.
*
* Note that we guarantee that either the proof-of-work is valid on pblock, or
* (and possibly also) BlockChecked will have been called.
*
* May not be called in a validationinterface callback.
*
* @param[in] config The global config.
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used
* for non-network block sources and whitelisted peers.
* @param[out] fNewBlock A boolean which is set to indicate if the block was
* first received via this call.
* @return True if the block is accepted as a valid block.
*/
bool ProcessNewBlock(const Config &config,
const std::shared_ptr<const CBlock> pblock,
bool fForceProcessing, bool *fNewBlock)
LOCKS_EXCLUDED(cs_main);
/**
* Process incoming block headers.
*
* May not be called in a validationinterface callback.
*
* @param[in] config The config.
* @param[in] block The block headers themselves.
* @param[out] state This may be set to an Error state if any error
* occurred processing them.
* @param[out] ppindex If set, the pointer will be set to point to the
* last new block index object for the given headers.
* @param[out] first_invalid First header that fails validation, if one exists.
* @return True if block headers were accepted as valid.
*/
bool ProcessNewBlockHeaders(const Config &config,
const std::vector<CBlockHeader> &block,
CValidationState &state,
const CBlockIndex **ppindex = nullptr,
CBlockHeader *first_invalid = nullptr)
LOCKS_EXCLUDED(cs_main);
/**
* Open a block file (blk?????.dat).
*/
FILE *OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
/**
* Translation to a filesystem path.
*/
fs::path GetBlockPosFilename(const FlatFilePos &pos);
/**
* Import blocks from an external file.
*/
bool LoadExternalBlockFile(const Config &config, FILE *fileIn,
FlatFilePos *dbp = nullptr);
/**
* Ensures we have a genesis block in the block tree, possibly writing one to
* disk.
*/
bool LoadGenesisBlock(const CChainParams &chainparams);
/**
* Load the block tree and coins database from disk, initializing state if we're
* running with -reindex.
*/
bool LoadBlockIndex(const Config &config) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Update the chain tip based on database information.
*/
bool LoadChainTip(const Config &config) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Unload database information.
*/
void UnloadBlockIndex();
/**
* Run an instance of the script checking thread.
*/
void ThreadScriptCheck(int worker_num);
/**
* Check whether we are doing an initial block download (synchronizing from disk
* or network)
*/
bool IsInitialBlockDownload();
/**
* Retrieve a transaction (from memory pool, or from disk, if possible).
*/
bool GetTransaction(const TxId &txid, CTransactionRef &txOut,
const Consensus::Params &params, BlockHash &hashBlock,
bool fAllowSlow = false,
const CBlockIndex *const blockIndex = nullptr);
/**
* Find the best known block, and make it the tip of the block chain
*
* May not be called with cs_main held. May not be called in a
* validationinterface callback.
*/
bool ActivateBestChain(
const Config &config, CValidationState &state,
std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams);
/**
* Guess verification progress (as a fraction between 0.0=genesis and
* 1.0=current tip).
*/
double GuessVerificationProgress(const ChainTxData &data,
const CBlockIndex *pindex);
/**
* Calculate the amount of disk space the block & undo files currently use.
*/
uint64_t CalculateCurrentUsage();
/**
* Mark one block file as pruned.
*/
void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Actually unlink the specified files
*/
void UnlinkPrunedFiles(const std::set<int> &setFilesToPrune);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
void PruneAndFlush();
/** Prune block files up to a given height */
void PruneBlockFilesManual(int nManualPruneHeight);
/**
* (try to) add transaction to memory pool
*/
bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool,
CValidationState &state, const CTransactionRef &tx,
bool *pfMissingInputs, bool bypass_limits,
const Amount nAbsurdFee, bool test_accept = false)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
/**
* Simple class for regulating resource usage during CheckInputs (and
* CScriptCheck), atomic so as to be compatible with parallel validation.
*/
class CheckInputsLimiter {
protected:
std::atomic<int64_t> remaining;
public:
CheckInputsLimiter(int64_t limit) : remaining(limit) {}
bool consume_and_check(int consumed) {
auto newvalue = (remaining -= consumed);
return newvalue >= 0;
}
bool check() { return remaining >= 0; }
};
class TxSigCheckLimiter : public CheckInputsLimiter {
public:
TxSigCheckLimiter() : CheckInputsLimiter(MAX_TX_SIGCHECKS) {}
// Let's make this bad boy copiable.
TxSigCheckLimiter(const TxSigCheckLimiter &rhs)
: CheckInputsLimiter(rhs.remaining.load()) {}
TxSigCheckLimiter &operator=(const TxSigCheckLimiter &rhs) {
remaining = rhs.remaining.load();
return *this;
}
};
/**
* Check whether all inputs of this transaction are valid (no double spends,
* scripts & sigs, amounts). This does not modify the UTXO set.
*
* If pvChecks is not nullptr, script checks are pushed onto it instead of being
* performed inline. Any script checks which are not necessary (eg due to script
* execution cache hits) are, obviously, not pushed onto pvChecks/run.
*
* Upon success nSigChecksOut will be filled in with either:
* - correct total for all inputs, or,
* - 0, in the case when checks were pushed onto pvChecks (i.e., a cache miss
* with pvChecks non-null), in which case the total can be found by executing
* pvChecks and adding the results.
*
* Setting sigCacheStore/scriptCacheStore to false will remove elements from the
* corresponding cache which are matched. This is useful for checking blocks
* where we will likely never need the cache entry again.
*
* pLimitSigChecks can be passed to limit the sigchecks count either in parallel
* or serial validation. With pvChecks null (serial validation), breaking the
* pLimitSigChecks limit will abort evaluation early and return false. With
* pvChecks not-null (parallel validation): the cached nSigChecks may itself
* break the limit in which case false is returned, OR, each entry in the
* returned pvChecks must be executed exactly once in order to probe the limit
* accurately.
*/
bool CheckInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &view, bool fScriptChecks,
const uint32_t flags, bool sigCacheStore,
bool scriptCacheStore,
const PrecomputedTransactionData &txdata, int &nSigChecksOut,
TxSigCheckLimiter &txLimitSigChecks,
CheckInputsLimiter *pBlockLimitSigChecks,
std::vector<CScriptCheck> *pvChecks)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Handy shortcut to full fledged CheckInputs call.
*/
static inline bool
CheckInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &view, bool fScriptChecks,
const uint32_t flags, bool sigCacheStore, bool scriptCacheStore,
const PrecomputedTransactionData &txdata, int &nSigChecksOut)
EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
TxSigCheckLimiter nSigChecksTxLimiter;
return CheckInputs(tx, state, view, fScriptChecks, flags, sigCacheStore,
scriptCacheStore, txdata, nSigChecksOut,
nSigChecksTxLimiter, nullptr, nullptr);
}
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params &params,
Consensus::DeploymentPos pos);
/** Get the BIP9 state for a given deployment at a given block. */
ThresholdState VersionBitsBlockState(const Consensus::Params &params,
Consensus::DeploymentPos pos,
const CBlockIndex *pindex);
/**
* Get the numerical statistics for the BIP9 state for a given deployment at the
* current tip.
*/
BIP9Stats VersionBitsTipStatistics(const Consensus::Params &params,
Consensus::DeploymentPos pos);
/**
* Get the block height at which the BIP9 deployment switched into the state for
* the block building on the current tip.
*/
int VersionBitsTipStateSinceHeight(const Consensus::Params &params,
Consensus::DeploymentPos pos);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, int nHeight);
/**
* Mark all the coins corresponding to a given transaction inputs as spent.
*/
void SpendCoins(CCoinsViewCache &view, const CTransaction &tx, CTxUndo &txundo,
int nHeight);
/**
* Apply the effects of this transaction on the UTXO set represented by view.
*/
void UpdateCoins(CCoinsViewCache &view, const CTransaction &tx, int nHeight);
void UpdateCoins(CCoinsViewCache &view, const CTransaction &tx, CTxUndo &txundo,
int nHeight);
/**
* Test whether the LockPoints height and time are still valid on the current
* chain.
*/
bool TestLockPointValidity(const LockPoints *lp)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Check if transaction will be BIP 68 final in the next block to be created.
*
* Simulates calling SequenceLocks() with data from the tip of the current
* active chain. Optionally stores in LockPoints the resulting height and time
* calculated and the hash of the block needed for calculation or skips the
* calculation and uses the LockPoints passed in for evaluation. The LockPoints
* should not be considered valid if CheckSequenceLocks returns false.
*
* See consensus/consensus.h for flag definitions.
*/
bool CheckSequenceLocks(const CTxMemPool &pool, const CTransaction &tx,
int flags, LockPoints *lp = nullptr,
bool useExistingLockPoints = false)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Closure representing one script verification.
* Note that this stores references to the spending transaction.
*
* Note that if pLimitSigChecks is passed, then failure does not imply that
* scripts have failed.
*/
class CScriptCheck {
private:
CScript scriptPubKey;
Amount amount;
const CTransaction *ptxTo;
unsigned int nIn;
uint32_t nFlags;
bool cacheStore;
ScriptError error;
ScriptExecutionMetrics metrics;
PrecomputedTransactionData txdata;
TxSigCheckLimiter *pTxLimitSigChecks;
CheckInputsLimiter *pBlockLimitSigChecks;
public:
CScriptCheck()
: amount(), ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false),
error(ScriptError::UNKNOWN), txdata(), pTxLimitSigChecks(nullptr),
pBlockLimitSigChecks(nullptr) {}
CScriptCheck(const CScript &scriptPubKeyIn, const Amount amountIn,
const CTransaction &txToIn, unsigned int nInIn,
uint32_t nFlagsIn, bool cacheIn,
const PrecomputedTransactionData &txdataIn,
TxSigCheckLimiter *pTxLimitSigChecksIn = nullptr,
CheckInputsLimiter *pBlockLimitSigChecksIn = nullptr)
: scriptPubKey(scriptPubKeyIn), amount(amountIn), ptxTo(&txToIn),
nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn),
error(ScriptError::UNKNOWN), txdata(txdataIn),
pTxLimitSigChecks(pTxLimitSigChecksIn),
pBlockLimitSigChecks(pBlockLimitSigChecksIn) {}
bool operator()();
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(amount, check.amount);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
std::swap(metrics, check.metrics);
std::swap(txdata, check.txdata);
std::swap(pTxLimitSigChecks, check.pTxLimitSigChecks);
std::swap(pBlockLimitSigChecks, check.pBlockLimitSigChecks);
}
ScriptError GetScriptError() const { return error; }
ScriptExecutionMetrics GetScriptExecutionMetrics() const { return metrics; }
};
/** Functions for disk access for blocks */
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos,
const Consensus::Params &params);
bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex,
const Consensus::Params &params);
/** Functions for validating blocks and updating the block tree */
/**
* Context-independent validity checks.
*
* Returns true if the provided block is valid (has valid header,
* transactions are valid, block is a valid size, etc.)
*/
bool CheckBlock(const CBlock &block, CValidationState &state,
const Consensus::Params &params,
BlockValidationOptions validationOptions);
/**
* This is a variant of ContextualCheckTransaction which computes the contextual
* check for a transaction based on the chain tip.
*
* See consensus/consensus.h for flag definitions.
*/
bool ContextualCheckTransactionForCurrentBlock(const Consensus::Params &params,
const CTransaction &tx,
CValidationState &state,
int flags = -1);
/**
* Check a block is completely valid from start to finish (only works on top of
* our current best block)
*/
bool TestBlockValidity(CValidationState &state, const CChainParams &params,
const CBlock &block, CBlockIndex *pindexPrev,
BlockValidationOptions validationOptions)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* RAII wrapper for VerifyDB: Verify consistency of the block and coin
* databases.
*/
class CVerifyDB {
public:
CVerifyDB();
~CVerifyDB();
bool VerifyDB(const Config &config, CCoinsView *coinsview, int nCheckLevel,
int nCheckDepth);
};
/** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const Consensus::Params &params, CCoinsView *view);
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex *FindForkInGlobalIndex(const CChain &chain,
const CBlockLocator &locator)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Mark a block as precious and reorganize.
*
* May not be called in a validationinterface callback.
*/
bool PreciousBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main);
/**
* Mark a block as finalized.
* A finalized block can not be reorged in any way.
*/
bool FinalizeBlockAndInvalidate(const Config &config, CValidationState &state,
CBlockIndex *pindex)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Mark a block as invalid. */
bool InvalidateBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex);
/** Park a block. */
bool ParkBlock(const Config &config, CValidationState &state,
CBlockIndex *pindex);
/** Remove invalidity status from a block and its descendants. */
void ResetBlockFailureFlags(CBlockIndex *pindex)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Remove parked status from a block and its descendants. */
void UnparkBlockAndChildren(CBlockIndex *pindex)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Remove parked status from a block. */
void UnparkBlock(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Retrieve the topmost finalized block.
*/
const CBlockIndex *GetFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Checks if a block is finalized.
*/
bool IsBlockFinalized(const CBlockIndex *pindex)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** @returns the most-work chain. */
CChain &ChainActive();
/**
* Global variable that points to the coins database (protected by cs_main)
*/
extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
/**
* Global variable that points to the active CCoinsView (protected by cs_main)
*/
extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
/**
* Global variable that points to the active block tree (protected by cs_main)
*/
extern std::unique_ptr<CBlockTreeDB> pblocktree;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
* While checking, GetBestBlock() refers to the parent block. (protected by
* cs_main)
* This is also true for mempool checks.
*/
int GetSpendHeight(const CCoinsViewCache &inputs);
/**
* Determine what nVersion a new block should use.
*/
int32_t ComputeBlockVersion(const CBlockIndex *pindexPrev,
const Consensus::Params &params);
/**
* Reject codes greater or equal to this can be returned by AcceptToMemPool or
* AcceptBlock for blocks/transactions, to signal internal conditions. They
* cannot and should not be sent over the P2P network.
*/
static const unsigned int REJECT_INTERNAL = 0x100;
/** Too high fee. Can not be triggered by P2P transactions */
static const unsigned int REJECT_HIGHFEE = 0x100;
/** Block conflicts with a transaction already known */
static const unsigned int REJECT_AGAINST_FINALIZED = 0x103;
/** Get block file info entry for one block file */
CBlockFileInfo *GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
bool DumpMempool(const CTxMemPool &pool);
/** Load the mempool from disk. */
bool LoadMempool(const Config &config, CTxMemPool &pool);
//! Check whether the block associated with this index entry is pruned or not.
bool IsBlockPruned(const CBlockIndex *pblockindex);
#endif // BITCOIN_VALIDATION_H
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index fda199178..ff6b4e711 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -1,257 +1,277 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Copyright (c) 2014-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mining RPCs
- getmininginfo
- getblocktemplate proposal mode
- submitblock"""
import copy
from decimal import Decimal
-from test_framework.blocktools import create_coinbase
+from test_framework.blocktools import (
+ create_coinbase,
+ TIME_GENESIS_BLOCK,
+)
from test_framework.messages import (
CBlock,
CBlockHeader,
)
from test_framework.mininode import (
P2PDataStore,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
+ connect_nodes_bi,
)
def assert_template(node, block, expect, rehash=True):
if rehash:
block.hashMerkleRoot = block.calc_merkle_root()
rsp = node.getblocktemplate(
template_request={
'data': block.serialize().hex(),
'mode': 'proposal'})
assert_equal(rsp, expect)
class MiningTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
+ self.setup_clean_chain = True
+
+ def mine_chain(self):
+ self.log.info('Create some old blocks')
+ node = self.nodes[0]
+ address = node.get_deterministic_priv_key().address
+ for t in range(TIME_GENESIS_BLOCK,
+ TIME_GENESIS_BLOCK + 200 * 600, 600):
+ node.setmocktime(t)
+ node.generatetoaddress(1, address)
+ mining_info = node.getmininginfo()
+ assert_equal(mining_info['blocks'], 200)
+ assert_equal(mining_info['currentblocktx'], 0)
+ assert_equal(mining_info['currentblocksize'], 1000)
+ self.restart_node(0)
+ connect_nodes_bi(self.nodes[0], self.nodes[1])
def run_test(self):
+ self.mine_chain()
node = self.nodes[0]
def assert_submitblock(block, result_str_1, result_str_2=None):
block.solve()
result_str_2 = result_str_2 or 'duplicate-invalid'
assert_equal(result_str_1, node.submitblock(
hexdata=block.serialize().hex()))
assert_equal(result_str_2, node.submitblock(
hexdata=block.serialize().hex()))
self.log.info('getmininginfo')
mining_info = node.getmininginfo()
assert_equal(mining_info['blocks'], 200)
assert_equal(mining_info['chain'], 'regtest')
- assert_equal(mining_info['currentblocksize'], 0)
- assert_equal(mining_info['currentblocktx'], 0)
+ assert 'currentblocktx' not in mining_info
+ assert 'currentblocksize' not in mining_info
assert_equal(mining_info['difficulty'],
Decimal('4.656542373906925E-10'))
assert_equal(mining_info['networkhashps'],
Decimal('0.003333333333333334'))
assert_equal(mining_info['pooledtx'], 0)
# Mine a block to leave initial block download
node.generatetoaddress(1, node.get_deterministic_priv_key().address)
tmpl = node.getblocktemplate()
self.log.info("getblocktemplate: Test capability advertised")
assert 'proposal' in tmpl['capabilities']
assert 'coinbasetxn' not in tmpl
coinbase_tx = create_coinbase(height=int(tmpl["height"]) + 1)
# sequence numbers must not be max for nLockTime to have effect
coinbase_tx.vin[0].nSequence = 2 ** 32 - 2
coinbase_tx.rehash()
block = CBlock()
block.nVersion = tmpl["version"]
block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
block.nTime = tmpl["curtime"]
block.nBits = int(tmpl["bits"], 16)
block.nNonce = 0
block.vtx = [coinbase_tx]
self.log.info("getblocktemplate: Test valid block")
assert_template(node, block, None)
self.log.info("submitblock: Test block decode failure")
assert_raises_rpc_error(-22, "Block decode failed",
node.submitblock, block.serialize()[:-15].hex())
self.log.info(
"getblocktemplate: Test bad input hash for coinbase transaction")
bad_block = copy.deepcopy(block)
bad_block.vtx[0].vin[0].prevout.hash += 1
bad_block.vtx[0].rehash()
assert_template(node, bad_block, 'bad-cb-missing')
self.log.info("submitblock: Test invalid coinbase transaction")
assert_raises_rpc_error(-22, "Block does not start with a coinbase",
node.submitblock, bad_block.serialize().hex())
self.log.info("getblocktemplate: Test truncated final transaction")
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {
'data': block.serialize()[:-1].hex(), 'mode': 'proposal'})
self.log.info("getblocktemplate: Test duplicate transaction")
bad_block = copy.deepcopy(block)
bad_block.vtx.append(bad_block.vtx[0])
assert_template(node, bad_block, 'bad-txns-duplicate')
assert_submitblock(bad_block, 'bad-txns-duplicate',
'bad-txns-duplicate')
self.log.info("getblocktemplate: Test invalid transaction")
bad_block = copy.deepcopy(block)
bad_tx = copy.deepcopy(bad_block.vtx[0])
bad_tx.vin[0].prevout.hash = 255
bad_tx.rehash()
bad_block.vtx.append(bad_tx)
assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')
assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent')
self.log.info("getblocktemplate: Test nonfinal transaction")
bad_block = copy.deepcopy(block)
bad_block.vtx[0].nLockTime = 2 ** 32 - 1
bad_block.vtx[0].rehash()
assert_template(node, bad_block, 'bad-txns-nonfinal')
assert_submitblock(bad_block, 'bad-txns-nonfinal')
self.log.info("getblocktemplate: Test bad tx count")
# The tx count is immediately after the block header
TX_COUNT_OFFSET = 80
bad_block_sn = bytearray(block.serialize())
assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1)
bad_block_sn[TX_COUNT_OFFSET] += 1
assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {
'data': bad_block_sn.hex(), 'mode': 'proposal'})
self.log.info("getblocktemplate: Test bad bits")
bad_block = copy.deepcopy(block)
bad_block.nBits = 469762303 # impossible in the real world
assert_template(node, bad_block, 'bad-diffbits')
self.log.info("getblocktemplate: Test bad merkle root")
bad_block = copy.deepcopy(block)
bad_block.hashMerkleRoot += 1
assert_template(node, bad_block, 'bad-txnmrklroot', False)
assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot')
self.log.info("getblocktemplate: Test bad timestamps")
bad_block = copy.deepcopy(block)
bad_block.nTime = 2 ** 31 - 1
assert_template(node, bad_block, 'time-too-new')
assert_submitblock(bad_block, 'time-too-new', 'time-too-new')
bad_block.nTime = 0
assert_template(node, bad_block, 'time-too-old')
assert_submitblock(bad_block, 'time-too-old', 'time-too-old')
self.log.info("getblocktemplate: Test not best block")
bad_block = copy.deepcopy(block)
bad_block.hashPrevBlock = 123
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
assert_submitblock(bad_block, 'prev-blk-not-found',
'prev-blk-not-found')
self.log.info('submitheader tests')
assert_raises_rpc_error(-22, 'Block header decode failed',
lambda: node.submitheader(hexdata='xx' * 80))
assert_raises_rpc_error(-22, 'Block header decode failed',
lambda: node.submitheader(hexdata='ff' * 78))
assert_raises_rpc_error(-25, 'Must submit previous header',
lambda: node.submitheader(hexdata='ff' * 80))
block.nTime += 1
block.solve()
def chain_tip(b_hash, *, status='headers-only', branchlen=1):
return {'hash': b_hash, 'height': 202,
'branchlen': branchlen, 'status': status}
assert chain_tip(block.hash) not in node.getchaintips()
node.submitheader(hexdata=block.serialize().hex())
assert chain_tip(block.hash) in node.getchaintips()
# Noop
node.submitheader(hexdata=CBlockHeader(block).serialize().hex())
assert chain_tip(block.hash) in node.getchaintips()
bad_block_root = copy.deepcopy(block)
bad_block_root.hashMerkleRoot += 2
bad_block_root.solve()
assert chain_tip(bad_block_root.hash) not in node.getchaintips()
node.submitheader(hexdata=CBlockHeader(
bad_block_root).serialize().hex())
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# Should still reject invalid blocks, even if we have the header:
assert_equal(node.submitblock(
hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
assert_equal(node.submitblock(
hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# We know the header for this invalid block, so should just return
# early without error:
node.submitheader(hexdata=CBlockHeader(
bad_block_root).serialize().hex())
assert chain_tip(bad_block_root.hash) in node.getchaintips()
bad_block_lock = copy.deepcopy(block)
bad_block_lock.vtx[0].nLockTime = 2**32 - 1
bad_block_lock.vtx[0].rehash()
bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
bad_block_lock.solve()
assert_equal(node.submitblock(
hexdata=bad_block_lock.serialize().hex()), 'bad-txns-nonfinal')
assert_equal(node.submitblock(
hexdata=bad_block_lock.serialize().hex()), 'duplicate-invalid')
# Build a "good" block on top of the submitted bad block
bad_block2 = copy.deepcopy(block)
bad_block2.hashPrevBlock = bad_block_lock.sha256
bad_block2.solve()
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(
hexdata=CBlockHeader(bad_block2).serialize().hex()))
# Should reject invalid header right away
bad_block_time = copy.deepcopy(block)
bad_block_time.nTime = 1
bad_block_time.solve()
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(
hexdata=CBlockHeader(bad_block_time).serialize().hex()))
# Should ask for the block from a p2p node, if they announce the header
# as well:
node.add_p2p_connection(P2PDataStore())
# Drop the first getheaders
node.p2p.wait_for_getheaders(timeout=5)
node.p2p.send_blocks_and_test(blocks=[block], node=node)
# Must be active now:
assert chain_tip(block.hash, status='active',
branchlen=0) in node.getchaintips()
# Building a few blocks should give the same results
node.generatetoaddress(10, node.get_deterministic_priv_key().address)
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(
hexdata=CBlockHeader(bad_block_time).serialize().hex()))
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(
hexdata=CBlockHeader(bad_block2).serialize().hex()))
node.submitheader(hexdata=CBlockHeader(block).serialize().hex())
node.submitheader(hexdata=CBlockHeader(
bad_block_root).serialize().hex())
# valid
assert_equal(node.submitblock(
hexdata=block.serialize().hex()), 'duplicate')
if __name__ == '__main__':
MiningTest().main()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 7dfbc792f..6ec4cf752 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,229 +1,231 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2016 The Bitcoin Core developers
+# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
from .script import (
CScript,
OP_CHECKSIG,
OP_DUP,
OP_EQUALVERIFY,
OP_HASH160,
OP_RETURN,
OP_TRUE,
)
from .messages import (
CBlock,
COIN,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
FromHex,
ToHex,
ser_string,
)
from .txtools import pad_tx
from .util import assert_equal, satoshi_round
-# Create a block (with regtest difficulty)
+# Genesis block time (regtest)
+TIME_GENESIS_BLOCK = 1296688602
def create_block(hashprev, coinbase, nTime=None):
+ """Create a block (with regtest difficulty)."""
block = CBlock()
if nTime is None:
import time
block.nTime = int(time.time() + 600)
else:
block.nTime = nTime
block.hashPrevBlock = hashprev
block.nBits = 0x207fffff # Will break after a difficulty adjustment...
block.vtx.append(coinbase)
block.hashMerkleRoot = block.calc_merkle_root()
block.calc_sha256()
return block
def make_conform_to_ctor(block):
for tx in block.vtx:
tx.rehash()
block.vtx = [block.vtx[0]] + \
sorted(block.vtx[1:], key=lambda tx: tx.get_id())
def serialize_script_num(value):
r = bytearray(0)
if value == 0:
return r
neg = value < 0
absvalue = -value if neg else value
while (absvalue):
r.append(int(absvalue & 0xff))
absvalue >>= 8
if r[-1] & 0x80:
r.append(0x80 if neg else 0)
elif neg:
r[-1] |= 0x80
return r
# Create a coinbase transaction, assuming no miner fees.
# If pubkey is passed in, the coinbase output will be a P2PK output;
# otherwise an anyone-can-spend output.
def create_coinbase(height, pubkey=None):
coinbase = CTransaction()
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
ser_string(serialize_script_num(height)), 0xffffffff))
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = 50 * COIN
halvings = int(height / 150) # regtest
coinbaseoutput.nValue >>= halvings
if (pubkey is not None):
coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG])
else:
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
coinbase.vout = [coinbaseoutput]
# Make sure the coinbase is at least 100 bytes
pad_tx(coinbase)
coinbase.calc_sha256()
return coinbase
def create_tx_with_script(prevtx, n, script_sig=b"",
amount=1, script_pub_key=CScript()):
"""Return one-input, one-output transaction object
spending the prevtx's n-th output with the given amount.
Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.
"""
tx = CTransaction()
assert(n < len(prevtx.vout))
tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))
tx.vout.append(CTxOut(amount, script_pub_key))
pad_tx(tx)
tx.calc_sha256()
return tx
def create_transaction(node, txid, to_address, amount):
""" Return signed transaction spending the first output of the
input txid. Note that the node must be able to sign for the
output that is being spent, and the node must not be running
multiple wallets.
"""
raw_tx = create_raw_transaction(node, txid, to_address, amount)
tx = FromHex(CTransaction(), raw_tx)
return tx
def create_raw_transaction(node, txid, to_address, amount):
""" Return raw signed transaction spending the first output of the
input txid. Note that the node must be able to sign for the
output that is being spent, and the node must not be running
multiple wallets.
"""
inputs = [{"txid": txid, "vout": 0}]
outputs = {to_address: amount}
rawtx = node.createrawtransaction(inputs, outputs)
signresult = node.signrawtransactionwithwallet(rawtx)
assert_equal(signresult["complete"], True)
return signresult['hex']
def get_legacy_sigopcount_block(block, fAccurate=True):
count = 0
for tx in block.vtx:
count += get_legacy_sigopcount_tx(tx, fAccurate)
return count
def get_legacy_sigopcount_tx(tx, fAccurate=True):
count = 0
for i in tx.vout:
count += i.scriptPubKey.GetSigOpCount(fAccurate)
for j in tx.vin:
# scriptSig might be of type bytes, so convert to CScript for the
# moment
count += CScript(j.scriptSig).GetSigOpCount(fAccurate)
return count
def create_confirmed_utxos(node, count, age=101):
"""
Helper to create at least "count" utxos
"""
to_generate = int(0.5 * count) + age
while to_generate > 0:
node.generate(min(25, to_generate))
to_generate -= 25
utxos = node.listunspent()
iterations = count - len(utxos)
addr1 = node.getnewaddress()
addr2 = node.getnewaddress()
if iterations <= 0:
return utxos
for i in range(iterations):
t = utxos.pop()
inputs = []
inputs.append({"txid": t["txid"], "vout": t["vout"]})
outputs = {}
outputs[addr1] = satoshi_round(t['amount'] / 2)
outputs[addr2] = satoshi_round(t['amount'] / 2)
raw_tx = node.createrawtransaction(inputs, outputs)
ctx = FromHex(CTransaction(), raw_tx)
fee = node.calculate_fee(ctx) // 2
ctx.vout[0].nValue -= fee
# Due to possible truncation, we go ahead and take another satoshi in
# fees to ensure the transaction gets through
ctx.vout[1].nValue -= fee + 1
signed_tx = node.signrawtransactionwithwallet(ToHex(ctx))["hex"]
node.sendrawtransaction(signed_tx)
while (node.getmempoolinfo()['size'] > 0):
node.generate(1)
utxos = node.listunspent()
assert len(utxos) >= count
return utxos
def mine_big_block(node, utxos=None):
# generate a 66k transaction,
# and 14 of them is close to the 1MB block limit
num = 14
utxos = utxos if utxos is not None else []
if len(utxos) < num:
utxos.clear()
utxos.extend(node.listunspent())
send_big_transactions(node, utxos, num, 100)
node.generate(1)
def send_big_transactions(node, utxos, num, fee_multiplier):
from .cashaddr import decode
txids = []
padding = "1" * 512
addrHash = decode(node.getnewaddress())[2]
for _ in range(num):
ctx = CTransaction()
utxo = utxos.pop()
txid = int(utxo['txid'], 16)
ctx.vin.append(CTxIn(COutPoint(txid, int(utxo["vout"])), b""))
ctx.vout.append(
CTxOut(int(satoshi_round(utxo['amount'] * COIN)),
CScript([OP_DUP, OP_HASH160, addrHash, OP_EQUALVERIFY, OP_CHECKSIG])))
for i in range(0, 127):
ctx.vout.append(CTxOut(0, CScript(
[OP_RETURN, bytes(padding, 'utf-8')])))
# Create a proper fee for the transaction to be mined
ctx.vout[0].nValue -= int(fee_multiplier * node.calculate_fee(ctx))
signresult = node.signrawtransactionwithwallet(
ToHex(ctx), None, "NONE|FORKID")
txid = node.sendrawtransaction(signresult["hex"], True)
txids.append(txid)
return txids

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 10:24 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187345
Default Alt Text
(119 KB)

Event Timeline