2,002 changes: 2,002 additions & 0 deletions qa/rpc-tests/data/addresses.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/chainparams.cpp
Expand Up @@ -131,6 +131,8 @@ class CMainParams : public CChainParams {
nSizeDoubleEpoch = 60*60*24*365*2; // two years
nMaxSizeBase = 8*1000*1000; // 8MB
nMaxSizeDoublings = 10;
nActivateSizeForkMajority = 750; // 75% of hashpower to activate fork
nSizeForkGracePeriod = 60*60*24*14; // two week grace period after activation

/**
* Build the genesis block. Note that the output of the genesis coinbase cannot
Expand Down Expand Up @@ -222,6 +224,8 @@ class CTestNetParams : public CMainParams {
nSizeDoubleEpoch = 60*60*24*365*2; // two years
nMaxSizeBase = 8*1000*1000; // 8MB
nMaxSizeDoublings = 10;
nActivateSizeForkMajority = 75; // 75 of 100 to activate fork
nSizeForkGracePeriod = 60*60*24; // 1-day grace period

//! Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1296688602;
Expand Down
7 changes: 5 additions & 2 deletions src/chainparams.h
Expand Up @@ -82,14 +82,15 @@ class CChainParams
virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0;

/** Maximum block size of a block with timestamp nBlockTimestamp */
int ActivateSizeForkMajority() const { return nActivateSizeForkMajority; }
uint64_t SizeForkGracePeriod() const { return nSizeForkGracePeriod; }
uint64_t MaxBlockSize(uint64_t nBlockTimestamp) const {
if (nBlockTimestamp < nEarliestSizeForkTime || nBlockTimestamp < nSizeForkActivationTime)
return nMaxSizePreFork;
if (nBlockTimestamp >= nEarliestSizeForkTime + nSizeDoubleEpoch * nMaxSizeDoublings)
return nMaxSizeBase << nMaxSizeDoublings;

// Piecewise-linear-between-doublings approximation of the ideal
// exponential function:
// Piecewise-linear-between-doublings growth:
uint64_t timeDelta = nBlockTimestamp - nEarliestSizeForkTime;
uint64_t doublings = timeDelta / nSizeDoubleEpoch;
uint64_t remainder = timeDelta % nSizeDoubleEpoch;
Expand Down Expand Up @@ -132,6 +133,8 @@ class CChainParams
uint32_t nSizeDoubleEpoch;
uint64_t nMaxSizeBase;
uint8_t nMaxSizeDoublings;
int nActivateSizeForkMajority;
uint64_t nSizeForkGracePeriod;

int64_t nTargetTimespan;
int64_t nTargetSpacing;
Expand Down
48 changes: 42 additions & 6 deletions src/main.cpp
Expand Up @@ -74,10 +74,11 @@ void EraseOrphansFor(NodeId peer);
static bool SanityCheckMessage(CNode* peer, const CNetMessage& msg);

/**
* Returns true if there are nRequired or more blocks of minVersion or above
* in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards.
* Returns true if there are nRequired or more blocks with a version that matches
* versionBitMask in the last Consensus::Params::nMajorityWindow blocks,
* starting at pstart and going backwards.
*/
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired);
static bool IsSuperMajority(int versionBitmask, const CBlockIndex* pstart, unsigned nRequired);
static void CheckBlockIndex();

/** Constant stuff for coinbase transactions we create: */
Expand Down Expand Up @@ -1880,6 +1881,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001);

// See if this block triggered activation of the max block size fork:
if ((block.nVersion & SIZE_FORK_VERSION) &&
!pblocktree->ForkActivated(SIZE_FORK_VERSION) &&
CBlockIndex::IsSuperMajority(SIZE_FORK_VERSION, pindex, Params().ActivateSizeForkMajority())) {

uint64_t tActivate = block.nTime + Params().SizeForkGracePeriod();
LogPrintf("%s: Max block size fork activating at time %d\n", __func__, tActivate);
pblocktree->ActivateFork(SIZE_FORK_VERSION, pindex->GetBlockHash());
CChainParams::SetSizeForkActivationTime(tActivate);
}

return true;
}

Expand Down Expand Up @@ -2019,6 +2031,14 @@ bool static DisconnectTip(CValidationState &state) {
}
mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight);
mempool.check(pcoinsTip);

// Re-org past the size fork, reset activation condition:
if (pblocktree->ForkActivated(SIZE_FORK_VERSION) == pindexDelete->GetBlockHash()) {
LogPrintf("%s: re-org past size fork\n", __func__);
pblocktree->ActivateFork(SIZE_FORK_VERSION, uint256(0));
CChainParams::SetSizeForkActivationTime(std::numeric_limits<uint64_t>::max());
}

// Update chainActive and related variables.
UpdateTip(pindexDelete->pprev);
// Let wallets know transactions went from 1-confirmed to
Expand Down Expand Up @@ -2739,13 +2759,13 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return true;
}

bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired)
bool CBlockIndex::IsSuperMajority(int versionBitmask, const CBlockIndex* pstart, unsigned int nRequired)
{
unsigned int nToCheck = Params().ToCheckBlockUpgradeMajority();
unsigned int nFound = 0;
for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++)
{
if (pstart->nVersion >= minVersion)
if ( (pstart->nVersion & versionBitmask) == versionBitmask)
++nFound;
pstart = pstart->pprev;
}
Expand Down Expand Up @@ -2943,6 +2963,16 @@ bool static LoadBlockIndexDB()
if (!pblocktree->LoadBlockIndexGuts())
return false;

// If the max-block-size fork threshold was reached, update
// chainparams so big blocks are allowed:
uint256 sizeForkHash = pblocktree->ForkActivated(SIZE_FORK_VERSION);
if (sizeForkHash != uint256(0)) {
BlockMap::iterator it = mapBlockIndex.find(sizeForkHash);
assert(it != mapBlockIndex.end());
uint64_t tActivate = it->second->GetBlockTime()+ Params().SizeForkGracePeriod();
CChainParams::SetSizeForkActivationTime(tActivate);
}

boost::this_thread::interruption_point();

// Calculate nChainWork
Expand Down Expand Up @@ -3515,7 +3545,13 @@ static std::map<std::string, size_t> maxMessageSizes = boost::assign::map_list_o
bool static SanityCheckMessage(CNode* peer, const CNetMessage& msg)
{
const std::string& strCommand = msg.hdr.GetCommand();
if (msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ||
if (strCommand == "block") {
if (msg.hdr.nMessageSize > Params().MaxBlockSize(GetAdjustedTime() + 2 * 60 * 60)) {
LogPrint("net", "Oversized %s message from peer=%i\n", SanitizeString(strCommand), peer->GetId());
return false;
}
}
else if (msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ||
(maxMessageSizes.count(strCommand) && msg.hdr.nMessageSize > maxMessageSizes[strCommand])) {
LogPrint("net", "Oversized %s message from peer=%i\n", SanitizeString(strCommand), peer->GetId());
return false;
Expand Down
5 changes: 4 additions & 1 deletion src/primitives/block.h
Expand Up @@ -10,6 +10,9 @@
#include "serialize.h"
#include "uint256.h"

/** Blocks with this version activate the bigger-block fork */
const unsigned int SIZE_FORK_VERSION = 0x20000004;

/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
Expand All @@ -21,7 +24,7 @@ class CBlockHeader
{
public:
// header
static const int32_t CURRENT_VERSION=3;
static const int32_t CURRENT_VERSION=SIZE_FORK_VERSION;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
Expand Down
6 changes: 4 additions & 2 deletions src/test/ReceiveMsgBytes_tests.cpp
Expand Up @@ -11,6 +11,7 @@
#include "net.h"
#include "pow.h"
#include "serialize.h"
#include "timedata.h"
#include "util.h"

#include <boost/test/unit_test.hpp>
Expand Down Expand Up @@ -76,15 +77,16 @@ BOOST_AUTO_TEST_CASE(TooLargeBlock)
s << block;

// Test: too large
s.resize(MAX_PROTOCOL_MESSAGE_LENGTH+headerLen+1);
size_t maxBlockSize = Params().MaxBlockSize(GetAdjustedTime());
s.resize(maxBlockSize+headerLen+1);
CNetMessage::FinalizeHeader(s);

BOOST_CHECK(!testNode.ReceiveMsgBytes(&s[0], s.size()));

testNode.vRecvMsg.clear();

// Test: exactly at max:
s.resize(MAX_PROTOCOL_MESSAGE_LENGTH+headerLen);
s.resize(maxBlockSize+headerLen);
CNetMessage::FinalizeHeader(s);

BOOST_CHECK(testNode.ReceiveMsgBytes(&s[0], s.size()));
Expand Down
49 changes: 49 additions & 0 deletions src/txdb.cpp
Expand Up @@ -14,6 +14,8 @@

using namespace std;

static const char DB_FORK_ACTIVATION = 'a';

void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
if (coins.IsPruned())
batch.Erase(make_pair('c', hash));
Expand Down Expand Up @@ -224,5 +226,52 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
}
}

// Load fork activation info
ssKeySet.clear();
ssKeySet << make_pair(DB_FORK_ACTIVATION, 0);
pcursor->Seek(ssKeySet.str());
while (pcursor->Valid()) {
try {
leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
char chType;
ssKey >> chType;
if (chType == DB_FORK_ACTIVATION) {
uint32_t nVersion;
ssKey >> nVersion;
leveldb::Slice slValue = pcursor->value();
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
uint256 blockHash;
ssValue >> blockHash;
forkActivationMap[nVersion] = blockHash;

pcursor->Next();
} else {
break; // finished loading block index
}
}
catch (std::exception &e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
}

return true;
}

uint256 CBlockTreeDB::ForkActivated(int32_t nForkVersion) const
{
std::map<int32_t, uint256>::const_iterator it = forkActivationMap.find(nForkVersion);
if (it != forkActivationMap.end())
return it->second;

return uint256(0);
}

bool CBlockTreeDB::ActivateFork(int32_t nForkVersion, const uint256& blockHash)
{
forkActivationMap[nForkVersion] = blockHash;
if (!blockHash)
return Erase(make_pair(DB_FORK_ACTIVATION, nForkVersion));
else
return Write(make_pair(DB_FORK_ACTIVATION, nForkVersion), blockHash);
}
4 changes: 4 additions & 0 deletions src/txdb.h
Expand Up @@ -47,6 +47,8 @@ class CBlockTreeDB : public CLevelDBWrapper
private:
CBlockTreeDB(const CBlockTreeDB&);
void operator=(const CBlockTreeDB&);
std::map<int32_t, uint256> forkActivationMap;

public:
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
Expand All @@ -60,6 +62,8 @@ class CBlockTreeDB : public CLevelDBWrapper
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool LoadBlockIndexGuts();
uint256 ForkActivated(int32_t nForkVersion) const;
bool ActivateFork(int32_t nForkVersion, const uint256& blockHash);
};

#endif // BITCOIN_TXDB_H