// miner's coin stake reward based on nBits and coin age spent (coin-days)
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly)
{
- int64 nRewardCoinYear, nSubsidy;
+ int64 nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN;
if(fTestNet || nTime > STAKE_SWITCH_TIME)
{
// Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/6)
//
- bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget;
+ bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue;
+ bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
}
else
{
// Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/3)
//
- bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnTargetLimit;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget;
+ bnMidPart = bnMidValue * bnMidValue * bnMidValue;
+ bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
}
- if (bnMidPart > bnRewardPart)
+ if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget)
bnUpperBound = bnMidValue;
else
bnLowerBound = bnMidValue;
//
// This will stimulate large holders to use smaller inputs, that's good for the network protection
if(fTestNet || STAKECURVE_SWITCH_TIME < nTime)
- nSubsidy = min(nSubsidy, 10 * COIN);
+ {
+ if (fDebug && GetBoolArg("-printcreation") && nSubsidyLimit < nSubsidy)
+ printf("GetProofOfStakeReward(): %s is greater than %s, coinstake reward will be truncated\n", FormatMoney(nSubsidy).c_str(), FormatMoney(nSubsidyLimit).c_str());
+
+ nSubsidy = min(nSubsidy, nSubsidyLimit);
+ }
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
}
//
-// minimum amount of work that could possibly be required nTime after
-// minimum work required was nBase
+// maximum nBits value could possible be required nTime after
//
-unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
+unsigned int ComputeMaxBits(CBigNum bnTargetLimit, unsigned int nBase, int64 nTime)
{
- CBigNum bnTargetLimit = bnProofOfWorkLimit;
-
CBigNum bnResult;
bnResult.SetCompact(nBase);
bnResult *= 2;
return bnResult.GetCompact();
}
+//
+// minimum amount of work that could possibly be required nTime after
+// minimum proof-of-work required was nBase
+//
+unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
+{
+ return ComputeMaxBits(bnProofOfWorkLimit, nBase, nTime);
+}
+
+//
+// minimum amount of stake that could possibly be required nTime after
+// minimum proof-of-stake required was nBase
+//
+unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime)
+{
+ return ComputeMaxBits(GetProofOfStakeLimit(0, nBlockTime), nBase, nTime);
+}
+
+
// ppcoin: find last block index up to pindex
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake)
{
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
{
- // Check it again in case a previous version let a bad block in
- if (!CheckBlock(!fJustCheck, !fJustCheck))
+ // Check it again in case a previous version let a bad block in, but skip BlockSig checking
+ if (!CheckBlock(!fJustCheck, !fJustCheck, false))
return false;
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust();
// ppcoin: compute stake entropy bit for stake modifier
- if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nHeight)))
+ if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nTime)))
return error("AddToBlockIndex() : SetStakeEntropyBit() failed");
// ppcoin: record proof-of-stake hash value
-bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
+bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) const
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
- // Special short-term limits to avoid 10,000 BDB lock limit:
- if (GetBlockTime() < LOCKS_SWITCH_TIME)
- {
- // Rule is: #unique txids referenced <= 4,500
- // ... to prevent 10,000 BDB lock exhaustion on old clients
- set<uint256> setTxIn;
- for (size_t i = 0; i < vtx.size(); i++)
- {
- setTxIn.insert(vtx[i].GetHash());
- if (i == 0) continue; // skip coinbase txin
- BOOST_FOREACH(const CTxIn& txin, vtx[i].vin)
- setTxIn.insert(txin.prevout.hash);
- }
- size_t nTxids = setTxIn.size();
- if (nTxids > 4500)
- return error("CheckBlock() : maxlocks violation");
- }
-
// Check proof of work matches claimed amount
if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits))
return DoS(50, error("CheckBlock() : proof of work failed"));
// Check coinstake timestamp
if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime))
return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
+
+ // NovaCoin: check proof-of-stake block signature
+ if (fCheckSig && !CheckBlockSignature(true))
+ return DoS(100, error("CheckBlock() : bad proof-of-stake block signature"));
}
else
{
return DoS(50, error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")",
vtx[0].GetValueOut(),
GetProofOfWorkReward(nBits) - nFee));
+
+ // Should we check proof-of-work block signature or not?
+ //
+ // * Always skip on TestNet
+ // * Perform checking for the first 9689 blocks
+ // * Perform checking since last checkpoint until 20 Sep 2013 (will be removed after)
+
+ if(!fTestNet && fCheckSig)
+ {
+ bool isAfterCheckpoint = (GetBlockTime() > Checkpoints::GetLastCheckpointTime());
+ bool checkEntropySig = (GetBlockTime() < ENTROPY_SWITCH_TIME);
+ bool checkPoWSig = (isAfterCheckpoint && GetBlockTime() < CHAINCHECKS_SWITCH_TIME);
+
+ // NovaCoin: check proof-of-work block signature
+ if ((checkEntropySig || checkPoWSig) && !CheckBlockSignature(false))
+ return DoS(100, error("CheckBlock() : bad proof-of-work block signature"));
+ }
}
// Check transactions
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
- // NovaCoin: check proof-of-stake block signature
- if (IsProofOfStake() || (!fTestNet && GetBlockTime() < CHAINCHECKS_SWITCH_TIME))
- {
- if (!CheckBlockSignature())
- return DoS(100, error("CheckBlock() : bad block signature"));
- }
return true;
}
if (!Checkpoints::CheckHardened(nHeight, hash))
return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lock-in at %d", nHeight));
- // ppcoin: check that the block satisfies synchronized checkpoint
- if (!Checkpoints::CheckSync(hash, pindexPrev))
- {
- if(!GetBoolArg("-nosynccheckpoints", false))
- {
- return error("AcceptBlock() : rejected by synchronized checkpoint");
- }
- else
- {
- strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!");
- }
- }
+ // Check that the block satisfies synchronized checkpoint
+ if (!GetBoolArg("-nosynccheckpoints", false) && !Checkpoints::CheckSync(hash, pindexPrev))
+ return error("AcceptBlock() : rejected by synchronized checkpoint");
// Enforce rule that the coinbase starts with serialized block height
CScript expect = CScript() << nHeight;
CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits);
CBigNum bnRequired;
- bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime));
+
+ if (pblock->IsProofOfStake())
+ bnRequired.SetCompact(ComputeMinStake(GetLastBlockIndex(pcheckpoint, true)->nBits, deltaTime, pblock->nTime));
+ else
+ bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, false)->nBits, deltaTime));
+
if (bnNewBlock > bnRequired)
{
if (pfrom)
}
// ppcoin: check block signature
-bool CBlock::CheckBlockSignature() const
+bool CBlock::CheckBlockSignature(bool fProofOfStake) const
{
if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
return vchBlockSig.empty();
vector<valtype> vSolutions;
txnouttype whichType;
- if(IsProofOfStake())
+ if(fProofOfStake)
{
const CTxOut& txout = vtx[1].vout[1];
strStatusBar = strMiscWarning;
}
- // ppcoin: should not enter safe mode for longer invalid chain
- // ppcoin: if sync-checkpoint is too old do not enter safe mode
- if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload())
+ // * Should not enter safe mode for longer invalid chain
+ // * If sync-checkpoint is too old do not enter safe mode
+ // * Do not display warning if -nosynccheckpoints specified
+ if (!GetBoolArg("-nosynccheckpoints", false) && Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload())
{
nPriority = 100;
strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers.";
nPriority = alert.nPriority;
strStatusBar = alert.strStatusBar;
if (nPriority > 1000)
- strRPC = strStatusBar; // ppcoin: safe mode for high alert
+ strRPC = strStatusBar;
}
}
}
else if (strCommand == "getaddr")
{
+ // Don't return addresses older than nCutOff timestamp
+ int64 nCutOff = GetTime() - (nNodeLifespan * 24 * 60 * 60);
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
BOOST_FOREACH(const CAddress &addr, vAddr)
- pfrom->PushAddress(addr);
+ if(addr.nTime > nCutOff)
+ pfrom->PushAddress(addr);
}
// Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
- // Special compatibility rule before 20 Aug: limit size to 500,000 bytes:
- if (GetAdjustedTime() < LOCKS_SWITCH_TIME)
- nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN));
-
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000);