Skip to content

Commit

Permalink
Black
Browse files Browse the repository at this point in the history
  • Loading branch information
miohtama committed Jul 22, 2023
1 parent 33109e1 commit 66fef1a
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 64 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Current

- Add MEV blocking support
- Add JSON-RPC fallback switching
- Add MEV blocking support in the form of `eth_defi.mev_blocker.MEVBlockerProvider`
- Add JSON-RPC fallback switching in the form of `eth_defi.fallback_provider.FallbackProvider`
- Add `HotWallet.create_for_testing`

# 0.21.8
Expand Down
5 changes: 4 additions & 1 deletion eth_defi/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ def install_api_call_counter_middleware_on_provider(provider: JSONBaseProvider)
api_counter = Counter()

def factory(make_request: Callable[[RPCEndpoint, Any], Any], web3: "Web3"):
import ipdb; ipdb.set_trace()
import ipdb

ipdb.set_trace()

def middleware(method: RPCEndpoint, params: Any) -> Optional[RPCResponse]:
api_counter[method] += 1
api_counter["total"] += 1
Expand Down
41 changes: 15 additions & 26 deletions eth_defi/fallback_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@


class FallbackStrategy(enum.Enum):

#: Automatically switch to the next provider on an error
#:
cycle_on_error = "cycle_on_error"



class FallbackProvider(JSONBaseProvider):
"""Fall back to the next provder in the list if a JSON-RPC request fails.
Expand All @@ -42,15 +40,15 @@ class FallbackProvider(JSONBaseProvider):
"""

def __init__(
self,
providers: List[JSONBaseProvider],
strategy=FallbackStrategy.cycle_on_error,
retryable_exceptions=DEFAULT_RETRYABLE_EXCEPTIONS,
retryable_status_codes=DEFAULT_RETRYABLE_HTTP_STATUS_CODES,
retryable_rpc_error_codes= DEFAULT_RETRYABLE_RPC_ERROR_CODES,
sleep: float = 5.0,
backoff: float = 1.6,
retries: int = 6,
self,
providers: List[JSONBaseProvider],
strategy=FallbackStrategy.cycle_on_error,
retryable_exceptions=DEFAULT_RETRYABLE_EXCEPTIONS,
retryable_status_codes=DEFAULT_RETRYABLE_HTTP_STATUS_CODES,
retryable_rpc_error_codes=DEFAULT_RETRYABLE_RPC_ERROR_CODES,
sleep: float = 5.0,
backoff: float = 1.6,
retries: int = 6,
):
"""
:param providers:
Expand Down Expand Up @@ -106,7 +104,6 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
for i in range(self.retries):
provider = self.get_provider()
try:

# Call the underlying provider
val = provider.make_request(method, params)

Expand All @@ -116,26 +113,18 @@ def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
return val

except Exception as e:

if is_retryable_http_exception(
e,
retryable_rpc_error_codes=self.retryable_rpc_error_codes,
retryable_status_codes=self.retryable_status_codes,
retryable_exceptions=self.retryable_exceptions,
e,
retryable_rpc_error_codes=self.retryable_rpc_error_codes,
retryable_status_codes=self.retryable_status_codes,
retryable_exceptions=self.retryable_exceptions,
):

old_provider_name = _get_provider_name(provider)
self.switch_provider()
new_provider_name = _get_provider_name(self.get_provider())

if i < self.retries - 1:
logger.warning(
"Encountered JSON-RPC retryable error %s when calling method %s.\n"
"Switching providers %s -> %s\n"
"Retrying in %f seconds, retry #%d",
e, method,
old_provider_name, new_provider_name,
current_sleep, i)
logger.warning("Encountered JSON-RPC retryable error %s when calling method %s.\n" "Switching providers %s -> %s\n" "Retrying in %f seconds, retry #%d", e, method, old_provider_name, new_provider_name, current_sleep, i)
time.sleep(current_sleep)
current_sleep *= self.backoff
self.retry_count += 1
Expand All @@ -155,4 +144,4 @@ def _get_provider_name(provider: JSONBaseProvider) -> str:
"""
if isinstance(provider, HTTPProvider):
return get_url_domain(provider.endpoint_uri)
return str(provider)
return str(provider)
13 changes: 7 additions & 6 deletions eth_defi/hotwallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,13 @@ def create_for_testing(web3: Web3, test_account_n=0, eth_amount=10):
"""
wallet = HotWallet.from_private_key("0x" + secrets.token_hex(32))
tx_hash = web3.eth.send_transaction({
"from": web3.eth.accounts[test_account_n],
"to": wallet.address,
"value": eth_amount*10**18,
})
tx_hash = web3.eth.send_transaction(
{
"from": web3.eth.accounts[test_account_n],
"to": wallet.address,
"value": eth_amount * 10**18,
}
)
web3.eth.wait_for_transaction_receipt(tx_hash)
wallet.sync_nonce(web3)
return wallet

18 changes: 10 additions & 8 deletions eth_defi/mev_blocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,23 @@ class MEVBlockerProvider(JSONBaseProvider):
"""

def __init__(
self,
call_provider: JSONBaseProvider,
transact_provivder: JSONBaseProvider,
transact_methods=TRANSACT_METHODS,
self,
call_provider: JSONBaseProvider,
transact_provivder: JSONBaseProvider,
transact_methods=TRANSACT_METHODS,
):
super().__init__()
self.call_provider = call_provider
self.transact_provider = transact_provivder
self.transact_methods = transact_methods

#: Keep tabs on how much API traffic we generate through each endpoint
self.provider_counter = Counter({
"call": 0,
"transact": 0,
})
self.provider_counter = Counter(
{
"call": 0,
"transact": 0,
}
)

def is_transact_method(self, method: RPCEndpoint) -> bool:
"""Does this RPC method do a transaction"""
Expand Down
2 changes: 1 addition & 1 deletion eth_defi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,4 @@ def get_url_domain(url: str) -> str:
Some services e.g. infura use path as an API key.
"""
parsed = urlparse(url)
return parsed.hostname
return parsed.hostname
5 changes: 1 addition & 4 deletions tests/test_event_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,8 @@ def test_read_events_concurrent_two_blocks_concurrent(web3):
assert max(blocks) == 37898276



def test_read_events_lazy_timestamp(web3):
"""Read events but extract timestamps only for events, not whole block ranges.
"""
"""Read events but extract timestamps only for events, not whole block ranges."""

# Get contracts
Pair = get_contract(web3, "sushi/UniswapV2Pair.json")
Expand Down
10 changes: 3 additions & 7 deletions tests/test_fallback_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def fallback_provider(provider_1, provider_2) -> FallbackProvider:


def test_fallback_no_issue(fallback_provider: FallbackProvider):
"""Callback goes through the first provider """
"""Callback goes through the first provider"""
web3 = Web3(fallback_provider)
assert fallback_provider.api_call_counts[0]["eth_blockNumber"] == 0
assert fallback_provider.api_call_counts[1]["eth_blockNumber"] == 0
Expand Down Expand Up @@ -70,9 +70,7 @@ def test_fallback_double_fault(fallback_provider: FallbackProvider, provider_1,

web3 = Web3(fallback_provider)

with patch.object(provider_1, "make_request", side_effect=requests.exceptions.ConnectionError), \
patch.object(provider_2, "make_request", side_effect=requests.exceptions.ConnectionError):

with patch.object(provider_1, "make_request", side_effect=requests.exceptions.ConnectionError), patch.object(provider_2, "make_request", side_effect=requests.exceptions.ConnectionError):
with pytest.raises(requests.exceptions.ConnectionError):
web3.eth.block_number

Expand All @@ -93,9 +91,7 @@ def borg_start(*args, **kwargs):
raise requests.exceptions.ConnectionError()
return DEFAULT

with patch.object(provider_1, "make_request", side_effect=borg_start), \
patch.object(provider_2, "make_request", side_effect=borg_start):

with patch.object(provider_1, "make_request", side_effect=borg_start), patch.object(provider_2, "make_request", side_effect=borg_start):
web3.eth.block_number

assert fallback_provider.api_call_counts[0]["eth_blockNumber"] == 1
Expand Down
19 changes: 10 additions & 9 deletions tests/test_mev_blocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
@pytest.fixture(scope="session")
def anvil() -> AnvilLaunch:
"""Launch Anvil for the test backend."""
anvil = launch_anvil(
)
anvil = launch_anvil()
try:
yield anvil
finally:
Expand Down Expand Up @@ -57,13 +56,15 @@ def test_mev_blocker_send_transaction_raw(mev_blocker_provider: MEVBlockerProvid
web3 = Web3(mev_blocker_provider)
wallet = HotWallet.create_for_testing(web3)

signed_tx = wallet.sign_transaction_with_new_nonce({
"from": wallet.address,
"to": ZERO_ADDRESS,
"value": 1,
"gas": 100_000,
"gasPrice": web3.eth.gas_price,
})
signed_tx = wallet.sign_transaction_with_new_nonce(
{
"from": wallet.address,
"to": ZERO_ADDRESS,
"value": 1,
"gas": 100_000,
"gasPrice": web3.eth.gas_price,
}
)

# Account for setup API counts from create_for_testing()
assert mev_blocker_provider.provider_counter["call"] == 10
Expand Down

0 comments on commit 66fef1a

Please sign in to comment.