Skip to content

Commit ec8722f

Browse files
authored
Add utxo and datum cache in Ogmios context (#237)
Reducing duplicated calls to Ogmios and Kupo
1 parent bea3047 commit ec8722f

File tree

4 files changed

+61
-7
lines changed

4 files changed

+61
-7
lines changed

poetry.lock

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pycardano/backend/ogmios.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import json
22
import time
3+
from copy import deepcopy
34
from datetime import datetime, timezone
45
from enum import Enum
56
from typing import Any, Dict, List, Optional, Tuple, Union
67

78
import cbor2
89
import requests
910
import websocket
11+
from cachetools import Cache, LRUCache, TTLCache
1012

1113
from pycardano.address import Address
1214
from pycardano.backend.base import (
@@ -49,6 +51,8 @@ class OgmiosChainContext(ChainContext):
4951
_last_chain_tip_fetch: float
5052
_genesis_param: Optional[GenesisParameters]
5153
_protocol_param: Optional[ProtocolParameters]
54+
_utxo_cache: Cache
55+
_datum_cache: Cache
5256

5357
def __init__(
5458
self,
@@ -57,6 +61,8 @@ def __init__(
5761
compact_result=True,
5862
kupo_url=None,
5963
refetch_chain_tip_interval: Optional[float] = None,
64+
utxo_cache_size: int = 10000,
65+
datum_cache_size: int = 10000,
6066
):
6167
self._ws_url = ws_url
6268
self._network = network
@@ -77,6 +83,11 @@ def __init__(
7783
/ self.genesis_param.active_slots_coefficient
7884
)
7985

86+
self._utxo_cache = TTLCache(
87+
ttl=self._refetch_chain_tip_interval, maxsize=utxo_cache_size
88+
)
89+
self._datum_cache = LRUCache(maxsize=datum_cache_size)
90+
8091
def _request(self, method: OgmiosQueryType, args: JsonDict) -> Any:
8192
ws = websocket.WebSocket()
8293
ws.connect(self._ws_url)
@@ -253,13 +264,45 @@ def _utxos(self, address: str) -> List[UTxO]:
253264
Returns:
254265
List[UTxO]: A list of UTxOs.
255266
"""
267+
if (self.last_block_slot, address) in self._utxo_cache:
268+
return deepcopy(self._utxo_cache[(self.last_block_slot, address)])
269+
256270
if self._kupo_url:
257271
utxos = self._utxos_kupo(address)
258272
else:
259273
utxos = self._utxos_ogmios(address)
260274

275+
self._utxo_cache[(self.last_block_slot, address)] = deepcopy(utxos)
276+
261277
return utxos
262278

279+
def _get_datum_from_kupo(self, datum_hash: str) -> Optional[RawCBOR]:
280+
"""Get datum from Kupo.
281+
282+
Args:
283+
datum_hash (str): A datum hash.
284+
285+
Returns:
286+
Optional[RawCBOR]: A datum.
287+
"""
288+
datum = self._datum_cache.get(datum_hash, None)
289+
290+
if datum is not None or (datum is None and not self._is_chain_tip_updated()):
291+
return datum
292+
293+
if self._kupo_url is None:
294+
raise AssertionError(
295+
"kupo_url object attribute has not been assigned properly."
296+
)
297+
298+
kupo_datum_url = self._kupo_url + "/datums/" + datum_hash
299+
datum_result = requests.get(kupo_datum_url).json()
300+
if datum_result and datum_result["datum"] != datum_hash:
301+
datum = RawCBOR(bytes.fromhex(datum_result["datum"]))
302+
303+
self._datum_cache[datum_hash] = datum
304+
return datum
305+
263306
def _utxos_kupo(self, address: str) -> List[UTxO]:
264307
"""Get all UTxOs associated with an address with Kupo.
265308
Since UTxO querying will be deprecated from Ogmios in next
@@ -313,10 +356,8 @@ def _utxos_kupo(self, address: str) -> List[UTxO]:
313356
else None
314357
)
315358
if datum_hash and result.get("datum_type", "inline"):
316-
kupo_datum_url = self._kupo_url + "/datums/" + result["datum_hash"]
317-
datum_result = requests.get(kupo_datum_url).json()
318-
if datum_result and datum_result["datum"] != datum_hash:
319-
datum = RawCBOR(bytes.fromhex(datum_result["datum"]))
359+
datum = self._get_datum_from_kupo(result["datum_hash"])
360+
if datum is not None:
320361
datum_hash = None
321362

322363
if not result["value"]["assets"]:

pycardano/plutus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ def __deepcopy__(self, memo):
670670
return self.__class__.from_cbor(self.to_cbor_hex())
671671

672672

673-
@dataclass
673+
@dataclass(repr=False)
674674
class RawPlutusData(CBORSerializable):
675675
data: CBORTag
676676

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ mnemonic = "^0.20"
3434
ECPy = "^1.2.5"
3535
frozendict = "^2.3.8"
3636
frozenlist = "^1.3.3"
37+
cachetools = "^5.3.0"
3738

3839
[tool.poetry.dev-dependencies]
3940
Sphinx = "^4.3.2"

0 commit comments

Comments
 (0)