This PR adds support for requesting liquidity at a target block height range:
the endpoints:
/liquidity/token/{tokenA}/{tokenB}
/liquidity/pair/{tokenA}/{tokenB} (new)
support query parameters:
block_range.from_height: defaults to 0
block_range.to_height: defaults to undefined
and return new body attributes:
block_range.from_height: the block (non-inclusive) that the update begins from
block_range.to_height: the block (inclusive) that the update ends at
Using no block_range query parameters will cause a default range from 0-currentHeight, effectively the same request and response as previous exiting route /liquidity/token/{tokenA}/{tokenB} created in https://github.com/duality-labs/hapi-indexer/pull/21
Optional long polling functionality with block_range.from_height
By making a request with block_range.from_height that would return an empty update (no data found since this height), the indexer will wait until data becomes available, and send that data. At that point the front end client may recursively take that response's block_range.to_height value and use it in a subsequent request as the block_range.from_height param, effectively waiting for the next block of data after every request response, i.e. long-polling.
Consistent height pagination with block_range.to_height
A concern with pagination of any data is: "what happens if the underlying data has changed in between page requests?". This can be dealt with in many ways, one being database specific solutions that can lookup database cursors using nextKey params, but if using just offset and limit as is being used currently here, the data may change between page requests.
This PR caches all pages of data for new requests against the specific height so that the same user may come back and receive the pages of data that continues their same request at the same block height. There is a specific issue that may be encountered due to this "just caching" method when run in production with multiple indexers and the user unintentionally queries different indexers between pages (due to a load balancer or other architecture reason) which is detailed in:
22
Fetching both tick liquidity sides of of token pair at once using /liquidity/pair/{tokenA}/{tokenB}
A new route /liquidity/pair/{tokenA}/{tokenB} exposes the ability to requests both tick sides at once. This provides a much stronger guarantee to front end clients that the data being presented for both side of liquidity for a pair is the data at the same point in time (i.e. the same block height on both sides).
Database Changes
To achieve this a new field and index in the derived.tick_state SQL table: related.block.header.height tracks the height at which the update to the tick was made, which allows us to select only the relevant data that has changed from a certain block (up to the current block), the table overwrites data rows for each tickIndex with newer height data so it is not possible to query a range that exists only in the past, #22 should resolve this by tracking much more state data and enabling this.
An event listener was also created to listen for newHeight events (when a new block height is seen in the block table).
This PR adds support for requesting liquidity at a target block height range:
the endpoints:
/liquidity/token/{tokenA}/{tokenB}
/liquidity/pair/{tokenA}/{tokenB}
(new)support query parameters:
block_range.from_height
: defaults to0
block_range.to_height
: defaults toundefined
and return new body attributes:
block_range.from_height
: the block (non-inclusive) that the update begins fromblock_range.to_height
: the block (inclusive) that the update ends atUsing no
block_range
query parameters will cause a default range from 0-currentHeight, effectively the same request and response as previous exiting route/liquidity/token/{tokenA}/{tokenB}
created in https://github.com/duality-labs/hapi-indexer/pull/21Optional long polling functionality with
block_range.from_height
By making a request with
block_range.from_height
that would return an empty update (no data found since this height), the indexer will wait until data becomes available, and send that data. At that point the front end client may recursively take that response'sblock_range.to_height
value and use it in a subsequent request as theblock_range.from_height
param, effectively waiting for the next block of data after every request response, i.e. long-polling.Consistent height pagination with
block_range.to_height
A concern with pagination of any data is: "what happens if the underlying data has changed in between page requests?". This can be dealt with in many ways, one being database specific solutions that can lookup database cursors using
nextKey
params, but if using justoffset
andlimit
as is being used currently here, the data may change between page requests.This PR caches all pages of data for new requests against the specific height so that the same user may come back and receive the pages of data that continues their same request at the same block height. There is a specific issue that may be encountered due to this "just caching" method when run in production with multiple indexers and the user unintentionally queries different indexers between pages (due to a load balancer or other architecture reason) which is detailed in:
22
Fetching both tick liquidity sides of of token pair at once using
/liquidity/pair/{tokenA}/{tokenB}
A new route
/liquidity/pair/{tokenA}/{tokenB}
exposes the ability to requests both tick sides at once. This provides a much stronger guarantee to front end clients that the data being presented for both side of liquidity for a pair is the data at the same point in time (i.e. the same block height on both sides).Database Changes
To achieve this a new field and index in the
derived.tick_state
SQL table:related.block.header.height
tracks the height at which the update to the tick was made, which allows us to select only the relevant data that has changed from a certain block (up to the current block), the table overwrites data rows for each tickIndex with newer height data so it is not possible to query a range that exists only in the past, #22 should resolve this by tracking much more state data and enabling this.An event listener was also created to listen for
newHeight
events (when a new block height is seen in theblock
table).