Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce CBlockchain and move CheckBlockHeader #8087

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Expand Up @@ -75,6 +75,7 @@ BITCOIN_CORE_H = \
addrman.h \
base58.h \
bloom.h \
blockchain.h \
chain.h \
chainparams.h \
chainparamsbase.h \
Expand Down Expand Up @@ -163,6 +164,7 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
bloom.cpp \
blockchain.cpp \
chain.cpp \
checkpoints.cpp \
httprpc.cpp \
Expand Down
109 changes: 109 additions & 0 deletions src/blockchain.cpp
@@ -0,0 +1,109 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 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 "addrman.h"
#include "arith_uint256.h"
#include "blockchain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "hash.h"
#include "init.h"
#include "merkleblock.h"
#include "net.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
#include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
#include "versionbits.h"

#include <sstream>

#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/math/distributions/poisson.hpp>
#include <boost/thread.hpp>

bool CBlockchain::CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) {
return CheckBlockHeader(Params(), block, state, GetAdjustedTime(), fCheckPOW);
}

bool CBlockchain::CheckBlockHeader(const CChainParams chainParams, const CBlockHeader& block, CValidationState& state, int64_t nAdjustedTime, bool fCheckPOW) {
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, chainParams.GetConsensus()))
return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");

// Check timestamp
if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");

return true;
}

bool CBlockchain::CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");

// Check for negative or overflow output values
CAmount nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
if (txout.nValue < 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}

// Check for duplicate inputs
std::set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (vInOutPoints.count(txin.prevout))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout);
}

if (tx.IsCoinBase())
{
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
}
else
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
}

return true;
}
22 changes: 22 additions & 0 deletions src/blockchain.h
@@ -0,0 +1,22 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 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_BLOCKCHAIN_H
#define BITCOIN_BLOCKCHAIN_H

#include "chainparams.h"
#include "consensus/validation.h"
#include "primitives/block.h"

class CBlockchain {
protected:
static bool CheckBlockHeader(const CChainParams chainParams, const CBlockHeader& block, CValidationState& state, int64_t nAdjustedTime, bool fCheckPOW = true);
public:
/** Context-independent validity checks */
static bool CheckTransaction(const CTransaction& tx, CValidationState& state);
static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
};

#endif // BITCOIN_BLOCKCHAIN_H
70 changes: 5 additions & 65 deletions src/main.cpp
Expand Up @@ -7,6 +7,7 @@

#include "addrman.h"
#include "arith_uint256.h"
#include "blockchain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
Expand Down Expand Up @@ -936,54 +937,6 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in



bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");

// Check for negative or overflow output values
CAmount nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
if (txout.nValue < 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}

// Check for duplicate inputs
set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (vInOutPoints.count(txin.prevout))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout);
}

if (tx.IsCoinBase())
{
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
}
else
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
}

return true;
}

void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
int expired = pool.Expire(GetTime() - age);
if (expired != 0)
Expand Down Expand Up @@ -1013,7 +966,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (pfMissingInputs)
*pfMissingInputs = false;

if (!CheckTransaction(tx, state))
if (!CBlockchain::CheckTransaction(tx, state))
return false; // state filled in by CheckTransaction

// Coinbase is only valid in a block, not as a loose transaction
Expand Down Expand Up @@ -3234,19 +3187,6 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
return true;
}

bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
{
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))
return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");

// Check timestamp
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");

return true;
}

bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
{
// These are checks that are independent of context.
Expand All @@ -3256,7 +3196,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo

// Check that the header is valid (particularly PoW). This is mostly
// redundant with the call in AcceptBlockHeader.
if (!CheckBlockHeader(block, state, fCheckPOW))
if (!CBlockchain::CheckBlockHeader(block, state, fCheckPOW))
return false;

// Check the merkle root.
Expand Down Expand Up @@ -3290,7 +3230,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo

// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state))
if (!CBlockchain::CheckTransaction(tx, state))
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage()));

Expand Down Expand Up @@ -3397,7 +3337,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
return true;
}

if (!CheckBlockHeader(block, state))
if (!CBlockchain::CheckBlockHeader(block, state))
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));

// Get prev block index
Expand Down
4 changes: 0 additions & 4 deletions src/main.h
Expand Up @@ -340,9 +340,6 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);

/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);

/**
* Check if transaction is final and can be included in a block with the
* specified height and time. Consensus critical.
Expand Down Expand Up @@ -425,7 +422,6 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
/** Functions for validating blocks and updating the block tree */

/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);

/** Context-dependent validity checks.
Expand Down
4 changes: 2 additions & 2 deletions src/test/sighash_tests.cpp
Expand Up @@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "blockchain.h"
#include "consensus/validation.h"
#include "data/sighash.json.h"
#include "hash.h"
#include "main.h" // For CheckTransaction
#include "random.h"
#include "script/interpreter.h"
#include "script/script.h"
Expand Down Expand Up @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
stream >> tx;

CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK_MESSAGE(CBlockchain::CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());

std::vector<unsigned char> raw = ParseHex(raw_script);
Expand Down
11 changes: 6 additions & 5 deletions src/test/transaction_tests.cpp
Expand Up @@ -6,12 +6,13 @@
#include "data/tx_valid.json.h"
#include "test/test_bitcoin.h"

#include "blockchain.h"
#include "clientversion.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
#include "main.h" // For CheckTransaction
#include "main.h" // For cs_main, minRelayTxFee, and DEFAULT_MIN_RELAY_TX_FEE
#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
Expand Down Expand Up @@ -138,7 +139,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx;

CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK_MESSAGE(CBlockchain::CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());

for (unsigned int i = 0; i < tx.vin.size(); i++)
Expand Down Expand Up @@ -213,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx;

CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
fValid = CBlockchain::CheckTransaction(tx, state) && state.IsValid();

for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
Expand Down Expand Up @@ -242,11 +243,11 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CMutableTransaction tx;
stream >> tx;
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
BOOST_CHECK_MESSAGE(CBlockchain::CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");

// Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]);
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
BOOST_CHECK_MESSAGE(!CBlockchain::CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
}

//
Expand Down
4 changes: 2 additions & 2 deletions src/wallet/walletdb.cpp
Expand Up @@ -6,8 +6,8 @@
#include "wallet/walletdb.h"

#include "base58.h"
#include "blockchain.h"
#include "consensus/validation.h"
#include "main.h" // For CheckTransaction
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
Expand Down Expand Up @@ -374,7 +374,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx;
ssValue >> wtx;
CValidationState state;
if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
if (!(CBlockchain::CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
return false;

// Undo serialize changes in 31600
Expand Down