diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 3b8b0db16..e1d5ac78b 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -24,11 +24,16 @@ By default, this endpoint will only search the mempool. To query for a confirmed transaction, 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. -Responds with 404 if the block doesn't exist. +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 2c4d47554..a44c2a2d7 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -202,16 +202,28 @@ 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; CBlockIndex* tip = nullptr; { LOCK(cs_main); tip = ::ChainActive().Tip(); - 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 a036dfc79..58e73e1d9 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -86,7 +86,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() @@ -209,6 +209,7 @@ class RESTTest (BitcoinTestFramework): self.log.info("Test the /block, /blockhashbyheight and /headers URIs") bb_hash = self.nodes[0].getbestblockhash() + bb_height = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['height'] # Check result if block does not exists assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), []) @@ -225,6 +226,14 @@ class RESTTest (BitcoinTestFramework): assert_greater_than(int(response.getheader('content-length')), BLOCK_HEADER_SIZE) 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')), BLOCK_HEADER_SIZE) @@ -284,9 +293,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