2017-05-30 21:55:17 +02:00
|
|
|
// Copyright (c) 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 <interfaces/chain.h>
|
|
|
|
|
2017-07-27 16:08:31 +02:00
|
|
|
#include <chain.h>
|
2019-01-08 07:56:46 +01:00
|
|
|
#include <chainparams.h>
|
2017-07-29 03:40:29 +02:00
|
|
|
#include <policy/fees.h>
|
|
|
|
#include <policy/policy.h>
|
2017-07-29 01:25:26 +02:00
|
|
|
#include <policy/rbf.h>
|
2019-01-08 07:56:46 +01:00
|
|
|
#include <primitives/block.h>
|
2017-07-26 16:23:01 +02:00
|
|
|
#include <sync.h>
|
2017-07-29 00:13:23 +02:00
|
|
|
#include <threadsafety.h>
|
2017-07-29 01:25:26 +02:00
|
|
|
#include <txmempool.h>
|
2017-07-27 16:08:31 +02:00
|
|
|
#include <uint256.h>
|
2017-05-30 21:55:17 +02:00
|
|
|
#include <util/system.h>
|
2017-07-26 16:23:01 +02:00
|
|
|
#include <validation.h>
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <utility>
|
2017-05-30 21:55:17 +02:00
|
|
|
|
|
|
|
namespace interfaces {
|
|
|
|
namespace {
|
|
|
|
|
2017-07-26 16:23:01 +02:00
|
|
|
class LockImpl : public Chain::Lock
|
|
|
|
{
|
2017-07-27 16:08:31 +02:00
|
|
|
Optional<int> getHeight() override
|
|
|
|
{
|
|
|
|
int height = ::chainActive.Height();
|
|
|
|
if (height >= 0) {
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
Optional<int> getBlockHeight(const uint256& hash) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = LookupBlockIndex(hash);
|
|
|
|
if (block && ::chainActive.Contains(block)) {
|
|
|
|
return block->nHeight;
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
int getBlockDepth(const uint256& hash) override
|
|
|
|
{
|
|
|
|
const Optional<int> tip_height = getHeight();
|
|
|
|
const Optional<int> height = getBlockHeight(hash);
|
|
|
|
return tip_height && height ? *tip_height - *height + 1 : 0;
|
|
|
|
}
|
|
|
|
uint256 getBlockHash(int height) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = ::chainActive[height];
|
|
|
|
assert(block != nullptr);
|
|
|
|
return block->GetBlockHash();
|
|
|
|
}
|
2019-01-08 07:35:47 +01:00
|
|
|
int64_t getBlockTime(int height) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = ::chainActive[height];
|
|
|
|
assert(block != nullptr);
|
|
|
|
return block->GetBlockTime();
|
|
|
|
}
|
|
|
|
int64_t getBlockMedianTimePast(int height) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = ::chainActive[height];
|
|
|
|
assert(block != nullptr);
|
|
|
|
return block->GetMedianTimePast();
|
|
|
|
}
|
2019-01-08 09:06:24 +01:00
|
|
|
bool haveBlockOnDisk(int height) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = ::chainActive[height];
|
|
|
|
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
|
|
|
|
}
|
2019-01-08 08:38:53 +01:00
|
|
|
Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
|
|
|
|
{
|
|
|
|
CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
|
|
|
|
if (block) {
|
|
|
|
if (hash) *hash = block->GetBlockHash();
|
|
|
|
return block->nHeight;
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
|
|
|
|
{
|
|
|
|
// TODO: Could update CChain::FindEarliestAtLeast() to take a height
|
|
|
|
// parameter and use it with std::lower_bound() to make this
|
|
|
|
// implementation more efficient and allow combining
|
|
|
|
// findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
|
|
|
|
// method.
|
|
|
|
for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
|
|
|
|
if (block->GetBlockTime() >= time) {
|
|
|
|
return block->nHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
Optional<int> findPruned(int start_height, Optional<int> stop_height) override
|
|
|
|
{
|
|
|
|
if (::fPruneMode) {
|
|
|
|
CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
|
|
|
|
while (block && block->nHeight >= start_height) {
|
|
|
|
if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
|
|
|
|
return block->nHeight;
|
|
|
|
}
|
|
|
|
block = block->pprev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
2019-01-08 07:56:46 +01:00
|
|
|
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
|
|
|
|
{
|
|
|
|
const CBlockIndex* block = LookupBlockIndex(hash);
|
|
|
|
const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
|
|
|
|
if (height) {
|
|
|
|
if (block) {
|
|
|
|
*height = block->nHeight;
|
|
|
|
} else {
|
|
|
|
height->reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fork) {
|
|
|
|
return fork->nHeight;
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
2019-01-08 09:06:24 +01:00
|
|
|
bool isPotentialTip(const uint256& hash) override
|
|
|
|
{
|
|
|
|
if (::chainActive.Tip()->GetBlockHash() == hash) return true;
|
|
|
|
CBlockIndex* block = LookupBlockIndex(hash);
|
|
|
|
return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
|
|
|
|
}
|
2019-02-01 22:17:43 +01:00
|
|
|
CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); }
|
2019-01-08 09:06:24 +01:00
|
|
|
Optional<int> findLocatorFork(const CBlockLocator& locator) override
|
|
|
|
{
|
|
|
|
LockAnnotation lock(::cs_main);
|
|
|
|
if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
|
|
|
|
return fork->nHeight;
|
|
|
|
}
|
|
|
|
return nullopt;
|
|
|
|
}
|
2017-07-29 00:13:23 +02:00
|
|
|
bool checkFinalTx(const CTransaction& tx) override
|
|
|
|
{
|
|
|
|
LockAnnotation lock(::cs_main);
|
|
|
|
return CheckFinalTx(tx);
|
|
|
|
}
|
2017-07-26 16:23:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
|
|
|
|
{
|
|
|
|
using UniqueLock::UniqueLock;
|
|
|
|
};
|
|
|
|
|
2017-05-30 21:55:17 +02:00
|
|
|
class ChainImpl : public Chain
|
|
|
|
{
|
2017-07-26 16:23:01 +02:00
|
|
|
public:
|
|
|
|
std::unique_ptr<Chain::Lock> lock(bool try_lock) override
|
|
|
|
{
|
|
|
|
auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
|
|
|
|
if (try_lock && result && !*result) return {};
|
|
|
|
// std::move necessary on some compilers due to conversion from
|
|
|
|
// LockingStateImpl to Lock pointer
|
|
|
|
return std::move(result);
|
|
|
|
}
|
|
|
|
std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
|
2019-01-08 07:56:46 +01:00
|
|
|
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
|
|
|
|
{
|
|
|
|
CBlockIndex* index;
|
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
|
|
|
index = LookupBlockIndex(hash);
|
|
|
|
if (!index) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (time) {
|
|
|
|
*time = index->GetBlockTime();
|
|
|
|
}
|
|
|
|
if (time_max) {
|
|
|
|
*time_max = index->GetBlockTimeMax();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
|
|
|
|
block->SetNull();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2019-01-08 08:38:53 +01:00
|
|
|
double guessVerificationProgress(const uint256& block_hash) override
|
|
|
|
{
|
|
|
|
LOCK(cs_main);
|
|
|
|
return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
|
|
|
|
}
|
2017-07-29 01:25:26 +02:00
|
|
|
RBFTransactionState isRBFOptIn(const CTransaction& tx) override
|
|
|
|
{
|
|
|
|
LOCK(::mempool.cs);
|
|
|
|
return IsRBFOptIn(tx, ::mempool);
|
|
|
|
}
|
2017-07-29 01:29:50 +02:00
|
|
|
bool hasDescendantsInMempool(const uint256& txid) override
|
|
|
|
{
|
|
|
|
LOCK(::mempool.cs);
|
|
|
|
auto it_mp = ::mempool.mapTx.find(txid);
|
|
|
|
return it_mp != ::mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1;
|
|
|
|
}
|
2017-07-29 01:42:27 +02:00
|
|
|
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
|
|
|
|
{
|
|
|
|
::mempool.GetTransactionAncestry(txid, ancestors, descendants);
|
|
|
|
}
|
2017-07-29 01:45:45 +02:00
|
|
|
bool checkChainLimits(CTransactionRef tx) override
|
|
|
|
{
|
|
|
|
LockPoints lp;
|
|
|
|
CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
|
|
|
|
CTxMemPool::setEntries ancestors;
|
|
|
|
auto limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
|
|
|
|
auto limit_ancestor_size = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000;
|
|
|
|
auto limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
|
|
|
|
auto limit_descendant_size = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
|
|
|
|
std::string unused_error_string;
|
|
|
|
LOCK(::mempool.cs);
|
|
|
|
return ::mempool.CalculateMemPoolAncestors(entry, ancestors, limit_ancestor_count, limit_ancestor_size,
|
|
|
|
limit_descendant_count, limit_descendant_size, unused_error_string);
|
|
|
|
}
|
2017-07-29 03:40:29 +02:00
|
|
|
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
|
|
|
|
{
|
|
|
|
return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative);
|
|
|
|
}
|
|
|
|
unsigned int estimateMaxBlocks() override
|
|
|
|
{
|
|
|
|
return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
|
|
|
|
}
|
|
|
|
CFeeRate mempoolMinFee() override
|
|
|
|
{
|
|
|
|
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
|
|
|
|
}
|
2017-05-30 21:55:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
|
|
|
|
|
|
|
|
} // namespace interfaces
|