aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2015-04-28 10:02:45 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2015-04-28 10:07:25 +0200
commit6364408122210b2fa9f4e135783ff82636ef81c1 (patch)
treecc1737e3bfdae29485b3116606fe615d47680dfa /src
parentf9645ba80a004d87b9094b5348ab744e6c8d585e (diff)
parent1ec900a29e115503ca3a70eba28f2de33ca06228 (diff)
downloadbitcoin-6364408122210b2fa9f4e135783ff82636ef81c1.tar.xz
Merge pull request #5199
1ec900a Remove broken+useless lock/unlock log prints (Matt Corallo) 352ed22 Add merkle blocks test (Matt Corallo) 59ed61b Add RPC call to generate and verify merkle blocks (Matt Corallo) 30da90d Add CMerkleBlock constructor for tx set + block and an empty one (Matt Corallo)
Diffstat (limited to 'src')
-rw-r--r--src/merkleblock.cpp23
-rw-r--r--src/merkleblock.h5
-rw-r--r--src/rpcclient.cpp1
-rw-r--r--src/rpcrawtransaction.cpp114
-rw-r--r--src/rpcserver.cpp2
-rw-r--r--src/rpcserver.h2
-rw-r--r--src/sync.cpp5
7 files changed, 147 insertions, 5 deletions
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index c48d8cd508..dc87d0377a 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -37,6 +37,29 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
txn = CPartialMerkleTree(vHashes, vMatch);
}
+CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
+{
+ header = block.GetBlockHeader();
+
+ vector<bool> vMatch;
+ vector<uint256> vHashes;
+
+ vMatch.reserve(block.vtx.size());
+ vHashes.reserve(block.vtx.size());
+
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
+ {
+ const uint256& hash = block.vtx[i].GetHash();
+ if (txids.count(hash))
+ vMatch.push_back(true);
+ else
+ vMatch.push_back(false);
+ vHashes.push_back(hash);
+ }
+
+ txn = CPartialMerkleTree(vHashes, vMatch);
+}
+
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
if (height == 0) {
// hash at height 0 is the txids themself
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 52c914967f..d90face17c 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -139,6 +139,11 @@ public:
*/
CMerkleBlock(const CBlock& block, CBloomFilter& filter);
+ // Create from a CBlock, matching the txids in the set
+ CMerkleBlock(const CBlock& block, const std::set<uint256>& txids);
+
+ CMerkleBlock() {}
+
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 428e1049dc..ad676f9edc 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -79,6 +79,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendrawtransaction", 1 },
{ "gettxout", 1 },
{ "gettxout", 2 },
+ { "gettxoutproof", 0 },
{ "lockunspent", 0 },
{ "lockunspent", 1 },
{ "importprivkey", 2 },
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 8393a8502e..1e13f5dbba 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -9,6 +9,7 @@
#include "init.h"
#include "keystore.h"
#include "main.h"
+#include "merkleblock.h"
#include "net.h"
#include "rpcserver.h"
#include "script/script.h"
@@ -193,6 +194,119 @@ Value getrawtransaction(const Array& params, bool fHelp)
return result;
}
+Value gettxoutproof(const Array& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 1 && params.size() != 2))
+ throw runtime_error(
+ "gettxoutproof [\"txid\",...] ( blockhash )\n"
+ "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
+ "\nNOTE: By default this function only works sometimes. This is when there is an\n"
+ "unspent output in the utxo for this transaction. To make it always work,\n"
+ "you need to maintain a transaction index, using the -txindex command line option or\n"
+ "specify the block in which the transaction is included in manually (by blockhash).\n"
+ "\nReturn the raw transaction data.\n"
+ "\nArguments:\n"
+ "1. \"txids\" (string) A json array of txids to filter\n"
+ " [\n"
+ " \"txid\" (string) A transaction hash\n"
+ " ,...\n"
+ " ]\n"
+ "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n"
+ "\nResult:\n"
+ "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
+ );
+
+ set<uint256> setTxids;
+ uint256 oneTxid;
+ Array txids = params[0].get_array();
+ BOOST_FOREACH(Value& txid, txids) {
+ if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str());
+ uint256 hash(uint256S(txid.get_str()));
+ if (setTxids.count(hash))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str());
+ setTxids.insert(hash);
+ oneTxid = hash;
+ }
+
+ LOCK(cs_main);
+
+ CBlockIndex* pblockindex = NULL;
+
+ uint256 hashBlock;
+ if (params.size() > 1)
+ {
+ hashBlock = uint256S(params[1].get_str());
+ if (!mapBlockIndex.count(hashBlock))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ pblockindex = mapBlockIndex[hashBlock];
+ } else {
+ CCoins coins;
+ if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height())
+ pblockindex = chainActive[coins.nHeight];
+ }
+
+ if (pblockindex == NULL)
+ {
+ CTransaction tx;
+ if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
+ if (!mapBlockIndex.count(hashBlock))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
+ pblockindex = mapBlockIndex[hashBlock];
+ }
+
+ CBlock block;
+ if(!ReadBlockFromDisk(block, pblockindex))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+
+ unsigned int ntxFound = 0;
+ BOOST_FOREACH(const CTransaction&tx, block.vtx)
+ if (setTxids.count(tx.GetHash()))
+ ntxFound++;
+ if (ntxFound != setTxids.size())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block");
+
+ CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION);
+ CMerkleBlock mb(block, setTxids);
+ ssMB << mb;
+ std::string strHex = HexStr(ssMB.begin(), ssMB.end());
+ return strHex;
+}
+
+Value verifytxoutproof(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "verifytxoutproof \"proof\"\n"
+ "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
+ "and throwing an RPC error if the block is not in our best chain\n"
+ "\nArguments:\n"
+ "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
+ "\nResult:\n"
+ "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
+ );
+
+ CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ CMerkleBlock merkleBlock;
+ ssMB >> merkleBlock;
+
+ Array res;
+
+ vector<uint256> vMatch;
+ if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
+ return res;
+
+ LOCK(cs_main);
+
+ if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
+
+ BOOST_FOREACH(const uint256& hash, vMatch)
+ res.push_back(hash.GetHex());
+ return res;
+}
+
Value createrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 2)
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index e2df41fe21..61dda9125b 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -293,6 +293,8 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true },
{ "blockchain", "getrawmempool", &getrawmempool, true },
{ "blockchain", "gettxout", &gettxout, true },
+ { "blockchain", "gettxoutproof", &gettxoutproof, true },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, true },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
{ "blockchain", "verifychain", &verifychain, true },
diff --git a/src/rpcserver.h b/src/rpcserver.h
index c3200d8c35..790104f8c9 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -218,6 +218,8 @@ extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params,
extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value gettxoutproof(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value verifytxoutproof(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp
extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp);
diff --git a/src/sync.cpp b/src/sync.cpp
index e28caee8e7..a422939964 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -86,7 +86,6 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
if (lockstack.get() == NULL)
lockstack.reset(new LockStack);
- LogPrint("lock", "Locking: %s\n", locklocation.ToString());
dd_mutex.lock();
(*lockstack).push_back(std::make_pair(c, locklocation));
@@ -113,10 +112,6 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
static void pop_lock()
{
- if (fDebug) {
- const CLockLocation& locklocation = (*lockstack).rbegin()->second;
- LogPrint("lock", "Unlocked: %s\n", locklocation.ToString());
- }
dd_mutex.lock();
(*lockstack).pop_back();
dd_mutex.unlock();