Repository: rotki/rotki

Issue:
Can't generate PnL Report
## Problem Definition

In rotki 1.31.0 there are 2 issues that I wasn't experiencing before.

When I click on the `Profit and Loss Report` tab an error notification is shown

![image](https://github.com/rotki/rotki/assets/73274/99c60140-13da-45d2-9c2b-e80987f348b0)

Also the report won't end successfully 

> An unexpected response was received while generating the profit and loss report. This might indicate an issue with the generation mechanism. Please check the logs for any error messages (you might have to enable debug logging first) and create an issue.
>
> The backend query task died unexpectedly: **'ValidatorDailyStats' object has no attribute 'event_identifier'**

![image](https://github.com/rotki/rotki/assets/73274/91365ec7-ef36-4353-a06d-e57a4756da98)

## Logs

Clicking Profit and Loss Report tab:

```
2023-11-27T13:02:36.066Z: (error): [
  {
    "code": "invalid_type",
    "expected": "boolean",
    "received": "undefined",
    "path": [
      "entries",
      0,
      "settings",
      "includeFeesInCostBasis"
    ],
    "message": "Required"
  }
]
```

When report it about to end

```
[27/11/2023 14:09:33 CET] ERROR rotkehlchen.api.rest Greenlet with id 140627884780992: Greenlet for task 52 dies with exception: 'ValidatorDailyStats' object has no attribute 'event_identifier'.
Exception Name: <class 'AttributeError'>
Exception Info: 'ValidatorDailyStats' object has no attribute 'event_identifier'
Traceback:
   File "src/gevent/greenlet.py", line 908, in gevent._gevent_cgreenlet.Greenlet.run
  File "rotkehlchen/api/rest.py", line 413, in _do_query_async
  File "rotkehlchen/api/rest.py", line 1528, in process_history
  File "rotkehlchen/rotkehlchen.py", line 847, in process_history
  File "rotkehlchen/accounting/accountant.py", line 164, in process_history
  File "rotkehlchen/accounting/accountant.py", line 304, in _process_event
  File "rotkehlchen/accounting/structures/evm_event.py", line 289, in process
  File "rotkehlchen/accounting/history_base_entries.py", line 108, in process
```

### System Description

Operating system: Ubuntu
Rotki version: 1.31.0




Discussion:
Okay so these are indeed 2 different issues.

### Frontend zod error

 The first one with the zod error is something that @lukicenturi is looking at and has been reported in the discord.

The "hack" for now is to delete the transient DB for your user. This is the `rotkehlchen_transient.db` which contains old reports

### Backend logs

This I haven't seen before. Will need to investigate.

Resolving patch:
diff --git a/rotkehlchen/accounting/history_base_entries.py b/rotkehlchen/accounting/history_base_entries.py
--- a/rotkehlchen/accounting/history_base_entries.py
+++ b/rotkehlchen/accounting/history_base_entries.py
@@ -95,18 +95,17 @@ def process(
                 )
                 return 1
 
-            next_event = cast(HistoryBaseEntry, next_event)
-            if next_event.event_identifier != event.event_identifier:
+            if not isinstance(next_event, HistoryBaseEntry) or next_event.event_identifier != event.event_identifier:  # noqa: E501
                 log.error(
                     f'Tried to process accounting swap but the in '
                     f'event for {event} is not there',
                 )
                 return 1
-            in_event = cast(HistoryBaseEntry, next(events_iterator))
+            in_event = cast(HistoryBaseEntry, next(events_iterator))  # guaranteed by the if check
 
-            next_event = cast(HistoryBaseEntry, events_iterator.peek(None))
-            if next_event and next_event.event_identifier == event.event_identifier and next_event.event_subtype == HistoryEventSubType.FEE:  # noqa: E501
-                fee_event = cast(HistoryBaseEntry, next(events_iterator))
+            next_event = events_iterator.peek(None)
+            if next_event and isinstance(next_event, HistoryBaseEntry) and next_event.event_identifier == event.event_identifier and next_event.event_subtype == HistoryEventSubType.FEE:  # noqa: E501
+                fee_event = cast(HistoryBaseEntry, next(events_iterator))  # guaranteed by if check
 
             return self._process_swap(
                 timestamp=timestamp,


Test patch:
diff --git a/rotkehlchen/tests/unit/accounting/evm/test_cowswap.py b/rotkehlchen/tests/unit/accounting/evm/test_cowswap.py
--- a/rotkehlchen/tests/unit/accounting/evm/test_cowswap.py
+++ b/rotkehlchen/tests/unit/accounting/evm/test_cowswap.py
@@ -14,28 +14,13 @@
 from rotkehlchen.constants import ONE, ZERO
 from rotkehlchen.constants.assets import A_USDC, A_WBTC
 from rotkehlchen.fval import FVal
+from rotkehlchen.tests.utils.accounting import MOCKED_PRICES, TIMESTAMP_1_MS, TIMESTAMP_1_SEC
 from rotkehlchen.tests.utils.factories import make_evm_address, make_evm_tx_hash
-from rotkehlchen.types import Location, Price, Timestamp, TimestampMS
+from rotkehlchen.types import Location, Price
 
 if TYPE_CHECKING:
     from rotkehlchen.accounting.accountant import Accountant
 
-TIMESTAMP_1_MS = TimestampMS(1000)
-TIMESTAMP_1_SEC = Timestamp(1)
-
-MOCKED_PRICES = {
-    A_WBTC.identifier: {
-        'EUR': {
-            TIMESTAMP_1_SEC: Price(ONE),
-        },
-    },
-    A_USDC.identifier: {
-        'EUR': {
-            TIMESTAMP_1_SEC: Price(ONE),
-        },
-    },
-}
-
 
 @pytest.mark.parametrize('mocked_price_queries', [MOCKED_PRICES])
 @pytest.mark.parametrize('accounting_initialize_parameters', [True])
diff --git a/rotkehlchen/tests/unit/accounting/test_basic.py b/rotkehlchen/tests/unit/accounting/test_basic.py
--- a/rotkehlchen/tests/unit/accounting/test_basic.py
+++ b/rotkehlchen/tests/unit/accounting/test_basic.py
@@ -6,19 +6,25 @@
 from rotkehlchen.accounting.pnl import PNL, PnlTotals
 from rotkehlchen.accounting.structures.balance import Balance
 from rotkehlchen.accounting.structures.base import HistoryEvent
+from rotkehlchen.accounting.structures.evm_event import EvmEvent
 from rotkehlchen.accounting.structures.types import HistoryEventSubType, HistoryEventType
 from rotkehlchen.accounting.types import MissingPrice
 from rotkehlchen.assets.asset import EvmToken
+from rotkehlchen.chain.ethereum.modules.eth2.structures import ValidatorDailyStats
+from rotkehlchen.chain.evm.decoding.cowswap.constants import CPT_COWSWAP
 from rotkehlchen.constants import ONE, ZERO
-from rotkehlchen.constants.assets import A_BTC, A_COMP, A_ETH, A_EUR, A_USD
+from rotkehlchen.constants.assets import A_BTC, A_COMP, A_ETH, A_EUR, A_USD, A_USDC, A_WBTC
 from rotkehlchen.exchanges.data_structures import Trade
 from rotkehlchen.fval import FVal
 from rotkehlchen.tests.utils.accounting import (
+    MOCKED_PRICES,
+    TIMESTAMP_1_MS,
     accounting_history_process,
     check_pnls_and_csv,
     history1,
 )
 from rotkehlchen.tests.utils.constants import A_CHF, A_XMR
+from rotkehlchen.tests.utils.factories import make_evm_address, make_evm_tx_hash
 from rotkehlchen.tests.utils.history import prices
 from rotkehlchen.tests.utils.messages import no_message_errors
 from rotkehlchen.types import (
@@ -479,3 +485,60 @@ def test_all_chains_have_explorers(accountant: 'Accountant'):
     """Test that all chain in the csv exporter have a valid explorer url"""
     for chain in EVM_CHAINS_WITH_TRANSACTIONS:
         assert chain in accountant.csvexporter.transaction_explorers
+
+
+@pytest.mark.parametrize('mocked_price_queries', [MOCKED_PRICES])
+def test_non_history_event_in_history_iterator(accountant):
+    """Test that the PnL report does not fail if a non-history event follows a swap
+
+    Regression test for: https://github.com/rotki/rotki/issues/7009
+    """
+    tx_hash = make_evm_tx_hash()
+    user_address = make_evm_address()
+    contract_address = make_evm_address()
+    swap_amount_str = '0.99'
+    receive_amount_str = '10000'
+    history = [HistoryEvent(
+        event_identifier='1',
+        sequence_index=0,
+        timestamp=TIMESTAMP_1_MS,
+        location=Location.EXTERNAL,
+        event_type=HistoryEventType.RECEIVE,
+        event_subtype=HistoryEventSubType.NONE,
+        asset=A_WBTC,
+        balance=Balance(amount=ONE),
+    ), EvmEvent(
+        tx_hash=tx_hash,
+        sequence_index=1,
+        timestamp=TIMESTAMP_1_MS,
+        location=Location.ETHEREUM,
+        event_type=HistoryEventType.TRADE,
+        event_subtype=HistoryEventSubType.SPEND,
+        asset=A_WBTC,
+        balance=Balance(amount=FVal(swap_amount_str)),
+        location_label=user_address,
+        notes=f'Swap {swap_amount_str} WBTC in cowswap',
+        counterparty=CPT_COWSWAP,
+        address=contract_address,
+    ), EvmEvent(
+        tx_hash=tx_hash,
+        sequence_index=2,
+        timestamp=TIMESTAMP_1_MS,
+        location=Location.ETHEREUM,
+        event_type=HistoryEventType.TRADE,
+        event_subtype=HistoryEventSubType.RECEIVE,
+        asset=A_USDC,
+        balance=Balance(amount=FVal(receive_amount_str)),
+        location_label=user_address,
+        notes=f'Receive {receive_amount_str} USDC as the result of a swap in cowswap',
+        counterparty=CPT_COWSWAP,
+        address=contract_address,
+    ), ValidatorDailyStats(
+        validator_index=1,
+        timestamp=Timestamp(2),
+        pnl=FVal('0.1'),
+    )]
+    accounting_history_process(accountant, Timestamp(0), Timestamp(1635314397), history)
+    no_message_errors(accountant.msg_aggregator)
+    missing_acquisitions = accountant.pots[0].cost_basis.missing_acquisitions
+    assert missing_acquisitions == []
diff --git a/rotkehlchen/tests/utils/accounting.py b/rotkehlchen/tests/utils/accounting.py
--- a/rotkehlchen/tests/utils/accounting.py
+++ b/rotkehlchen/tests/utils/accounting.py
@@ -8,13 +8,13 @@
 from rotkehlchen.accounting.mixins.event import AccountingEventMixin, AccountingEventType
 from rotkehlchen.accounting.pnl import PNL, PnlTotals
 from rotkehlchen.accounting.structures.processed_event import ProcessedAccountingEvent
-from rotkehlchen.constants import ZERO
-from rotkehlchen.constants.assets import A_BTC, A_ETH, A_EUR
+from rotkehlchen.constants import ONE, ZERO
+from rotkehlchen.constants.assets import A_BTC, A_ETH, A_EUR, A_USDC, A_WBTC
 from rotkehlchen.db.filtering import ReportDataFilterQuery
 from rotkehlchen.db.reports import DBAccountingReports
 from rotkehlchen.exchanges.data_structures import Trade
 from rotkehlchen.fval import FVal
-from rotkehlchen.types import AssetAmount, Fee, Location, Price, Timestamp, TradeType
+from rotkehlchen.types import AssetAmount, Fee, Location, Price, Timestamp, TimestampMS, TradeType
 from rotkehlchen.utils.version_check import get_current_version
 
 if TYPE_CHECKING:
@@ -24,6 +24,23 @@
     from rotkehlchen.tests.fixtures.google import GoogleService
 
 
+TIMESTAMP_1_MS = TimestampMS(1000)
+TIMESTAMP_1_SEC = Timestamp(1)
+
+MOCKED_PRICES = {
+    A_WBTC.identifier: {
+        'EUR': {
+            TIMESTAMP_1_SEC: Price(ONE),
+        },
+    },
+    A_USDC.identifier: {
+        'EUR': {
+            TIMESTAMP_1_SEC: Price(ONE),
+        },
+    },
+}
+
+
 history1 = [
     Trade(
         timestamp=Timestamp(1446979735),