Repository: ethereum/web3.py

Issue:
Web3 crashes in time-based gas price strategies with empty chain
* Version: 4.7.1
* Python: 3.6
* OS: linux

### What was wrong?

Running our test suite web3 crashes when estimating time based gas price. Probably it is caused by not having any transactions in our test chain. However when probabilities are calculated they are empty (empty tuple) which causes then an Index Error in ` '104, in _compute_gas_price\r\n    first = probabilities[0]\r\nIndexError: tuple index out of range\`

It might be the case that there is a problem with our geth client during runtime.


```
File “/home/circleci/raiden/raiden/network/rpc/client.py”, line 346, in gas_price
return int(self.web3.eth.generateGasPrice())
File “/home/circleci/venv-3.7/lib/python3.7/site-packages/web3/eth.py”, line 385, in generateGasPrice
return self.gasPriceStrategy(self.web3, transaction_params)
File “/home/circleci/venv-3.7/lib/python3.7/site-packages/web3/gas_strategies/time_based.py”, line 168, in time_based_gas_price_strategy
gas_price = _compute_gas_price(probabilities, probability / 100)
File “/home/circleci/venv-3.7/lib/python3.7/site-packages/web3/gas_strategies/time_based.py”, line 104, in _compute_gas_price
first = probabilities[0]
IndexError: tuple index out of range
```


### How can it be fixed?

However I would suggest handling the edge case that there is an empty tuple and not unconditionally access `first = probabilities[0] `

I'm happy to give more information when needed


Discussion:
Yes, I believe this is a known issue. I'll leave it open for tracking.

I think the current solution is: don't try to estimate gas if you don't have any transactions to go on (which is obviously unsatisfying).

But, I'm also not sure what the estimate function should do otherwise. I don't think it would be appropriate to return any number, or `None` (requiring return value checking is bad:tm:).

The only better option I can think of is to raise a `ValidationError` that is clearly saying that there are no transactions to base an estimate on.

Any other ideas?
I'd argue that the best fallback would be to use ` web3.eth.gasPrice`.

Resolving patch:
diff --git a/web3/gas_strategies/time_based.py b/web3/gas_strategies/time_based.py
--- a/web3/gas_strategies/time_based.py
+++ b/web3/gas_strategies/time_based.py
@@ -216,6 +216,10 @@ def construct_time_based_gas_price_strategy(
     """
 
     def time_based_gas_price_strategy(w3: Web3, transaction_params: TxParams) -> Wei:
+        # return gas price when no transactions available to sample
+        if w3.eth.get_block("latest")["number"] == 0:
+            return w3.eth.gas_price
+
         if weighted:
             avg_block_time = _get_weighted_avg_block_time(w3, sample_size=sample_size)
         else:


Test patch:
diff --git a/tests/core/gas-strategies/test_time_based_gas_price_strategy.py b/tests/core/gas-strategies/test_time_based_gas_price_strategy.py
--- a/tests/core/gas-strategies/test_time_based_gas_price_strategy.py
+++ b/tests/core/gas-strategies/test_time_based_gas_price_strategy.py
@@ -171,6 +171,46 @@ def test_time_based_gas_price_strategy(strategy_params, expected):
     assert actual == expected
 
 
+def _get_initial_block(method, params):
+    return {
+        "hash": constants.HASH_ZERO,
+        "number": 0,
+        "parentHash": None,
+        "transactions": [],
+        "miner": "0x" + "Aa" * 20,
+        "timestamp": 0,
+    }
+
+
+def _get_gas_price(method, params):
+    return 4321
+
+
+def test_time_based_gas_price_strategy_without_transactions():
+    fixture_middleware = construct_result_generator_middleware(
+        {
+            "eth_getBlockByHash": _get_initial_block,
+            "eth_getBlockByNumber": _get_initial_block,
+            "eth_gasPrice": _get_gas_price,
+        }
+    )
+
+    w3 = Web3(
+        provider=BaseProvider(),
+        middlewares=[fixture_middleware],
+    )
+
+    time_based_gas_price_strategy = construct_time_based_gas_price_strategy(
+        max_wait_seconds=80,
+        sample_size=5,
+        probability=50,
+        weighted=True,
+    )
+    w3.eth.set_gas_price_strategy(time_based_gas_price_strategy)
+    actual = w3.eth.generate_gas_price()
+    assert actual == w3.eth.gas_price
+
+
 @pytest.mark.parametrize(
     "strategy_params_zero,expected_exception_message",
     (