From 0fda10d4e6f4c8eef7eefc62ed997638baf5dd78 Mon Sep 17 00:00:00 2001
From: holgern <holgernahrstaedt@gmx.de>
Date: Wed, 8 Apr 2020 13:17:59 +0200
Subject: [PATCH] Add default_chain to storage

* Add get_blockchain_name to Steem, returns either steem or hive
* Add switch_blockchain to Steem, can be used to switch between hive and steem
* Storage has now a new config "default_chain", can be either hive or steem
* updatenode --hive switches to hive and use hive nodes
* updatenode --steem switches to steem and use steem nodes
---
 CHANGELOG.rst               |  5 +++
 beem/cli.py                 | 41 ++++++++++++++++------
 beem/nodelist.py            | 28 ++++++++-------
 beem/steem.py               | 70 ++++++++++++++++++++++++++++---------
 beem/storage.py             |  9 ++++-
 tests/beem/test_cli.py      |  4 +--
 tests/beem/test_nodelist.py | 18 +++++++++-
 7 files changed, 132 insertions(+), 43 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a3f1a2ae..a2c0b79b 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -8,6 +8,11 @@ Changelog
 * Add get_hive_nodes and get_steem_nodes functions to NodeList
 * beempy command resteem renamed to reblog
 * When using in shell mode, beempy walletinfo --unlock can be used to unlock the wallet and walletinfo --lock to unlock it again
+* Add get_blockchain_name to Steem, returns either steem or hive
+* Add switch_blockchain to Steem, can be used to switch between hive and steem
+* Storage has now a new config "default_chain", can be either hive or steem
+* updatenode --hive switches to hive and use hive nodes
+* updatenode --steem switches to steem and use steem nodes
 
 0.22.13
 -------
diff --git a/beem/cli.py b/beem/cli.py
index 0849598a..cfad9d5a 100644
--- a/beem/cli.py
+++ b/beem/cli.py
@@ -257,6 +257,8 @@ def set(key, value):
             stm.set_default_nodes(value)
         else:
             stm.set_default_nodes("")
+    elif key == "default_chain":
+        stm.config["default_chain"] = value
     elif key == "password_storage":
         stm.config["password_storage"] = value
         if KEYRING_AVAILABLE and value == "keyring":
@@ -418,7 +420,7 @@ def currentnode(version, url):
         t.add_row(["Node-Url", node[0]])
     if not offline:
         t.add_row(["Version", stm.get_blockchain_version()])
-        t.add_row(["HIVE", stm.is_hive])
+        t.add_row(["Chain", stm.get_blockchain_name()])
     else:
         t.add_row(["Version", "steempy is in offline mode..."])
     print(t)
@@ -430,7 +432,10 @@ def currentnode(version, url):
     help="Prints the updated nodes")
 @click.option(
     '--hive', '-h', is_flag=True, default=False,
-    help="Use only HIVE nodes, when set to true.")
+    help="Switch to HIVE blockchain, when set to true.")
+@click.option(
+    '--steem', '-e', is_flag=True, default=False,
+    help="Switch to STEEM nodes, when set to true.")
 @click.option(
     '--test', '-t', is_flag=True, default=False,
     help="Do change the node list, only print the newest nodes setup.")
@@ -440,23 +445,37 @@ def currentnode(version, url):
 @click.option(
     '--only-wss', '-w', is_flag=True, default=False,
     help="Use only websocket nodes.")
-@click.option(
-    '--only-appbase', '-a', is_flag=True, default=False,
-    help="Use only appbase nodes")
-@click.option(
-    '--only-non-appbase', '-n', is_flag=True, default=False,
-    help="Use only non-appbase nodes")
-def updatenodes(show, hive, test, only_https, only_wss, only_appbase, only_non_appbase):
+def updatenodes(show, hive, steem, test, only_https, only_wss):
     """ Update the nodelist from @fullnodeupdate
     """
     stm = shared_steem_instance()
     if stm.rpc is not None:
         stm.rpc.rpcconnect()
+    if steem and hive:
+        print("hive and steem cannot be active both")
+        return
     t = PrettyTable(["node", "Version", "score"])
     t.align = "l"
+    if steem:
+        blockchain = "steem"
+    elif hive:
+        blockchain = "hive"
+    else:
+        blockchain = stm.config["default_chain"]
     nodelist = NodeList()
     nodelist.update_nodes(steem_instance=stm)
-    nodes = nodelist.get_nodes(hive=hive, exclude_limited=False, normal=not only_appbase, appbase=not only_non_appbase, wss=not only_https, https=not only_wss)
+    if hive:
+        nodes = nodelist.get_hive_nodes(wss=not only_https, https=not only_wss)
+        if stm.config["default_chain"] == "steem":
+            stm.config["default_chain"] = "hive"
+    elif steem:
+        nodes = nodelist.get_steem_nodes(wss=not only_https, https=not only_wss)
+        if stm.config["default_chain"] == "hive":
+            stm.config["default_chain"] = "steem"    
+    elif stm.config["default_chain"] == "steem":
+        nodes = nodelist.get_steem_nodes(wss=not only_https, https=not only_wss)
+    else:
+        nodes = nodelist.get_hive_nodes(wss=not only_https, https=not only_wss)
     if show or test:
         sorted_nodes = sorted(nodelist, key=lambda node: node["score"], reverse=True)
         for node in sorted_nodes:
@@ -480,7 +499,9 @@ def config():
         if key in availableConfigurationKeys and key != "nodes" and key != "node":
             t.add_row([key, stm.config[key]])
     node = stm.get_default_nodes()
+    blockchain = stm.config["default_chain"]
     nodes = json.dumps(node, indent=4)
+    t.add_row(["default_chain", blockchain])
     t.add_row(["nodes", nodes])
     if "password_storage" not in availableConfigurationKeys:
         t.add_row(["password_storage", stm.config["password_storage"]])
diff --git a/beem/nodelist.py b/beem/nodelist.py
index a95b4581..4c90509d 100644
--- a/beem/nodelist.py
+++ b/beem/nodelist.py
@@ -50,14 +50,6 @@ class NodeList(list):
                 "hive": False,
                 "score": -10
             },
-            {
-                "url": "https://steemd.privex.io",
-                "version": "0.20.2",
-                "type": "appbase",
-                "owner": "privex",
-                "hive": False,
-                "score": 50
-            },
             {
                 "url": "https://steemd.minnowsupportproject.org",
                 "version": "0.19.12",
@@ -307,17 +299,22 @@ class NodeList(list):
 
         return [node["url"] for node in sorted(node_list, key=lambda self: self['score'], reverse=True)]
 
-    def get_hive_nodes(self, not_working=False, wss=True, https=True):
+    def get_hive_nodes(self, testnet=False, not_working=False, wss=True, https=True):
         """ Returns hive only nodes as list
 
+            :param bool testnet: when True, testnet nodes are included
             :param bool not_working: When True, all nodes including not working ones will be returned
 
         """
         node_list = []
         node_type_list = []
-
+      
         for node in self:
-            if node["hive"] and (node["score"] >= 0 or not_working):
+            if not node["hive"]:
+                continue
+            if (node["score"] < 0 and not not_working):
+                continue
+            if (testnet and node["type"] == "testnet") or (not testnet and node["type"] != "testnet"):
                 if not https and node["url"][:5] == 'https':
                     continue
                 if not wss and node["url"][:3] == 'wss':
@@ -326,9 +323,10 @@ class NodeList(list):
 
         return [node["url"] for node in sorted(node_list, key=lambda self: self['score'], reverse=True)]
 
-    def get_steem_nodes(self, not_working=False, wss=True, https=True):
+    def get_steem_nodes(self, testnet=False, not_working=False, wss=True, https=True):
         """ Returns steem only nodes as list
 
+            :param bool testnet: when True, testnet nodes are included
             :param bool not_working: When True, all nodes including not working ones will be returned
 
         """
@@ -336,7 +334,11 @@ class NodeList(list):
         node_type_list = []
 
         for node in self:
-            if not node["hive"] and (node["score"] >= 0 or not_working):
+            if node["hive"]:
+                continue
+            if (node["score"] < 0 and not not_working):
+                continue
+            if (testnet and node["type"] == "testnet") or (not testnet and node["type"] != "testnet"):            
                 if not https and node["url"][:5] == 'https':
                     continue
                 if not wss and node["url"][:3] == 'wss':
diff --git a/beem/steem.py b/beem/steem.py
index 7360620f..1fff34b4 100644
--- a/beem/steem.py
+++ b/beem/steem.py
@@ -194,22 +194,7 @@ class Steem(object):
                          rpcpassword=rpcpassword,
                          **kwargs)
 
-        self.data = {'last_refresh': None, 'last_node': None,
-                     'last_refresh_dynamic_global_properties': None,
-                     'dynamic_global_properties': None,
-                     'feed_history': None,
-                     'get_feed_history': None,
-                     'last_refresh_feed_history': None,
-                     'hardfork_properties': None,
-                     'last_refresh_hardfork_properties': None,
-                     'network': None,
-                     'last_refresh_network': None,
-                     'witness_schedule': None,
-                     'last_refresh_witness_schedule': None,
-                     'config': None,
-                     'last_refresh_config': None,
-                     'reward_funds': None,
-                     'last_refresh_reward_funds': None}
+        self.clear_data()
         self.data_refresh_time_seconds = data_refresh_time_seconds
         # self.refresh_data()
 
@@ -264,6 +249,25 @@ class Steem(object):
             return "<%s, nobroadcast=%s>" % (
                 self.__class__.__name__, str(self.nobroadcast))
 
+    def clear_data(self):
+        """ Clears all stored blockchain parameters"""
+        self.data = {'last_refresh': None, 'last_node': None,
+                     'last_refresh_dynamic_global_properties': None,
+                     'dynamic_global_properties': None,
+                     'feed_history': None,
+                     'get_feed_history': None,
+                     'last_refresh_feed_history': None,
+                     'hardfork_properties': None,
+                     'last_refresh_hardfork_properties': None,
+                     'network': None,
+                     'last_refresh_network': None,
+                     'witness_schedule': None,
+                     'last_refresh_witness_schedule': None,
+                     'config': None,
+                     'last_refresh_config': None,
+                     'reward_funds': None,
+                     'last_refresh_reward_funds': None}        
+
     def refresh_data(self, property, force_refresh=False, data_refresh_time_seconds=None):
         """ Read and stores steem blockchain parameters
             If the last data refresh is older than data_refresh_time_seconds, data will be refreshed
@@ -511,6 +515,17 @@ class Steem(object):
                 blockchain_version = props[key]
         return blockchain_version
 
+    def get_blockchain_name(self, use_stored_data=True):
+        """Returns the blockchain version"""
+        props = self.get_config(use_stored_data=use_stored_data)
+        blockchain_name = ''
+        if props is None:
+            return blockchain_version
+        for key in props:
+            if key[-18:] == "BLOCKCHAIN_VERSION":
+                blockchain_name = key.split("_")[0].lower()
+        return blockchain_name
+
     def get_dust_threshold(self, use_stored_data=True):
         """Returns the vote dust threshold"""
         props = self.get_config(use_stored_data=use_stored_data)
@@ -893,6 +908,29 @@ class Steem(object):
         Account(account, steem_instance=self)
         self.config["default_account"] = account
 
+    def switch_blockchain(self, blockchain, update_nodes=False):
+        """ Switches the connected blockchain. Can be either hive or steem.
+
+            :param str blockchain: can be "hive" or "steem"
+            :param bool update_nodes: When true, the nodes are updated, using
+                NodeList.update_nodes()
+        """
+        assert blockchain in ["hive", "steem"]
+        if blockchain == self.config["default_chain"] and not update_nodes:
+            return
+        from beem.nodelist import NodeList
+        nodelist = NodeList()
+        if update_nodes:
+            nodelist.update_nodes()
+        if blockchain == "hive":
+            self.set_default_nodes(nodelist.get_hive_nodes())
+        else:
+            self.set_default_nodes(nodelist.get_steem_nodes())
+        self.config["default_chain"] = blockchain
+        if not self.offline:
+            self.connect(node="")
+        
+
     def set_password_storage(self, password_storage):
         """ Set the password storage mode.
 
diff --git a/beem/storage.py b/beem/storage.py
index 87b6cb6e..8c0a51cf 100644
--- a/beem/storage.py
+++ b/beem/storage.py
@@ -404,9 +404,16 @@ class Configuration(DataDir):
 
     #: Default configuration
     nodelist = NodeList()
-    nodes = nodelist.get_nodes(normal=True, appbase=True, dev=False, testnet=False)
+    blockchain = "steem" # will be changed to hive in the next release
+    if blockchain == "hive":
+        nodes = nodelist.get_hive_nodes(testnet=False)
+    elif blockchain == "steem":
+        nodes = nodelist.get_steem_nodes(testnet=False)
+    else:
+        nodes = []
     config_defaults = {
         "node": nodes,
+        "default_chain": blockchain,
         "password_storage": "environment",
         "rpcpassword": "",
         "rpcuser": "",
diff --git a/tests/beem/test_cli.py b/tests/beem/test_cli.py
index 90a53735..33af36fd 100644
--- a/tests/beem/test_cli.py
+++ b/tests/beem/test_cli.py
@@ -322,9 +322,9 @@ class Testcases(unittest.TestCase):
         result = runner.invoke(cli, ['openorders'])
         self.assertEqual(result.exit_code, 0)
 
-    def test_resteem(self):
+    def test_reblog(self):
         runner = CliRunner()
-        result = runner.invoke(cli, ['-dto', 'resteem', '@steemit/firstposte'], input="test\n")
+        result = runner.invoke(cli, ['-dto', 'reblog', '@steemit/firstpost'], input="test\n")
         self.assertEqual(result.exit_code, 0)
 
     def test_follow_unfollow(self):
diff --git a/tests/beem/test_nodelist.py b/tests/beem/test_nodelist.py
index 6bd1eebb..baf1fd80 100644
--- a/tests/beem/test_nodelist.py
+++ b/tests/beem/test_nodelist.py
@@ -15,7 +15,7 @@ class Testcases(unittest.TestCase):
     def setUpClass(cls):
         nodelist = NodeList()
         cls.bts = Steem(
-            node=nodelist.get_nodes(exclude_limited=False),
+            node=nodelist.get_nodes(),
             nobroadcast=True,
             num_retries=10
         )
@@ -28,6 +28,22 @@ class Testcases(unittest.TestCase):
         https_nodes = nodelist.get_nodes(wss=False)
         self.assertEqual(https_nodes[0][:5], 'https')
 
+    def test_hive_nodes(self):
+        nodelist = NodeList()
+        nodelist.update_nodes()
+        hive_nodes = nodelist.get_hive_nodes()
+        for node in hive_nodes:
+            blockchainobject = Steem(node=node)
+            assert blockchainobject.is_hive
+
+    def test_steem_nodes(self):
+        nodelist = NodeList()
+        nodelist.update_nodes()
+        steem_nodes = nodelist.get_steem_nodes()
+        for node in steem_nodes:
+            blockchainobject = Steem(node=node)
+            assert not blockchainobject.is_hive
+
     def test_nodes_update(self):
         nodelist = NodeList()
         all_nodes = nodelist.get_nodes(exclude_limited=False, dev=True, testnet=True)
-- 
GitLab