-
Notifications
You must be signed in to change notification settings - Fork 528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rosetta: Fast canonical lookups chain_status #9797
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,9 @@ module Block_query = struct | |
| Some index, Some hash -> | ||
M.return (Some (`Those (`Height index, `Hash hash))) | ||
|
||
let of_partial_identifier' (identifier : Partial_block_identifier.t option) = | ||
of_partial_identifier (Option.value identifier ~default:{Partial_block_identifier.index = None; hash = None }) | ||
|
||
let is_genesis ~hash = function | ||
| Some (`This (`Height index)) -> | ||
Int64.equal index Network.genesis_block_height | ||
|
@@ -241,15 +244,39 @@ module Sql = struct | |
|
||
let typ = Caqti_type.(tup3 int Archive_lib.Processor.Block.typ Extras.typ) | ||
|
||
let query_height = | ||
let query_max_height = | ||
Caqti_request.find Caqti_type.unit Caqti_type.int64 | ||
{| SELECT MAX(height) FROM blocks |} | ||
|
||
let query_height_old = | ||
Caqti_request.find_opt Caqti_type.int64 typ | ||
(* The archive database will only reconcile the canonical columns for | ||
* blocks older than k + epsilon | ||
*) | ||
{| | ||
SELECT c.id, c.state_hash, c.parent_id, c.parent_hash, c.creator_id, c.block_winner_id, c.snarked_ledger_hash_id, c.staking_epoch_data_id, c.next_epoch_data_id, c.ledger_hash, c.height, c.global_slot, c.global_slot_since_genesis, c.timestamp, pk.value as creator, bw.value as winner FROM blocks c | ||
INNER JOIN public_keys pk | ||
ON pk.id = c.creator_id | ||
INNER JOIN public_keys bw | ||
ON bw.id = c.block_winner_id | ||
WHERE c.height = ? AND c.chain_status = 'canonical' | ||
|} | ||
|
||
|
||
let query_height_recent = | ||
Caqti_request.find_opt Caqti_type.int64 typ | ||
(* According to the clarification of the Rosetta spec here | ||
* https://community.rosetta-api.org/t/querying-block-by-just-its-index/84/3 , | ||
* it is important to select only the block on the canonical chain for a | ||
* given height, and not an arbitrary one. | ||
* | ||
* This query recursively traverses the blockchain from the longest tip | ||
* backwards until it reaches a block of the given height. *) | ||
* backwards until it reaches a block of the given height. | ||
* | ||
* This query is best used only for _short_ (around ~k blocks back | ||
* + epsilon) | ||
* requests since recursive queries stress PostgreSQL. | ||
*) | ||
{| | ||
WITH RECURSIVE chain AS ( | ||
(SELECT id, state_hash, parent_id, parent_hash, creator_id, block_winner_id, snarked_ledger_hash_id, staking_epoch_data_id, next_epoch_data_id, ledger_hash, height, global_slot, global_slot_since_genesis, timestamp FROM blocks b WHERE height = (select MAX(height) from blocks) | ||
|
@@ -312,9 +339,24 @@ WITH RECURSIVE chain AS ( | |
let run_by_id (module Conn : Caqti_async.CONNECTION) id = | ||
Conn.find_opt query_by_id id | ||
|
||
let run_is_old_height (module Conn : Caqti_async.CONNECTION) ~height = | ||
let open Deferred.Result.Let_syntax in | ||
let open Int64 in | ||
let%map max_height = | ||
Conn.find query_max_height () | ||
in | ||
(* buffer an epsilon of 5 just in case archive node isn't caught up *) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the criterion to distinguish old from new queries based just on the current height, or should it examine whether blocks have marked as canonical? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes I was thinking we should just rely on height here -- we know performing the long recursive queries in rosetta cause Postgres to choke, so I'd rather the queries fail in the case that we haven't marked things as canonical as opposed to trying the big recursive queries in that case and then fail. |
||
let epsilon = of_int 5 in | ||
height < (max_height - (of_int Genesis_constants.k)) - epsilon | ||
|
||
let run (module Conn : Caqti_async.CONNECTION) = function | ||
| Some (`This (`Height h)) -> | ||
Conn.find_opt query_height h | ||
let open Deferred.Result.Let_syntax in | ||
let%bind is_old_height = run_is_old_height (module Conn) ~height:h in | ||
if is_old_height then | ||
Conn.find_opt query_height_old h | ||
else | ||
Conn.find_opt query_height_recent h | ||
| Some (`That (`Hash h)) -> | ||
Conn.find_opt query_hash h | ||
| Some (`Those (`Height height, `Hash hash)) -> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a comment here how this is shared by
query_old
andquery_recent
would be helpful for future audiences