|
|
@ -20,6 +20,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <sstream> |
|
|
|
#include <sstream> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/dynamic_bitset.hpp> |
|
|
|
#include <boost/algorithm/string/replace.hpp> |
|
|
|
#include <boost/algorithm/string/replace.hpp> |
|
|
|
#include <boost/filesystem.hpp> |
|
|
|
#include <boost/filesystem.hpp> |
|
|
|
#include <boost/filesystem/fstream.hpp> |
|
|
|
#include <boost/filesystem/fstream.hpp> |
|
|
@ -3512,6 +3513,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) |
|
|
|
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RandAddSeedPerfmon(); |
|
|
|
RandAddSeedPerfmon(); |
|
|
@ -3860,6 +3930,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") |
|
|
|
else if (strCommand == "tx") |
|
|
|
{ |
|
|
|
{ |
|
|
|
vector<uint256> vWorkQueue; |
|
|
|
vector<uint256> vWorkQueue; |
|
|
|