diff --git a/pyproject.toml b/pyproject.toml index 3236323..89a3885 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "sentinel_sdk" -version = "0.0.5" +version = "0.1.3" description = "A Sentinel SDK Written in Python" authors = [ { name = "NAST0R" }, @@ -13,7 +13,7 @@ authors = [ ] readme = "README.md" requires-python = ">=3.10" -keywords = ["sentinel_sdk", "mospy", "sentinel", "cosmos", "protobuf", "sentinel_protobuf"] +keywords = ["sentinel_sdk", "mospy", "sentinel", "dvpn", "cosmos", "protobuf", "sentinel_protobuf"] license = {text = "GPL-3.0 license"} classifiers = [ "Development Status :: 3 - Alpha", @@ -22,7 +22,7 @@ classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", ] dependencies = [ - "sentinel-protobuf==0.3.3", + "sentinel-protobuf==0.5.1", "grpcio>=1.51.1", "bip-utils==2.9.0", "mospy-wallet==0.6.0", diff --git a/requirements.txt b/requirements.txt index e706fa9..720a7ef 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -sentinel-protobuf==0.3.3 +sentinel-protobuf==0.4.3 grpcio>=1.51.1 bip-utils==2.9.0 -mospy-wallet @ git+https://github.com/Tkd-Alex/mospy.git@development +mospy-wallet==0.6.0 diff --git a/src/sentinel_sdk/modules/lease.py b/src/sentinel_sdk/modules/lease.py new file mode 100644 index 0000000..a3dfb16 --- /dev/null +++ b/src/sentinel_sdk/modules/lease.py @@ -0,0 +1,65 @@ + +import grpc +import sentinel_protobuf.sentinel.lease.v1.lease_pb2 as lease_pb2 +import sentinel_protobuf.sentinel.lease.v1.querier_pb2 as sentinel_subscription_v2_querier_pb2 +import sentinel_protobuf.sentinel.lease.v1.querier_pb2_grpc as sentinel_subscription_v2_querier_pb2_grpc +import sentinel_protobuf.sentinel.subscription.v2.subscription_pb2 as subscription_pb2 +import sentinel_protobuf.sentinel.lease.v1.msg_pb2 as msg_pb2 +from sentinel_protobuf.sentinel.types.v1.price_pb2 import Price +from sentinel_protobuf.sentinel.types.v1.renewal_pb2 import RenewalPricePolicy + +from sentinel_sdk.querier.querier import Querier +from sentinel_sdk.transactor.transactor import Transactor +from sentinel_sdk.types import PageRequest, TxParams + +class LeaseModule(Querier, Transactor): + def __init__(self, channel: grpc.Channel, account, provider_account, client): + self.__stub = sentinel_subscription_v2_querier_pb2_grpc.QueryServiceStub( + channel + ) + self._account = account + self._client = client + self._provider_account = provider_account + + def EndLease(self, subscription_id: int, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgEndLeaseRequest( + frm = self._provider_account.address, + id = subscription_id, + ) + + return self.transaction([msg], tx_params) + + def RenewLease(self, subscription_id: int, hours: int, max_price: Price = Price, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgRenewLeaseRequest( + frm = self._provider_account.address, + id = subscription_id, + hours = hours, + max_price = max_price, + ) + + return self.transaction([msg], tx_params) + + def StartLease(self, node: str, hours: int, max_price: Price, renewal: int = RenewalPricePolicy.RENEWAL_PRICE_POLICY_IF_LESSER_OR_EQUAL, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgStartLeaseRequest( + frm = self._provider_account.address, + node_address = node, + hours = hours, + max_price = max_price, + renewal_price_policy = renewal, + ) + + return self.transaction([msg], tx_params) + + def UpdateLease(self, subscription_id: int, renewal: int = RenewalPricePolicy.RENEWAL_PRICE_POLICY_IF_LESSER_OR_EQUAL, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgUpdateLeaseRequest( + frm = self._provider_account.address, + id = subscription_id, + renewal_price_policy = renewal, + ) + + return self.transaction([msg], tx_params) + + + + + \ No newline at end of file diff --git a/src/sentinel_sdk/modules/node.py b/src/sentinel_sdk/modules/node.py index 5df66f3..1e45d73 100755 --- a/src/sentinel_sdk/modules/node.py +++ b/src/sentinel_sdk/modules/node.py @@ -10,10 +10,12 @@ import hashlib import ecdsa import grpc -import sentinel_protobuf.sentinel.node.v2.node_pb2 as node_pb2 -import sentinel_protobuf.sentinel.node.v2.querier_pb2 as sentinel_node_v2_querier_pb2 -import sentinel_protobuf.sentinel.node.v2.querier_pb2_grpc as sentinel_node_v2_querier_pb2_grpc +import sentinel_protobuf.sentinel.node.v3.node_pb2 as node_pb2 +import sentinel_protobuf.sentinel.node.v3.querier_pb2 as sentinel_node_v3_querier_pb2 +import sentinel_protobuf.sentinel.node.v3.querier_pb2_grpc as sentinel_node_v3_querier_pb2_grpc import sentinel_protobuf.sentinel.node.v2.msg_pb2 as msg_pb2 +import sentinel_protobuf.sentinel.node.v3.msg_pb2 as msg_pb2_3 +from sentinel_protobuf.sentinel.types.v1.price_pb2 import Price from sentinel_sdk.querier.querier import Querier from sentinel_sdk.transactor.transactor import Transactor @@ -25,7 +27,7 @@ class NodeModule(Querier, Transactor): def __init__(self, channel: grpc.Channel, node_timeout: int, account, client): self.node_timeout = node_timeout - self.__stub = sentinel_node_v2_querier_pb2_grpc.QueryServiceStub(channel) + self.__stub = sentinel_node_v3_querier_pb2_grpc.QueryServiceStub(channel) # Disable SSL verification self.__ssl_ctx = ssl.create_default_context() @@ -36,20 +38,20 @@ def __init__(self, channel: grpc.Channel, node_timeout: int, account, client): self._client = client self.__nodes_status_cache = {} - + def QueryParams(self) -> Any: - return self.__stub.QueryParams(sentinel_node_v2_querier_pb2.QueryParamsRequest()).params - + return self.__stub.QueryParams(sentinel_node_v3_querier_pb2.QueryParamsRequest()).params + def QueryNode(self, address: str) -> Any: r = self.__stub.QueryNode( - sentinel_node_v2_querier_pb2.QueryNodeRequest(address=address) + sentinel_node_v3_querier_pb2.QueryNodeRequest(address=address) ) return r.node def QueryNodes(self, status: int, pagination: PageRequest = None) -> list: return self.QueryAll( query=self.__stub.QueryNodes, - request=sentinel_node_v2_querier_pb2.QueryNodesRequest, + request=sentinel_node_v3_querier_pb2.QueryNodesRequest, attribute="nodes", status=status.value, pagination=pagination, @@ -57,20 +59,38 @@ def QueryNodes(self, status: int, pagination: PageRequest = None) -> list: def QueryNumOfNodesWithStatus(self, status: int) -> int: r = self.__stub.QueryNodes( - sentinel_node_v2_querier_pb2.QueryNodesRequest(status=status.value) + sentinel_node_v3_querier_pb2.QueryNodesRequest(status=status.value) ) return r.pagination.total def QueryNodeStatus(self, node: node_pb2.Node, is_in_thread: bool = False) -> str: - node_endpoint = node.remote_url + node_endpoint = "https://" + node.remote_addrs[0] + gb_price = "" + hr_price = "" + if node.gigabyte_prices: + for prices in node.gigabyte_prices: + gb_price = gb_price + prices.quote_value + prices.denom + ',' + else: + gb_price = "0udvpn" + if node.hourly_prices: + for prices in node.hourly_prices: + hr_price = hr_price + prices.quote_value + prices.denom + ',' + else: + hr_price = "0udvpn" + + gb_price = gb_price.rstrip(',') + hr_price = hr_price.rstrip(',') + print(f"GB Prices: {gb_price}\n Hourly Prices: {hr_price}") + print(f"Node Endpoint: {node_endpoint}") try: contents = urllib.request.urlopen( - f"{node_endpoint}/status", + f"{node_endpoint}", context=self.__ssl_ctx, timeout=self.node_timeout, ).read() contents = contents.decode("utf-8") - except urllib.error.URLError: + except urllib.error.URLError as E: + print(str(E)) contents = '{"success":false,"urllib-error":"URLError encountered"}' except TimeoutError: contents = '{"success":false,"urllib-error":"Data reading timed out"}' @@ -78,6 +98,11 @@ def QueryNodeStatus(self, node: node_pb2.Node, is_in_thread: bool = False) -> st contents = '{"success":false,"http-error":"Remote endpoint closed connection"}' except: contents = '{"success":false,"error":"Unrecognizable error encountered"}' + contents = json.loads(contents) + contents['gigabyte_prices'] = gb_price + contents['hourly_prices'] = hr_price + contents = json.dumps(contents) + if is_in_thread: self.__nodes_status_cache[node.address] = contents else: @@ -103,7 +128,7 @@ def QueryNodesForPlan( ) -> list: return self.QueryAll( query=self.__stub.QueryNodesForPlan, - request=sentinel_node_v2_querier_pb2.QueryNodesForPlanRequest, + request=sentinel_node_v3_querier_pb2.QueryNodesForPlanRequest, attribute="nodes", status=status.value, id=plan_id, @@ -128,17 +153,16 @@ def RegisterNode(self, gigabyte_prices: int, hourly_prices: int, remote_url: str remote_url=remote_url, ) return self.transaction([msg], tx_params) - - def SubscribeToNode(self, node_address: str, gigabytes: int = 0, hours: int = 0, denom: str = "udvpn", tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgSubscribeRequest( + + def SubscribeToNode(self, node_address: str, price: Price, gigabytes: int = 0, hours: int = 0, next_sequence: bool = False, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgStartSessionRequest( frm = self._account.address, - denom = denom, gigabytes = gigabytes, hours = hours, node_address = node_address, + max_price = price, ) - return self.transaction([msg], tx_params) - + return self.transaction([msg], tx_params, next_sequence) def UpdateNodeDetails(self, gigabyte_prices: int, hourly_prices: int, remote_url: str, tx_params: TxParams = TxParams()): msg = msg_pb2.MsgUpdateDetailsRequest( frm = self._account.address, diff --git a/src/sentinel_sdk/modules/plan.py b/src/sentinel_sdk/modules/plan.py index ea91c2e..9843bcb 100755 --- a/src/sentinel_sdk/modules/plan.py +++ b/src/sentinel_sdk/modules/plan.py @@ -4,6 +4,7 @@ import sentinel_protobuf.sentinel.plan.v2.querier_pb2 as sentinel_plan_v2_querier_pb2 import sentinel_protobuf.sentinel.plan.v2.querier_pb2_grpc as sentinel_plan_v2_querier_pb2_grpc import sentinel_protobuf.sentinel.plan.v2.msg_pb2 as msg_pb2 +import sentinel_protobuf.sentinel.plan.v3.msg_pb2 as msg_pb2_3 from sentinel_sdk.querier.querier import Querier from sentinel_sdk.transactor.transactor import Transactor @@ -59,13 +60,14 @@ def Create(self, duration: int, gigabytes: int, prices: int, tx_params: TxParams return self.transaction([msg], tx_params) def LinkNode(self, plan_id: int, node_address: str, tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgLinkNodeRequest( + msg = msg_pb2_3.MsgLinkNodeRequest( frm = self._provider_account.address, id = plan_id, node_address = node_address, ) return self.transaction([msg], tx_params) - + + ''' def Subscribe(self, denom: str, plan_id: int, tx_params: TxParams = TxParams()): msg = msg_pb2.MsgSubscribeRequest( frm = self._account.address, @@ -73,9 +75,10 @@ def Subscribe(self, denom: str, plan_id: int, tx_params: TxParams = TxParams()): denom = denom, ) return self.transaction([msg], tx_params) + ''' def UnlinkNode(self, plan_id: int, node_address: str, tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgUnlinkNodeRequest( + msg = msg_pb2_3.MsgUnlinkNodeRequest( frm = self._provider_account.address, id = plan_id, node_address = node_address, diff --git a/src/sentinel_sdk/modules/session.py b/src/sentinel_sdk/modules/session.py index 87bee9b..96ec55d 100755 --- a/src/sentinel_sdk/modules/session.py +++ b/src/sentinel_sdk/modules/session.py @@ -1,12 +1,10 @@ from typing import Any import grpc -import sentinel_protobuf.sentinel.session.v2.querier_pb2 as sentinel_session_v2_querier_pb2 -import sentinel_protobuf.sentinel.session.v2.querier_pb2_grpc as sentinel_session_v2_querier_pb2_grpc -import sentinel_protobuf.sentinel.session.v2.msg_pb2 as msg_pb2 +import sentinel_protobuf.sentinel.session.v3.querier_pb2 as sentinel_session_v3_querier_pb2 +import sentinel_protobuf.sentinel.session.v3.querier_pb2_grpc as sentinel_session_v3_querier_pb2_grpc +import sentinel_protobuf.sentinel.session.v3.msg_pb2 as msg_pb2 -from sentinel_protobuf.sentinel.session.v2 import proof_pb2 -from sentinel_protobuf.sentinel.types.v1.bandwidth_pb2 import Bandwidth from google.protobuf.duration_pb2 import Duration from sentinel_sdk.querier.querier import Querier @@ -16,14 +14,14 @@ class SessionModule(Querier, Transactor): def __init__(self, channel: grpc.Channel, account, client): - self.__stub = sentinel_session_v2_querier_pb2_grpc.QueryServiceStub(channel) + self.__stub = sentinel_session_v3_querier_pb2_grpc.QueryServiceStub(channel) self._account = account self._client = client def QuerySession(self, session_id: int) -> Any: try: r = self.__stub.QuerySession( - sentinel_session_v2_querier_pb2.QuerySessionRequest(id=session_id) + sentinel_session_v3_querier_pb2.QuerySessionRequest(id=session_id) ) except grpc._channel._InactiveRpcError as e: print(e) @@ -34,7 +32,7 @@ def QuerySession(self, session_id: int) -> Any: def QuerySessions(self, pagination: PageRequest = None) -> list: return self.QueryAll( query=self.__stub.QuerySessions, - request=sentinel_session_v2_querier_pb2.QuerySessionsRequest, + request=sentinel_session_v3_querier_pb2.QuerySessionsRequest, attribute="sessions", pagination=pagination, ) @@ -44,7 +42,7 @@ def QuerySessionsForAccount( ) -> list: return self.QueryAll( query=self.__stub.QuerySessionsForAccount, - request=sentinel_session_v2_querier_pb2.QuerySessionsForAccountRequest, + request=sentinel_session_v3_querier_pb2.QuerySessionsForAccountRequest, attribute="sessions", address=address, pagination=pagination, @@ -55,7 +53,7 @@ def QuerySessionsForAllocation( ) -> list: return self.QueryAll( query=self.__stub.QuerySessionsForAllocation, - request=sentinel_session_v2_querier_pb2.QuerySessionsForAllocationRequest, + request=sentinel_session_v3_querier_pb2.QuerySessionsForAllocationRequest, attribute="sessions", id=allocation_id, address=address, @@ -67,7 +65,7 @@ def QuerySessionsForNode( ) -> list: return self.QueryAll( query=self.__stub.QuerySessionsForNode, - request=sentinel_session_v2_querier_pb2.QuerySessionsForNodeRequest, + request=sentinel_session_v3_querier_pb2.QuerySessionsForNodeRequest, attribute="sessions", address=address, pagination=pagination, @@ -78,39 +76,41 @@ def QuerySessionsForSubscription( ) -> list: return self.QueryAll( query=self.__stub.QuerySessionsForSubscription, - request=sentinel_session_v2_querier_pb2.QuerySessionsForSubscriptionRequest, + request=sentinel_session_v3_querier_pb2.QuerySessionsForSubscriptionRequest, attribute="sessions", id=subscription_id, pagination=pagination, ) - def StartSession(self, address: str, subscription_id: int, tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgStartRequest( - frm = self._account.address, - id = subscription_id, - address = address + def EndSession(self, session_id: int, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgCancelSessionRequest( + frm=self._account.address, + id=session_id, ) return self.transaction([msg], tx_params) - def EndSession(self, session_id: int, rating: int, tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgEndRequest( - frm = self._account.address, - id = session_id, - rating = rating, + def UpdateSession( + self, + session_id: int, + download_bytes: int, + upload_bytes: int, + duration_seconds: int, + signature: bytes, + tx_params: TxParams = TxParams(), + ): + msg = msg_pb2.MsgUpdateSessionRequest( + frm=self._account.address, + id=session_id, + download_bytes=str(download_bytes), + upload_bytes=str(upload_bytes), + duration=Duration(seconds=duration_seconds), + signature=signature, ) return self.transaction([msg], tx_params) - def UpdateDetails(self, proof: proof_pb2.Proof, signature: bytes, tx_params: TxParams = TxParams()): - msg = msg_pb2.MsgUpdateDetailsRequest( - frm = self._account.address, - proof = proof, - signature = signature, + def UpdateParams(self, params, tx_params: TxParams = TxParams()): + msg = msg_pb2.MsgUpdateParamsRequest( + frm=self._account.address, + params=params, ) return self.transaction([msg], tx_params) - - def Proof(self, session_id: int, bandwidth: Bandwidth, duration: Duration) -> proof_pb2.Proof: - return proof_pb2.Proof( - id=session_id, - bandwidth=bandwidth, - duration=duration - ) \ No newline at end of file diff --git a/src/sentinel_sdk/modules/subscription.py b/src/sentinel_sdk/modules/subscription.py index 81b0c7f..4675acd 100755 --- a/src/sentinel_sdk/modules/subscription.py +++ b/src/sentinel_sdk/modules/subscription.py @@ -1,10 +1,11 @@ from typing import Any import grpc -import sentinel_protobuf.sentinel.subscription.v2.querier_pb2 as sentinel_subscription_v2_querier_pb2 -import sentinel_protobuf.sentinel.subscription.v2.querier_pb2_grpc as sentinel_subscription_v2_querier_pb2_grpc -import sentinel_protobuf.sentinel.subscription.v2.subscription_pb2 as subscription_pb2 -import sentinel_protobuf.sentinel.subscription.v2.msg_pb2 as msg_pb2 +import sentinel_protobuf.sentinel.subscription.v3.querier_pb2 as sentinel_subscription_v3_querier_pb2 +import sentinel_protobuf.sentinel.subscription.v3.querier_pb2_grpc as sentinel_subscription_v3_querier_pb2_grpc +import sentinel_protobuf.sentinel.subscription.v3.subscription_pb2 as subscription_pb2 +import sentinel_protobuf.sentinel.subscription.v3.msg_pb2 as msg_pb2_3 +from sentinel_protobuf.sentinel.types.v1.renewal_pb2 import RenewalPricePolicy from sentinel_sdk.querier.querier import Querier from sentinel_sdk.transactor.transactor import Transactor @@ -13,7 +14,7 @@ class SubscriptionModule(Querier, Transactor): def __init__(self, channel: grpc.Channel, account, client): - self.__stub = sentinel_subscription_v2_querier_pb2_grpc.QueryServiceStub( + self.__stub = sentinel_subscription_v3_querier_pb2_grpc.QueryServiceStub( channel ) self._account = account @@ -22,7 +23,7 @@ def __init__(self, channel: grpc.Channel, account, client): def QuerySubscription(self, subscription_id: int) -> Any: try: r = self.__stub.QuerySubscription( - sentinel_subscription_v2_querier_pb2.QuerySubscriptionRequest( + sentinel_subscription_v3_querier_pb2.QuerySubscriptionRequest( id=subscription_id ) ) @@ -35,7 +36,7 @@ def QuerySubscription(self, subscription_id: int) -> Any: def QuerySubscriptions(self, pagination: PageRequest = None) -> list: subscriptions = self.QueryAll( query=self.__stub.QuerySubscriptions, - request=sentinel_subscription_v2_querier_pb2.QuerySubscriptionsRequest, + request=sentinel_subscription_v3_querier_pb2.QuerySubscriptionsRequest, attribute="subscriptions", pagination=pagination, ) @@ -43,7 +44,9 @@ def QuerySubscriptions(self, pagination: PageRequest = None) -> list: self.__ConvertAnyToNodeSubscription(subscription.value) for subscription in subscriptions ] - + + # not in subscription/v3/querier.proto + ''' def QueryAllocation(self, address: str, subscription_id: int) -> list: try: r = self.__stub.QueryAllocation( @@ -106,13 +109,13 @@ def QueryPayoutsForNode(self, address: str, pagination: PageRequest = None) -> l address=address, pagination=pagination, ) - + ''' def QuerySubscriptionsForAccount( self, address: str, pagination: PageRequest = None ) -> list: subscriptions = self.QueryAll( query=self.__stub.QuerySubscriptionsForAccount, - request=sentinel_subscription_v2_querier_pb2.QuerySubscriptionsForAccountRequest, + request=sentinel_subscription_v3_querier_pb2.QuerySubscriptionsForAccountRequest, attribute="subscriptions", address=address, pagination=pagination, @@ -121,13 +124,15 @@ def QuerySubscriptionsForAccount( self.__ConvertAnyToNodeSubscription(subscription.value) for subscription in subscriptions ] - + + # deprecated + ''' def QuerySubscriptionsForNode( self, address: str, pagination: PageRequest = None ) -> list: subscriptions = self.QueryAll( query=self.__stub.QuerySubscriptionsForNode, - request=sentinel_subscription_v2_querier_pb2.QuerySubscriptionsForNodeRequest, + request=sentinel_subscription_v3_querier_pb2.QuerySubscriptionsForNodeRequest, attribute="subscriptions", address=address, pagination=pagination, @@ -136,13 +141,14 @@ def QuerySubscriptionsForNode( self.__ConvertAnyToNodeSubscription(subscription.value) for subscription in subscriptions ] - + ''' + def QuerySubscriptionsForPlan( self, plan_id: int, pagination: PageRequest = None ) -> list: subscriptions = self.QueryAll( query=self.__stub.QuerySubscriptionsForPlan, - request=sentinel_subscription_v2_querier_pb2.QuerySubscriptionsForPlanRequest, + request=sentinel_subscription_v3_querier_pb2.QuerySubscriptionsForPlanRequest, attribute="subscriptions", id=plan_id, pagination=pagination, @@ -151,7 +157,9 @@ def QuerySubscriptionsForPlan( self.__ConvertAnyToPlanSubscription(subscription.value) for subscription in subscriptions ] - + + # not in use anymore + ''' def Allocate(self, address: str, bytes: str, id: int, tx_params: TxParams = TxParams()): msg = msg_pb2.MsgAllocateRequest( frm = self._account.address, @@ -161,13 +169,67 @@ def Allocate(self, address: str, bytes: str, id: int, tx_params: TxParams = TxPa ) return self.transaction([msg], tx_params) + def Cancel(self, id: int, tx_params: TxParams = TxParams()): msg = msg_pb2.MsgCancelRequest( frm = self._account.address, id = id, ) return self.transaction([msg], tx_params) - + ''' + + # id is subscription id i.e., lease ID + def Cancel(self, id: int, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgCancelSubscriptionRequest( + frm = self._account.address, + id = id, + ) + return self.transaction([msg], tx_params) + + def RenewSubscription(self, subscription_id: int, denom: str, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgRenewSubscriptionRequest( + frm = self._account.address, + id = subscription_id, + denom = denom, + ) + return self.transaction([msg], tx_params) + + def ShareSubscription(self, subscription_id: int, wallet_address: str, bytes: str, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgShareSubscriptionRequest( + frm = self._account.address, + id = subscription_id, + acc_address = wallet_address, + bytes = bytes, + ) + return self.transaction([msg], tx_params) + + # id is plan_id + def StartSubscription(self, plan_id: int, denom: str, renewal: int = RenewalPricePolicy.RENEWAL_PRICE_POLICY_IF_LESSER_OR_EQUAL, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgStartSubscriptionRequest( + frm = self._account.address, + id = plan_id, + denom = denom, + renewal_price_polilcy = renewal, + ) + return self.transaction([msg], tx_params) + + def UpdateSubscription(self, subscription_id: int, renewal: int = RenewalPricePolicy.RENEWAL_PRICE_POLICY_IF_LESSER_OR_EQUAL, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgUpdateSubscriptionRequest( + frm = self._account.address, + id = id, + renewal_price_policy = renewal, + ) + return self.transaction([msg], tx_params) + + # Used for plan subs + def StartSession(self, address: str, subscription_id: int, next_sequence: bool = False, tx_params: TxParams = TxParams()): + msg = msg_pb2_3.MsgStartSessionRequest( + frm = self._account.address, + id = subscription_id, + node_address = address + ) + return self.transaction([msg], tx_params, next_sequence) + # Node subscriptions are returned by grpc querier in google's 'Any' type and need to be converted into desired protobuf type # # diff --git a/src/sentinel_sdk/querier/querier.py b/src/sentinel_sdk/querier/querier.py index 67113cc..b131a04 100755 --- a/src/sentinel_sdk/querier/querier.py +++ b/src/sentinel_sdk/querier/querier.py @@ -12,6 +12,7 @@ def QueryAll( pagination: PageRequest = None, **kwargs, ) -> list: + # ["status", "address", "id"] are the only valid kwargs request_arguments = { k: kwargs[k] for k in kwargs if k in ["status", "address", "id"] @@ -34,5 +35,4 @@ def QueryAll( # Stop iteration if PageRequest contain a offset value if pagination.offset is not None: break - return items \ No newline at end of file diff --git a/src/sentinel_sdk/sdk.py b/src/sentinel_sdk/sdk.py index d84a6c5..f7d0140 100755 --- a/src/sentinel_sdk/sdk.py +++ b/src/sentinel_sdk/sdk.py @@ -11,6 +11,7 @@ from sentinel_sdk.modules.provider import ProviderModule from sentinel_sdk.modules.session import SessionModule from sentinel_sdk.modules.subscription import SubscriptionModule +from sentinel_sdk.modules.lease import LeaseModule from mospy import Account from mospy.clients import GRPCClient @@ -138,6 +139,7 @@ def __load_modules(self): self.nodes = NodeModule(self._channel, 10, self._account, self._client) self.deposits = DepositModule(self._channel) self.plans = PlanModule(self._channel, self._account, self._provider_account, self._client) + self.lease = LeaseModule(self._channel, self._account, self._provider_account, self._client) self.providers = ProviderModule(self._channel, self._account, self._client) self.sessions = SessionModule(self._channel, self._account, self._client) self.subscriptions = SubscriptionModule(self._channel, self._account, self._client) @@ -149,7 +151,7 @@ def renew_account(self, secret: str): self.__load_modules() def renew_grpc(self, grpcaddr: str, grpcport: int, use_ssl: bool = False): - self._client = self.__create_client(grpcaddr, grpcport) + self._client = self.__create_client(grpcaddr, grpcport, use_ssl) self._client.load_account_data(account=self._account) self.__load_modules() diff --git a/src/sentinel_sdk/transactor/transactor.py b/src/sentinel_sdk/transactor/transactor.py index cbe0d6a..f2ebc78 100755 --- a/src/sentinel_sdk/transactor/transactor.py +++ b/src/sentinel_sdk/transactor/transactor.py @@ -38,6 +38,7 @@ def transaction( self, messages: list, tx_params: TxParams = TxParams(), + next_sequence: bool = False ) -> dict: if self._account is None or self._client is None: raise ValueError("Transactor was not initialized due missing secret, unable to transact") @@ -57,7 +58,10 @@ def transaction( tx.add_raw_msg(message, type_url=f"/{message.DESCRIPTOR.full_name}") # Required before each tx of we get account sequence mismatch, expected 945, got 944: incorrect account sequence - self._client.load_account_data(account=self._account) + #self._client.load_account_data(account=self._account) + + if next_sequence: + self._account.increase_sequence() # inplace, auto-update gas with update=True # auto calculate the gas only if was not already passed as args: diff --git a/src/sentinel_sdk/types.py b/src/sentinel_sdk/types.py index b5d1809..7a5423c 100755 --- a/src/sentinel_sdk/types.py +++ b/src/sentinel_sdk/types.py @@ -18,6 +18,7 @@ def __str__(self): class NodeType(Enum): WIREGUARD = 1 V2RAY = 2 + OPENVPN = 3 @dataclass class TxParams: @@ -26,7 +27,6 @@ class TxParams: gas: float = 0 gas_multiplier: float = 1.5 - class PageRequest: """ // key is a value returned in PageResponse.next_key to begin diff --git a/src/sentinel_sdk/utils.py b/src/sentinel_sdk/utils.py index 9bb611d..101cc7e 100755 --- a/src/sentinel_sdk/utils.py +++ b/src/sentinel_sdk/utils.py @@ -1,14 +1,20 @@ import json import base64 +from collections import OrderedDict # TODO: we want to move this method (?) # In the latest version of mospy the response was converted as dict # from google.protobuf.json_format import MessageToDict # https://github.com/ctrl-Felix/mospy/blob/ea07705b6ec4c76cc355b7dc933fae7c09fd8429/src/mospy/clients/GRPCClient.py#L155 def search_attribute(tx_response: dict, event_type: str, attribute_key: str) -> dict: + tx_response = ordered_dict_to_dict(tx_response) for event in tx_response.get("txResponse", tx_response).get("events", []): if event["type"] == event_type: for attribute in event["attributes"]: - if base64.b64decode(attribute["key"]) == attribute_key.encode(): - return json.loads(base64.b64decode(attribute["value"]).decode("utf-8")) + if attribute["key"] == attribute_key: + return json.loads(attribute["value"]) return None + + +def ordered_dict_to_dict(od): + return {k: (ordered_dict_to_dict(v) if isinstance(v, OrderedDict) else v) for k, v in od.items()}