X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=63e326e3960e7f49155357ea9d743e89e37a6770;hb=3176e0f244d929669aa3e1d81e0787d82d9150d3;hp=8a76b03feaa54ce0f9ca684fd4425db7b5ac1bb1;hpb=3b2f04b998fca87c3f5e57b6fbb78f01da699a34;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 8a76b03..63e326e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 The PPCoin developers +// Copyright (c) 2011-2013 The PPCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,8 @@ #include "net.h" #include "init.h" #include "ui_interface.h" +#include "kernel.h" +#include "scrypt_mine.h" #include #include #include @@ -31,8 +33,8 @@ unsigned int nTransactionsUpdated = 0; map mapBlockIndex; set > setStakeSeen; uint256 hashGenesisBlock = hashGenesisBlockOfficial; -CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); -CBigNum bnInitialHashTarget(~uint256(0) >> 20); +static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); +static CBigNum bnInitialHashTarget(~uint256(0) >> 20); unsigned int nStakeMinAge = STAKE_MIN_AGE; int nCoinbaseMaturity = COINBASE_MATURITY_PPC; CBlockIndex* pindexGenesisBlock = NULL; @@ -48,6 +50,7 @@ CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes map mapOrphanBlocks; multimap mapOrphanBlocksByPrev; set > setStakeSeenOrphan; +map mapProofOfStake; map mapOrphanTransactions; map > mapOrphanTransactionsByPrev; @@ -871,8 +874,7 @@ int64 GetProofOfStakeReward(int64 nCoinAge) } static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week -static const int64 nTargetSpacingStake = 10 * 60; // ten minutes -static const int64 nTargetSpacingWorkMax = 2 * 60 * 60; // two hours +static const int64 nTargetSpacingWorkMax = 12 * STAKE_TARGET_SPACING; // 2-hour // // minimum amount of work that could possibly be required nTime after @@ -920,7 +922,7 @@ unsigned int static GetNextTargetRequired(const CBlockIndex* pindexLast, bool fP // ppcoin: retarget with exponential moving toward target spacing CBigNum bnNew; bnNew.SetCompact(pindexPrev->nBits); - int64 nTargetSpacing = fProofOfStake? nTargetSpacingStake : min(nTargetSpacingWorkMax, nTargetSpacingStake * (1 + pindexLast->nHeight - pindexPrev->nHeight)); + int64 nTargetSpacing = fProofOfStake? STAKE_TARGET_SPACING : min(nTargetSpacingWorkMax, (int64) STAKE_TARGET_SPACING * (1 + pindexLast->nHeight - pindexPrev->nHeight)); int64 nInterval = nTargetTimespan / nTargetSpacing; bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); bnNew /= ((nInterval + 1) * nTargetSpacing); @@ -1351,15 +1353,17 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) // already refuses previously-known transaction id's entirely. // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC. // On testnet it is enabled as of februari 20, 2012, 0:00 UTC. - - BOOST_FOREACH(CTransaction& tx, vtx) + if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000)) { - CTxIndex txindexOld; - if (txdb.ReadTxIndex(tx.GetHash(), txindexOld)) + BOOST_FOREACH(CTransaction& tx, vtx) { - BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent) - if (pos.IsNull()) - return false; + CTxIndex txindexOld; + if (txdb.ReadTxIndex(tx.GetHash(), txindexOld)) + { + BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent) + if (pos.IsNull()) + return false; + } } } @@ -1677,69 +1681,6 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } -// ppcoin: coinstake must meet hash target according to the protocol: -// kernel (input 0) must meet the formula -// hash(nBits + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDay -// this ensures that the chance of getting a coinstake is proportional to the -// amount of coin age one owns. -// The reason this hash is chosen is the following: -// nBits: encodes all past block timestamps, making computing hash in advance -// more difficult -// txPrev.block.nTime: prevent nodes from guessing a good timestamp to -// generate transaction for future advantage -// txPrev.offset: offset of txPrev inside block, to reduce the chance of -// nodes generating coinstake at the same time -// txPrev.nTime: reduce the chance of nodes generating coinstake at the same -// time -// txPrev.vout.n: output number of txPrev, to reduce the chance of nodes -// generating coinstake at the same time -// block/tx hash should not be used here as they can be generated in vast -// quantities so as to generate blocks faster, degrading the system back into -// a proof-of-work situation. -// -bool CTransaction::CheckProofOfStake(unsigned int nBits) const -{ - CBigNum bnTargetPerCoinDay; - bnTargetPerCoinDay.SetCompact(nBits); - - if (!IsCoinStake()) - return true; - - // Kernel (input 0) must match the stake hash target per coin age (nBits) - 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, true, 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)) - return false; // unable to read block of previous transaction - if (block.GetBlockTime() + nStakeMinAge > nTime) - return false; // only count coins meeting min age requirement - - int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; - CBigNum bnCoinDay = CBigNum(nValueIn) * min(nTime-txPrev.nTime, (unsigned int)STAKE_MAX_AGE) / COIN / (24 * 60 * 60); - // Calculate hash - CDataStream ss(SER_GETHASH, 0); - ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime; - if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) - return true; - else - 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. // Only those coins meeting minimum age requirement counts. As those // transactions not in main chain are not currently indexed so we @@ -1820,11 +1761,8 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); if (!pindexNew) return error("AddToBlockIndex() : new CBlockIndex failed"); - map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - if (pindexNew->fProofOfStake) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - pindexNew->phashBlock = &((*mi).first); + pindexNew->phashBlock = &hash; map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); if (miPrev != mapBlockIndex.end()) { @@ -1835,6 +1773,35 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) // ppcoin: compute chain trust score pindexNew->bnChainTrust = (pindexNew->pprev ? pindexNew->pprev->bnChainTrust : 0) + pindexNew->GetBlockTrust(); + // ppcoin: compute stake entropy bit for stake modifier + if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit())) + return error("AddToBlockIndex() : SetStakeEntropyBit() failed"); + + // ppcoin: record proof-of-stake hash value + if (pindexNew->IsProofOfStake()) + { + if (!mapProofOfStake.count(hash)) + return error("AddToBlockIndex() : hashProofOfStake not found in map"); + pindexNew->hashProofOfStake = mapProofOfStake[hash]; + } + + // ppcoin: compute stake modifier + uint64 nStakeModifier = 0; + bool fGeneratedStakeModifier = false; + if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) + return error("AddToBlockIndex() : ComputeNextStakeModifier() failed"); + pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); + pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); + if (!CheckStakeModifierCheckpoints(pindexNew->nHeight, pindexNew->nStakeModifierChecksum)) + return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindexNew->nHeight, nStakeModifier); + + // Add to mapBlockIndex + map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + if (pindexNew->IsProofOfStake()) + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + pindexNew->phashBlock = &((*mi).first); + + // Write to disk block index CTxDB txdb; if (!txdb.TxnBegin()) return false; @@ -1902,8 +1869,8 @@ bool CBlock::CheckBlock() const 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")); + if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) + return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%u nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); // Check coinbase reward if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0)) @@ -2039,10 +2006,16 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) return error("ProcessBlock() : CheckBlock FAILED"); // ppcoin: verify hash target and signature of coinstake tx - if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits)) + if (pblock->IsProofOfStake()) { - printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str()); - return false; // do not error here as we expect this during initial block download + uint256 hashProofOfStake = 0; + if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake)) + { + printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str()); + return false; // do not error here as we expect this during initial block download + } + if (!mapProofOfStake.count(hash)) // add to mapProofOfStake + mapProofOfStake.insert(make_pair(hash, hashProofOfStake)); } CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint(); @@ -2245,6 +2218,10 @@ bool CBlock::CheckBlockSignature() const } + + + + bool CheckDiskSpace(uint64 nAdditionalBytes) { uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available; @@ -2313,8 +2290,8 @@ bool LoadBlockIndex(bool fAllowNew) nCoinbaseMaturity = 60; } - printf("%s Network: genesis=0x%s nBitsLimit=0x%08x nBitsInitial=0x%08x nStakeMinAge=%d nCoinbaseMaturity=%d\n", - fTestNet? "Test" : "NovaCoin", hashGenesisBlock.ToString().substr(0, 20).c_str(), bnProofOfWorkLimit.GetCompact(), bnInitialHashTarget.GetCompact(), nStakeMinAge, nCoinbaseMaturity); + printf("%s Network: genesis=0x%s nBitsLimit=0x%08x nBitsInitial=0x%08x nStakeMinAge=%d nCoinbaseMaturity=%d nModifierInterval=%d\n", + fTestNet? "Test" : "NovaCoin", hashGenesisBlock.ToString().substr(0, 20).c_str(), bnProofOfWorkLimit.GetCompact(), bnInitialHashTarget.GetCompact(), nStakeMinAge, nCoinbaseMaturity, nModifierInterval); // // Load block index @@ -2332,13 +2309,6 @@ bool LoadBlockIndex(bool fAllowNew) if (!fAllowNew) return false; - // Genesis Block: - // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) - // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) - // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) - // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) - // vMerkleTree: 4a5e1e - // Genesis block const char* pszTimestamp = "https://bitcointalk.org/index.php?topic=134179.msg1502196#msg1502196"; CTransaction txNew; @@ -2357,9 +2327,6 @@ bool LoadBlockIndex(bool fAllowNew) block.nNonce = 1575379; //// debug print - 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("0x4cb33b3b6a861dcbc685d3e614a9cafb945738d6833f182855679f2fad02057b")); block.print(); assert(block.GetHash() == hashGenesisBlock); @@ -2518,11 +2485,11 @@ string GetWarnings(string strFor) } // ppcoin: should not enter safe mode for longer invalid chain - // ppcoin: if sync-checkpoint too old enter safe mode - if (Checkpoints::IsMatureSyncCheckpoint() && !fTestNet) + // ppcoin: if sync-checkpoint is too old do not enter safe mode + if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet) { - nPriority = 2000; - strStatusBar = strRPC = "WARNING: Checkpoint is too old. Wait for block chain download, or notify developers."; + nPriority = 100; + strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers."; } // ppcoin: if detected invalid checkpoint enter safe mode @@ -3654,13 +3621,18 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) { pblock->nBits = GetNextTargetRequired(pindexPrev, true); CTransaction txCoinStake; - int64 nSearchTime = GetAdjustedTime(); + int64 nSearchTime = txCoinStake.nTime; // search to current time if (nSearchTime > nLastCoinStakeSearchTime) { if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake)) { - pblock->vtx.push_back(txCoinStake); - pblock->vtx[0].vout[0].SetEmpty(); + if (txCoinStake.nTime >= max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - nMaxClockDrift)) + { // make sure coinstake would meet timestamp protocol + // as it would be the same as the block timestamp + pblock->vtx[0].vout[0].SetEmpty(); + pblock->vtx[0].nTime = txCoinStake.nTime; + pblock->vtx.push_back(txCoinStake); + } } nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime; nLastCoinStakeSearchTime = nSearchTime; @@ -3755,7 +3727,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) continue; // Timestamp limit - if (tx.nTime > GetAdjustedTime()) + if (tx.nTime > GetAdjustedTime() || (pblock->IsProofOfStake() && tx.nTime > pblock->vtx[1].nTime)) continue; // ppcoin: simplify transaction fee - allow free = false @@ -3817,9 +3789,12 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + if (pblock->IsProofOfStake()) + pblock->nTime = pblock->vtx[1].nTime; //same as coinstake timestamp pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime()); pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); - pblock->UpdateTime(pindexPrev); + if (pblock->IsProofOfWork()) + pblock->UpdateTime(pindexPrev); pblock->nNonce = 0; return pblock.release(); @@ -3932,9 +3907,9 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) void static ThreadBitcoinMiner(void* parg); -bool fGenerateBitcoins = false; -bool fLimitProcessors = false; -int nLimitProcessors = -1; +static bool fGenerateBitcoins = false; +static bool fLimitProcessors = false; +static int nLimitProcessors = -1; void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) {