diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 7010edfcd..6982df5b1 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -17,10 +17,16 @@ Given a transaction hash: returns a transaction in binary, hex-encoded binary, o For full TX query capability, one must enable the transaction index via "txindex=1" command line / configuration option. #### Blocks +`GET /rest/block/tip.` `GET /rest/block/.` +`GET /rest/block/.` +`GET /rest/block/notxdetails/tip.` `GET /rest/block/notxdetails/.` +`GET /rest/block/notxdetails/.` Given a block hash: returns a block, in binary, hex-encoded binary or JSON formats. +You can give a block height instead of a hash. Height 0 is not available, +but can be negative to go back that many blocks from the tip. 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. diff --git a/src/rest.cpp b/src/rest.cpp index b81a6f9c5..95648c09b 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -205,14 +205,26 @@ static bool rest_block(HTTPRequest* req, const RetFormat rf = ParseDataFormat(hashStr, strURIPart); uint256 hash; - if (!ParseHashStr(hashStr, hash)) - return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); - + long int blockHeight = 0; + if (hashStr != "tip") { + blockHeight = hashStr.size() < 12 ? std::strtol(hashStr.c_str(), nullptr, 10) : 0; + if (blockHeight == 0 && !ParseHashStr(hashStr, hash)) + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash or block height: " + hashStr); + } CBlock block; CBlockIndex* pblockindex = nullptr; { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + if (blockHeight < 0) // negative block heights take us back from current tip + blockHeight += chainActive.Height(); + if (blockHeight > 0 && blockHeight <= chainActive.Height()) + pblockindex = chainActive[blockHeight]; + else if (blockHeight != 0) + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash or block height: " + hashStr); + else if (hashStr == "tip") + pblockindex = chainActive.Tip(); + else + pblockindex = LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index afa9de580..4efb8cd32 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -84,7 +84,7 @@ class RESTTest (BitcoinTestFramework): self.nodes[1].generatetoaddress(100, not_related_address) self.sync_all() - assert_equal(self.nodes[0].getbalance(), 50) + assert_equal(self.nodes[0].getbalance(), 1) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() @@ -200,17 +200,26 @@ class RESTTest (BitcoinTestFramework): self.log.info("Test the /block and /headers URIs") bb_hash = self.nodes[0].getbestblockhash() + bb_height = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['height'] # Check binary format response = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) assert_greater_than(int(response.getheader('content-length')), 80) response_bytes = response.read() + response2 = self.test_rest_request("/block/{}".format(bb_height), req_type=ReqType.BIN, ret_type=RetType.OBJ) + response2_bytes = response2.read() + assert_equal(response_bytes, response2_bytes) + + response3 = self.test_rest_request("/block/tip", req_type=ReqType.BIN, ret_type=RetType.OBJ) + response3_bytes = response3.read() + assert_equal(response_bytes, response3_bytes) + # Compare with block header response_header = self.test_rest_request("/headers/1/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) - assert_equal(int(response_header.getheader('content-length')), 80) + assert_equal(int(response_header.getheader('content-length')), 112) response_header_bytes = response_header.read() - assert_equal(response_bytes[:80], response_header_bytes) + assert_equal(response_bytes[:112], response_header_bytes) # Check block hex format response_hex = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) @@ -259,9 +268,9 @@ class RESTTest (BitcoinTestFramework): # Make 3 tx and mine them on node 1 txs = [] - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) + txs.append(self.nodes[0].sendtoaddress(not_related_address, 0.11)) + txs.append(self.nodes[0].sendtoaddress(not_related_address, 0.11)) + txs.append(self.nodes[0].sendtoaddress(not_related_address, 0.11)) self.sync_all() # Check that there are exactly 3 transactions in the TX memory pool before generating the block