Skip to content

Conversation

@aaron-hanson
Copy link
Contributor

Added a /rest/blockhash/.json endpoint, so that the user can fetch a block hash by height via REST (analogous to the 'getblockhash' RPC method).

For someone wanting to gather block or header data via REST only, there was no way to begin fetching blocks/headers at specific heights without knowing the block hashes at those heights. This endpoint might also come in handy for someone wanting to quickly verify a block existing at a specific height in the active chain.

@jonasschnelli
Copy link
Contributor

Nice. Thanks for contributing.
Concept ACK.

What holds you back in completing this with supporting hex/bin? Should be trivial.

@aaron-hanson
Copy link
Contributor Author

@jonasschnelli Yeah I noticed the hex/bin pattern but wasn't entirely sure if I should use those here too. I suppose I wasn't sure exactly what should be serialized in this case, as the other endpoints using bin/hex are serializing whole class/struct instances like CBlockHeader or CBlock, whereas this is a simple hash string. I can certainly add that support.

Thanks for taking a look!

@jonasschnelli
Copy link
Contributor

@aaron-hanson.
You can just create a data stream and push the hashes onto the stream. A rest client could save ~50% brutto bandwidth over a JSON/hexstring.

CDataStream ssFooBar(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << pindex->GetBlockHash();

@aaron-hanson aaron-hanson force-pushed the rest-blockhash-endpoint branch from 469317d to e02f4c3 Compare November 25, 2017 10:12
@aaron-hanson
Copy link
Contributor Author

Added bin/hex formats, associated tests and documentation.

Copy link
Contributor

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK. I agree it should be possible to query block by height.

There are only tests for successful calls. IMHO there should be tests for the errors too:

  • RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
  • RESTERR(req, HTTP_BAD_REQUEST, "Block height out of range: " + strHeight).

Another option would be to overload /rest/block/[hash|height].[bin,hex.json]. Note that json response includes the hash.

std::string strHex = HexStr(ssGetBlockHashResponse.begin(), ssGetBlockHashResponse.end()) + "\n";

req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of forming the stream, use req->WriteReply(HTTP_OK, pindex->GetBlockHash()->GetHex());?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was wondering about this...I had just followed the pattern for the other endpoints' hex formats. Directly writing the output of pindex->GetBlockHash().GetHex() reverses the order of the bytes as compared to HexStr(). I'm not sure which is correct?

@aaron-hanson
Copy link
Contributor Author

Another option would be to overload /rest/block/[hash|height].[bin,hex.json]. Note that json response includes the hash.

@promag - I thought about this too... After researching a bit I found an older issue (#6011) about essentially the same thing, but in RPC. I assumed from the opinions there that I should probably just add this blockhash endpoint and not overload the block endpoint.

@promag
Copy link
Contributor

promag commented Nov 26, 2017

As others say in #6011, it was possible to query block by height but with 2 calls. With REST call there is no way unless you walk back from the tip. Unless we want to mirror the RPC interface, I think overloading sounds cooler.

In that scenario, the difference between the 2 endpoints would be cache headers, since by hash the block is immutable but not by height (at least near the tip).

@promag
Copy link
Contributor

promag commented Nov 26, 2017

BTW nice first contribution.

Copy link
Contributor

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New tests looks good.

src/rest.cpp Outdated
return true;
}
default: {
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only json format? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nice catch...details!

@promag
Copy link
Contributor

promag commented Nov 27, 2017

utACK b026c5f. Needs squash.

@promag
Copy link
Contributor

promag commented Feb 3, 2018

Needs rebase.

@jnewbery
Copy link
Contributor

jnewbery commented Apr 3, 2018

@aaron-hanson - are you still working on this? It needs rebasing and squashing.

Suggest we close with 'up for grabs' if there's no activity on this PR soon.

@aaron-hanson
Copy link
Contributor Author

@jnewbery - ah sorry, for some reason I missed the previous comments... I'll squash/rebase and retest tonight.

Added a /rest/blockhash/<HEIGHT>.<bin|hex|json> endpoint, so that the user can fetch a block hash by height via REST (analogous to the 'getblockhash' RPC method).
@aaron-hanson aaron-hanson force-pushed the rest-blockhash-endpoint branch from b026c5f to 1323df9 Compare April 4, 2018 02:22
@aaron-hanson
Copy link
Contributor Author

@jnewbery @promag - squashed and rebased.

Copy link
Contributor

@jnewbery jnewbery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks great. Thanks for the contribution and the good tests.

There are a few code style nits, which I haven't commented on inline. Take a look at https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#coding-style. Notably:

  • variables should be snake case
  • switch code block should be indented
  • the then clause for if statements should either be on the same line or enclosed in braces.

(I realise that you were probably copying surrounding style, but new code should adhere to the style guildelines where possible.)

switch (rf) {
case RetFormat::BINARY: {
CDataStream ssGetBlockHashResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetBlockHashResponse << pindex->GetBlockHash();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the call to pindex->GetBlockHash() be refactored out of the switch statement, both to reduce code repetition and to minimise the scope of where cs_main is held?

self.nodes[0].generate(1) #generate block to not affect upcoming tests
self.sync_all()


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be aware of #12766, which completely refactors this test (and makes it much better IMO). That obviously conflicts heavily with this change.

@aaron-hanson
Copy link
Contributor Author

@jnewbery thanks for the tips! I should have time this week to make the style adjustments and do a new rebase.

@adamjonas
Copy link
Member

This was replaced by #14353. Up for grabs label can be removed.

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants