X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=26e89f0ea0019e05e8daf8193aa61b824cfff78c;hb=b22defc501d9eb8f227567fe2c7d279e243ba6be;hp=d1f435a23e122c9ad013b4d3eb28c6c961cb0472;hpb=97fede720284325d62704b5af5d0a09c667c918b;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index d1f435a..26e89f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,6 +37,7 @@ CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); // "standard" scrypt target limit CBigNum bnProofOfStakeLegacyLimit(~uint256(0) >> 24); // proof of stake target limit from block #15000 and until 20 June 2013, results with 0,00390625 proof of stake difficulty CBigNum bnProofOfStakeLimit(~uint256(0) >> 27); // proof of stake target limit since 20 June 2013, equal to 0.03125 proof of stake difficulty CBigNum bnProofOfStakeHardLimit(~uint256(0) >> 30); // disabled temporarily, will be used in the future to fix minimal proof of stake difficulty at 0.25 +uint256 nPoWBase = uint256("0x00000000ffff0000000000000000000000000000000000000000000000000000"); // difficulty-1 target CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 16); @@ -48,8 +49,10 @@ unsigned int nModifierInterval = 6 * 60 * 60; // time to elapse before new modif int nCoinbaseMaturity = 500; CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; -CBigNum bnBestChainTrust = 0; -CBigNum bnBestInvalidTrust = 0; + +uint256 nBestChainTrust = 0; +uint256 nBestInvalidTrust = 0; + uint256 hashBestChain = 0; CBlockIndex* pindexBest = NULL; int64 nTimeBestReceived = 0; @@ -476,8 +479,10 @@ bool CTransaction::CheckTransaction() const if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake()) return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction")); - // ppcoin: enforce minimum output amount - if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT) + // NovaCoin: enforce minimum output amount for user transactions + // (and for all transactions until 20 Sep 2013) + if ((!IsCoinBase() || nTime < CHAINCHECKS_SWITCH_TIME) + && (!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT) return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum")); if (txout.nValue > MAX_MONEY) @@ -499,7 +504,7 @@ bool CTransaction::CheckTransaction() const if (IsCoinBase()) { if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) - return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); + return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size is invalid")); } else { @@ -937,7 +942,7 @@ uint256 WantedByOrphan(const CBlock* pblockOrphan) } // select stake target limit according to hard-coded conditions -CBigNum static GetProofOfStakeLimit(int nHeight, unsigned int nTime) +CBigNum inline GetProofOfStakeLimit(int nHeight, unsigned int nTime) { if(fTestNet) // separate proof of stake target limit for testnet return bnProofOfStakeLimit; @@ -982,6 +987,7 @@ int64 GetProofOfWorkReward(unsigned int nBits) } int64 nSubsidy = bnUpperBound.getuint64(); + nSubsidy = (nSubsidy / CENT) * CENT; if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nBits, nSubsidy); @@ -990,9 +996,9 @@ int64 GetProofOfWorkReward(unsigned int nBits) } // miner's coin stake reward based on nBits and coin age spent (coin-days) -int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime) +int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly) { - int64 nRewardCoinYear; + int64 nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN; if(fTestNet || nTime > STAKE_SWITCH_TIME) { @@ -1004,22 +1010,46 @@ int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTi CBigNum bnTargetLimit = GetProofOfStakeLimit(0, nTime); bnTargetLimit.SetCompact(bnTargetLimit.GetCompact()); - // NovaCoin: reward for coin-year is cut in half every 64x multiply of PoS difficulty - // A reasonably continuous curve is used to avoid shock to market - // (nRewardCoinYearLimit / nRewardCoinYear) ** 6 == bnProofOfStakeLimit / bnTarget - // - // Human readable form: - // - // nRewardCoinYear = 1 / (posdiff ^ 1/6) + // NovaCoin: A reasonably continuous curve is used to avoid shock to market + + CBigNum bnLowerBound = 1 * CENT, // Lower interest bound is 1% per year + bnUpperBound = bnRewardCoinYearLimit, // Upper interest bound is 100% per year + bnMidPart, bnRewardPart; - CBigNum bnLowerBound = 1 * CENT; // Lower interest bound is 1% per year - CBigNum bnUpperBound = bnRewardCoinYearLimit; while (bnLowerBound + CENT <= bnUpperBound) { CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2; if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfStakeReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64()); - if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget) + + if(!fTestNet && nTime < STAKECURVE_SWITCH_TIME) + { + // + // Until 20 Oct 2013: reward for coin-year is cut in half every 64x multiply of PoS difficulty + // + // (nRewardCoinYearLimit / nRewardCoinYear) ** 6 == bnProofOfStakeLimit / bnTarget + // + // Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/6) + // + + bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue; + bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit; + } + else + { + // + // Since 20 Oct 2013: reward for coin-year is cut in half every 8x multiply of PoS difficulty + // + // (nRewardCoinYearLimit / nRewardCoinYear) ** 3 == bnProofOfStakeLimit / bnTarget + // + // Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/3) + // + + bnMidPart = bnMidValue * bnMidValue * bnMidValue; + bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit; + } + + if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget) bnUpperBound = bnMidValue; else bnLowerBound = bnMidValue; @@ -1034,7 +1064,26 @@ int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTi nRewardCoinYear = 5 * CENT; } - int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; + if(bCoinYearOnly) + return nRewardCoinYear; + + // Fix problem with proof-of-stake rewards calculation since 20 Sep 2013 + if(nTime < CHAINCHECKS_SWITCH_TIME) + nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; + else + nSubsidy = nCoinAge * nRewardCoinYear * 33 / (365 * 33 + 8); + + // Set reasonable reward limit for large inputs since 20 Oct 2013 + // + // This will stimulate large holders to use smaller inputs, that's good for the network protection + if(fTestNet || STAKECURVE_SWITCH_TIME < nTime) + { + 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); return nSubsidy; @@ -1043,7 +1092,7 @@ int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTi static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week // get proof of work blocks max spacing according to hard-coded conditions -int64 static GetTargetSpacingWorkMax(int nHeight, unsigned int nTime) +int64 inline GetTargetSpacingWorkMax(int nHeight, unsigned int nTime) { if(nTime > TARGETS_SWITCH_TIME) return 3 * nStakeTargetSpacing; // 30 minutes on mainNet since 20 Jul 2013 00:00:00 @@ -1154,22 +1203,28 @@ bool IsInitialBlockDownload() void static InvalidChainFound(CBlockIndex* pindexNew) { - if (pindexNew->bnChainTrust > bnBestInvalidTrust) + if (pindexNew->nChainTrust > nBestInvalidTrust) { - bnBestInvalidTrust = pindexNew->bnChainTrust; - CTxDB().WriteBestInvalidTrust(bnBestInvalidTrust); + nBestInvalidTrust = pindexNew->nChainTrust; + CTxDB().WriteBestInvalidTrust(CBigNum(nBestInvalidTrust)); uiInterface.NotifyBlocksChanged(); } - printf("InvalidChainFound: invalid block=%s height=%d trust=%s date=%s\n", + uint256 nBestInvalidBlockTrust = pindexNew->nChainTrust - pindexNew->pprev->nChainTrust; + uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust; + + printf("InvalidChainFound: invalid block=%s height=%d trust=%s blocktrust=%"PRI64d" date=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, - pindexNew->bnChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", - pindexNew->GetBlockTime()).c_str()); - printf("InvalidChainFound: current best=%s height=%d trust=%s date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), + CBigNum(pindexNew->nChainTrust).ToString().c_str(), nBestInvalidBlockTrust.Get64(), + DateTimeStrFormat("%x %H:%M:%S", pindexNew->GetBlockTime()).c_str()); + printf("InvalidChainFound: current best=%s height=%d trust=%s blocktrust=%"PRI64d" date=%s\n", + hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, + CBigNum(pindexBest->nChainTrust).ToString().c_str(), + nBestBlockTrust.Get64(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); } + void CBlock::UpdateTime(const CBlockIndex* pindexPrev) { nTime = max(GetBlockTime(), GetAdjustedTime()); @@ -1425,9 +1480,12 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, uint64 nCoinAge; if (!GetCoinAge(txdb, nCoinAge)) return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str()); + int64 nStakeReward = GetValueOut() - nValueIn; - if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee() + MIN_TX_FEE) - return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str())); + int64 nCalculatedStakeReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee() + MIN_TX_FEE; + + if (nStakeReward > nCalculatedStakeReward) + return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%"PRI64d" vs calculated=%"PRI64d")", nStakeReward, nCalculatedStakeReward)); } else { @@ -1527,8 +1585,8 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) 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, @@ -1803,7 +1861,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) // Reorganize is costly in terms of db load, as it works in a single db transaction. // Try to limit how much needs to be done inside - while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainTrust > pindexBest->bnChainTrust) + while (pindexIntermediate->pprev && pindexIntermediate->pprev->nChainTrust > pindexBest->nChainTrust) { vpindexSecondary.push_back(pindexIntermediate); pindexIntermediate = pindexIntermediate->pprev; @@ -1852,11 +1910,16 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) pindexBest = pindexNew; pblockindexFBBHLast = NULL; nBestHeight = pindexBest->nHeight; - bnBestChainTrust = pindexNew->bnChainTrust; + nBestChainTrust = pindexNew->nChainTrust; nTimeBestReceived = GetTime(); nTransactionsUpdated++; - printf("SetBestChain: new best=%s height=%d trust=%s date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), + + uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust; + + printf("SetBestChain: new best=%s height=%d trust=%s blocktrust=%"PRI64d" date=%s\n", + hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, + CBigNum(nBestChainTrust).ToString().c_str(), + nBestBlockTrust.Get64(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // Check the version of the last 100 blocks to see if we need to upgrade: @@ -1976,10 +2039,10 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) } // ppcoin: compute chain trust score - pindexNew->bnChainTrust = (pindexNew->pprev ? pindexNew->pprev->bnChainTrust : 0) + pindexNew->GetBlockTrust(); + 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 @@ -2015,7 +2078,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) return false; // New best - if (pindexNew->bnChainTrust > bnBestChainTrust) + if (pindexNew->nChainTrust > nBestChainTrust) if (!SetBestChain(txdb, pindexNew)) return false; @@ -2036,7 +2099,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) -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. @@ -2078,28 +2141,59 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const if (vtx[i].IsCoinBase()) return DoS(100, error("CheckBlock() : more than one coinbase")); - // ppcoin: only the second transaction can be the optional coinstake - for (unsigned int i = 2; i < vtx.size(); i++) - if (vtx[i].IsCoinStake()) - return DoS(100, error("CheckBlock() : coinstake in wrong position")); - - // ppcoin: coinbase output should be empty if proof-of-stake block - if (IsProofOfStake() && (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty())) - return error("CheckBlock() : coinbase output not empty for proof-of-stake block"); - // Check coinbase timestamp if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift) return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); - // Check coinstake timestamp - if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) - return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); + if (IsProofOfStake()) + { + // Coinbase output should be empty if proof-of-stake block + if (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()) + return DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block")); + + // Second transaction must be coinstake, the rest must not be + if (vtx.empty() || !vtx[1].IsCoinStake()) + return DoS(100, error("CheckBlock() : second tx is not coinstake")); + for (unsigned int i = 2; i < vtx.size(); i++) + if (vtx[i].IsCoinStake()) + return DoS(100, error("CheckBlock() : more than one coinstake")); + + // 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 + { + // Coinbase fee paid until 20 Sep 2013 + int64 nFee = GetBlockTime() < CHAINCHECKS_SWITCH_TIME ? vtx[0].GetMinFee() - MIN_TX_FEE : 0; - // Check coinbase reward - if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0)) - return DoS(50, error("CheckBlock() : coinbase reward exceeded %s > %s", - FormatMoney(vtx[0].GetValueOut()).c_str(), - FormatMoney(IsProofOfWork()? GetProofOfWorkReward(nBits) : 0).c_str())); + // Check coinbase reward + if (vtx[0].GetValueOut() > (GetProofOfWorkReward(nBits) - nFee)) + 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 BOOST_FOREACH(const CTransaction& tx, vtx) @@ -2134,9 +2228,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); - // ppcoin: check block signature - if (!CheckBlockSignature()) - return DoS(100, error("CheckBlock() : bad block signature")); return true; } @@ -2185,10 +2276,6 @@ bool CBlock::AcceptBlock() } } - // Reject block.nVersion < 3 blocks since 95% threshold on mainNet and always on testNet: - if (nVersion < 3 && ((!fTestNet && nHeight > 14060) || (fTestNet && nHeight > 0))) - return error("CheckBlock() : rejected nVersion < 3 block"); - // Enforce rule that the coinbase starts with serialized block height CScript expect = CScript() << nHeight; if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) @@ -2220,6 +2307,90 @@ bool CBlock::AcceptBlock() return true; } +uint256 CBlockIndex::GetBlockTrust() const +{ + CBigNum bnTarget; + bnTarget.SetCompact(nBits); + + if (bnTarget <= 0) + return 0; + + /* Old protocol, will be removed later */ + if (!fTestNet && GetBlockTime() < CHAINCHECKS_SWITCH_TIME) + return (IsProofOfStake()? ((CBigNum(1)<<256) / (bnTarget+1)).getuint256() : 1); + + /* New protocol */ + + // Calculate work amount for block + uint256 nPoWTrust = (CBigNum(nPoWBase) / (bnTarget+1)).getuint256(); + + // Set nPowTrust to 1 if we are checking PoS block or PoW difficulty is too low + nPoWTrust = (IsProofOfStake() || nPoWTrust < 1) ? 1 : nPoWTrust; + + // Return nPoWTrust for the first 12 blocks + if (pprev == NULL || pprev->nHeight < 12) + return nPoWTrust; + + const CBlockIndex* currentIndex = pprev; + + if(IsProofOfStake()) + { + CBigNum bnNewTrust = (CBigNum(1)<<256) / (bnTarget+1); + + // Return 1/3 of score if parent block is not the PoW block + if (!pprev->IsProofOfWork()) + return (bnNewTrust / 3).getuint256(); + + int nPoWCount = 0; + + // Check last 12 blocks type + while (pprev->nHeight - currentIndex->nHeight < 12) + { + if (currentIndex->IsProofOfWork()) + nPoWCount++; + currentIndex = currentIndex->pprev; + } + + // Return 1/3 of score if less than 3 PoW blocks found + if (nPoWCount < 3) + return (bnNewTrust / 3).getuint256(); + + return bnNewTrust.getuint256(); + } + else + { + CBigNum bnLastBlockTrust = CBigNum(pprev->nChainTrust - pprev->pprev->nChainTrust); + + // Return nPoWTrust + 2/3 of previous block score if two parent blocks are not PoS blocks + if (!(pprev->IsProofOfStake() && pprev->pprev->IsProofOfStake())) + return nPoWTrust + (2 * bnLastBlockTrust / 3).getuint256(); + + int nPoSCount = 0; + + // Check last 12 blocks type + while (pprev->nHeight - currentIndex->nHeight < 12) + { + if (currentIndex->IsProofOfStake()) + nPoSCount++; + currentIndex = currentIndex->pprev; + } + + // Return nPoWTrust + 2/3 of previous block score if less than 7 PoS blocks found + if (nPoSCount < 7) + return nPoWTrust + (2 * bnLastBlockTrust / 3).getuint256(); + + bnTarget.SetCompact(pprev->nBits); + + if (bnTarget <= 0) + return 0; + + CBigNum bnNewTrust = (CBigNum(1)<<256) / (bnTarget+1); + + // Return nPoWTrust + full trust score for previous block nBits + return nPoWTrust + bnNewTrust.getuint256(); + } +} + bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) { unsigned int nFound = 0; @@ -2407,7 +2578,7 @@ bool CBlock::SignBlock(const CKeyStore& keystore) } // ppcoin: check block signature -bool CBlock::CheckBlockSignature() const +bool CBlock::CheckBlockSignature(bool fProofOfStake) const { if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) return vchBlockSig.empty(); @@ -2415,7 +2586,7 @@ bool CBlock::CheckBlockSignature() const vector vSolutions; txnouttype whichType; - if(IsProofOfStake()) + if(fProofOfStake) { const CTxOut& txout = vtx[1].vout[1]; @@ -3337,6 +3508,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); + // Truncate messages to the size of the tx in them + unsigned int nSize = ::GetSerializeSize(tx,SER_NETWORK, PROTOCOL_VERSION); + if (nSize < vMsg.size()){ + vMsg.resize(nSize); + } + bool fMissingInputs = false; if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs)) { @@ -3413,10 +3590,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (strCommand == "getaddr") { + // Don't return addresses older than nCutOff timestamp + int64 nCutOff = GetTime() - (nNodeLifespan * 24 * 60 * 60); pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); BOOST_FOREACH(const CAddress &addr, vAddr) - pfrom->PushAddress(addr); + if(addr.nTime > nCutOff) + pfrom->PushAddress(addr); } @@ -4328,17 +4508,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) return true; } -void static ThreadBitcoinMiner(void* parg); - -static bool fGenerateBitcoins = false; -static bool fLimitProcessors = false; -static int nLimitProcessors = -1; - void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) { - void *scratchbuf = scrypt_buffer_alloc(); - - printf("CPUMiner started for proof-of-%s\n", fProofOfStake? "stake" : "work"); SetThreadPriority(THREAD_PRIORITY_LOWEST); // Make this thread recognisable as the mining thread @@ -4348,7 +4519,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; - while (fGenerateBitcoins || fProofOfStake) + while (fProofOfStake) { if (fShutdown) return; @@ -4357,7 +4528,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) Sleep(1000); if (fShutdown) return; - if ((!fGenerateBitcoins) && !fProofOfStake) + if (!fProofOfStake) return; } @@ -4371,7 +4542,6 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) // // Create new block // - unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; CBlockIndex* pindexPrev = pindexBest; auto_ptr pblock(CreateNewBlock(pwallet, fProofOfStake)); @@ -4390,7 +4560,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) continue; } strMintWarning = ""; - printf("CPUMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str()); + printf("StakeMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str()); SetThreadPriority(THREAD_PRIORITY_NORMAL); CheckWork(pblock.get(), *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); @@ -4398,174 +4568,6 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) Sleep(500); continue; } - - printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Pre-build hash buffers - // - char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf); - char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); - char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); - - FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); - - unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); - unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); - - - // - // Search - // - int64 nStart = GetTime(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - - unsigned int max_nonce = 0xffff0000; - block_header res_header; - uint256 result; - - loop - { - unsigned int nHashesDone = 0; - unsigned int nNonceFound; - - nNonceFound = scanhash_scrypt( - (block_header *)&pblock->nVersion, - scratchbuf, - max_nonce, - nHashesDone, - UBEGIN(result), - &res_header - ); - - // Check if something found - if (nNonceFound != (unsigned int) -1) - { - if (result <= hashTarget) - { - // Found a solution - pblock->nNonce = nNonceFound; - assert(result == pblock->GetHash()); - if (!pblock->SignBlock(*pwalletMain)) - { -// strMintWarning = strMintMessage; - break; - } - strMintWarning = ""; - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock.get(), *pwalletMain, reservekey); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - break; - } - } - - // Meter hashes/sec - static int64 nHashCounter; - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; - { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - static int64 nLogTime; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); - } - } - } - } - - // Check for stop or if block needs to be rebuilt - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) - return; - if (vNodes.empty()) - break; - if (nBlockNonce >= 0xffff0000) - break; - if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != pindexBest) - break; - - // Update nTime every few seconds - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime()); - pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); - pblock->UpdateTime(pindexPrev); - nBlockTime = ByteReverse(pblock->nTime); - - if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nMaxClockDrift) - break; // need to update coinbase timestamp - } } - - scrypt_buffer_free(scratchbuf); -} - -void static ThreadBitcoinMiner(void* parg) -{ - CWallet* pwallet = (CWallet*)parg; - try - { - vnThreadsRunning[THREAD_MINER]++; - BitcoinMiner(pwallet, false); - vnThreadsRunning[THREAD_MINER]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(&e, "ThreadBitcoinMiner()"); - } catch (...) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(NULL, "ThreadBitcoinMiner()"); - } - nHPSTimerStart = 0; - if (vnThreadsRunning[THREAD_MINER] == 0) - dHashesPerSec = 0; - printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); } - -void GenerateBitcoins(bool fGenerate, CWallet* pwallet) -{ - fGenerateBitcoins = fGenerate; - nLimitProcessors = GetArg("-genproclimit", -1); - if (nLimitProcessors == 0) - fGenerateBitcoins = false; - fLimitProcessors = (nLimitProcessors != -1); - - if (fGenerate) - { - int nProcessors = boost::thread::hardware_concurrency(); - printf("%d processors\n", nProcessors); - if (nProcessors < 1) - nProcessors = 1; - if (fLimitProcessors && nProcessors > nLimitProcessors) - nProcessors = nLimitProcessors; - int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; - printf("Starting %d BitcoinMiner threads\n", nAddThreads); - for (int i = 0; i < nAddThreads; i++) - { - if (!NewThread(ThreadBitcoinMiner, pwallet)) - printf("Error: NewThread(ThreadBitcoinMiner) failed\n"); - Sleep(10); - } - } -}