X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=0801f2b301b55d3bdd5f8667f3c76efd02716d33;hb=74a7badde0d9ba0a888d30b46133de50a5267f61;hp=8a562ddcde201b5085c60f8f41616e7b83332a59;hpb=fb1190e5e897550e513f84c1b8f7ab45fdaad1d9;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 8a562dd..0801f2b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,7 +77,7 @@ int64 nHPSTimerStart; // Settings int64 nTransactionFee = MIN_TX_FEE; - +bool fStakeUsePooledKeys = false; ////////////////////////////////////////////////////////////////////////////// // @@ -1104,13 +1104,10 @@ int64 inline GetTargetSpacingWorkMax(int nHeight, unsigned int nTime) } // -// minimum amount of work that could possibly be required nTime after -// minimum work required was nBase +// maximum nBits value could possible be required nTime after // -unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) +unsigned int ComputeMaxBits(CBigNum bnTargetLimit, unsigned int nBase, int64 nTime) { - CBigNum bnTargetLimit = bnProofOfWorkLimit; - CBigNum bnResult; bnResult.SetCompact(nBase); bnResult *= 2; @@ -1125,6 +1122,25 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) return bnResult.GetCompact(); } +// +// minimum amount of work that could possibly be required nTime after +// minimum proof-of-work required was nBase +// +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) +{ + return ComputeMaxBits(bnProofOfWorkLimit, nBase, nTime); +} + +// +// minimum amount of stake that could possibly be required nTime after +// minimum proof-of-stake required was nBase +// +unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime) +{ + return ComputeMaxBits(GetProofOfStakeLimit(0, nBlockTime), nBase, nTime); +} + + // ppcoin: find last block index up to pindex const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake) { @@ -1585,8 +1601,8 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) { - // Check it again in case a previous version let a bad block in - if (!CheckBlock(!fJustCheck, !fJustCheck)) + // Check it again in case a previous version let a bad block in, but skip BlockSig checking + if (!CheckBlock(!fJustCheck, !fJustCheck, false)) return false; // Do not allow blocks that contain transactions which 'overwrite' older transactions, @@ -2042,7 +2058,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust(); // ppcoin: compute stake entropy bit for stake modifier - if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nHeight))) + if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nTime))) return error("AddToBlockIndex() : SetStakeEntropyBit() failed"); // ppcoin: record proof-of-stake hash value @@ -2099,7 +2115,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) -bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const +bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) const { // These are checks that are independent of context // that can be verified before saving an orphan block. @@ -2108,24 +2124,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const 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")); - // Special short-term limits to avoid 10,000 BDB lock limit: - if (GetBlockTime() < LOCKS_SWITCH_TIME) - { - // Rule is: #unique txids referenced <= 4,500 - // ... to prevent 10,000 BDB lock exhaustion on old clients - set setTxIn; - for (size_t i = 0; i < vtx.size(); i++) - { - setTxIn.insert(vtx[i].GetHash()); - if (i == 0) continue; // skip coinbase txin - BOOST_FOREACH(const CTxIn& txin, vtx[i].vin) - setTxIn.insert(txin.prevout.hash); - } - size_t nTxids = setTxIn.size(); - if (nTxids > 4500) - return error("CheckBlock() : maxlocks violation"); - } - // Check proof of work matches claimed amount if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) return DoS(50, error("CheckBlock() : proof of work failed")); @@ -2161,6 +2159,10 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const // Check coinstake timestamp if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); + + // NovaCoin: check proof-of-stake block signature + if (fCheckSig && !CheckBlockSignature(true)) + return DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); } else { @@ -2172,6 +2174,23 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const return DoS(50, error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")", vtx[0].GetValueOut(), GetProofOfWorkReward(nBits) - nFee)); + + // Should we check proof-of-work block signature or not? + // + // * Always skip on TestNet + // * Perform checking for the first 9689 blocks + // * Perform checking since last checkpoint until 20 Sep 2013 (will be removed after) + + if(!fTestNet && fCheckSig) + { + bool isAfterCheckpoint = (GetBlockTime() > Checkpoints::GetLastCheckpointTime()); + bool checkEntropySig = (GetBlockTime() < ENTROPY_SWITCH_TIME); + bool checkPoWSig = (isAfterCheckpoint && GetBlockTime() < CHAINCHECKS_SWITCH_TIME); + + // NovaCoin: check proof-of-work block signature + if ((checkEntropySig || checkPoWSig) && !CheckBlockSignature(false)) + return DoS(100, error("CheckBlock() : bad proof-of-work block signature")); + } } // Check transactions @@ -2207,12 +2226,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); - // NovaCoin: check proof-of-stake block signature - if (IsProofOfStake() || (!fTestNet && GetBlockTime() < CHAINCHECKS_SWITCH_TIME)) - { - if (!CheckBlockSignature()) - return DoS(100, error("CheckBlock() : bad block signature")); - } return true; } @@ -2248,18 +2261,9 @@ bool CBlock::AcceptBlock() if (!Checkpoints::CheckHardened(nHeight, hash)) return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lock-in at %d", nHeight)); - // ppcoin: check that the block satisfies synchronized checkpoint - if (!Checkpoints::CheckSync(hash, pindexPrev)) - { - if(!GetBoolArg("-nosynccheckpoints", false)) - { - return error("AcceptBlock() : rejected by synchronized checkpoint"); - } - else - { - strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!"); - } - } + // Check that the block satisfies synchronized checkpoint + if (!GetBoolArg("-nosynccheckpoints", false) && !Checkpoints::CheckSync(hash, pindexPrev)) + return error("AcceptBlock() : rejected by synchronized checkpoint"); // Enforce rule that the coinbase starts with serialized block height CScript expect = CScript() << nHeight; @@ -2410,8 +2414,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) // ppcoin: verify hash target and signature of coinstake tx if (pblock->IsProofOfStake()) { - uint256 hashProofOfStake = 0; - if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake)) + uint256 hashProofOfStake = 0, targetProofOfStake = 0; + if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake, targetProofOfStake)) { 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 @@ -2428,7 +2432,12 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) CBigNum bnNewBlock; bnNewBlock.SetCompact(pblock->nBits); CBigNum bnRequired; - bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime)); + + if (pblock->IsProofOfStake()) + bnRequired.SetCompact(ComputeMinStake(GetLastBlockIndex(pcheckpoint, true)->nBits, deltaTime, pblock->nTime)); + else + bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, false)->nBits, deltaTime)); + if (bnNewBlock > bnRequired) { if (pfrom) @@ -2563,7 +2572,7 @@ bool CBlock::SignBlock(const CKeyStore& keystore) } // ppcoin: check block signature -bool CBlock::CheckBlockSignature() const +bool CBlock::CheckBlockSignature(bool fProofOfStake) const { if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) return vchBlockSig.empty(); @@ -2571,7 +2580,7 @@ bool CBlock::CheckBlockSignature() const vector vSolutions; txnouttype whichType; - if(IsProofOfStake()) + if(fProofOfStake) { const CTxOut& txout = vtx[1].vout[1]; @@ -2965,9 +2974,10 @@ string GetWarnings(string strFor) strStatusBar = strMiscWarning; } - // ppcoin: should not enter safe mode for longer invalid chain - // ppcoin: if sync-checkpoint is too old do not enter safe mode - if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload()) + // * Should not enter safe mode for longer invalid chain + // * If sync-checkpoint is too old do not enter safe mode + // * Do not display warning if -nosynccheckpoints specified + if (!GetBoolArg("-nosynccheckpoints", false) && Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload()) { nPriority = 100; strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers."; @@ -2991,7 +3001,7 @@ string GetWarnings(string strFor) nPriority = alert.nPriority; strStatusBar = alert.strStatusBar; if (nPriority > 1000) - strRPC = strStatusBar; // ppcoin: safe mode for high alert + strRPC = strStatusBar; } } } @@ -3575,10 +3585,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (strCommand == "getaddr") { + // Don't return addresses older than nCutOff timestamp + int64 nCutOff = GetTime() - (nNodeLifespan * 24 * 60 * 60); pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); BOOST_FOREACH(const CAddress &addr, vAddr) - pfrom->PushAddress(addr); + if(addr.nTime > nCutOff) + pfrom->PushAddress(addr); } @@ -4106,8 +4119,6 @@ public: // fProofOfStake: try (best effort) to make a proof-of-stake block CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) { - CReserveKey reservekey(pwallet); - // Create new block auto_ptr pblock(new CBlock()); if (!pblock.get()) @@ -4118,7 +4129,14 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vout.resize(1); - txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + + if (!fProofOfStake) + { + CReserveKey reservekey(pwallet); + txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + } + else + txNew.vout[0].SetEmpty(); // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); @@ -4128,10 +4146,6 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - // Special compatibility rule before 20 Aug: limit size to 500,000 bytes: - if (GetAdjustedTime() < LOCKS_SWITCH_TIME) - nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN)); - // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); @@ -4167,7 +4181,6 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) 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); } @@ -4458,12 +4471,14 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) uint256 hash = pblock->GetHash(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - if (hash > hashTarget && pblock->IsProofOfWork()) - return error("BitcoinMiner : proof-of-work not meeting target"); + if(!pblock->IsProofOfWork()) + return error("CheckWork() : %s is not a proof-of-work block", hash.GetHex().c_str()); + + if (hash > hashTarget) + return error("CheckWork() : proof-of-work not meeting target"); //// debug print - printf("BitcoinMiner:\n"); - printf("new block found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + printf("CheckWork() : new proof-of-stake block found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); pblock->print(); printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); @@ -4471,7 +4486,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { LOCK(cs_main); if (pblock->hashPrevBlock != hashBestChain) - return error("BitcoinMiner : generated block is stale"); + return error("CheckWork() : generated block is stale"); // Remove key from key pool reservekey.KeepKey(); @@ -4484,7 +4499,44 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Process this block the same as if we had received it from another node if (!ProcessBlock(NULL, pblock)) - return error("BitcoinMiner : ProcessBlock, block not accepted"); + return error("CheckWork() : ProcessBlock, block not accepted"); + } + + return true; +} + +bool CheckStake(CBlock* pblock, CWallet& wallet) +{ + uint256 proofHash = 0, hashTarget = 0; + uint256 hash = pblock->GetHash(); + + if(!pblock->IsProofOfStake()) + return error("CheckStake() : %s is not a proof-of-stake block", hash.GetHex().c_str()); + + // verify hash target and signature of coinstake tx + if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, proofHash, hashTarget)) + return error("CheckStake() : proof-of-stake checking failed"); + + //// debug print + printf("CheckStake() : new proof-of-stake block found \n hash: %s \nproofhash: %s \ntarget: %s\n", hash.GetHex().c_str(), proofHash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + printf("out %s\n", FormatMoney(pblock->vtx[1].GetValueOut()).c_str()); + + // Found a solution + { + LOCK(cs_main); + if (pblock->hashPrevBlock != hashBestChain) + return error("CheckStake() : generated block is stale"); + + // Track how many getdata requests this block gets + { + LOCK(wallet.cs_wallet); + wallet.mapRequestCount[pblock->GetHash()] = 0; + } + + // Process this block the same as if we had received it from another node + if (!ProcessBlock(NULL, pblock)) + return error("CheckStake() : ProcessBlock, block not accepted"); } return true; @@ -4497,8 +4549,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) // Make this thread recognisable as the mining thread RenameThread("bitcoin-miner"); - // Each thread has its own key and counter - CReserveKey reservekey(pwallet); + // Each thread has its own counter unsigned int nExtraNonce = 0; while (fProofOfStake) @@ -4531,25 +4582,23 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) return; IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); - if (fProofOfStake) + if(pblock->IsProofOfStake()) { - // ppcoin: if proof-of-stake block found then process block - if (pblock->IsProofOfStake()) + // Trying to sign a block + if (!pblock->SignBlock(*pwalletMain)) { - if (!pblock->SignBlock(*pwalletMain)) - { - strMintWarning = strMintMessage; - continue; - } - strMintWarning = ""; - printf("StakeMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock.get(), *pwalletMain, reservekey); - SetThreadPriority(THREAD_PRIORITY_LOWEST); + strMintWarning = strMintMessage; + continue; } - Sleep(500); - continue; + + strMintWarning = ""; + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CheckStake(pblock.get(), *pwalletMain); + SetThreadPriority(THREAD_PRIORITY_LOWEST); } + + Sleep(500); + continue; } }