11import importlib
2- from urllib .parse import urlparse
32
43import grpc
5- from grpc import _channel
64import web3
75
86from snet .sdk .payment_strategies .payment_strategy import PaymentStrategy
9- from snet .sdk .resources .root_certificate import certificate
107from snet .sdk .utils .utils import RESOURCES_PATH , add_to_path
118
129class FreeCallPaymentStrategy (PaymentStrategy ):
1310
11+ def __init__ (self ):
12+ self ._user_address = None
13+ self ._free_call_token = None
14+ self ._token_expiration_block = None
15+ self ._free_calls_available = None
16+
1417 def is_free_call_available (self , service_client ) -> bool :
15- try :
18+ if not self . _user_address :
1619 self ._user_address = service_client .account .signer_address
17- self ._free_call_token , self ._token_expiry_date_block = self .get_free_call_token_details (service_client )
1820
19- if not self ._free_call_token :
20- return False
21+ current_block_number = service_client .get_current_block_number ()
2122
22- with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
23- state_service_pb2 = importlib .import_module ("state_service_pb2" )
23+ if (not self ._free_call_token or
24+ not self ._token_expiration_block or
25+ current_block_number > self ._token_expiration_block ):
26+ self ._free_call_token , self ._token_expiration_block = self .get_free_call_token_details (service_client )
2427
25- with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
26- state_service_pb2_grpc = importlib .import_module ("state_service_pb2_grpc " )
28+ with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
29+ state_service_pb2 = importlib .import_module ("state_service_pb2 " )
2730
28- signature , current_block_number = self .generate_signature (service_client )
31+ with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
32+ state_service_pb2_grpc = importlib .import_module ("state_service_pb2_grpc" )
2933
30- request = state_service_pb2 .FreeCallStateRequest ()
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
34- request .signature = signature
35- request .current_block = current_block_number
34+ signature = self .generate_signature (service_client , current_block_number )
35+ request = state_service_pb2 .FreeCallStateRequest (
36+ address = self ._user_address ,
37+ free_call_token = self ._free_call_token ,
38+ signature = signature ,
39+ current_block = current_block_number
40+ )
3641
37- channel = self .select_channel (service_client )
42+ channel = service_client ._get_grpc_channel ()
43+ stub = state_service_pb2_grpc .FreeCallStateServiceStub (channel )
3844
39- stub = state_service_pb2_grpc . FreeCallStateServiceStub ( channel )
45+ try :
4046 response = stub .GetFreeCallsAvailable (request )
4147 if response .free_calls_available > 0 :
4248 return True
@@ -45,10 +51,10 @@ def is_free_call_available(self, service_client) -> bool:
4551 if self ._user_address :
4652 print (f"Warning: { e .details ()} " )
4753 return False
48- except Exception as e :
49- return False
5054
5155 def get_payment_metadata (self , service_client ) -> list :
56+ if self .is_free_call_available (service_client ):
57+ raise Exception (f"Free calls limit for address { self ._user_address } has expired. Please use another payment strategy" )
5258 signature , current_block_number = self .generate_signature (service_client )
5359 metadata = [("snet-free-call-auth-token-bin" , self ._free_call_token ),
5460 ("snet-payment-type" , "free-call" ),
@@ -58,52 +64,39 @@ def get_payment_metadata(self, service_client) -> list:
5864
5965 return metadata
6066
61- def select_channel (self , service_client ) -> _channel .Channel :
62- _ , _ , _ , daemon_endpoint = service_client .get_service_details ()
63- endpoint_object = urlparse (daemon_endpoint )
64- if endpoint_object .port is not None :
65- channel_endpoint = endpoint_object .hostname + ":" + str (endpoint_object .port )
66- else :
67- channel_endpoint = endpoint_object .hostname
68-
69- if endpoint_object .scheme == "http" :
70- channel = grpc .insecure_channel (channel_endpoint )
71- elif endpoint_object .scheme == "https" :
72- channel = grpc .secure_channel (channel_endpoint , grpc .ssl_channel_credentials (root_certificates = certificate ))
73- else :
74- raise ValueError ('Unsupported scheme in service metadata ("{}")' .format (endpoint_object .scheme ))
75- return channel
76-
77- def generate_signature (self , service_client ) -> tuple [bytes , int ]:
67+ def generate_signature (self , service_client , current_block_number = None , with_token = True ) -> tuple [bytes , int ]:
68+ if not current_block_number :
69+ current_block_number = service_client .get_current_block_number ()
7870 org_id , service_id , group_id , _ = service_client .get_service_details ()
7971
80- if self ._token_expiry_date_block == 0 or len (self ._user_address ) == 0 or len (self ._free_call_token ) == 0 :
81- raise Exception (
82- "You are using default 'FreeCallPaymentStrategy' to use this strategy you need to pass "
83- "'free_call_auth_token-bin','user_address','free-call-token-expiry-block' in config" )
72+ message_types = ["string" , "string" , "string" , "string" , "string" , "uint256" , "bytes32" ]
73+ message_values = ["__prefix_free_trial" , self ._user_address , org_id , service_id , group_id ,
74+ current_block_number , self ._free_call_token ]
8475
85- current_block_number = service_client .get_current_block_number ()
76+ if not with_token :
77+ message_types = message_types [:- 1 ]
78+ message_values = message_values [:- 1 ]
8679
87- message = web3 .Web3 .solidity_keccak (
88- ["string" , "string" , "string" , "string" , "string" , "uint256" , "bytes32" ],
89- ["__prefix_free_trial" , self ._user_address , org_id , service_id , group_id , current_block_number ,
90- self ._free_call_token ]
91- )
80+ message = web3 .Web3 .solidity_keccak (message_types , message_values )
9281 return service_client .generate_signature (message ), current_block_number
9382
94- def get_free_call_token_details (self , service_client ) -> tuple [bytes , int ]:
83+ def get_free_call_token_details (self , service_client , current_block_number = None ) -> tuple [bytes , int ]:
84+
85+ signature , current_block_number = self .generate_signature (service_client , current_block_number , with_token = False )
86+
9587 with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
9688 state_service_pb2 = importlib .import_module ("state_service_pb2" )
9789
9890 request = state_service_pb2 .GetFreeCallTokenRequest (
9991 address = self ._user_address ,
100-
92+ signature = signature ,
93+ current_block = current_block_number
10194 )
10295
10396 with add_to_path (str (RESOURCES_PATH .joinpath ("proto" ))):
10497 state_service_pb2_grpc = importlib .import_module ("state_service_pb2_grpc" )
10598
106- channel = self . select_channel ( service_client )
99+ channel = service_client . _get_grpc_channel ( )
107100 stub = state_service_pb2_grpc .FreeCallStateServiceStub (channel )
108101 response = stub .GetFreeCallToken (request )
109102
0 commit comments