Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eth -> Method getBlock #1735

Merged
merged 3 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/1735.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Convert eth_getBalance to use ``Method`` class
26 changes: 12 additions & 14 deletions tests/core/gas-strategies/test_time_based_gas_price_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ def _get_block_by_something(method, params):
block_identifier = params[0]
if (
block_identifier == 'latest' or
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000005' or
wolovim marked this conversation as resolved.
Show resolved Hide resolved
block_identifier == 5
block_identifier == '0x5'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000005',
Expand All @@ -35,12 +34,12 @@ def _get_block_by_something(method, params):
{'gasPrice': 5},
{'gasPrice': 50},
],
'miner': '0xA',
'miner': '0x' + 'AA' * 20,
wolovim marked this conversation as resolved.
Show resolved Hide resolved
'timestamp': 120,
}
elif (
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000004' or
block_identifier == 4
block_identifier == '0x4'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000004',
Expand All @@ -51,12 +50,12 @@ def _get_block_by_something(method, params):
{'gasPrice': 80},
{'gasPrice': 60},
],
'miner': '0xB',
'miner': '0x' + 'BB' * 20,
'timestamp': 90,
}
elif (
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000003' or
block_identifier == 3
block_identifier == '0x3'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000003',
Expand All @@ -65,25 +64,25 @@ def _get_block_by_something(method, params):
'transactions': [
{'gasPrice': 100},
],
'miner': '0xC',
'miner': '0x' + 'Cc' * 20,
'timestamp': 60,
}
elif (
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000002' or
block_identifier == 2
block_identifier == '0x2'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000002',
'number': 2,
'parentHash': '0x0000000000000000000000000000000000000000000000000000000000000001',
'transactions': [
],
'miner': '0xB',
'miner': '0x' + 'Bb' * 20,
'timestamp': 30,
}
elif (
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000001' or
block_identifier == 1
block_identifier == '0x1'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000001',
Expand All @@ -94,12 +93,11 @@ def _get_block_by_something(method, params):
{'gasPrice': 35},
{'gasPrice': 65},
],
'miner': '0xA',
'miner': '0x' + 'Aa' * 20,
'timestamp': 15,
}
elif (
block_identifier == '0x0000000000000000000000000000000000000000000000000000000000000000' or
block_identifier == 0
block_identifier == '0x0'
):
return {
'hash': '0x0000000000000000000000000000000000000000000000000000000000000000',
Expand All @@ -119,7 +117,7 @@ def _get_block_by_something(method, params):
{'gasPrice': 54},
{'gasPrice': 10000000000000000000000},
],
'miner': '0xA',
'miner': '0x' + 'Aa' * 20,
'timestamp': 0,
}
else:
Expand Down
21 changes: 16 additions & 5 deletions tests/core/middleware/test_filter_middleware.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import pytest

from hexbytes import (
HexBytes,
)

from web3 import Web3
from web3.datastructures import (
AttributeDict,
)
from web3.middleware import (
construct_result_generator_middleware,
local_filter_middleware,
Expand All @@ -22,6 +29,10 @@ def make_request(self, method, params):
))


BLOCK_HASH = '0xfe88c94d860f01a17f961bf4bdfb6e0c6cd10d3fda5cc861e805ca1240c58553'
FILTER_LOG = [AttributeDict({'address': '0xDc3A9Db694BCdd55EBaE4A89B22aC6D12b3F0c24', 'blockHash': HexBytes('0xb72256286ca528e09022ffd408856a73ef90e7216ac560187c6e43b4c4efd2f0'), 'blockNumber': 2217196, 'data': '0x0000000000000000000000000000000000000000000000000000000000000001', 'logIndex': 0, 'topics': [HexBytes('0xe65b00b698ba37c614af350761c735c5f4a82b4ab365a1f1022d49d9dfc8e930'), HexBytes('0x000000000000000000000000754c50465885f1ed1fa1a55b95ee8ecf3f1f4324'), HexBytes('0x296c7fb6ccafa3e689950b947c2895b07357c95b066d5cdccd58c301f41359a3')], 'transactionHash': HexBytes('0xfe1289fd3915794b99702202f65eea2e424b2f083a12749d29b4dd51f6dce40d'), 'transactionIndex': 1})] # noqa: E501


@pytest.fixture(scope='function')
def iter_block_number(start=0):
def iterator():
Expand All @@ -38,8 +49,8 @@ def iterator():
@pytest.fixture(scope='function')
def result_generator_middleware(iter_block_number):
return construct_result_generator_middleware({
'eth_getLogs': lambda *_: ["middleware"],
'eth_getBlockByNumber': lambda *_: type('block', (object,), {'hash': 'middleware'}),
'eth_getLogs': lambda *_: FILTER_LOG,
wolovim marked this conversation as resolved.
Show resolved Hide resolved
'eth_getBlockByNumber': lambda *_: {'hash': BLOCK_HASH},
'net_version': lambda *_: 1,
'eth_blockNumber': lambda *_: next(iter_block_number),
})
Expand Down Expand Up @@ -141,13 +152,13 @@ def test_local_filter_middleware(w3, iter_block_number):

log_filter = w3.eth.filter(filter_params={'fromBlock': 'latest'})

assert w3.eth.getFilterChanges(block_filter.filter_id) == ["middleware"]
assert w3.eth.getFilterChanges(block_filter.filter_id) == [HexBytes(BLOCK_HASH)]

iter_block_number.send(2)
results = w3.eth.getFilterChanges(log_filter.filter_id)
assert results == ["middleware"]
assert results == FILTER_LOG

assert w3.eth.getFilterLogs(log_filter.filter_id) == ["middleware"]
assert w3.eth.getFilterLogs(log_filter.filter_id) == FILTER_LOG

filter_ids = (
block_filter.filter_id,
Expand Down
10 changes: 10 additions & 0 deletions tests/core/middleware/test_latest_block_based_cache_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import uuid

from eth_utils import (
is_hex,
is_integer,
to_tuple,
)
Expand All @@ -13,6 +14,9 @@
from web3._utils.caching import (
generate_cache_key,
)
from web3._utils.formatters import (
hex_to_integer,
)
from web3.middleware import ( # noqa: F401
construct_error_generator_middleware,
construct_latest_block_based_cache_middleware,
Expand Down Expand Up @@ -82,6 +86,12 @@ def _get_block_by_number(method, params, block_info=_block_info):
return blocks[block_id]
else:
return None
elif is_hex(block_id):
block_id = hex_to_integer(block_id)
if block_id <= head_block_number:
return blocks[block_id]
else:
return None
else:
raise TypeError('Invalid type for block_id')

Expand Down
4 changes: 4 additions & 0 deletions web3/_utils/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
is_text,
remove_0x_prefix,
)
from eth_utils.toolz import (
curry,
)

from web3.types import (
RPCEndpoint,
Expand Down Expand Up @@ -51,6 +54,7 @@ def is_hex_encoded_block_number(value: Any) -> bool:
return 0 <= value_as_int < 2**256


@curry
def select_method_for_block_identifier(
value: Any, if_hash: RPCEndpoint, if_number: RPCEndpoint, if_predefined: RPCEndpoint
) -> RPCEndpoint:
Expand Down
21 changes: 18 additions & 3 deletions web3/_utils/method_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Collection,
Dict,
Iterable,
NoReturn,
Tuple,
Union,
)
Expand Down Expand Up @@ -69,7 +70,11 @@
from web3.datastructures import (
AttributeDict,
)
from web3.exceptions import (
BlockNotFound,
)
from web3.types import (
BlockIdentifier,
RPCEndpoint,
TReturn,
)
Expand Down Expand Up @@ -495,6 +500,17 @@ def get_request_formatters(
return compose(*formatters)


def raise_block_not_found(params: Tuple[BlockIdentifier, bool]) -> NoReturn:
block_identifier = params[0]
raise BlockNotFound(f"Block with id: {block_identifier} not found.")


NULL_RESULT_FORMATTERS: Dict[RPCEndpoint, Callable[..., Any]] = {
RPC.eth_getBlockByNumber: raise_block_not_found,
RPC.eth_getBlockByHash: raise_block_not_found,
}


def get_result_formatters(
method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
Expand All @@ -504,15 +520,14 @@ def get_result_formatters(
)
attrdict_formatter = apply_formatter_if(is_dict and not_attrdict, AttributeDict.recursive)

return compose(*formatters, attrdict_formatter)
return compose(attrdict_formatter, *formatters)


def get_error_formatters(
method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
) -> Dict[str, Callable[..., Any]]:
# Note error formatters work on the full response dict
# TODO - test this function
error_formatter_maps = ()
error_formatter_maps = (NULL_RESULT_FORMATTERS,)
formatters = combine_formatters(error_formatter_maps, method_name)

return compose(*formatters)
32 changes: 14 additions & 18 deletions web3/eth.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,27 +250,23 @@ def getCode(
[account, block_identifier],
)

def getBlock(
self, block_identifier: BlockIdentifier, full_transactions: bool = False
) -> BlockData:
"""
`eth_getBlockByHash`
`eth_getBlockByNumber`
"""
method = select_method_for_block_identifier(
block_identifier,
def get_block_munger(
self, block_identifier: BlockIdentifier, full_transactions: bool=False
) -> Tuple[BlockIdentifier, bool]:
return (block_identifier, full_transactions)

"""
`eth_getBlockByHash`
`eth_getBlockByNumber`
"""
getBlock: Method[Callable[..., BlockData]] = Method(
method_choice_depends_on_args=select_method_for_block_identifier(
if_predefined=RPC.eth_getBlockByNumber,
if_hash=RPC.eth_getBlockByHash,
if_number=RPC.eth_getBlockByNumber,
)

result = self.web3.manager.request_blocking(
method,
[block_identifier, full_transactions],
)
if result is None:
raise BlockNotFound(f"Block with id: {block_identifier} not found.")
return result
),
mungers=[get_block_munger],
)

def getBlockTransactionCount(self, block_identifier: BlockIdentifier) -> int:
"""
Expand Down
9 changes: 8 additions & 1 deletion web3/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@


def apply_error_formatters(
error_formatters: Callable[..., Any], response: RPCResponse
error_formatters: Callable[..., Any],
response: Optional[RPCResponse]=None,
params: Optional[Any]=None,
) -> RPCResponse:
if 'error' in response and error_formatters:
formatted_response = pipe(response, error_formatters)
return formatted_response
elif 'result' in response.keys() and response['result'] is None and error_formatters:
formatted_response = pipe(params, error_formatters)
return formatted_response
else:
return response

Expand Down Expand Up @@ -151,6 +156,8 @@ def request_blocking(
if "error" in response:
apply_error_formatters(error_formatters, response)
raise ValueError(response["error"])
elif response['result'] is None:
apply_error_formatters(error_formatters, response, params)

return response['result']

Expand Down
7 changes: 7 additions & 0 deletions web3/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,15 @@ def __init__(
request_formatters: Optional[Callable[..., TReturn]] = None,
result_formatters: Optional[Callable[..., TReturn]] = None,
error_formatters: Optional[Callable[..., TReturn]] = None,
method_choice_depends_on_args: Optional[Callable[..., RPCEndpoint]] = None,
web3: Optional["Web3"] = None):

self.json_rpc_method = json_rpc_method
self.mungers = mungers or [default_munger]
self.request_formatters = request_formatters or get_request_formatters
self.result_formatters = result_formatters or get_result_formatters
self.error_formatters = get_error_formatters
self.method_choice_depends_on_args = method_choice_depends_on_args

def __get__(self, obj: Optional["ModuleV2"] = None,
obj_type: Optional[Type["ModuleV2"]] = None) -> TFunc:
Expand Down Expand Up @@ -169,6 +171,11 @@ def process_params(
self, module: Union["Module", "ModuleV2"], *args: Any, **kwargs: Any
) -> Tuple[Tuple[Union[RPCEndpoint, Callable[..., Any]], Any], Tuple[Any, Any]]:
params = self.input_munger(module, args, kwargs)
# block_identifier is always the first argument passed in for methods where
# method_choice_depends_on_args is called.
if self.method_choice_depends_on_args:
block_identifier = args[0]
self.json_rpc_method = self.method_choice_depends_on_args(value=block_identifier)
method = self.method_selector_fn()
response_formatters = (self.result_formatters(method), self.error_formatters(method))

Expand Down