diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index c6d5db786..9acb3fd30 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -239,7 +239,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu uint256 txid(uint256S(strTxid)); static const unsigned int minTxOutSz = 9; - static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz; + static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz); // extract and validate vout std::string strVout = vStrInputParts[1]; diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 9cac10d2b..7adab586e 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -15,8 +15,6 @@ #include -#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)) - CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) : nonce(GetRand(std::numeric_limits::max())), shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) { @@ -50,7 +48,7 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const { ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn) { if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) return READ_STATUS_INVALID; - if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE) + if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZEABLE_TRANSACTION_WEIGHT) return READ_STATUS_INVALID; assert(header.IsNull() && txn_available.empty()); diff --git a/src/coins.cpp b/src/coins.cpp index b5dc6197b..e30bda930 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -245,7 +245,8 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const return true; } -static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h. +static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT; const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid) { diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 58b2ed4b3..a1bb99a80 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -6,25 +6,23 @@ #ifndef BITCOIN_CONSENSUS_CONSENSUS_H #define BITCOIN_CONSENSUS_CONSENSUS_H +#include #include /** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000; /** The maximum allowed weight for a block, see BIP 141 (network rule) */ static const unsigned int MAX_BLOCK_WEIGHT = 4000000; -/** - * The maximum allowed size for a block excluding witness data, in bytes (network rule). - * This parameter is largely superfluous because it is directly implied by the above block - * weight limit, even when BIP 141 is not active. It continues to exist for use in - * various early tests that run before the witness data has been checked. - * All tests related to it could be removed without breaking consensus compatibility. - */ -static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const int64_t MAX_BLOCK_SIGOPS_COST = 80000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +static const int WITNESS_SCALE_FACTOR = 4; + +static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is the lower bound for the size of a valid serialized CTransaction +static const size_t MIN_SERIALIZEABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction + /** Flags for nSequence and nLockTime locks */ enum { /* Interpret sequence numbers as relative lock-time constraints. */ diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 0671cbc13..0a71915d1 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -164,7 +164,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe if (tx.vout.empty()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability) - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE) + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 8fc3ef1b6..5494ce40e 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -7,6 +7,10 @@ #define BITCOIN_CONSENSUS_VALIDATION_H #include +#include "version.h" +#include "consensus/consensus.h" +#include "primitives/transaction.h" +#include "primitives/block.h" /** "reject" message codes */ static const unsigned char REJECT_MALFORMED = 0x01; @@ -85,4 +89,18 @@ public: std::string GetDebugMessage() const { return strDebugMessage; } }; +static inline int64_t GetTransactionWeight(const CTransaction& tx) +{ + return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); +} + +static inline int64_t GetBlockWeight(const CBlock& block) +{ + // This implements the weight = (stripped_size * 4) + witness_size formula, + // using only serialization with and without witness data. As witness_size + // is equal to total_size - stripped_size, this formula is identical to: + // weight = (stripped_size * 3) + total_size. + return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); +} + #endif // BITCOIN_CONSENSUS_VALIDATION_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 7f38e9e56..a366ef933 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -5,7 +5,8 @@ #include "core_io.h" #include "base58.h" -#include "primitives/transaction.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" #include "script/script.h" #include "script/standard.h" #include "serialize.h" @@ -15,7 +16,6 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" - std::string FormatScript(const CScript& script) { std::string ret; diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index 78d7cd600..ba5f7b400 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -153,7 +153,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector &vMatch, std::ve if (nTransactions == 0) return uint256(); // check for excessively high numbers of transactions - if (nTransactions > MAX_BLOCK_BASE_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction + if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT) return uint256(); // there can never be more hashes provided than one for every txid if (vHash.size() > nTransactions) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 2f78d2f34..9f2d623e7 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -7,6 +7,7 @@ #include "policy/policy.h" +#include "consensus/validation.h" #include "validation.h" #include "coins.h" #include "tinyformat.h" diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 9a979094c..24be67c84 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -31,12 +31,3 @@ std::string CBlock::ToString() const } return s.str(); } - -int64_t GetBlockWeight(const CBlock& block) -{ - // This implements the weight = (stripped_size * 4) + witness_size formula, - // using only serialization with and without witness data. As witness_size - // is equal to total_size - stripped_size, this formula is identical to: - // weight = (stripped_size * 3) + total_size. - return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); -} diff --git a/src/primitives/block.h b/src/primitives/block.h index f03cf4850..c90a1dfa6 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -152,7 +152,4 @@ struct CBlockLocator } }; -/** Compute the consensus-critical block weight (see BIP 141). */ -int64_t GetBlockWeight(const CBlock& tx); - #endif // BITCOIN_PRIMITIVES_BLOCK_H diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index a0d7793f9..f87934d58 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -114,8 +114,3 @@ std::string CTransaction::ToString() const str += " " + vout[i].ToString() + "\n"; return str; } - -int64_t GetTransactionWeight(const CTransaction& tx) -{ - return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); -} diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 00ac0b92b..f1dd51b9f 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_PRIMITIVES_TRANSACTION_H #define BITCOIN_PRIMITIVES_TRANSACTION_H +#include #include "amount.h" #include "script/script.h" #include "serialize.h" @@ -13,8 +14,6 @@ static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000; -static const int WITNESS_SCALE_FACTOR = 4; - /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { @@ -411,7 +410,4 @@ typedef std::shared_ptr CTransactionRef; static inline CTransactionRef MakeTransactionRef() { return std::make_shared(); } template static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared(std::forward(txIn)); } -/** Compute the weight of a transaction, as defined by BIP 141 */ -int64_t GetTransactionWeight(const CTransaction &tx); - #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 046c85a76..10bb341e5 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -645,15 +645,16 @@ UniValue getblocktemplate(const JSONRPCRequest& request) result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; + int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE; if (fPreSegWit) { assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); nSigOpLimit /= WITNESS_SCALE_FACTOR; + assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0); + nSizeLimit /= WITNESS_SCALE_FACTOR; } result.push_back(Pair("sigoplimit", nSigOpLimit)); - if (fPreSegWit) { - result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_BASE_SIZE)); - } else { - result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE)); + result.push_back(Pair("sizelimit", nSizeLimit)); + if (!fPreSegWit) { result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); } result.push_back(Pair("curtime", pblock->GetBlockTime())); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index eddb80aed..d3b8b0722 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "consensus/tx_verify.h" +#include "consensus/validation.h" #include "pubkey.h" #include "key.h" #include "script/script.h" diff --git a/src/undo.h b/src/undo.h index 3749d5d7a..0f9d041bb 100644 --- a/src/undo.h +++ b/src/undo.h @@ -60,7 +60,8 @@ public: TxInUndoDeserializer(Coin* coin) : txout(coin) {} }; -static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_INPUT_WEIGHT; /** Undo information for a CTransaction */ class CTxUndo diff --git a/src/validation.cpp b/src/validation.cpp index 16d11529b..c10149760 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2803,7 +2803,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // checks that use witness data may be performed here. // Size limits - if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_BASE_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE) + if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); // First transaction must be coinbase, the rest must not be