2 changes: 1 addition & 1 deletion src/bitcoin-tx.cpp
Expand Up @@ -218,7 +218,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_STRIPPED_TRANSACTION_SIZE / minTxOutSz;

// extract and validate vout
std::string strVout = vStrInputParts[1];
Expand Down
2 changes: 1 addition & 1 deletion src/blockencodings.cpp
Expand Up @@ -50,7 +50,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_POSSIBLE_BLOCK_SIZE / MIN_TRANSACTION_BASE_SIZE)
return READ_STATUS_INVALID;

assert(header.IsNull() && txn_available.empty());
Expand Down
12 changes: 8 additions & 4 deletions src/consensus/consensus.h
Expand Up @@ -8,14 +8,18 @@

#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 size for a serialized block under BIP 141 rules, in bytes */
static const unsigned int MAX_BIP141_BLOCK_SIZE = 4000000;
/** The maximum possible size for a serialized block, in bytes (only for buffer size limits) */
static const unsigned int MAX_POSSIBLE_BLOCK_SIZE = 30921408;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
static const unsigned int MAX_BIP141_BLOCK_WEIGHT = 4000000;
/** The maximum allowed size for a block excluding witness data, in bytes (network rule) */
static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000;
static const unsigned int MAX_BIP141_STRIPPED_BLOCK_SIZE = 1000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
/** The maximum allowed size for a transaction excluding witness data, in bytes (network rule) */
static const unsigned int MAX_STRIPPED_TRANSACTION_SIZE = 1000000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;

Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Expand Up @@ -17,6 +17,7 @@ enum DeploymentPos
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
DEPLOYMENT_BLKSIZE,
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
2 changes: 1 addition & 1 deletion src/merkleblock.cpp
Expand Up @@ -155,7 +155,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_POSSIBLE_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
return uint256();
// there can never be more hashes provided than one for every txid
if (vHash.size() > nTransactions)
Expand Down
15 changes: 8 additions & 7 deletions src/miner.cpp
Expand Up @@ -86,7 +86,7 @@ BlockAssembler::BlockAssembler(const CChainParams& _chainparams)
bool fWeightSet = false;
if (IsArgSet("-blockmaxweight")) {
nBlockMaxWeight = GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
nBlockMaxSize = MAX_POSSIBLE_BLOCK_SIZE;
fWeightSet = true;
}
if (IsArgSet("-blockmaxsize")) {
Expand All @@ -103,12 +103,13 @@ BlockAssembler::BlockAssembler(const CChainParams& _chainparams)
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
}

// Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_WEIGHT-4000), nBlockMaxWeight));
// Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize));
// FIXME: Adjust these if DEPLOYMENT_BLKSIZE is active
// Limit weight to between 4K and MAX_BIP141_BLOCK_WEIGHT-4K for sanity:
nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BIP141_BLOCK_WEIGHT-4000), nBlockMaxWeight));
// Limit size to between 1K and MAX_BIP141_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BIP141_BLOCK_SIZE-1000), nBlockMaxSize));
// Whether we need to account for byte usage (in addition to weight usage)
fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000);
fNeedSizeAccounting = (nBlockMaxSize < nBlockMaxWeight * 4);
}

void BlockAssembler::resetBlock()
Expand Down Expand Up @@ -189,7 +190,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxFees[0] = -nFees;

uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock, SERIALIZE_TRANSACTION_NO_WITNESS /* FIXME */), nBlockTx, nFees, nBlockSigOpsCost);

// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
Expand Down
2 changes: 1 addition & 1 deletion src/net.cpp
Expand Up @@ -2496,7 +2496,7 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)
{
// keep a large enough buffer to at least relay each block once
uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_SIZE;
uint64_t buffer = timeLeftInCycle / 600 * MAX_POSSIBLE_BLOCK_SIZE;
if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions src/primitives/block.cpp
Expand Up @@ -32,11 +32,11 @@ std::string CBlock::ToString() const
return s.str();
}

int64_t GetBlockWeight(const CBlock& block)
int64_t GetBlockWeight(const CBlock& block, int nWitnessVersionFlags)
{
// 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);
return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | nWitnessVersionFlags) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
}
4 changes: 2 additions & 2 deletions src/primitives/block.h
Expand Up @@ -155,7 +155,7 @@ struct CBlockLocator
}
};

/** Compute the consensus-critical block weight (see BIP 141). */
int64_t GetBlockWeight(const CBlock& tx);
/** Compute the consensus-critical block weight. */
int64_t GetBlockWeight(const CBlock& tx, int nWitnessVersionFlags);

#endif // BITCOIN_PRIMITIVES_BLOCK_H
9 changes: 8 additions & 1 deletion src/primitives/transaction.h
Expand Up @@ -12,6 +12,7 @@
#include "uint256.h"

static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
static const int SERIALIZE_TRANSACTION_NO_SIGS = 0x60000000; /* includes SERIALIZE_TRANSACTION_NO_WITNESS */

static const int WITNESS_SCALE_FACTOR = 4;

Expand Down Expand Up @@ -107,7 +108,13 @@ class CTxIn
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
READWRITE(*(CScriptBase*)(&scriptSig));
if ((s.GetVersion() & SERIALIZE_TRANSACTION_NO_SIGS) == SERIALIZE_TRANSACTION_NO_SIGS) {
assert(!ser_action.ForRead());
CScriptBase dummy;
READWRITE(dummy);
} else {
READWRITE(*(CScriptBase*)(&scriptSig));
}
READWRITE(nSequence);
}

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/blockchain.cpp
Expand Up @@ -113,7 +113,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("weight", (int)::GetBlockWeight(block)));
result.push_back(Pair("weight", (int)::GetBlockWeight(block, SERIALIZE_TRANSACTION_NO_WITNESS /* FIXME */)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
Expand Down
5 changes: 3 additions & 2 deletions src/rpc/mining.cpp
Expand Up @@ -676,8 +676,9 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
nSigOpLimit /= WITNESS_SCALE_FACTOR;
}
result.push_back(Pair("sigoplimit", nSigOpLimit));
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
// FIXME: Adjust these if DEPLOYMENT_BLKSIZE is active
result.push_back(Pair("sizelimit", (int64_t)MAX_BIP141_BLOCK_SIZE));
result.push_back(Pair("weightlimit", (int64_t)MAX_BIP141_BLOCK_WEIGHT));
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
Expand Down
62 changes: 56 additions & 6 deletions src/validation.cpp
Expand Up @@ -466,7 +466,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) > MAX_STRIPPED_TRANSACTION_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");

// Check for negative or overflow output values
Expand Down Expand Up @@ -1667,6 +1667,39 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
return nVersion;
}

uint32_t GetMaxStrippedBlockSize(const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams, int64_t nMedianTimePast) {
if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_BLKSIZE, versionbitscache) != THRESHOLD_ACTIVE) {
return MAX_BIP141_STRIPPED_BLOCK_SIZE;
}

// In case we activate early on regtest.
if (nMedianTimePast < 1483246800) {
return 300000;
}
// The first step is on January 1st 2017.
// After that, one step happens every 2^23 seconds.
int64_t step = (nMedianTimePast - 1483246800) >> 23;
// Don't do more than 107 steps, to stay under 32 MB.
step = std::min<int64_t>(step, 107);
// Every step is a 2^(1/16) factor.
static const uint32_t bases[16] = {
// bases[i] == round(300000 * pow(2.0, i / 16.0))
300000, 313282, 327152, 341637,
356762, 372557, 389052, 406277,
424264, 443048, 462663, 483147,
504538, 526876, 550202, 574562
};
return bases[step & 15] << (step / 16);
}

uint32_t GetMaxBlockSize(const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams, int64_t nMedianTimePast) {
if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_BLKSIZE, versionbitscache) != THRESHOLD_ACTIVE && VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) {
return MAX_BIP141_BLOCK_SIZE;
} else {
return GetMaxStrippedBlockSize(pindexPrev, consensusParams, nMedianTimePast);
}
}

/**
* Threshold condition checker that triggers when unknown versionbits are seen on the network.
*/
Expand Down Expand Up @@ -2822,7 +2855,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() > MAX_POSSIBLE_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_POSSIBLE_BLOCK_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");

// First transaction must be coinbase, the rest must not be
Expand Down Expand Up @@ -2955,6 +2988,12 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();

// Size limits
const uint32_t maxStrippedBlockSize = GetMaxStrippedBlockSize(pindexPrev, consensusParams, nMedianTimePast);
if (::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > maxStrippedBlockSize)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");

// Start enforcing BIP113 (Median Time Past) using versionbits logic.
int nLockTimeFlags = 0;
Expand Down Expand Up @@ -3026,8 +3065,19 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
// large by filling up the coinbase witness, which doesn't change
// the block hash, so we couldn't mark the block as permanently
// failed).
if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__));
if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_BLKSIZE, versionbitscache) == THRESHOLD_ACTIVE) {
const uint32_t maxBlockSize = GetMaxBlockSize(pindexPrev, consensusParams, nMedianTimePast);
if (::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > maxBlockSize) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
}
const int64_t nMaxBlockWeight = maxBlockSize * 2;
if (GetBlockWeight(block, SERIALIZE_TRANSACTION_NO_SIGS) > nMaxBlockWeight) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__));
}
} else {
if (GetBlockWeight(block, SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BIP141_BLOCK_WEIGHT) {
return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__));
}
}

return true;
Expand Down Expand Up @@ -3815,7 +3865,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
int nLoaded = 0;
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE+8, SER_DISK, CLIENT_VERSION);
CBufferedFile blkdat(fileIn, 2*MAX_POSSIBLE_BLOCK_SIZE, MAX_POSSIBLE_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
boost::this_thread::interruption_point();
Expand All @@ -3834,7 +3884,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
continue;
// read size
blkdat >> nSize;
if (nSize < 80 || nSize > MAX_BLOCK_SERIALIZED_SIZE)
if (nSize < 80 || nSize > MAX_POSSIBLE_BLOCK_SIZE)
continue;
} catch (const std::exception&) {
// no valid block header found; don't complain
Expand Down
3 changes: 3 additions & 0 deletions src/validation.h
Expand Up @@ -545,6 +545,9 @@ int GetSpendHeight(const CCoinsViewCache& inputs);

extern VersionBitsCache versionbitscache;

uint32_t GetMaxStrippedBlockSize(const CBlockIndex* pindexPrev, const Consensus::Params&, int64_t nMedianTimePast);
uint32_t GetMaxBlockSize(const CBlockIndex* pindexPrev, const Consensus::Params&, int64_t nMedianTimePast);

/**
* Determine what nVersion a new block should use.
*/
Expand Down
6 changes: 5 additions & 1 deletion src/versionbits.cpp
Expand Up @@ -18,7 +18,11 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
{
/*.name =*/ "segwit",
/*.gbt_force =*/ false,
}
},
{
/*.name =*/ "blksize",
/*.gbt_force =*/ true,
},
};

ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
Expand Down