diff options
author | Gregory Maxwell <greg@xiph.org> | 2017-06-17 00:18:42 +0000 |
---|---|---|
committer | Gregory Maxwell <greg@xiph.org> | 2017-07-14 19:24:17 +0000 |
commit | 3babbcb48786372d4b22171674c4cc5a6220c294 (patch) | |
tree | 099fab1403b69a6da62d222fbf8b2d45f0c12fa7 | |
parent | e4fcbf797ed3b472d352ac3794ec82f581209c50 (diff) |
Remove confusing MAX_BLOCK_BASE_SIZE.
Some people keep thinking that MAX_BLOCK_BASE_SIZE is a separate
size limit from the weight limit when it fact it is superfluous,
and used in early tests before the witness data has been
validated or just to compute worst case sizes. The size checks
that use it would not behave any differently consensus wise
if they were eliminated completely.
Its correct value is not independently settable but is a function
of the weight limit and weight formula.
This patch just eliminates it and uses the scale factor as
required to compute the worse case constants.
It also moves the weight factor out of primitives into consensus,
which is a more logical place for it.
-rw-r--r-- | src/bitcoin-tx.cpp | 2 | ||||
-rw-r--r-- | src/blockencodings.cpp | 4 | ||||
-rw-r--r-- | src/coins.cpp | 3 | ||||
-rw-r--r-- | src/consensus/consensus.h | 14 | ||||
-rw-r--r-- | src/consensus/tx_verify.cpp | 2 | ||||
-rw-r--r-- | src/consensus/validation.h | 18 | ||||
-rw-r--r-- | src/core_write.cpp | 4 | ||||
-rw-r--r-- | src/merkleblock.cpp | 2 | ||||
-rw-r--r-- | src/policy/policy.cpp | 1 | ||||
-rw-r--r-- | src/primitives/block.cpp | 9 | ||||
-rw-r--r-- | src/primitives/block.h | 3 | ||||
-rw-r--r-- | src/primitives/transaction.cpp | 5 | ||||
-rw-r--r-- | src/primitives/transaction.h | 6 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 9 | ||||
-rw-r--r-- | src/test/sigopcount_tests.cpp | 1 | ||||
-rw-r--r-- | src/undo.h | 3 | ||||
-rw-r--r-- | src/validation.cpp | 2 |
17 files changed, 43 insertions, 45 deletions
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index c6d5db786e..9acb3fd30e 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 9cac10d2b8..7adab586e8 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -15,8 +15,6 @@ #include <unordered_map> -#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<uint64_t>::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<std::pair<uint256, CTransactionRef>>& 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 b5dc6197bd..e30bda930a 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 58b2ed4b3e..a1bb99a802 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 <stdlib.h> #include <stdint.h> /** 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 0671cbc132..0a71915d1d 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 8fc3ef1b66..5494ce40ea 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -7,6 +7,10 @@ #define BITCOIN_CONSENSUS_VALIDATION_H #include <string> +#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 7f38e9e565..a366ef933c 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 78d7cd6001..ba5f7b400c 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -153,7 +153,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &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 2f78d2f347..9f2d623e76 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 9a979094cc..24be67c84f 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 f03cf48504..c90a1dfa64 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 a0d7793f97..f87934d586 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 00ac0b92b5..f1dd51b9fd 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 <stdint.h> #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<const CTransaction> CTransactionRef; static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); } template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(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 046c85a76e..10bb341e54 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 eddb80aed5..d3b8b07228 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 3749d5d7a8..0f9d041bbd 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 16d11529b0..c101497600 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 |