From 73351c3686094158c3a61f1f11126569c5c3ed3f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 28 Nov 2014 20:32:52 +0100 Subject: [PATCH 1/3] [REST] /rest/block response with full tx details - rest block request returns full unfolded tx details - /rest/block/notxdetails/ returns block where transactions are only represented by its hash --- qa/rpc-tests/rest.py | 29 ++++++++++++++++++++++++++++- src/rest.cpp | 26 ++++++++++++++++++++++---- src/rpcblockchain.cpp | 14 ++++++++++++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py index c62a96fbb..cb1868de3 100755 --- a/qa/rpc-tests/rest.py +++ b/qa/rpc-tests/rest.py @@ -48,7 +48,7 @@ class RESTTest (BitcoinTestFramework): assert_equal(json_obj['hash'], bb_hash) # do tx test - tx_hash = json_obj['tx'][0]; + tx_hash = json_obj['tx'][0]['txid']; json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) @@ -57,6 +57,33 @@ class RESTTest (BitcoinTestFramework): hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", True) assert_equal(response.status, 200) assert_greater_than(int(response.getheader('content-length')), 10) + + # check block tx details + # let's make 3 tx and mine them on node 1 + txs = [] + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + self.sync_all() + + # now mine the transactions + newblockhash = self.nodes[1].setgenerate(True, 1) + self.sync_all() + + #check if the 3 tx show up in the new block + json_string = http_get_call(url.hostname, url.port, '/rest/block/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') + json_obj = json.loads(json_string) + for tx in json_obj['tx']: + if not 'coinbase' in tx['vin'][0]: #exclude coinbase + assert_equal(tx['txid'] in txs, True) + + #check the same but without tx details + json_string = http_get_call(url.hostname, url.port, '/rest/block/notxdetails/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') + json_obj = json.loads(json_string) + for tx in txs: + assert_equal(tx in json_obj['tx'], True) + + if __name__ == '__main__': RESTTest ().main () diff --git a/src/rest.cpp b/src/rest.cpp index 6285784af..6329b44c5 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -42,7 +42,7 @@ public: }; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex); +extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); static RestErr RESTERR(enum HTTPStatusCode status, string message) { @@ -92,7 +92,8 @@ static bool ParseHashStr(const string& strReq, uint256& v) static bool rest_block(AcceptedConnection* conn, string& strReq, map& mapHeaders, - bool fRun) + bool fRun, + bool showTxDetails) { vector params; enum RetFormat rf = ParseDataFormat(params, strReq); @@ -131,7 +132,7 @@ static bool rest_block(AcceptedConnection* conn, } case RF_JSON: { - Object objBlock = blockToJSON(block, pblockindex); + Object objBlock = blockToJSON(block, pblockindex, showTxDetails); string strJSON = write_string(Value(objBlock), false) + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; @@ -146,6 +147,22 @@ static bool rest_block(AcceptedConnection* conn, return true; // continue to process further HTTP reqs on this cxn } +static bool rest_block_extended(AcceptedConnection* conn, + string& strReq, + map& mapHeaders, + bool fRun) +{ + return rest_block(conn, strReq, mapHeaders, fRun, true); +} + +static bool rest_block_notxdetails(AcceptedConnection* conn, + string& strReq, + map& mapHeaders, + bool fRun) +{ + return rest_block(conn, strReq, mapHeaders, fRun, false); +} + static bool rest_tx(AcceptedConnection* conn, string& strReq, map& mapHeaders, @@ -205,7 +222,8 @@ static const struct { bool fRun); } uri_prefixes[] = { {"/rest/tx/", rest_tx}, - {"/rest/block/", rest_block}, + {"/rest/block/notxdetails/", rest_block_notxdetails}, + {"/rest/block/", rest_block_extended}, }; bool HTTPReq_REST(AcceptedConnection* conn, diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 924f41690..778438775 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -16,6 +16,7 @@ using namespace json_spirit; using namespace std; +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); double GetDifficulty(const CBlockIndex* blockindex) @@ -50,7 +51,7 @@ double GetDifficulty(const CBlockIndex* blockindex) } -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); @@ -65,7 +66,16 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) - txs.push_back(tx.GetHash().GetHex()); + { + if(txDetails) + { + Object objTx; + TxToJSON(tx, block.GetHash(), objTx); + txs.push_back(objTx); + } + else + txs.push_back(tx.GetHash().GetHex()); + } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); From cae548685dc26c3be823f132ab88947175d19af6 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sat, 6 Dec 2014 10:54:09 +0100 Subject: [PATCH 2/3] [REST] added /rest/block/notxdetails/ into REST-interface.md documentation --- doc/REST-interface.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 05c532be5..0af650b4e 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -11,12 +11,15 @@ Given a transaction hash, Returns a transaction, in binary, hex-encoded binary or JSON formats. `GET /rest/block/BLOCK-HASH.{bin|hex|json}` +`GET /rest/block/notxdetails/BLOCK-HASH.{bin|hex|json}` Given a block hash, Returns a block, in binary, hex-encoded binary or JSON formats. The HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request. +With the /notxdetails/ option JSON response will only contain the transaction hash instead of the complete transaction details. The option only affects the JSON response. + For full TX query capability, one must enable the transaction index via "txindex=1" command line / configuration option. Risks From 932ef50f775b5f514941e6ee9dc91d0dcf89321f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sat, 6 Dec 2014 19:09:03 +0100 Subject: [PATCH 3/3] [REST] JSON output: remove block infos from tx details if it is nested in block --- src/rpcblockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 778438775..66e86ebac 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -70,7 +70,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe if(txDetails) { Object objTx; - TxToJSON(tx, block.GetHash(), objTx); + TxToJSON(tx, uint256(0), objTx); txs.push_back(objTx); } else