Merge pull request #35 from MaxMustermann2/validator-sigs
add `hex_to_one`, fix `bech32` installation, bug fixpull/36/head
commit
d12bde7328
@ -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 |
||||
|
@ -1,11 +1,9 @@ |
||||
""" |
||||
Provides pyhmy version information. |
||||
""" |
||||
"""Provides pyhmy version information.""" |
||||
|
||||
# This file is auto-generated! Do not edit! |
||||
# Use `python -m incremental.update pyhmy` to change this file. |
||||
|
||||
from incremental import Version |
||||
|
||||
__version__ = Version('pyhmy', 20, 5, 20) |
||||
__version__ = Version( "pyhmy", 20, 5, 20 ) |
||||
__all__ = [ "__version__" ] |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,18 @@ |
||||
""" |
||||
Constants |
||||
""" |
||||
|
||||
# localnet constants |
||||
DEFAULT_ENDPOINT = 'http://localhost:9500' |
||||
DEFAULT_TIMEOUT = 30 |
||||
|
||||
# staking percentage constants |
||||
PRECISION = 18 |
||||
MAX_DECIMAL = 1000000000000000000 |
||||
|
||||
NAME_CHAR_LIMIT = 140 |
||||
IDENTITY_CHAR_LIMIT = 140 |
||||
WEBSITE_CHAR_LIMIT = 140 |
||||
SECURITY_CONTACT_CHAR_LIMIT = 140 |
||||
DETAILS_CHAR_LIMIT = 280 |
||||
MIN_REQUIRED_DELEGATION = int( 10000 * 1e18 ) |
@ -1,27 +1,26 @@ |
||||
""" |
||||
RPC Specific Exceptions |
||||
""" |
||||
|
||||
import requests |
||||
|
||||
|
||||
class RPCError( RuntimeError ): |
||||
""" |
||||
Exception raised when RPC call returns an error |
||||
""" |
||||
|
||||
"""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 |
||||
""" |
||||
|
||||
class RequestsError( requests.exceptions.RequestException ): |
||||
"""Wrapper for requests lib exceptions.""" |
||||
def __init__( self, endpoint ): |
||||
super().__init__(f'Error connecting to {endpoint}') |
||||
super().__init__( f"Error connecting to {endpoint}" ) |
||||
|
||||
class RequestsTimeoutError(requests.exceptions.Timeout): |
||||
""" |
||||
Wrapper for requests lib Timeout exceptions |
||||
""" |
||||
|
||||
class RequestsTimeoutError( requests.exceptions.Timeout ): |
||||
"""Wrapper for requests lib Timeout exceptions.""" |
||||
def __init__( self, endpoint ): |
||||
super().__init__(f'Error connecting to {endpoint}') |
||||
super().__init__( f"Error connecting to {endpoint}" ) |
||||
|
@ -1,218 +1,325 @@ |
||||
from enum import ( |
||||
Enum, |
||||
auto |
||||
) |
||||
""" |
||||
Helper module for signing Harmony staking transactions |
||||
""" |
||||
# disable most of the Lint here |
||||
# pylint: disable=protected-access,no-member,invalid-name,missing-class-docstring,missing-function-docstring |
||||
|
||||
from rlp.sedes import ( |
||||
big_endian_int, |
||||
Binary, |
||||
CountableList, |
||||
List, |
||||
Text |
||||
) |
||||
from enum import Enum, auto |
||||
|
||||
from eth_rlp import ( |
||||
HashableRLP |
||||
) |
||||
from rlp.sedes import big_endian_int, Binary, CountableList, List, Text |
||||
|
||||
from eth_utils.curried import ( |
||||
to_int, |
||||
hexstr_if_str, |
||||
) |
||||
from eth_rlp import HashableRLP |
||||
|
||||
from eth_utils.curried import ( to_int, hexstr_if_str, ) |
||||
|
||||
class StakingSettings: |
||||
PRECISION = 18 |
||||
MAX_DECIMAL = 1000000000000000000 |
||||
|
||||
class Directive(Enum): # https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L120 |
||||
def _generate_next_value_(name, start, count, last_values): |
||||
# https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L120 |
||||
class Directive( Enum ): |
||||
def _generate_next_value_( name, start, count, last_values ): # pylint: disable=no-self-argument |
||||
return count |
||||
|
||||
CreateValidator = auto() |
||||
EditValidator = auto() |
||||
Delegate = auto() |
||||
Undelegate = auto() |
||||
CollectRewards = auto() |
||||
|
||||
|
||||
FORMATTERS = { |
||||
'directive': hexstr_if_str(to_int), # delegatorAddress is already formatted before the call |
||||
'nonce': hexstr_if_str(to_int), |
||||
'gasPrice': hexstr_if_str(to_int), |
||||
'gasLimit': hexstr_if_str(to_int), |
||||
'chainId': hexstr_if_str(to_int), |
||||
"directive": hexstr_if_str( |
||||
to_int |
||||
), # delegatorAddress is already formatted before the call |
||||
"nonce": hexstr_if_str(to_int), |
||||
"gasPrice": hexstr_if_str(to_int), |
||||
"gasLimit": hexstr_if_str(to_int), |
||||
"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 |
||||
|
||||
@staticmethod |
||||
def SignedChainId(): |
||||
class SignedChainId( HashableRLP ): |
||||
fields = CollectRewards.UnsignedChainId()._meta.fields[:-1] + ( # drop chainId |
||||
fields = CollectRewards.UnsignedChainId()._meta.fields[ |
||||
:-1 |
||||
] + ( # drop chainId |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return SignedChainId |
||||
|
||||
@staticmethod |
||||
def Unsigned(): |
||||
class Unsigned( HashableRLP ): |
||||
fields = CollectRewards.UnsignedChainId()._meta.fields[:-1] # drop chainId |
||||
fields = CollectRewards.UnsignedChainId( |
||||
)._meta.fields[ :-1 ] # drop chainId |
||||
|
||||
return Unsigned |
||||
|
||||
@staticmethod |
||||
def Signed(): |
||||
class Signed( HashableRLP ): |
||||
fields = CollectRewards.Unsigned()._meta.fields[:-3] + ( # drop last 3 for raw.pop() |
||||
fields = CollectRewards.Unsigned()._meta.fields[ |
||||
:-3 |
||||
] + ( # drop last 3 for raw.pop() |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return Signed |
||||
|
||||
|
||||
class DelegateOrUndelegate: |
||||
@staticmethod |
||||
def UnsignedChainId(): |
||||
class UnsignedChainId( HashableRLP ): |
||||
fields = ( |
||||
('directive', big_endian_int), |
||||
('stakeMsg', List([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), |
||||
( "directive", |
||||
big_endian_int ), |
||||
( |
||||
"stakeMsg", |
||||
List( |
||||
[ |
||||
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 ), |
||||
) |
||||
|
||||
return UnsignedChainId |
||||
|
||||
@staticmethod |
||||
def SignedChainId(): |
||||
class SignedChainId( HashableRLP ): |
||||
fields = DelegateOrUndelegate.UnsignedChainId()._meta.fields[:-1] + ( # drop chainId |
||||
fields = DelegateOrUndelegate.UnsignedChainId()._meta.fields[ |
||||
:-1 |
||||
] + ( # drop chainId |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return SignedChainId |
||||
|
||||
@staticmethod |
||||
def Unsigned(): |
||||
class Unsigned( HashableRLP ): |
||||
fields = DelegateOrUndelegate.UnsignedChainId()._meta.fields[:-1] # drop chainId |
||||
fields = DelegateOrUndelegate.UnsignedChainId( |
||||
)._meta.fields[ :-1 ] # drop chainId |
||||
|
||||
return Unsigned |
||||
|
||||
@staticmethod |
||||
def Signed(): |
||||
class Signed( HashableRLP ): |
||||
fields = DelegateOrUndelegate.Unsigned()._meta.fields[:-3] + ( # drop last 3 for raw.pop() |
||||
fields = DelegateOrUndelegate.Unsigned()._meta.fields[ |
||||
:-3 |
||||
] + ( # drop last 3 for raw.pop() |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return Signed |
||||
|
||||
|
||||
class CreateValidator: |
||||
@staticmethod |
||||
def UnsignedChainId(): |
||||
class UnsignedChainId( HashableRLP ): |
||||
fields = ( |
||||
('directive', big_endian_int), |
||||
('stakeMsg', List([ # list with the following members |
||||
Binary.fixed_length(20, allow_empty=True), # validatorAddress |
||||
List([Text()]*5,True), # description is Text of 5 elements |
||||
List([List([big_endian_int],True)]*3,True), # commission rate is made up of 3 integers in an array [ [int1], [int2], [int3] ] |
||||
("directive", big_endian_int), |
||||
( |
||||
"stakeMsg", |
||||
List( |
||||
[ # list with the following members |
||||
# validatorAddress |
||||
Binary.fixed_length( |
||||
20, allow_empty=True |
||||
), |
||||
# description is Text of 5 elements |
||||
List( |
||||
[Text()] * 5, True |
||||
), |
||||
# commission rate is made up of 3 integers in an array |
||||
List( |
||||
[List([big_endian_int], True)] * 3, True |
||||
), |
||||
big_endian_int, # min self delegation |
||||
big_endian_int, # max total delegation |
||||
CountableList(Binary.fixed_length(48, allow_empty=True)), # bls-public-keys array of unspecified length, each key of 48 |
||||
# bls-public-keys array of unspecified length, each key of 48 |
||||
CountableList( |
||||
Binary.fixed_length(48, allow_empty=True) |
||||
), |
||||
# bls-key-sigs array of unspecified length, each sig of 96 |
||||
CountableList( |
||||
Binary.fixed_length(96, allow_empty=True) |
||||
), |
||||
big_endian_int, # amount |
||||
], True)), # strictly these number of elements |
||||
('nonce', big_endian_int), |
||||
('gasPrice', big_endian_int), |
||||
('gasLimit', big_endian_int), |
||||
('chainId', big_endian_int), |
||||
], |
||||
True, |
||||
), |
||||
), # strictly these number of elements |
||||
("nonce", big_endian_int), |
||||
("gasPrice", big_endian_int), |
||||
("gasLimit", big_endian_int), |
||||
("chainId", big_endian_int), |
||||
) |
||||
|
||||
return UnsignedChainId |
||||
|
||||
@staticmethod |
||||
def SignedChainId(): |
||||
class SignedChainId( HashableRLP ): |
||||
fields = CreateValidator.UnsignedChainId()._meta.fields[:-1] + ( # drop chainId |
||||
fields = CreateValidator.UnsignedChainId()._meta.fields[ |
||||
:-1 |
||||
] + ( # drop chainId |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return SignedChainId |
||||
|
||||
@staticmethod |
||||
def Unsigned(): |
||||
class Unsigned( HashableRLP ): |
||||
fields = CreateValidator.UnsignedChainId()._meta.fields[:-1] # drop chainId |
||||
fields = CreateValidator.UnsignedChainId( |
||||
)._meta.fields[ :-1 ] # drop chainId |
||||
|
||||
return Unsigned |
||||
|
||||
@staticmethod |
||||
def Signed(): |
||||
class Signed( HashableRLP ): |
||||
fields = CreateValidator.Unsigned()._meta.fields[:-3] + ( # drop last 3 for raw.pop() |
||||
fields = CreateValidator.Unsigned()._meta.fields[ |
||||
:-3 |
||||
] + ( # drop last 3 for raw.pop() |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return Signed |
||||
|
||||
|
||||
class EditValidator: |
||||
@staticmethod |
||||
def UnsignedChainId(): |
||||
class UnsignedChainId( HashableRLP ): |
||||
fields = ( |
||||
('directive', big_endian_int), |
||||
('stakeMsg', List([ # list with the following members |
||||
Binary.fixed_length(20, allow_empty=True), # validatorAddress |
||||
List([Text()]*5,True), # description is Text of 5 elements |
||||
List([big_endian_int],True), # new rate is in a list |
||||
("directive", big_endian_int), |
||||
( |
||||
"stakeMsg", |
||||
List( |
||||
[ # list with the following members |
||||
# validatorAddress |
||||
Binary.fixed_length( |
||||
20, allow_empty=True |
||||
), |
||||
# description is Text of 5 elements |
||||
List( |
||||
[Text()] * 5, True |
||||
), |
||||
# new rate is in a list |
||||
List([big_endian_int], True), |
||||
big_endian_int, # min self delegation |
||||
big_endian_int, # max total delegation |
||||
Binary.fixed_length(48, allow_empty=True), # slot key to remove |
||||
Binary.fixed_length(48, allow_empty=True), # slot key to add |
||||
], True)), # strictly these number of elements |
||||
('nonce', big_endian_int), |
||||
('gasPrice', big_endian_int), |
||||
('gasLimit', big_endian_int), |
||||
('chainId', big_endian_int), |
||||
# slot key to remove |
||||
Binary.fixed_length( |
||||
48, allow_empty=True |
||||
), |
||||
# slot key to add |
||||
Binary.fixed_length( |
||||
48, allow_empty=True |
||||
), |
||||
# slot key to add sig |
||||
Binary.fixed_length( |
||||
96, allow_empty=True |
||||
), |
||||
], |
||||
True, |
||||
), |
||||
), # strictly these number of elements |
||||
("nonce", big_endian_int), |
||||
("gasPrice", big_endian_int), |
||||
("gasLimit", big_endian_int), |
||||
("chainId", big_endian_int), |
||||
) |
||||
|
||||
return UnsignedChainId |
||||
|
||||
@staticmethod |
||||
def SignedChainId(): |
||||
class SignedChainId( HashableRLP ): |
||||
fields = EditValidator.UnsignedChainId()._meta.fields[:-1] + ( # drop chainId |
||||
fields = EditValidator.UnsignedChainId()._meta.fields[ |
||||
:-1 |
||||
] + ( # drop chainId |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return SignedChainId |
||||
|
||||
@staticmethod |
||||
def Unsigned(): |
||||
class Unsigned( HashableRLP ): |
||||
fields = EditValidator.UnsignedChainId()._meta.fields[:-1] # drop chainId |
||||
fields = EditValidator.UnsignedChainId( |
||||
)._meta.fields[ :-1 ] # drop chainId |
||||
|
||||
return Unsigned |
||||
|
||||
@staticmethod |
||||
def Signed(): |
||||
class Signed( HashableRLP ): |
||||
fields = EditValidator.Unsigned()._meta.fields[:-3] + ( # drop last 3 for raw.pop() |
||||
fields = EditValidator.Unsigned()._meta.fields[ |
||||
:-3 |
||||
] + ( # drop last 3 for raw.pop() |
||||
("v", big_endian_int), |
||||
("r", big_endian_int), |
||||
("s", big_endian_int), |
||||
) |
||||
|
||||
return Signed |
||||
|
@ -0,0 +1,578 @@ |
||||
{ |
||||
"cells": [ |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 105, |
||||
"id": "feee22ef", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"from pyhmy import signing, staking_signing, numbers, transaction, account, validator as validator_module, staking_structures, contract\n", |
||||
"from web3 import Web3" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 3, |
||||
"id": "55b8db60", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"# we need five transactions in conftest\n", |
||||
"# simple transfer (from localnet address)\n", |
||||
"# contract creation (from second address)\n", |
||||
"# cross shard transfer (from second address)\n", |
||||
"# validator creation (from localnet address)\n", |
||||
"# delegation (from second address)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "e104724c", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### Simple Transfer" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 144, |
||||
"id": "d7fa35f8", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"pk = \"1f84c95ac16e6a50f08d44c7bde7aff8742212fda6e4321fde48bf83bef266dc\"\n", |
||||
"tx = {\n", |
||||
" 'from': 'one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3',\n", |
||||
" # 3c86ac59f6b038f584be1c08fced78d7c71bb55d5655f81714f3cddc82144c65\n", |
||||
" 'to': 'one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37',\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gas': 21000,\n", |
||||
" 'chainId': 2, # localnet\n", |
||||
" 'value': int( numbers.convert_one_to_atto( 503 ) ),\n", |
||||
" 'nonce': 0,\n", |
||||
" 'shardID': 0,\n", |
||||
" 'toShardID': 0,\n", |
||||
"}\n", |
||||
"raw_tx = signing.sign_transaction(tx, pk).rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_transaction(raw_tx)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 145, |
||||
"id": "ed907d4b", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf86f8085174876e8008252088080941f2213a52f7409ff4f103458e6d202e0b3aa805a891b4486fafde57c00008027a0d7c0b20207dcc9dde376822dc3f5625eac6f59a7526111695cdba3e29553ca17a05d4ca9a421ae16f89cbf6848186eaea7a800da732446dff9952e7c1e91d414e3\n", |
||||
"0xc26be5776aa57438bccf196671a2d34f3f22c9c983c0f844c62b2fb90403aa43\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "1bbee37b", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### Contract Creation" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 147, |
||||
"id": "b143507b", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"pk = '3c86ac59f6b038f584be1c08fced78d7c71bb55d5655f81714f3cddc82144c65'\n", |
||||
"data = \"0x6080604052348015600f57600080fd5b50607780601d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f0033\"\n", |
||||
"tx = {\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gas': 100000,\n", |
||||
" 'chainId': 2,\n", |
||||
" 'nonce': 0,\n", |
||||
" 'shardID': 0,\n", |
||||
" 'toShardID': 0,\n", |
||||
" 'data': data,\n", |
||||
"}\n", |
||||
"raw_tx = signing.sign_transaction(tx, pk).rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_transaction(raw_tx)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 148, |
||||
"id": "53dbcbff", |
||||
"metadata": { |
||||
"scrolled": true |
||||
}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf8e88085174876e800830186a080808080b8946080604052348015600f57600080fd5b50607780601d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f003327a08bf26ee0120c296b17af507f62606abdb5c5f09a65642c3d30b349b8bfbb3d69a03ec7be51c615bcbf2f1d63f6eaa56cf8d7be81671717f90239619830a81ebc9f\n", |
||||
"0xa605852dd2fa39ed42e101c17aaca9d344d352ba9b24b14b9af94ec9cb58b31f\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 130, |
||||
"id": "6e66392b", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"contract_address = transaction.get_transaction_receipt( tx_hash ).get( 'contractAddress' )\n", |
||||
"deployed = contract.get_code( contract_address, 'latest' )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 131, |
||||
"id": "ead2f9d4", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0x6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f0033\n", |
||||
"0x6080604052348015600f57600080fd5b50607780601d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f0033\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( deployed )\n", |
||||
"print( data )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 132, |
||||
"id": "453a34d6", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"3300f080003436c6f63746dc447adeb4d82da06660bc16489e70d315a93fde5dd4f95a1387620d8e0af3af0221228537660796462aef3f091002063009180915092518100615080406b5df080006b575d2064163dc63943608c10e065300067582060163400605b5df08000675f0065108432504060806x0\n", |
||||
"3300f080003436c6f63746dc447adeb4d82da06660bc16489e70d315a93fde5dd4f95a1387620d8e0af3af0221228537660796462aef3f091002063009180915092518100615080406b5df080006b575d2064163dc63943608c10e065300067582060163400605b5df08000675f0065108432504060806ef3f0006930006d10608770605b5df08000675f0065108432504060806x0\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( \"\".join( [ deployed[ len( deployed ) - ( i + 1 ) ] for i in range( len( deployed ) ) ] ) )\n", |
||||
"print( \"\".join( [ data[ len( data ) - ( i + 1 ) ] for i in range( len( data ) ) ] ) )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 133, |
||||
"id": "d251d1bf", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"data": { |
||||
"text/plain": [ |
||||
"True" |
||||
] |
||||
}, |
||||
"execution_count": 133, |
||||
"metadata": {}, |
||||
"output_type": "execute_result" |
||||
} |
||||
], |
||||
"source": [ |
||||
"\"0x6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f0033\" == deployed" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "812e033c", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### Cross Shard Transfer" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 149, |
||||
"id": "d7c70614", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"pk = '3c86ac59f6b038f584be1c08fced78d7c71bb55d5655f81714f3cddc82144c65'\n", |
||||
"tx = {\n", |
||||
" 'from': 'one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37',\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gas': 21000,\n", |
||||
" 'chainId': 2,\n", |
||||
" 'nonce': 1,\n", |
||||
" 'shardID': 0,\n", |
||||
" 'toShardID': 1,\n", |
||||
" 'to': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'value': Web3.toWei( 100, 'gwei' ),\n", |
||||
"}\n", |
||||
"raw_tx = signing.sign_transaction(tx, pk).rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_transaction(raw_tx)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 150, |
||||
"id": "f20990f1", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf86b0185174876e800825208800194c9c6d47ee5f2e3e08d7367ad1a1373ba9dd1724185174876e8008027a02501c517220e9499f14e97c20b0a88cd3b7ba80637bba43ed295422e69a3f300a079b8e1213c9506184aed6ac2eb0b2cb00594c3f9fcdd6c088937ce17fe47107c\n", |
||||
"0xf73ba634cb96fc0e3e2c9d3b4c91379e223741be4a5aa56e6d6caf49c1ae75cf\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 153, |
||||
"id": "66f024b9", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"data": { |
||||
"text/plain": [ |
||||
"0" |
||||
] |
||||
}, |
||||
"execution_count": 153, |
||||
"metadata": {}, |
||||
"output_type": "execute_result" |
||||
} |
||||
], |
||||
"source": [ |
||||
"account.get_balance( 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes', 'http://localhost:9502' )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "2b2446df", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### Validator Creation" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 154, |
||||
"id": "c3513c37", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"pk = \"1f84c95ac16e6a50f08d44c7bde7aff8742212fda6e4321fde48bf83bef266dc\"\n", |
||||
"address = \"one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3\"\n", |
||||
"info = {\n", |
||||
" \"name\": \"Alice\",\n", |
||||
" \"identity\": \"alice\",\n", |
||||
" \"website\": \"alice.harmony.one\",\n", |
||||
" \"security-contact\": \"Bob\",\n", |
||||
" \"details\": \"Are you even reading this?\",\n", |
||||
" \"min-self-delegation\": int( numbers.convert_one_to_atto( 10000 ) ),\n", |
||||
" \"max-total-delegation\": int( numbers.convert_one_to_atto( 100000 ) ),\n", |
||||
" \"rate\": \"0.1\",\n", |
||||
" \"max-rate\": \"0.9\",\n", |
||||
" \"max-change-rate\": \"0.05\",\n", |
||||
" \"bls-public-keys\": [\n", |
||||
" # private key is b1f2a5029f5f43c8c933a61ce936ced030b2c9379f8e2478fc888fa670cdbc89b8cd1ebc29b5b00a81d3152bb3aaa3a337404f50bee5e434430ca3693a94a1c102a765cf3b0887b8b0bcf5317d33f4bec60a97feae2498a39ab7a1c2\n", |
||||
" # blspass.txt is empty\n", |
||||
" \"0xa20e70089664a874b00251c5e85d35a73871531306f3af43e02138339d294e6bb9c4eb82162199c6a852afeaa8d68712\",\n", |
||||
" ],\n", |
||||
" \"amount\": int( numbers.convert_one_to_atto( 10000 ) ),\n", |
||||
" \"bls-key-sigs\": [\n", |
||||
" \"0xef2c49a2f31fbbd23c21bc176eaf05cd0bebe6832033075d81fea7cff6f9bc1ab42f3b6895c5493fe645d8379d2eaa1413de55a9d3ce412a4f747cb57d52cc4da4754bfb2583ec9a41fe5dd48287f964f276336699959a5fcef3391dc24df00d\",\n", |
||||
" ]\n", |
||||
"}\n", |
||||
"validator = validator_module.Validator( address )\n", |
||||
"validator.load( info )\n", |
||||
"raw_tx = validator.sign_create_validator_transaction(\n", |
||||
" 1,\n", |
||||
" Web3.toWei( 100, 'gwei' ),\n", |
||||
" 55000000, # gas limit\n", |
||||
" pk,\n", |
||||
" 2 # chain id\n", |
||||
").rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_staking_transaction(\n", |
||||
" raw_tx,\n", |
||||
")" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 155, |
||||
"id": "9b12f75f", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf9017c80f9012994a5241513da9f4463f1d4874b548dfbac29d91f34f83d85416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f629a41726520796f75206576656e2072656164696e6720746869733fddc988016345785d8a0000c9880c7d713b49da0000c887b1a2bc2ec500008a021e19e0c9bab24000008a152d02c7e14af6800000f1b0a20e70089664a874b00251c5e85d35a73871531306f3af43e02138339d294e6bb9c4eb82162199c6a852afeaa8d68712f862b860ef2c49a2f31fbbd23c21bc176eaf05cd0bebe6832033075d81fea7cff6f9bc1ab42f3b6895c5493fe645d8379d2eaa1413de55a9d3ce412a4f747cb57d52cc4da4754bfb2583ec9a41fe5dd48287f964f276336699959a5fcef3391dc24df00d8a021e19e0c9bab24000000185174876e8008403473bc028a08c1146305eaef981aa24c2f17c8519664d10c99ee42acedbc258749930d31a7ca031dadf114ee6ab9bd09933208094c65037b66c796bcfc57a70158106b37357b0\n", |
||||
"0x400e9831d358f5daccd153cad5bf53650a0d413bd8682ec0ffad55367d162968\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "4c2ff645", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### Delegation" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 156, |
||||
"id": "458d81b8", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf88302f4941f2213a52f7409ff4f103458e6d202e0b3aa805a94a5241513da9f4463f1d4874b548dfbac29d91f3489056bc75e2d631000000285174876e80082c35028a02c5e953062dcdfa2de9723639b63bab45705eb6dfbfe7f44536ed266c3c7ca20a0742964e646338e7431874f70715565d99c01c762324355c69db34a9ed9de81d7\n", |
||||
"0xc8177ace2049d9f4eb4a45fd6bd6b16f693573d036322c36774cc00d05a3e24f\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"pk = \"3c86ac59f6b038f584be1c08fced78d7c71bb55d5655f81714f3cddc82144c65\"\n", |
||||
"tx = {\n", |
||||
" 'directive': staking_structures.Directive.Delegate,\n", |
||||
" 'delegatorAddress': 'one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37',\n", |
||||
" 'validatorAddress': 'one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3',\n", |
||||
" 'amount': Web3.toWei( 100, 'ether' ),\n", |
||||
" 'nonce': 2,\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gasLimit': 50000,\n", |
||||
" 'chainId': 2,\n", |
||||
"}\n", |
||||
"raw_tx = staking_signing.sign_staking_transaction(\n", |
||||
" tx,\n", |
||||
" pk,\n", |
||||
").rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_staking_transaction(\n", |
||||
" raw_tx,\n", |
||||
")\n", |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "8efa5536", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### test_transaction.py - transfer 105 ONE to another address" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 157, |
||||
"id": "c3295fee", |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"pk = '3c86ac59f6b038f584be1c08fced78d7c71bb55d5655f81714f3cddc82144c65'\n", |
||||
"tx = {\n", |
||||
" 'from': 'one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37',\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gas': 21000,\n", |
||||
" 'chainId': 2,\n", |
||||
" 'nonce': 3,\n", |
||||
" 'shardID': 0,\n", |
||||
" 'toShardID': 0,\n", |
||||
" 'to': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'value': Web3.toWei( 105, 'ether' ),\n", |
||||
"}\n", |
||||
"raw_tx = signing.sign_transaction(tx, pk).rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_transaction(raw_tx)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 158, |
||||
"id": "af515c7e", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf86f0385174876e800825208808094c9c6d47ee5f2e3e08d7367ad1a1373ba9dd172418905b12aefafa80400008027a07a4952b90bf38723a9197179a8e6d2e9b3a86fd6da4e66a9cf09fdc59783f757a053910798b311245525bd77d6119332458c2855102e4fb9e564f6a3b710d18bb0\n", |
||||
"0x7ccd80f8513f76ec58b357c7a82a12a95e025d88f1444e953f90e3d86e222571\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"id": "bb546b3e", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"### test_transaction.py - staking transaction" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 168, |
||||
"id": "c14e2d6d", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"0xf88302f494c9c6d47ee5f2e3e08d7367ad1a1373ba9dd1724194a5241513da9f4463f1d4874b548dfbac29d91f3489056bc75e2d631000008085174876e80082c35027a0808ea7d27adf3b1f561e8da4676814084bb75ac541b616bece87c6446e6cc54ea02f19f0b14240354bd42ad60b0c7189873c0be87044e13072b0981a837ca76f64\n", |
||||
"0xe7d07ef6d9fca595a14ceb0ca917bece7bedb15efe662300e9334a32ac1da629\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"pk = \"ff9ef6b00a61672b4b7bedd5ac653439b56ac8ee808c99a1bd871cf51b7d60eb\"\n", |
||||
"tx = {\n", |
||||
" 'directive': staking_structures.Directive.Delegate,\n", |
||||
" 'delegatorAddress': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'validatorAddress': 'one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3',\n", |
||||
" 'amount': Web3.toWei( 100, 'ether' ),\n", |
||||
" 'nonce': 0,\n", |
||||
" 'gasPrice': Web3.toWei( 100, 'gwei' ),\n", |
||||
" 'gasLimit': 50000,\n", |
||||
" 'chainId': 2,\n", |
||||
"}\n", |
||||
"raw_tx = staking_signing.sign_staking_transaction(\n", |
||||
" tx,\n", |
||||
" pk,\n", |
||||
").rawTransaction.hex()\n", |
||||
"tx_hash = transaction.send_raw_staking_transaction(\n", |
||||
" raw_tx,\n", |
||||
")\n", |
||||
"print( raw_tx )\n", |
||||
"print( tx_hash )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 162, |
||||
"id": "ebf296aa", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"data": { |
||||
"text/plain": [ |
||||
"{'blockHash': '0xf55f1fb3c9be76fb74370e8a7d8580327797d2d6082040074783207a171e2de6',\n", |
||||
" 'blockNumber': 34,\n", |
||||
" 'from': 'one1ru3p8ff0wsyl7ncsx3vwd5szuze64qz60upg37',\n", |
||||
" 'hash': '0xf73ba634cb96fc0e3e2c9d3b4c91379e223741be4a5aa56e6d6caf49c1ae75cf',\n", |
||||
" 'shardID': 0,\n", |
||||
" 'to': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'toShardID': 1,\n", |
||||
" 'value': 100000000000}" |
||||
] |
||||
}, |
||||
"execution_count": 162, |
||||
"metadata": {}, |
||||
"output_type": "execute_result" |
||||
} |
||||
], |
||||
"source": [ |
||||
"transaction.get_cx_receipt_by_hash( '0xf73ba634cb96fc0e3e2c9d3b4c91379e223741be4a5aa56e6d6caf49c1ae75cf', 'http://localhost:9502' )" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 166, |
||||
"id": "ff0229ce", |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"data": { |
||||
"text/plain": [ |
||||
"{'blockHash': '0x0000000000000000000000000000000000000000000000000000000000000000',\n", |
||||
" 'blockNumber': None,\n", |
||||
" 'from': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'gas': 50000,\n", |
||||
" 'gasPrice': 100000000000,\n", |
||||
" 'hash': '0x279935278d20d778cbe4fdfa5d51be9eb1eb184053dc9a7cb88ad3365df73060',\n", |
||||
" 'msg': {'amount': 100000000000000000000,\n", |
||||
" 'delegatorAddress': 'one1e8rdglh97t37prtnv7k35ymnh2wazujpzsmzes',\n", |
||||
" 'validatorAddress': 'one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3'},\n", |
||||
" 'nonce': 2,\n", |
||||
" 'r': '0x8660a63c10af06f2fb3f24b92cf61d4f319044a1f1931c4f4e54ce986ff563c',\n", |
||||
" 's': '0x597785559c4283d3ece2df37cbf37077966487a2a2dc0f4cdbbf75a8f20bc1a8',\n", |
||||
" 'timestamp': 0,\n", |
||||
" 'transactionIndex': 0,\n", |
||||
" 'type': 'Delegate',\n", |
||||
" 'v': '0x27'}" |
||||
] |
||||
}, |
||||
"execution_count": 166, |
||||
"metadata": {}, |
||||
"output_type": "execute_result" |
||||
} |
||||
], |
||||
"source": [ |
||||
"transaction.get_staking_transaction_by_hash( \"0x279935278d20d778cbe4fdfa5d51be9eb1eb184053dc9a7cb88ad3365df73060\" )" |
||||
] |
||||
} |
||||
], |
||||
"metadata": { |
||||
"kernelspec": { |
||||
"display_name": "Python 3 (ipykernel)", |
||||
"language": "python", |
||||
"name": "python3" |
||||
}, |
||||
"language_info": { |
||||
"codemirror_mode": { |
||||
"name": "ipython", |
||||
"version": 3 |
||||
}, |
||||
"file_extension": ".py", |
||||
"mimetype": "text/x-python", |
||||
"name": "python", |
||||
"nbconvert_exporter": "python", |
||||
"pygments_lexer": "ipython3", |
||||
"version": "3.10.5" |
||||
} |
||||
}, |
||||
"nbformat": 4, |
||||
"nbformat_minor": 5 |
||||
} |
@ -1,9 +1,9 @@ |
||||
from pyhmy.bech32 import ( |
||||
bech32 |
||||
) |
||||
from pyhmy.bech32 import bech32 |
||||
|
||||
|
||||
def test_encode(): |
||||
bech32.encode('one', 5, [121, 161]) |
||||
bech32.encode( "one", 5, [ 121, 161 ] ) |
||||
|
||||
|
||||
def test_decode(): |
||||
bech32.decode('one', 'one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9') |
||||
bech32.decode( "one", "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9" ) |
||||
|
@ -1,116 +1,155 @@ |
||||
import pytest |
||||
import requests |
||||
|
||||
from pyhmy import ( |
||||
account |
||||
) |
||||
|
||||
from pyhmy.rpc import ( |
||||
exceptions |
||||
) |
||||
from pyhmy import account |
||||
|
||||
from pyhmy.rpc import exceptions |
||||
|
||||
explorer_endpoint = 'http://localhost:9599' |
||||
endpoint_shard_one = 'http://localhost:9501' |
||||
local_test_address = 'one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur' |
||||
test_validator_address = 'one18tvf56zqjkjnak686lwutcp5mqfnvee35xjnhc' |
||||
explorer_endpoint = "http://localhost:9700" |
||||
endpoint_shard_one = "http://localhost:9502" |
||||
local_test_address = "one155jp2y76nazx8uw5sa94fr0m4s5aj8e5xm6fu3" |
||||
test_validator_address = local_test_address |
||||
genesis_block_number = 0 |
||||
test_block_number = 1 |
||||
fake_shard = 'http://example.com' |
||||
fake_shard = "http://example.com" |
||||
|
||||
|
||||
def _test_account_rpc( fn, *args, **kwargs ): |
||||
if not callable( fn ): |
||||
pytest.fail(f'Invalid function: {fn}') |
||||
pytest.fail( f"Invalid function: {fn}" ) |
||||
|
||||
try: |
||||
response = fn( *args, **kwargs ) |
||||
except Exception as e: |
||||
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}') |
||||
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}" ) |
||||
return response |
||||
|
||||
|
||||
@pytest.mark.run(order=1) |
||||
def test_get_balance( setup_blockchain ): |
||||
balance = _test_account_rpc( account.get_balance, local_test_address ) |
||||
assert isinstance( balance, int ) |
||||
assert balance > 0 |
||||
|
||||
@pytest.mark.run(order=2) |
||||
|
||||
def test_get_balance_by_block( setup_blockchain ): |
||||
balance = _test_account_rpc(account.get_balance_by_block, local_test_address, genesis_block_number) |
||||
balance = _test_account_rpc( |
||||
account.get_balance_by_block, |
||||
local_test_address, |
||||
genesis_block_number |
||||
) |
||||
assert isinstance( balance, int ) |
||||
assert balance > 0 |
||||
|
||||
@pytest.mark.run(order=3) |
||||
|
||||
def test_get_account_nonce( setup_blockchain ): |
||||
true_nonce = _test_account_rpc(account.get_account_nonce, local_test_address, test_block_number, endpoint=endpoint_shard_one) |
||||
true_nonce = _test_account_rpc( |
||||
account.get_account_nonce, |
||||
local_test_address, |
||||
test_block_number, |
||||
endpoint = endpoint_shard_one, |
||||
) |
||||
assert isinstance( true_nonce, int ) |
||||
|
||||
@pytest.mark.run(order=4) |
||||
|
||||
def test_get_transaction_history( setup_blockchain ): |
||||
tx_history = _test_account_rpc(account.get_transaction_history, local_test_address, endpoint=explorer_endpoint) |
||||
tx_history = _test_account_rpc( |
||||
account.get_transaction_history, |
||||
local_test_address, |
||||
endpoint = explorer_endpoint |
||||
) |
||||
assert isinstance( tx_history, list ) |
||||
assert len( tx_history ) >= 0 |
||||
|
||||
@pytest.mark.run(order=5) |
||||
|
||||
def test_get_staking_transaction_history( setup_blockchain ): |
||||
staking_tx_history = _test_account_rpc(account.get_staking_transaction_history, test_validator_address, endpoint=explorer_endpoint) |
||||
staking_tx_history = _test_account_rpc( |
||||
account.get_staking_transaction_history, |
||||
test_validator_address, |
||||
endpoint = explorer_endpoint, |
||||
) |
||||
assert isinstance( staking_tx_history, list ) |
||||
assert len( staking_tx_history ) > 0 |
||||
|
||||
@pytest.mark.run(order=6) |
||||
|
||||
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 |
||||
|
||||
@pytest.mark.run(order=7) |
||||
|
||||
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 |
||||
|
||||
@pytest.mark.run(order=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" |
||||
) |
||||
|
||||
|
||||
@pytest.mark.run(order=8) |
||||
def test_get_transaction_count( setup_blockchain ): |
||||
tx_count = _test_account_rpc(account.get_transaction_count, local_test_address, 'latest') |
||||
tx_count = _test_account_rpc( |
||||
account.get_transaction_count, |
||||
local_test_address, |
||||
"latest", |
||||
explorer_endpoint |
||||
) |
||||
assert isinstance( tx_count, int ) |
||||
assert tx_count > 0 |
||||
|
||||
@pytest.mark.run(order=9) |
||||
|
||||
def test_get_transactions_count( setup_blockchain ): |
||||
tx_count = _test_account_rpc(account.get_transactions_count, local_test_address, 'ALL') |
||||
tx_count = _test_account_rpc( |
||||
account.get_transactions_count, |
||||
local_test_address, |
||||
"ALL", |
||||
explorer_endpoint |
||||
) |
||||
|
||||
|
||||
@pytest.mark.run(order=10) |
||||
def test_get_staking_transactions_count( setup_blockchain ): |
||||
tx_count = _test_account_rpc(account.get_staking_transactions_count, local_test_address, 'ALL') |
||||
tx_count = _test_account_rpc( |
||||
account.get_staking_transactions_count, |
||||
local_test_address, |
||||
"ALL", |
||||
explorer_endpoint, |
||||
) |
||||
assert isinstance( tx_count, int ) |
||||
|
||||
@pytest.mark.run(order=10) |
||||
|
||||
def test_errors(): |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_balance('', fake_shard) |
||||
account.get_balance( "", fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_balance_by_block('', 1, fake_shard) |
||||
account.get_balance_by_block( "", 1, fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_account_nonce('', 1, fake_shard) |
||||
account.get_account_nonce( "", 1, fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_transaction_count('', 1, fake_shard) |
||||
account.get_transaction_count( "", 1, fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_transactions_count('', 1, fake_shard) |
||||
account.get_transactions_count( "", 1, fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_transactions_count('', 'ALL', fake_shard) |
||||
account.get_transactions_count( "", "ALL", fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_transaction_history('', endpoint=fake_shard) |
||||
account.get_transaction_history( "", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_staking_transaction_history('', endpoint=fake_shard) |
||||
account.get_staking_transaction_history( "", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_balance_on_all_shards('', endpoint=fake_shard) |
||||
account.get_balance_on_all_shards( "", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
account.get_total_balance('', endpoint=fake_shard) |
||||
account.get_total_balance( "", endpoint = fake_shard ) |
||||
|
@ -1,74 +1,86 @@ |
||||
import pytest |
||||
|
||||
from pyhmy import ( |
||||
contract |
||||
) |
||||
from pyhmy import contract |
||||
|
||||
from pyhmy.rpc import ( |
||||
exceptions |
||||
) |
||||
from pyhmy.rpc import exceptions |
||||
|
||||
explorer_endpoint = 'http://localhost:9599' |
||||
contract_tx_hash = '0xa13414dd152173395c69a11e79dea31bf029660f747a42a53744181d05571e70' |
||||
explorer_endpoint = "http://localhost:9599" |
||||
contract_tx_hash = "0xa605852dd2fa39ed42e101c17aaca9d344d352ba9b24b14b9af94ec9cb58b31f" |
||||
# deployedBytecode from json file |
||||
contract_code = "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80634936cd3614602d575b600080fd5b604080516001815290519081900360200190f3fea2646970667358221220fa3fa0e8d0267831a59f4dd5edf39a513d07e98461cb06660ad28d4beda744cd64736f6c634300080f0033" |
||||
contract_address = None |
||||
fake_shard = 'http://example.com' |
||||
fake_shard = "http://example.com" |
||||
|
||||
|
||||
def _test_contract_rpc( fn, *args, **kwargs ): |
||||
if not callable( fn ): |
||||
pytest.fail(f'Invalid function: {fn}') |
||||
pytest.fail( f"Invalid function: {fn}" ) |
||||
|
||||
try: |
||||
response = fn( *args, **kwargs ) |
||||
except Exception as e: |
||||
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): |
||||
pytest.skip(f'{str(e)}') |
||||
pytest.fail(f'Unexpected error: {e.__class__} {e}') |
||||
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 ): |
||||
pytest.skip( f"{str(e)}" ) |
||||
pytest.fail( f"Unexpected error: {e.__class__} {e}" ) |
||||
return response |
||||
|
||||
@pytest.mark.run(order=1) |
||||
|
||||
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_address = _test_contract_rpc( |
||||
contract.get_contract_address_from_hash, |
||||
contract_tx_hash |
||||
) |
||||
assert isinstance( contract_address, str ) |
||||
|
||||
@pytest.mark.run(order=2) |
||||
|
||||
def test_call( setup_blockchain ): |
||||
if not contract_address: |
||||
pytest.skip('Contract address not loaded yet') |
||||
called = _test_contract_rpc(contract.call, contract_address, 'latest') |
||||
assert isinstance(called, str) and called.startswith('0x') |
||||
pytest.skip( "Contract address not loaded yet" ) |
||||
called = _test_contract_rpc( contract.call, contract_address, "latest" ) |
||||
assert isinstance( called, str ) and called.startswith( "0x" ) |
||||
|
||||
|
||||
@pytest.mark.run(order=3) |
||||
def test_estimate_gas( setup_blockchain ): |
||||
if not contract_address: |
||||
pytest.skip('Contract address not loaded yet') |
||||
pytest.skip( "Contract address not loaded yet" ) |
||||
gas = _test_contract_rpc( contract.estimate_gas, contract_address ) |
||||
assert isinstance( gas, int ) |
||||
|
||||
@pytest.mark.run(order=4) |
||||
|
||||
def test_get_code( setup_blockchain ): |
||||
if not contract_address: |
||||
pytest.skip('Contract address not loaded yet') |
||||
code = _test_contract_rpc(contract.get_code, contract_address, 'latest') |
||||
assert code == '0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063445df0ac146100465780638da5cb5b14610064578063fdacd576146100ae575b600080fd5b61004e6100dc565b6040518082815260200191505060405180910390f35b61006c6100e2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100da600480360360208110156100c457600080fd5b8101908080359060200190929190505050610107565b005b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561016457806001819055505b5056fea265627a7a723158209b80813a158b44af65aee232b44c0ac06472c48f4abbe298852a39f0ff34a9f264736f6c63430005100032' |
||||
pytest.skip( "Contract address not loaded yet" ) |
||||
code = _test_contract_rpc( contract.get_code, contract_address, "latest" ) |
||||
assert code == contract_code |
||||
|
||||
|
||||
@pytest.mark.run(order=5) |
||||
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') |
||||
assert isinstance(storage, str) and storage.startswith('0x') |
||||
pytest.skip( "Contract address not loaded yet" ) |
||||
storage = _test_contract_rpc( |
||||
contract.get_storage_at, |
||||
contract_address, |
||||
"0x0", |
||||
"latest" |
||||
) |
||||
assert isinstance( storage, str ) and storage.startswith( "0x" ) |
||||
|
||||
|
||||
def test_errors(): |
||||
with pytest.raises( exceptions.RPCError ): |
||||
contract.get_contract_address_from_hash('', fake_shard) |
||||
contract.get_contract_address_from_hash( "", fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
contract.call('', '', endpoint=fake_shard) |
||||
contract.call( "", "", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
contract.estimate_gas('', endpoint=fake_shard) |
||||
contract.estimate_gas( "", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
contract.get_code('', 'latest', endpoint=fake_shard) |
||||
contract.get_code( "", "latest", endpoint = fake_shard ) |
||||
with pytest.raises( exceptions.RPCError ): |
||||
contract.get_storage_at('', 1, 'latest', endpoint=fake_shard) |
||||
contract.get_storage_at( "", 1, "latest", endpoint = fake_shard ) |
||||
|
Loading…
Reference in new issue