Skip to content

Add utxo and datum cache in Ogmios context #237

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

Merged
merged 1 commit into from
May 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 45 additions & 4 deletions pycardano/backend/ogmios.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import json
import time
from copy import deepcopy
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Dict, List, Optional, Tuple, Union

import cbor2
import requests
import websocket
from cachetools import Cache, LRUCache, TTLCache

from pycardano.address import Address
from pycardano.backend.base import (
Expand Down Expand Up @@ -49,6 +51,8 @@ class OgmiosChainContext(ChainContext):
_last_chain_tip_fetch: float
_genesis_param: Optional[GenesisParameters]
_protocol_param: Optional[ProtocolParameters]
_utxo_cache: Cache
_datum_cache: Cache

def __init__(
self,
Expand All @@ -57,6 +61,8 @@ def __init__(
compact_result=True,
kupo_url=None,
refetch_chain_tip_interval: Optional[float] = None,
utxo_cache_size: int = 10000,
datum_cache_size: int = 10000,
):
self._ws_url = ws_url
self._network = network
Expand All @@ -77,6 +83,11 @@ def __init__(
/ self.genesis_param.active_slots_coefficient
)

self._utxo_cache = TTLCache(
ttl=self._refetch_chain_tip_interval, maxsize=utxo_cache_size
)
self._datum_cache = LRUCache(maxsize=datum_cache_size)

def _request(self, method: OgmiosQueryType, args: JsonDict) -> Any:
ws = websocket.WebSocket()
ws.connect(self._ws_url)
Expand Down Expand Up @@ -253,13 +264,45 @@ def _utxos(self, address: str) -> List[UTxO]:
Returns:
List[UTxO]: A list of UTxOs.
"""
if (self.last_block_slot, address) in self._utxo_cache:
return deepcopy(self._utxo_cache[(self.last_block_slot, address)])

if self._kupo_url:
utxos = self._utxos_kupo(address)
else:
utxos = self._utxos_ogmios(address)

self._utxo_cache[(self.last_block_slot, address)] = deepcopy(utxos)

return utxos

def _get_datum_from_kupo(self, datum_hash: str) -> Optional[RawCBOR]:
"""Get datum from Kupo.

Args:
datum_hash (str): A datum hash.

Returns:
Optional[RawCBOR]: A datum.
"""
datum = self._datum_cache.get(datum_hash, None)

if datum is not None or (datum is None and not self._is_chain_tip_updated()):
return datum

if self._kupo_url is None:
raise AssertionError(
"kupo_url object attribute has not been assigned properly."
)

kupo_datum_url = self._kupo_url + "/datums/" + datum_hash
datum_result = requests.get(kupo_datum_url).json()
if datum_result and datum_result["datum"] != datum_hash:
datum = RawCBOR(bytes.fromhex(datum_result["datum"]))

self._datum_cache[datum_hash] = datum
return datum

def _utxos_kupo(self, address: str) -> List[UTxO]:
"""Get all UTxOs associated with an address with Kupo.
Since UTxO querying will be deprecated from Ogmios in next
Expand Down Expand Up @@ -313,10 +356,8 @@ def _utxos_kupo(self, address: str) -> List[UTxO]:
else None
)
if datum_hash and result.get("datum_type", "inline"):
kupo_datum_url = self._kupo_url + "/datums/" + result["datum_hash"]
datum_result = requests.get(kupo_datum_url).json()
if datum_result and datum_result["datum"] != datum_hash:
datum = RawCBOR(bytes.fromhex(datum_result["datum"]))
datum = self._get_datum_from_kupo(result["datum_hash"])
if datum is not None:
datum_hash = None

if not result["value"]["assets"]:
Expand Down
2 changes: 1 addition & 1 deletion pycardano/plutus.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ def __deepcopy__(self, memo):
return self.__class__.from_cbor(self.to_cbor_hex())


@dataclass
@dataclass(repr=False)
class RawPlutusData(CBORSerializable):
data: CBORTag

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mnemonic = "^0.20"
ECPy = "^1.2.5"
frozendict = "^2.3.8"
frozenlist = "^1.3.3"
cachetools = "^5.3.0"

[tool.poetry.dev-dependencies]
Sphinx = "^4.3.2"
Expand Down