X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=a8b65a83a07663efd238bc84509d50bad457e7dd;hb=f3a172bdf16a3a316e34ad6335514f95b0ebf1e4;hp=d722b742bc4afabbd1321bc3de2636fc81d645b4;hpb=fc10774eb50b2b97c9b49f878dd6566635ecbab0;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index d722b74..a8b65a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,8 +29,8 @@ unsigned int nTransactionsUpdated = 0; map mapNextTx; map mapBlockIndex; -set setStakeSeen; -uint256 hashGenesisBlock("0x000000006d52486334316794cc38ffeb7ebf35a7ebd661fd39f5f46b0d001575"); +set > setStakeSeen; +uint256 hashGenesisBlock("0x000000007c82d1f0aa2896b01bf533a8cc26a1f44790be4ceb4ecde7bee24add"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" CBlockIndex* pindexGenesisBlock = NULL; @@ -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) { @@ -1589,6 +1595,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; } @@ -1605,12 +1614,16 @@ 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()) return error("ProcessBlock() : CheckBlock FAILED"); + // ppcoin: verify hash target and signature of coinstake tx + 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) { @@ -1624,11 +1637,15 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) CBigNum bnNewBlock; bnNewBlock.SetCompact(pblock->nBits); CBigNum bnRequired; - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (pblock->IsProofOfWork() && bnNewBlock > bnRequired) + if (pblock->IsProofOfWork()) + bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); + else + bnRequired = bnNewBlock; // TODO: Computer Min Stake Target Allowed + + if (bnNewBlock > bnRequired) { pfrom->Misbehaving(100); - return error("ProcessBlock() : block with too little proof-of-work"); + return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work"); } } @@ -1644,7 +1661,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()); } @@ -1789,20 +1806,19 @@ bool LoadBlockIndex(bool fAllowNew) // Genesis block const char* pszTimestamp = "MarketWatch 07/Nov/2011 Gold tops $1,790 to end at over six-week high"; CTransaction txNew; - txNew.nTime = 1325878371; + txNew.nTime = 1339538219; txNew.vin.resize(1); txNew.vout.resize(1); txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].nValue = GetProofOfWorkReward(bnProofOfWorkLimit.GetCompact()); - txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + txNew.vout[0].SetEmpty(); CBlock block; block.vtx.push_back(txNew); block.hashPrevBlock = 0; block.hashMerkleRoot = block.BuildMerkleTree(); block.nVersion = 1; - block.nTime = 1325882536; + block.nTime = 1339540307; block.nBits = bnProofOfWorkLimit.GetCompact(); - block.nNonce = 2081920190; + block.nNonce = 1281822831; if (fTestNet) { @@ -1815,7 +1831,7 @@ bool LoadBlockIndex(bool fAllowNew) printf("%s\n", block.GetHash().ToString().c_str()); printf("%s\n", hashGenesisBlock.ToString().c_str()); printf("%s\n", block.hashMerkleRoot.ToString().c_str()); - assert(block.hashMerkleRoot == uint256("0xc7311b56de266580cca65be108ae53d7100b5c3b17da8b1106044103abd7a521")); + assert(block.hashMerkleRoot == uint256("0x1557f46a17fcf8843dbe4c0c0edfd1d17eeff2c3c48d73a59d11f5d176e4b54d")); block.print(); assert(block.GetHash() == hashGenesisBlock); assert(block.CheckBlock()); @@ -1827,6 +1843,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; @@ -2152,6 +2175,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); @@ -2565,6 +2593,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 { @@ -3011,7 +3053,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()) { @@ -3021,7 +3063,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))