Skip to content

Commit 80caf36

Browse files
author
Eunsoo Park
authored
Merge pull request #69 from icon-project/experimental/query_with_height
Add "height" key "params" of query request
2 parents e445926 + 11d7c32 commit 80caf36

File tree

8 files changed

+68
-18
lines changed

8 files changed

+68
-18
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ call = CallBuilder().from_(wallet.get_address())\
122122
.to("cx000...1")\
123123
.method("balance_of")\
124124
.params({"address": "hx000...1"})\
125+
.height(100)\
125126
.build()
126127

127128
# Executes a call method to call a read-only API method on the SCORE immediately without creating a transaction
@@ -185,7 +186,7 @@ block = icon_service.get_block("latest")
185186
### get_balance
186187

187188
```python
188-
get_balance(address: str)
189+
get_balance(address: str, height: int = None)
189190
```
190191

191192
Returns the ICX balance of the given EOA or SCORE
@@ -196,6 +197,8 @@ Delegates to **icx_getBalance** RPC method
196197

197198
address : An address of EOA or SCORE
198199

200+
height(optional) : Block height
201+
199202
#### Returns
200203

201204
Number of ICX coins
@@ -218,7 +221,7 @@ balance = icon_service.get_balance("hx000...1")
218221
### get_score_api
219222

220223
```python
221-
get_score_api(address: str)
224+
get_score_api(address: str, height: int = None)
222225
```
223226

224227
Returns SCORE's external API list
@@ -229,6 +232,8 @@ Delegates to **icx_getScoreApi** RPC method
229232

230233
address : A SCORE address to be examined
231234

235+
height(optional) : Block height
236+
232237
#### Returns
233238

234239
A list of API methods of the SCORE and its information
@@ -264,7 +269,7 @@ score_apis = icon_service.get_score_api("cx000...1")
264269
### get_total_supply
265270

266271
```python
267-
get_total_supply()
272+
get_total_supply(height: int = None)
268273
```
269274

270275
Returns total ICX coin supply that has been issued
@@ -273,7 +278,7 @@ Delegates to **icx_getTotalSupply** RPC method
273278

274279
#### Parameters
275280

276-
None
281+
height(optional) : Block height
277282

278283
#### Returns
279284

iconsdk/builder/call_builder.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ class Call:
2222
Class `Call` for calling a SCORE API.
2323
Once an instance generated, it is read-only."""
2424

25-
def __init__(self, from_: str, to: str, method: str, params: dict):
25+
def __init__(self, from_: str, to: str, method: str, params: dict, height: int):
2626
self.__from = from_
2727
self.__to = to
2828
self.__method = method
2929
self.__params = params
30+
self.__height = height
3031

3132
@property
3233
def from_(self) -> str:
@@ -44,8 +45,12 @@ def method(self) -> str:
4445
def params(self) -> dict:
4546
return object_to_str(self.__params) if self.__params else None
4647

48+
@property
49+
def height(self) -> int:
50+
return object_to_str(self.__height) if self.__height else None
51+
4752
def to_dict(self) -> dict:
48-
return {"from_": self.from_, "to": self.to, "method": self.method, "params": self.params}
53+
return {"from_": self.from_, "to": self.to, "method": self.method, "params": self.params, "height": self.height}
4954

5055

5156
class CallBuilder:
@@ -54,11 +59,13 @@ class CallBuilder:
5459
Once setting it, a value of any property can't be changed forever.
5560
"""
5661

57-
def __init__(self, from_: str = None, to: str = None, method: str = None, params: dict = None) -> Call:
62+
def __init__(self, from_: str = None, to: str = None, method: str = None, params: dict = None,
63+
height: int = None) -> Call:
5864
self._from_ = from_
5965
self._to = to
6066
self._method = method
6167
self._params = params
68+
self._height = height
6269

6370
def from_(self, from_: str) -> 'CallBuilder':
6471
self._from_ = from_
@@ -76,8 +83,12 @@ def params(self, params: dict) -> 'CallBuilder':
7683
self._params = params
7784
return self
7885

86+
def height(self, height: int) -> 'CallBuilder':
87+
self._height = height
88+
return self
89+
7990
def build(self) -> Call:
80-
return Call(self._from_, self._to, self._method, self._params)
91+
return Call(self._from_, self._to, self._method, self._params, self._height)
8192

8293
@classmethod
8394
def from_dict(cls, call_as_dict: dict) -> 'CallBuilder':
@@ -87,7 +98,8 @@ def from_dict(cls, call_as_dict: dict) -> 'CallBuilder':
8798
from_=call_as_dict['from_'] if "from_" in call_as_dict else None,
8899
to=call_as_dict['to'],
89100
method=call_as_dict['method'],
90-
params=call_as_dict['params'] if "params" in call_as_dict else None
101+
params=call_as_dict['params'] if "params" in call_as_dict else None,
102+
height=call_as_dict['height'],
91103
)
92104
except KeyError:
93105
raise DataTypeException("The input data invalid. Mapping key not found.")

iconsdk/icon_service.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,33 +115,41 @@ def return_infos_by_block_version(_prev_method: str) -> Tuple[str, Any, bool]:
115115

116116
return result
117117

118-
def get_total_supply(self, full_response: bool = False) -> Union[dict, int]:
118+
def get_total_supply(self, height: int = None, full_response: bool = False) -> Union[dict, int]:
119119
"""
120120
Returns total ICX coin supply that has been issued
121121
Delegates to icx_getTotalSupply RPC method
122122
123+
:param height: Block height
123124
:param full_response: Boolean to check whether get naive dict or refined data from server
124125
:return: Total number of ICX coins issued
125126
"""
126127

127-
result = self.__provider.make_request('icx_getTotalSupply', full_response=full_response)
128+
params = {}
129+
if height is not None:
130+
params["height"] = hex(height)
131+
132+
result = self.__provider.make_request('icx_getTotalSupply', params, full_response=full_response)
128133

129134
if full_response:
130135
return result
131136
else:
132137
return int(remove_0x_prefix(result), 16)
133138

134-
def get_balance(self, address: str, full_response: bool = False) -> Union[dict, int]:
139+
def get_balance(self, address: str, height: int = None, full_response: bool = False) -> Union[dict, int]:
135140
"""
136141
Returns the ICX balance of the given EOA or SCORE.
137142
Delegates to icx_getBalance RPC method.
138143
139144
:param address: An address of EOA or SCORE. type(str)
145+
:param height: Block height. type(int)
140146
:param full_response: Boolean to check whether get naive dict or refined data from server
141147
:return: Number of ICX coins
142148
"""
143149
if is_score_address(address) or is_wallet_address(address):
144150
params = {'address': address}
151+
if height is not None:
152+
params["height"] = hex(height)
145153

146154
result = self.__provider.make_request('icx_getBalance', params, full_response)
147155

@@ -152,19 +160,22 @@ def get_balance(self, address: str, full_response: bool = False) -> Union[dict,
152160
else:
153161
raise AddressException("Address is wrong.")
154162

155-
def get_score_api(self, address: str, full_response: bool = False) -> Union[dict, list]:
163+
def get_score_api(self, address: str, height: int = None, full_response: bool = False) -> Union[dict, list]:
156164
"""
157165
Returns SCORE's external API list.
158166
Delegates to icx_getScoreApi RPC method.
159167
160168
:param address: A SCORE address to be examined
169+
:param height: Block height
161170
:param full_response: Boolean to check whether get naive dict or refined data from server
162171
:return: A list of API methods of the SCORE and its information
163172
"""
164173
if not is_score_address(address):
165174
raise AddressException("SCORE Address is wrong.")
166175

167176
params = {'address': address}
177+
if height is not None:
178+
params['height'] = hex(height)
168179
return self.__provider.make_request('icx_getScoreApi', params, full_response)
169180

170181
def get_transaction_result(self, tx_hash: str, full_response: bool = False) -> dict:
@@ -255,6 +266,9 @@ def call(self, call: object, full_response: bool = False) -> Union[dict, str]:
255266
if isinstance(call.params, dict):
256267
params["data"]["params"] = call.params
257268

269+
if call.height is not None:
270+
params["height"] = call.height
271+
258272
return self.__provider.make_request('icx_call', params, full_response)
259273

260274
def send_transaction(self, signed_transaction: SignedTransaction, full_response: bool = False) -> Union[dict, str]:

tests/api_get/test_get_balance.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ def test_get_balance_from_wallet(self, _make_id):
4848
self.assertEqual(expected_request, actual_request)
4949
self.assertEqual(expected_result, result)
5050

51+
# with height
52+
self.icon_service.get_balance(self.setting['from'], height=self.setting['height'])
53+
actual_request = json.loads(m._adapter.last_request.text)
54+
self.assertEqual(hex(self.setting['height']), actual_request['params']['height'])
55+
5156
def test_get_balance_invalid(self, _make_id):
5257
# case 1: when a param is wrong.
5358
self.assertRaises(AddressException, self.icon_service.get_balance, self.setting["to"][2:])

tests/api_get/test_get_score_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def test_get_score_api(self, _make_id):
4646
self.assertTrue(result)
4747
self.assertTrue(is_score_apis(result))
4848

49+
# with height
50+
self.icon_service.get_score_api(governance_address, height=self.setting['height'])
51+
actual_request = json.loads(m._adapter.last_request.text)
52+
self.assertEqual(hex(self.setting['height']), actual_request['params']['height'])
53+
4954
def test_get_score_api_invalid(self, _make_id):
5055
# case 1: when address is wrong - wallet address
5156
self.assertRaises(AddressException, self.icon_service.get_score_api,

tests/api_get/test_get_total_supply.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ def test_get_total_supply(self, _make_id):
4545
self.assertEqual(expected_request, actual_request)
4646
self.assertTrue(result, supply)
4747

48+
# with height
49+
self.icon_service.get_total_supply(height=self.setting['height'])
50+
actual_request = json.loads(m._adapter.last_request.text)
51+
self.assertEqual(hex(self.setting['height']), actual_request['params']['height'])
52+
4853

4954
if __name__ == "__main__":
5055
main()

tests/api_send/test_send_super.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ def setUpClass(cls):
8080
# It is used to send message only.
8181
"data": "0x" + "test".encode().hex(),
8282
"id": "0x" + os.urandom(32).hex(),
83-
"timestamp": 10_000
83+
"timestamp": 10_000,
84+
"height": 100,
8485
}
8586

8687

tests/builder/test_call_builder.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ class TestCallBuilder(TestCase):
2222

2323
def test_make_call_builder(self):
2424
"""Testing for making a couple of call builders successfully"""
25+
height = 100
2526

2627
call_1 = CallBuilder() \
2728
.from_("1_FROM") \
2829
.to("1_TO") \
2930
.method("1_METHOD") \
3031
.params({"test": 123}) \
32+
.height(height) \
3133
.build()
3234

33-
call_2 = CallBuilder().from_("2_FROM").to("2_TO").method("2_METHOD").params({"test": 123}).build()
35+
call_2 = CallBuilder().from_("2_FROM").to("2_TO").method("2_METHOD").params({"test": 123}).height(100).build()
3436

35-
properties = ["from_", "to", "method", "params"]
36-
values_call_1 = ["1_FROM", "1_TO", "1_METHOD", {'test': '0x7b'}]
37-
values_call_2 = ["2_FROM", "2_TO", "2_METHOD", {'test': '0x7b'}]
37+
properties = ["from_", "to", "method", "params", "height"]
38+
values_call_1 = ["1_FROM", "1_TO", "1_METHOD", {'test': '0x7b'}, hex(height)]
39+
values_call_2 = ["2_FROM", "2_TO", "2_METHOD", {'test': '0x7b'}, hex(height)]
3840

3941
# Checks all of property is collect.
4042
for idx, property in enumerate(properties):
@@ -47,6 +49,7 @@ def test_make_call_builder_from_dict_to_dict(self):
4749
.to("1_TO") \
4850
.method("1_METHOD") \
4951
.params({"test": 123}) \
52+
.height(100) \
5053
.build()
5154

5255
call_1_as_dict = call_1.to_dict()

0 commit comments

Comments
 (0)