Skip to content

Commit 4e6879a

Browse files
authored
Merge pull request #92 from singnet/SPS-6
Free calls updates
2 parents 44f814f + 45190c0 commit 4e6879a

9 files changed

Lines changed: 272 additions & 183 deletions

File tree

README.md

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,17 @@ visit the [Payment](#payment) section.
149149

150150
### Free call
151151

152-
If you want to use the free calls you will need to pass these arguments to the `create_service_client()` method:
152+
If you want to use the free calls you will need to pass this argument to the `create_service_client()` method:
153153

154154
```python
155-
free_call_auth_token_bin = "f2548d27ffd319b9c05918eeac15ebab934e5cfcd68e1ec3db2b92765",
156-
free_call_token_expiry_block = 172800,
157-
email = "test@test.com" # which using in AI marketplace account
155+
address = "YOUR_ETHEREUM_ADDRESS"
158156
```
159157

160-
You can receive these for a given service from the [Dapp](https://beta.singularitynet.io/)
161-
162158
Creating a service client with free calls included would look like this:
163159
```python
164160
service_client = snet_sdk.create_service_client(org_id="26072b8b6a0e448180f8c0e702ab6d2f",
165-
service_id="Exampleservice"
166-
free_call_auth_token_bin="f2548d27ffd319b9c05918eeac15ebab934e5cfcd68e1ec3db2b92765",
167-
free_call_token_expiry_block=172800,
168-
email="test@mail.com")
161+
service_id="Exampleservice",
162+
address="0xtest")
169163
```
170164

171165
### Paid call

docs/main/init.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ of the `ServiceClient` class with all the required parameters, which is then ret
7373
- `service_id` (str): The ID of the service.
7474
- `group_name` (str): The name of the payment group. Defaults to _None_.
7575
- `payment_strategy` (PaymentStrategy): The payment channel management strategy. Defaults to _None_.
76-
- `free_call_auth_token_bin` (str): The free call authentication token in binary format. Defaults to _None_.
77-
- `free_call_token_expiry_block` (int): The block number when the free call token expires. Defaults to _None_.
76+
- `address` (str): Wallet address to use free calls. Defaults to _None_.
7877
- `options` (dict): Additional options for the service client. Defaults to _None_.
7978
- `concurrent_calls` (int): The number of concurrent calls allowed. Defaults to 1.
8079

docs/payment_strategies/freecall_payment_strategy.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Entities:
77
- [is_free_call_available](#is_free_call_available)
88
- [get_payment_metadata](#get_payment_metadata)
99
- [generate_signature](#generate_signature)
10+
- [get_free_call_token_details](#get_free_call_token_details)
11+
- [select_channel](#select_channel)
1012

1113
### Class `FreeCallPaymentStrategy`
1214

@@ -17,7 +19,7 @@ is extended by: -
1719
#### description
1820

1921
The `FreeCallPaymentStrategy` class is a concrete implementation of the `PaymentStrategy` interface.
20-
It allows you to use free calls (which can be received from the [Dapp](https://beta.singularitynet.io/)) to
22+
It allows you to use free calls (which can be received from the daemon) to
2123
call services.
2224

2325
#### methods
@@ -68,3 +70,31 @@ Generates a signature for the given service client using the provided free call
6870
###### raises:
6971

7072
- Exception: If any of the required parameters for the free call strategy are missing.
73+
74+
#### `get_free_call_token_details`
75+
76+
Sends a request to the daemon and receives a free call token.
77+
78+
###### args:
79+
80+
- `service_client` (ServiceClient): The service client instance.
81+
82+
###### returns:
83+
84+
- A tuple containing the free call token and the token expiration block number. (tuple[str, int])
85+
86+
###### raises:
87+
88+
- Exception: If an error occurred while receiving the token.
89+
90+
#### `select_channel`
91+
92+
Creates a channel to the daemon.
93+
94+
###### args:
95+
96+
- `service_client` (ServiceClient): The service client object.
97+
98+
###### returns:
99+
100+
- The channel for the service calling.

snet/sdk/__init__.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from snet.sdk.client_lib_generator import ClientLibGenerator
2727
from snet.sdk.mpe.mpe_contract import MPEContract
2828
from snet.sdk.mpe.payment_channel_provider import PaymentChannelProvider
29-
from snet.sdk.payment_strategies.default_payment_strategy import DefaultPaymentStrategy as PaymentStrategy
29+
from snet.sdk.payment_strategies.default_payment_strategy import DefaultPaymentStrategy
3030
from snet.sdk.service_client import ServiceClient
3131
from snet.sdk.storage_provider.storage_provider import StorageProvider
3232
from snet.sdk.custom_typing import ModuleName, ServiceStub
@@ -93,9 +93,7 @@ def create_service_client(self,
9393
service_id: str,
9494
group_name=None,
9595
payment_strategy=None,
96-
free_call_auth_token_bin=None,
97-
free_call_token_expiry_block=None,
98-
email=None,
96+
address=None,
9997
options=None,
10098
concurrent_calls: int = 1):
10199

@@ -121,20 +119,13 @@ def create_service_client(self,
121119
self.lib_generator.generate_client_library()
122120

123121
if payment_strategy is None:
124-
payment_strategy = PaymentStrategy(
122+
payment_strategy = DefaultPaymentStrategy(
125123
concurrent_calls=concurrent_calls
126124
)
127125

128126
if options is None:
129127
options = dict()
130-
options['free_call_auth_token-bin'] = (
131-
bytes.fromhex(free_call_auth_token_bin) if
132-
free_call_token_expiry_block else ""
133-
)
134-
options['free-call-token-expiry-block'] = (
135-
free_call_token_expiry_block if free_call_token_expiry_block else 0
136-
)
137-
options['email'] = email if email else ""
128+
options['user_address'] = address if address else ""
138129
options['concurrency'] = self._sdk_config.get("concurrency", True)
139130

140131
service_metadata = self._metadata_provider.enhance_service_metadata(

snet/sdk/payment_strategies/freecall_payment_strategy.py

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,87 +2,109 @@
22
from urllib.parse import urlparse
33

44
import grpc
5+
from grpc import _channel
56
import web3
6-
from snet.sdk.resources.root_certificate import certificate
7-
from snet.sdk.utils.utils import RESOURCES_PATH, add_to_path
87

98
from snet.sdk.payment_strategies.payment_strategy import PaymentStrategy
10-
9+
from snet.sdk.resources.root_certificate import certificate
10+
from snet.sdk.utils.utils import RESOURCES_PATH, add_to_path
1111

1212
class FreeCallPaymentStrategy(PaymentStrategy):
1313

14-
def is_free_call_available(self, service_client):
14+
def is_free_call_available(self, service_client) -> bool:
1515
try:
16-
org_id, service_id, group_id, daemon_endpoint = service_client.get_service_details()
17-
email, token_for_free_call, token_expiry_date_block = service_client.get_free_call_config()
16+
self._user_address = service_client.options["user_address"]
17+
self._free_call_token, self._token_expiry_date_block = self.get_free_call_token_details(service_client)
1818

19-
if not token_for_free_call:
19+
if not self._free_call_token:
2020
return False
2121

22-
signature, current_block_number = self.generate_signature(service_client)
2322
with add_to_path(str(RESOURCES_PATH.joinpath("proto"))):
2423
state_service_pb2 = importlib.import_module("state_service_pb2")
2524

2625
with add_to_path(str(RESOURCES_PATH.joinpath("proto"))):
2726
state_service_pb2_grpc = importlib.import_module("state_service_pb2_grpc")
2827

28+
signature, current_block_number = self.generate_signature(service_client)
29+
2930
request = state_service_pb2.FreeCallStateRequest()
30-
request.user_id = email
31-
request.token_for_free_call = token_for_free_call
32-
request.token_expiry_date_block = token_expiry_date_block
31+
request.user_address = self._user_address
32+
request.token_for_free_call = self._free_call_token
33+
request.token_expiry_date_block = self._token_expiry_date_block
3334
request.signature = signature
3435
request.current_block = current_block_number
3536

36-
endpoint_object = urlparse(daemon_endpoint)
37-
if endpoint_object.port is not None:
38-
channel_endpoint = endpoint_object.hostname + ":" + str(endpoint_object.port)
39-
else:
40-
channel_endpoint = endpoint_object.hostname
41-
42-
if endpoint_object.scheme == "http":
43-
channel = grpc.insecure_channel(channel_endpoint)
44-
elif endpoint_object.scheme == "https":
45-
channel = grpc.secure_channel(channel_endpoint, grpc.ssl_channel_credentials(root_certificates=certificate))
46-
else:
47-
raise ValueError('Unsupported scheme in service metadata ("{}")'.format(endpoint_object.scheme))
37+
channel = self.select_channel(service_client)
4838

4939
stub = state_service_pb2_grpc.FreeCallStateServiceStub(channel)
5040
response = stub.GetFreeCallsAvailable(request)
5141
if response.free_calls_available > 0:
5242
return True
5343
return False
44+
except grpc.RpcError as e:
45+
if self._user_address:
46+
print(f"Warning: {e.details()}")
47+
return False
5448
except Exception as e:
5549
return False
5650

57-
def get_payment_metadata(self, service_client):
58-
email, token_for_free_call, token_expiry_date_block = service_client.get_free_call_config()
51+
def get_payment_metadata(self, service_client) -> list:
5952
signature, current_block_number = self.generate_signature(service_client)
60-
metadata = [("snet-free-call-auth-token-bin", token_for_free_call),
61-
("snet-free-call-token-expiry-block", str(token_expiry_date_block)),
53+
metadata = [("snet-free-call-auth-token-bin", self._free_call_token),
54+
("snet-free-call-token-expiry-block", str(self._token_expiry_date_block)),
6255
("snet-payment-type", "free-call"),
63-
("snet-free-call-user-id", email),
56+
("snet-free-call-user-id", self._user_address),
6457
("snet-current-block-number", str(current_block_number)),
6558
("snet-payment-channel-signature-bin", signature)]
6659

6760
return metadata
6861

69-
def select_channel(self, service_client):
70-
pass
71-
72-
def generate_signature(self, service_client):
73-
org_id, service_id, group_id, daemon_endpoint = service_client.get_service_details()
74-
email, token_for_free_call, token_expiry_date_block = service_client.get_free_call_config()
75-
76-
if token_expiry_date_block == 0 or len(email) == 0 or len(token_for_free_call) == 0:
62+
def select_channel(self, service_client) -> _channel.Channel:
63+
_, _, _, daemon_endpoint = service_client.get_service_details()
64+
endpoint_object = urlparse(daemon_endpoint)
65+
if endpoint_object.port is not None:
66+
channel_endpoint = endpoint_object.hostname + ":" + str(endpoint_object.port)
67+
else:
68+
channel_endpoint = endpoint_object.hostname
69+
70+
if endpoint_object.scheme == "http":
71+
channel = grpc.insecure_channel(channel_endpoint)
72+
elif endpoint_object.scheme == "https":
73+
channel = grpc.secure_channel(channel_endpoint, grpc.ssl_channel_credentials(root_certificates=certificate))
74+
else:
75+
raise ValueError('Unsupported scheme in service metadata ("{}")'.format(endpoint_object.scheme))
76+
return channel
77+
78+
def generate_signature(self, service_client) -> tuple[bytes, int]:
79+
org_id, service_id, group_id, _ = service_client.get_service_details()
80+
81+
if self._token_expiry_date_block == 0 or len(self._user_address) == 0 or len(self._free_call_token) == 0:
7782
raise Exception(
7883
"You are using default 'FreeCallPaymentStrategy' to use this strategy you need to pass "
79-
"'free_call_auth_token-bin','email','free-call-token-expiry-block' in config")
84+
"'free_call_auth_token-bin','user_address','free-call-token-expiry-block' in config")
8085

8186
current_block_number = service_client.get_current_block_number()
8287

8388
message = web3.Web3.solidity_keccak(
8489
["string", "string", "string", "string", "string", "uint256", "bytes32"],
85-
["__prefix_free_trial", email, org_id, service_id, group_id, current_block_number,
86-
token_for_free_call]
90+
["__prefix_free_trial", self._user_address, org_id, service_id, group_id, current_block_number,
91+
self._free_call_token]
8792
)
8893
return service_client.generate_signature(message), current_block_number
94+
95+
def get_free_call_token_details(self, service_client) -> tuple[bytes, int]:
96+
with add_to_path(str(RESOURCES_PATH.joinpath("proto"))):
97+
state_service_pb2 = importlib.import_module("state_service_pb2")
98+
99+
request = state_service_pb2.GetFreeCallTokenRequest()
100+
request.address = self._user_address
101+
102+
with add_to_path(str(RESOURCES_PATH.joinpath("proto"))):
103+
state_service_pb2_grpc = importlib.import_module("state_service_pb2_grpc")
104+
105+
channel = self.select_channel(service_client)
106+
stub = state_service_pb2_grpc.FreeCallStateServiceStub(channel)
107+
response = stub.GetFreeCallToken(request)
108+
109+
return response.token, response.token_expiration_block
110+

0 commit comments

Comments
 (0)