[REST] /rest/block response with full tx details

- rest block request returns full unfolded tx details
- /rest/block/notxdetails/<HASH> returns block where transactions are only represented by its hash
This commit is contained in:
Jonas Schnelli 2014-11-28 20:32:52 +01:00
parent 0a1d03ca52
commit 73351c3686
3 changed files with 62 additions and 7 deletions

View file

@ -48,7 +48,7 @@ class RESTTest (BitcoinTestFramework):
assert_equal(json_obj['hash'], bb_hash) assert_equal(json_obj['hash'], bb_hash)
# do tx test # 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_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json")
json_obj = json.loads(json_string) json_obj = json.loads(json_string)
assert_equal(json_obj['txid'], tx_hash) assert_equal(json_obj['txid'], tx_hash)
@ -58,5 +58,32 @@ class RESTTest (BitcoinTestFramework):
assert_equal(response.status, 200) assert_equal(response.status, 200)
assert_greater_than(int(response.getheader('content-length')), 10) 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__': if __name__ == '__main__':
RESTTest ().main () RESTTest ().main ()

View file

@ -42,7 +42,7 @@ public:
}; };
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); 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) 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, static bool rest_block(AcceptedConnection* conn,
string& strReq, string& strReq,
map<string, string>& mapHeaders, map<string, string>& mapHeaders,
bool fRun) bool fRun,
bool showTxDetails)
{ {
vector<string> params; vector<string> params;
enum RetFormat rf = ParseDataFormat(params, strReq); enum RetFormat rf = ParseDataFormat(params, strReq);
@ -131,7 +132,7 @@ static bool rest_block(AcceptedConnection* conn,
} }
case RF_JSON: { case RF_JSON: {
Object objBlock = blockToJSON(block, pblockindex); Object objBlock = blockToJSON(block, pblockindex, showTxDetails);
string strJSON = write_string(Value(objBlock), false) + "\n"; string strJSON = write_string(Value(objBlock), false) + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true; return true;
@ -146,6 +147,22 @@ static bool rest_block(AcceptedConnection* conn,
return true; // continue to process further HTTP reqs on this cxn 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, static bool rest_tx(AcceptedConnection* conn,
string& strReq, string& strReq,
map<string, string>& mapHeaders, map<string, string>& mapHeaders,
@ -205,7 +222,8 @@ static const struct {
bool fRun); bool fRun);
} uri_prefixes[] = { } uri_prefixes[] = {
{"/rest/tx/", rest_tx}, {"/rest/tx/", rest_tx},
{"/rest/block/", rest_block}, {"/rest/block/notxdetails/", rest_block_notxdetails},
{"/rest/block/", rest_block_extended},
}; };
bool HTTPReq_REST(AcceptedConnection* conn, bool HTTPReq_REST(AcceptedConnection* conn,

View file

@ -16,6 +16,7 @@
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
double GetDifficulty(const CBlockIndex* blockindex) 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; Object result;
result.push_back(Pair("hash", block.GetHash().GetHex())); 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())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
Array txs; Array txs;
BOOST_FOREACH(const CTransaction&tx, block.vtx) 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("tx", txs));
result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("nonce", (uint64_t)block.nNonce));