Skip to content

Commit

Permalink
fix: raise error if the requested range isn't covered
Browse files Browse the repository at this point in the history
  • Loading branch information
tmcgroul committed Feb 7, 2024
1 parent 3bd88e4 commit 0d6591c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 12 deletions.
17 changes: 14 additions & 3 deletions ape_subsquid/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from requests.exceptions import HTTPError

from ape_subsquid.exceptions import ApeSubsquidError, DataIsNotAvailable, NotReadyToServeError
from ape_subsquid.utils import ttl_cache

TraceType = Union[Literal["create"], Literal["call"], Literal["reward"], Literal["suicide"]]

Expand Down Expand Up @@ -239,6 +240,10 @@ class Archive:
_session = Session()
_retry_schedule = [5, 10, 20, 30, 60]

@ttl_cache(seconds=30)
def get_height(self, network: str) -> int:
return self._retry(self._get_height, network)

def query(self, network: str, query: Query) -> list[Block]:
return self._retry(self._query, network, query)

Expand All @@ -254,6 +259,12 @@ def _get_worker(self, network: str, start_block: int) -> str:
response.raise_for_status()
return response.text

def _get_height(self, network: str) -> int:
url = f"https://v2.archive.subsquid.io/network/{network}/height"
response = self._session.get(url)
response.raise_for_status()
return int(response.text)

def _retry(self, request: Callable[..., T], *args, **kwargs) -> T:
retries = 0
while True:
Expand All @@ -263,7 +274,7 @@ def _retry(self, request: Callable[..., T], *args, **kwargs) -> T:
if self._is_retryable_error(e) and retries < len(self._retry_schedule):
pause = self._retry_schedule[retries]
retries += 1
logger.warning(f"archive request failed, will retry in {pause} secs")
logger.warning(f"Archive request failed, will retry in {pause} secs")
sleep(pause)
else:
self._raise_error(e)
Expand All @@ -277,9 +288,9 @@ def _is_retryable_error(self, error: HTTPError) -> bool:
def _raise_error(self, error: HTTPError) -> ApeSubsquidError:
assert error.response is not None
text = error.response.text
if "not ready to serve block" in text:
if "Not ready to serve block" in text:
raise NotReadyToServeError(text)
elif "is not available" in text:
elif "Is not available" in text:
raise DataIsNotAvailable(text)
else:
raise ApeSubsquidError(text)
12 changes: 10 additions & 2 deletions ape_subsquid/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ class ApeSubsquidError(ApeException):

class NotReadyToServeError(ApeSubsquidError):
"""
Raised when archive isn't ready to serve a specific block
or a network isn't supported.
Raised when subsquid network isn't ready to serve a specific block.
"""


class DataIsNotAvailable(ApeSubsquidError):
"""
Raised when a specific worker has no requested data.
"""


class DataRangeIsNotAvailable(ApeSubsquidError):
"""
Raised when subsquid network doesn't cover the requested data range.
"""

def __init__(self, range: tuple[int, int], height: int) -> None:
super().__init__(f"Range {range} isn't covered. Last available block is {height}.")
5 changes: 1 addition & 4 deletions ape_subsquid/mappings.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from hexbytes import HexBytes

from ape_subsquid.archive import BlockHeader, Log, Transaction


def hex_to_int(value: str):
return int(value, 16)
from ape_subsquid.utils import hex_to_int


def map_header(value: BlockHeader, transactions: list[Transaction]) -> dict:
Expand Down
17 changes: 14 additions & 3 deletions ape_subsquid/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
QueryType,
)
from ape.exceptions import QueryEngineError
from ape.logging import logger
from ape.types import ContractLog
from ape.utils import singledispatchmethod
from hexbytes import HexBytes
Expand All @@ -22,6 +23,7 @@
Query,
TxFieldSelection,
)
from ape_subsquid.exceptions import DataRangeIsNotAvailable
from ape_subsquid.mappings import map_header, map_log, map_receipt
from ape_subsquid.networks import get_network

Expand Down Expand Up @@ -190,14 +192,23 @@ def all_fields(cls: Type[T]) -> T:
return cast(T, fields)


def ensure_range_is_available(archive: Archive, network: str, query: Query):
height = archive.get_height(network)
if query["toBlock"] > height:
range = (query["fromBlock"], query["toBlock"])
raise DataRangeIsNotAvailable(range, height)


def archive_ingest(archive: Archive, network: str, query: Query) -> Iterator[list[Block]]:
ensure_range_is_available(archive, network, query)
while True:
data = archive.query(network, query)
yield data

last_block = data[-1]
last_block = data[-1]["header"]["number"]
logger.info(f"Done fetching the range ({query['fromBlock']}, {last_block})")
if "toBlock" in query:
if last_block["header"]["number"] == query["toBlock"]:
if last_block == query["toBlock"]:
break

query["fromBlock"] = last_block["header"]["number"] + 1
query["fromBlock"] = last_block + 1
27 changes: 27 additions & 0 deletions ape_subsquid/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import functools
import time


def ttl_cache(seconds: int):
def decorator(func):
value = None
last_access = 0

@functools.wraps(func)
def inner(*args, **kwargs):
nonlocal value, last_access
now = time.time()

if (now - seconds) >= last_access or value is None:
value = func(*args, **kwargs)
last_access = time.time()

return value

return inner

return decorator


def hex_to_int(value: str):
return int(value, 16)

0 comments on commit 0d6591c

Please sign in to comment.