Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14362764
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Subscribers
None
View Options
diff --git a/src/chain.h b/src/chain.h
index 81b4fc20c9..df3f7ad640 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -1,427 +1,426 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 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_CHAIN_H
#define BITCOIN_CHAIN_H
#include <arith_uint256.h>
#include <blockstatus.h>
#include <blockvalidity.h>
#include <consensus/params.h>
#include <flatfile.h>
-#include <pow.h>
#include <primitives/block.h>
#include <sync.h>
#include <tinyformat.h>
#include <uint256.h>
#include <unordered_map>
#include <vector>
/**
* Maximum amount of time that a block timestamp is allowed to exceed the
* current network-adjusted time before the block will be accepted.
*/
static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
/**
* Timestamp window used as a grace period by code that compares external
* timestamps (such as timestamps passed to RPCs, or wallet key creation times)
* to block timestamps. This should be set at least as high as
* MAX_FUTURE_BLOCK_TIME.
*/
static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
/**
* Maximum gap between node time and block time used
* for the "Catching up..." mode in GUI.
*
* Ref: https://github.com/bitcoin/bitcoin/pull/1026
*/
static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60;
/**
* The block chain is a tree shaped structure starting with the genesis block at
* the root, with each block potentially having multiple candidates to be the
* next block. A blockindex may have multiple pprev pointing to it, but at most
* one of them can be part of the currently active branch.
*/
class CBlockIndex {
public:
//! pointer to the hash of the block, if any. Memory is owned by this
//! CBlockIndex
const uint256 *phashBlock;
//! pointer to the index of the predecessor of this block
CBlockIndex *pprev;
//! pointer to the index of some further predecessor of this block
CBlockIndex *pskip;
//! height of the entry in the chain. The genesis block has height 0
int nHeight;
//! Which # file this block is stored in (blk?????.dat)
int nFile;
//! Byte offset within blk?????.dat where this block's data is stored
unsigned int nDataPos;
//! Byte offset within rev?????.dat where this block's undo data is stored
unsigned int nUndoPos;
//! (memory only) Total amount of work (expected number of hashes) in the
//! chain up to and including this block
arith_uint256 nChainWork;
//! Number of transactions in this block.
//! Note: in a potential headers-first mode, this number cannot be relied
//! upon
unsigned int nTx;
//! (memory only) Number of transactions in the chain up to and including
//! this block.
//! This value will be non-zero only if and only if transactions for this
//! block and all its parents are available. Change to 64-bit type when
//! necessary; won't happen before 2030
unsigned int nChainTx;
//! Verification status of this block. See enum BlockStatus
BlockStatus nStatus;
//! block header
int32_t nVersion;
uint256 hashMerkleRoot;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
//! (memory only) Sequential id assigned to distinguish order in which
//! blocks are received.
int32_t nSequenceId;
//! (memory only) block header metadata
uint64_t nTimeReceived;
//! (memory only) Maximum nTime in the chain up to and including this block.
unsigned int nTimeMax;
void SetNull() {
phashBlock = nullptr;
pprev = nullptr;
pskip = nullptr;
nHeight = 0;
nFile = 0;
nDataPos = 0;
nUndoPos = 0;
nChainWork = arith_uint256();
nTx = 0;
nChainTx = 0;
nStatus = BlockStatus();
nSequenceId = 0;
nTimeMax = 0;
nVersion = 0;
hashMerkleRoot = uint256();
nTime = 0;
nTimeReceived = 0;
nBits = 0;
nNonce = 0;
}
CBlockIndex() { SetNull(); }
explicit CBlockIndex(const CBlockHeader &block) {
SetNull();
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
nTime = block.nTime;
nTimeReceived = 0;
nBits = block.nBits;
nNonce = block.nNonce;
}
FlatFilePos GetBlockPos() const {
FlatFilePos ret;
if (nStatus.hasData()) {
ret.nFile = nFile;
ret.nPos = nDataPos;
}
return ret;
}
FlatFilePos GetUndoPos() const {
FlatFilePos ret;
if (nStatus.hasUndo()) {
ret.nFile = nFile;
ret.nPos = nUndoPos;
}
return ret;
}
CBlockHeader GetBlockHeader() const {
CBlockHeader block;
block.nVersion = nVersion;
if (pprev) {
block.hashPrevBlock = pprev->GetBlockHash();
}
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
}
uint256 GetBlockHash() const { return *phashBlock; }
int64_t GetBlockTime() const { return int64_t(nTime); }
int64_t GetBlockTimeMax() const { return int64_t(nTimeMax); }
int64_t GetHeaderReceivedTime() const { return nTimeReceived; }
int64_t GetReceivedTimeDiff() const {
return GetHeaderReceivedTime() - GetBlockTime();
}
static constexpr int nMedianTimeSpan = 11;
int64_t GetMedianTimePast() const {
int64_t pmedian[nMedianTimeSpan];
int64_t *pbegin = &pmedian[nMedianTimeSpan];
int64_t *pend = &pmedian[nMedianTimeSpan];
const CBlockIndex *pindex = this;
for (int i = 0; i < nMedianTimeSpan && pindex;
i++, pindex = pindex->pprev) {
*(--pbegin) = pindex->GetBlockTime();
}
std::sort(pbegin, pend);
return pbegin[(pend - pbegin) / 2];
}
std::string ToString() const {
return strprintf(
"CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", pprev,
nHeight, hashMerkleRoot.ToString(), GetBlockHash().ToString());
}
//! Check whether this block index entry is valid up to the passed validity
//! level.
bool IsValid(enum BlockValidity nUpTo = BlockValidity::TRANSACTIONS) const {
return nStatus.isValid(nUpTo);
}
//! Raise the validity level of this block index entry.
//! Returns true if the validity was changed.
bool RaiseValidity(enum BlockValidity nUpTo) {
// Only validity flags allowed.
if (nStatus.isInvalid()) {
return false;
}
if (nStatus.getValidity() >= nUpTo) {
return false;
}
nStatus = nStatus.withValidity(nUpTo);
return true;
}
//! Build the skiplist pointer for this entry.
void BuildSkip();
//! Efficiently find an ancestor of this block.
CBlockIndex *GetAncestor(int height);
const CBlockIndex *GetAncestor(int height) const;
};
/**
* Maintain a map of CBlockIndex for all known headers.
*/
struct BlockHasher {
size_t operator()(const uint256 &hash) const { return hash.GetCheapHash(); }
};
typedef std::unordered_map<uint256, CBlockIndex *, BlockHasher> BlockMap;
extern BlockMap &mapBlockIndex;
extern CCriticalSection cs_main;
inline CBlockIndex *LookupBlockIndex(const uint256 &hash) {
AssertLockHeld(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
return it == mapBlockIndex.end() ? nullptr : it->second;
}
arith_uint256 GetBlockProof(const CBlockIndex &block);
/**
* Return the time it would take to redo the work difference between from and
* to, assuming the current hashrate corresponds to the difficulty at tip, in
* seconds.
*/
int64_t GetBlockProofEquivalentTime(const CBlockIndex &to,
const CBlockIndex &from,
const CBlockIndex &tip,
const Consensus::Params &);
/**
* Find the forking point between two chain tips.
*/
const CBlockIndex *LastCommonAncestor(const CBlockIndex *pa,
const CBlockIndex *pb);
/**
* Check if two block index are on the same fork.
*/
bool AreOnTheSameFork(const CBlockIndex *pa, const CBlockIndex *pb);
/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex {
public:
uint256 hashPrev;
CDiskBlockIndex() { hashPrev = uint256(); }
explicit CDiskBlockIndex(const CBlockIndex *pindex) : CBlockIndex(*pindex) {
hashPrev = (pprev ? pprev->GetBlockHash() : uint256());
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
int _nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(VARINT(_nVersion));
}
READWRITE(VARINT(nHeight));
READWRITE(nStatus);
READWRITE(VARINT(nTx));
if (nStatus.hasData() || nStatus.hasUndo()) {
READWRITE(VARINT(nFile));
}
if (nStatus.hasData()) {
READWRITE(VARINT(nDataPos));
}
if (nStatus.hasUndo()) {
READWRITE(VARINT(nUndoPos));
}
// block header
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
}
uint256 GetBlockHash() const {
CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block.GetHash();
}
std::string ToString() const {
std::string str = "CDiskBlockIndex(";
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
GetBlockHash().ToString(), hashPrev.ToString());
return str;
}
};
/**
* An in-memory indexed chain of blocks.
*/
class CChain {
private:
std::vector<CBlockIndex *> vChain;
public:
/**
* Returns the index entry for the genesis block of this chain, or nullptr
* if none.
*/
CBlockIndex *Genesis() const {
return vChain.size() > 0 ? vChain[0] : nullptr;
}
/**
* Returns the index entry for the tip of this chain, or nullptr if none.
*/
CBlockIndex *Tip() const {
return vChain.size() > 0 ? vChain[vChain.size() - 1] : nullptr;
}
/**
* Returns the index entry at a particular height in this chain, or nullptr
* if no such height exists.
*/
CBlockIndex *operator[](int nHeight) const {
if (nHeight < 0 || nHeight >= (int)vChain.size()) {
return nullptr;
}
return vChain[nHeight];
}
/** Compare two chains efficiently. */
friend bool operator==(const CChain &a, const CChain &b) {
return a.vChain.size() == b.vChain.size() &&
a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1];
}
/** Efficiently check whether a block is present in this chain. */
bool Contains(const CBlockIndex *pindex) const {
return (*this)[pindex->nHeight] == pindex;
}
/**
* Find the successor of a block in this chain, or nullptr if the given
* index is not found or is the tip.
*/
CBlockIndex *Next(const CBlockIndex *pindex) const {
if (!Contains(pindex)) {
return nullptr;
}
return (*this)[pindex->nHeight + 1];
}
/**
* Return the maximal height in the chain. Is equal to chain.Tip() ?
* chain.Tip()->nHeight : -1.
*/
int Height() const { return vChain.size() - 1; }
/** Set/initialize a chain with a given tip. */
void SetTip(CBlockIndex *pindex);
/**
* Return a CBlockLocator that refers to a block in this chain (by default
* the tip).
*/
CBlockLocator GetLocator(const CBlockIndex *pindex = nullptr) const;
/**
* Find the last common block between this chain and a block index entry.
*/
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
/**
* Find the earliest block with timestamp equal or greater than the given.
*/
CBlockIndex *FindEarliestAtLeast(int64_t nTime) const;
};
#endif // BITCOIN_CHAIN_H
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 4c4c08865d..a9068ba531 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -1,207 +1,208 @@
// Copyright (c) 2011-2016 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 <test/test_bitcoin.h>
#include <chain.h>
#include <chainparams.h>
#include <config.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
#include <fs.h>
#include <key.h>
#include <logging.h>
#include <miner.h>
#include <net_processing.h>
#include <noui.h>
+#include <pow.h>
#include <pubkey.h>
#include <random.h>
#include <rpc/register.h>
#include <rpc/server.h>
#include <script/scriptcache.h>
#include <script/sigcache.h>
#include <txdb.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <validation.h>
#include <memory>
FastRandomContext g_insecure_rand_ctx;
std::ostream &operator<<(std::ostream &os, const uint256 &num) {
os << num.ToString();
return os;
}
BasicTestingSetup::BasicTestingSetup(const std::string &chainName)
: m_path_root(fs::temp_directory_path() / "test_bitcoin" /
strprintf("%lu_%i", static_cast<unsigned long>(GetTime()),
int(InsecureRandRange(1 << 30)))) {
SHA256AutoDetect();
RandomInit();
ECC_Start();
SetupEnvironment();
SetupNetworking();
InitSignatureCache();
InitScriptExecutionCache();
// Don't want to write to debug.log file.
GetLogger().m_print_to_file = false;
fCheckBlockIndex = true;
SelectParams(chainName);
noui_connect();
}
BasicTestingSetup::~BasicTestingSetup() {
fs::remove_all(m_path_root);
ECC_Stop();
}
fs::path BasicTestingSetup::SetDataDir(const std::string &name) {
fs::path ret = m_path_root / name;
fs::create_directories(ret);
gArgs.ForceSetArg("-datadir", ret.string());
return ret;
}
TestingSetup::TestingSetup(const std::string &chainName)
: BasicTestingSetup(chainName) {
SetDataDir("tempdir");
const Config &config = GetConfig();
const CChainParams &chainparams = config.GetChainParams();
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
RPCServer rpcServer;
RegisterAllRPCCommands(config, rpcServer, tableRPC);
/**
* RPC does not come out of the warmup state on its own. Normally, this is
* handled in bitcoind's init path, but unit tests do not trigger this
* codepath, so we call it explicitly as part of setup.
*/
std::string rpcWarmupStatus;
if (RPCIsInWarmup(&rpcWarmupStatus)) {
SetRPCWarmupFinished();
}
ClearDatadirCache();
// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
threadGroup.create_thread(
boost::bind(&CScheduler::serviceQueue, &scheduler));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
g_mempool.setSanityCheck(1.0);
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}
{
CValidationState state;
if (!ActivateBestChain(config, state)) {
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)",
FormatStateMessage(state)));
}
}
nScriptCheckThreads = 3;
for (int i = 0; i < nScriptCheckThreads - 1; i++) {
threadGroup.create_thread(&ThreadScriptCheck);
}
// Deterministic randomness for tests.
g_connman = std::make_unique<CConnman>(config, 0x1337, 0x1337);
}
TestingSetup::~TestingSetup() {
threadGroup.interrupt_all();
threadGroup.join_all();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
g_connman.reset();
UnloadBlockIndex();
pcoinsTip.reset();
pcoinsdbview.reset();
pblocktree.reset();
}
TestChain100Setup::TestChain100Setup()
: TestingSetup(CBaseChainParams::REGTEST) {
// Generate a 100-block chain:
coinbaseKey.MakeNewKey(true);
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey())
<< OP_CHECKSIG;
for (int i = 0; i < COINBASE_MATURITY; i++) {
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
m_coinbase_txns.push_back(b.vtx[0]);
}
}
//
// Create a new block with just given transactions, coinbase paying to
// scriptPubKey, and try to add it to the current chain.
//
CBlock TestChain100Setup::CreateAndProcessBlock(
const std::vector<CMutableTransaction> &txns, const CScript &scriptPubKey) {
const Config &config = GetConfig();
std::unique_ptr<CBlockTemplate> pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
CBlock &block = pblocktemplate->block;
// Replace mempool-selected txns with just coinbase plus passed-in txns:
block.vtx.resize(1);
for (const CMutableTransaction &tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
}
// Order transactions by canonical order
std::sort(std::begin(block.vtx) + 1, std::end(block.vtx),
[](const std::shared_ptr<const CTransaction> &txa,
const std::shared_ptr<const CTransaction> &txb) -> bool {
return txa->GetId() < txb->GetId();
});
// IncrementExtraNonce creates a valid coinbase and merkleRoot
{
LOCK(cs_main);
unsigned int extraNonce = 0;
IncrementExtraNonce(config, &block, chainActive.Tip(), extraNonce);
}
const Consensus::Params ¶ms = config.GetChainParams().GetConsensus();
while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
++block.nNonce;
}
std::shared_ptr<const CBlock> shared_pblock =
std::make_shared<const CBlock>(block);
ProcessNewBlock(config, shared_pblock, true, nullptr);
CBlock result = block;
return result;
}
TestChain100Setup::~TestChain100Setup() {}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx,
CTxMemPool *pool) {
return FromTx(MakeTransactionRef(tx), pool);
}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef &tx,
CTxMemPool *pool) {
// Hack to assume either it's completely dependent on other mempool txs or
// not at all.
Amount inChainValue =
pool && pool->HasNoInputsOf(*tx) ? tx->GetValueOut() : Amount::zero();
return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight, inChainValue,
spendsCoinbase, sigOpCost, lp);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, May 13, 01:47 (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5777067
Default Alt Text
(19 KB)
Attached To
rSTAGING Bitcoin ABC staging
Event Timeline
Log In to Comment