From e753adb1c15d8dc091e8598d15bc665872146d20 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Sun, 15 Dec 2024 22:02:18 +0100 Subject: [PATCH 1/4] refactor: imports (again) --- src/poktroll_clients/__init__.py | 11 ++++++++--- src/poktroll_clients/tx_client.py | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/poktroll_clients/__init__.py b/src/poktroll_clients/__init__.py index 79ce7d4..bc7f70c 100644 --- a/src/poktroll_clients/__init__.py +++ b/src/poktroll_clients/__init__.py @@ -1,12 +1,12 @@ # Add generated protobuf types to the module path. from os import path +from .go_memory import ffi, libpoktroll_clients, go_ref, check_err, check_ref, GoManagedMem +from .depinject import Supply, SupplyMany +from .events_query_client import EventsQueryClient from .block_client import BlockClient, BlockQueryClient from .tx_context import TxContext from .tx_client import TxClient -from .events_query_client import EventsQueryClient -from .depinject import Supply, SupplyMany -from .go_memory import go_ref __all__ = [ 'BlockClient', @@ -16,5 +16,10 @@ 'EventsQueryClient', 'Supply', 'SupplyMany', + 'ffi', 'go_ref', + 'check_err', + 'check_ref', + 'GoManagedMem', + 'libpoktroll_clients', ] diff --git a/src/poktroll_clients/tx_client.py b/src/poktroll_clients/tx_client.py index ef96443..aa240f6 100644 --- a/src/poktroll_clients/tx_client.py +++ b/src/poktroll_clients/tx_client.py @@ -7,12 +7,19 @@ from cffi import FFIError -from poktroll_clients.events_query_client import EventsQueryClient -from poktroll_clients.block_client import BlockClient, BlockQueryClient -from poktroll_clients.depinject import SupplyMany -from poktroll_clients.tx_context import TxContext -from poktroll_clients.ffi import ffi, libpoktroll_clients -from poktroll_clients.go_memory import GoManagedMem, go_ref, check_err, check_ref +from poktroll_clients import ( + EventsQueryClient, + BlockClient, + BlockQueryClient, + SupplyMany, + TxContext, + libpoktroll_clients, + ffi, + go_ref, + GoManagedMem, + check_err, + check_ref, +) from poktroll_clients.protobuf import SerializedProto, ProtoMessageArray From 5520dba0a51b2ddf92b57e4d219af7594f8d3e82 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Sun, 15 Dec 2024 22:03:03 +0100 Subject: [PATCH 2/4] refactor: raname self_ref var for consistency --- src/poktroll_clients/go_memory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/poktroll_clients/go_memory.py b/src/poktroll_clients/go_memory.py index 7b7d36c..be54f43 100644 --- a/src/poktroll_clients/go_memory.py +++ b/src/poktroll_clients/go_memory.py @@ -34,15 +34,15 @@ class GoManagedMem: go_ref: go_ref err_ptr: ffi.CData = ffi.new("char **") - def __init__(self, go_ref: go_ref): + def __init__(self, self_ref: go_ref): """ Constructor for GoManagedMem. Stores the Go-managed memory reference. """ - self.go_ref = go_ref + self.go_ref = self_ref check_err(self.err_ptr) - check_ref(go_ref) + check_ref(self_ref) def __del__(self): """ From 0b4cad14b85f54fe8547baa320b920971274c9ee Mon Sep 17 00:00:00 2001 From: Bryan White Date: Sun, 15 Dec 2024 22:03:21 +0100 Subject: [PATCH 3/4] wip: multi-query client --- src/poktroll_clients/ffi.py | 81 ++++++++++++++++++++++++++++ src/poktroll_clients/query_client.py | 20 +++++++ 2 files changed, 101 insertions(+) create mode 100644 src/poktroll_clients/query_client.py diff --git a/src/poktroll_clients/ffi.py b/src/poktroll_clients/ffi.py index c5f496c..9c18aa9 100644 --- a/src/poktroll_clients/ffi.py +++ b/src/poktroll_clients/ffi.py @@ -91,6 +91,87 @@ go_ref NewTxClient(go_ref deps_ref, char *signing_key_name, char **err); go_ref TxClient_SignAndBroadcast(AsyncOperation* op, go_ref self_ref, serialized_proto *msg); go_ref TxClient_SignAndBroadcastMany(AsyncOperation* op, go_ref self_ref, proto_message_array *msgs); + + // Params update methods (all modules) + go_ref TxClient_UpdateSharedParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateApplicationParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateGatewayParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateSupplierParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateSessionParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateServiceParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateProofParams(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateTokenomicsParams(AsyncOperation* op, go_ref self_ref, char *params); + + // Param (individual) update methods (all modules) + go_ref TxClient_UpdateSharedParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateApplicationParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateGatewayParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateSupplierParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateSessionParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateServiceParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateProofParam(AsyncOperation* op, go_ref self_ref, char *params); + go_ref TxClient_UpdateTokenomicsParam(AsyncOperation* op, go_ref self_ref, char *params); + + // Application module message methods + go_ref TxClient_StakeApplication(AsyncOperation* op, go_ref self_ref, char *address, char *stake, proto_message_array *services); + go_ref TxClient_UnstakeApplication(AsyncOperation* op, go_ref self_ref, char *address, char *stake, proto_message_array *services); + go_ref TxClient_DelegateToGateway(AsyncOperation* op, go_ref self_ref, char *address, char *stake, proto_message_array *services); + go_ref TxClient_UndelegateFromGateway(AsyncOperation* op, go_ref self_ref, char *address, char *stake, proto_message_array *services); + go_ref TxClient_TransferApplication(AsyncOperation* op, go_ref self_ref, char *address, char *stake, proto_message_array *services); + + // Gateway module message methods + go_ref TxClient_StakeGateway(AsyncOperation* op, go_ref self_ref, char *address, char *stake); + go_ref TxClient_UnstakeGateway(AsyncOperation* op, go_ref self_ref, char *address, char *stake); + + // Supplier module message methods + go_ref TxClient_StakeSupplier(AsyncOperation* op, go_ref self_ref, char *address, char *stake); + go_ref TxClient_UnstakeSupplier(AsyncOperation* op, go_ref self_ref, char *address, char *stake); + + // Service module message methods + go_ref TxClient_AddService(AsyncOperation* op, go_ref self_ref, char *owner_address, serialized_proto *service); + + // Proof module message methods + go_ref TxClient_CreateClaim(AsyncOperation* op, go_ref self_ref, char *owner_address, char *session_header, char *root_hash, char *proof); + go_ref TxClient_SubmitProof(AsyncOperation* op, go_ref self_ref, char *owner_address, char *session_header, char *proof); + + go_ref NewQueryClient(char *query_node_rpc_url, char **err); + + // Params query methods (all modules) + go_ref QueryClient_GatSharedParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatApplicationParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatGatewayParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatSupplierParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatSessionParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatServiceParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatProofParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GatTokenomicsParams(AsyncOperation* op, go_ref self_ref); + + // Application module query methods + go_ref QueryClient_GetApplication(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllApplications(AsyncOperation* op, go_ref self_ref, char *address); + + // Gateway module query methods + go_ref QueryClient_GetGateway(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllGateways(AsyncOperation* op, go_ref self_ref, char *address); + + // Supplier module query methods + go_ref QueryClient_GetSupplier(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllSuppliers(AsyncOperation* op, go_ref self_ref, char *address); + + // Session module query methods + go_ref QueryClient_GetSession(AsyncOperation* op, go_ref self_ref, char *address); + + // Service module query methods + go_ref QueryClient_GetService(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllServices(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetRelayMiningDifficulty(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllRelayMiningDifficulties(AsyncOperation* op, go_ref self_ref, char *address); + + // Proof module query methods + go_ref QueryClient_GetClaim(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllClaims(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetProof(AsyncOperation* op, go_ref self_ref, char *address); + go_ref QueryClient_GetAllProofs(AsyncOperation* op, go_ref self_ref, char *address); """) diff --git a/src/poktroll_clients/query_client.py b/src/poktroll_clients/query_client.py new file mode 100644 index 0000000..863cb58 --- /dev/null +++ b/src/poktroll_clients/query_client.py @@ -0,0 +1,20 @@ +from poktroll_clients import ( + go_ref, + ffi, + libpoktroll_clients, + GoManagedMem, +) + + +class QueryClient(GoManagedMem): + """ + TODO_IN_THIS_COMMIT: comment + """ + + go_ref: go_ref + err_ptr: ffi.CData + + def __init__(self, query_node_rpc_url: str): + self_ref = libpoktroll_clients.NewQueryClient(query_node_rpc_url.encode('utf-8'), + self.err_ptr) + super().__init__(self_ref) From e31a248014ae06c856d4bc5ec349c5411c6ca8bc Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 17 Dec 2024 13:46:02 +0100 Subject: [PATCH 4/4] wip: add query client support --- src/poktroll_clients/block_client.py | 2 +- src/poktroll_clients/events_query_client.py | 4 +- src/poktroll_clients/ffi.py | 23 +-- src/poktroll_clients/go_memory.py | 4 +- src/poktroll_clients/protobuf.py | 98 +++++++++++++ src/poktroll_clients/query_client.py | 153 +++++++++++++++++++- src/poktroll_clients/tx_client.py | 2 + tests/test_query_client.py | 27 ++++ 8 files changed, 295 insertions(+), 18 deletions(-) create mode 100644 tests/test_query_client.py diff --git a/src/poktroll_clients/block_client.py b/src/poktroll_clients/block_client.py index dd6456a..c5c6df4 100644 --- a/src/poktroll_clients/block_client.py +++ b/src/poktroll_clients/block_client.py @@ -25,7 +25,7 @@ class BlockQueryClient(GoManagedMem): TODO_IN_THIS_COMMIT: comment """ - self_ref: go_ref + go_ref: go_ref err_ptr: ffi.CData def __init__(self, query_node_rpc_url: str): diff --git a/src/poktroll_clients/events_query_client.py b/src/poktroll_clients/events_query_client.py index 34a37e7..a51eb49 100644 --- a/src/poktroll_clients/events_query_client.py +++ b/src/poktroll_clients/events_query_client.py @@ -11,8 +11,8 @@ class EventsQueryClient(GoManagedMem): err_ptr: ffi.CData def __init__(self, query_node_rpc_websocket_url: str): - go_ref = libpoktroll_clients.NewEventsQueryClient(query_node_rpc_websocket_url.encode('utf-8')) - super().__init__(go_ref) + self_ref = libpoktroll_clients.NewEventsQueryClient(query_node_rpc_websocket_url.encode('utf-8')) + super().__init__(self_ref) def EventsBytes(self, query: str) -> go_ref: return libpoktroll_clients.EventsQueryClientEventsBytes(self.go_ref, query.encode('utf-8')) diff --git a/src/poktroll_clients/ffi.py b/src/poktroll_clients/ffi.py index 9c18aa9..b239e47 100644 --- a/src/poktroll_clients/ffi.py +++ b/src/poktroll_clients/ffi.py @@ -30,6 +30,7 @@ long long int __align; } pthread_cond_t; + // TODO: convert to snake case typedef struct AsyncContext { pthread_mutex_t mutex; pthread_cond_t cond; @@ -45,6 +46,7 @@ typedef void (*error_callback)(AsyncContext* ctx, const char* error); typedef void (*cleanup_callback)(AsyncContext* ctx); + // TODO: convert to snake case typedef struct AsyncOperation { AsyncContext* ctx; success_callback on_success; @@ -78,6 +80,8 @@ serialized_proto* messages; size_t num_messages; } proto_message_array; + + serialized_proto* GetGoProtoAsSerializedProto(go_ref go_proto_ref, char **err); go_ref NewEventsQueryClient(const char* comet_websocket_url); go_ref EventsQueryClientEventsBytes(go_ref selfRef, const char* query); @@ -134,17 +138,18 @@ go_ref TxClient_CreateClaim(AsyncOperation* op, go_ref self_ref, char *owner_address, char *session_header, char *root_hash, char *proof); go_ref TxClient_SubmitProof(AsyncOperation* op, go_ref self_ref, char *owner_address, char *session_header, char *proof); - go_ref NewQueryClient(char *query_node_rpc_url, char **err); + go_ref NewQueryClient(go_ref deps_ref, char *query_node_rpc_url, char **err); // Params query methods (all modules) - go_ref QueryClient_GatSharedParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatApplicationParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatGatewayParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatSupplierParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatSessionParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatServiceParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatProofParams(AsyncOperation* op, go_ref self_ref); - go_ref QueryClient_GatTokenomicsParams(AsyncOperation* op, go_ref self_ref); + // go_ref QueryClient_GetSharedParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetSharedParams(go_ref self_ref, char **err); + go_ref QueryClient_GetApplicationParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetGatewayParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetSupplierParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetSessionParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetServiceParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetProofParams(AsyncOperation* op, go_ref self_ref); + go_ref QueryClient_GetTokenomicsParams(AsyncOperation* op, go_ref self_ref); // Application module query methods go_ref QueryClient_GetApplication(AsyncOperation* op, go_ref self_ref, char *address); diff --git a/src/poktroll_clients/go_memory.py b/src/poktroll_clients/go_memory.py index be54f43..f19577e 100644 --- a/src/poktroll_clients/go_memory.py +++ b/src/poktroll_clients/go_memory.py @@ -10,7 +10,7 @@ # TODO_IN_THIS_COMMIT: switch to an err_msg[] array -def check_err(err_ptr: ffi.CData): +def check_err(err_ptr: ffi.CData) -> None: """ TODO_IN_THIS_COMMIT: comment... """ @@ -18,7 +18,7 @@ def check_err(err_ptr: ffi.CData): raise FFIError(ffi.string(err_ptr[0])) -def check_ref(go_ref: go_ref): +def check_ref(go_ref: go_ref) -> None: if go_ref < 1: raise FFIError("unexpected emtpy go_ref") diff --git a/src/poktroll_clients/protobuf.py b/src/poktroll_clients/protobuf.py index 70a37dc..d92917f 100644 --- a/src/poktroll_clients/protobuf.py +++ b/src/poktroll_clients/protobuf.py @@ -1,6 +1,11 @@ +import importlib from dataclasses import dataclass from typing import List +from google.protobuf import symbol_database, message +from google.protobuf.json_format import MessageToDict + +from poktroll_clients import go_ref, libpoktroll_clients, check_err from poktroll_clients.ffi import ffi @@ -13,6 +18,21 @@ class SerializedProto: type_url: str data: bytes + @staticmethod + def from_c_struct(c_serialized_proto: ffi.CData): + return SerializedProto( + type_url=(ffi.string(c_serialized_proto.type_url, c_serialized_proto.type_url_length).decode('utf-8')), + data=(bytes(ffi.buffer(c_serialized_proto.data, c_serialized_proto.data_length))), + ) + + def __init__(self, c_serialized_proto: ffi.CData = None, type_url: str = "", data: bytes = b""): + self.type_url = type_url + self.data = data + + if c_serialized_proto is not None: + self.type_url = ffi.string(c_serialized_proto.type_url, c_serialized_proto.type_url_length).decode('utf-8') + self.data = bytes(ffi.buffer(c_serialized_proto.data, c_serialized_proto.data_length)) + def to_c_struct(self) -> ffi.CData: """ Converts the Python protobuf data to a C struct while preserving the underlying memory. @@ -68,3 +88,81 @@ def to_c_struct(self) -> ffi.CData: proto_message_array.messages[i].data_length = c_msg.data_length return proto_message_array + + +def get_serialized_proto(go_proto_ref: go_ref) -> SerializedProto: + """ + TODO_IN_THIS_COMMIT: move and comment... + """ + err_ptr = ffi.new("char **") + + c_serialized_proto = libpoktroll_clients.GetGoProtoAsSerializedProto(go_proto_ref, err_ptr) + + check_err(err_ptr) + + return SerializedProto.from_c_struct(c_serialized_proto) + + +def deserialize_protobuf(serialized_data: bytes, type_url: str) -> message.Message: + """ + Deserialize protocol buffer data given a type URL. + + Args: + serialized_data: Bytes containing the serialized protobuf message + type_url: Type URL in format "type.googleapis.com/package.MessageType" + or "package.MessageType" + Returns: + dict: Deserialized protobuf message as a dictionary + + Raises: + ValueError: If type URL is invalid or message type cannot be found + ImportError: If the protobuf module cannot be imported + """ + try: + # First, import the module containing the protobuf classes + # This ensures the types are registered in the symbol database + type_url = type_url.lstrip("/") + poktroll_namespace = type_url.rsplit(".", 1)[0] + package_filename = f"{type_url.rsplit('.', 1)[1].lower()}_pb2" + package_module = f"poktroll_clients.proto.{poktroll_namespace}.{package_filename}" + importlib.import_module(package_module) + except ImportError as e: + raise ImportError(f"Could not import protobuf module {package_module}: {str(e)}") + + # Extract the full message type from the type URL + if '/' in type_url: + _, full_type = type_url.split('/', 1) + else: + full_type = type_url + + # Split into package and message type to validate format + parts = full_type.split('.') + if len(parts) < 2: + raise ValueError("Invalid type URL format") + + try: + # Get the message class from the symbol database + db = symbol_database.Default() + message_class = db.GetSymbol(full_type) + + # Create a new message instance and parse the data + message = message_class() + message.ParseFromString(serialized_data) + + return message + # # Convert to dictionary for easier handling + # return MessageToDict(message) + + except KeyError as e: + raise ValueError( + f"Could not find message type: {full_type}. Make sure it's registered in the symbol database.") from e + except Exception as e: + raise ValueError(f"Error deserializing protobuf: {str(e)}") from e + + +def get_proto_from_go_ref(go_proto_ref: go_ref) -> message.Message: + """ + TODO_IN_THIS_COMMIT: move and comment... + """ + serialized_proto = get_serialized_proto(go_proto_ref) + return deserialize_protobuf(serialized_proto.data, serialized_proto.type_url) diff --git a/src/poktroll_clients/query_client.py b/src/poktroll_clients/query_client.py index 863cb58..37d682d 100644 --- a/src/poktroll_clients/query_client.py +++ b/src/poktroll_clients/query_client.py @@ -1,9 +1,24 @@ +import asyncio +from typing import Tuple, Dict + +from atomics import INTEGRAL, atomic, INT +from cffi import FFIError + from poktroll_clients import ( go_ref, ffi, libpoktroll_clients, - GoManagedMem, + GoManagedMem, BlockQueryClient, Supply, check_err, check_ref, ) +from poktroll_clients.proto.poktroll.shared.params_pb2 import Params as SharedParams +from poktroll_clients.proto.poktroll.application.params_pb2 import Params as ApplicationParams +from poktroll_clients.proto.poktroll.gateway.params_pb2 import Params as GatewayParams +from poktroll_clients.proto.poktroll.supplier.params_pb2 import Params as SupplierParams +from poktroll_clients.proto.poktroll.session.params_pb2 import Params as SessionParams +from poktroll_clients.proto.poktroll.service.params_pb2 import Params as ServiceParams +from poktroll_clients.proto.poktroll.proof.params_pb2 import Params as ProofParams +from poktroll_clients.proto.poktroll.tokenomics.params_pb2 import Params as TokenomicsParams +from poktroll_clients.protobuf import get_proto_from_go_ref class QueryClient(GoManagedMem): @@ -13,8 +28,138 @@ class QueryClient(GoManagedMem): go_ref: go_ref err_ptr: ffi.CData + # _callback_idx: INTEGRAL = atomic(width=8, atype=INT) + # _callback_fns: Dict[int, Tuple[ffi.CData, ffi.CData, ffi.CData]] = {} + + def __init__(self, query_node_rpc_url: str, deps_ref: go_ref = -1): + if deps_ref == -1: + deps_ref = _new_query_client_depinject_config(query_node_rpc_url) - def __init__(self, query_node_rpc_url: str): - self_ref = libpoktroll_clients.NewQueryClient(query_node_rpc_url.encode('utf-8'), - self.err_ptr) + self_ref = libpoktroll_clients.NewQueryClient(deps_ref, + query_node_rpc_url.encode('utf-8'), + self.err_ptr) super().__init__(self_ref) + + # async def get_shared_params(self) -> asyncio.Future[SharedParams]: + # op, future = self._new_async_operation() + # + # err_ch_ref = libpoktroll_clients.QueryClient_GetSharedParams( # <-- line 71 + # op, + # self.go_ref, + # ) + # + # if err_ch_ref == -1: + # error_msg = ffi.string(op.ctx.error_msg).decode('utf-8') + # future.set_exception(FFIError(error_msg)) + # + # return await future + + def get_shared_params(self) -> asyncio.Future[SharedParams]: + response_ref = libpoktroll_clients.QueryClient_GetSharedParams(self.go_ref, self.err_ptr) + check_err(self.err_ptr) + check_ref(response_ref) + + return get_proto_from_go_ref(response_ref) + + def get_application_params(self) -> ApplicationParams: + response_ref = libpoktroll_clients.QueryClient_GetApplicationParams(self.go_ref, self.err_ptr) + + def get_supplier_params(self) -> SupplierParams: + response_ref = libpoktroll_clients.QueryClient_GetSupplierParams(self.go_ref, self.err_ptr) + + def get_gateway_params(self) -> GatewayParams: + response_ref = libpoktroll_clients.QueryClient_GetGatewayParams(self.go_ref, self.err_ptr) + + def get_session_params(self) -> SessionParams: + response_ref = libpoktroll_clients.QueryClient_GetSessionParams(self.go_ref, self.err_ptr) + + def get_service_params(self) -> ServiceParams: + response_ref = libpoktroll_clients.QueryClient_GetServiceParams(self.go_ref, self.err_ptr) + + def get_proof_params(self) -> ProofParams: + response_ref = libpoktroll_clients.QueryClient_GetProofParams(self.go_ref, self.err_ptr) + + def get_tokenomics_params(self) -> TokenomicsParams: + response_ref = libpoktroll_clients.QueryClient_GetTokenomicsParams(self.go_ref, self.err_ptr) + + # TODO_CONSIDERATION: support an async API as well? + + # def _new_async_operation(self) -> Tuple[ffi.CData, asyncio.Future]: + # """ + # Creates a new AsyncOperation with callbacks and associated Future. + # The callbacks are protected from garbage collection by storing in self._callback_fns. + # + # TODO_IN_THIS_COMMIT: & de-duplicate w/ TxClient... + # """ + # + # try: + # loop = asyncio.get_running_loop() + # except RuntimeError: + # loop = asyncio.new_event_loop() + # asyncio.set_event_loop(loop) + # + # future = loop.create_future() + # + # # Create AsyncContext + # ctx = ffi.new("AsyncContext *") + # next_callback_idx = self._callback_idx.fetch_inc() + # + # # Define callbacks + # @ffi.callback("void(AsyncContext*, const void*)") + # def success_cb(ctx: ffi.CData, response_ref: go_ref): + # try: + # print("success_cb") + # # serialized_proto_response = ffi.cast("serialized_proto*", response_ref) + # response = get_proto_from_go_ref(response_ref).params + # loop.call_soon_threadsafe(future.set_result, response) + # finally: + # self._free_callback(next_callback_idx) + # + # @ffi.callback("void(AsyncContext*, const char*)") + # def error_cb(ctx, error): + # print("error_cb") + # try: + # error_str = ffi.string(error).decode('utf-8') + # loop.call_soon_threadsafe(future.set_exception, Exception(error_str)) + # except Exception as e: + # future.set_exception(e) + # finally: + # self._free_callback(next_callback_idx) + # + # @ffi.callback("void(AsyncContext*)") + # def cleanup_cb(ctx): + # self._free_callback(next_callback_idx) + # + # # Create AsyncOperation + # op = ffi.new("AsyncOperation *") + # op.ctx = ctx + # op.on_success = success_cb + # op.on_error = error_cb + # op.cleanup = cleanup_cb + # + # # Store callbacks to protect from garbage collection + # self._callback_fns[next_callback_idx] = (success_cb, error_cb, cleanup_cb) + # + # return op, future + + def _free_callback(self, callback_idx: int): + """ + Clean up stored callbacks. + """ + self._callback_fns.pop(callback_idx) + + +def _new_query_client_depinject_config( + query_node_rpc_url: str, +) -> go_ref: + """ + TODO_IN_THIS_COMMIT: comment + """ + + # TODO_IN_THIS_COMMIT: add more detail to the error messages, + # explaining the expected format, with an example. + if not query_node_rpc_url: + raise ValueError("query_node_rpc_url must be specified") + + block_query_client = BlockQueryClient(query_node_rpc_url) + return Supply(block_query_client.go_ref) diff --git a/src/poktroll_clients/tx_client.py b/src/poktroll_clients/tx_client.py index aa240f6..3157da4 100644 --- a/src/poktroll_clients/tx_client.py +++ b/src/poktroll_clients/tx_client.py @@ -85,6 +85,8 @@ def _new_async_operation(self) -> Tuple[ffi.CData, asyncio.Future]: """ Creates a new AsyncOperation with callbacks and associated Future. The callbacks are protected from garbage collection by storing in self._callback_fns. + + TODO_IN_THIS_COMMIT: & de-duplicate w/ QueryClient... """ try: diff --git a/tests/test_query_client.py b/tests/test_query_client.py new file mode 100644 index 0000000..6289399 --- /dev/null +++ b/tests/test_query_client.py @@ -0,0 +1,27 @@ +from pprint import pprint + +import pytest + +from poktroll_clients.proto.poktroll.shared.params_pb2 import Params as SharedParams +from poktroll_clients.query_client import QueryClient + + +# @pytest.mark.asyncio +def test_query_client(): + query_client = QueryClient("http://127.0.0.1:26657") + + # shared_params = await query_client.get_shared_params() + shared_params = query_client.get_shared_params() + + expected_shared_params = SharedParams( + num_blocks_per_session=10, + grace_period_end_offset_blocks=1, + claim_window_open_offset_blocks=1, + claim_window_close_offset_blocks=4, + proof_window_close_offset_blocks=4, + supplier_unbonding_period_sessions=1, + application_unbonding_period_sessions=1, + compute_units_to_tokens_multiplier=42, + ) + + assert shared_params == expected_shared_params