Skip to content

Commit

Permalink
Networking updates. getblocks() message is issued after connection to…
Browse files Browse the repository at this point in the history
… new node if waited longer than MAX_TIME_SINCE_BEST_BLOCK seconds.

Changing target for initial blockchain download to 275000.

This way client will get quickly there and will have fewer number of blocks to obtain using slower methods.
  • Loading branch information
l0rdicon committed Jan 11, 2015
1 parent ec8955a commit 6649357
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 39 deletions.
1 change: 0 additions & 1 deletion src/chainparams.cpp
Expand Up @@ -87,7 +87,6 @@ class CMainParams : public CChainParams {
PUSH_SEED("173.31.55.8")
PUSH_SEED("46.5.84.204")
PUSH_SEED("54.75.227.85")
PUSH_SEED("66.30.80.136")
PUSH_SEED("73.172.149.95")
PUSH_SEED("73.55.207.245")
PUSH_SEED("76.94.201.185")
Expand Down
3 changes: 2 additions & 1 deletion src/checkpoints.cpp
Expand Up @@ -28,10 +28,11 @@ namespace Checkpoints
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 0, hashGenesisBlock )
( 6666, uint256("0x000002129d8a2b43509d2abb0aa24932b7af2f760e869d5952dee97d4b8ea8bf") )
( 6666, uint256("0x000002129d8a2b43509d2abb0aa24932b7af2f760e869d5952dee97d4b8ea8bf") )
( 10000, uint256("0x00000de398b1ec72c393c5c54574a1e1784eb178d683e1ad0856c12fac34f603") )
( 29000, uint256("0x068769a2ab0e35fc3ac31690158401b9538a7cce2a97096b22d47e50355b2e1f") )
( 175000, uint256("0xec64deeb7f1295216f20ce5dbe68b0bd28189a5a644a111e722c05451d51e66c") )
( 250000, uint256("0xb560c121438f630401c102767587b70cb0cc7d1e0c09114dd0b91455262aa64c") )
;

// TestNet has no checkpoints
Expand Down
125 changes: 90 additions & 35 deletions src/main.cpp
Expand Up @@ -946,13 +946,6 @@ uint256 WantedByOrphan(const COrphanBlock* pblockOrphan)
pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrev];
return pblockOrphan->hashPrev;
}

int generateMTRandom(unsigned int s, int range)
{
random::mt19937 gen(s);
random::uniform_int_distribution<> dist(1, range);
return dist(gen);
}

// Remove a random orphan block (which does not have any dependent orphans).
void static PruneOrphanBlocks()
Expand All @@ -979,6 +972,14 @@ void static PruneOrphanBlocks()
mapOrphanBlocksByPrev.erase(it);
mapOrphanBlocks.erase(hash);
}

int generateMTRandom(unsigned int s, int range)
{
random::mt19937 gen(s);
random::uniform_int_distribution<> dist(1, range);
return dist(gen);
}


// miner's coin base reward
int64_t GetProofOfWorkReward(int nHeight, int64_t nFees)
Expand Down Expand Up @@ -2406,25 +2407,42 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString());

map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(pblock->hashPrevBlock);
if (mi == mapBlockIndex.end())
return false;

This comment has been minimized.

Copy link
@dooglus

dooglus Jan 30, 2015

Collaborator

This is the problematic code. When we receive an orphan block we will immediately reject it here rather than saving it as an orphan and requesting its parent.

My f8677c0 commit fixes this.

CBlockIndex* pPrev = (*mi).second;

// ppcoin: check proof-of-stake
// Limited duplicity on stake: prevents block flood attack
// Duplicate stake allowed only when there is orphan child block
if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString(), pblock->GetProofOfStake().second, hash.ToString());

CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
// Preliminary checks
if (!pblock->CheckBlock())
return error("ProcessBlock() : CheckBlock FAILED");

uint256 hashProof;
// ppcoin: verify hash target and signature of coinstake tx
if (pblock->IsProofOfStake())
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
if (deltaTime < -10*60)
uint256 hashProofOfStake = 0;
if (!CheckProofOfStake(pPrev, pblock->vtx[1], pblock->nBits, hashProof, hashProofOfStake))
{
if (pfrom)
pfrom->Misbehaving(1);
return error("ProcessBlock() : block with timestamp before last checkpoint");
// Ignore CheckProofOfStake() failure for hashHighBlock in order to speed up initial
// blockchain download.
if (pblock->GetHash() != hashHighBlock) {
//printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str());
return false; // do not error here as we expect this during initial block download
}
}
}

/* FIXME
CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits);
CBigNum bnRequired;
Expand All @@ -2440,23 +2458,17 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
pfrom->Misbehaving(100);
return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
}
*/
}

// Block signature can be malleated in such a way that it increases block size up to maximum allowed by protocol
// For now we just strip garbage from newly received blocks
if (!ReserealizeBlockSignature(pblock))
LogPrintf("WARNING: ProcessBlock() : ReserealizeBlockSignature FAILED\n");

// Preliminary checks
if (!pblock->CheckBlock())
return error("ProcessBlock() : CheckBlock FAILED");

// ppcoin: ask for pending sync-checkpoint if any
if (!IsInitialBlockDownload())
Checkpoints::AskForPendingSyncCheckpoint(pfrom);

// If we don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock))
{
LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString());
Expand Down Expand Up @@ -3047,11 +3059,17 @@ void static ProcessGetData(CNode* pfrom)
// Trigger them to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
{
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
// Default behavior of PoS coins is to send last PoW block here which client
// receives as an orphan. With CLAM we want hyper download speed so further
// block (index HIGH_BLOCK_INDEX) is sent. If server does not have it yet,
// then proceeds with default behavior.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
if (nBestHeight > HIGH_BLOCK_INDEX) {
vInv.push_back(CInv(MSG_BLOCK, hashHighBlock));
} else {
vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(pindexBest, false)->GetBlockHash()));
}

pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
Expand Down Expand Up @@ -3147,17 +3165,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!vRecv.empty())
vRecv >> pfrom->nStartingHeight;

// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
if (pfrom->fInbound && addrMe.IsRoutable())
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
return true;
pfrom->addrLocal = addrMe;

This comment has been minimized.

Copy link
@dooglus

dooglus Feb 7, 2015

Collaborator

This line needs to be outside the containing 'if' block so that it runs for outbound connections as well. See issue #137.

SeenLocal(addrMe);
}

if (pfrom->nVersion < 60014)
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
printf("partner %s using a buggy client %d, disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
return true;
}
Expand All @@ -3168,6 +3185,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);

AddTimeData(pfrom->addr, nTime);

// Change version
pfrom->PushMessage("verack");
pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
Expand Down Expand Up @@ -3202,6 +3221,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}

// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
if (!pfrom->fClient && !pfrom->fOneShot &&
(pfrom->nStartingHeight > (nBestHeight - 144)) &&
(pfrom->nVersion < NOBLKS_VERSION_START ||
pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
PushGetBlocks(pfrom, pindexBest, uint256(0));
}

// Relay alerts
{
LOCK(cs_mapAlerts);
Expand All @@ -3220,6 +3251,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

LogPrintf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString(), addrFrom.ToString(), pfrom->addr.ToString());



// Be more aggressive with blockchain download. Send new getblocks() message after connection
// to new node if waited longer than MAX_TIME_SINCE_BEST_BLOCK.
int64 TimeSinceBestBlock = GetTime() - nTimeBestReceived;
if (TimeSinceBestBlock > MAX_TIME_SINCE_BEST_BLOCK) {
//LogPrintf("INFO: Waiting %d sec which is too long. Sending GetBlocks(0)\n", TimeSinceBestBlock);
PushGetBlocks(pfrom, pindexBest, uint256(0));
}

// ppcoin: ask for pending sync-checkpoint if any
if (!IsInitialBlockDownload())
Checkpoints::AskForPendingSyncCheckpoint(pfrom);
Expand Down Expand Up @@ -3398,13 +3439,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
int nLimit = 500;
int nLimit = 1000;
LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// ppcoin: tell downloading node about the latest block if it's
// without risk being rejected due to stake connection check
if (hashStop != hashBestChain && pindex->GetBlockTime() + nStakeMinAge > pindexBest->GetBlockTime())
pfrom->PushInventory(CInv(MSG_BLOCK, hashBestChain));
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
Expand Down Expand Up @@ -3552,8 +3597,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

LOCK(cs_main);

if (ProcessBlock(pfrom, &block))
if (ProcessBlock(pfrom, &block)) {
mapAlreadyAskedFor.erase(inv);
} else {
// Be more aggressive with blockchain download. Send getblocks() message after
// an error related to new block download
int64 TimeSinceBestBlock = GetTime() - nTimeBestReceived;
if (TimeSinceBestBlock > MAX_TIME_SINCE_BEST_BLOCK) {
//LogPrintf("INFO: Waiting %d sec which is too long. Sending GetBlocks(0)\n", TimeSinceBestBlock);
PushGetBlocks(pfrom, pindexBest, uint256(0));
}
}

if (block.nDoS) pfrom->Misbehaving(block.nDoS);
}

Expand Down
6 changes: 5 additions & 1 deletion src/main.h
Expand Up @@ -62,6 +62,10 @@ static const unsigned int MAX_TX_COMMENT_LEN = 140; // 128 bytes + little extra
static const uint256 hashGenesisBlock("0x00000c3ce6b3d823a35224a39798eca9ad889966aeb5a9da7b960ffb9869db35");
static const uint256 hashGenesisBlockTestNet("0x0000135b14723652fecaeb07a52cebf3f69512594eae48d139956bca67552441");

static const uint256 hashHighBlock ("0xdb61f591d7fb40afa08476d6492e81a06edddf332d7027968ac130db95c07cb7");
static const int HIGH_BLOCK_INDEX = 275000;


inline bool IsProtocolV2(int nHeight) { return nHeight > 203500; }

inline int64_t PastDrift(int64_t nTime, int nHeight) { return IsProtocolV2(nHeight) ? nTime : nTime - 10 * 60; }
Expand All @@ -70,7 +74,7 @@ inline int64_t FutureDriftV1(int64_t nTime) { return nTime + 10 * 60; }
inline int64_t FutureDriftV2(int64_t nTime) { return nTime + 15; }
inline int64_t FutureDrift(int64_t nTime, int nHeight) { return IsProtocolV2(nHeight) ? FutureDriftV2(nTime) : FutureDriftV1(nTime); }


static const int64 MAX_TIME_SINCE_BEST_BLOCK = 10; // how many seconds to wait before sending next PushGetBlocks()
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern CTxMemPool mempool;
Expand Down
2 changes: 1 addition & 1 deletion src/version.h
Expand Up @@ -21,7 +21,7 @@ static const int PROTOCOL_VERSION = 60014;
static const int INIT_PROTO_VERSION = 209;

// disconnect from peers older than this proto version
static const int MIN_PEER_PROTO_VERSION = 209;
static const int MIN_PEER_PROTO_VERSION = 60014;

// nTime field added to CAddress, starting with this version;
// if possible, avoid requesting addresses nodes older than this
Expand Down

1 comment on commit 6649357

@robvanmieghem
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes the client to get stuck sometimes (when staking a block that is not accepted).
Reverting this commit makes the client to continue, no need to resync from scratch.

Please sign in to comment.