X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=263a9e94902ef372855e806652032a0c60cef708;hb=b2516d2435f6916974ecd19241514b421a823a01;hp=4e27d4b9870f5961a98561279354b22ba0b9cf3f;hpb=851fe4f82c9400ced6d58f6f279bc01539d8a1f9;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 4e27d4b..263a9e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -668,6 +668,15 @@ uint256 static GetOrphanRoot(const CBlock* pblock) return pblock->GetHash(); } +// ppcoin: find block wanted by given orphan block +uint256 WantedByOrphan(const CBlock* pblockOrphan) +{ + // Work back to the first block in the orphan chain + while (mapOrphanBlocks.count(pblockOrphan->hashPrevBlock)) + pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrevBlock]; + return pblockOrphan->hashPrevBlock; +} + int64 static GetProofOfWorkReward(unsigned int nBits) { CBigNum bnSubsidyLimit = 9999 * COIN; // subsidy amount for difficulty 1 @@ -723,12 +732,12 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) { CBigNum bnResult; bnResult.SetCompact(nBase); + bnResult *= 2; while (nTime > 0 && bnResult < bnProofOfWorkLimit) { - // Maximum 400% adjustment... - bnResult *= 4; - // ... in best-case exactly 4-times-normal target time - nTime -= nTargetTimespan*4; + // Maximum 200% adjustment per day... + bnResult *= 2; + nTime -= 24 * 60 * 60; } if (bnResult > bnProofOfWorkLimit) bnResult = bnProofOfWorkLimit; @@ -1191,8 +1200,6 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) } if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash())) return error("Reorganize() : WriteHashBestChain failed"); - if (!txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint))) - return error("Reorganize() : WriteAutoCheckpoint failed"); // Make sure it's successfully written to disk before changing memory structure if (!txdb.TxnCommit()) @@ -1228,7 +1235,6 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) { txdb.WriteHashBestChain(hash); - txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint)); if (!txdb.TxnCommit()) return error("SetBestChain() : TxnCommit failed"); pindexGenesisBlock = pindexNew; @@ -1236,7 +1242,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) else if (hashPrevBlock == hashBestChain) { // Adding to current best branch - if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash) || !txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint))) + if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) { txdb.TxnAbort(); InvalidChainFound(pindexNew); @@ -1277,7 +1283,6 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) nBestChainTrust = pindexNew->nChainTrust; nTimeBestReceived = GetTime(); nTransactionsUpdated++; - Checkpoints::AdvanceAutoCheckpoint(pindexBest->nCheckpoint); printf("SetBestChain: new best=%s height=%d trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str()); return true; @@ -1437,10 +1442,6 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) { pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; - - // ppcoin: compute chain checkpoint - pindexNew->nCheckpoint = Checkpoints::GetNextChainCheckpoint(pindexNew->pprev); - assert (pindexNew->nCheckpoint >= pindexNew->pprev->nCheckpoint); } // ppcoin: compute chain trust score @@ -1574,10 +1575,6 @@ bool CBlock::AcceptBlock() if (!Checkpoints::CheckHardened(nHeight, hash)) return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lockin at %d", nHeight)); - // ppcoin: check that the block satisfies automatic checkpoint - if (!Checkpoints::CheckAuto(pindexPrev)) - return DoS(100, error("AcceptBlock() : rejected by automatic checkpoint at %d", Checkpoints::nAutoCheckpoint)); - // ppcoin: check that the block satisfies synchronized checkpoint if (!Checkpoints::CheckSync(hash, pindexPrev)) return error("AcceptBlock() : rejected by synchronized checkpoint"); @@ -1617,7 +1614,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) // 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)) + 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().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str()); // Preliminary checks @@ -1628,23 +1625,15 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits)) return error("ProcessBlock() : check proof-of-stake failed for block %s", hash.ToString().c_str()); - CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); - if (pcheckpoint && pblock->hashPrevBlock != hashBestChain) + 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; - if (deltaTime < 0) - { - pfrom->Misbehaving(100); - return error("ProcessBlock() : block with timestamp before last checkpoint"); - } CBigNum bnNewBlock; bnNewBlock.SetCompact(pblock->nBits); CBigNum bnRequired; - if (pblock->IsProofOfWork()) - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - else - bnRequired = bnNewBlock; // TODO: Computer Min Stake Target Allowed + bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime)); if (bnNewBlock > bnRequired) { @@ -1664,7 +1653,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) { // Limited duplicity on stake: prevents block flood attack // Duplicate stake allowed only when there is orphan child block - if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash)) + if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock2->GetProofOfStake().first.ToString().c_str(), pblock2->GetProofOfStake().second, hash.ToString().c_str()); else setStakeSeenOrphan.insert(pblock2->GetProofOfStake()); @@ -1676,10 +1665,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) if (pfrom) { pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); - // ppcoin: getblocks may not obtain the parent block rejected earlier - // by duplicate-stake check so we must ask for it again directly - if (!mapOrphanBlocks.count(pblock->hashPrevBlock)) - pfrom->AskFor(CInv(MSG_BLOCK, pblock->hashPrevBlock)); + // ppcoin: getblocks may not obtain the ancestor block rejected + // earlier by duplicate-stake check so we ask for it again directly + pfrom->AskFor(CInv(MSG_BLOCK, WantedByOrphan(pblock2))); } return true; } @@ -1855,11 +1843,26 @@ bool LoadBlockIndex(bool fAllowNew) return error("LoadBlockIndex() : genesis block not accepted"); // ppcoin: initialize synchronized checkpoint - CTxDB txdbc; - if (!txdbc.WriteSyncCheckpoint(hashGenesisBlock)) + if (!Checkpoints::WriteSyncCheckpoint(hashGenesisBlock)) return error("LoadBlockIndex() : failed to init sync checkpoint"); - txdbc.Close(); - Checkpoints::hashSyncCheckpoint = hashGenesisBlock; + } + + // ppcoin: if checkpoint master key changed must reset sync-checkpoint + { + CTxDB txdb; + string strPubKey = ""; + if (!txdb.ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey) + { + // write checkpoint master key to db + txdb.TxnBegin(); + if (!txdb.WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey)) + return error("LoadBlockIndex() : failed to write new checkpoint master key to db"); + if (!txdb.TxnCommit()) + return error("LoadBlockIndex() : failed to commit new checkpoint master key to db"); + if (!Checkpoints::ResetSyncCheckpoint()) + return error("LoadBlockIndex() : failed to reset sync-checkpoint"); + } + txdb.Close(); } return true; @@ -1979,6 +1982,12 @@ string GetWarnings(string strFor) strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."; } + if (Checkpoints::hashInvalidCheckpoint != 0) + { + nPriority = 3000; + strStatusBar = strRPC = "WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."; + } + // Alerts CRITICAL_BLOCK(cs_mapAlerts) { @@ -3043,7 +3052,7 @@ public: }; -CBlock* CreateNewBlock(CWallet* pwallet) +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfWorkOnly) { CReserveKey reservekey(pwallet); @@ -3065,24 +3074,28 @@ CBlock* CreateNewBlock(CWallet* pwallet) // ppcoin: if coinstake available add coinstake tx static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift + 60; // only initialized at startup CBlockIndex* pindexPrev = pindexBest; - while (nLastCoinStakeCheckTime < GetAdjustedTime()) + + if (!fProofOfWorkOnly) { - pindexPrev = pindexBest; // get best block again to avoid getting stale - pblock->nBits = GetNextTargetRequired(pindexPrev, true); - static CCriticalSection cs; - CTransaction txCoinStake; - CRITICAL_BLOCK(cs) + while (nLastCoinStakeCheckTime < GetAdjustedTime()) { - // mining may have been suspended for a while so - // need to take max to satisfy the timestamp protocol - nLastCoinStakeCheckTime = max(++nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60)); - txCoinStake.nTime = nLastCoinStakeCheckTime; - } - if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake)) - { - pblock->vtx.push_back(txCoinStake); - pblock->vtx[0].vout[0].SetEmpty(); - break; + pindexPrev = pindexBest; // get best block again to avoid getting stale + pblock->nBits = GetNextTargetRequired(pindexPrev, true); + static CCriticalSection cs; + CTransaction txCoinStake; + CRITICAL_BLOCK(cs) + { + // mining may have been suspended for a while so + // need to take max to satisfy the timestamp protocol + nLastCoinStakeCheckTime = max(++nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60)); + txCoinStake.nTime = nLastCoinStakeCheckTime; + } + if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake)) + { + pblock->vtx.push_back(txCoinStake); + pblock->vtx[0].vout[0].SetEmpty(); + break; + } } } @@ -3361,8 +3374,11 @@ void static BitcoinMiner(CWallet *pwallet) // ppcoin: if proof-of-stake block found then process block if (pblock->IsProofOfStake()) { - // should be able to sign block - assert here for now - assert(pblock->SignBlock(*pwalletMain)); + if (!pblock->SignBlock(*pwalletMain)) + { + error("BitcoinMiner: Unable to sign new proof-of-stake block"); + return; + } printf("BitcoinMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str()); SetThreadPriority(THREAD_PRIORITY_NORMAL); CheckWork(pblock.get(), *pwalletMain, reservekey); @@ -3413,8 +3429,11 @@ void static BitcoinMiner(CWallet *pwallet) // Found a solution pblock->nNonce = ByteReverse(nNonceFound); assert(hash == pblock->GetHash()); - // should be able to sign block - assert here for now - assert(pblock->SignBlock(*pwalletMain)); + if (!pblock->SignBlock(*pwalletMain)) + { + error("BitcoinMiner: Unable to sign new proof-of-work block"); + return; + } SetThreadPriority(THREAD_PRIORITY_NORMAL); CheckWork(pblock.get(), *pwalletMain, reservekey);