Skip to content

Commit

Permalink
feat: get_block_at_timestamp util (#484)
Browse files Browse the repository at this point in the history
* feat: get_block_at_timestamp util (current closest_block_after_timestamp implementation is a bit weird because the block is final)
  • Loading branch information
BobTheBuidler authored Jan 10, 2024
1 parent 819c22b commit 5e2f2e9
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 2 deletions.
1 change: 1 addition & 0 deletions y/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class NetworkNotSpecified(Exception):
from y.networks import Network
from y.prices import magic
from y.prices.magic import get_price, get_prices
from y.time import get_block_at_timestamp
from y.utils.dank_mids import dank_w3
from y.utils.logging import enable_debug_logging
from y.utils.multicall import fetch_multicall
Expand Down
6 changes: 6 additions & 0 deletions y/_db/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ class Trace(db.Entity):
to_address = Required(str, index=True, lazy=True)
raw = Required(bytes)

class BlockAtTimestamp(db.Entity):
chainid = Required(int)
timestamp = Required(datetime)
PrimaryKey(chainid, timestamp)
block = Required(int)


@db_session
def insert(type: db.Entity, **kwargs: Any) -> typing_Optional[db.Entity]:
Expand Down
13 changes: 12 additions & 1 deletion y/_db/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from brownie import chain

from y._db.entities import Block, Chain, insert
from y._db.entities import Block, BlockAtTimestamp, Chain, insert
from y._db.utils._ep import _get_get_block
from y._db.utils.decorators import a_sync_read_db_session, a_sync_write_db_session, a_sync_write_db_session_cached

Expand Down Expand Up @@ -54,3 +54,14 @@ def set_block_timestamp(block: int, timestamp: int) -> None:
timestamp = datetime.fromtimestamp(timestamp, tz=timezone.utc)
block.timestamp = timestamp
logger.debug("cached %s.timestamp %s", block, timestamp)

@a_sync_read_db_session
def get_block_at_timestamp(timestamp: datetime) -> Optional[int]:
if block := BlockAtTimestamp.get(chainid=chain.id, timestamp=timestamp):
logger.debug("found block %s for %s in ydb", block, timestamp)
return block

@a_sync_write_db_session
def set_block_at_timestamp(timestamp: datetime, block: int) -> None:
insert(BlockAtTimestamp, chainid=chain.id, timestamp=timestamp, block=block)
logger.debug("inserted block %s for %s", block, timestamp)
16 changes: 15 additions & 1 deletion y/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ async def get_block_timestamp_async(height: int) -> int:
await db.set_block_timestamp(height, ts, sync=False)
return ts

# TODO: deprecate
@memory.cache()
def last_block_on_date(date: Union[str, datetime.date]) -> int:
""" Returns the last block on a given `date`. You can pass either a `datetime.date` object or a date string formatted as 'YYYY-MM-DD'. """
Expand Down Expand Up @@ -84,6 +85,20 @@ def last_block_on_date(date: Union[str, datetime.date]) -> int:
logger.debug('last %s block on date %s -> %s', Network.name(), date, block)
return block


@a_sync(cache_type='memory', ram_cache_ttl=ENVS.CACHE_TTL)
async def get_block_at_timestamp(timestamp: datetime) -> int:
import y._db.utils.utils as db
if block_at_timestamp := await db.get_block_at_timestamp(timestamp):
return block_at_timestamp

# TODO: invert this and use this fn inside of closest_block_after_timestamp for backwards compatability before deprecating closest_block_after_timestamp
block_after_timestamp = await closest_block_after_timestamp_async(timestamp)
block_at_timestamp = block_after_timestamp - 1
await db.set_block_at_timestamp(timestamp, block_at_timestamp)
return block_at_timestamp


class UnixTimestamp(int):
pass

Expand Down Expand Up @@ -132,7 +147,6 @@ async def closest_block_after_timestamp_async(timestamp: Timestamp, wait_for_blo
raise NoBlockFound(f"No block found after timestamp {timestamp}")
return hi


@memory.cache()
def _closest_block_after_timestamp_cached(timestamp: int) -> int:
height = chain.height
Expand Down

0 comments on commit 5e2f2e9

Please sign in to comment.