X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=f78133b535ce4fcab4dd0018f5488ff0fc0c7153;hb=882164196e5b1971313493f95a6d027f05e2ec92;hp=18d3c2f0ea8b36d739a8b39843ea17acededd20a;hpb=137d0685a45d4a02f5773652130704ad135e63f7;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 18d3c2f..f78133b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" @@ -52,6 +52,11 @@ multimap mapOrphanBlocksByPrev; map mapOrphanTransactions; multimap mapOrphanTransactionsByPrev; +// Constant stuff for coinbase transactions we create: +CScript COINBASE_FLAGS; + +const string strMessageMagic = "Bitcoin Signed Message:\n"; + double dHashesPerSec; int64 nHPSTimerStart; @@ -277,11 +282,8 @@ bool CTransaction::IsStandard() const // bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const { - if (fTestNet) - return true; // Allow non-standard on testnet - if (IsCoinBase()) - return true; // Coinbases are allowed to have any input + return true; // Coinbases don't use vin normally for (int i = 0; i < vin.size(); i++) { @@ -293,18 +295,33 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const const CScript& prevScript = prev.scriptPubKey; if (!Solver(prevScript, whichType, vSolutions)) return false; + int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); + + // Transactions with extra stuff in their scriptSigs are + // non-standard. Note that this EvalScript() call will + // be quick, because if there are any operations + // beside "push data" in the scriptSig the + // IsStandard() call returns false + vector > stack; + if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0)) + return false; + if (whichType == TX_SCRIPTHASH) { - vector > stack; - - if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0)) - return false; if (stack.empty()) return false; CScript subscript(stack.back().begin(), stack.back().end()); - if (!::IsStandard(subscript)) + vector > vSolutions2; + txnouttype whichType2; + if (!Solver(subscript, whichType2, vSolutions2)) return false; + if (whichType2 == TX_SCRIPTHASH) + return false; + nArgsExpected += ScriptSigArgsExpected(whichType2, vSolutions2); } + + if (stack.size() != nArgsExpected) + return false; } return true; @@ -492,15 +509,18 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi { MapPrevTx mapInputs; map mapUnused; - if (!FetchInputs(txdb, mapUnused, false, false, mapInputs)) + bool fInvalid = false; + if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) { + if (fInvalid) + return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); if (pfMissingInputs) *pfMissingInputs = true; return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str()); } // Check for non-standard pay-to-script-hash in inputs - if (!AreInputsStandard(mapInputs)) + if (!AreInputsStandard(mapInputs) && !fTestNet) return error("AcceptToMemoryPool() : nonstandard transaction input"); // Note: if you modify this code to accept non-standard transactions, then @@ -543,8 +563,6 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) { - if (pfMissingInputs) - *pfMissingInputs = true; return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } } @@ -767,6 +785,11 @@ static const int64 nInterval = nTargetTimespan / nTargetSpacing; // unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) { + // Testnet has min-difficulty blocks + // after nTargetSpacing*2 time between blocks: + if (fTestNet && nTime > nTargetSpacing*2) + return bnProofOfWorkLimit.GetCompact(); + CBigNum bnResult; bnResult.SetCompact(nBase); while (nTime > 0 && bnResult < bnProofOfWorkLimit) @@ -781,16 +804,36 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) return bnResult.GetCompact(); } -unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) +unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock) { + unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact(); // Genesis block if (pindexLast == NULL) - return bnProofOfWorkLimit.GetCompact(); + return nProofOfWorkLimit; // Only change once per interval if ((pindexLast->nHeight+1) % nInterval != 0) + { + // Special rules for testnet after 15 Feb 2012: + if (fTestNet && pblock->nTime > 1329264000) + { + // If the new block's timestamp is more than 2* 10 minutes + // then allow mining of a min-difficulty block. + if (pblock->nTime - pindexLast->nTime > nTargetSpacing*2) + return nProofOfWorkLimit; + else + { + // Return the last non-special-min-difficulty-rules-block + const CBlockIndex* pindex = pindexLast; + while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit) + pindex = pindex->pprev; + return pindex->nBits; + } + } + return pindexLast->nBits; + } // Go back by what we want to be 14 days worth of blocks const CBlockIndex* pindexFirst = pindexLast; @@ -920,8 +963,14 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb) bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTestPool, - bool fBlock, bool fMiner, MapPrevTx& inputsRet) + bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid) { + // FetchInputs can return false either because we just haven't seen some inputs + // (in which case the transaction should be stored as an orphan) + // or because the transaction is malformed (in which case the transaction should + // be dropped). If tx is definitely invalid, fInvalid will be set to true. + fInvalid = false; + if (IsCoinBase()) return true; // Coinbase transactions have no inputs to fetch. @@ -977,7 +1026,12 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTes const CTxIndex& txindex = inputsRet[prevout.hash].first; const CTransaction& txPrev = inputsRet[prevout.hash].second; if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) + { + // Revisit this if/when transaction replacement is implemented and allows + // adding inputs: + fInvalid = true; return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + } } return true; @@ -1176,8 +1230,9 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) // To avoid being on the short end of a block-chain split, // don't do secondary validation of pay-to-script-hash transactions - // until blocks with timestamps after paytoscripthashtime: - int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", 1329264000); // Feb 15, 2012 + // until blocks with timestamps after paytoscripthashtime (see init.cpp for default). + // This code can be removed once a super-majority of the network has upgraded. + int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", std::numeric_limits::max()); bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime); //// issue here: it doesn't know the version @@ -1198,7 +1253,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) MapPrevTx mapInputs; if (!tx.IsCoinBase()) { - if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs)) + bool fInvalid; + if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid)) return false; if (fStrictPayToScriptHash) @@ -1527,7 +1583,7 @@ bool CBlock::AcceptBlock() int nHeight = pindexPrev->nHeight+1; // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev)) + if (nBits != GetNextWorkRequired(pindexPrev, this)) return DoS(100, error("AcceptBlock() : incorrect proof of work")); // Check timestamp against prev @@ -2069,7 +2125,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (!pfrom->fInbound) { // Advertise our address - if (addrLocalHost.IsRoutable() && !fUseProxy) + if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() && + !IsInitialBlockDownload()) { CAddress addr(addrLocalHost); addr.nTime = GetAdjustedTime(); @@ -2665,18 +2722,18 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Address refresh broadcast static int64 nLastRebroadcast; - if (GetTime() - nLastRebroadcast > 24 * 60 * 60) + if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { - nLastRebroadcast = GetTime(); CRITICAL_BLOCK(cs_vNodes) { BOOST_FOREACH(CNode* pnode, vNodes) { // Periodically clear setAddrKnown to allow refresh broadcasts - pnode->setAddrKnown.clear(); + if (nLastRebroadcast) + pnode->setAddrKnown.clear(); // Rebroadcast our address - if (addrLocalHost.IsRoutable() && !fUseProxy) + if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable()) { CAddress addr(addrLocalHost); addr.nTime = GetAdjustedTime(); @@ -2684,6 +2741,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } } } + nLastRebroadcast = GetTime(); } // Clear out old addresses periodically so it's not too much work at once @@ -3056,11 +3114,12 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // because we're already processing them in order of dependency map mapTestPoolTmp(mapTestPool); MapPrevTx mapInputs; - if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs)) + bool fInvalid; + if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) continue; - int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); - if (nFees < nMinFee) + int64 nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + if (nTxFees < nMinFee) continue; nTxSigOps += tx.GetP2SHSigOpCount(mapInputs); @@ -3077,6 +3136,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; + nFees += nTxFees; // Add transactions that depend on this one to the priority queue uint256 hash = tx.GetHash(); @@ -3105,7 +3165,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - pblock->nBits = GetNextWorkRequired(pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get()); pblock->nNonce = 0; return pblock.release();