Repository: Chia-Network/chia-blockchain
Pull request: Check AttributeError for non-Optional members during node shutdown
During node shutdown some AttributeErrors could be thrown if the shutdown happens before the node fully started up. Checks against None are not applicable as the attributes in question were not declared Optional and not initialized to None. Added hasattr checks
See #7553 

Problem statement:
[BUG] AttributeError: 'FullNode' object has no attribute 'blockchain'
**To Reproduce**
OS Version: Freebsd 12.2 Release P9
Built From source following wiki guide, using python3.8 instead of 3.7 and clvm_rs 0.1.8
Chia version: Latest - 1.2.3.dev0

**Expected behavior**
Probably shouldn't have a traceback why trying to stop the full node

**Screenshots**
```
(venv) [root@chia ~/chia-1.2.2/chia-blockchain]# chia start farmer -r
chia_harvester: stopped
chia_harvester: started
chia_farmer: stopped
chia_farmer: started
chia_full_node: Traceback (most recent call last):
  File "/root/chia-1.2.2/chia-blockchain/venv/bin/chia_full_node", line 33, in <module>
    sys.exit(load_entry_point('chia-blockchain', 'console_scripts', 'chia_full_node')())
  File "/root/chia-1.2.2/chia-blockchain/chia/server/start_full_node.py", line 60, in main
    return run_service(**kwargs)
  File "/root/chia-1.2.2/chia-blockchain/chia/server/start_service.py", line 255, in run_service
    return asyncio.run(async_run_service(*args, **kwargs))
  File "/usr/local/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 1823, in _run_once
    event_list = self._selector.select(timeout)
  File "/usr/local/lib/python3.8/selectors.py", line 558, in select
    kev_list = self._selector.control(None, max_ev, timeout)
  File "/root/chia-1.2.2/chia-blockchain/chia/server/start_service.py", line 193, in _accept_signal
    self.stop()
  File "/root/chia-1.2.2/chia-blockchain/chia/server/start_service.py", line 210, in stop
    self._node._close()
  File "/root/chia-1.2.2/chia-blockchain/chia/full_node/full_node.py", line 561, in _close
    if self.blockchain is not None:
AttributeError: 'FullNode' object has no attribute 'blockchain'
stopped
chia_full_node: started
chia_wallet: stopped
chia_wallet: started
```

Rebuilt after updating my jails and had to make some changes to dependencies. When I did a restart of the farmer services I got this traceback but it seemed to stopped even with the failure and restart correctly. After the restart farming has continued and node is synced. Just the traceback when stopping is the problem it seems.

Hints from issue discussion:
it happens to me too since 1.2+ update . i just run a script with 'chia start farmer' on each system reboot, and most times full node won't start normally, so i have to restart it manually and see "AttributeError: 'FullNode' object has no attribute 'blockchain'" message upon restarting... tried to redownload and rebuild, same behavouir. system is clean ubuntu 20.04 under esxi 6.7
Same issue at
Ubuntu 20.04.2 LTS (Focal Fossa)
Chia ver.1.2.2
Seeing the same issue on Arch Linux with Chia v 1.2.3.
The same bug. Chia v. 1.2.3
Ubuntu Ubuntu 20.04.2 LTS.

Acording to this report first time this BUG was almost month ago. Still no solutions ??

Commit message: Check AttributeError for non-Optional elements

Patch to review:
diff --git a/chia/full_node/full_node.py b/chia/full_node/full_node.py
index 24781e7ce2af..24b9a998f050 100644
--- a/chia/full_node/full_node.py
+++ b/chia/full_node/full_node.py
@@ -557,10 +557,17 @@ def _close(self):
         self._shut_down = True
         if self._init_weight_proof is not None:
             self._init_weight_proof.cancel()
-        if self.blockchain is not None:
+        # blockchain is created in _start and in certain cases it may not exist here during _close
+        try:
             self.blockchain.shut_down()
-        if self.mempool_manager is not None:
+        except AttributeError:
+            pass
+        # same for mempool_manager
+        try:
             self.mempool_manager.shut_down()
+        except AttributeError:
+            pass
+
         if self.full_node_peers is not None:
             asyncio.create_task(self.full_node_peers.close())
         if self.uncompact_task is not None:


Code review comments:
diff_hunk: @@ -557,10 +557,17 @@ def _close(self):
         self._shut_down = True
         if self._init_weight_proof is not None:
             self._init_weight_proof.cancel()
-        if self.blockchain is not None:
+        # blockchain is created in _start and in certain cases it may not exist here during _close
+        try:
             self.blockchain.shut_down()
-        if self.mempool_manager is not None:
+        except AttributeError:
path: chia/full_node/full_node.py
text: @user1:
This would swallow and suppress `AttributeError`s being throw out of the `shut_down()` functions.

I would have expected something like this:

```
if self.blockchain:
    self.blockchain.shut_down()
```

instead.

@author:
Changed to hasattr