diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bloom.h | 2 | ||||
-rw-r--r-- | src/chainparams.cpp | 3 | ||||
-rw-r--r-- | src/chainparamsbase.cpp | 3 | ||||
-rw-r--r-- | src/core.cpp | 4 | ||||
-rw-r--r-- | src/core.h | 48 | ||||
-rw-r--r-- | src/db.cpp | 2 | ||||
-rw-r--r-- | src/init.cpp | 12 | ||||
-rw-r--r-- | src/key.h | 2 | ||||
-rw-r--r-- | src/main.cpp | 276 | ||||
-rw-r--r-- | src/main.h | 81 | ||||
-rw-r--r-- | src/miner.cpp | 4 | ||||
-rw-r--r-- | src/net.cpp | 2 | ||||
-rw-r--r-- | src/pow.cpp | 48 | ||||
-rw-r--r-- | src/pow.h | 8 | ||||
-rw-r--r-- | src/protocol.h | 1 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 8 | ||||
-rw-r--r-- | src/qt/splashscreen.cpp | 1 | ||||
-rw-r--r-- | src/rpcblockchain.cpp | 10 | ||||
-rw-r--r-- | src/rpcdump.cpp | 6 | ||||
-rw-r--r-- | src/rpcmining.cpp | 2 | ||||
-rw-r--r-- | src/sync.cpp | 3 | ||||
-rw-r--r-- | src/test/DoS_tests.cpp | 6 | ||||
-rw-r--r-- | src/test/multisig_tests.cpp | 4 | ||||
-rw-r--r-- | src/txmempool.cpp | 7 | ||||
-rw-r--r-- | src/ui_interface.h | 6 | ||||
-rw-r--r-- | src/version.h | 2 | ||||
-rw-r--r-- | src/wallet.cpp | 99 | ||||
-rw-r--r-- | src/wallet.h | 58 |
28 files changed, 313 insertions, 395 deletions
diff --git a/src/bloom.h b/src/bloom.h index d0caf9e9fa..54d16d7126 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -60,7 +60,7 @@ public: // It should generally always be a random value (and is largely only exposed for unit testing) // nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK) CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn); - CBloomFilter() : isFull(true) {} + CBloomFilter() : isFull(true), isEmpty(false), nHashFuncs(0), nTweak(0), nFlags(0) {} IMPLEMENT_SERIALIZE ( diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f32d4ed235..ce99f268f3 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -5,10 +5,11 @@ #include "chainparams.h" -#include "assert.h" #include "random.h" #include "util.h" +#include <assert.h> + #include <boost/assign/list_of.hpp> using namespace std; diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 720e24c4a8..d1e19871c3 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -5,9 +5,10 @@ #include "chainparamsbase.h" -#include "assert.h" #include "util.h" +#include <assert.h> + #include <boost/assign/list_of.hpp> using namespace boost::assign; diff --git a/src/core.cpp b/src/core.cpp index 71d6fea610..e6636ae04f 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -12,14 +12,14 @@ std::string COutPoint::ToString() const return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); } -CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn) +CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn) { prevout = prevoutIn; scriptSig = scriptSigIn; nSequence = nSequenceIn; } -CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn) +CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn) { prevout = COutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; diff --git a/src/core.h b/src/core.h index e3ceac97aa..126e1baa98 100644 --- a/src/core.h +++ b/src/core.h @@ -26,13 +26,13 @@ class COutPoint { public: uint256 hash; - unsigned int n; + uint32_t n; COutPoint() { SetNull(); } - COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } + COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) - void SetNull() { hash = 0; n = (unsigned int) -1; } - bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); } + void SetNull() { hash = 0; n = (uint32_t) -1; } + bool IsNull() const { return (hash == 0 && n == (uint32_t) -1); } friend bool operator<(const COutPoint& a, const COutPoint& b) { @@ -57,12 +57,12 @@ class CInPoint { public: const CTransaction* ptx; - unsigned int n; + uint32_t n; CInPoint() { SetNull(); } - CInPoint(const CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } - void SetNull() { ptx = NULL; n = (unsigned int) -1; } - bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); } + CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; } + void SetNull() { ptx = NULL; n = (uint32_t) -1; } + bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } }; /** An input of a transaction. It contains the location of the previous @@ -74,15 +74,15 @@ class CTxIn public: COutPoint prevout; CScript scriptSig; - unsigned int nSequence; + uint32_t nSequence; CTxIn() { nSequence = std::numeric_limits<unsigned int>::max(); } - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); - CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max()); + CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<uint32_t>::max()); IMPLEMENT_SERIALIZE ( @@ -93,7 +93,7 @@ public: bool IsFinal() const { - return (nSequence == std::numeric_limits<unsigned int>::max()); + return (nSequence == std::numeric_limits<uint32_t>::max()); } friend bool operator==(const CTxIn& a, const CTxIn& b) @@ -217,17 +217,17 @@ private: void UpdateHash() const; public: - static const int CURRENT_VERSION=1; + static const int32_t CURRENT_VERSION=1; // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not // actually immutable; deserialization and assignment are implemented, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. - const int nVersion; + const int32_t nVersion; const std::vector<CTxIn> vin; const std::vector<CTxOut> vout; - const unsigned int nLockTime; + const uint32_t nLockTime; /** Construct a CTransaction that qualifies as IsNull() */ CTransaction(); @@ -238,11 +238,11 @@ public: CTransaction& operator=(const CTransaction& tx); IMPLEMENT_SERIALIZE( - READWRITE(*const_cast<int*>(&this->nVersion)); + READWRITE(*const_cast<int32_t*>(&this->nVersion)); nVersion = this->nVersion; READWRITE(*const_cast<std::vector<CTxIn>*>(&vin)); READWRITE(*const_cast<std::vector<CTxOut>*>(&vout)); - READWRITE(*const_cast<unsigned int*>(&nLockTime)); + READWRITE(*const_cast<uint32_t*>(&nLockTime)); if (fRead) UpdateHash(); ) @@ -284,10 +284,10 @@ public: /** A mutable version of CTransaction. */ struct CMutableTransaction { - int nVersion; + int32_t nVersion; std::vector<CTxIn> vin; std::vector<CTxOut> vout; - unsigned int nLockTime; + uint32_t nLockTime; CMutableTransaction(); CMutableTransaction(const CTransaction& tx); @@ -399,13 +399,13 @@ class CBlockHeader { public: // header - static const int CURRENT_VERSION=2; - int nVersion; + static const int32_t CURRENT_VERSION=2; + int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; + uint32_t nTime; + uint32_t nBits; + uint32_t nNonce; CBlockHeader() { diff --git a/src/db.cpp b/src/db.cpp index 8c139843a1..23d2cc988d 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -227,10 +227,10 @@ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL), activeTxn(NULL) { int ret; + fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); if (pszFile == NULL) return; - fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); bool fCreate = strchr(pszMode, 'c'); unsigned int nFlags = DB_THREAD; if (fCreate) diff --git a/src/init.cpp b/src/init.cpp index 7b1318654f..b8988f8b75 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -35,6 +35,7 @@ #include "compat/sanity.h" #include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/interprocess/sync/file_lock.hpp> #include <boost/thread.hpp> @@ -369,6 +370,14 @@ std::string LicenseInfo() "\n"; } +static void BlockNotifyCallback(const uint256& hashNewTip) +{ + std::string strCmd = GetArg("-blocknotify", ""); + + boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free +} + struct CImportingNow { CImportingNow() { @@ -1185,6 +1194,9 @@ bool AppInit2(boost::thread_group& threadGroup) #endif // !ENABLE_WALLET // ********************************************************* Step 9: import blocks + if (mapArgs.count("-blocknotify")) + uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); + // scan for better chains in the block chain database, that are not yet connected in the active best chain CValidationState state; if (!ActivateBestChain(state)) @@ -189,7 +189,7 @@ private: public: // Construct an invalid private key. - CKey() : fValid(false) { + CKey() : fValid(false), fCompressed(false) { LockObject(vch); } diff --git a/src/main.cpp b/src/main.cpp index de5730a388..4aebdadd3b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,6 @@ #include <sstream> -#include <boost/dynamic_bitset.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -733,53 +732,6 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in return nSigOps; } -int CMerkleTx::SetMerkleBranch(const CBlock* pblock) -{ - AssertLockHeld(cs_main); - CBlock blockTmp; - - if (pblock == NULL) { - CCoins coins; - if (pcoinsTip->GetCoins(GetHash(), coins)) { - CBlockIndex *pindex = chainActive[coins.nHeight]; - if (pindex) { - if (!ReadBlockFromDisk(blockTmp, pindex)) - return 0; - pblock = &blockTmp; - } - } - } - - if (pblock) { - // Update the tx's hashBlock - hashBlock = pblock->GetHash(); - - // Locate the transaction - for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++) - if (pblock->vtx[nIndex] == *(CTransaction*)this) - break; - if (nIndex == (int)pblock->vtx.size()) - { - vMerkleBranch.clear(); - nIndex = -1; - LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); - return 0; - } - - // Fill in merkle branch - vMerkleBranch = pblock->GetMerkleBranch(nIndex); - } - - // Is the tx in a block that's in the main chain - map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); - if (mi == mapBlockIndex.end()) - return 0; - CBlockIndex* pindex = (*mi).second; - if (!pindex || !chainActive.Contains(pindex)) - return 0; - - return chainActive.Height() - pindex->nHeight + 1; -} @@ -1029,58 +981,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return true; } - -int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const -{ - if (hashBlock == 0 || nIndex == -1) - return 0; - AssertLockHeld(cs_main); - - // Find the block it claims to be in - map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); - if (mi == mapBlockIndex.end()) - return 0; - CBlockIndex* pindex = (*mi).second; - if (!pindex || !chainActive.Contains(pindex)) - return 0; - - // Make sure the merkle branch connects to this block - if (!fMerkleVerified) - { - if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot) - return 0; - fMerkleVerified = true; - } - - pindexRet = pindex; - return chainActive.Height() - pindex->nHeight + 1; -} - -int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const -{ - AssertLockHeld(cs_main); - int nResult = GetDepthInMainChainINTERNAL(pindexRet); - if (nResult == 0 && !mempool.exists(GetHash())) - return -1; // Not in chain, not in mempool - - return nResult; -} - -int CMerkleTx::GetBlocksToMaturity() const -{ - if (!IsCoinBase()) - return 0; - return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); -} - - -bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee) -{ - CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee); -} - - // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { @@ -1388,10 +1288,8 @@ void Misbehaving(NodeId pnode, int howmuch) void static InvalidChainFound(CBlockIndex* pindexNew) { if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) - { pindexBestInvalid = pindexNew; - uiInterface.NotifyBlocksChanged(); - } + LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", @@ -1421,25 +1319,6 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state } } -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) -{ - block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - - // Updating time can change work required on testnet: - if (Params().AllowMinDifficultyBlocks()) - block.nBits = GetNextWorkRequired(pindexPrev, &block); -} - - - - - - - - - - - void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) { bool ret; @@ -1976,15 +1855,19 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; -// Connect a new block to chainActive. -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { +// Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock +// corresponding to pindexNew, to bypass loading it again from disk. +bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { assert(pindexNew->pprev == chainActive.Tip()); mempool.check(pcoinsTip); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; - if (!ReadBlockFromDisk(block, pindexNew)) - return state.Abort(_("Failed to read block")); + if (!pblock) { + if (!ReadBlockFromDisk(block, pindexNew)) + return state.Abort(_("Failed to read block")); + pblock = █ + } // Apply the block atomically to the chain state. int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime3; @@ -1992,7 +1875,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { { CCoinsViewCache view(*pcoinsTip, true); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); - if (!ConnectBlock(block, state, pindexNew, view)) { + if (!ConnectBlock(*pblock, state, pindexNew, view)) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); @@ -2011,7 +1894,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. list<CTransaction> txConflicted; - mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted); + mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted); mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); @@ -2021,8 +1904,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { SyncWithWallets(tx, NULL); } // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, &block); + BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { + SyncWithWallets(tx, pblock); } int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); @@ -2071,7 +1954,8 @@ static CBlockIndex* FindMostWorkChain() { } // Try to make some progress towards making pindexMostWork the active block. -static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) { +// pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. +static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) { AssertLockHeld(cs_main); bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -2086,14 +1970,15 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo // Build list of new blocks to connect. std::vector<CBlockIndex*> vpindexToConnect; vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); - while (pindexMostWork && pindexMostWork != pindexFork) { - vpindexToConnect.push_back(pindexMostWork); - pindexMostWork = pindexMostWork->pprev; + CBlockIndex *pindexIter = pindexMostWork; + while (pindexIter && pindexIter != pindexFork) { + vpindexToConnect.push_back(pindexIter); + pindexIter = pindexIter->pprev; } // Connect new blocks. BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect)) { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -2134,7 +2019,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo return true; } -bool ActivateBestChain(CValidationState &state) { +// Make the best chain active, in multiple steps. The result is either failure +// or an activated best chain. pblock is either NULL or a pointer to a block +// that is already loaded (to avoid loading it again from disk). +bool ActivateBestChain(CValidationState &state, CBlock *pblock) { CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexMostWork = NULL; do { @@ -2149,7 +2037,7 @@ bool ActivateBestChain(CValidationState &state) { if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork)) + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; pindexNewTip = chainActive.Tip(); @@ -2162,18 +2050,15 @@ bool ActivateBestChain(CValidationState &state) { uint256 hashNewTip = pindexNewTip->GetBlockHash(); // Relay inventory, but don't relay old inventory during initial block download. int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); + { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); - - std::string strCmd = GetArg("-blocknotify", ""); - if (!strCmd.empty()) { - boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free } + + uiInterface.NotifyBlockTip(hashNewTip); } - uiInterface.NotifyBlocksChanged(); } while(pindexMostWork != chainActive.Tip()); return true; @@ -2427,12 +2312,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"), REJECT_CHECKPOINT, "time-too-old"); } - bool fOverflow = false; - uint256 bnNewBlock; - bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow); - uint256 bnRequired; - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (fOverflow || bnNewBlock > bnRequired) + if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime)) { return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), REJECT_INVALID, "bad-diffbits"); @@ -2697,7 +2577,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, pblock)) return error("ProcessBlock() : ActivateBestChain failed"); return true; @@ -3137,7 +3017,7 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); - if (!ActivateBestChain(state)) + if (!ActivateBestChain(state, &block)) return error("LoadBlockIndex() : genesis block cannot be activated"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); @@ -3289,15 +3169,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) return nLoaded > 0; } - - - - - - - - - ////////////////////////////////////////////////////////////////////////////// // // CAlert @@ -3519,75 +3390,6 @@ void static ProcessGetData(CNode* pfrom) } } -struct CCoin { - uint32_t nTxVer; // Don't call this nVersion, that name has a special meaning inside IMPLEMENT_SERIALIZE - uint32_t nHeight; - CTxOut out; - - IMPLEMENT_SERIALIZE( - READWRITE(nTxVer); - READWRITE(nHeight); - READWRITE(out); - ) -}; - -bool ProcessGetUTXOs(const vector<COutPoint> &vOutPoints, bool fCheckMemPool, vector<unsigned char> *result, vector<CCoin> *resultCoins) -{ - // Defined by BIP 64. - // - // Allows a peer to retrieve the CTxOut structures corresponding to the given COutPoints. - // Note that this data is not authenticated by anything: this code could just invent any - // old rubbish and hand it back, with the peer being unable to tell unless they are checking - // the outpoints against some out of band data. - // - // Also the answer could change the moment after we give it. However some apps can tolerate - // this, because they're only using the result as a hint or are willing to trust the results - // based on something else. For example we may be a "trusted node" for the peer, or it may - // be checking the results given by several nodes for consistency, it may - // run the UTXOs returned against scriptSigs of transactions obtained elsewhere (after checking - // for a standard script form), and because the height in which the UTXO was defined is provided - // a client that has a map of heights to block headers (as SPV clients do, for recent blocks) - // can request the creating block via hash. - // - // IMPORTANT: Clients expect ordering to be preserved! - if (vOutPoints.size() > MAX_INV_SZ) - return error("message getutxos size() = %u", vOutPoints.size()); - - LogPrint("net", "getutxos for %d queries %s mempool\n", vOutPoints.size(), fCheckMemPool ? "with" : "without"); - - boost::dynamic_bitset<unsigned char> hits(vOutPoints.size()); - { - LOCK2(cs_main, mempool.cs); - CCoinsViewMemPool cvMemPool(*pcoinsTip, mempool); - CCoinsViewCache view(fCheckMemPool ? cvMemPool : *pcoinsTip); - for (size_t i = 0; i < vOutPoints.size(); i++) - { - CCoins coins; - uint256 hash = vOutPoints[i].hash; - if (view.GetCoins(hash, coins)) - { - mempool.pruneSpent(hash, coins); - if (coins.IsAvailable(vOutPoints[i].n)) - { - hits[i] = true; - // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if - // n is valid but points to an already spent output (IsNull). - CCoin coin; - coin.nTxVer = coins.nVersion; - coin.nHeight = coins.nHeight; - coin.out = coins.vout.at(vOutPoints[i].n); - assert(!coin.out.IsNull()); - resultCoins->push_back(coin); - } - } - } - } - - boost::to_block_range(hits, std::back_inserter(*result)); - return true; -} - - bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { RandAddSeedPerfmon(); @@ -3936,22 +3738,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } - else if (strCommand == "getutxos") - { - bool fCheckMemPool; - vector<COutPoint> vOutPoints; - vRecv >> fCheckMemPool; - vRecv >> vOutPoints; - - vector<unsigned char> bitmap; - vector<CCoin> outs; - if (ProcessGetUTXOs(vOutPoints, fCheckMemPool, &bitmap, &outs)) - pfrom->PushMessage("utxos", chainActive.Height(), chainActive.Tip()->GetBlockHash(), bitmap, outs); - else - Misbehaving(pfrom->GetId(), 20); - } - - else if (strCommand == "tx") { vector<uint256> vWorkQueue; diff --git a/src/main.h b/src/main.h index fae8990d20..6b78356642 100644 --- a/src/main.h +++ b/src/main.h @@ -14,6 +14,7 @@ #include "coins.h" #include "core.h" #include "net.h" +#include "pow.h" #include "script.h" #include "sync.h" #include "txmempool.h" @@ -160,11 +161,9 @@ std::string GetWarnings(std::string strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState &state); +bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL); int64_t GetBlockValue(int nHeight, int64_t nFees); -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); - /** Create a new block index entry for a given block hash */ CBlockIndex * InsertBlockIndex(uint256 hash); /** Verify a signature */ @@ -329,7 +328,7 @@ private: int nHashType; public: - CScriptCheck() {} + CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), nHashType(0) {} CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { } @@ -345,66 +344,6 @@ public: } }; -/** A transaction with a merkle branch linking it to the block chain. */ -class CMerkleTx : public CTransaction -{ -private: - int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const; - -public: - uint256 hashBlock; - std::vector<uint256> vMerkleBranch; - int nIndex; - - // memory only - mutable bool fMerkleVerified; - - - CMerkleTx() - { - Init(); - } - - CMerkleTx(const CTransaction& txIn) : CTransaction(txIn) - { - Init(); - } - - void Init() - { - hashBlock = 0; - nIndex = -1; - fMerkleVerified = false; - } - - - IMPLEMENT_SERIALIZE - ( - nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action); - nVersion = this->nVersion; - READWRITE(hashBlock); - READWRITE(vMerkleBranch); - READWRITE(nIndex); - ) - - - int SetMerkleBranch(const CBlock* pblock=NULL); - - // Return depth of transaction in blockchain: - // -1 : not in blockchain, and not in memory pool (conflicted transaction) - // 0 : in memory pool, waiting to be included in a block - // >=1 : this many blocks deep in the main chain - int GetDepthInMainChain(CBlockIndex* &pindexRet) const; - int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } - bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; } - int GetBlocksToMaturity() const; - bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true); -}; - - - - - /** Data structure that represents a partial merkle tree. * * It respresents a subset of the txid's of a known block, in a way that @@ -736,17 +675,7 @@ public: uint256 GetBlockWork() const { - uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; + return GetProofIncrement(nBits); } enum { nMedianTimeSpan=11 }; @@ -887,7 +816,7 @@ private: unsigned char chRejectCode; bool corruptionPossible; public: - CValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {} + CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {} bool DoS(int level, bool ret = false, unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false) { diff --git a/src/miner.cpp b/src/miner.cpp index 8696edcf6e..96dc80a26d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -307,7 +307,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -540,7 +540,7 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: diff --git a/src/net.cpp b/src/net.cpp index e2adba8517..3966706207 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -67,7 +67,7 @@ namespace { // bool fDiscover = true; bool fListen = true; -uint64_t nLocalServices = NODE_NETWORK | NODE_GETUTXOS; +uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; map<CNetAddr, LocalServiceInfo> mapLocalHost; static bool vfReachable[NET_MAX] = {}; diff --git a/src/pow.cpp b/src/pow.cpp index b091cbec3d..893f6c18be 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -8,6 +8,7 @@ #include "chainparams.h" #include "core.h" #include "main.h" +#include "timedata.h" #include "uint256.h" #include "util.h" @@ -94,27 +95,58 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) } // -// minimum amount of work that could possibly be required nTime after -// minimum work required was nBase +// true if nBits is greater than the minimum amount of work that could +// possibly be required deltaTime after minimum work required was nBase // -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime) { + bool fOverflow = false; + uint256 bnNewBlock; + bnNewBlock.SetCompact(nBits, NULL, &fOverflow); + if (fOverflow) + return false; + const uint256 &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after Params().TargetSpacing()*2 time between blocks: - if (Params().AllowMinDifficultyBlocks() && nTime > Params().TargetSpacing()*2) - return bnLimit.GetCompact(); + if (Params().AllowMinDifficultyBlocks() && deltaTime > Params().TargetSpacing()*2) + return bnNewBlock <= bnLimit; uint256 bnResult; bnResult.SetCompact(nBase); - while (nTime > 0 && bnResult < bnLimit) + while (deltaTime > 0 && bnResult < bnLimit) { // Maximum 400% adjustment... bnResult *= 4; // ... in best-case exactly 4-times-normal target time - nTime -= Params().TargetTimespan()*4; + deltaTime -= Params().TargetTimespan()*4; } if (bnResult > bnLimit) bnResult = bnLimit; - return bnResult.GetCompact(); + + return bnNewBlock <= bnResult; +} + +void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) +{ + pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + + // Updating time can change work required on testnet: + if (Params().AllowMinDifficultyBlocks()) + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); +} + +uint256 GetProofIncrement(unsigned int nBits) +{ + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; } @@ -17,7 +17,11 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); -/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime); +/** Check the work is more than the minimum a received block needs, without knowing its direct parent */ +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime); + +void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); + +uint256 GetProofIncrement(unsigned int nBits); #endif diff --git a/src/protocol.h b/src/protocol.h index 94d313e9c0..d7565584af 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -64,7 +64,6 @@ class CMessageHeader enum { NODE_NETWORK = (1 << 0), - NODE_GETUTXOS = (1 << 1), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 9c9ff5b3a1..738fb48ef8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -209,12 +209,6 @@ static void ShowProgress(ClientModel *clientmodel, const std::string &title, int Q_ARG(int, nProgress)); } -static void NotifyBlocksChanged(ClientModel *clientmodel) -{ - // This notification is too frequent. Don't trigger a signal. - // Don't remove it, though, as it might be useful later. -} - static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) { // Too noisy: qDebug() << "NotifyNumConnectionsChanged : " + QString::number(newNumConnections); @@ -234,7 +228,6 @@ void ClientModel::subscribeToCoreSignals() { // Connect signals to client uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); - uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); } @@ -243,7 +236,6 @@ void ClientModel::unsubscribeFromCoreSignals() { // Disconnect signals from client uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); - uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); } diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 1162e2d87f..5dd110b36a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -4,6 +4,7 @@ #include "splashscreen.h" +#include "version.h" #include "clientversion.h" #include "init.h" #include "ui_interface.h" diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index b71d5a0804..83fe629351 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -54,9 +54,11 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); - CMerkleTx txGen(block.vtx[0]); - txGen.SetMerkleBranch(&block); - result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); + int confirmations = -1; + // Only report confirmations if the block is on the main chain + if (chainActive.Contains(blockindex)) + confirmations = chainActive.Height() - blockindex->nHeight + 1; + result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); @@ -242,7 +244,7 @@ Value getblock(const Array& params, bool fHelp) "\nResult (for verbose = true):\n" "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" - " \"confirmations\" : n, (numeric) The number of confirmations\n" + " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index e68ddee040..c286626fd3 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -165,14 +165,14 @@ Value importaddress(const Array& params, bool fHelp) std::vector<unsigned char> data(ParseHex(params[0].get_str())); script = CScript(data.begin(), data.end()); } else { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); } string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); - // Whether to perform rescan after import + // Whether to perform rescan after import bool fRescan = true; if (params.size() > 2) fRescan = params[2].get_bool(); @@ -191,7 +191,7 @@ Value importaddress(const Array& params, bool fHelp) pwalletMain->MarkDirty(); if (!pwalletMain->AddWatchOnly(script)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); if (fRescan) { diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6e508abcda..e4a5bc4162 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -458,7 +458,7 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nNonce = 0; Array transactions; diff --git a/src/sync.cpp b/src/sync.cpp index e624a9ee84..066c1ca744 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -5,8 +5,11 @@ #include "sync.h" #include "util.h" +#include "utilstrencodings.h" #include <boost/foreach.hpp> +#include <boost/thread.hpp> +#include <stdio.h> #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 4ecf6e2535..8fa38c3605 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -107,11 +107,7 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, return CheckNBits(nbits2, time2, nbits1, time1); int64_t deltaTime = time2-time1; - uint256 required; - required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - uint256 have; - have.SetCompact(nbits2); - return (have <= required); + return CheckMinWork(nbits2, nbits1, deltaTime); } BOOST_AUTO_TEST_CASE(DoS_checknbits) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 2a0466e928..02c6d095f2 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -164,9 +164,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) // Tests Solver() that returns lists of keys that are // required to satisfy a ScriptPubKey // - // Also tests IsMine() and ExtractAddress() + // Also tests IsMine() and ExtractDestination() // - // Note: ExtractAddress for the multisignature transactions + // Note: ExtractDestination for the multisignature transactions // always returns false for this release, even if you have // one key that would satisfy an (a|b) or 2-of-3 keys needed // to spend an escrow transaction. diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 8af1f1c91b..238d5bab16 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -11,7 +11,8 @@ using namespace std; -CTxMemPoolEntry::CTxMemPoolEntry() +CTxMemPoolEntry::CTxMemPoolEntry(): + nFee(0), nTxSize(0), nTime(0), dPriority(0.0) { nHeight = MEMPOOL_HEIGHT; } @@ -345,7 +346,9 @@ public: }; -CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : minRelayFee(_minRelayFee) +CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : + nTransactionsUpdated(0), + minRelayFee(_minRelayFee) { // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number diff --git a/src/ui_interface.h b/src/ui_interface.h index b3df2b5a85..bbc8a203c9 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -78,9 +78,6 @@ public: /** Translate a message to the native language of the user. */ boost::signals2::signal<std::string (const char* psz)> Translate; - /** Block chain changed. */ - boost::signals2::signal<void ()> NotifyBlocksChanged; - /** Number of network connections changed. */ boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged; @@ -95,6 +92,9 @@ public: /** Show progress e.g. for verifychain */ boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; + + /** New block has been accepted */ + boost::signals2::signal<void (const uint256& hash)> NotifyBlockTip; }; extern CClientUIInterface uiInterface; diff --git a/src/version.h b/src/version.h index 3a6c0f3719..b87aa8258c 100644 --- a/src/version.h +++ b/src/version.h @@ -27,7 +27,7 @@ extern const std::string CLIENT_DATE; // network protocol versioning // -static const int PROTOCOL_VERSION = 70003; +static const int PROTOCOL_VERSION = 70002; // initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; diff --git a/src/wallet.cpp b/src/wallet.cpp index 786b2f6a92..18a5b3971c 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -2194,3 +2194,102 @@ CWalletKey::CWalletKey(int64_t nExpires) nTimeCreated = (nExpires ? GetTime() : 0); nTimeExpires = nExpires; } + +int CMerkleTx::SetMerkleBranch(const CBlock* pblock) +{ + AssertLockHeld(cs_main); + CBlock blockTmp; + + if (pblock == NULL) { + CCoins coins; + if (pcoinsTip->GetCoins(GetHash(), coins)) { + CBlockIndex *pindex = chainActive[coins.nHeight]; + if (pindex) { + if (!ReadBlockFromDisk(blockTmp, pindex)) + return 0; + pblock = &blockTmp; + } + } + } + + if (pblock) { + // Update the tx's hashBlock + hashBlock = pblock->GetHash(); + + // Locate the transaction + for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++) + if (pblock->vtx[nIndex] == *(CTransaction*)this) + break; + if (nIndex == (int)pblock->vtx.size()) + { + vMerkleBranch.clear(); + nIndex = -1; + LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); + return 0; + } + + // Fill in merkle branch + vMerkleBranch = pblock->GetMerkleBranch(nIndex); + } + + // Is the tx in a block that's in the main chain + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !chainActive.Contains(pindex)) + return 0; + + return chainActive.Height() - pindex->nHeight + 1; +} + +int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const +{ + if (hashBlock == 0 || nIndex == -1) + return 0; + AssertLockHeld(cs_main); + + // Find the block it claims to be in + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !chainActive.Contains(pindex)) + return 0; + + // Make sure the merkle branch connects to this block + if (!fMerkleVerified) + { + if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot) + return 0; + fMerkleVerified = true; + } + + pindexRet = pindex; + return chainActive.Height() - pindex->nHeight + 1; +} + +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const +{ + AssertLockHeld(cs_main); + int nResult = GetDepthInMainChainINTERNAL(pindexRet); + if (nResult == 0 && !mempool.exists(GetHash())) + return -1; // Not in chain, not in mempool + + return nResult; +} + +int CMerkleTx::GetBlocksToMaturity() const +{ + if (!IsCoinBase()) + return 0; + return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); +} + + +bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee) +{ + CValidationState state; + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee); +} + diff --git a/src/wallet.h b/src/wallet.h index 052da24609..544b4f5bfb 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -457,6 +457,63 @@ struct COutputEntry int vout; }; +/** A transaction with a merkle branch linking it to the block chain. */ +class CMerkleTx : public CTransaction +{ +private: + int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const; + +public: + uint256 hashBlock; + std::vector<uint256> vMerkleBranch; + int nIndex; + + // memory only + mutable bool fMerkleVerified; + + + CMerkleTx() + { + Init(); + } + + CMerkleTx(const CTransaction& txIn) : CTransaction(txIn) + { + Init(); + } + + void Init() + { + hashBlock = 0; + nIndex = -1; + fMerkleVerified = false; + } + + + IMPLEMENT_SERIALIZE + ( + nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action); + nVersion = this->nVersion; + READWRITE(hashBlock); + READWRITE(vMerkleBranch); + READWRITE(nIndex); + ) + + + int SetMerkleBranch(const CBlock* pblock=NULL); + + // Return depth of transaction in blockchain: + // -1 : not in blockchain, and not in memory pool (conflicted transaction) + // 0 : in memory pool, waiting to be included in a block + // >=1 : this many blocks deep in the main chain + int GetDepthInMainChain(CBlockIndex* &pindexRet) const; + int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } + bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; } + int GetBlocksToMaturity() const; + bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true); +}; + + /** A transaction with a bunch of additional info that only the owner cares about. * It includes any unrecorded transactions needed to link it back to the block chain. */ @@ -905,6 +962,7 @@ public: strOtherAccount.clear(); strComment.clear(); nOrderPos = -1; + nEntryNo = 0; } IMPLEMENT_SERIALIZE |