diff --git a/README.md b/README.md index a2e01ab..20f3a1c 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ leader_address = blockchain.get_leader_address(test_net) is_last_block = blockchain.is_last_block(block_num=0, test_net) last_block_of_epoch5 = blockchain.epoch_last_block(block_num=5, test_net) circulating_supply = Decimal(blockchain.get_circulating_supply(test_net)) -premined = blockchain.get_total_supply(test_net) # should be None? +premined = blockchain.get_total_supply(test_net) # RPC result for the pre-mined token supply current_block_num = blockchain.get_block_number(test_net) current_epoch = blockchain.get_current_epoch(test_net) gas_price = blockchain.get_gas_price(test_net) # this returns 1 always diff --git a/pyhmy/blockchain.py b/pyhmy/blockchain.py index a989be1..c37cf81 100644 --- a/pyhmy/blockchain.py +++ b/pyhmy/blockchain.py @@ -3,6 +3,8 @@ blocks, headers, transaction pool, node status, etc. """ # pylint: disable=too-many-lines +from typing import Optional + from .rpc.request import rpc_request from .exceptions import InvalidRPCReplyError @@ -656,7 +658,7 @@ def epoch_last_block( def get_circulating_supply( endpoint = DEFAULT_ENDPOINT, timeout = DEFAULT_TIMEOUT -) -> int: +) -> Optional[str]: """Get current circulation supply of tokens in ONE. Parameters @@ -668,8 +670,8 @@ def get_circulating_supply( Returns ------- - str - Current circulation supply (with decimal point) + str or None + Current circulation supply (with decimal point) or `None` if the RPC returns it Raises ------ @@ -685,15 +687,15 @@ def get_circulating_supply( return rpc_request( method, endpoint = endpoint, timeout = timeout )[ "result" ] - except KeyError as exception: + except ( KeyError, TypeError ) as exception: raise InvalidRPCReplyError( method, endpoint ) from exception def get_total_supply( endpoint = DEFAULT_ENDPOINT, timeout = DEFAULT_TIMEOUT -) -> int: - """Get total number of pre-mined tokens. +) -> Optional[str]: + """Get the RPC result for the total number of pre-mined tokens. Parameters ---------- @@ -704,13 +706,13 @@ def get_total_supply( Returns ------- - str - Total number of pre-mined tokens, or None if no such tokens + str or None + Total number of pre-mined tokens returned by the RPC, or `None` if the RPC returns it Raises ------ InvalidRPCReplyError - If received unknown result from endpoint + If the RPC payload is malformed or missing a result API Reference ------------- @@ -718,10 +720,10 @@ def get_total_supply( """ method = "hmyv2_getTotalSupply" try: - rpc_request( method, - endpoint = endpoint, - timeout = timeout )[ "result" ] - except KeyError as exception: + return rpc_request( method, + endpoint = endpoint, + timeout = timeout )[ "result" ] + except ( KeyError, TypeError ) as exception: raise InvalidRPCReplyError( method, endpoint ) from exception diff --git a/tests/unit-pyhmy/test_blockchain_circulating_supply_unit.py b/tests/unit-pyhmy/test_blockchain_circulating_supply_unit.py new file mode 100644 index 0000000..620e255 --- /dev/null +++ b/tests/unit-pyhmy/test_blockchain_circulating_supply_unit.py @@ -0,0 +1,29 @@ +import pytest + +from pyhmy import blockchain +from pyhmy.exceptions import InvalidRPCReplyError + + +def test_get_circulating_supply_returns_rpc_result(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {"result": "98765.4321"} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + assert blockchain.get_circulating_supply() == "98765.4321" + + +def test_get_circulating_supply_allows_none(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {"result": None} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + assert blockchain.get_circulating_supply() is None + + +def test_get_circulating_supply_raises_on_missing_result(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + with pytest.raises(InvalidRPCReplyError): + blockchain.get_circulating_supply() diff --git a/tests/unit-pyhmy/test_blockchain_total_supply_unit.py b/tests/unit-pyhmy/test_blockchain_total_supply_unit.py new file mode 100644 index 0000000..0a822fa --- /dev/null +++ b/tests/unit-pyhmy/test_blockchain_total_supply_unit.py @@ -0,0 +1,56 @@ +import pytest + +from pyhmy import blockchain +from pyhmy.exceptions import InvalidRPCReplyError + + +def test_get_total_supply_returns_rpc_result(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {"result": "12345.6789"} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + assert blockchain.get_total_supply() == "12345.6789" + + +def test_get_total_supply_forwards_endpoint_and_timeout(monkeypatch): + captured = {} + + def fake_rpc_request(*args, **kwargs): + captured["args"] = args + captured["kwargs"] = kwargs + return {"result": "98765.4321"} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + + endpoint = "https://example.invalid/rpc" + timeout = 17 + + assert blockchain.get_total_supply(endpoint=endpoint, timeout=timeout) == "98765.4321" + assert captured["args"] == ("hmyv2_getTotalSupply",) + assert captured["kwargs"] == {"endpoint": endpoint, "timeout": timeout} + + +def test_get_total_supply_allows_none(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {"result": None} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + assert blockchain.get_total_supply() is None + + +def test_get_total_supply_raises_on_missing_result(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return {} + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + with pytest.raises(InvalidRPCReplyError): + blockchain.get_total_supply() + + +def test_get_total_supply_raises_on_non_mapping_response(monkeypatch): + def fake_rpc_request(*_args, **_kwargs): + return None + + monkeypatch.setattr(blockchain, "rpc_request", fake_rpc_request) + with pytest.raises(InvalidRPCReplyError): + blockchain.get_total_supply()