aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-08-25 10:01:28 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-08-25 10:37:40 +0200
commit11270ebde4b27f9df7e2098b647e406079e5fb1d (patch)
treea1074d48dd2d6d6d96af18bd10f0cce362cbc2ad /src
parent41abb021227568b321be8073eeebb0b9ab654639 (diff)
parentda2ec100f3681176f60dec6dc675fc64147ade3a (diff)
Merge pull request #4351
da2ec10 Add a getutxos command to the p2p protocol. It allows querying of the UTXO set given a set of outpoints. (Mike Hearn)
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp86
-rw-r--r--src/net.cpp2
-rw-r--r--src/protocol.h1
-rw-r--r--src/version.h2
4 files changed, 89 insertions, 2 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 01f3e06a60..d8d3096c46 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>
@@ -3521,6 +3522,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();
@@ -3869,6 +3939,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;
diff --git a/src/net.cpp b/src/net.cpp
index 2443740c45..cae9b70da7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -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] = {};
diff --git a/src/protocol.h b/src/protocol.h
index d7565584af..94d313e9c0 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -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
diff --git a/src/version.h b/src/version.h
index 85c5dbf8d7..fbb731c91d 100644
--- a/src/version.h
+++ b/src/version.h
@@ -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;