diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 98 |
1 files changed, 90 insertions, 8 deletions
diff --git a/src/main.cpp b/src/main.cpp index d8f96ed2c3..947494ce62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,7 @@ #include <sstream> +#include <boost/dynamic_bitset.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -3233,7 +3234,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } uint64_t nRewind = blkdat.GetPos(); - while (blkdat.good() && !blkdat.eof()) { + while (!blkdat.eof()) { boost::this_thread::interruption_point(); blkdat.SetPos(nRewind); @@ -3517,6 +3518,75 @@ 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(); @@ -3564,7 +3634,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { - vRecv >> pfrom->strSubVer; + vRecv >> LIMITED_STRING(pfrom->strSubVer, 256); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } if (!vRecv.empty()) @@ -3865,6 +3935,22 @@ 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; @@ -3964,7 +4050,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> block; LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id); - // block.print(); CInv inv(MSG_BLOCK, block.GetHash()); pfrom->AddInventoryKnown(inv); @@ -4188,7 +4273,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (fDebug) { string strMsg; unsigned char ccode; string strReason; - vRecv >> strMsg >> ccode >> strReason; + vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111); ostringstream ss; ss << strMsg << " code " << itostr(ccode) << ": " << strReason; @@ -4199,10 +4284,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> hash; ss << ": hash " << hash.ToString(); } - // Truncate to reasonable length and sanitize before printing: - string s = ss.str(); - if (s.size() > 111) s.erase(111, string::npos); - LogPrint("net", "Reject %s\n", SanitizeString(s)); + LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); } } |