mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-30 06:51:08 +02:00
Merge #14353: REST: add blockhash call, fetch blockhash by height
42ff30ec6
[Docs] add short documentation for /rest/blockhashbyheight (Jonas Schnelli)579d418f7
[QA] add rest tests for /rest/blockhashbyheight/<HEIGHT>.<FORMAT> (Jonas Schnelli)eb9ef04c4
REST: add "blockhashbyheight" call, fetch blockhash by height (Jonas Schnelli) Pull request description: Completes the REST interface for trivial block exploring by adding a call that allows to fetch the blockhash in the main chain by a given height. Tree-SHA512: 94be9e56718f857279b11cc16dfa8d04f3b5a762e87ae54281b4d87247c71c844895f4944d5a47f09056bf851f4c4761ac4fbdbaaee957265d14de5c1c73e8d2
This commit is contained in:
@@ -39,6 +39,11 @@ With the /notxdetails/ option JSON response will only contain the transaction ha
|
|||||||
Given a block hash: returns <COUNT> amount of blockheaders in upward direction.
|
Given a block hash: returns <COUNT> amount of blockheaders in upward direction.
|
||||||
Returns empty if the block doesn't exist or it isn't in the active chain.
|
Returns empty if the block doesn't exist or it isn't in the active chain.
|
||||||
|
|
||||||
|
#### Blockhash by height
|
||||||
|
`GET /rest/blockhashbyheight/<HEIGHT>.<bin|hex|json>`
|
||||||
|
|
||||||
|
Given a height: returns hash of block in best-block-chain at height provided.
|
||||||
|
|
||||||
#### Chaininfos
|
#### Chaininfos
|
||||||
`GET /rest/chaininfo.json`
|
`GET /rest/chaininfo.json`
|
||||||
|
|
||||||
|
47
src/rest.cpp
47
src/rest.cpp
@@ -575,6 +575,52 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rest_blockhash_by_height(HTTPRequest* req,
|
||||||
|
const std::string& str_uri_part)
|
||||||
|
{
|
||||||
|
if (!CheckWarmup(req)) return false;
|
||||||
|
std::string height_str;
|
||||||
|
const RetFormat rf = ParseDataFormat(height_str, str_uri_part);
|
||||||
|
|
||||||
|
int32_t blockheight;
|
||||||
|
if (!ParseInt32(height_str, &blockheight) || blockheight < 0) {
|
||||||
|
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlockIndex* pblockindex = nullptr;
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
if (blockheight > chainActive.Height()) {
|
||||||
|
return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
|
||||||
|
}
|
||||||
|
pblockindex = chainActive[blockheight];
|
||||||
|
}
|
||||||
|
switch (rf) {
|
||||||
|
case RetFormat::BINARY: {
|
||||||
|
CDataStream ss_blockhash(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss_blockhash << pblockindex->GetBlockHash();
|
||||||
|
req->WriteHeader("Content-Type", "application/octet-stream");
|
||||||
|
req->WriteReply(HTTP_OK, ss_blockhash.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RetFormat::HEX: {
|
||||||
|
req->WriteHeader("Content-Type", "text/plain");
|
||||||
|
req->WriteReply(HTTP_OK, pblockindex->GetBlockHash().GetHex() + "\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RetFormat::JSON: {
|
||||||
|
req->WriteHeader("Content-Type", "application/json");
|
||||||
|
UniValue resp = UniValue(UniValue::VOBJ);
|
||||||
|
resp.pushKV("blockhash", pblockindex->GetBlockHash().GetHex());
|
||||||
|
req->WriteReply(HTTP_OK, resp.write() + "\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
const char* prefix;
|
const char* prefix;
|
||||||
bool (*handler)(HTTPRequest* req, const std::string& strReq);
|
bool (*handler)(HTTPRequest* req, const std::string& strReq);
|
||||||
@@ -587,6 +633,7 @@ static const struct {
|
|||||||
{"/rest/mempool/contents", rest_mempool_contents},
|
{"/rest/mempool/contents", rest_mempool_contents},
|
||||||
{"/rest/headers/", rest_headers},
|
{"/rest/headers/", rest_headers},
|
||||||
{"/rest/getutxos", rest_getutxos},
|
{"/rest/getutxos", rest_getutxos},
|
||||||
|
{"/rest/blockhashbyheight/", rest_blockhash_by_height},
|
||||||
};
|
};
|
||||||
|
|
||||||
void StartREST()
|
void StartREST()
|
||||||
|
@@ -198,7 +198,7 @@ class RESTTest (BitcoinTestFramework):
|
|||||||
self.nodes[0].generate(1) # generate block to not affect upcoming tests
|
self.nodes[0].generate(1) # generate block to not affect upcoming tests
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
self.log.info("Test the /block and /headers URIs")
|
self.log.info("Test the /block, /blockhashbyheight and /headers URIs")
|
||||||
bb_hash = self.nodes[0].getbestblockhash()
|
bb_hash = self.nodes[0].getbestblockhash()
|
||||||
|
|
||||||
# Check result if block does not exists
|
# Check result if block does not exists
|
||||||
@@ -237,6 +237,23 @@ class RESTTest (BitcoinTestFramework):
|
|||||||
# Check json format
|
# Check json format
|
||||||
block_json_obj = self.test_rest_request("/block/{}".format(bb_hash))
|
block_json_obj = self.test_rest_request("/block/{}".format(bb_hash))
|
||||||
assert_equal(block_json_obj['hash'], bb_hash)
|
assert_equal(block_json_obj['hash'], bb_hash)
|
||||||
|
assert_equal(self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']))['blockhash'], bb_hash)
|
||||||
|
|
||||||
|
# Check hex/bin format
|
||||||
|
resp_hex = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.HEX, ret_type=RetType.OBJ)
|
||||||
|
assert_equal(resp_hex.read().decode('utf-8').rstrip(), bb_hash)
|
||||||
|
resp_bytes = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.BIN, ret_type=RetType.BYTES)
|
||||||
|
blockhash = binascii.hexlify(resp_bytes[::-1]).decode('utf-8')
|
||||||
|
assert_equal(blockhash, bb_hash)
|
||||||
|
|
||||||
|
# Check invalid blockhashbyheight requests
|
||||||
|
resp = self.test_rest_request("/blockhashbyheight/abc", ret_type=RetType.OBJ, status=400)
|
||||||
|
assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: abc")
|
||||||
|
resp = self.test_rest_request("/blockhashbyheight/1000000", ret_type=RetType.OBJ, status=404)
|
||||||
|
assert_equal(resp.read().decode('utf-8').rstrip(), "Block height out of range")
|
||||||
|
resp = self.test_rest_request("/blockhashbyheight/-1", ret_type=RetType.OBJ, status=400)
|
||||||
|
assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: -1")
|
||||||
|
self.test_rest_request("/blockhashbyheight/", ret_type=RetType.OBJ, status=400)
|
||||||
|
|
||||||
# Compare with json block header
|
# Compare with json block header
|
||||||
json_obj = self.test_rest_request("/headers/1/{}".format(bb_hash))
|
json_obj = self.test_rest_request("/headers/1/{}".format(bb_hash))
|
||||||
|
Reference in New Issue
Block a user