chore(yapf): run yapf

pull/35/head
MaxMustermann2 2 years ago
parent 98514c7a2c
commit ca6a6ae1a8
No known key found for this signature in database
GPG Key ID: 4F4AB9DB6FF24C94
  1. 404
      .style.yapf
  2. 8
      pyhmy/__init__.py
  3. 115
      pyhmy/account.py
  4. 10
      pyhmy/bech32/bech32.py
  5. 389
      pyhmy/blockchain.py
  6. 82
      pyhmy/cli.py
  7. 60
      pyhmy/contract.py
  8. 3
      pyhmy/exceptions.py
  9. 22
      pyhmy/logging.py
  10. 1
      pyhmy/numbers.py
  11. 8
      pyhmy/rpc/exceptions.py
  12. 21
      pyhmy/rpc/request.py
  13. 100
      pyhmy/signing.py
  14. 243
      pyhmy/staking.py
  15. 95
      pyhmy/staking_signing.py
  16. 69
      pyhmy/staking_structures.py
  17. 212
      pyhmy/transaction.py
  18. 28
      pyhmy/util.py
  19. 118
      pyhmy/validator.py
  20. 3
      tests/cli-pyhmy/test_cli.py
  21. 35
      tests/request-pyhmy/test_request.py
  22. 24
      tests/sdk-pyhmy/conftest.py
  23. 41
      tests/sdk-pyhmy/test_account.py
  24. 71
      tests/sdk-pyhmy/test_blockchain.py
  25. 16
      tests/sdk-pyhmy/test_contract.py
  26. 9
      tests/sdk-pyhmy/test_signing.py
  27. 60
      tests/sdk-pyhmy/test_staking.py
  28. 10
      tests/sdk-pyhmy/test_staking_signing.py
  29. 57
      tests/sdk-pyhmy/test_transaction.py
  30. 22
      tests/sdk-pyhmy/test_validator.py
  31. 7
      tests/util-pyhmy/test_util.py

@ -0,0 +1,404 @@
[style]
# Align closing bracket with visual indentation.
align_closing_bracket_with_visual_indent=True
# Allow dictionary keys to exist on multiple lines. For example:
#
# x = {
# ('this is the first element of a tuple',
# 'this is the second element of a tuple'):
# value,
# }
allow_multiline_dictionary_keys=False
# Allow lambdas to be formatted on more than one line.
allow_multiline_lambdas=False
# Allow splitting before a default / named assignment in an argument list.
allow_split_before_default_or_named_assigns=True
# Allow splits before the dictionary value.
allow_split_before_dict_value=False
# Let spacing indicate operator precedence. For example:
#
# a = 1 * 2 + 3 / 4
# b = 1 / 2 - 3 * 4
# c = (1 + 2) * (3 - 4)
# d = (1 - 2) / (3 + 4)
# e = 1 * 2 - 3
# f = 1 + 2 + 3 + 4
#
# will be formatted as follows to indicate precedence:
#
# a = 1*2 + 3/4
# b = 1/2 - 3*4
# c = (1+2) * (3-4)
# d = (1-2) / (3+4)
# e = 1*2 - 3
# f = 1 + 2 + 3 + 4
#
arithmetic_precedence_indication=False
# Number of blank lines surrounding top-level function and class
# definitions.
blank_lines_around_top_level_definition=2
# Number of blank lines between top-level imports and variable
# definitions.
blank_lines_between_top_level_imports_and_variables=1
# Insert a blank line before a class-level docstring.
blank_line_before_class_docstring=False
# Insert a blank line before a module docstring.
blank_line_before_module_docstring=False
# Insert a blank line before a 'def' or 'class' immediately nested
# within another 'def' or 'class'. For example:
#
# class Foo:
# # <------ this blank line
# def method():
# ...
blank_line_before_nested_class_or_def=False
# Do not split consecutive brackets. Only relevant when
# dedent_closing_brackets is set. For example:
#
# call_func_that_takes_a_dict(
# {
# 'key1': 'value1',
# 'key2': 'value2',
# }
# )
#
# would reformat to:
#
# call_func_that_takes_a_dict({
# 'key1': 'value1',
# 'key2': 'value2',
# })
coalesce_brackets=False
# The column limit.
column_limit=80
# The style for continuation alignment. Possible values are:
#
# - SPACE: Use spaces for continuation alignment. This is default behavior.
# - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns
# (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or
# CONTINUATION_INDENT_WIDTH spaces) for continuation alignment.
# - VALIGN-RIGHT: Vertically align continuation lines to multiple of
# INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if
# cannot vertically align continuation lines with indent characters.
continuation_align_style=SPACE
# Indent width used for line continuations.
continuation_indent_width=4
# Put closing brackets on a separate line, dedented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
# config = {
# 'key1': 'value1',
# 'key2': 'value2',
# } # <--- this bracket is dedented and on a separate line
#
# time_series = self.remote_client.query_entity_counters(
# entity='dev3246.region1',
# key='dns.query_latency_tcp',
# transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
# start_ts=now()-timedelta(days=3),
# end_ts=now(),
# ) # <--- this bracket is dedented and on a separate line
dedent_closing_brackets=True
# Disable the heuristic which places each list element on a separate line
# if the list is comma-terminated.
disable_ending_comma_heuristic=True
# Place each dictionary entry onto its own line.
each_dict_entry_on_separate_line=True
# Require multiline dictionary even if it would normally fit on one line.
# For example:
#
# config = {
# 'key1': 'value1'
# }
force_multiline_dict=True
# The regex for an i18n comment. The presence of this comment stops
# reformatting of that line, because the comments are required to be
# next to the string they translate.
i18n_comment=#\..*
# The i18n function call names. The presence of this function stops
# reformattting on that line, because the string it has cannot be moved
# away from the i18n comment.
i18n_function_call=N_, _
# Indent blank lines.
indent_blank_lines=False
# Put closing brackets on a separate line, indented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
# config = {
# 'key1': 'value1',
# 'key2': 'value2',
# } # <--- this bracket is indented and on a separate line
#
# time_series = self.remote_client.query_entity_counters(
# entity='dev3246.region1',
# key='dns.query_latency_tcp',
# transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
# start_ts=now()-timedelta(days=3),
# end_ts=now(),
# ) # <--- this bracket is indented and on a separate line
indent_closing_brackets=False
# Indent the dictionary value if it cannot fit on the same line as the
# dictionary key. For example:
#
# config = {
# 'key1':
# 'value1',
# 'key2': value1 +
# value2,
# }
indent_dictionary_value=False
# The number of columns to use for indentation.
indent_width=4
# Join short lines into one line. E.g., single line 'if' statements.
join_multiple_lines=False
# Do not include spaces around selected binary operators. For example:
#
# 1 + 2 * 3 - 4 / 5
#
# will be formatted as follows when configured with "*,/":
#
# 1 + 2*3 - 4/5
no_spaces_around_selected_binary_operators=
# Use spaces around default or named assigns.
spaces_around_default_or_named_assign=True
# Adds a space after the opening '{' and before the ending '}' dict
# delimiters.
#
# {1: 2}
#
# will be formatted as:
#
# { 1: 2 }
spaces_around_dict_delimiters=True
# Adds a space after the opening '[' and before the ending ']' list
# delimiters.
#
# [1, 2]
#
# will be formatted as:
#
# [ 1, 2 ]
spaces_around_list_delimiters=True
# Use spaces around the power operator.
spaces_around_power_operator=False
# Use spaces around the subscript / slice operator. For example:
#
# my_list[1 : 10 : 2]
spaces_around_subscript_colon=True
# Adds a space after the opening '(' and before the ending ')' tuple
# delimiters.
#
# (1, 2, 3)
#
# will be formatted as:
#
# ( 1, 2, 3 )
spaces_around_tuple_delimiters=True
# The number of spaces required before a trailing comment.
# This can be a single value (representing the number of spaces
# before each trailing comment) or list of values (representing
# alignment column values; trailing comments within a block will
# be aligned to the first column value that is greater than the maximum
# line length within the block). For example:
#
# With spaces_before_comment=5:
#
# 1 + 1 # Adding values
#
# will be formatted as:
#
# 1 + 1 # Adding values <-- 5 spaces between the end of the
# # statement and comment
#
# With spaces_before_comment=15, 20:
#
# 1 + 1 # Adding values
# two + two # More adding
#
# longer_statement # This is a longer statement
# short # This is a shorter statement
#
# a_very_long_statement_that_extends_beyond_the_final_column # Comment
# short # This is a shorter statement
#
# will be formatted as:
#
# 1 + 1 # Adding values <-- end of line comments in block
# # aligned to col 15
# two + two # More adding
#
# longer_statement # This is a longer statement <-- end of line
# # comments in block aligned to col 20
# short # This is a shorter statement
#
# a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length
# short # This is a shorter statement
#
spaces_before_comment=2
# Insert a space between the ending comma and closing bracket of a list,
# etc.
space_between_ending_comma_and_closing_bracket=True
# Use spaces inside brackets, braces, and parentheses. For example:
#
# method_call( 1 )
# my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ]
# my_set = { 1, 2, 3 }
space_inside_brackets=True
# Split before arguments
split_all_comma_separated_values=True
# Split before arguments, but do not split all subexpressions recursively
# (unless needed).
split_all_top_level_comma_separated_values=False
# Split before arguments if the argument list is terminated by a
# comma.
split_arguments_when_comma_terminated=True
# Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@'
# rather than after.
split_before_arithmetic_operator=False
# Set to True to prefer splitting before '&', '|' or '^' rather than
# after.
split_before_bitwise_operator=False
# Split before the closing bracket if a list or dict literal doesn't fit on
# a single line.
split_before_closing_bracket=True
# Split before a dictionary or set generator (comp_for). For example, note
# the split before the 'for':
#
# foo = {
# variable: 'Hello world, have a nice day!'
# for variable in bar if variable != 42
# }
split_before_dict_set_generator=True
# Split before the '.' if we need to split a longer expression:
#
# foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d))
#
# would reformat to something like:
#
# foo = ('This is a really long string: {}, {}, {}, {}'
# .format(a, b, c, d))
split_before_dot=True
# Split after the opening paren which surrounds an expression if it doesn't
# fit on a single line.
split_before_expression_after_opening_paren=False
# If an argument / parameter list is going to be split, then split before
# the first argument.
split_before_first_argument=False
# Set to True to prefer splitting before 'and' or 'or' rather than
# after.
split_before_logical_operator=False
# Split named assignments onto individual lines.
split_before_named_assigns=True
# Set to True to split list comprehensions and generators that have
# non-trivial expressions and multiple clauses before each of these
# clauses. For example:
#
# result = [
# a_long_var + 100 for a_long_var in xrange(1000)
# if a_long_var % 10]
#
# would reformat to something like:
#
# result = [
# a_long_var + 100
# for a_long_var in xrange(1000)
# if a_long_var % 10]
split_complex_comprehension=True
# The penalty for splitting right after the opening bracket.
split_penalty_after_opening_bracket=300
# The penalty for splitting the line after a unary operator.
split_penalty_after_unary_operator=10000
# The penalty of splitting the line around the '+', '-', '*', '/', '//',
# ``%``, and '@' operators.
split_penalty_arithmetic_operator=300
# The penalty for splitting right before an if expression.
split_penalty_before_if_expr=0
# The penalty of splitting the line around the '&', '|', and '^'
# operators.
split_penalty_bitwise_operator=300
# The penalty for splitting a list comprehension or generator
# expression.
split_penalty_comprehension=2100
# The penalty for characters over the column limit.
split_penalty_excess_character=7000
# The penalty incurred by adding a line split to the logical line. The
# more line splits added the higher the penalty.
split_penalty_for_added_line_split=30
# The penalty of splitting a list of "import as" names. For example:
#
# from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
# long_argument_2,
# long_argument_3)
#
# would reformat to something like:
#
# from a_very_long_or_indented_module_name_yada_yad import (
# long_argument_1, long_argument_2, long_argument_3)
split_penalty_import_names=0
# The penalty of splitting the line around the 'and' and 'or'
# operators.
split_penalty_logical_operator=300
# Use the Tab character for indentation.
use_tabs=False

@ -9,11 +9,15 @@ from ._version import __version__
if sys.version_info.major < 3:
warnings.simplefilter( "always", DeprecationWarning )
warnings.warn(
DeprecationWarning("`pyhmy` does not support Python 2. Please use Python 3.")
DeprecationWarning(
"`pyhmy` does not support Python 2. Please use Python 3."
)
)
warnings.resetwarnings()
if sys.platform.startswith( "win32" ) or sys.platform.startswith( "cygwin" ):
warnings.simplefilter( "always", ImportWarning )
warnings.warn(ImportWarning("`pyhmy` does not work on Windows or Cygwin."))
warnings.warn(
ImportWarning( "`pyhmy` does not work on Windows or Cygwin." )
)
warnings.resetwarnings()

@ -13,6 +13,7 @@ from .bech32.bech32 import bech32_decode
from .constants import DEFAULT_ENDPOINT, DEFAULT_TIMEOUT
def is_valid_address( address ) -> bool:
"""
Check if given string is valid one address
@ -36,7 +37,11 @@ def is_valid_address(address) -> bool:
return True
def get_balance(address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_balance(
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get current account balance.
Parameters
@ -66,7 +71,10 @@ def get_balance(address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
params = [ address ]
try:
balance = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( balance ) # v2 returns the result as it is
except TypeError as exception: # check will work if rpc returns None
@ -74,7 +82,10 @@ def get_balance(address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
def get_balance_by_block(
address, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get account balance for address at a given block number.
@ -108,7 +119,10 @@ def get_balance_by_block(
params = [ address, block_num ]
try:
balance = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( balance )
except TypeError as exception:
@ -116,7 +130,10 @@ def get_balance_by_block(
def get_account_nonce(
address, block_num="latest", endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
block_num = "latest",
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the account nonce.
@ -148,23 +165,32 @@ def get_account_nonce(
method = "hmyv2_getAccountNonce"
params = [ address, block_num ]
try:
nonce = rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
nonce = rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( nonce )
except TypeError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_nonce(
address, block_num="latest", endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
block_num = "latest",
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""See get_account_nonce."""
return get_account_nonce( address, block_num, endpoint, timeout )
def get_transaction_count(
address, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the number of transactions the given address has sent for the given
block number Legacy for apiv1. For apiv2, please use
@ -199,16 +225,22 @@ def get_transaction_count(
method = "hmyv2_getTransactionCount"
params = [ address, block_num ]
try:
nonce = rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
nonce = rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( nonce )
except TypeError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_transactions_count(
address, tx_type, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
tx_type,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the number of regular transactions from genesis of input type.
@ -243,7 +275,10 @@ def get_transactions_count(
params = [ address, tx_type ]
try:
tx_count = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( tx_count )
except TypeError as exception:
@ -251,7 +286,10 @@ def get_transactions_count(
def get_staking_transactions_count(
address, tx_type, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
tx_type,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the number of staking transactions from genesis of input type
("SENT", "RECEIVED", "ALL")
@ -287,7 +325,10 @@ def get_staking_transactions_count(
params = [ address, tx_type ]
try:
tx_count = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return int( tx_count )
except ( KeyError, TypeError ) as exception:
@ -359,7 +400,10 @@ def get_transaction_history( # pylint: disable=too-many-arguments
method = "hmyv2_getTransactionsHistory"
try:
tx_history = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)
return tx_history[ "result" ][ "transactions" ]
except KeyError as exception:
@ -445,7 +489,10 @@ def get_staking_transaction_history( # pylint: disable=too-many-arguments
method = "hmyv2_getStakingTransactionsHistory"
try:
stx_history = rpc_request(
method, params=params, endpoint=endpoint, timeout=timeout
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
return stx_history[ "staking_transactions" ]
except KeyError as exception:
@ -453,7 +500,10 @@ def get_staking_transaction_history( # pylint: disable=too-many-arguments
def get_balance_on_all_shards(
address, skip_error=True, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
skip_error = True,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get current account balance in all shards & optionally report errors
getting account balance for a shard.
@ -483,25 +533,37 @@ def get_balance_on_all_shards(
]
"""
balances = []
sharding_structure = get_sharding_structure(endpoint=endpoint, timeout=timeout)
sharding_structure = get_sharding_structure(
endpoint = endpoint,
timeout = timeout
)
for shard in sharding_structure:
try:
balances.append(
{
"shard": shard[ "shardID" ],
"balance": get_balance(
address, endpoint=shard["http"], timeout=timeout
address,
endpoint = shard[ "http" ],
timeout = timeout
),
}
)
except ( KeyError, RPCError, RequestsError, RequestsTimeoutError ):
if not skip_error:
balances.append({"shard": shard["shardID"], "balance": None})
balances.append(
{
"shard": shard[ "shardID" ],
"balance": None
}
)
return balances
def get_total_balance(
address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get total account balance on all shards.
@ -530,7 +592,10 @@ def get_total_balance(
"""
try:
balances = get_balance_on_all_shards(
address, skip_error=False, endpoint=endpoint, timeout=timeout
address,
skip_error = False,
endpoint = endpoint,
timeout = timeout
)
return sum( b[ "balance" ] for b in balances )
except TypeError as exception:

@ -17,10 +17,8 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Reference implementation for Bech32 and segwit addresses."""
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
@ -38,7 +36,8 @@ def bech32_polymod(values):
def bech32_hrp_expand( hrp ):
"""Expand the HRP into values for checksum computation."""
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
return [ ord( x ) >> 5 for x in hrp ] + [ 0
] + [ ord( x ) & 31 for x in hrp ]
def bech32_verify_checksum( hrp, data ):
@ -61,9 +60,8 @@ def bech32_encode(hrp, data):
def bech32_decode( bech ):
"""Validate a Bech32 string, and determine HRP and data."""
if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (
bech.lower() != bech and bech.upper() != bech
):
if ( any( ord( x ) < 33 or ord( x ) > 126 for x in bech
) ) or ( bech.lower() != bech and bech.upper() != bech ):
return ( None, None )
bech = bech.lower()
pos = bech.rfind( "1" )

@ -9,10 +9,14 @@ from .exceptions import InvalidRPCReplyError
from .constants import DEFAULT_ENDPOINT, DEFAULT_TIMEOUT
#############################
# Node / network level RPCs #
#############################
def get_bad_blocks(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> list:
def get_bad_blocks(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""[WIP] Get list of bad blocks in memory of specific node Known issues
with RPC not returning correctly.
@ -38,7 +42,9 @@ def get_bad_blocks(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> list:
"""
method = "hmyv2_getCurrentBadBlocks"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -74,7 +80,10 @@ def chain_id(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_node_metadata(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_node_metadata(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get config for the node.
Parameters
@ -133,7 +142,10 @@ def get_node_metadata(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dic
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_peer_info(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_peer_info(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get peer info for the node.
Parameters
@ -165,12 +177,17 @@ def get_peer_info(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
"""
method = "hmyv2_getPeerInfo"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def protocol_version(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def protocol_version(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the current Harmony protocol version this node supports.
Parameters
@ -202,7 +219,10 @@ def protocol_version(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_num_peers(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_num_peers(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get number of peers connected to the node.
Parameters
@ -229,13 +249,19 @@ def get_num_peers(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
method = "net_peerCount"
try: # Number of peers represented as a hex string
return int(
rpc_request(method, endpoint=endpoint, timeout=timeout)["result"], 16
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ],
16
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_version(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_version(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get version of the EVM network (https://chainid.network/)
Parameters
@ -262,7 +288,10 @@ def get_version(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
method = "net_version"
try:
return int(
rpc_request(method, endpoint=endpoint, timeout=timeout)["result"], 16
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ],
16
) # this is hexadecimal
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -293,12 +322,19 @@ def in_sync(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> bool:
"""
method = "hmyv2_inSync"
try:
return bool(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return bool(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def beacon_in_sync(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> bool:
def beacon_in_sync(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""Whether the beacon chain is in sync or syncing (not out of sync)
Parameters
@ -323,12 +359,19 @@ def beacon_in_sync(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> bool:
"""
method = "hmyv2_beaconInSync"
try:
return bool(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return bool(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_staking_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_staking_epoch(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get epoch number when blockchain switches to EPoS election.
Parameters
@ -358,13 +401,18 @@ def get_staking_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int
"""
method = "hmyv2_getNodeMetadata"
try:
data = rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
data = rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
return int( data[ "chain-config" ][ "staking-epoch" ] )
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_prestaking_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_prestaking_epoch(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get epoch number when blockchain switches to allow staking features
without election.
@ -395,7 +443,9 @@ def get_prestaking_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
"""
method = "hmyv2_getNodeMetadata"
try:
data = rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
data = rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
return int( data[ "chain-config" ][ "prestaking-epoch" ] )
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -430,15 +480,16 @@ def get_shard(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
"""
method = "hmyv2_getNodeMetadata"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"][
"shard-id"
]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ][ "shard-id" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_sharding_structure(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get network sharding structure.
@ -468,7 +519,9 @@ def get_sharding_structure(
"""
method = "hmyv2_getShardingStructure"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -476,7 +529,10 @@ def get_sharding_structure(
#############################
# Current status of network #
#############################
def get_leader_address(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> str:
def get_leader_address(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Get current leader one address.
Parameters
@ -502,13 +558,17 @@ def get_leader_address(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> st
"""
method = "hmyv2_getLeader"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def is_last_block(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""If the block at block_num is the last block.
@ -534,22 +594,25 @@ def is_last_block(
-------------
https://github.com/harmony-one/harmony/blob/1a8494c069dc3f708fdf690456713a2411465199/rpc/blockchain.go#L286
"""
params = [
block_num,
]
params = [ block_num, ]
method = "hmyv2_isLastBlock"
try:
return bool(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def epoch_last_block(
epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
epoch,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Returns the number of the last block in the epoch.
@ -575,21 +638,25 @@ def epoch_last_block(
-------------
https://github.com/harmony-one/harmony/blob/1a8494c069dc3f708fdf690456713a2411465199/rpc/blockchain.go#L294
"""
params = [
epoch,
]
params = [ epoch, ]
method = "hmyv2_epochLastBlock"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_circulating_supply(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_circulating_supply(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get current circulation supply of tokens in ONE.
Parameters
@ -615,12 +682,17 @@ def get_circulating_supply(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -
"""
method = "hmyv2_getCirculatingSupply"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_total_supply(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_total_supply(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get total number of pre-mined tokens.
Parameters
@ -646,12 +718,17 @@ def get_total_supply(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
"""
method = "hmyv2_getTotalSupply"
try:
rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_number(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_block_number(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get current block number.
Parameters
@ -677,12 +754,19 @@ def get_block_number(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
"""
method = "hmyv2_blockNumber"
try:
return int(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return int(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_current_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_current_epoch(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get current epoch number.
Parameters
@ -708,12 +792,19 @@ def get_current_epoch(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int
"""
method = "hmyv2_getEpoch"
try:
return int(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return int(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_last_cross_links(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> list:
def get_last_cross_links(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get last cross shard links.
Parameters
@ -746,12 +837,17 @@ def get_last_cross_links(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
"""
method = "hmyv2_getLastCrossLinks"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_gas_price(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_gas_price(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get network gas price.
Parameters
@ -777,7 +873,11 @@ def get_gas_price(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
"""
method = "hmyv2_gasPrice"
try:
return int(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return int(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -785,7 +885,10 @@ def get_gas_price(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
##############
# Block RPCs #
##############
def get_latest_header(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_latest_header(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get block header of latest block.
Parameters
@ -829,13 +932,17 @@ def get_latest_header(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dic
"""
method = "hmyv2_latestHeader"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_header_by_number(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get block header of block at block_num.
@ -864,15 +971,19 @@ def get_header_by_number(
method = "hmyv2_getHeaderByNumber"
params = [ block_num ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_latest_chain_headers(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get block header of latest block for beacon chain & shard chain.
@ -919,7 +1030,9 @@ def get_latest_chain_headers(
"""
method = "hmyv2_getLatestChainHeaders"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -1005,9 +1118,12 @@ def get_block_by_number( # pylint: disable=too-many-arguments
]
method = "hmyv2_getBlockByNumber"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -1062,15 +1178,20 @@ def get_block_by_hash( # pylint: disable=too-many-arguments
]
method = "hmyv2_getBlockByHash"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_transaction_count_by_number(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get transaction count for specific block number.
@ -1103,16 +1224,21 @@ def get_block_transaction_count_by_number(
method = "hmyv2_getBlockTransactionCountByNumber"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_transaction_count_by_hash(
block_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get transaction count for specific block hash.
@ -1145,16 +1271,21 @@ def get_block_transaction_count_by_hash(
method = "hmyv2_getBlockTransactionCountByHash"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_staking_transaction_count_by_number(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get staking transaction count for specific block number.
@ -1187,16 +1318,21 @@ def get_block_staking_transaction_count_by_number(
method = "hmyv2_getBlockStakingTransactionCountByNumber"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_staking_transaction_count_by_hash(
block_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get staking transaction count for specific block hash.
@ -1229,9 +1365,12 @@ def get_block_staking_transaction_count_by_hash(
method = "hmyv2_getBlockStakingTransactionCountByHash"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -1293,15 +1432,20 @@ def get_blocks( # pylint: disable=too-many-arguments
]
method = "hmyv2_getBlocks"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_signers(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of block signers for specific block number.
@ -1331,15 +1475,20 @@ def get_block_signers(
params = [ block_num ]
method = "hmyv2_getBlockSigners"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_block_signers_keys(
block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of block signer public bls keys for specific block number.
@ -1369,15 +1518,21 @@ def get_block_signers_keys(
params = [ block_num ]
method = "hmyv2_getBlockSignerKeys"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def is_block_signer(
block_num, address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""Determine if the account at address is a signer for the block at
block_num.
@ -1409,15 +1564,20 @@ def is_block_signer(
params = [ block_num, address ]
method = "hmyv2_isBlockSigner"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_signed_blocks(
address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""The number of blocks a particular validator signed for last blocksPeriod
(1 epoch)
@ -1448,15 +1608,22 @@ def get_signed_blocks(
method = "hmyv2_getSignedBlocks"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validators(epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_validators(
epoch,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get list of validators for specific epoch number.
Parameters
@ -1488,15 +1655,20 @@ def get_validators(epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
params = [ epoch ]
method = "hmyv2_getValidators"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_keys(
epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
epoch,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of validator public bls keys for specific epoch number.
@ -1526,8 +1698,11 @@ def get_validator_keys(
params = [ epoch ]
method = "hmyv2_getValidatorKeys"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception

@ -77,7 +77,6 @@ ARG_PREFIX = "__PYHMY_ARG_PREFIX__"
environment = os.environ.copy() # The environment for the CLI to execute in.
# completely remove caching...
# we need to improve getting address better internally to REDUCE single calls....
# def _cache_and_lock_accounts_keystore(fn):
@ -102,6 +101,7 @@ environment = os.environ.copy() # The environment for the CLI to execute in.
# return wrap
def account_keystore_path( value = None ):
"""
Gets or sets the ACCOUNT_KEYSTORE_PATH
@ -112,6 +112,7 @@ def account_keystore_path(value=None):
account_keystore_path.value = value
return account_keystore_path.value
def binary_path( value = None ):
"""
Gets or sets the BINARY_PATH
@ -122,6 +123,7 @@ def binary_path(value=None):
binary_path.value = value
return binary_path.value
def _get_current_accounts_keystore():
"""Internal function that gets the current keystore from the CLI.
@ -132,9 +134,13 @@ def _get_current_accounts_keystore():
response = single_call( "hmy keys list" )
lines = response.split( "\n" )
if "NAME" not in lines[ 0 ] or "ADDRESS" not in lines[ 0 ]:
raise ValueError("Name or Address not found on first line of key list")
raise ValueError(
"Name or Address not found on first line of key list"
)
if lines[ 1 ] != "":
raise ValueError("Unknown format: No blank line between label and data")
raise ValueError(
"Unknown format: No blank line between label and data"
)
for line in lines[ 2 : ]:
columns = line.split( "\t" )
if len( columns ) != 2:
@ -184,8 +190,13 @@ def _make_call_command(command):
command_toks_prefix = [ el for el in command.split( " " ) if el ]
command_toks = []
for element in command_toks_prefix:
if element.startswith(f'"{ARG_PREFIX}_') and element.endswith('"'):
index = int(element.replace(f'"{ARG_PREFIX}_', "").replace('"', ""))
if element.startswith( f'"{ARG_PREFIX}_'
) and element.endswith( '"' ):
index = int(
element.replace( f'"{ARG_PREFIX}_',
"" ).replace( '"',
"" )
)
command_toks.append( all_strings[ index ] )
else:
command_toks.append( element )
@ -213,7 +224,8 @@ def is_valid_binary(path):
os.chmod( path, os.stat( path ).st_mode | stat.S_IEXEC )
try:
with subprocess.Popen(
[path, "version"],
[ path,
"version" ],
env = environment,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
@ -222,7 +234,11 @@ def is_valid_binary(path):
if not err:
return False
return "harmony" in err.decode().strip().lower()
except (OSError, subprocess.CalledProcessError, subprocess.SubprocessError):
except (
OSError,
subprocess.CalledProcessError,
subprocess.SubprocessError
):
return False
@ -256,7 +272,8 @@ def get_version():
:return: The version string of the CLI binary.
"""
with subprocess.Popen(
[binary_path(), "version"],
[ binary_path(),
"version" ],
env = environment,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
@ -301,7 +318,10 @@ def get_accounts(address):
Note that a list of account names is needed because 1 address can
have multiple names within the CLI's keystore.
"""
return [acc for acc, addr in get_accounts_keystore().items() if address == addr]
return [
acc for acc,
addr in get_accounts_keystore().items() if address == addr
]
def remove_account( name ):
@ -318,7 +338,8 @@ def remove_account(name):
shutil.rmtree( keystore_path )
except ( shutil.Error, FileNotFoundError ) as err:
raise RuntimeError(
f"Failed to delete dir: {keystore_path}\n" f"\tException: {err}"
f"Failed to delete dir: {keystore_path}\n"
f"\tException: {err}"
) from err
_sync_accounts()
@ -343,12 +364,15 @@ def single_call(command, timeout=60, error_ok=False):
command_toks = [ binary_path() ] + _make_call_command( command )
try:
return subprocess.check_output(
command_toks, env=environment, timeout=timeout
command_toks,
env = environment,
timeout = timeout
).decode()
except subprocess.CalledProcessError as err:
if not error_ok:
raise RuntimeError(
f"Bad CLI args: `{command}`\n " f"\tException: {err}"
f"Bad CLI args: `{command}`\n "
f"\tException: {err}"
) from err
return err.output.decode()
@ -363,12 +387,16 @@ def expect_call(command, timeout=60):
command_toks = _make_call_command( command )
try:
proc = pexpect.spawn(
f"{binary_path()}", command_toks, env=environment, timeout=timeout
f"{binary_path()}",
command_toks,
env = environment,
timeout = timeout
)
proc.delaybeforesend = None
except pexpect.ExceptionPexpect as err:
raise RuntimeError(
f"Bad CLI args: `{command}`\n " f"\tException: {err}"
f"Bad CLI args: `{command}`\n "
f"\tException: {err}"
) from err
return proc
@ -399,28 +427,40 @@ def download(path="./bin/hmy", replace=True, verbose=True):
"https://raw.githubusercontent.com/harmony-one/go-sdk/master/scripts/hmy.sh"
).content.decode()
)
os.chmod(hmy_script_path, os.stat(hmy_script_path).st_mode | stat.S_IEXEC)
os.chmod(
hmy_script_path,
os.stat( hmy_script_path ).st_mode | stat.S_IEXEC
)
same_name_file = False
if (
os.path.exists(os.path.join(parent_dir, "hmy")) and Path(path).name != "hmy"
os.path.exists( os.path.join( parent_dir,
"hmy" ) ) and
Path( path ).name != "hmy"
): # Save same name file.
same_name_file = True
os.rename(
os.path.join(parent_dir, "hmy"), os.path.join(parent_dir, ".hmy_tmp")
os.path.join( parent_dir,
"hmy" ),
os.path.join( parent_dir,
".hmy_tmp" )
)
if verbose:
subprocess.call( [ hmy_script_path, "-d" ] )
else:
with open( os.devnull, "w", encoding = "UTF-8" ) as devnull:
subprocess.call(
[hmy_script_path, "-d"],
[ hmy_script_path,
"-d" ],
stdout = devnull,
stderr = subprocess.STDOUT,
)
os.rename( os.path.join( parent_dir, "hmy" ), path )
if same_name_file:
os.rename(
os.path.join(parent_dir, ".hmy_tmp"), os.path.join(parent_dir, "hmy")
os.path.join( parent_dir,
".hmy_tmp" ),
os.path.join( parent_dir,
"hmy" )
)
if verbose:
print( f"Saved harmony binary to: `{path}`" )
@ -434,7 +474,9 @@ def download(path="./bin/hmy", replace=True, verbose=True):
env[ "DYLD_FALLBACK_LIBRARY_PATH" ] = parent_dir
elif os.path.exists(
f"{get_gopath()}/src/github.com/harmony-one/bls"
) and os.path.exists(f"{get_gopath()}/src/github.com/harmony-one/mcl"):
) and os.path.exists(
f"{get_gopath()}/src/github.com/harmony-one/mcl"
):
env.update( get_bls_build_variables() )
else:
raise RuntimeWarning(

@ -76,9 +76,12 @@ def call( # pylint: disable=too-many-arguments
]
method = "hmyv2_call"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -141,9 +144,12 @@ def estimate_gas( # pylint: disable=too-many-arguments
method = "hmyv2_estimateGas"
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
],
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ],
16,
)
except KeyError as exception:
@ -151,7 +157,10 @@ def estimate_gas( # pylint: disable=too-many-arguments
def get_code(
address, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Get the code stored at the given address in the state for the given
block number.
@ -185,15 +194,22 @@ def get_code(
params = [ address, block_num ]
method = "hmyv2_getCode"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_storage_at(
address, key, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
key,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Get the storage from the state at the given address, the key and the
block number.
@ -229,15 +245,20 @@ def get_storage_at(
params = [ address, key, block_num ]
method = "hmyv2_getStorageAt"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_contract_address_from_hash(
tx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
tx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Get address of the contract which was deployed in the transaction
represented by tx_hash.
@ -266,6 +287,11 @@ def get_contract_address_from_hash(
https://github.com/harmony-one/harmony-test/blob/master/localnet/rpc_tests/test_contract.py#L36
"""
try:
return get_transaction_receipt(tx_hash, endpoint, timeout)["contractAddress"]
return get_transaction_receipt( tx_hash,
endpoint,
timeout )[ "contractAddress" ]
except KeyError as exception:
raise InvalidRPCReplyError("hmyv2_getTransactionReceipt", endpoint) from exception
raise InvalidRPCReplyError(
"hmyv2_getTransactionReceipt",
endpoint
) from exception

@ -2,11 +2,11 @@
Exceptions used by pyhmy
"""
class InvalidRPCReplyError( RuntimeError ):
"""Exception raised when RPC call returns unexpected result Generally
indicates Harmony API has been updated & pyhmy library needs to be updated
as well."""
def __init__( self, method, endpoint ):
super().__init__( f"Unexpected reply for {method} from {endpoint}" )
@ -34,6 +34,5 @@ class InvalidValidatorError(ValueError):
class TxConfirmationTimedoutError( AssertionError ):
"""Exception raised when a transaction is sent to the chain But not
confirmed during the timeout period specified."""
def __init__( self, msg ):
super().__init__( f"{msg}" )

@ -22,7 +22,6 @@ class _GZipRotator: # pylint: disable=too-few-public-methods
class ControlledLogger: # pylint: disable=too-many-instance-attributes
"""A simple logger that only writes to file when the 'write' method is
called."""
def __init__( self, logger_name, log_dir, backup_count = 5 ):
"""
:param logger_name: The name of the logger and logfile
@ -33,9 +32,14 @@ class ControlledLogger: # pylint: disable=too-many-instance-attributes
log_dir = os.path.realpath( log_dir )
os.makedirs( log_dir, exist_ok = True )
handler = logging.handlers.TimedRotatingFileHandler(
f"{log_dir}/{logger_name}.log", "midnight", 1, backupCount=backup_count
f"{log_dir}/{logger_name}.log",
"midnight",
1,
backupCount = backup_count
)
handler.setFormatter(
logging.Formatter( "%(levelname)s - %(message)s" )
)
handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
handler.rotator = _GZipRotator()
self.filename = handler.baseFilename
@ -64,7 +68,8 @@ class ControlledLogger: # pylint: disable=too-many-instance-attributes
"""
with self._lock:
self.info_buffer.append(
f"[{threading.get_ident()}] " f"{datetime.datetime.utcnow()} : {msg}"
f"[{threading.get_ident()}] "
f"{datetime.datetime.utcnow()} : {msg}"
)
def debug( self, msg ):
@ -73,7 +78,8 @@ class ControlledLogger: # pylint: disable=too-many-instance-attributes
"""
with self._lock:
self.debug_buffer.append(
f"[{threading.get_ident()}] " f"{datetime.datetime.utcnow()} : {msg}"
f"[{threading.get_ident()}] "
f"{datetime.datetime.utcnow()} : {msg}"
)
def warning( self, msg ):
@ -82,7 +88,8 @@ class ControlledLogger: # pylint: disable=too-many-instance-attributes
"""
with self._lock:
self.warning_buffer.append(
f"[{threading.get_ident()}] " f"{datetime.datetime.utcnow()} : {msg}"
f"[{threading.get_ident()}] "
f"{datetime.datetime.utcnow()} : {msg}"
)
def error( self, msg ):
@ -91,7 +98,8 @@ class ControlledLogger: # pylint: disable=too-many-instance-attributes
"""
with self._lock:
self.error_buffer.append(
f"[{threading.get_ident()}] " f"{datetime.datetime.utcnow()} : {msg}"
f"[{threading.get_ident()}] "
f"{datetime.datetime.utcnow()} : {msg}"
)
def print_info( self ):

@ -5,7 +5,6 @@ For more granular conversions, see Web3.toWei
from decimal import Decimal
_conversion_unit = Decimal( 1e18 )

@ -4,23 +4,23 @@ RPC Specific Exceptions
import requests
class RPCError( RuntimeError ):
"""Exception raised when RPC call returns an error."""
def __init__( self, method, endpoint, error ):
self.error = error
super().__init__(f"Error in reply from {endpoint}: {method} returned {error}")
super().__init__(
f"Error in reply from {endpoint}: {method} returned {error}"
)
class RequestsError( requests.exceptions.RequestException ):
"""Wrapper for requests lib exceptions."""
def __init__( self, endpoint ):
super().__init__( f"Error connecting to {endpoint}" )
class RequestsTimeoutError( requests.exceptions.Timeout ):
"""Wrapper for requests lib Timeout exceptions."""
def __init__( self, endpoint ):
super().__init__( f"Error connecting to {endpoint}" )

@ -11,7 +11,10 @@ from ..constants import DEFAULT_ENDPOINT, DEFAULT_TIMEOUT
def base_request(
method, params=None, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
method,
params = None,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Basic RPC request.
@ -46,8 +49,15 @@ def base_request(
raise TypeError( f"invalid type {params.__class__}" )
try:
payload = {"id": "1", "jsonrpc": "2.0", "method": method, "params": params}
headers = {"Content-Type": "application/json"}
payload = {
"id": "1",
"jsonrpc": "2.0",
"method": method,
"params": params
}
headers = {
"Content-Type": "application/json"
}
resp = requests.request(
"POST",
@ -65,7 +75,10 @@ def base_request(
def rpc_request(
method, params=None, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
method,
params = None,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""RPC request.

@ -45,14 +45,23 @@ class UnsignedHarmonyTxData(HashableRLP):
as the difference against Eth
"""
fields = (
("nonce", big_endian_int),
("gasPrice", big_endian_int),
("gas", big_endian_int),
("shardID", big_endian_int),
("toShardID", big_endian_int),
("to", Binary.fixed_length(20, allow_empty=True)),
("value", big_endian_int),
("data", binary),
( "nonce",
big_endian_int ),
( "gasPrice",
big_endian_int ),
( "gas",
big_endian_int ),
( "shardID",
big_endian_int ),
( "toShardID",
big_endian_int ),
( "to",
Binary.fixed_length( 20,
allow_empty = True ) ),
( "value",
big_endian_int ),
( "data",
binary ),
)
@ -68,18 +77,31 @@ class SignedHarmonyTxData(HashableRLP):
("s", big_endian_int), # Next 32 bytes
)
# https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L55
def encode_transaction(
unsigned_transaction, vrs
):
def encode_transaction( unsigned_transaction, vrs ):
"""serialize and encode an unsigned transaction with v,r,s."""
( v, r, s ) = vrs # pylint: disable=invalid-name
chain_naive_transaction = dissoc(unsigned_transaction.as_dict(), "v", "r", "s")
if isinstance(unsigned_transaction, (UnsignedHarmonyTxData, SignedHarmonyTxData)):
chain_naive_transaction = dissoc(
unsigned_transaction.as_dict(),
"v",
"r",
"s"
)
if isinstance(
unsigned_transaction,
( UnsignedHarmonyTxData,
SignedHarmonyTxData )
):
serializer = SignedHarmonyTxData
else:
serializer = SignedEthereumTxData
signed_transaction = serializer(v=v, r=r, s=s, **chain_naive_transaction)
signed_transaction = serializer(
v = v,
r = r,
s = s,
**chain_naive_transaction
)
return rlp.encode( signed_transaction )
@ -98,7 +120,11 @@ def serialize_transaction(filled_transaction):
for field, _ in serializer._meta.fields:
assert field in filled_transaction, f"Could not find {field} in transaction"
return serializer.from_dict(
{field: filled_transaction[field] for field, _ in serializer._meta.fields}
{
field: filled_transaction[ field ]
for field,
_ in serializer._meta.fields
}
)
@ -109,12 +135,13 @@ def sanitize_transaction(transaction_dict, private_key):
account = Account.from_key( # pylint: disable=no-value-for-parameter
private_key
)
sanitized_transaction = transaction_dict.copy() # do not alter the original dictionary
sanitized_transaction = transaction_dict.copy(
) # do not alter the original dictionary
if "from" in sanitized_transaction:
sanitized_transaction["from"] = convert_one_to_hex(transaction_dict["from"])
if (
sanitized_transaction["from"] == account.address
):
sanitized_transaction[ "from" ] = convert_one_to_hex(
transaction_dict[ "from" ]
)
if sanitized_transaction[ "from" ] == account.address:
sanitized_transaction = dissoc( sanitized_transaction, "from" )
else:
raise TypeError(
@ -122,7 +149,9 @@ def sanitize_transaction(transaction_dict, private_key):
"but it was {sanitized_transaction['from']}"
)
if "chainId" in sanitized_transaction:
sanitized_transaction["chainId"] = chain_id_to_int(sanitized_transaction["chainId"])
sanitized_transaction[ "chainId" ] = chain_id_to_int(
sanitized_transaction[ "chainId" ]
)
return account, sanitized_transaction
@ -172,13 +201,17 @@ def sign_transaction(transaction_dict, private_key) -> SignedTransaction:
https://readthedocs.org/projects/eth-account/downloads/pdf/stable/
"""
account, sanitized_transaction = sanitize_transaction(transaction_dict, private_key)
if "to" in sanitized_transaction and sanitized_transaction["to"] is not None:
sanitized_transaction["to"] = convert_one_to_hex(sanitized_transaction["to"])
if "to" in sanitized_transaction and sanitized_transaction[ "to"
] is not None:
sanitized_transaction[ "to" ] = convert_one_to_hex(
sanitized_transaction[ "to" ]
)
# https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L39
filled_transaction = pipe(
sanitized_transaction,
dict,
partial(merge, TRANSACTION_DEFAULTS),
partial( merge,
TRANSACTION_DEFAULTS ),
chain_id_to_v,
apply_formatters_to_dict( HARMONY_FORMATTERS ),
)
@ -187,13 +220,26 @@ def sign_transaction(transaction_dict, private_key) -> SignedTransaction:
# https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/signing.py#L26
if isinstance(
unsigned_transaction, (UnsignedEthereumTxData, UnsignedHarmonyTxData)
unsigned_transaction,
( UnsignedEthereumTxData,
UnsignedHarmonyTxData )
):
chain_id = None
else:
chain_id = unsigned_transaction.v
(v, r, s) = sign_transaction_hash(account._key_obj, transaction_hash, chain_id) # pylint: disable=invalid-name
encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s))
( v, # pylint: disable=invalid-name
r, # pylint: disable=invalid-name
s ) = sign_transaction_hash( # pylint: disable=invalid-name
account._key_obj,
transaction_hash,
chain_id
)
encoded_transaction = encode_transaction(
unsigned_transaction,
vrs = ( v,
r,
s )
)
signed_transaction_hash = keccak( encoded_transaction )
return SignedTransaction(
rawTransaction = HexBytes( encoded_transaction ),

@ -8,11 +8,13 @@ from .exceptions import InvalidRPCReplyError
from .constants import DEFAULT_ENDPOINT, DEFAULT_TIMEOUT
##################
# Validator RPCs #
##################
def get_all_validator_addresses(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of all created validator addresses on chain.
@ -39,13 +41,17 @@ def get_all_validator_addresses(
"""
method = "hmyv2_getAllValidatorAddresses"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_information(
validator_addr, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
validator_addr,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get validator information for validator address.
@ -120,15 +126,19 @@ def get_validator_information(
method = "hmyv2_getValidatorInformation"
params = [ validator_addr ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_elected_validator_addresses(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of elected validator addresses.
@ -156,12 +166,18 @@ def get_elected_validator_addresses(
"""
method = "hmyv2_getElectedValidatorAddresses"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validators(epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> list:
def get_validators(
epoch,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get validators list for a particular epoch.
Parameters
@ -193,15 +209,20 @@ def get_validators(epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
method = "hmyv2_getValidators"
params = [ epoch ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_keys(
epoch, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
epoch,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get validator BLS keys in the committee for a particular epoch.
@ -230,15 +251,21 @@ def get_validator_keys(
method = "hmyv2_getValidatorKeys"
params = [ epoch ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_information_by_block_number(
validator_addr, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
validator_addr,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
):
"""Get validator information for validator address at a block.
@ -269,15 +296,20 @@ def get_validator_information_by_block_number(
method = "hmyv2_getValidatorInformationByBlockNumber"
params = [ validator_addr, block_num ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_all_validator_information(
page=0, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
page = 0,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get validator information for all validators on chain.
@ -306,15 +338,20 @@ def get_all_validator_information(
method = "hmyv2_getAllValidatorInformation"
params = [ page ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_self_delegation(
address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the amount self delegated by validator.
@ -344,16 +381,21 @@ def get_validator_self_delegation(
params = [ address ]
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_validator_total_delegation(
address, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
address,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get the total amount delegated t ovalidator (including self delegated)
@ -383,16 +425,22 @@ def get_validator_total_delegation(
params = [ address ]
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_all_validator_information_by_block_number(
block_num, page=0, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
page = 0,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get validator information at block number for all validators on chain.
@ -424,9 +472,12 @@ def get_all_validator_information_by_block_number(
method = "hmyv2_getAllValidatorInformationByBlockNumber"
params = [ page, block_num ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -435,7 +486,9 @@ def get_all_validator_information_by_block_number(
# Delegation RPCs #
###################
def get_all_delegation_information(
page=0, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
page = 0,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get delegation information for all delegators on chain.
@ -464,19 +517,22 @@ def get_all_delegation_information(
https://github.com/harmony-one/harmony/blob/1a8494c069dc3f708fdf690456713a2411465199/rpc/staking.go#L413
"""
method = "hmyv2_getAllDelegationInformation"
params = [
page,
]
params = [ page, ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_delegations_by_delegator(
delegator_addr, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
delegator_addr,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of delegations by a delegator.
@ -512,15 +568,21 @@ def get_delegations_by_delegator(
method = "hmyv2_getDelegationsByDelegator"
params = [ delegator_addr ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_delegations_by_delegator_by_block_number(
delegator_addr, block_num, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
delegator_addr,
block_num,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of delegations by a delegator at a specific block.
@ -551,9 +613,12 @@ def get_delegations_by_delegator_by_block_number(
method = "hmyv2_getDelegationsByDelegatorByBlockNumber"
params = [ delegator_addr, block_num ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -594,15 +659,20 @@ def get_delegation_by_delegator_and_validator(
method = "hmyv2_getDelegationByDelegatorAndValidator"
params = [ delegator_addr, validator_address ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_available_redelegation_balance(
delegator_addr, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
delegator_addr,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get amount of locked undelegated tokens.
@ -632,16 +702,21 @@ def get_available_redelegation_balance(
params = [ delegator_addr ]
try:
return int(
rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_delegations_by_validator(
validator_addr, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
validator_addr,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of delegations to a validator.
@ -670,9 +745,12 @@ def get_delegations_by_validator(
method = "hmyv2_getDelegationsByValidator"
params = [ validator_addr ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -681,7 +759,8 @@ def get_delegations_by_validator(
# Staking Network RPCs #
########################
def get_current_utility_metrics(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get current utility metrics of network.
@ -711,13 +790,16 @@ def get_current_utility_metrics(
"""
method = "hmyv2_getCurrentUtilityMetrics"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_staking_network_info(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get staking network information.
@ -748,12 +830,17 @@ def get_staking_network_info(
"""
method = "hmyv2_getStakingNetworkInfo"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_super_committees(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_super_committees(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get voting committees for current & previous epoch.
Parameters
@ -801,12 +888,17 @@ def get_super_committees(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) ->
"""
method = "hmyv2_getSuperCommittees"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_total_staking(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int:
def get_total_staking(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> int:
"""Get total staking by validators, only meant to be called on beaconchain.
Parameters
@ -831,13 +923,18 @@ def get_total_staking(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> int
"""
method = "hmyv2_getTotalStaking"
try:
return int(rpc_request(method, endpoint=endpoint, timeout=timeout)["result"])
return int(
rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
)
except ( KeyError, TypeError ) as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_raw_median_stake_snapshot(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get median stake & additional committee data of the current epoch.
@ -876,6 +973,8 @@ def get_raw_median_stake_snapshot(
"""
method = "hmyv2_getMedianRawStakeSnapshot"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception

@ -7,12 +7,7 @@ import math
from decimal import Decimal
from functools import partial
from toolz import (
pipe,
dissoc,
merge,
identity,
)
from toolz import ( pipe, dissoc, merge, identity, )
from hexbytes import HexBytes
@ -51,9 +46,7 @@ from .util import convert_one_to_hex
# https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L335
def _convert_staking_percentage_to_number(
value,
):
def _convert_staking_percentage_to_number( value, ):
"""Convert from staking percentage to integer For example, 0.1 becomes
1000000000000000000. Since Python floats are problematic with precision,
this function is used as a workaround.
@ -97,9 +90,7 @@ def _convert_staking_percentage_to_number(
elif len( splitted ) > 2:
raise ValueError( "Too many periods to be a StakingDecimal string" )
if length > PRECISION:
raise ValueError(
"Too much precision, must be less than {PRECISION}"
)
raise ValueError( "Too much precision, must be less than {PRECISION}" )
zeroes_to_add = PRECISION - length
combined_str += (
"0" * zeroes_to_add
@ -135,12 +126,16 @@ def _get_account_and_transaction(transaction_dict, private_key):
transaction_dict, private_key
) # remove from, convert chain id ( if present ) to integer
sanitized_transaction[ "directive" ] = sanitized_transaction[
"directive"
].value # convert to value, like in TypeScript
"directive" ].value # convert to value, like in TypeScript
return account, sanitized_transaction
# pylint: disable=too-many-locals,protected-access,invalid-name
def _sign_transaction_generic(account, sanitized_transaction, parent_serializer):
def _sign_transaction_generic(
account,
sanitized_transaction,
parent_serializer
):
"""Sign a generic staking transaction, given the serializer base class and
account.
@ -184,7 +179,11 @@ def _sign_transaction_generic(account, sanitized_transaction, parent_serializer)
for field, _ in unsigned_serializer._meta.fields:
assert field in filled_transaction, f"Could not find {field} in transaction"
unsigned_transaction = unsigned_serializer.from_dict(
{f: filled_transaction[f] for f, _ in unsigned_serializer._meta.fields}
{
f: filled_transaction[ f ]
for f,
_ in unsigned_serializer._meta.fields
}
) # drop extras silently
# sign the unsigned transaction
if "v" in unsigned_transaction.as_dict( ):
@ -192,9 +191,17 @@ def _sign_transaction_generic(account, sanitized_transaction, parent_serializer)
else:
chain_id = None
transaction_hash = unsigned_transaction.hash( )
(v, r, s) = sign_transaction_hash(account._key_obj, transaction_hash, chain_id)
( v,
r,
s
) = sign_transaction_hash( account._key_obj,
transaction_hash,
chain_id )
chain_naive_transaction = dissoc(
unsigned_transaction.as_dict(), "v", "r", "s"
unsigned_transaction.as_dict( ),
"v",
"r",
"s"
) # remove extra v/r/s added by chain_id_to_v
# serialize it
# https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L207
@ -229,7 +236,10 @@ def _sign_delegate_or_undelegate(transaction_dict, private_key):
"""Sign a delegate or undelegate transaction See sign_staking_transaction
for details."""
# preliminary steps
if transaction_dict["directive"] not in [Directive.Delegate, Directive.Undelegate]:
if transaction_dict[ "directive" ] not in [
Directive.Delegate,
Directive.Undelegate
]:
raise TypeError(
"Only Delegate or Undelegate are supported by _sign_delegate_or_undelegate"
)
@ -239,15 +249,25 @@ def _sign_delegate_or_undelegate(transaction_dict, private_key):
)
# encode the stakeMsg
sanitized_transaction[ "stakeMsg" ] = apply_formatters_to_sequence(
[hexstr_if_str(to_bytes), hexstr_if_str(to_bytes), hexstr_if_str(to_int)],
[
convert_one_to_hex(sanitized_transaction.pop("delegatorAddress")),
convert_one_to_hex(sanitized_transaction.pop("validatorAddress")),
hexstr_if_str( to_bytes ),
hexstr_if_str( to_bytes ),
hexstr_if_str( to_int )
],
[
convert_one_to_hex(
sanitized_transaction.pop( "delegatorAddress" )
),
convert_one_to_hex(
sanitized_transaction.pop( "validatorAddress" )
),
sanitized_transaction.pop( "amount" ),
],
)
return _sign_transaction_generic(
account, sanitized_transaction, DelegateOrUndelegate
account,
sanitized_transaction,
DelegateOrUndelegate
)
@ -256,7 +276,9 @@ def _sign_collect_rewards(transaction_dict, private_key):
details."""
# preliminary steps
if transaction_dict[ "directive" ] != Directive.CollectRewards:
raise TypeError("Only CollectRewards is supported by _sign_collect_rewards")
raise TypeError(
"Only CollectRewards is supported by _sign_collect_rewards"
)
# first common step
account, sanitized_transaction = _get_account_and_transaction(
transaction_dict, private_key
@ -264,10 +286,16 @@ def _sign_collect_rewards(transaction_dict, private_key):
# encode the stakeMsg
sanitized_transaction[ "stakeMsg" ] = [
hexstr_if_str( to_bytes )(
convert_one_to_hex(sanitized_transaction.pop("delegatorAddress"))
convert_one_to_hex(
sanitized_transaction.pop( "delegatorAddress" )
)
)
]
return _sign_transaction_generic(account, sanitized_transaction, CollectRewards)
return _sign_transaction_generic(
account,
sanitized_transaction,
CollectRewards
)
def _sign_create_validator( transaction_dict, private_key ):
@ -308,7 +336,8 @@ def _sign_create_validator(transaction_dict, private_key):
sanitized_transaction.pop( "bls-public-keys" ),
)
bls_key_sigs = apply_formatter_to_array(
hexstr_if_str(to_bytes), sanitized_transaction.pop("bls-key-sigs") # formatter
hexstr_if_str( to_bytes ),
sanitized_transaction.pop( "bls-key-sigs" ) # formatter
)
sanitized_transaction[ "stakeMsg" ] = apply_formatters_to_sequence(
[
@ -340,7 +369,11 @@ def _sign_create_validator(transaction_dict, private_key):
math.floor( sanitized_transaction.pop( "amount" ) ),
],
)
return _sign_transaction_generic(account, sanitized_transaction, CreateValidator)
return _sign_transaction_generic(
account,
sanitized_transaction,
CreateValidator
)
def _sign_edit_validator( transaction_dict, private_key ):
@ -391,7 +424,11 @@ def _sign_edit_validator(transaction_dict, private_key):
sanitized_transaction.pop( "bls-key-to-add-sig" ),
],
)
return _sign_transaction_generic(account, sanitized_transaction, EditValidator)
return _sign_transaction_generic(
account,
sanitized_transaction,
EditValidator
)
def sign_staking_transaction( transaction_dict, private_key ):

@ -10,15 +10,11 @@ from rlp.sedes import big_endian_int, Binary, CountableList, List, Text
from eth_rlp import HashableRLP
from eth_utils.curried import (
to_int,
hexstr_if_str,
)
from eth_utils.curried import ( to_int, hexstr_if_str, )
# https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L120
class Directive(
Enum
):
class Directive( Enum ):
def _generate_next_value_( name, start, count, last_values ): # pylint: disable=no-self-argument
return count
@ -39,17 +35,29 @@ FORMATTERS = {
"chainId": hexstr_if_str(to_int),
}
class CollectRewards:
@staticmethod
def UnsignedChainId():
class UnsignedChainId( HashableRLP ):
fields = (
("directive", big_endian_int),
("stakeMsg", CountableList(Binary.fixed_length(20, allow_empty=True))),
("nonce", big_endian_int),
("gasPrice", big_endian_int),
("gasLimit", big_endian_int),
("chainId", big_endian_int),
( "directive",
big_endian_int ),
(
"stakeMsg",
CountableList(
Binary.fixed_length( 20,
allow_empty = True )
)
),
( "nonce",
big_endian_int ),
( "gasPrice",
big_endian_int ),
( "gasLimit",
big_endian_int ),
( "chainId",
big_endian_int ),
)
return UnsignedChainId
@ -70,7 +78,8 @@ class CollectRewards:
@staticmethod
def Unsigned():
class Unsigned( HashableRLP ):
fields = CollectRewards.UnsignedChainId()._meta.fields[:-1] # drop chainId
fields = CollectRewards.UnsignedChainId(
)._meta.fields[ :-1 ] # drop chainId
return Unsigned
@ -93,22 +102,29 @@ class DelegateOrUndelegate:
def UnsignedChainId():
class UnsignedChainId( HashableRLP ):
fields = (
("directive", big_endian_int),
( "directive",
big_endian_int ),
(
"stakeMsg",
List(
[
Binary.fixed_length(20, allow_empty=True),
Binary.fixed_length(20, allow_empty=True),
Binary.fixed_length( 20,
allow_empty = True ),
Binary.fixed_length( 20,
allow_empty = True ),
big_endian_int,
],
True,
),
),
("nonce", big_endian_int),
("gasPrice", big_endian_int),
("gasLimit", big_endian_int),
("chainId", big_endian_int),
( "nonce",
big_endian_int ),
( "gasPrice",
big_endian_int ),
( "gasLimit",
big_endian_int ),
( "chainId",
big_endian_int ),
)
return UnsignedChainId
@ -129,9 +145,8 @@ class DelegateOrUndelegate:
@staticmethod
def Unsigned():
class Unsigned( HashableRLP ):
fields = DelegateOrUndelegate.UnsignedChainId()._meta.fields[
:-1
] # drop chainId
fields = DelegateOrUndelegate.UnsignedChainId(
)._meta.fields[ :-1 ] # drop chainId
return Unsigned
@ -210,7 +225,8 @@ class CreateValidator:
@staticmethod
def Unsigned():
class Unsigned( HashableRLP ):
fields = CreateValidator.UnsignedChainId()._meta.fields[:-1] # drop chainId
fields = CreateValidator.UnsignedChainId(
)._meta.fields[ :-1 ] # drop chainId
return Unsigned
@ -290,7 +306,8 @@ class EditValidator:
@staticmethod
def Unsigned():
class Unsigned( HashableRLP ):
fields = EditValidator.UnsignedChainId()._meta.fields[:-1] # drop chainId
fields = EditValidator.UnsignedChainId(
)._meta.fields[ :-1 ] # drop chainId
return Unsigned

@ -13,7 +13,8 @@ from .exceptions import TxConfirmationTimedoutError, InvalidRPCReplyError
# Transaction Pool RPCs #
#########################
def get_pending_transactions(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of pending transactions.
@ -39,13 +40,16 @@ def get_pending_transactions(
"""
method = "hmyv2_pendingTransactions"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_transaction_error_sink(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get current transactions error sink.
@ -74,13 +78,16 @@ def get_transaction_error_sink(
"""
method = "hmyv2_getCurrentTransactionErrorSink"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_pending_staking_transactions(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of pending staking transactions.
@ -106,13 +113,16 @@ def get_pending_staking_transactions(
"""
method = "hmyv2_pendingStakingTransactions"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_staking_transaction_error_sink(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get current staking transactions error sink.
@ -142,12 +152,17 @@ def get_staking_transaction_error_sink(
"""
method = "hmyv2_getCurrentStakingErrorSink"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_pool_stats(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
def get_pool_stats(
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get stats of the pool, that is, number of pending and queued (non-
executable) transactions.
@ -175,7 +190,9 @@ def get_pool_stats(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
"""
method = "hmyv2_getPoolStats"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -184,7 +201,9 @@ def get_pool_stats(endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT) -> dict:
# Transaction RPCs #
####################
def get_transaction_by_hash(
tx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
tx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get transaction by hash.
@ -233,15 +252,21 @@ def get_transaction_by_hash(
method = "hmyv2_getTransactionByHash"
params = [ tx_hash ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_transaction_by_block_hash_and_index(
block_hash, tx_index, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_hash,
tx_index,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get transaction based on index in list of transactions in a block by
block hash.
@ -273,15 +298,21 @@ def get_transaction_by_block_hash_and_index(
method = "hmyv2_getTransactionByBlockHashAndIndex"
params = [ block_hash, tx_index ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_transaction_by_block_number_and_index(
block_num, tx_index, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
tx_index,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get transaction based on index in list of transactions in a block by
block number.
@ -313,15 +344,20 @@ def get_transaction_by_block_number_and_index(
method = "hmyv2_getTransactionByBlockNumberAndIndex"
params = [ block_num, tx_index ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_transaction_receipt(
tx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
tx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get transaction receipt corresponding to tx_hash.
@ -366,15 +402,20 @@ def get_transaction_receipt(
method = "hmyv2_getTransactionReceipt"
params = [ tx_hash ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def send_raw_transaction(
signed_tx, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
signed_tx,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Send signed transaction.
@ -406,15 +447,20 @@ def send_raw_transaction(
params = [ signed_tx ]
method = "hmyv2_sendRawTransaction"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def send_and_confirm_raw_transaction(
signed_tx, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
signed_tx,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Send signed transaction and wait for it to be confirmed.
@ -455,14 +501,17 @@ def send_and_confirm_raw_transaction(
if unique_chars != "0":
return tx_response
time.sleep( random.uniform( 0.2, 0.5 ) )
raise TxConfirmationTimedoutError("Could not confirm transaction on-chain.")
raise TxConfirmationTimedoutError(
"Could not confirm transaction on-chain."
)
###############################
# CrossShard Transaction RPCs #
###############################
def get_pending_cx_receipts(
endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Get list of pending cross shard transactions.
@ -511,13 +560,17 @@ def get_pending_cx_receipts(
"""
method = "hmyv2_getPendingCXReceipts"
try:
return rpc_request(method, endpoint=endpoint, timeout=timeout)["result"]
return rpc_request( method,
endpoint = endpoint,
timeout = timeout )[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_cx_receipt_by_hash(
cx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
cx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get cross shard receipt by hash on the receiving shard end point.
@ -555,15 +608,20 @@ def get_cx_receipt_by_hash(
params = [ cx_hash ]
method = "hmyv2_getCXReceiptByHash"
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def resend_cx_receipt(
cx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
cx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""Resend the cross shard receipt to the receiving shard to re-process if
the transaction did not pay out.
@ -594,9 +652,12 @@ def resend_cx_receipt(
method = "hmyv2_resendCx"
params = [ cx_hash ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
@ -605,7 +666,9 @@ def resend_cx_receipt(
# Staking Transaction RPCs #
############################
def get_staking_transaction_by_hash(
tx_hash, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
tx_hash,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get staking transaction by hash.
@ -648,15 +711,21 @@ def get_staking_transaction_by_hash(
method = "hmyv2_getStakingTransactionByHash"
params = [ tx_hash ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_staking_transaction_by_block_hash_and_index(
block_hash, tx_index, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_hash,
tx_index,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get staking transaction by block hash and transaction index.
@ -687,15 +756,21 @@ def get_staking_transaction_by_block_hash_and_index(
method = "hmyv2_getStakingTransactionByBlockHashAndIndex"
params = [ block_hash, tx_index ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def get_staking_transaction_by_block_number_and_index(
block_num, tx_index, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
block_num,
tx_index,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> dict:
"""Get staking transaction by block number and transaction index.
@ -726,15 +801,20 @@ def get_staking_transaction_by_block_number_and_index(
method = "hmyv2_getStakingTransactionByBlockNumberAndIndex"
params = [ block_num, tx_index ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def send_raw_staking_transaction(
raw_tx, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
raw_tx,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> str:
"""Send signed staking transaction.
@ -766,15 +846,20 @@ def send_raw_staking_transaction(
method = "hmyv2_sendRawStakingTransaction"
params = [ raw_tx ]
try:
return rpc_request(method, params=params, endpoint=endpoint, timeout=timeout)[
"result"
]
return rpc_request(
method,
params = params,
endpoint = endpoint,
timeout = timeout
)[ "result" ]
except KeyError as exception:
raise InvalidRPCReplyError( method, endpoint ) from exception
def send_and_confirm_raw_staking_transaction(
signed_tx, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
signed_tx,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> list:
"""Send signed staking transaction and wait for it to be confirmed.
@ -808,11 +893,16 @@ def send_and_confirm_raw_staking_transaction(
tx_hash = send_raw_staking_transaction( signed_tx, endpoint = endpoint )
start_time = time.time()
while ( time.time() - start_time ) <= timeout:
tx_response = get_staking_transaction_by_hash(tx_hash, endpoint=endpoint)
tx_response = get_staking_transaction_by_hash(
tx_hash,
endpoint = endpoint
)
if tx_response is not None:
block_hash = tx_response.get( "blockHash", "0x00" )
unique_chars = "".join( set( list( block_hash[ 2 : ] ) ) )
if unique_chars != "0":
return tx_response
time.sleep( random.uniform( 0.2, 0.5 ) )
raise TxConfirmationTimedoutError("Could not confirm transaction on-chain.")
raise TxConfirmationTimedoutError(
"Could not confirm transaction on-chain."
)

@ -13,16 +13,13 @@ from eth_utils import to_checksum_address
from .blockchain import get_latest_header
from .rpc.exceptions import (
RPCError,
RequestsError,
RequestsTimeoutError,
)
from .rpc.exceptions import ( RPCError, RequestsError, RequestsTimeoutError, )
from .account import is_valid_address
from .bech32.bech32 import bech32_decode, bech32_encode, convertbits
class Typgpy( str ):
"""Typography constants for pretty printing.
@ -107,7 +104,8 @@ def convert_hex_to_one(addr):
return addr
checksum_addr = str( to_checksum_address( addr ) )
data = bytearray.fromhex(
checksum_addr[2:] if checksum_addr.startswith("0x") else checksum_addr
checksum_addr[ 2 : ] if checksum_addr
.startswith( "0x" ) else checksum_addr
)
buf = convertbits( data, 8, 5 )
return str( bech32_encode( "one", buf ) )
@ -124,7 +122,8 @@ def is_active_shard(endpoint, delay_tolerance=60):
latest_header = get_latest_header( endpoint = endpoint )
time_str = latest_header[ "timestamp" ][ : 19 ] + ".0" # Fit time format
timestamp = datetime.datetime.strptime(
time_str, "%Y-%m-%d %H:%M:%S.%f"
time_str,
"%Y-%m-%d %H:%M:%S.%f"
).replace( tzinfo = None )
time_delta = curr_time - timestamp
return abs( time_delta.seconds ) < delay_tolerance
@ -144,10 +143,11 @@ def get_bls_build_variables():
variables = {}
try:
openssl_dir = (
subprocess.check_output(["which", "openssl"])
.decode()
.strip()
.split("\n", maxsplit=1)[0]
subprocess.check_output(
[ "which",
"openssl" ]
).decode().strip().split( "\n",
maxsplit = 1 )[ 0 ]
)
except ( IndexError, subprocess.CalledProcessError ) as exception:
raise RuntimeError( "`openssl` not found" ) from exception
@ -161,8 +161,10 @@ def get_bls_build_variables():
"CGO_CFLAGS"
] = f"-I{bls_dir}/include -I{mcl_dir}/include -I{openssl_dir}/include"
variables[ "CGO_LDFLAGS" ] = f"-L{bls_dir}/lib -L{openssl_dir}/lib"
variables["LD_LIBRARY_PATH"] = f"{bls_dir}/lib:{mcl_dir}/lib:{openssl_dir}/lib"
variables["DYLD_FALLBACK_LIBRARY_PATH"] = variables["LD_LIBRARY_PATH"]
variables[ "LD_LIBRARY_PATH"
] = f"{bls_dir}/lib:{mcl_dir}/lib:{openssl_dir}/lib"
variables[ "DYLD_FALLBACK_LIBRARY_PATH" ] = variables[ "LD_LIBRARY_PATH"
]
else:
variables[ "CGO_CFLAGS" ] = f"-I{bls_dir}/include -I{mcl_dir}/include"
variables[ "CGO_LDFLAGS" ] = f"-L{bls_dir}/lib"

@ -22,11 +22,7 @@ from .constants import (
from .exceptions import InvalidValidatorError
from .rpc.exceptions import (
RPCError,
RequestsError,
RequestsTimeoutError,
)
from .rpc.exceptions import ( RPCError, RequestsError, RequestsTimeoutError, )
from .staking import get_all_validator_addresses, get_validator_information
@ -34,16 +30,22 @@ from .staking_structures import Directive
from .staking_signing import sign_staking_transaction
class Validator: # pylint: disable=too-many-instance-attributes, too-many-public-methods
"""
Harmony validator
"""
def __init__( self, address ):
if not isinstance( address, str ):
raise InvalidValidatorError(1, "given ONE address was not a string")
raise InvalidValidatorError(
1,
"given ONE address was not a string"
)
if not is_valid_address( address ):
raise InvalidValidatorError(1, f"{address} is not valid ONE address")
raise InvalidValidatorError(
1,
f"{address} is not valid ONE address"
)
self._address = address
self._bls_keys = []
self._bls_key_sigs = []
@ -191,7 +193,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
name = self._sanitize_input( name )
if len( name ) > NAME_CHAR_LIMIT:
raise InvalidValidatorError(
3, f"Name must be less than {NAME_CHAR_LIMIT} characters"
3,
f"Name must be less than {NAME_CHAR_LIMIT} characters"
)
self._name = name
@ -221,7 +224,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
identity = self._sanitize_input( identity )
if len( identity ) > IDENTITY_CHAR_LIMIT:
raise InvalidValidatorError(
3, f"Identity must be less than {IDENTITY_CHAR_LIMIT} characters"
3,
f"Identity must be less than {IDENTITY_CHAR_LIMIT} characters"
)
self._identity = identity
@ -251,7 +255,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
website = self._sanitize_input( website )
if len( website ) > WEBSITE_CHAR_LIMIT:
raise InvalidValidatorError(
3, f"Website must be less than {WEBSITE_CHAR_LIMIT} characters"
3,
f"Website must be less than {WEBSITE_CHAR_LIMIT} characters"
)
self._website = website
@ -312,7 +317,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
details = self._sanitize_input( details )
if len( details ) > DETAILS_CHAR_LIMIT:
raise InvalidValidatorError(
3, f"Details must be less than {DETAILS_CHAR_LIMIT} characters"
3,
f"Details must be less than {DETAILS_CHAR_LIMIT} characters"
)
self._details = details
@ -344,7 +350,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
delegation = Decimal( delegation )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(
3, "Min self delegation must be a number"
3,
"Min self delegation must be a number"
) from exception
if delegation < MIN_REQUIRED_DELEGATION:
raise InvalidValidatorError(
@ -381,7 +388,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
max_delegation = Decimal( max_delegation )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(
3, "Max total delegation must be a number"
3,
"Max total delegation must be a number"
) from exception
if self._min_self_delegation:
if max_delegation < self._min_self_delegation:
@ -392,7 +400,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
)
else:
raise InvalidValidatorError(
4, "Min self delegation must be set before max total delegation"
4,
"Min self delegation must be set before max total delegation"
)
self._max_total_delegation = max_delegation
@ -423,7 +432,10 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
try:
amount = Decimal( amount )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(3, "Amount must be a number") from exception
raise InvalidValidatorError(
3,
"Amount must be a number"
) from exception
if self._min_self_delegation:
if amount < self._min_self_delegation:
raise InvalidValidatorError(
@ -433,7 +445,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
)
else:
raise InvalidValidatorError(
4, "Min self delegation must be set before amount"
4,
"Min self delegation must be set before amount"
)
if self._max_total_delegation:
if amount > self._max_total_delegation:
@ -444,7 +457,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
)
else:
raise InvalidValidatorError(
4, "Max total delegation must be set before amount"
4,
"Max total delegation must be set before amount"
)
self._inital_delegation = amount
@ -475,7 +489,10 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
try:
rate = Decimal( rate )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(3, "Max rate must be a number") from exception
raise InvalidValidatorError(
3,
"Max rate must be a number"
) from exception
if rate < 0 or rate > 1:
raise InvalidValidatorError( 3, "Max rate must be between 0 and 1" )
self._max_rate = rate
@ -507,10 +524,14 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
try:
rate = Decimal( rate )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(3, "Max change rate must be a number") from exception
raise InvalidValidatorError(
3,
"Max change rate must be a number"
) from exception
if rate < 0:
raise InvalidValidatorError(
3, "Max change rate must be greater than or equal to 0"
3,
"Max change rate must be greater than or equal to 0"
)
if self._max_rate:
if rate > self._max_rate:
@ -520,7 +541,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
)
else:
raise InvalidValidatorError(
4, "Max rate must be set before max change rate"
4,
"Max rate must be set before max change rate"
)
self._max_change_rate = rate
@ -551,13 +573,20 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
try:
rate = Decimal( rate )
except ( TypeError, InvalidOperation ) as exception:
raise InvalidValidatorError(3, "Rate must be a number") from exception
raise InvalidValidatorError(
3,
"Rate must be a number"
) from exception
if rate < 0:
raise InvalidValidatorError(3, "Rate must be greater than or equal to 0")
raise InvalidValidatorError(
3,
"Rate must be greater than or equal to 0"
)
if self._max_rate:
if rate > self._max_rate:
raise InvalidValidatorError(
3, f"Rate must be less than or equal to max rate: {self._max_rate}"
3,
f"Rate must be less than or equal to max rate: {self._max_rate}"
)
else:
raise InvalidValidatorError( 4, "Max rate must be set before rate" )
@ -574,7 +603,9 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
return self._rate
def does_validator_exist(
self, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
self,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
) -> bool:
"""Check if validator exists on blockchain.
@ -653,10 +684,15 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
for key in info[ "bls-key-sigs" ]:
self.add_bls_key_sig( key )
except KeyError as exception:
raise InvalidValidatorError(3, "Info has missing key") from exception
raise InvalidValidatorError(
3,
"Info has missing key"
) from exception
def load_from_blockchain(
self, endpoint=DEFAULT_ENDPOINT, timeout=DEFAULT_TIMEOUT
self,
endpoint = DEFAULT_ENDPOINT,
timeout = DEFAULT_TIMEOUT
):
"""Import validator information from blockchain with given address At
the moment, this is unable to fetch the BLS Signature, which is not
@ -677,17 +713,24 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
try:
if not self.does_validator_exist( endpoint, timeout ):
raise InvalidValidatorError(
5, f"Validator does not exist on chain according to {endpoint}"
5,
f"Validator does not exist on chain according to {endpoint}"
)
except ( RPCError, RequestsError, RequestsTimeoutError ) as exception:
raise InvalidValidatorError(
5, "Error requesting validator information"
5,
"Error requesting validator information"
) from exception
try:
validator_info = get_validator_information(self._address, endpoint, timeout)
validator_info = get_validator_information(
self._address,
endpoint,
timeout
)
except ( RPCError, RequestsError, RequestsTimeoutError ) as exception:
raise InvalidValidatorError(
5, "Error requesting validator information"
5,
"Error requesting validator information"
) from exception
# Skip additional sanity checks when importing from chain
@ -711,7 +754,8 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
self._bls_keys = info[ "bls-public-keys" ]
except KeyError as exception:
raise InvalidValidatorError(
5, "Error importing validator information from RPC result"
5,
"Error importing validator information from RPC result"
) from exception
def export( self ) -> dict:
@ -761,7 +805,9 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
"""
info = self.export().copy()
info[ "directive" ] = Directive.CreateValidator
info["validatorAddress"] = info.pop("validator-addr") # change the key
info[ "validatorAddress" ] = info.pop(
"validator-addr"
) # change the key
info[ "nonce" ] = nonce
info[ "gasPrice" ] = gas_price
info[ "gasLimit" ] = gas_limit
@ -802,7 +848,9 @@ class Validator: # pylint: disable=too-many-instance-attributes, too-many-public
self.remove_bls_key( bls_key_to_remove )
info = self.export().copy()
info[ "directive" ] = Directive.EditValidator
info["validatorAddress"] = info.pop("validator-addr") # change the key
info[ "validatorAddress" ] = info.pop(
"validator-addr"
) # change the key
info[ "nonce" ] = nonce
info[ "gasPrice" ] = gas_price
info[ "gasLimit" ] = gas_limit

@ -46,7 +46,8 @@ def test_bad_bin_set():
def test_bin_set():
cli.set_binary( BINARY_FILE_PATH )
cli_binary_path = cli.get_binary_path()
assert os.path.realpath(cli_binary_path) == os.path.realpath(BINARY_FILE_PATH)
assert os.path.realpath( cli_binary_path
) == os.path.realpath( BINARY_FILE_PATH )
def test_update_keystore():

@ -13,8 +13,15 @@ def setup():
timeout = 30
method = "hmyv2_getNodeMetadata"
params = []
payload = {"id": "1", "jsonrpc": "2.0", "method": method, "params": params}
headers = {"Content-Type": "application/json"}
payload = {
"id": "1",
"jsonrpc": "2.0",
"method": method,
"params": params
}
headers = {
"Content-Type": "application/json"
}
try:
response = requests.request(
@ -26,7 +33,10 @@ def setup():
allow_redirects = True,
)
except Exception as e:
pytest.skip("can not connect to local blockchain", allow_module_level=True)
pytest.skip(
"can not connect to local blockchain",
allow_module_level = True
)
def test_request_connection_error():
@ -42,7 +52,8 @@ def test_request_connection_error():
bad_request = None
try:
bad_request = request.rpc_request(
"hmyv2_getNodeMetadata", endpoint=bad_endpoint
"hmyv2_getNodeMetadata",
endpoint = bad_endpoint
)
except Exception as e:
assert isinstance( e, exceptions.RequestsError )
@ -54,7 +65,10 @@ def test_request_rpc_error():
try:
error_request = request.rpc_request( "hmyv2_getBalance" )
except ( exceptions.RequestsTimeoutError, exceptions.RequestsError ) as err:
pytest.skip("can not connect to local blockchain", allow_module_level=True)
pytest.skip(
"can not connect to local blockchain",
allow_module_level = True
)
except Exception as e:
assert isinstance( e, exceptions.RPCError )
assert error_request is None
@ -65,8 +79,15 @@ def test_rpc_request():
timeout = 30
method = "hmyv2_getNodeMetadata"
params = []
payload = {"id": "1", "jsonrpc": "2.0", "method": method, "params": params}
headers = {"Content-Type": "application/json"}
payload = {
"id": "1",
"jsonrpc": "2.0",
"method": method,
"params": params
}
headers = {
"Content-Type": "application/json"
}
response = None
try:

@ -11,7 +11,9 @@ import requests
endpoint = "http://localhost:9500"
timeout = 30
headers = {"Content-Type": "application/json"}
headers = {
"Content-Type": "application/json"
}
txs = [
# same shard 503 ONE transfer from one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3 to one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37 (0 nonce)
"0xf86f8085174876e8008252088080941f2213a52f7409ff4f103458e6d202e0b3aa805a891b4486fafde57c00008027a0d7c0b20207dcc9dde376822dc3f5625eac6f59a7526111695cdba3e29553ca17a05d4ca9a421ae16f89cbf6848186eaea7a800da732446dff9952e7c1e91d414e3",
@ -52,7 +54,8 @@ def setup_blockchain():
_send_transaction( tx, endpoint )
if not _wait_for_transaction_confirmed( tx_hash, endpoint ):
pytest.skip(
"Could not confirm initial transaction #{} on chain".format(i),
"Could not confirm initial transaction #{} on chain"
.format( i ),
allow_module_level = True,
)
@ -62,7 +65,8 @@ def setup_blockchain():
_send_staking_transaction( stx, endpoint )
if not _wait_for_staking_transaction_confirmed( stx_hash, endpoint ):
pytest.skip(
"Could not confirm initial staking transaction #{} on chain".format(i),
"Could not confirm initial staking transaction #{} on chain"
.format( i ),
allow_module_level = True,
)
@ -126,10 +130,14 @@ def _check_staking_epoch(metadata):
allow_module_level = True,
)
except Exception as e:
pytest.skip("Failed to get hmyv2_latestHeader reply", allow_module_level=True)
pytest.skip(
"Failed to get hmyv2_latestHeader reply",
allow_module_level = True
)
if metadata and latest_header:
staking_epoch = metadata["result"]["chain-config"]["staking-epoch"]
staking_epoch = metadata[ "result" ][ "chain-config" ][ "staking-epoch"
]
current_epoch = latest_header[ "result" ][ "epoch" ]
if staking_epoch > current_epoch:
pytest.skip(
@ -162,7 +170,8 @@ def _send_transaction(raw_tx, endpoint):
)
except Exception as e:
pytest.skip(
"Failed to get hmyv2_sendRawTransaction reply", allow_module_level=True
"Failed to get hmyv2_sendRawTransaction reply",
allow_module_level = True
)
@ -186,7 +195,8 @@ def _check_transaction(tx_hash, endpoint):
return tx_data
except Exception as e:
pytest.skip(
"Failed to get hmyv2_getTransactionByHash reply", allow_module_level=True
"Failed to get hmyv2_getTransactionByHash reply",
allow_module_level = True
)

@ -5,7 +5,6 @@ from pyhmy import account
from pyhmy.rpc import exceptions
explorer_endpoint = "http://localhost:9700"
endpoint_shard_one = "http://localhost:9502"
local_test_address = "one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3"
@ -22,8 +21,8 @@ def _test_account_rpc(fn, *args, **kwargs):
try:
response = fn( *args, **kwargs )
except Exception as e:
if isinstance(
e, exceptions.RPCError
if isinstance( e,
exceptions.RPCError
) and "does not exist/is not available" in str( e ):
pytest.skip( f"{str(e)}" )
pytest.fail( f"Unexpected error: {e.__class__} {e}" )
@ -38,7 +37,9 @@ def test_get_balance(setup_blockchain):
def test_get_balance_by_block( setup_blockchain ):
balance = _test_account_rpc(
account.get_balance_by_block, local_test_address, genesis_block_number
account.get_balance_by_block,
local_test_address,
genesis_block_number
)
assert isinstance( balance, int )
assert balance > 0
@ -56,7 +57,9 @@ def test_get_account_nonce(setup_blockchain):
def test_get_transaction_history( setup_blockchain ):
tx_history = _test_account_rpc(
account.get_transaction_history, local_test_address, endpoint=explorer_endpoint
account.get_transaction_history,
local_test_address,
endpoint = explorer_endpoint
)
assert isinstance( tx_history, list )
assert len( tx_history ) >= 0
@ -73,25 +76,38 @@ def test_get_staking_transaction_history(setup_blockchain):
def test_get_balance_on_all_shards( setup_blockchain ):
balances = _test_account_rpc(account.get_balance_on_all_shards, local_test_address)
balances = _test_account_rpc(
account.get_balance_on_all_shards,
local_test_address
)
assert isinstance( balances, list )
assert len( balances ) == 2
def test_get_total_balance( setup_blockchain ):
total_balance = _test_account_rpc(account.get_total_balance, local_test_address)
total_balance = _test_account_rpc(
account.get_total_balance,
local_test_address
)
assert isinstance( total_balance, int )
assert total_balance > 0
def test_is_valid_address():
assert account.is_valid_address("one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur")
assert not account.is_valid_address("one1wje75aedczmj4dwjs0812xcg7vx0dy231cajk0")
assert account.is_valid_address(
"one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur"
)
assert not account.is_valid_address(
"one1wje75aedczmj4dwjs0812xcg7vx0dy231cajk0"
)
def test_get_transaction_count( setup_blockchain ):
tx_count = _test_account_rpc(
account.get_transaction_count, local_test_address, "latest", explorer_endpoint
account.get_transaction_count,
local_test_address,
"latest",
explorer_endpoint
)
assert isinstance( tx_count, int )
assert tx_count > 0
@ -99,7 +115,10 @@ def test_get_transaction_count(setup_blockchain):
def test_get_transactions_count( setup_blockchain ):
tx_count = _test_account_rpc(
account.get_transactions_count, local_test_address, "ALL", explorer_endpoint
account.get_transactions_count,
local_test_address,
"ALL",
explorer_endpoint
)

@ -5,7 +5,6 @@ from pyhmy import blockchain
from pyhmy.rpc import exceptions
test_epoch_number = 0
genesis_block_number = 0
test_block_number = 1
@ -21,8 +20,8 @@ def _test_blockchain_rpc(fn, *args, **kwargs):
try:
response = fn( *args, **kwargs )
except Exception as e:
if isinstance(
e, exceptions.RPCError
if isinstance( e,
exceptions.RPCError
) and "does not exist/is not available" in str( e ):
pytest.skip( f"{str(e)}" )
pytest.fail( f"Unexpected error: {e.__class__} {e}" )
@ -35,7 +34,9 @@ def test_get_node_metadata(setup_blockchain):
def test_get_sharding_structure( setup_blockchain ):
sharding_structure = _test_blockchain_rpc(blockchain.get_sharding_structure)
sharding_structure = _test_blockchain_rpc(
blockchain.get_sharding_structure
)
assert isinstance( sharding_structure, list )
assert len( sharding_structure ) > 0
@ -78,7 +79,10 @@ def test_get_latest_chain_headers(setup_blockchain):
def test_get_block_by_number( setup_blockchain ):
global test_block_hash
block = _test_blockchain_rpc(blockchain.get_block_by_number, test_block_number)
block = _test_blockchain_rpc(
blockchain.get_block_by_number,
test_block_number
)
assert isinstance( block, dict )
assert "hash" in block.keys()
test_block_hash = block[ "hash" ]
@ -87,13 +91,17 @@ def test_get_block_by_number(setup_blockchain):
def test_get_block_by_hash( setup_blockchain ):
if not test_block_hash:
pytest.skip( "Failed to get reference block hash" )
block = _test_blockchain_rpc(blockchain.get_block_by_hash, test_block_hash)
block = _test_blockchain_rpc(
blockchain.get_block_by_hash,
test_block_hash
)
assert isinstance( block, dict )
def test_get_block_transaction_count_by_number( setup_blockchain ):
tx_count = _test_blockchain_rpc(
blockchain.get_block_transaction_count_by_number, test_block_number
blockchain.get_block_transaction_count_by_number,
test_block_number
)
assert isinstance( tx_count, int )
@ -102,14 +110,17 @@ def test_get_block_transaction_count_by_hash(setup_blockchain):
if not test_block_hash:
pytest.skip( "Failed to get reference block hash" )
tx_count = _test_blockchain_rpc(
blockchain.get_block_transaction_count_by_hash, test_block_hash
blockchain.get_block_transaction_count_by_hash,
test_block_hash
)
assert isinstance( tx_count, int )
def test_get_blocks( setup_blockchain ):
blocks = _test_blockchain_rpc(
blockchain.get_blocks, genesis_block_number, test_block_number
blockchain.get_blocks,
genesis_block_number,
test_block_number
)
assert isinstance( blocks, list )
assert len( blocks ) == ( test_block_number - genesis_block_number + 1 )
@ -117,14 +128,18 @@ def test_get_blocks(setup_blockchain):
def test_get_block_signers( setup_blockchain ):
block_signers = _test_blockchain_rpc(
blockchain.get_block_signers, test_block_number
blockchain.get_block_signers,
test_block_number
)
assert isinstance( block_signers, list )
assert len( block_signers ) > 0
def test_get_validators( setup_blockchain ):
validators = _test_blockchain_rpc(blockchain.get_validators, test_epoch_number)
validators = _test_blockchain_rpc(
blockchain.get_validators,
test_epoch_number
)
assert isinstance( validators, dict )
assert "validators" in validators.keys()
assert len( validators[ "validators" ] ) > 0
@ -154,13 +169,19 @@ def test_get_bad_blocks(setup_blockchain):
def test_get_validator_keys( setup_blockchain ):
keys = _test_blockchain_rpc(blockchain.get_validator_keys, test_epoch_number)
keys = _test_blockchain_rpc(
blockchain.get_validator_keys,
test_epoch_number
)
assert isinstance( keys, list )
assert len( keys ) > 0
def test_get_block_signers_keys( setup_blockchain ):
keys = _test_blockchain_rpc(blockchain.get_block_signers_keys, test_block_number)
keys = _test_blockchain_rpc(
blockchain.get_block_signers_keys,
test_block_number
)
assert isinstance( keys, list )
assert len( keys ) > 0
@ -192,7 +213,9 @@ def test_epoch_last_block(setup_blockchain):
def test_get_circulating_supply( setup_blockchain ):
circulating_supply = _test_blockchain_rpc(blockchain.get_circulating_supply)
circulating_supply = _test_blockchain_rpc(
blockchain.get_circulating_supply
)
assert isinstance( circulating_supply, str )
@ -223,7 +246,8 @@ def test_get_header_by_number(setup_blockchain):
def test_get_block_staking_transaction_count_by_number( setup_blockchain ):
tx_count = _test_blockchain_rpc(
blockchain.get_block_staking_transaction_count_by_number, test_block_number
blockchain.get_block_staking_transaction_count_by_number,
test_block_number
)
assert isinstance( tx_count, int )
@ -232,20 +256,26 @@ def test_get_block_staking_transaction_count_by_hash(setup_blockchain):
if not test_block_hash:
pytest.skip( "Failed to get reference block hash" )
tx_count = _test_blockchain_rpc(
blockchain.get_block_staking_transaction_count_by_hash, test_block_hash
blockchain.get_block_staking_transaction_count_by_hash,
test_block_hash
)
assert isinstance( tx_count, int )
def test_is_block_signer( setup_blockchain ):
is_signer = _test_blockchain_rpc(
blockchain.is_block_signer, test_block_number, address
blockchain.is_block_signer,
test_block_number,
address
)
assert isinstance( is_signer, bool )
def test_get_signed_blocks( setup_blockchain ):
signed_blocks = _test_blockchain_rpc(blockchain.get_signed_blocks, address)
signed_blocks = _test_blockchain_rpc(
blockchain.get_signed_blocks,
address
)
assert isinstance( signed_blocks, int )
@ -313,7 +343,10 @@ def test_errors():
with pytest.raises( exceptions.RPCError ):
blockchain.get_block_transaction_count_by_hash( "", fake_shard )
with pytest.raises( exceptions.RPCError ):
blockchain.get_block_staking_transaction_count_by_number(0, fake_shard)
blockchain.get_block_staking_transaction_count_by_number(
0,
fake_shard
)
with pytest.raises( exceptions.RPCError ):
blockchain.get_block_staking_transaction_count_by_hash( "", fake_shard )
with pytest.raises( exceptions.RPCError ):

@ -19,11 +19,13 @@ def _test_contract_rpc(fn, *args, **kwargs):
try:
response = fn( *args, **kwargs )
except Exception as e:
if isinstance(
e, exceptions.RPCError
if isinstance( e,
exceptions.RPCError
) and "does not exist/is not available" in str( e ):
pytest.skip( f"{str(e)}" )
elif isinstance(e, exceptions.RPCError) and "estimateGas returned" in str(e):
elif isinstance( e,
exceptions.RPCError
) and "estimateGas returned" in str( e ):
pytest.skip( f"{str(e)}" )
pytest.fail( f"Unexpected error: {e.__class__} {e}" )
return response
@ -32,7 +34,8 @@ def _test_contract_rpc(fn, *args, **kwargs):
def test_get_contract_address_from_hash( setup_blockchain ):
global contract_address
contract_address = _test_contract_rpc(
contract.get_contract_address_from_hash, contract_tx_hash
contract.get_contract_address_from_hash,
contract_tx_hash
)
assert isinstance( contract_address, str )
@ -62,7 +65,10 @@ def test_get_storage_at(setup_blockchain):
if not contract_address:
pytest.skip( "Contract address not loaded yet" )
storage = _test_contract_rpc(
contract.get_storage_at, contract_address, "0x0", "latest"
contract.get_storage_at,
contract_address,
"0x0",
"latest"
)
assert isinstance( storage, str ) and storage.startswith( "0x" )

@ -1,5 +1,4 @@
from pyhmy import signing
"""
Test signature source (node.js)
import { Transaction, RLPSign, TxStatus } from '@harmony-js/transaction';
@ -43,8 +42,8 @@ def test_eth_transaction():
"4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
)
assert (
signed_tx.rawTransaction.hex()
== "0xf85d0201649414791697260e4c9a71f18484c9f997b308e5932505801ca0b364f4296bfd3231889d1b9ac94c68abbcb8ee6a6c7a5fa412ac82b5b7b0d5d1a02233864842ab28ee4f99c207940a867b0f8534ca362836190792816b48dde3b1"
signed_tx.rawTransaction.hex() ==
"0xf85d0201649414791697260e4c9a71f18484c9f997b308e5932505801ca0b364f4296bfd3231889d1b9ac94c68abbcb8ee6a6c7a5fa412ac82b5b7b0d5d1a02233864842ab28ee4f99c207940a867b0f8534ca362836190792816b48dde3b1"
)
@ -96,6 +95,6 @@ def test_hmy_transaction():
"4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
)
assert (
signed_tx.rawTransaction.hex()
== "0xf85f02016480019414791697260e4c9a71f18484c9f997b308e59325058026a02a203357ca6d7cdec981ad3d3692ad2c9e24536a9b6e7b486ce2f94f28c7563ea010d38cd0312a153af0aa7d8cd986040c36118bba373cb94e3e86fd4aedce904d"
signed_tx.rawTransaction.hex() ==
"0xf85f02016480019414791697260e4c9a71f18484c9f997b308e59325058026a02a203357ca6d7cdec981ad3d3692ad2c9e24536a9b6e7b486ce2f94f28c7563ea010d38cd0312a153af0aa7d8cd986040c36118bba373cb94e3e86fd4aedce904d"
)

@ -5,7 +5,6 @@ from pyhmy import staking
from pyhmy.rpc import exceptions
explorer_endpoint = "http://localhost:9700"
test_validator_address = "one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3"
fake_shard = "http://example.com"
@ -18,8 +17,8 @@ def _test_staking_rpc(fn, *args, **kwargs):
try:
response = fn( *args, **kwargs )
except Exception as e:
if isinstance(
e, exceptions.RPCError
if isinstance( e,
exceptions.RPCError
) and "does not exist/is not available" in str( e ):
pytest.skip( f"{str(e)}" )
pytest.fail( f"Unexpected error: {e.__class__} {e}" )
@ -27,26 +26,34 @@ def _test_staking_rpc(fn, *args, **kwargs):
def test_get_all_validator_addresses( setup_blockchain ):
validator_addresses = _test_staking_rpc(staking.get_all_validator_addresses)
validator_addresses = _test_staking_rpc(
staking.get_all_validator_addresses
)
assert isinstance( validator_addresses, list )
assert len( validator_addresses ) > 0
assert test_validator_address in validator_addresses
def test_get_validator_information( setup_blockchain ):
info = _test_staking_rpc(staking.get_validator_information, test_validator_address)
info = _test_staking_rpc(
staking.get_validator_information,
test_validator_address
)
assert isinstance( info, dict )
def test_get_all_validator_information( setup_blockchain ):
all_validator_information = _test_staking_rpc(staking.get_all_validator_information)
all_validator_information = _test_staking_rpc(
staking.get_all_validator_information
)
assert isinstance( all_validator_information, list )
assert len( all_validator_information ) > 0
def test_get_delegations_by_delegator( setup_blockchain ):
delegations = _test_staking_rpc(
staking.get_delegations_by_delegator, test_validator_address
staking.get_delegations_by_delegator,
test_validator_address
)
assert isinstance( delegations, list )
assert len( delegations ) > 0
@ -54,7 +61,8 @@ def test_get_delegations_by_delegator(setup_blockchain):
def test_get_delegations_by_validator( setup_blockchain ):
delegations = _test_staking_rpc(
staking.get_delegations_by_validator, test_validator_address
staking.get_delegations_by_validator,
test_validator_address
)
assert isinstance( delegations, list )
assert len( delegations ) > 0
@ -112,7 +120,9 @@ def test_get_delegations_by_delegator_by_block(setup_blockchain):
def test_get_elected_validator_addresses( setup_blockchain ):
validator_addresses = _test_staking_rpc(staking.get_elected_validator_addresses)
validator_addresses = _test_staking_rpc(
staking.get_elected_validator_addresses
)
assert isinstance( validator_addresses, list )
assert len( validator_addresses ) > 0
@ -130,7 +140,8 @@ def test_get_validator_keys(setup_blockchain):
def test_get_validator_self_delegation( setup_blockchain ):
self_delegation = _test_staking_rpc(
staking.get_validator_self_delegation, test_validator_address
staking.get_validator_self_delegation,
test_validator_address
)
assert isinstance( self_delegation, int )
assert self_delegation > 0
@ -138,7 +149,8 @@ def test_get_validator_self_delegation(setup_blockchain):
def test_get_validator_total_delegation( setup_blockchain ):
total_delegation = _test_staking_rpc(
staking.get_validator_total_delegation, test_validator_address
staking.get_validator_total_delegation,
test_validator_address
)
assert isinstance( total_delegation, int )
assert total_delegation > 0
@ -146,7 +158,8 @@ def test_get_validator_total_delegation(setup_blockchain):
def test_get_all_delegation_information( setup_blockchain ):
delegation_information = _test_staking_rpc(
staking.get_all_delegation_information, 0
staking.get_all_delegation_information,
0
)
assert isinstance( delegation_information, list )
assert len( delegation_information ) > 0
@ -163,7 +176,8 @@ def test_get_delegation_by_delegator_and_validator(setup_blockchain):
def test_get_available_redelegation_balance( setup_blockchain ):
redelgation_balance = _test_staking_rpc(
staking.get_available_redelegation_balance, test_validator_address
staking.get_available_redelegation_balance,
test_validator_address
)
assert isinstance( redelgation_balance, int )
assert redelgation_balance == 0
@ -173,10 +187,10 @@ def test_get_total_staking(setup_blockchain):
total_staking = _test_staking_rpc( staking.get_total_staking )
assert isinstance( total_staking, int )
if (
staking.get_validator_information(test_validator_address, explorer_endpoint)[
"active-status"
]
== "active"
staking.get_validator_information(
test_validator_address,
explorer_endpoint
)[ "active-status" ] == "active"
):
assert total_staking > 0
@ -201,13 +215,21 @@ def test_errors():
with pytest.raises( exceptions.RPCError ):
staking.get_validator_total_delegation( "", fake_shard )
with pytest.raises( exceptions.RPCError ):
staking.get_all_validator_information_by_block_number(1, 1, fake_shard)
staking.get_all_validator_information_by_block_number(
1,
1,
fake_shard
)
with pytest.raises( exceptions.RPCError ):
staking.get_all_delegation_information( 1, fake_shard )
with pytest.raises( exceptions.RPCError ):
staking.get_delegations_by_delegator( "", fake_shard )
with pytest.raises( exceptions.RPCError ):
staking.get_delegations_by_delegator_by_block_number("", 1, fake_shard)
staking.get_delegations_by_delegator_by_block_number(
"",
1,
fake_shard
)
with pytest.raises( exceptions.RPCError ):
staking.get_delegation_by_delegator_and_validator( "", "", fake_shard )
with pytest.raises( exceptions.RPCError ):

@ -5,7 +5,6 @@ from pyhmy.numbers import convert_one_to_atto
# other transactions (create/edit validator) are in test_validator.py
# test_delegate is the same as test_undelegate (except the directive) so it has been omitted
# staking transactions without a chain id have been omitted as well, since the node does not accept them anyway
"""
let stakingTx
let stakeMsg3: CollectRewards = new CollectRewards(
@ -33,7 +32,6 @@ console.log(signed)
# }
# signed_tx = staking_signing.sign_staking_transaction(transaction_dict, '4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48')
# assert signed_tx.rawTransaction.hex() == '0xf85a04d594ebcd16e8c1d8f493ba04e99a56474122d81a9c5823a0490e4ceb747563ba40da3e0db8a65133cf6f6ae4c48a24866cd6aa1f0d6c2414a06dbd51a67b35b5685e7b7420cba26e63b0e7d3c696fc6cb69d48e54fcad280e9'
"""
let stakingTx
let stakeMsg3: CollectRewards = new CollectRewards(
@ -67,8 +65,8 @@ def test_collect_rewards_chain_id():
"4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
)
assert (
signed_tx.rawTransaction.hex()
== "0xf86504d594ebcd16e8c1d8f493ba04e99a56474122d81a9c5802880de0b6b3a76400006425a055d6c3c0d8e7a1e75152db361a2ed47f5ab54f6f19b0d8e549953dbdf13ba647a076e1367dfca38eae3bd0e8da296335acabbaeb87dc17e47ebe4942db29334099"
signed_tx.rawTransaction.hex() ==
"0xf86504d594ebcd16e8c1d8f493ba04e99a56474122d81a9c5802880de0b6b3a76400006425a055d6c3c0d8e7a1e75152db361a2ed47f5ab54f6f19b0d8e549953dbdf13ba647a076e1367dfca38eae3bd0e8da296335acabbaeb87dc17e47ebe4942db29334099"
)
@ -109,6 +107,6 @@ def test_delegate():
"4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48",
)
assert (
signed_tx.rawTransaction.hex()
== "0xf87b02eb94ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c580502880de0b6b3a76400006428a0c856fd483a989ca4db4b5257f6996729527828fb21ec13cc65f0bffe6c015ab1a05e9d3c92742e8cb7450bebdfb7ad277ccbfc9fa0719db0b12a715a0a173cadd6"
signed_tx.rawTransaction.hex() ==
"0xf87b02eb94ebcd16e8c1d8f493ba04e99a56474122d81a9c5894ebcd16e8c1d8f493ba04e99a56474122d81a9c580502880de0b6b3a76400006428a0c856fd483a989ca4db4b5257f6996729527828fb21ec13cc65f0bffe6c015ab1a05e9d3c92742e8cb7450bebdfb7ad277ccbfc9fa0719db0b12a715a0a173cadd6"
)

@ -4,7 +4,6 @@ from pyhmy import transaction
from pyhmy.rpc import exceptions
endpoint = "http://localhost:9500"
endpoint_shard_one = "http://localhost:9502"
fake_shard = "http://example.com"
@ -37,8 +36,8 @@ def _test_transaction_rpc(fn, *args, **kwargs):
try:
response = fn( *args, **kwargs )
except Exception as e:
if isinstance(
e, exceptions.RPCError
if isinstance( e,
exceptions.RPCError
) and "does not exist/is not available" in str( e ):
pytest.skip( f"{str(e)}" )
pytest.fail( f"Unexpected error: {e.__class__} {e}" )
@ -52,7 +51,9 @@ def test_get_pending_transactions(setup_blockchain):
def test_get_transaction_by_hash( setup_blockchain ):
tx = _test_transaction_rpc(
transaction.get_transaction_by_hash, tx_hash, endpoint=endpoint
transaction.get_transaction_by_hash,
tx_hash,
endpoint = endpoint
)
assert tx
assert isinstance( tx, dict )
@ -94,7 +95,9 @@ def test_get_transaction_by_block_number_and_index(setup_blockchain):
def test_get_transaction_receipt( setup_blockchain ):
tx_receipt = _test_transaction_rpc(
transaction.get_transaction_receipt, tx_hash, endpoint=endpoint
transaction.get_transaction_receipt,
tx_hash,
endpoint = endpoint
)
assert tx_receipt
assert isinstance( tx_receipt, dict )
@ -108,7 +111,8 @@ def test_get_transaction_error_sink(setup_blockchain):
def test_send_and_confirm_raw_transaction( setup_blockchain ):
# Note: this test is not yet idempotent since the localnet will reject transactions which were previously finalized.
test_tx = _test_transaction_rpc(
transaction.send_and_confirm_raw_transaction, raw_tx
transaction.send_and_confirm_raw_transaction,
raw_tx
)
assert isinstance( test_tx, dict )
assert test_tx[ "hash" ] == raw_tx_hash
@ -121,7 +125,9 @@ def test_get_pending_cx_receipts(setup_blockchain):
def test_get_cx_receipt_by_hash( setup_blockchain ):
cx = _test_transaction_rpc(
transaction.get_cx_receipt_by_hash, cx_hash, endpoint_shard_one
transaction.get_cx_receipt_by_hash,
cx_hash,
endpoint_shard_one
)
assert cx
assert isinstance( cx, dict )
@ -135,7 +141,8 @@ def test_resend_cx_receipt(setup_blockchain):
def test_get_staking_transaction_by_hash( setup_blockchain ):
staking_tx = _test_transaction_rpc(
transaction.get_staking_transaction_by_hash, stx_hash
transaction.get_staking_transaction_by_hash,
stx_hash
)
assert staking_tx
assert isinstance( staking_tx, dict )
@ -174,13 +181,17 @@ def test_get_transaction_by_block_number_and_index(setup_blockchain):
def test_get_staking_transaction_error_sink( setup_blockchain ):
errors = _test_transaction_rpc(transaction.get_staking_transaction_error_sink)
errors = _test_transaction_rpc(
transaction.get_staking_transaction_error_sink
)
assert isinstance( errors, list )
def test_send_raw_staking_transaction( setup_blockchain ):
test_stx = _test_transaction_rpc(
transaction.send_and_confirm_raw_staking_transaction, raw_stx, endpoint=endpoint
transaction.send_and_confirm_raw_staking_transaction,
raw_stx,
endpoint = endpoint
)
assert isinstance( test_stx, dict )
assert test_stx[ "hash" ] == raw_stx_hash
@ -188,14 +199,16 @@ def test_send_raw_staking_transaction(setup_blockchain):
def test_get_pool_stats( setup_blockchain ):
test_pool_stats = _test_transaction_rpc(
transaction.get_pool_stats, endpoint=endpoint
transaction.get_pool_stats,
endpoint = endpoint
)
assert isinstance( test_pool_stats, dict )
def test_get_pending_staking_transactions( setup_blockchain ):
pending_staking_transactions = _test_transaction_rpc(
transaction.get_pending_staking_transactions, endpoint=endpoint
transaction.get_pending_staking_transactions,
endpoint = endpoint
)
assert isinstance( pending_staking_transactions, list )
@ -210,9 +223,17 @@ def test_errors():
with pytest.raises( exceptions.RPCError ):
transaction.get_transaction_by_hash( "", endpoint = fake_shard )
with pytest.raises( exceptions.RPCError ):
transaction.get_transaction_by_block_hash_and_index("", 1, endpoint=fake_shard)
transaction.get_transaction_by_block_hash_and_index(
"",
1,
endpoint = fake_shard
)
with pytest.raises( exceptions.RPCError ):
transaction.get_transaction_by_block_number_and_index(1, 1, endpoint=fake_shard)
transaction.get_transaction_by_block_number_and_index(
1,
1,
endpoint = fake_shard
)
with pytest.raises( exceptions.RPCError ):
transaction.get_transaction_receipt( "", endpoint = fake_shard )
with pytest.raises( exceptions.RPCError ):
@ -227,11 +248,15 @@ def test_errors():
transaction.get_staking_transaction_by_hash( "", endpoint = fake_shard )
with pytest.raises( exceptions.RPCError ):
transaction.get_staking_transaction_by_block_hash_and_index(
"", 1, endpoint=fake_shard
"",
1,
endpoint = fake_shard
)
with pytest.raises( exceptions.RPCError ):
transaction.get_staking_transaction_by_block_number_and_index(
1, 1, endpoint=fake_shard
1,
1,
endpoint = fake_shard
)
with pytest.raises( exceptions.RPCError ):
transaction.get_staking_transaction_error_sink( endpoint = fake_shard )

@ -89,8 +89,8 @@ def test_create_validator_sign(setup_blockchain):
2,
).rawTransaction.hex()
assert (
signed_hash
== "0xf9017580f9012394ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121dcc8872386f26fc10000c9880c7d713b49da0000c887b1a2bc2ec500008a021e19e0c9bab24000008a0878678326eac9000000f1b030b2c38b1316da91e068ac3bd8751c0901ef6c02a1d58bc712104918302c6ed03d5894671d0c816dad2b4d303320f202f862b86068f800b6adf657b674903e04708060912b893b7c7b500788808247550ab3e186e56a44ebf3ca488f8ed1a42f6cef3a04bd5d2b2b7eb5a767848d3135b362e668ce6bba42c7b9d5666d8e3a83be707b5708e722c58939fe9b07c170f3b70624148a021e27c1806e59a4000002880de0b6b3a76400006428a0c6c7e62f02331df0afd4699ec514a2fc4548c920d77ad74d98caeec8c924c09aa02b27b999a724b1d341d6bbb0e877611d0047542cb7e380f9a6a272d204b450cd"
signed_hash ==
"0xf9017580f9012394ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121dcc8872386f26fc10000c9880c7d713b49da0000c887b1a2bc2ec500008a021e19e0c9bab24000008a0878678326eac9000000f1b030b2c38b1316da91e068ac3bd8751c0901ef6c02a1d58bc712104918302c6ed03d5894671d0c816dad2b4d303320f202f862b86068f800b6adf657b674903e04708060912b893b7c7b500788808247550ab3e186e56a44ebf3ca488f8ed1a42f6cef3a04bd5d2b2b7eb5a767848d3135b362e668ce6bba42c7b9d5666d8e3a83be707b5708e722c58939fe9b07c170f3b70624148a021e27c1806e59a4000002880de0b6b3a76400006428a0c6c7e62f02331df0afd4699ec514a2fc4548c920d77ad74d98caeec8c924c09aa02b27b999a724b1d341d6bbb0e877611d0047542cb7e380f9a6a272d204b450cd"
)
@ -152,8 +152,8 @@ def test_edit_validator_sign(setup_blockchain):
2,
).rawTransaction.hex()
assert (
signed_hash
== "0xf9012101f8d094ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c887d529ae9e8600008a021e19e0c9bab24000008a0878678326eac9000000b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608612b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861102880de0b6b3a76400006428a0782ed9f909b5c68eb050a917a274d9187a4c8f13799f21ba351bdcb11290c6c7a00a3b4ec8431290565acbbbb8231cafe32ed7c0b6211e7cf570b459cb733e0995"
signed_hash ==
"0xf9012101f8d094ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c887d529ae9e8600008a021e19e0c9bab24000008a0878678326eac9000000b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608612b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861102880de0b6b3a76400006428a0782ed9f909b5c68eb050a917a274d9187a4c8f13799f21ba351bdcb11290c6c7a00a3b4ec8431290565acbbbb8231cafe32ed7c0b6211e7cf570b459cb733e0995"
)
@ -193,8 +193,8 @@ def test_validator_getters(setup_blockchain):
if not ( test_validator_object or test_validator_loaded ):
pytest.skip( "Validator not instantiated yet" )
assert (
test_validator_object.get_address()
== "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9"
test_validator_object.get_address() ==
"one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9"
)
assert test_validator_object.add_bls_key( "5" )
assert test_validator_object.remove_bls_key( "5" )
@ -203,8 +203,14 @@ def test_validator_getters(setup_blockchain):
assert test_validator_object.get_website() == "alice.harmony.one"
assert test_validator_object.get_security_contact() == "Bob"
assert test_validator_object.get_details() == "Don't mess with me!!!"
assert isinstance(test_validator_object.get_min_self_delegation(), Decimal)
assert isinstance(test_validator_object.get_max_total_delegation(), Decimal)
assert isinstance(
test_validator_object.get_min_self_delegation(),
Decimal
)
assert isinstance(
test_validator_object.get_max_total_delegation(),
Decimal
)
assert isinstance( test_validator_object.get_amount(), Decimal )
assert isinstance( test_validator_object.get_max_rate(), Decimal )
assert isinstance( test_validator_object.get_max_change_rate(), Decimal )

@ -22,7 +22,12 @@ def test_json_load():
dec = util.json_load( "1.1", parse_float = decimal.Decimal )
assert isinstance( dec, decimal.Decimal )
assert float( dec ) == 1.1
ref_dict = {"test": "val", "arr": [1, 2, 3]}
ref_dict = {
"test": "val",
"arr": [ 1,
2,
3 ]
}
loaded_dict = util.json_load( json.dumps( ref_dict ) )
assert str( ref_dict ) == str( loaded_dict )

Loading…
Cancel
Save