Merge bitcoin/bitcoin#34074: A few followups after introducing /rest/blockpart/ endpoint

59b93f11e8 rest: print also HTTP response reason in case of an error (Roman Zeyde)
7fe94a0493 rest: add a test for unsuported `/blockpart/` request type (Roman Zeyde)
55d0d19b5c rest: deduplicate `interface_rest.py` negative tests (Roman Zeyde)
89eb531024 rest: update release notes for `/blockpart/` endpoint (Roman Zeyde)
41118e17f8 blockstorage: simplify partial block read validation (Roman Zeyde)
599effdeab rest: reformat `uri_prefixes` initializer list (Roman Zeyde)

Pull request description:

  The commits below should resolve a few leftovers from #33657.

ACKs for top commit:
  l0rinc:
    ACK 59b93f11e8
  hodlinator:
    re-ACK 59b93f11e8

Tree-SHA512: ae45e08edd315018e11283b354fb32f9658f5829c956554dc662a81c2e16397def7c3700e6354e0a91ff03c850def35638a69ec2668b7c015d25d6fed42b92bb
This commit is contained in:
merge-script
2025-12-17 15:09:15 +00:00
4 changed files with 23 additions and 20 deletions

View File

@@ -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/<BLOCK-HASH>.<bin|hex>?offset=<OFFSET>&size=<SIZE>`) has been introduced
for efficiently fetching a range of bytes from block `<BLOCK-HASH>`.

View File

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

View File

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

View File

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