Add a getutxos command to the p2p protocol. It allows querying of the UTXO set
given a set of outpoints.
This commit is contained in:
parent
36065cc529
commit
da2ec100f3
4 changed files with 89 additions and 2 deletions
86
src/main.cpp
86
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>
|
||||
|
@ -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)
|
||||
{
|
||||
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")
|
||||
{
|
||||
vector<uint256> vWorkQueue;
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace {
|
|||
//
|
||||
bool fDiscover = true;
|
||||
bool fListen = true;
|
||||
uint64_t nLocalServices = NODE_NETWORK;
|
||||
uint64_t nLocalServices = NODE_NETWORK | NODE_GETUTXOS;
|
||||
CCriticalSection cs_mapLocalHost;
|
||||
map<CNetAddr, LocalServiceInfo> mapLocalHost;
|
||||
static bool vfReachable[NET_MAX] = {};
|
||||
|
|
|
@ -64,6 +64,7 @@ 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
|
||||
|
|
|
@ -26,7 +26,7 @@ extern const std::string CLIENT_DATE;
|
|||
// network protocol versioning
|
||||
//
|
||||
|
||||
static const int PROTOCOL_VERSION = 70002;
|
||||
static const int PROTOCOL_VERSION = 70003;
|
||||
|
||||
// initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
|
|
Loading…
Reference in a new issue