From edd5d09d72eacc3fdbc5134dc680364c6bcabf49 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 11 Aug 2019 18:43:49 +0300 Subject: [PATCH] [Net/Core] Add getutxos message --- src/main.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/net.cpp | 2 +- src/protocol.h | 1 + src/version.h | 5 ++- 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e4deca4d..7660f5b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace std; using namespace boost; @@ -3765,6 +3766,73 @@ void static ProcessGetData(CNode* pfrom) pfrom->PushMessage("notfound", vNotFound); } } +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 &vOutPoints, bool fCheckMemPool, vector *result, vector *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 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) { @@ -4113,6 +4181,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushMessage("headers", vHeaders); } + else if (strCommand == "getutxos") + { + bool fCheckMemPool; + vector vOutPoints; + vRecv >> fCheckMemPool; + vRecv >> vOutPoints; + + vector bitmap; + vector 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"|| strCommand == "dstx") { diff --git a/src/net.cpp b/src/net.cpp index 028a2e22..55699377 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -45,7 +45,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu // Global state variables // bool fDiscover = true; -uint64_t nLocalServices = NODE_NETWORK; +uint64_t nLocalServices = NODE_NETWORK | NODE_GETUTXOS; CCriticalSection cs_mapLocalHost; map mapLocalHost; static bool vfReachable[NET_MAX] = {}; diff --git a/src/protocol.h b/src/protocol.h index df6d4d62..462f4c65 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -60,6 +60,7 @@ class CMessageHeader enum { NODE_NETWORK = (1 << 0), + NODE_GETUTXOS = (1 << 1), }; /** A CService with information about it as peer */ diff --git a/src/version.h b/src/version.h index 7d21e888..b635f0a0 100644 --- a/src/version.h +++ b/src/version.h @@ -30,7 +30,7 @@ static const int DATABASE_VERSION = 70509; // // network protocol versioning // -static const int PROTOCOL_VERSION = 62017; +static const int PROTOCOL_VERSION = 62018; // intial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -68,4 +68,7 @@ static const int BIP0031_VERSION = 60000; // "mempool" command, enhanced "getdata" behavior starts with this version: static const int MEMPOOL_GD_VERSION = 60002; +//getutxos p2p message support starts with this version: +static const int GETUTXOS_P2P_VERSION = 62018; + #endif