def gas_price_strategy_eth_gas_station_or_with_margin( web3: Web3, transaction_params): # FIXME: This is a temporary fix to speed up gas price generation # by fetching from eth_gas_station if possible. # Once we have a reliable gas price calculation this can be removed if int(web3.net.version) == 1: try: response = requests.get(ETH_GAS_STATION_API) if response and response.status_code == 200: data = response.json() log.debug( f"fetched gas price: {Wei(int(data['fast'] * 10e7 * 1.1))} Wei" ) return Wei(int(data["fast"] * 10e7 * 1.1)) except (TimeoutError, ConnectionError, KeyError): log.debug( "Could not fetch from ethgasstation. Falling back to web3 gas estimation." ) gas_price_strategy = construct_time_based_gas_price_strategy( max_wait_seconds=15, sample_size=25) gas_price = Wei( int( gas_price_strategy(web3, transaction_params) * GAS_PRICE_MARGIN)) return gas_price
def setup_gas_strategy(w3, transaction_wait): w3.eth.setGasPriceStrategy( construct_time_based_gas_price_strategy(transaction_wait)) w3.middleware_onion.add(middleware.time_based_cache_middleware) w3.middleware_onion.add(middleware.latest_block_based_cache_middleware) w3.middleware_onion.add(middleware.simple_cache_middleware)
def get_web3_client( http_endpoint: str = "", ws_endpoint: str = "", ws_endpoint_timeout: int = 60, apply_gas_price_strategy: bool = False, max_tx_wait_seconds: int = 120, inject_retry_request: bool = False, inject_poa: bool = False, inject_local_filter: bool = False, inject_stale_check: bool = False, stale_check_allowable_delay: Union[int, None] = None, ) -> Web3: """Returns instance of the Web3 client.""" # Either http or ws endpoint must be provided (prefer ws over http) if ws_endpoint: w3 = Web3( Web3.WebsocketProvider(ws_endpoint, websocket_timeout=ws_endpoint_timeout)) logger.info(f"Using Web3 websocket endpoint {ws_endpoint}") if inject_retry_request: w3.middleware_onion.add(ws_retry_request_middleware) logger.info("Injected request retry middleware") else: w3 = Web3(Web3.HTTPProvider(http_endpoint)) logger.info(f"Using Web3 HTTP endpoint {http_endpoint}") if inject_retry_request: w3.middleware_onion.add(http_retry_request_middleware) logger.info("Injected request retry middleware") if inject_poa: w3.middleware_onion.inject(geth_poa_middleware, layer=0) logger.info("Injected POA middleware") if inject_stale_check and stale_check_allowable_delay is not None: stale_check_middleware = make_stalecheck_middleware( stale_check_allowable_delay) w3.middleware_onion.add(stale_check_middleware) logger.info("Injected stale check middleware") if inject_local_filter: w3.middleware_onion.add(local_filter_middleware) logger.info("Injected local filter middleware") if apply_gas_price_strategy: w3.eth.setGasPriceStrategy( construct_time_based_gas_price_strategy( max_wait_seconds=max_tx_wait_seconds, weighted=True, sample_size=120, )) w3.middleware_onion.add(_time_based_cache_middleware) w3.middleware_onion.add(_latest_block_based_cache_middleware) w3.middleware_onion.add(_simple_cache_middleware) logger.info( f"Set gas price strategy with {max_tx_wait_seconds} wait seconds") return w3
def test_time_based_gas_price_strategy(strategy_params, expected): fixture_middleware = construct_result_generator_middleware({ 'eth_getBlockByHash': _get_block_by_something, 'eth_getBlockByNumber': _get_block_by_something, }) w3 = Web3( provider=BaseProvider(), middlewares=[fixture_middleware], ) time_based_gas_price_strategy = construct_time_based_gas_price_strategy( **strategy_params, ) w3.eth.setGasPriceStrategy(time_based_gas_price_strategy) actual = w3.eth.generate_gas_price() assert actual == expected
def test_time_based_gas_price_strategy(strategy_params, expected): fixture_middleware = construct_result_generator_middleware({ 'eth_getBlockByHash': _get_block_by_something, 'eth_getBlockByNumber': _get_block_by_something, }) w3 = Web3( providers=[BaseProvider()], middlewares=[fixture_middleware], ) time_based_gas_price_strategy = construct_time_based_gas_price_strategy( **strategy_params, ) w3.eth.setGasPriceStrategy(time_based_gas_price_strategy) actual = w3.eth.generateGasPrice() assert actual == expected
def test_time_based_gas_price_strategy_zero_sample(strategy_params_zero, expected_exception_message): with pytest.raises(ValidationError) as excinfo: fixture_middleware = construct_result_generator_middleware({ 'eth_getBlockByHash': _get_block_by_something, 'eth_getBlockByNumber': _get_block_by_something, }) w3 = Web3( provider=BaseProvider(), middlewares=[fixture_middleware], ) time_based_gas_price_strategy_zero = construct_time_based_gas_price_strategy( **strategy_params_zero, ) w3.eth.setGasPriceStrategy(time_based_gas_price_strategy_zero) w3.eth.generate_gas_price() assert str(excinfo.value) == expected_exception_message
def test_time_based_gas_price_strategy_zero_sample(strategy_params_zero, expected_exception_message): with pytest.raises(ValidationError) as excinfo: fixture_middleware = construct_result_generator_middleware({ 'eth_getBlockByHash': _get_block_by_something, 'eth_getBlockByNumber': _get_block_by_something, }) w3 = Web3( providers=[BaseProvider()], middlewares=[fixture_middleware], ) time_based_gas_price_strategy_zero = construct_time_based_gas_price_strategy( **strategy_params_zero, ) w3.eth.setGasPriceStrategy(time_based_gas_price_strategy_zero) w3.eth.generateGasPrice() assert str(excinfo.value) == expected_exception_message
def __init__(self, node_uri, use_ipc=False, use_poa=False): """ Create instance to interact with the contract deployer. Args: node_uri (str): Either the http address of an ethereum node or the path to the IPC file if 'use_ipc=True'. use_ipc (bool): If True then 'node_uri' will be treated as a file path to the 'geth.ipc' file of the node to connect to. use_poa (bool): If True then it will inject 'geth_poa_middleware' to the web3 instance. When 'node_uri' refers to a Rinkeby node then this needs to be set to True. """ if use_ipc: provider = IPCProvider(node_uri) else: provider = HTTPProvider(node_uri) self.w3 = Web3(provider) self.default_account = None self.contract_data = None if use_poa: # Needed only with PoA (Rinkeby) self.w3.middleware_stack.inject(middleware.geth_poa_middleware, layer=0) block_sample = 40 prob = 95 # Probability to be included express_strategy = construct_time_based_gas_price_strategy( 30, block_sample, prob) self.w3.eth.setGasPriceStrategy(express_strategy) # Tries to make transactions faster (and more expensive?) # self.w3.eth.setGasPriceStrategy(fast_gas_price_strategy) self.w3.middleware_stack.add(middleware.time_based_cache_middleware) self.w3.middleware_stack.add( middleware.latest_block_based_cache_middleware) self.w3.middleware_stack.add(middleware.simple_cache_middleware)
import functools from cachetools import LRUCache from web3.gas_strategies.time_based import construct_time_based_gas_price_strategy from web3.middleware.cache import construct_simple_cache_middleware from web3.types import RPCEndpoint BLOCK_HASH_CACHE_RPC_WHITELIST = {RPCEndpoint("eth_getBlockByHash")} block_hash_cache_middleware = construct_simple_cache_middleware( # default sample size of gas price strategies is 120 cache_class=functools.partial(LRUCache, 150), # type: ignore rpc_whitelist=BLOCK_HASH_CACHE_RPC_WHITELIST, ) faster_gas_price_strategy = construct_time_based_gas_price_strategy( max_wait_seconds=15, sample_size=120, probability=99 )