Skip to content

Commit 65c2d92

Browse files
authored
feat: add max latency field (#59)
1 parent e3df885 commit 65c2d92

File tree

4 files changed

+269
-87
lines changed

4 files changed

+269
-87
lines changed

pythclient/pythaccounts.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
_VERSION_1 = 1
1818
_VERSION_2 = 2
1919
_SUPPORTED_VERSIONS = set((_VERSION_1, _VERSION_2))
20-
_ACCOUNT_HEADER_BYTES = 16 # magic + version + type + size, u32 * 4
20+
ACCOUNT_HEADER_BYTES = 16 # magic + version + type + size, u32 * 4
2121
_NULL_KEY_BYTES = b'\x00' * SolanaPublicKey.LENGTH
22-
MAX_SLOT_DIFFERENCE = 25
22+
DEFAULT_MAX_LATENCY = 25
2323

2424

2525
class PythAccountType(Enum):
@@ -81,7 +81,7 @@ def _read_attribute_string(buffer: bytes, offset: int) -> Tuple[Optional[str], i
8181

8282

8383
def _parse_header(buffer: bytes, offset: int = 0, *, key: SolanaPublicKeyOrStr) -> Tuple[PythAccountType, int, int]:
84-
if len(buffer) - offset < _ACCOUNT_HEADER_BYTES:
84+
if len(buffer) - offset < ACCOUNT_HEADER_BYTES:
8585
raise ValueError("Pyth account data too short")
8686

8787
# Pyth magic (u32) == MAGIC
@@ -141,7 +141,7 @@ def update_with_rpc_response(self, slot: int, value: Dict[str, Any]) -> None:
141141
f"wrong Pyth account type {type_} for {type(self)}")
142142

143143
try:
144-
self.update_from(data[:size], version=version, offset=_ACCOUNT_HEADER_BYTES)
144+
self.update_from(data[:size], version=version, offset=ACCOUNT_HEADER_BYTES)
145145
except Exception as e:
146146
logger.exception("error while parsing account", exception=e)
147147

@@ -482,6 +482,7 @@ class PythPriceAccount(PythAccount):
482482
aggregate price is composed of
483483
slot (int): the slot time when this account was last fetched
484484
product (Optional[PythProductAccount]): the product this price is for, if loaded
485+
max_latency (int): the maximum allowed slot difference for this feed
485486
"""
486487

487488
def __init__(self, key: SolanaPublicKey, solana: SolanaClient, *, product: Optional[PythProductAccount] = None) -> None:
@@ -503,6 +504,7 @@ def __init__(self, key: SolanaPublicKey, solana: SolanaClient, *, product: Optio
503504
self.prev_price: float = field(init=False)
504505
self.prev_conf: float = field(init=False)
505506
self.prev_timestamp: int = 0 # unix timestamp in seconds
507+
self.max_latency: int = 0 # maximum allowed slot difference for this feed
506508

507509
@property
508510
def aggregate_price(self) -> Optional[float]:
@@ -537,7 +539,7 @@ def get_aggregate_price_status_with_slot(self, slot: int) -> Optional[PythPriceS
537539
You might consider using this function with the latest solana slot to make sure the price has not gone stale.
538540
"""
539541
if self.aggregate_price_info.price_status == PythPriceStatus.TRADING and \
540-
slot - self.aggregate_price_info.pub_slot > MAX_SLOT_DIFFERENCE:
542+
slot - self.aggregate_price_info.pub_slot > self.max_latency:
541543
return PythPriceStatus.UNKNOWN
542544

543545
return self.aggregate_price_info.price_status
@@ -571,9 +573,12 @@ def update_from(self, buffer: bytes, *, version: int, offset: int = 0) -> None:
571573
derivations = list(struct.unpack_from("<6q", buffer, offset))
572574
self.derivations = dict((type_, derivations[type_.value - 1]) for type_ in [EmaType.EMA_CONFIDENCE_VALUE, EmaType.EMA_PRICE_VALUE])
573575
offset += 48 # struct.calcsize("6q")
574-
# drv[2-4]_ fields are currently unused
575576
timestamp, min_publishers = struct.unpack_from("<qB", buffer, offset)
576-
offset += 16 # struct.calcsize("qBbhi") ("bhi" is drv_2, drv_3, drv_4)
577+
offset += 9 # struct.calcsize("qB")
578+
_message_sent, max_latency = struct.unpack_from("<bB", buffer, offset)
579+
offset += 2 # struct.calcsize("bB")
580+
_drv_3, _drv_4 = struct.unpack_from("<bi", buffer, offset)
581+
offset += 5 # struct.calcsize("bi")
577582
product_account_key_bytes, next_price_account_key_bytes = struct.unpack_from("32s32s", buffer, offset)
578583
offset += 64 # struct.calcsize("32s32s")
579584
prev_slot, prev_price, prev_conf, prev_timestamp = struct.unpack_from("<QqQq", buffer, offset)
@@ -620,6 +625,8 @@ def update_from(self, buffer: bytes, *, version: int, offset: int = 0) -> None:
620625
self.prev_price = prev_price
621626
self.prev_conf = prev_conf
622627
self.prev_timestamp = prev_timestamp
628+
# a max latency of 0 is the default max latency
629+
self.max_latency = max_latency if max_latency != 0 else DEFAULT_MAX_LATENCY
623630

624631
def __str__(self) -> str:
625632
if self.product:

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setup(
99
name='pythclient',
10-
version='0.2.0',
10+
version='0.2.1',
1111
packages=['pythclient'],
1212
author='Pyth Developers',
1313
author_email='[email protected]',

0 commit comments

Comments
 (0)