X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=e5fba9c0a11f7926cf246e2261db27b6bf2eed3d;hb=198415e788fcbde13f2c3a6132e8e2a27b1a7bb8;hp=473e5bf4f33d1495c484476abda73240f44c1ce0;hpb=50c7b7bccd85b440caec734cc2cca4a40fa8496b;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 473e5bf..e5fba9c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,7 +77,11 @@ const string strMessageMagic = "NovaCoin Signed Message:\n"; // Settings int64_t nTransactionFee = MIN_TX_FEE; -int64_t nMinimumInputValue = MIN_TX_FEE; +int64_t nMinimumInputValue = MIN_TXOUT_AMOUNT; + +// Ping and address broadcast intervals +int64_t nPingInterval = 30 * 60; +int64_t nBroadcastInterval = 24 * 60 * 60; extern enum Checkpoints::CPMode CheckpointsMode; @@ -135,7 +139,7 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, { if (!fConnect) { - // ppcoin: wallets need to refund inputs when disconnecting coinstake + // wallets need to refund inputs when disconnecting coinstake if (tx.IsCoinStake()) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@ -147,8 +151,6 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); - // Preloaded coins cache invalidation - fCoinsDataActual = false; } // notify wallets about a new best chain @@ -555,7 +557,7 @@ int64_t CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, enum G if(IsCoinStake()) { - // Enforce 0.01 as minimum fee for old approach or coinstake + // Enforce 0.01 as minimum fee for coinstake nMinTxFee = CENT; nMinRelayTxFee = CENT; } @@ -730,7 +732,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false, true, SIG_SWITCH_TIME < tx.nTime ? STRICT_FLAGS : SOFT_FLAGS)) + if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false, true, STRICT_FLAGS)) { return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } @@ -1032,13 +1034,13 @@ int64_t GetProofOfWorkReward(unsigned int nBits, int64_t nFees) // Human readable form: // // nSubsidy = 100 / (diff ^ 1/6) + // + // Please note that we're using bisection to find an approximate solutuion CBigNum bnLowerBound = CENT; CBigNum bnUpperBound = bnSubsidyLimit; while (bnLowerBound + CENT <= bnUpperBound) { CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2; - if (fDebug && GetBoolArg("-printcreation")) - printf("GetProofOfWorkReward() : lower=%" PRId64 " upper=%" PRId64 " mid=%" PRId64 "\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64()); if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget) bnUpperBound = bnMidValue; else @@ -1055,92 +1057,65 @@ int64_t GetProofOfWorkReward(unsigned int nBits, int64_t nFees) } // miner's coin stake reward based on nBits and coin age spent (coin-days) -int64_t GetProofOfStakeReward(int64_t nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly) +int64_t GetProofOfStakeReward(int64_t nCoinAge, unsigned int nBits, int64_t nTime, bool bCoinYearOnly) { int64_t nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN; - if(fTestNet || nTime > STAKE_SWITCH_TIME) - { - // Stage 2 of emission process is PoS-based. It will be active on mainNet since 20 Jun 2013. + // Stage 2 of emission process is mostly PoS-based. - CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - CBigNum bnTargetLimit = GetProofOfStakeLimit(0, nTime); - bnTargetLimit.SetCompact(bnTargetLimit.GetCompact()); + CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest + CBigNum bnTarget; + bnTarget.SetCompact(nBits); + CBigNum bnTargetLimit = GetProofOfStakeLimit(0, nTime); + bnTargetLimit.SetCompact(bnTargetLimit.GetCompact()); - // NovaCoin: A reasonably continuous curve is used to avoid shock to market + // 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 + bnUpperBound = bnRewardCoinYearLimit, // Upper interest bound is 100% per year + bnMidPart, bnRewardPart; - while (bnLowerBound + CENT <= bnUpperBound) - { - CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2; - if (fDebug && GetBoolArg("-printcreation")) - printf("GetProofOfStakeReward() : lower=%" PRId64 " upper=%" PRId64 " mid=%" PRId64 "\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64()); + while (bnLowerBound + CENT <= bnUpperBound) + { + CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2; - 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; - } + // + // 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) + // - if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget) - bnUpperBound = bnMidValue; - else - bnLowerBound = bnMidValue; - } + bnMidPart = bnMidValue * bnMidValue * bnMidValue; + bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit; - nRewardCoinYear = bnUpperBound.getuint64(); - nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE); - } - else - { - // Old creation amount per coin-year, 5% fixed stake mint rate - nRewardCoinYear = 5 * CENT; + if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget) + bnUpperBound = bnMidValue; + else + bnLowerBound = bnMidValue; } + nRewardCoinYear = bnUpperBound.getuint64(); + nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE); + if(bCoinYearOnly) return nRewardCoinYear; nSubsidy = nCoinAge * nRewardCoinYear * 33 / (365 * 33 + 8); - // Set reasonable reward limit for large inputs since 20 Oct 2013 + // Set reasonable reward limit for large inputs // // 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") && 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=%" PRId64 " nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits); + return nSubsidy; } @@ -1263,13 +1238,14 @@ bool IsInitialBlockDownload() return true; static int64_t nLastUpdate; static CBlockIndex* pindexLastBest; + int64_t nCurrentTime = GetTime(); if (pindexBest != pindexLastBest) { pindexLastBest = pindexBest; - nLastUpdate = GetTime(); + nLastUpdate = nCurrentTime; } - return (GetTime() - nLastUpdate < 10 && - pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60); + return (nCurrentTime - nLastUpdate < 10 && + pindexBest->GetBlockTime() < nCurrentTime - 24 * 60 * 60); } void static InvalidChainFound(CBlockIndex* pindexNew) @@ -1571,18 +1547,21 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, map Checkpoints::GetLastCheckpointTime()) + { + unsigned int nTxSize = GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); - unsigned int nTxSize = (nTime > VALIDATION_SWITCH_TIME || fTestNet) ? GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) : 0; + // coin stake tx earns reward instead of paying fee + uint64_t nCoinAge; + if (!GetCoinAge(txdb, nCoinAge)) + return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str()); - int64_t nReward = GetValueOut() - nValueIn; - int64_t nCalculatedReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee(1, false, GMF_BLOCK, nTxSize) + CENT; + int64_t nReward = GetValueOut() - nValueIn; + int64_t nCalculatedReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee(1, false, GMF_BLOCK, nTxSize) + CENT; - if (nReward > nCalculatedReward) - return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%" PRId64 " vs calculated=%" PRId64 ")", nReward, nCalculatedReward)); + if (nReward > nCalculatedReward) + return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%" PRId64 " vs calculated=%" PRId64 ")", nReward, nCalculatedReward)); + } } else { @@ -2213,7 +2192,9 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) hashPrevBestCoinBase = vtx[0].GetHash(); } - uiInterface.NotifyBlocksChanged(); + static int8_t counter = 0; + if( (++counter & 0x0F) == 0 || !IsInitialBlockDownload()) // repaint every 16 blocks if not in initial block download + uiInterface.NotifyBlocksChanged(); return true; } @@ -2225,38 +2206,31 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c // These are checks that are independent of context // that can be verified before saving an orphan block. + set uniqueTx; // tx hashes + unsigned int nSigOps = 0; // total sigops + // Size limits if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return DoS(100, error("CheckBlock() : size limits failed")); - // Check proof of work matches claimed amount - if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) - return DoS(50, error("CheckBlock() : proof of work failed")); - - // Check timestamp - if (GetBlockTime() > FutureDrift(GetAdjustedTime())) - return error("CheckBlock() : block timestamp too far in the future"); + bool fProofOfStake = IsProofOfStake(); // First transaction must be coinbase, the rest must not be - if (vtx.empty() || !vtx[0].IsCoinBase()) + if (!vtx[0].IsCoinBase()) return DoS(100, error("CheckBlock() : first tx is not coinbase")); - // Check coinbase timestamp - if (GetBlockTime() < PastDrift((int64_t)vtx[0].nTime)) - return DoS(50, error("CheckBlock() : coinbase timestamp is too late")); - - for (unsigned int i = 1; i < vtx.size(); i++) - { - if (vtx[i].IsCoinBase()) - return DoS(100, error("CheckBlock() : more than one coinbase")); + if (!vtx[0].CheckTransaction()) + return DoS(vtx[0].nDoS, error("CheckBlock() : CheckTransaction failed on coinbase")); - // Check transaction timestamp - if (GetBlockTime() < (int64_t)vtx[i].nTime) - return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); - } + uniqueTx.insert(vtx[0].GetHash()); + nSigOps += vtx[0].GetLegacySigOpCount(); - if (IsProofOfStake()) + if (fProofOfStake) { + // Proof-of-STake related checkings. Note that we know here that 1st transactions is coinstake. We don't need + // check the type of 1st transaction because it's performed earlier by IsProofOfStake() + + // nNonce must be zero for proof-of-stake blocks if (nNonce != 0) return DoS(100, error("CheckBlock() : non-zero nonce in proof-of-stake block")); @@ -2264,13 +2238,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c 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 (GetBlockTime() != (int64_t)vtx[1].nTime) return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%" PRId64 " nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); @@ -2278,30 +2245,63 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c // NovaCoin: check proof-of-stake block signature if (fCheckSig && !CheckBlockSignature()) return DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); + + if (!vtx[1].CheckTransaction()) + return DoS(vtx[1].nDoS, error("CheckBlock() : CheckTransaction failed on coinstake")); + + uniqueTx.insert(vtx[1].GetHash()); + nSigOps += vtx[1].GetLegacySigOpCount(); } + else + { + // Check proof of work matches claimed amount + if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + return DoS(50, error("CheckBlock() : proof of work failed")); - // Check transactions - BOOST_FOREACH(const CTransaction& tx, vtx) + // Check timestamp + if (GetBlockTime() > FutureDrift(GetAdjustedTime())) + return error("CheckBlock() : block timestamp too far in the future"); + + // Check coinbase timestamp + if (GetBlockTime() < PastDrift((int64_t)vtx[0].nTime)) + return DoS(50, error("CheckBlock() : coinbase timestamp is too late")); + } + + // Iterate all transactions starting from second for proof-of-stake block + // or first for proof-of-work block + for (unsigned int i = fProofOfStake ? 2 : 1; i < vtx.size(); i++) { + const CTransaction& tx = vtx[i]; + + // Reject coinbase transactions at non-zero index + if (tx.IsCoinBase()) + return DoS(100, error("CheckBlock() : coinbase at wrong index")); + + // Reject coinstake transactions at index != 1 + if (tx.IsCoinStake()) + return DoS(100, error("CheckBlock() : coinstake at wrong index")); + + // Check transaction timestamp + if (GetBlockTime() < (int64_t)tx.nTime) + return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); + + // Check transaction consistency if (!tx.CheckTransaction()) return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); + + // Add transaction hash into list of unique transaction IDs + uniqueTx.insert(tx.GetHash()); + + // Calculate sigops count + nSigOps += tx.GetLegacySigOpCount(); } // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: - set uniqueTx; - BOOST_FOREACH(const CTransaction& tx, vtx) - { - uniqueTx.insert(tx.GetHash()); - } if (uniqueTx.size() != vtx.size()) return DoS(100, error("CheckBlock() : duplicate transaction")); - unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, vtx) - { - nSigOps += tx.GetLegacySigOpCount(); - } + // Reject block if validation would consume too much resources. if (nSigOps > MAX_BLOCK_SIGOPS) return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); @@ -2309,7 +2309,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); - return true; } @@ -2362,7 +2361,7 @@ bool CBlock::AcceptBlock() // Write block to history file if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) return error("AcceptBlock() : out of disk space"); - unsigned int nFile = -1; + unsigned int nFile = std::numeric_limits::max(); unsigned int nBlockPos = 0; if (!WriteToDisk(nFile, nBlockPos)) return error("AcceptBlock() : WriteToDisk failed"); @@ -2481,6 +2480,25 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns return (nFound >= nRequired); } +bool static ReserealizeBlockSignature(CBlock* pblock) +{ + if (pblock->IsProofOfWork()) + { + pblock->vchBlockSig.clear(); + return true; + } + + return CKey::ReserealizeSignature(pblock->vchBlockSig); +} + +bool static IsCanonicalBlockSignature(CBlock* pblock) +{ + if (pblock->IsProofOfWork()) + return pblock->vchBlockSig.empty(); + + return IsDERSignature(pblock->vchBlockSig); +} + bool ProcessBlock(CNode* pfrom, CBlock* pblock) { // Check for duplicate @@ -2490,14 +2508,20 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) if (mapOrphanBlocks.count(hash)) return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str()); - // ppcoin: check proof-of-stake + // 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) && !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()); + // Strip the garbage from newly received blocks, if we found some + if (!IsCanonicalBlockSignature(pblock)) { + if (!ReserealizeBlockSignature(pblock)) + printf("WARNING: ProcessBlock() : ReserealizeBlockSignature FAILED\n"); + } + // Preliminary checks - if (!pblock->CheckBlock()) + if (!pblock->CheckBlock(true, true, (pblock->nTime > Checkpoints::GetLastCheckpointTime()))) return error("ProcessBlock() : CheckBlock FAILED"); // ppcoin: verify hash target and signature of coinstake tx @@ -2543,17 +2567,17 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) if (!mapBlockIndex.count(pblock->hashPrevBlock)) { printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); - CBlock* pblock2 = new CBlock(*pblock); // ppcoin: check proof-of-stake - if (pblock2->IsProofOfStake()) + if (pblock->IsProofOfStake()) { // 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) && !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()); + if (setStakeSeenOrphan.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) + return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str()); else - setStakeSeenOrphan.insert(pblock2->GetProofOfStake()); + setStakeSeenOrphan.insert(pblock->GetProofOfStake()); } + CBlock* pblock2 = new CBlock(*pblock); mapOrphanBlocks.insert(make_pair(hash, pblock2)); mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); @@ -2602,79 +2626,26 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) return true; } -// novacoin: attempt to generate suitable proof-of-stake -bool CBlock::SignBlock(CWallet& wallet) -{ - // if we are trying to sign - // something except proof-of-stake block template - if (!vtx[0].vout[0].IsEmpty()) - return false; - - // if we are trying to sign - // a complete proof-of-stake block - if (IsProofOfStake()) - return true; - - static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // startup timestamp - - CKey key; - CTransaction txCoinStake; - int64_t nSearchTime = txCoinStake.nTime; // search to current time - - if (nSearchTime > nLastCoinStakeSearchTime) - { - if (wallet.CreateCoinStake(wallet, nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake, key)) - { - if (txCoinStake.nTime >= max(pindexBest->GetMedianTimePast()+1, PastDrift(pindexBest->GetBlockTime()))) - { - // make sure coinstake would meet timestamp protocol - // as it would be the same as the block timestamp - vtx[0].nTime = nTime = txCoinStake.nTime; - nTime = max(pindexBest->GetMedianTimePast()+1, GetMaxTransactionTime()); - nTime = max(GetBlockTime(), PastDrift(pindexBest->GetBlockTime())); - - // we have to make sure that we have no future timestamps in - // our transactions set - for (vector::iterator it = vtx.begin(); it != vtx.end();) - if (it->nTime > nTime) { it = vtx.erase(it); } else { ++it; } - - vtx.insert(vtx.begin() + 1, txCoinStake); - hashMerkleRoot = BuildMerkleTree(); - - // append a signature to our block - return key.Sign(GetHash(), vchBlockSig); - } - } - nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime; - nLastCoinStakeSearchTime = nSearchTime; - } - - return false; -} - // ppcoin: check block signature bool CBlock::CheckBlockSignature() const { - if (IsProofOfWork()) - return true; + if (vchBlockSig.empty()) + return false; - vector vSolutions; txnouttype whichType; - - const CTxOut& txout = vtx[1].vout[1]; - - if (!Solver(txout.scriptPubKey, whichType, vSolutions)) + vector vSolutions; + if (!Solver(vtx[1].vout[1].scriptPubKey, whichType, vSolutions)) return false; + if (whichType == TX_PUBKEY) { valtype& vchPubKey = vSolutions[0]; CKey key; if (!key.SetPubKey(vchPubKey)) return false; - if (vchBlockSig.empty()) - return false; return key.Verify(GetHash(), vchBlockSig); } + return false; } @@ -2743,6 +2714,18 @@ FILE* AppendBlockFile(unsigned int& nFileRet) } } +void UnloadBlockIndex() +{ + mapBlockIndex.clear(); + setStakeSeen.clear(); + pindexGenesisBlock = NULL; + nBestHeight = 0; + nBestChainTrust = 0; + nBestInvalidTrust = 0; + hashBestChain = 0; + pindexBest = NULL; +} + bool LoadBlockIndex(bool fAllowNew) { if (fTestNet) @@ -3000,7 +2983,7 @@ bool LoadExternalBlockFile(FILE* fileIn) } } } - catch (std::exception &e) { + catch (const std::exception&) { printf("%s() : Deserialize or I/O error caught during load\n", BOOST_CURRENT_FUNCTION); } @@ -3911,7 +3894,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Keep-alive ping. We send a nonce of zero because we don't use it anywhere // right now. - if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { + if (pto->nLastSend && GetTime() - pto->nLastSend > nPingInterval && pto->vSend.empty()) { uint64_t nonce = 0; if (pto->nVersion > BIP0031_VERSION) pto->PushMessage("ping", nonce); @@ -3930,7 +3913,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Address refresh broadcast static int64_t nLastRebroadcast; - if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) + if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > nBroadcastInterval)) { { LOCK(cs_vNodes); @@ -4066,3 +4049,25 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } return true; } + + +class CMainCleanup +{ +public: + CMainCleanup() {} + ~CMainCleanup() { + // block headers + std::map::iterator it1 = mapBlockIndex.begin(); + for (; it1 != mapBlockIndex.end(); it1++) + delete (*it1).second; + mapBlockIndex.clear(); + + // orphan blocks + std::map::iterator it2 = mapOrphanBlocks.begin(); + for (; it2 != mapOrphanBlocks.end(); it2++) + delete (*it2).second; + mapOrphanBlocks.clear(); + + // orphan transactions + } +} instance_of_cmaincleanup; \ No newline at end of file