Merge pull request #5391

932ef50 [REST] JSON output: remove block infos from tx details if it is nested in block (Jonas Schnelli)
cae5486 [REST] added /rest/block/notxdetails/<hash> into REST-interface.md documentation (Jonas Schnelli)
73351c3 [REST] /rest/block response with full tx details (Jonas Schnelli)
This commit is contained in:
Wladimir J. van der Laan 2014-12-11 10:32:36 +01:00
commit 5e521d3e4e
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
4 changed files with 65 additions and 7 deletions

View file

@ -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

View file

@ -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 ()

View file

@ -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<string, string>& mapHeaders,
bool fRun)
bool fRun,
bool showTxDetails)
{
vector<string> 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<string, string>& mapHeaders,
bool fRun)
{
return rest_block(conn, strReq, mapHeaders, fRun, true);
}
static bool rest_block_notxdetails(AcceptedConnection* conn,
string& strReq,
map<string, string>& mapHeaders,
bool fRun)
{
return rest_block(conn, strReq, mapHeaders, fRun, false);
}
static bool rest_tx(AcceptedConnection* conn,
string& strReq,
map<string, string>& 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,

View file

@ -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, uint256(0), 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));