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 <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;
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace {
|
||||||
//
|
//
|
||||||
bool fDiscover = true;
|
bool fDiscover = true;
|
||||||
bool fListen = true;
|
bool fListen = true;
|
||||||
uint64_t nLocalServices = NODE_NETWORK;
|
uint64_t nLocalServices = NODE_NETWORK | NODE_GETUTXOS;
|
||||||
CCriticalSection cs_mapLocalHost;
|
CCriticalSection cs_mapLocalHost;
|
||||||
map<CNetAddr, LocalServiceInfo> mapLocalHost;
|
map<CNetAddr, LocalServiceInfo> mapLocalHost;
|
||||||
static bool vfReachable[NET_MAX] = {};
|
static bool vfReachable[NET_MAX] = {};
|
||||||
|
|
|
@ -64,6 +64,7 @@ class CMessageHeader
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
NODE_NETWORK = (1 << 0),
|
NODE_NETWORK = (1 << 0),
|
||||||
|
NODE_GETUTXOS = (1 << 1),
|
||||||
|
|
||||||
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
|
// 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
|
// 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
|
// 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
|
// initial proto version, to be increased after version/verack negotiation
|
||||||
static const int INIT_PROTO_VERSION = 209;
|
static const int INIT_PROTO_VERSION = 209;
|
||||||
|
|
Loading…
Reference in a new issue