X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=3552d4e7a16e2efc4c0568897bad40c8868fc98a;hb=756f57a7421019737c517577244d683b9a4d0d92;hp=b8b665ba37fc256487d3a5c902144e1bf5355d7f;hpb=bb2d1adf243226e21e4af203a510cb8a40a0cf73;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index b8b665b..3552d4e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,7 @@ unsigned int nTransactionsUpdated = 0; map mapNextTx; map mapBlockIndex; -set setStakeSeen; +set > setStakeSeen; uint256 hashGenesisBlock("0x000000006d52486334316794cc38ffeb7ebf35a7ebd661fd39f5f46b0d001575"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" @@ -45,7 +45,7 @@ CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes map mapOrphanBlocks; multimap mapOrphanBlocksByPrev; -set setStakeSeenOrphan; +set > setStakeSeenOrphan; map mapOrphanTransactions; multimap mapOrphanTransactionsByPrev; @@ -1081,10 +1081,6 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) if (!CheckBlock()) return false; - // ppcoin: coin stake tx must meet target protocol - if (IsProofOfStake() && !vtx[1].CheckProofOfStake(txdb, nBits)) - return error("ConnectBlock() : Block %s unable to meet hash target for coinstake", GetHash().ToString().c_str()); - //// issue here: it doesn't know the version unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size()); @@ -1308,7 +1304,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) // quantities so as to generate blocks faster, degrading the system back into // a proof-of-work situation. // -bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const +bool CTransaction::CheckProofOfStake(unsigned int nBits) const { CBigNum bnTargetPerCoinDay; bnTargetPerCoinDay.SetCompact(nBits); @@ -1320,13 +1316,19 @@ bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const const CTxIn& txin = vin[0]; // First try finding the previous transaction in database + CTxDB txdb("r"); CTransaction txPrev; CTxIndex txindex; if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) return false; // previous transaction not in main chain + txdb.Close(); if (nTime < txPrev.nTime) return false; // Transaction timestamp violation + // Verify signature + if (!VerifySignature(txPrev, *this, 0)) + return DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", GetHash().ToString().c_str())); + // Read block header CBlock block; if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) @@ -1342,7 +1344,7 @@ bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) return true; else - return false; + return DoS(100, error("CheckProofOfStake() : check target failed on coinstake %s", GetHash().ToString().c_str())); } // ppcoin: total coin age spent in transaction, in the unit of coin-days. @@ -1427,7 +1429,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) return error("AddToBlockIndex() : new CBlockIndex failed"); map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; if (pindexNew->fProofOfStake) - setStakeSeen.insert(pindexNew->prevoutStake); + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); pindexNew->phashBlock = &((*mi).first); map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); @@ -1512,6 +1514,10 @@ bool CBlock::CheckBlock() const if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift) return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); + // Check coinstake timestamp + if (IsProofOfStake() && GetBlockTime() > (int64)vtx[1].nTime + nMaxClockDrift) + return DoS(50, error("CheckBlock() : coinstake timestamp is too early")); + // Check transactions BOOST_FOREACH(const CTransaction& tx, vtx) { @@ -1551,19 +1557,14 @@ bool CBlock::AcceptBlock() CBlockIndex* pindexPrev = (*mi).second; int nHeight = pindexPrev->nHeight+1; - // ppcoin: check for coinstake duplicate - if (IsProofOfStake()) - { // check if coinstake is already connected; that would imply the owner - // of the coinstake sent multiple blocks with the same coinstake - CTxIndex txindex; - if (CTxDB("r").ReadTxIndex(vtx[1].GetHash(), txindex)) - return error("AcceptBlock() : block %s has duplicate coinstake %s", hash.ToString().c_str(), vtx[1].GetHash().ToString().c_str()); - } - // Check proof-of-work or proof-of-stake if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake())) return DoS(100, error("AcceptBlock() : incorrect proof-of-work/proof-of-stake")); + // ppcoin: coinstake tx must meet target protocol + if (IsProofOfStake() && !vtx[1].CheckProofOfStake(nBits)) + return error("AcceptBlock() : Block %s unable to meet hash target for coinstake", GetHash().ToString().c_str()); + // Check timestamp against prev if (GetBlockTime() <= pindexPrev->GetMedianTimePast() || GetBlockTime() + nMaxClockDrift < pindexPrev->GetBlockTime()) return error("AcceptBlock() : block's timestamp is too early"); @@ -1598,6 +1599,9 @@ bool CBlock::AcceptBlock() if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700)) pnode->PushInventory(CInv(MSG_BLOCK, hash)); + // ppcoin: check pending sync-checkpoint + Checkpoints::AcceptPendingSyncCheckpoint(hash); + return true; } @@ -1614,7 +1618,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 (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash)) - return error("ProcessBlock() : duplicate proof-of-stake (%s) for block %s", pblock->GetProofOfStake().ToString().c_str(), hash.ToString().c_str()); + 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 if (!pblock->CheckBlock()) @@ -1653,7 +1657,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)) - return error("ProcessBlock() : duplicate proof-of-stake (%s) for orphan block %s", pblock2->GetProofOfStake().ToString().c_str(), hash.ToString().c_str()); + 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()); } @@ -1836,6 +1840,13 @@ bool LoadBlockIndex(bool fAllowNew) return error("LoadBlockIndex() : writing genesis block to disk failed"); if (!block.AddToBlockIndex(nFile, nBlockPos)) return error("LoadBlockIndex() : genesis block not accepted"); + + // ppcoin: initialize synchronized checkpoint + CTxDB txdbc; + if (!txdbc.WriteSyncCheckpoint(hashGenesisBlock)) + return error("LoadBlockIndex() : failed to init sync checkpoint"); + txdbc.Close(); + Checkpoints::hashSyncCheckpoint = hashGenesisBlock; } return true; @@ -2161,6 +2172,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) item.second.RelayTo(pfrom); + // ppcoin: relay sync-checkpoint + CRITICAL_BLOCK(Checkpoints::cs_hashSyncCheckpoint) + if (!Checkpoints::checkpointMessage.IsNull()) + Checkpoints::checkpointMessage.RelayTo(pfrom); + pfrom->fSuccessfullyConnected = true; printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight); @@ -2574,6 +2590,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } } + else if (strCommand == "checkpoint") + { + CSyncCheckpoint checkpoint; + vRecv >> checkpoint; + + if (checkpoint.ProcessSyncCheckpoint(pfrom)) + { + // Relay + pfrom->hashCheckpointKnown = checkpoint.hashCheckpoint; + CRITICAL_BLOCK(cs_vNodes) + BOOST_FOREACH(CNode* pnode, vNodes) + checkpoint.RelayTo(pnode); + } + } else { @@ -3020,7 +3050,7 @@ CBlock* CreateNewBlock(CWallet* pwallet) pblock->vtx.push_back(txNew); // ppcoin: if coinstake available add coinstake tx - static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift; // only initialized at startup + static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift + 60; // only initialized at startup CBlockIndex* pindexPrev = pindexBest; while (nLastCoinStakeCheckTime < GetAdjustedTime()) { @@ -3030,7 +3060,9 @@ CBlock* CreateNewBlock(CWallet* pwallet) CTransaction txCoinStake; CRITICAL_BLOCK(cs) { - nLastCoinStakeCheckTime++; + // 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))