diff --git a/doc/release-notes-33657.md b/doc/release-notes-33657.md index f9e6841bf74..a9821323356 100644 --- a/doc/release-notes-33657.md +++ b/doc/release-notes-33657.md @@ -1,5 +1,5 @@ New REST API ------------ -- A new REST API endpoint (`/rest/blockpart/BLOCKHASH.bin?offset=X&size=Y`) has been introduced - for efficiently fetching a range of bytes from block `BLOCKHASH`. +- A new REST API endpoint (`/rest/blockpart/.?offset=&size=`) has been introduced + for efficiently fetching a range of bytes from block ``. diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 8fc5f42db72..36dfe1e31fc 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -1091,7 +1091,7 @@ BlockManager::ReadRawBlockResult BlockManager::ReadRawBlock(const FlatFilePos& p if (block_part) { const auto [offset, size]{*block_part}; - if (size == 0 || offset >= blk_size || size > blk_size - offset) { + if (size == 0 || SaturatingAdd(offset, size) > blk_size) { return util::Unexpected{ReadRawError::BadPartRange}; // Avoid logging - offset/size come from untrusted REST input } filein.seek(offset, SEEK_CUR); diff --git a/src/rest.cpp b/src/rest.cpp index 06da3906649..b91b229a1f0 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1142,20 +1142,20 @@ static const struct { const char* prefix; bool (*handler)(const std::any& context, HTTPRequest* req, const std::string& strReq); } uri_prefixes[] = { - {"/rest/tx/", rest_tx}, - {"/rest/block/notxdetails/", rest_block_notxdetails}, - {"/rest/block/", rest_block_extended}, - {"/rest/blockpart/", rest_block_part}, - {"/rest/blockfilter/", rest_block_filter}, - {"/rest/blockfilterheaders/", rest_filter_header}, - {"/rest/chaininfo", rest_chaininfo}, - {"/rest/mempool/", rest_mempool}, - {"/rest/headers/", rest_headers}, - {"/rest/getutxos", rest_getutxos}, - {"/rest/deploymentinfo/", rest_deploymentinfo}, - {"/rest/deploymentinfo", rest_deploymentinfo}, - {"/rest/blockhashbyheight/", rest_blockhash_by_height}, - {"/rest/spenttxouts/", rest_spent_txouts}, + {"/rest/tx/", rest_tx}, + {"/rest/block/notxdetails/", rest_block_notxdetails}, + {"/rest/block/", rest_block_extended}, + {"/rest/blockpart/", rest_block_part}, + {"/rest/blockfilter/", rest_block_filter}, + {"/rest/blockfilterheaders/", rest_filter_header}, + {"/rest/chaininfo", rest_chaininfo}, + {"/rest/mempool/", rest_mempool}, + {"/rest/headers/", rest_headers}, + {"/rest/getutxos", rest_getutxos}, + {"/rest/deploymentinfo/", rest_deploymentinfo}, + {"/rest/deploymentinfo", rest_deploymentinfo}, + {"/rest/blockhashbyheight/", rest_blockhash_by_height}, + {"/rest/spenttxouts/", rest_spent_txouts}, }; void StartREST(const std::any& context) diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index be5bb78b10e..f27921692df 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -84,7 +84,7 @@ class RESTTest (BitcoinTestFramework): conn.request('POST', rest_uri, body) resp = conn.getresponse() - assert resp.status == status, f"Expected: {status}, Got: {resp.status} - Response: {str(resp.read())}" + assert resp.status == status, f"Expected: {status}, Got: {resp.status} ({resp.reason}) - Response: {str(resp.read())}" if ret_type == RetType.OBJ: return resp @@ -485,12 +485,15 @@ class RESTTest (BitcoinTestFramework): get_block_part(status=400, query_params={"offset": 0, "size": 0}) get_block_part(status=400, query_params={"offset": len(block_bin), "size": 0}) - get_block_part(status=400, query_params={"offset": len(block_bin) + 1, "size": 1}) get_block_part(status=400, query_params={"offset": len(block_bin), "size": 1}) get_block_part(status=400, query_params={"offset": len(block_bin) + 1, "size": 1}) get_block_part(status=400, query_params={"offset": 0, "size": len(block_bin) + 1}) - self.test_rest_request(f"/blockpart/{blockhash}", status=400, req_type=ReqType.JSON, ret_type=RetType.OBJ) + res = self.test_rest_request(f"/blockpart/{blockhash}", status=400, req_type=ReqType.BIN, ret_type=RetType.OBJ) + assert res.read().decode().startswith("Block part offset missing or invalid") + + res = self.test_rest_request(f"/blockpart/{blockhash}", query_params={"offset":0, "size":1}, status=400, req_type=ReqType.JSON, ret_type=RetType.OBJ) + assert res.read().decode().startswith("JSON output is not supported for this request type") self.log.info("Missing block data should cause REST API to fail")