Skip to content

Commit

Permalink
Add trace_call, deprecate traceCall
Browse files Browse the repository at this point in the history
  • Loading branch information
kclowes committed Apr 28, 2021
1 parent 2837d01 commit b224e1f
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
1 change: 1 addition & 0 deletions newsfragments/1957.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``parity.trace_call``, deprecate ``parity.traceCall``
23 changes: 20 additions & 3 deletions web3/_utils/module_testing/parity_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,23 @@ def test_trace_transaction(self, web3: "Web3", parity_fixture_data: Dict[str, st
trace = web3.parity.traceTransaction(HexStr(parity_fixture_data['mined_txn_hash']))
assert trace[0]['action']['from'] == add_0x_prefix(HexStr(parity_fixture_data['coinbase']))

def test_traceCall_deprecated(
self, web3: "Web3", math_contract: "Contract", math_contract_address: ChecksumAddress
) -> None:
coinbase = web3.eth.coinbase
txn_params = math_contract._prepare_transaction(
fn_name='add',
fn_args=(7, 11),
transaction={'from': coinbase, 'to': math_contract_address},
)
with pytest.warns(DeprecationWarning,
match="traceCall is deprecated in favor of trace_call"):
trace = web3.parity.traceCall(txn_params)
assert trace['stateDiff'] is None
assert trace['vmTrace'] is None
result = hex_to_integer(trace['output'])
assert result == 18

def test_trace_call(
self, web3: "Web3", math_contract: "Contract", math_contract_address: ChecksumAddress
) -> None:
Expand All @@ -104,13 +121,13 @@ def test_trace_call(
fn_args=(7, 11),
transaction={'from': coinbase, 'to': math_contract_address},
)
trace = web3.parity.traceCall(txn_params)
trace = web3.parity.trace_call(txn_params)
assert trace['stateDiff'] is None
assert trace['vmTrace'] is None
result = hex_to_integer(trace['output'])
assert result == 18

def test_eth_call_with_0_result(
def test_trace_call_with_0_result(
self, web3: "Web3", math_contract: "Contract", math_contract_address: ChecksumAddress
) -> None:
coinbase = web3.eth.coinbase
Expand All @@ -119,7 +136,7 @@ def test_eth_call_with_0_result(
fn_args=(0, 0),
transaction={'from': coinbase, 'to': math_contract_address},
)
trace = web3.parity.traceCall(txn_params)
trace = web3.parity.trace_call(txn_params)
assert trace['stateDiff'] is None
assert trace['vmTrace'] is None
result = hex_to_integer(trace['output'])
Expand Down
3 changes: 2 additions & 1 deletion web3/parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def trace_call_munger(

return (transaction, mode, block_identifier)

traceCall: Method[Callable[..., ParityBlockTrace]] = Method(
trace_call: Method[Callable[..., ParityBlockTrace]] = Method(
RPC.trace_call,
mungers=[trace_call_munger],
)
Expand Down Expand Up @@ -234,3 +234,4 @@ def trace_transactions_munger(
traceReplayBlockTransactions = DeprecatedMethod(trace_replay_block_transactions,
'traceReplayBlockTransactions',
'trace_replay_block_transactions')
traceCall = DeprecatedMethod(trace_call, 'traceCall', 'trace_call')
78 changes: 78 additions & 0 deletions web3/providers/async_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
class AsyncBaseProvider:
_middlewares: Tuple[Middleware, ...] = ()
# a tuple of (all_middlewares, request_func)
_request_func_cache: Tuple[Tuple[Middleware, ...], Callable[..., RPCResponse]] = (None, None)

@property
def middlewares(self) -> Tuple[Middleware, ...]:
return self._middlewares

@middlewares.setter
def middlewares(
self, values: MiddlewareOnion
) -> None:
# tuple(values) converts to MiddlewareOnion -> Tuple[Middleware, ...]
self._middlewares = tuple(values) # type: ignore

def request_func(
self, web3: "Web3", outer_middlewares: MiddlewareOnion
) -> Callable[..., RPCResponse]:
"""
@param outer_middlewares is an iterable of middlewares, ordered by first to execute
@returns a function that calls all the middleware and eventually self.make_request()
"""
# type ignored b/c tuple(MiddlewareOnion) converts to tuple of middlewares
all_middlewares: Tuple[Middleware] = tuple(outer_middlewares) + tuple(self.middlewares) # type: ignore # noqa: E501

cache_key = self._request_func_cache[0]
if cache_key is None or cache_key != all_middlewares:
self._request_func_cache = (
all_middlewares,
self._generate_request_func(web3, all_middlewares)
)
return self._request_func_cache[-1]

def _generate_request_func(
self, web3: "Web3", middlewares: Sequence[Middleware]
) -> Callable[..., RPCResponse]:
return combine_middlewares(
middlewares=middlewares,
web3=web3,
provider_request_fn=self.make_request,
)

async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
raise NotImplementedError("Providers must implement this method")

async def isConnected(self) -> bool:
raise NotImplementedError("Providers must implement this method")


class AsyncJSONBaseProvider(AsyncBaseProvider):
def __init__(self) -> None:
self.request_counter = itertools.count()

async def decode_rpc_response(self, raw_response: bytes) -> RPCResponse:
text_response = to_text(raw_response)
return await cast(RPCResponse, FriendlyJsonSerde().json_decode(text_response))

async def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
rpc_dict = {
"jsonrpc": "2.0",
"method": method,
"params": params or [],
"id": next(self.request_counter),
}
encoded = FriendlyJsonSerde().json_encode(rpc_dict)
return await to_bytes(text=encoded)

def isConnected(self) -> bool:
try:
response = self.make_request(RPCEndpoint('web3_clientVersion'), [])
except IOError:
return False

assert response['jsonrpc'] == '2.0'
assert 'error' not in response

return True

0 comments on commit b224e1f

Please sign in to comment.