Compare commits
	
		
			No commits in common. "main" and "c0d64201a802ae373415fce17cde5334950a16da" have entirely different histories.
		
	
	
		
			main
			...
			c0d64201a8
		
	
		
							
								
								
									
										19
									
								
								__init__.py
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								__init__.py
									
									
									
									
									
								
							| @ -1 +1,20 @@ | ||||
| from electrum.i18n import _ | ||||
| import subprocess | ||||
| from . import bal_resources | ||||
| BUILD_NUMBER = 1  | ||||
| REVISION_NUMBER = 1 | ||||
| VERSION_NUMBER = 0 | ||||
| def _version(): | ||||
|     return f'{VERSION_NUMBER}.{REVISION_NUMBER}-{BUILD_NUMBER}' | ||||
| 
 | ||||
| version = _version() | ||||
| author = "Bal Enterprise inc." | ||||
| fullname = _('B.A.L.') | ||||
| description = ''.join([ | ||||
|     "<img src='",bal_resources.icon_path('bal16x16.png'),"'>", _("Bitcoin After Life"), '<br/>', | ||||
|     _("For more information, visit"), | ||||
|     " <a href=\"https://bitcoin-after.life/\">https://bitcoin-after.life/</a><br/>", | ||||
|     "<p style='font-size:8pt;vertialAlign:bottom'>Version: ", _version(),"</p>" | ||||
| ]) | ||||
| #available_for = ['qt', 'cmdline', 'qml'] | ||||
| available_for = ['qt'] | ||||
|  | ||||
							
								
								
									
										160
									
								
								bal.py
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								bal.py
									
									
									
									
									
								
							| @ -1,128 +1,126 @@ | ||||
| import random | ||||
| import os | ||||
| import zipfile as zipfile_lib | ||||
| from hashlib import sha256 | ||||
| from typing import NamedTuple, Optional, Dict, Tuple | ||||
| 
 | ||||
| from electrum.plugin import BasePlugin | ||||
| from electrum.util import to_bytes, bfh | ||||
| from electrum import json_db | ||||
| from electrum.transaction import tx_from_any | ||||
| 
 | ||||
| from . import util as Util | ||||
| from . import willexecutors as Willexecutors | ||||
| import os | ||||
| json_db.register_dict('heirs', tuple, None) | ||||
| json_db.register_dict('will', lambda x: get_will(x), None) | ||||
| json_db.register_dict('will_settings', lambda x:x, None) | ||||
| 
 | ||||
| from electrum.logging import get_logger | ||||
| 
 | ||||
| def get_will(x): | ||||
|     try: | ||||
|         #print("______________________________________________________________________________________________________") | ||||
|         #print(x) | ||||
|         x['tx']=tx_from_any(x['tx']) | ||||
|     except Exception as e: | ||||
|         #Util.print_var(x) | ||||
|         raise e | ||||
| 
 | ||||
|     return x | ||||
| 
 | ||||
| class BalConfig(): | ||||
|     def __init__(self, config, name, default): | ||||
|         self.config = config | ||||
|         self.name = name | ||||
|         self.default = default | ||||
| 
 | ||||
|     def get(self,default=None): | ||||
|         v = self.config.get(self.name, default) | ||||
|         if v is None: | ||||
|             if not default is None: | ||||
|                 v = default | ||||
|             else: | ||||
|                 v = self.default | ||||
|         return v | ||||
|      | ||||
|     def set(self,value,save=True): | ||||
|         self.config.set_key(self.name,value,save=save) | ||||
| 
 | ||||
| class BalPlugin(BasePlugin): | ||||
|     LATEST_VERSION = '1' | ||||
|     KNOWN_VERSIONS = ('0', '1') | ||||
|     assert LATEST_VERSION in KNOWN_VERSIONS | ||||
|     def version(): | ||||
|         try: | ||||
|             f="" | ||||
|             with open("VERSION","r") as f: | ||||
|                 f = str(f.readline()) | ||||
|             return f | ||||
|         except: | ||||
|             return "unknown" | ||||
|     SIZE = (159, 97) | ||||
|     LOCKTIME_TIME = "bal_locktime_time" | ||||
|     LOCKTIME_BLOCKS = "bal_locktime_blocks" | ||||
|     LOCKTIMEDELTA_TIME = "bal_locktimedelta_time" | ||||
|     LOCKTIMEDELTA_BLOCKS = "bal_locktimedelta_blocks" | ||||
|     TX_FEES = "bal_tx_fees" | ||||
|     BROADCAST = "bal_broadcast" | ||||
|     ASK_BROADCAST = "bal_ask_broadcast" | ||||
|     INVALIDATE = "bal_invalidate" | ||||
|     ASK_INVALIDATE = "bal_ask_invalidate" | ||||
|     PREVIEW = "bal_preview" | ||||
|     SAVE_TXS = "bal_save_txs" | ||||
|     WILLEXECUTORS = "bal_willexecutors" | ||||
|     PING_WILLEXECUTORS = "bal_ping_willexecutors" | ||||
|     ASK_PING_WILLEXECUTORS = "bal_ask_ping_willexecutors" | ||||
|     NO_WILLEXECUTOR = "bal_no_willexecutor" | ||||
|     HIDE_REPLACED = "bal_hide_replaced" | ||||
|     HIDE_INVALIDATED = "bal_hide_invalidated" | ||||
|     ALLOW_REPUSH = "bal_allow_repush" | ||||
| 
 | ||||
|     def __init__(self, parent, config, name): | ||||
|         self.logger = get_logger(__name__) | ||||
|         BasePlugin.__init__(self, parent, config, name) | ||||
|         self.base_dir = os.path.join(config.electrum_path(), 'bal') | ||||
|         self.plugin_dir = os.path.split(os.path.realpath(__file__))[0] | ||||
|         zipfile="/".join(self.plugin_dir.split("/")[:-1]) | ||||
|         #print("real path",os.path.realpath(__file__)) | ||||
|         #self.logger.info(self.base_dir) | ||||
|         #print("base_dir:", self.base_dir) | ||||
|         #print("suca:",zipfile) | ||||
|         #print("plugin_dir:", self.plugin_dir) | ||||
|         import sys | ||||
|         sys.path.insert(0, zipfile) | ||||
|         #print("sono state listate?") | ||||
|         self.parent = parent | ||||
|         self.config = config | ||||
|         self.name = name | ||||
| 
 | ||||
|         self.ASK_BROADCAST              = BalConfig(config, "bal_ask_broadcast",            True) | ||||
|         self.BROADCAST                  = BalConfig(config, "bal_broadcast",                True) | ||||
|         self.LOCKTIME_TIME              = BalConfig(config, "bal_locktime_time",            90) | ||||
|         self.LOCKTIME_BLOCKS            = BalConfig(config, "bal_locktime_blocks",          144*90) | ||||
|         self.LOCKTIMEDELTA_TIME         = BalConfig(config, "bal_locktimedelta_time",       7) | ||||
|         self.LOCKTIMEDELTA_BLOCKS       = BalConfig(config, "bal_locktimedelta_blocks",     144*7) | ||||
|         self.ENABLE_MULTIVERSE          = BalConfig(config, "bal_enable_multiverse",        False) | ||||
|         self.TX_FEES                    = BalConfig(config, "bal_tx_fees",                  100) | ||||
|         self.INVALIDATE                 = BalConfig(config, "bal_invalidate",               True) | ||||
|         self.ASK_INVALIDATE             = BalConfig(config, "bal_ask_invalidate",           True) | ||||
|         self.PREVIEW                    = BalConfig(config, "bal_preview",                  True) | ||||
|         self.SAVE_TXS                   = BalConfig(config, "bal_save_txs",                 True) | ||||
|         self.WILLEXECUTORS              = BalConfig(config, "bal_willexecutors",            True) | ||||
|         self.PING_WILLEXECUTORS         = BalConfig(config, "bal_ping_willexecutors",       True) | ||||
|         self.ASK_PING_WILLEXECUTORS     = BalConfig(config, "bal_ask_ping_willexecutors",   True) | ||||
|         self.NO_WILLEXECUTOR            = BalConfig(config, "bal_no_willexecutor",          True)  | ||||
|         self.HIDE_REPLACED              = BalConfig(config, "bal_hide_replaced",            True) | ||||
|         self.HIDE_INVALIDATED           = BalConfig(config, "bal_hide_invalidated",         True) | ||||
|         self.ALLOW_REPUSH               = BalConfig(config, "bal_allow_repush",             True) | ||||
|         self.FIRST_EXECUTION            = BalConfig(config, "bal_first_execution",          True) | ||||
|         self.WILLEXECUTORS              = BalConfig(config, "bal_willexecutors", { | ||||
|                                                                 "mainnet":  { | ||||
|                                                                     'https://we.bitcoin-after.life': { | ||||
| 
 | ||||
|     DEFAULT_SETTINGS={ | ||||
|         LOCKTIME_TIME: 90, | ||||
|         LOCKTIME_BLOCKS: 144*90, | ||||
|         LOCKTIMEDELTA_TIME: 7, | ||||
|         LOCKTIMEDELTA_BLOCKS:144*7, | ||||
|         TX_FEES: 100, | ||||
|         BROADCAST: True, | ||||
|         ASK_BROADCAST: True, | ||||
|         INVALIDATE: True, | ||||
|         ASK_INVALIDATE: True, | ||||
|         PREVIEW: True, | ||||
|         SAVE_TXS: True, | ||||
|         PING_WILLEXECUTORS: False, | ||||
|         ASK_PING_WILLEXECUTORS: False, | ||||
|         NO_WILLEXECUTOR: False, | ||||
|         HIDE_REPLACED:True, | ||||
|         HIDE_INVALIDATED:True, | ||||
|         ALLOW_REPUSH: False, | ||||
|         WILLEXECUTORS:  { | ||||
|             'http://bitcoin-after.life:9137': { | ||||
|                 "base_fee": 100000, | ||||
|                 "status": "New", | ||||
|                 "info":"Bitcoin After Life Will Executor", | ||||
|                 "address":"bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7", | ||||
|                 "selected":True | ||||
|             } | ||||
|         }, | ||||
|     } | ||||
|                                                             }) | ||||
|         self.WILL_SETTINGS              = BalConfig(config, "bal_will_settings", { | ||||
|                                                                 'tx_fees':100,  | ||||
|                                                                 'threshold':'180d', | ||||
|                                                                 'locktime':'1y', | ||||
|                                                             }) | ||||
| 
 | ||||
|     LATEST_VERSION = '1' | ||||
|     KNOWN_VERSIONS = ('0', '1') | ||||
|     assert LATEST_VERSION in KNOWN_VERSIONS | ||||
| 
 | ||||
|         self._hide_invalidated= self.HIDE_INVALIDATED.get() | ||||
|         self._hide_replaced= self.HIDE_REPLACED.get() | ||||
|     SIZE = (159, 97) | ||||
| 
 | ||||
|     def __init__(self, parent, config, name): | ||||
|         self.logger= get_logger(__name__) | ||||
|         BasePlugin.__init__(self, parent, config, name) | ||||
|         self.base_dir = os.path.join(config.electrum_path(), 'bal') | ||||
|         self.logger.info(self.base_dir) | ||||
|         self.parent = parent | ||||
|         self.config = config | ||||
|         self.name = name | ||||
|         self._hide_invalidated= self.config_get(self.HIDE_INVALIDATED) | ||||
|         self._hide_replaced= self.config_get(self.HIDE_REPLACED) | ||||
|         self.plugin_dir = os.path.split(os.path.realpath(__file__))[0] | ||||
| 
 | ||||
|     def resource_path(self,*parts): | ||||
|         return os.path.join(self.plugin_dir, *parts) | ||||
| 
 | ||||
|     def config_get(self,key): | ||||
|         v = self.config.get(key,None) | ||||
|         if v is None: | ||||
|             self.config.set_key(key,self.DEFAULT_SETTINGS[key],save=True) | ||||
|             v = self.DEFAULT_SETTINGS[key] | ||||
|         return v | ||||
| 
 | ||||
|     def hide_invalidated(self): | ||||
|         self._hide_invalidated = not self._hide_invalidated | ||||
|         self.HIDE_INVALIDATED.set(self._hide_invalidated) | ||||
|         self.config.set_key(BalPlugin.HIDE_INVALIDATED,self.hide_invalidated,save=True) | ||||
| 
 | ||||
|     def hide_replaced(self): | ||||
|         self._hide_replaced = not self._hide_replaced | ||||
|         self.HIDE_REPLACED.set(self._hide_replaced) | ||||
|         self.config.set_key(BalPlugin.HIDE_REPLACED,self.hide_invalidated,save=True) | ||||
| 
 | ||||
|     def default_will_settings(self): | ||||
|         return { | ||||
|             'tx_fees':100,  | ||||
|             'threshold':'180d', | ||||
|             'locktime':'1y', | ||||
|         } | ||||
|     def validate_will_settings(self,will_settings): | ||||
|         if int(will_settings.get('tx_fees',1))<1: | ||||
|             will_settings['tx_fees']=1 | ||||
|  | ||||
| @ -2,7 +2,7 @@ import os | ||||
| 
 | ||||
| PLUGIN_DIR = os.path.split(os.path.realpath(__file__))[0] | ||||
| DEFAULT_ICON = 'bal32x32.png' | ||||
| DEFAULT_ICON_PATH = '' | ||||
| DEFAULT_ICON_PATH = 'icons' | ||||
| 
 | ||||
| 
 | ||||
| def icon_path(icon_basename: str = DEFAULT_ICON): | ||||
|  | ||||
| @ -95,8 +95,25 @@ class bal_checkbox(QCheckBox): | ||||
|     def __init__(self, plugin,variable,window=None): | ||||
|         QCheckBox.__init__(self) | ||||
|         self.setChecked(plugin.config_get(variable)) | ||||
|         window=window | ||||
|         def on_check(v): | ||||
|             plugin.config.set_key(variable,  v == 2) | ||||
|             plugin.config_get(variable) | ||||
|             plugin.config.set_key(variable, v == Qt.CheckState.Checked, save=True) | ||||
|             if window: | ||||
|                 plugin._hide_invalidated= plugin.config_get(plugin.HIDE_INVALIDATED) | ||||
|                 plugin._hide_replaced= plugin.config_get(plugin.HIDE_REPLACED) | ||||
| 
 | ||||
|                 window.update_all() | ||||
|         self.stateChanged.connect(on_check) | ||||
| 
 | ||||
|     #TODO IMPLEMENT PREVIEW DIALOG | ||||
|     #tx list display txid, willexecutor, qrcode, button to sign | ||||
|     #   :def preview_dialog(self, txs): | ||||
|     def preview_dialog(self, txs): | ||||
|         w=PreviewDialog(self,txs) | ||||
|         w.exec() | ||||
|         return w | ||||
|     def add_info_from_will(self,tx): | ||||
|         for input in tx.inputs(): | ||||
|             pass | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -225,7 +225,7 @@ class BalCloseDialog(BalDialog): | ||||
|             #self._stopping=True | ||||
|             #self.on_success_phase2() | ||||
|         #   return | ||||
|         _logger.debug("have to sign {}".format(self.have_to_sign)) | ||||
|         _logger.debug("have to sign",self.have_to_sign) | ||||
|         password=None | ||||
|         if self.have_to_sign is None: | ||||
|             self.msg_set_invalidating() | ||||
|  | ||||
| @ -199,6 +199,7 @@ class WillExecutorDialog(BalDialog,MessageBoxMixin): | ||||
|     def __init__(self, bal_window): | ||||
|         BalDialog.__init__(self,bal_window.window) | ||||
|         self.bal_plugin = bal_window.bal_plugin | ||||
|         self.gui_object = self.bal_plugin.gui_object | ||||
|         self.config = self.bal_plugin.config | ||||
|         self.window = bal_window.window | ||||
|         self.bal_window = bal_window | ||||
|  | ||||
							
								
								
									
										18
									
								
								heirs.py
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								heirs.py
									
									
									
									
									
								
							| @ -14,8 +14,9 @@ from electrum.transaction import PartialTxInput, PartialTxOutput,TxOutpoint,Part | ||||
| import datetime | ||||
| import urllib.request | ||||
| import urllib.parse | ||||
| from .util import Util | ||||
| from .willexecutors import Willexecutors | ||||
| from .bal import BalPlugin | ||||
| from . import util as Util | ||||
| from . import willexecutors as Willexecutors | ||||
| if TYPE_CHECKING: | ||||
|     from .wallet_db import WalletDB | ||||
|     from .simple_config import SimpleConfig | ||||
| @ -37,7 +38,6 @@ def reduce_outputs(in_amount, out_amount, fee, outputs): | ||||
|         for output in outputs: | ||||
|             output.value = math.floor((in_amount-fee)/out_amount * output.value) | ||||
| 
 | ||||
| """ | ||||
| #TODO: put this method inside wallet.db to replace or complete get_locktime_for_new_transaction | ||||
| def get_current_height(network:'Network'): | ||||
|     #if no network or not up to date, just set locktime to zero | ||||
| @ -57,7 +57,7 @@ def get_current_height(network:'Network'): | ||||
|     # discourage "fee sniping" | ||||
|     height = min(chain_height, server_height) | ||||
|     return height | ||||
| """ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @ -386,7 +386,7 @@ class Heirs(dict, Logger): | ||||
|             utxos = wallet.get_utxos() | ||||
|         willexecutors = Willexecutors.get_willexecutors(bal_plugin) or {} | ||||
|         self.decimal_point=bal_plugin.config.get_decimal_point() | ||||
|         no_willexecutors = bal_plugin.NO_WILLEXECUTOR.get() | ||||
|         no_willexecutors = bal_plugin.config_get(BalPlugin.NO_WILLEXECUTOR) | ||||
|         for utxo in utxos: | ||||
|             if utxo.value_sats()> 0*tx_fees: | ||||
|                 balance += utxo.value_sats() | ||||
| @ -563,7 +563,10 @@ class Heirs(dict, Logger): | ||||
| 
 | ||||
|     def validate_amount(amount): | ||||
|         try: | ||||
|             famount = float(amount[:-1]) if Util.is_perc(amount) else float(amount) | ||||
|             if Util.is_perc(amount): | ||||
|                 famount = float(amount[:-1]) | ||||
|             else: | ||||
|                 famount = float(amount) | ||||
|             if famount <= 0.00000001: | ||||
|                 raise AmountNotValid(f"amount have to be positive {famount} < 0") | ||||
|         except Exception as e: | ||||
| @ -572,8 +575,9 @@ class Heirs(dict, Logger): | ||||
| 
 | ||||
|     def validate_locktime(locktime,timestamp_to_check=False): | ||||
|         try: | ||||
|             locktime = Util.parse_locktime_string(locktime,None) | ||||
|             if timestamp_to_check: | ||||
|                 if Util.parse_locktime_string(locktime,None) < timestamp_to_check: | ||||
|                 if locktime < timestamp_to_check: | ||||
|                     raise HeirExpiredException() | ||||
|         except Exception as e: | ||||
|             raise LocktimeNotValid(f"locktime string not properly formatted, {e}") | ||||
|  | ||||
| @ -1,9 +0,0 @@ | ||||
| { | ||||
|  "name": "BAL", | ||||
|  "fullname": "Bitcoin After Life", | ||||
|  "description": "Provides free and decentralized inheritance support<br> Version: 0.2.2a", | ||||
|  "author":"Svatantrya", | ||||
|  "available_for": ["qt"], | ||||
|  "icon":"icons/bal32x32.png" | ||||
|  } | ||||
| 
 | ||||
							
								
								
									
										81
									
								
								util.py
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								util.py
									
									
									
									
									
								
							| @ -8,7 +8,6 @@ import urllib.parse | ||||
| from electrum.util import write_json_file,FileImportFailed,FileExportFailed | ||||
| 
 | ||||
| LOCKTIME_THRESHOLD = 500000000 | ||||
| class Util: | ||||
| def locktime_to_str(locktime): | ||||
|     try: | ||||
|         locktime=int(locktime) | ||||
| @ -17,6 +16,7 @@ class Util: | ||||
|             return dt | ||||
| 
 | ||||
|     except Exception as e: | ||||
|         #print(e) | ||||
|         pass | ||||
|     return str(locktime) | ||||
| 
 | ||||
| @ -27,6 +27,7 @@ class Util: | ||||
|         else: return int(locktime) | ||||
|     except Exception as e: | ||||
|         pass | ||||
|         #print(e) | ||||
|     dt_object = datetime.fromisoformat(locktime) | ||||
|     timestamp = dt_object.timestamp() | ||||
|     return int(timestamp) | ||||
| @ -37,6 +38,7 @@ class Util: | ||||
|   | ||||
|     except Exception as e:  | ||||
|         pass | ||||
|         #print("parse_locktime_string",e)  | ||||
|     try:  | ||||
|         now = datetime.now()  | ||||
|         if locktime[-1] == 'y':  | ||||
| @ -47,11 +49,12 @@ class Util: | ||||
|             locktime = int(locktime[:-1])  | ||||
|             height = 0  | ||||
|             if w:  | ||||
|                     height = Util.get_current_height(w.network)  | ||||
|                 height = get_current_height(w.network)  | ||||
|             locktime+=int(height)  | ||||
|         return int(locktime)  | ||||
|     except Exception as e:  | ||||
|             pass | ||||
|         print("parse_locktime_string",e)  | ||||
|         #raise e | ||||
|     return 0 | ||||
| 
 | ||||
| 
 | ||||
| @ -59,7 +62,7 @@ class Util: | ||||
|     return int(seconds + minutes*60 + hours*60*60 + days*60*60*24 + blocks * 600) | ||||
| 
 | ||||
| def encode_amount(amount, decimal_point): | ||||
|         if Util.is_perc(amount): | ||||
|     if is_perc(amount): | ||||
|         return amount | ||||
|     else: | ||||
|         try: | ||||
| @ -68,7 +71,7 @@ class Util: | ||||
|             return 0 | ||||
| 
 | ||||
| def decode_amount(amount,decimal_point): | ||||
|         if Util.is_perc(amount): | ||||
|     if is_perc(amount): | ||||
|         return amount | ||||
|     else: | ||||
|         num=8-decimal_point | ||||
| @ -108,6 +111,7 @@ class Util: | ||||
|     return False | ||||
| 
 | ||||
| def search_heir_by_values(heirs,heir,values): | ||||
|     #print() | ||||
|     for h,v in heirs.items(): | ||||
|         found = False | ||||
|         for val in values: | ||||
| @ -129,12 +133,13 @@ class Util: | ||||
|         if (exclude_willexecutors and not "w!ll3x3c\"" in heira) or not exclude_willexecutors: | ||||
|             found = False | ||||
|             for heirb in heirsb: | ||||
|                     if Util.cmp_heir_by_values(heirsa[heira],heirsb[heirb],values): | ||||
|                 if cmp_heir_by_values(heirsa[heira],heirsb[heirb],values): | ||||
|                     found=True | ||||
|             if not found: | ||||
|                 #print(f"not_found {heira}--{heirsa[heira]}") | ||||
|                 return False | ||||
|     if reverse: | ||||
|             return Util.cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False) | ||||
|         return cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False) | ||||
|     else: | ||||
|         return True | ||||
|      | ||||
| @ -143,10 +148,10 @@ class Util: | ||||
|         for heir in heirsa: | ||||
|             if not "w!ll3x3c\"" in heir: | ||||
|                 if not heir in heirsb or not cmp_function(heirsa[heir],heirsb[heir]): | ||||
|                         if not Util.search_heir_by_values(heirsb,heirsa[heir],[0,3]): | ||||
|                     if not search_heir_by_values(heirsb,heirsa[heir],[0,3]): | ||||
|                         return False | ||||
|         if reverse: | ||||
|                 return Util.cmp_heirs(heirsb,heirsa,cmp_function,False) | ||||
|             return cmp_heirs(heirsb,heirsa,cmp_function,False) | ||||
|         else: | ||||
|             return True | ||||
|     except Exception as e: | ||||
| @ -157,7 +162,7 @@ class Util: | ||||
|     if len(inputsa) != len(inputsb):  | ||||
|         return False  | ||||
|     for inputa in inputsa: | ||||
|             if not Util.in_utxo(inputa,inputsb): | ||||
|         if not in_utxo(inputa,inputsb): | ||||
|             return False | ||||
|     return True | ||||
| 
 | ||||
| @ -165,15 +170,15 @@ class Util: | ||||
|     if len(outputsa) != len(outputsb):  | ||||
|         return False  | ||||
|     for outputa in outputsa:  | ||||
|             if not Util.cmp_output(outputa,willexecutor_output): | ||||
|                 if not Util.in_output(outputa,outputsb):  | ||||
|         if not cmp_output(outputa,willexecutor_output): | ||||
|             if not in_output(outputa,outputsb):  | ||||
|                 return False | ||||
|     return True | ||||
| 
 | ||||
| def cmp_txs(txa,txb): | ||||
|         if not Util.cmp_inputs(txa.inputs(),txb.inputs()): | ||||
|     if not cmp_inputs(txa.inputs(),txb.inputs()): | ||||
|         return False | ||||
|         if not Util.cmp_outputs(txa.outputs(),txb.outputs()): | ||||
|     if not cmp_outputs(txa.outputs(),txb.outputs()): | ||||
|         return False | ||||
|     return True | ||||
| 
 | ||||
| @ -181,19 +186,30 @@ class Util: | ||||
|     outputsa=txa.outputs() | ||||
|     outputsb=txb.outputs() | ||||
|     value_amount = 0 | ||||
|     #if len(outputsa) != len(outputsb): | ||||
|     #    print("outputlen is different") | ||||
|     #    return False | ||||
| 
 | ||||
|     for outa in outputsa: | ||||
|             same_amount,same_address = Util.in_output(outa,txb.outputs()) | ||||
|         same_amount,same_address = in_output(outa,txb.outputs()) | ||||
|         if not (same_amount or same_address): | ||||
|             #print("outa notin txb", same_amount,same_address) | ||||
|             return False | ||||
|         if same_amount and same_address: | ||||
|             value_amount+=outa.value | ||||
|         if same_amount: | ||||
|             pass | ||||
|             #print("same amount") | ||||
|         if same_address: | ||||
|             pass | ||||
|             #print("same address") | ||||
| 
 | ||||
|     return value_amount | ||||
|     #not needed | ||||
|     #for outb in outputsb: | ||||
|     #    if not in_output(outb,txa.outputs()): | ||||
|     #        print("outb notin txb") | ||||
|     #        return False | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @ -228,8 +244,8 @@ class Util: | ||||
|         return 0 | ||||
|     strlocktime = str(locktimea) | ||||
|     strlocktimeb = str(locktimeb) | ||||
|         intlocktimea = Util.str_to_locktime(strlocktimea) | ||||
|         intlocktimeb = Util.str_to_locktime(strlocktimeb) | ||||
|     intlocktimea = str_to_locktime(strlocktimea) | ||||
|     intlocktimeb = str_to_locktime(strlocktimeb) | ||||
|     if locktimea[-1] in "ydb": | ||||
|         if locktimeb[-1] == locktimea[-1]: | ||||
|             return int(strlocktimea[-1])-int(strlocktimeb[-1]) | ||||
| @ -252,7 +268,8 @@ class Util: | ||||
|     sorted_timestamp=[] | ||||
|     sorted_block=[] | ||||
|     for l in locktimes: | ||||
|             l=Util.parse_locktime_string(l) | ||||
|         #print("locktime:",parse_locktime_string(l)) | ||||
|         l=parse_locktime_string(l) | ||||
|         if l < LOCKTIME_THRESHOLD: | ||||
|             bisect.insort(sorted_block,l) | ||||
|         else: | ||||
| @ -261,11 +278,11 @@ class Util: | ||||
|     return sorted(sorted_timestamp), sorted(sorted_block) | ||||
| 
 | ||||
| def get_lowest_locktimes_from_will(will): | ||||
|         return Util.get_lowest_locktimes(Util.get_locktimes(will)) | ||||
|     return get_lowest_locktimes(get_locktimes(will)) | ||||
| 
 | ||||
| def search_willtx_per_io(will,tx): | ||||
|     for wid, w in will.items(): | ||||
|             if Util.cmp_txs(w['tx'],tx['tx']): | ||||
|         if cmp_txs(w['tx'],tx['tx']): | ||||
|             return wid,w | ||||
|     return None, None | ||||
| 
 | ||||
| @ -287,16 +304,17 @@ class Util: | ||||
|     return str(utxo) | ||||
| 
 | ||||
| def cmp_utxo(utxoa,utxob): | ||||
|         utxoa=Util.utxo_to_str(utxoa) | ||||
|         utxob=Util.utxo_to_str(utxob) | ||||
|     utxoa=utxo_to_str(utxoa) | ||||
|     utxob=utxo_to_str(utxob) | ||||
|     if utxoa == utxob: | ||||
|     #if utxoa.prevout.txid==utxob.prevout.txid and utxoa.prevout.out_idx == utxob.prevout.out_idx: | ||||
|         return True | ||||
|     else: | ||||
|         return False | ||||
| 
 | ||||
| def in_utxo(utxo, utxos): | ||||
|     for s_u in utxos: | ||||
|             if Util.cmp_utxo(s_u,utxo): | ||||
|         if cmp_utxo(s_u,utxo): | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| @ -311,7 +329,7 @@ class Util: | ||||
| 
 | ||||
| def in_output(output,outputs): | ||||
|     for s_o in outputs: | ||||
|             if Util.cmp_output(s_o,output): | ||||
|         if cmp_output(s_o,output): | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| @ -327,9 +345,11 @@ class Util: | ||||
|         if int(out.value) == int(s_o.value): | ||||
|             same_amount.append(s_o) | ||||
|             if out.address==s_o.address: | ||||
|                 #print("SAME_:",out.address,s_o.address) | ||||
|                 return True, True | ||||
|             else: | ||||
|                 pass | ||||
|                 #print("NOT  SAME_:",out.address,s_o.address) | ||||
| 
 | ||||
|     if len(same_amount)>0: | ||||
|         return True, False | ||||
| @ -397,10 +417,11 @@ class Util: | ||||
| 
 | ||||
| def print_utxo(utxo, name = ""): | ||||
|     print(f"---utxo-{name}---") | ||||
|         Util.print_var(utxo,name) | ||||
|         Util.print_prevout(utxo.prevout,name) | ||||
|         Util.print_var(utxo.script_sig,f"{name}-script-sig") | ||||
|         Util.print_var(utxo.witness,f"{name}-witness") | ||||
|     print_var(utxo,name) | ||||
|     print_prevout(utxo.prevout,name) | ||||
|     print_var(utxo.script_sig,f"{name}-script-sig") | ||||
|     print_var(utxo.witness,f"{name}-witness") | ||||
|     #print("madonnamaiala_TXInput__scriptpubkey:",utxo._TXInput__scriptpubkey) | ||||
|     print("_TxInput__address:",utxo._TxInput__address) | ||||
|     print("_TxInput__scriptpubkey:",utxo._TxInput__scriptpubkey) | ||||
|     print("_TxInput__value_sats:",utxo._TxInput__value_sats) | ||||
| @ -408,8 +429,8 @@ class Util: | ||||
| 
 | ||||
| def print_prevout(prevout, name = ""): | ||||
|     print(f"---prevout-{name}---") | ||||
|         Util.print_var(prevout,f"{name}-prevout") | ||||
|         Util.print_var(prevout._asdict()) | ||||
|     print_var(prevout,f"{name}-prevout") | ||||
|     print_var(prevout._asdict()) | ||||
|     print(f"---prevout-end {name}---") | ||||
| 
 | ||||
| def export_meta_gui(electrum_window: 'ElectrumWindow', title, exporter): | ||||
|  | ||||
							
								
								
									
										134
									
								
								will.py
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								will.py
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| import copy | ||||
| 
 | ||||
| from .willexecutors import Willexecutors | ||||
| from .util import Util | ||||
| from . import willexecutors as Willexecutors | ||||
| from . import util as Util | ||||
| 
 | ||||
| from electrum.i18n import _ | ||||
| 
 | ||||
| @ -15,7 +15,6 @@ MIN_LOCKTIME = 1 | ||||
| MIN_BLOCK = 1 | ||||
| _logger = get_logger(__name__) | ||||
| 
 | ||||
| class Will: | ||||
| #return an array with the list of children | ||||
| def get_children(will,willid): | ||||
|     out = [] | ||||
| @ -30,7 +29,7 @@ class Will: | ||||
| #build a tree with parent transactions | ||||
| def add_willtree(will): | ||||
|     for willid in will: | ||||
|             will[willid].children = Will.get_children(will,willid) | ||||
|         will[willid].children = get_children(will,willid) | ||||
|         for child in will[willid].children: | ||||
|             if not will[child[0]].father:  | ||||
|                 will[child[0]].father = willid | ||||
| @ -66,14 +65,12 @@ class Will: | ||||
| 
 | ||||
| def add_info_from_will(will,wid,wallet): | ||||
|     if isinstance(will[wid].tx,str): | ||||
|             will[wid].tx = Will.get_tx_from_any(will[wid].tx) | ||||
|         will[wid].tx = get_tx_from_any(will[wid].tx) | ||||
|     if wallet: | ||||
|         will[wid].tx.add_info_from_wallet(wallet) | ||||
|     for txin in will[wid].tx.inputs(): | ||||
|         txid = txin.prevout.txid.hex() | ||||
|         if txid in will: | ||||
|                 #print(will[txid].tx.outputs()) | ||||
|                 #print(txin.prevout.out_idx) | ||||
|             change = will[txid].tx.outputs()[txin.prevout.out_idx] | ||||
|             txin._trusted_value_sats = change.value | ||||
|             try: | ||||
| @ -90,11 +87,8 @@ class Will: | ||||
|     to_delete = [] | ||||
|     to_add = {} | ||||
|     #add info from wallet | ||||
|         willitems={} | ||||
|     for wid in will: | ||||
|             Will.add_info_from_will(will,wid,wallet) | ||||
|             willitems[wid]=WillItem(will[wid]) | ||||
|         will=willitems | ||||
|         add_info_from_will(will,wid,wallet) | ||||
|     errors ={} | ||||
|     for wid in will: | ||||
| 
 | ||||
| @ -115,10 +109,10 @@ class Will: | ||||
|             outputs = will[wid].tx.outputs() | ||||
|             ow=will[wid] | ||||
|             ow.normalize_locktime(others_inputs) | ||||
|                 will[wid]=WillItem(ow.to_dict()) | ||||
|             will[wid]=ow.to_dict() | ||||
| 
 | ||||
|             for i in range(0,len(outputs)): | ||||
|                     Will.change_input(will,wid,i,outputs[i],others_inputs,to_delete,to_add) | ||||
|                 change_input(will,wid,i,outputs[i],others_inputs,to_delete,to_add) | ||||
| 
 | ||||
|             to_delete.append(wid) | ||||
|             to_add[ow.tx.txid()]=ow.to_dict() | ||||
| @ -147,16 +141,23 @@ class Will: | ||||
|     anticipate = Util.anticipate_locktime(ow.tx.locktime,days=1) | ||||
|     if int(nw.tx.locktime) >= int(anticipate): | ||||
|         if Util.cmp_heirs_by_values(ow.heirs,nw.heirs,[0,1],exclude_willexecutors = True): | ||||
|             print("same heirs",ow._id,nw._id) | ||||
|             if nw.we and ow.we: | ||||
|                 if ow.we['url'] == nw.we['url']: | ||||
|                     print("same willexecutors", ow.we['url'],nw.we['url']) | ||||
|                     if int(ow.we['base_fee'])>int(nw.we['base_fee']): | ||||
|                         print("anticipate") | ||||
|                         return anticipate | ||||
|                     else: | ||||
|                         if int(ow.tx_fees) != int(nw.tx_fees): | ||||
|                             return anticipate | ||||
|                         else: | ||||
|                             print("keep the same") | ||||
|                             #_logger.debug("ow,base fee > nw.base_fee") | ||||
|                             ow.tx.locktime | ||||
|                 else: | ||||
|                     #_logger.debug("ow.we['url']({ow.we['url']}) == nw.we['url']({nw.we['url']})") | ||||
|                     print("keep the same") | ||||
|                     ow.tx.locktime | ||||
|             else: | ||||
|                 if nw.we == ow.we: | ||||
| @ -187,7 +188,7 @@ class Will: | ||||
|                     if isinstance(w.tx,Transaction): | ||||
|                         will[wid].tx = PartialTransaction.from_tx(w.tx) | ||||
|                         will[wid].tx.set_rbf(True) | ||||
|                         will[wid].tx._inputs[i]=Will.new_input(wid,idx,change) | ||||
|                     will[wid].tx._inputs[i]=new_input(wid,idx,change) | ||||
|                     found = True | ||||
|             if found == True: | ||||
|                 pass | ||||
| @ -198,7 +199,7 @@ class Will: | ||||
|                 to_append[new_txid]=will[wid] | ||||
|                 outputs = will[wid].tx.outputs() | ||||
|                 for i in range(0,len(outputs)): | ||||
|                         Will.change_input(will, wid, i, outputs[i],others_inputs,to_delete,to_append) | ||||
|                     change_input(will, wid, i, outputs[i],others_inputs,to_delete,to_append) | ||||
|                      | ||||
| def get_all_inputs(will,only_valid = False): | ||||
|     all_inputs = {} | ||||
| @ -233,7 +234,7 @@ class Will: | ||||
|     redo = False | ||||
|     to_delete = [] | ||||
|     to_append = {} | ||||
|         new_inputs = Will.get_all_inputs(will,only_valid = True) | ||||
|     new_inputs = get_all_inputs(will,only_valid = True) | ||||
|     for nid,nwi in will.items(): | ||||
|         if nwi.search_anticipate(new_inputs) or nwi.search_anticipate(old_inputs): | ||||
|             if nid != nwi.tx.txid(): | ||||
| @ -242,7 +243,7 @@ class Will: | ||||
|                 to_append[nwi.tx.txid()] = nwi | ||||
|                 outputs = nwi.tx.outputs() | ||||
|                 for i in range(0,len(outputs)): | ||||
|                         Will.change_input(will,nid,i,outputs[i],new_inputs,to_delete,to_append) | ||||
|                     change_input(will,nid,i,outputs[i],new_inputs,to_delete,to_append) | ||||
|                      | ||||
| 
 | ||||
|     for w in to_delete: | ||||
| @ -253,25 +254,25 @@ class Will: | ||||
|     for k,w in to_append.items(): | ||||
|         will[k]=w | ||||
|     if redo: | ||||
|             Will.search_anticipate_rec(will,old_inputs) | ||||
|         search_anticipate_rec(will,old_inputs) | ||||
| 
 | ||||
| 
 | ||||
| def update_will(old_will,new_will): | ||||
|         all_old_inputs = Will.get_all_inputs(old_will,only_valid=True) | ||||
|         all_inputs_min_locktime = Will.get_all_inputs_min_locktime(all_old_inputs) | ||||
|         all_new_inputs = Will.get_all_inputs(new_will) | ||||
|     all_old_inputs = get_all_inputs(old_will,only_valid=True) | ||||
|     all_inputs_min_locktime = get_all_inputs_min_locktime(all_old_inputs) | ||||
|     all_new_inputs = get_all_inputs(new_will) | ||||
|     #check if the new input is already spent by other transaction | ||||
|     #if it is use the same locktime, or anticipate. | ||||
|         Will.search_anticipate_rec(new_will,all_old_inputs) | ||||
|     search_anticipate_rec(new_will,all_old_inputs) | ||||
| 
 | ||||
|         other_inputs = Will.get_all_inputs(old_will,{}) | ||||
|     other_inputs = get_all_inputs(old_will,{}) | ||||
|     try: | ||||
|             Will.normalize_will(new_will,others_inputs=other_inputs) | ||||
|         normalize_will(new_will,others_inputs=other_inputs) | ||||
|     except Exception as e: | ||||
|         raise e | ||||
|                          | ||||
| 
 | ||||
|         for oid in Will.only_valid(old_will): | ||||
|     for oid in only_valid(old_will): | ||||
|         if oid in new_will: | ||||
|             new_heirs = new_will[oid].heirs | ||||
|             new_we = new_will[oid].we | ||||
| @ -279,9 +280,11 @@ class Will: | ||||
|             new_will[oid]=old_will[oid] | ||||
|             new_will[oid].heirs = new_heirs | ||||
|             new_will[oid].we = new_we | ||||
|             print(f"found {oid}") | ||||
| 
 | ||||
|             continue | ||||
|         else: | ||||
|             print(f"not found {oid}") | ||||
|             continue | ||||
| 
 | ||||
| def get_higher_input_for_tx(will): | ||||
| @ -298,8 +301,8 @@ class Will: | ||||
|     return out | ||||
| 
 | ||||
| def invalidate_will(will,wallet,fees_per_byte): | ||||
|         will_only_valid = Will.only_valid_list(will) | ||||
|         inputs = Will.get_all_inputs(will_only_valid) | ||||
|     will_only_valid = only_valid_list(will) | ||||
|     inputs = get_all_inputs(will_only_valid) | ||||
|     utxos = wallet.get_utxos() | ||||
|     filtered_inputs = [] | ||||
|     prevout_to_spend = [] | ||||
| @ -334,7 +337,7 @@ class Will: | ||||
|             return tx | ||||
| 
 | ||||
|         else: | ||||
|                 _logger.debug(f"balance({balance}) - fee({fee}) <=0") | ||||
|             _logger.debug("balance - fee <=0") | ||||
|             pass | ||||
|     else: | ||||
|         _logger.debug("len utxo_to_spend <=0") | ||||
| @ -347,7 +350,7 @@ class Will: | ||||
|             return True | ||||
| 
 | ||||
| def search_rai (all_inputs,all_utxos,will,wallet): | ||||
|         will_only_valid = Will.only_valid_or_replaced_list(will) | ||||
|     will_only_valid = only_valid_or_replaced_list(will) | ||||
|     for inp,ws in all_inputs.items(): | ||||
|         inutxo = Util.in_utxo(inp,all_utxos) | ||||
|         for w in ws: | ||||
| @ -367,6 +370,16 @@ class Will: | ||||
|                             wi.set_status('CONFIRMED',True) | ||||
|                         else: | ||||
|                             wi.set_status('INVALIDATED',True) | ||||
|                 #else: | ||||
|                 #    if prevout_id in will: | ||||
|                 #        wo = will[prevout_id] | ||||
|                 #        ttx= wallet.db.get_transaction(prevout_id) | ||||
|                 #        if ttx: | ||||
|                 #            _logger.error("transaction in wallet should be early detected") | ||||
|                 #            #wi.set_status('CONFIRMED',True) | ||||
|                 #    #else: | ||||
|                 #    #    _logger.error("transaction not in will or utxo") | ||||
|                 #    #    wi.set_status('INVALIDATED',True) | ||||
|      | ||||
|                 for child in wi.search(all_inputs): | ||||
|                     if child.tx.locktime < wi.tx.locktime: | ||||
| @ -383,7 +396,7 @@ class Will: | ||||
|     will[wid].set_status("INVALIDATED",True) | ||||
|     if will[wid].children: | ||||
|         for c in self.children.items(): | ||||
|                 Will.set_invalidate(c[0],will) | ||||
|             set_invalidate(c[0],will) | ||||
| 
 | ||||
| def check_tx_height(tx, wallet): | ||||
|     info=wallet.get_tx_info(tx) | ||||
| @ -395,12 +408,18 @@ class Will: | ||||
|         if not w.father: | ||||
|             for inp in w.tx.inputs(): | ||||
|                 inp_str = Util.utxo_to_str(inp) | ||||
|                 #print(utxos_list) | ||||
|                 #print(inp_str) | ||||
|                 #print(inp_str in utxos_list) | ||||
|                 #print("notin: ",not inp_str in utxos_list) | ||||
|                 if not inp_str in utxos_list: | ||||
|                     #print("quindi qua non ci arrivo?") | ||||
|                     if wallet: | ||||
|                             height= Will.check_tx_height(w.tx,wallet) | ||||
|                         height= check_tx_height(w.tx,wallet) | ||||
| 
 | ||||
|                         if height < 0: | ||||
|                                 Will.set_invalidate(wid,willtree) | ||||
|                             #_logger.debug(f"heigth {height}") | ||||
|                             set_invalidate(wid,willtree) | ||||
|                         elif height == 0: | ||||
|                             w.set_status("PENDING",True) | ||||
|                         else: | ||||
| @ -417,7 +436,7 @@ class Will: | ||||
|                 if treeitem.get_status("REPLACED"): | ||||
|                     wc.set_status("REPLACED",True) | ||||
|                     if wc.children: | ||||
|                             Will.reflect_to_children(wc) | ||||
|                         reflect_to_children(wc) | ||||
| 
 | ||||
| def check_amounts(heirs,willexecutors,all_utxos,timestamp_to_check,dust): | ||||
|     fixed_heirs,fixed_amount,perc_heirs,perc_amount = heirs.fixed_percent_lists_amount(timestamp_to_check,dust,reverse=True) | ||||
| @ -438,32 +457,35 @@ class Will: | ||||
| 
 | ||||
| 
 | ||||
| def check_will(will,all_utxos,wallet,block_to_check,timestamp_to_check): | ||||
|         Will.add_willtree(will) | ||||
|         utxos_list= Will.utxos_strs(all_utxos) | ||||
|     add_willtree(will) | ||||
|     utxos_list= utxos_strs(all_utxos) | ||||
| 
 | ||||
|         Will.check_invalidated(will,utxos_list,wallet) | ||||
|     check_invalidated(will,utxos_list,wallet) | ||||
|     #from pprint import pprint | ||||
|     #for wid,w in will.items(): | ||||
|     #    pprint(w.to_dict()) | ||||
| 
 | ||||
|         all_inputs=Will.get_all_inputs(will,only_valid = True) | ||||
|     all_inputs=get_all_inputs(will,only_valid = True) | ||||
| 
 | ||||
|         all_inputs_min_locktime = Will.get_all_inputs_min_locktime(all_inputs) | ||||
|     all_inputs_min_locktime = get_all_inputs_min_locktime(all_inputs) | ||||
| 
 | ||||
|         Will.check_will_expired(all_inputs_min_locktime,block_to_check,timestamp_to_check) | ||||
|     check_will_expired(all_inputs_min_locktime,block_to_check,timestamp_to_check) | ||||
| 
 | ||||
|         all_inputs=Will.get_all_inputs(will,only_valid = True) | ||||
|     all_inputs=get_all_inputs(will,only_valid = True) | ||||
|       | ||||
|         Will.search_rai(all_inputs,all_utxos,will,wallet) | ||||
|     search_rai(all_inputs,all_utxos,will,wallet) | ||||
| 
 | ||||
| def is_will_valid(will, block_to_check, timestamp_to_check, tx_fees, all_utxos,heirs={},willexecutors={},self_willexecutor=False, wallet=False, callback_not_valid_tx=None): | ||||
| 
 | ||||
|         Will.check_will(will,all_utxos,wallet,block_to_check,timestamp_to_check) | ||||
|     check_will(will,all_utxos,wallet,block_to_check,timestamp_to_check) | ||||
| 
 | ||||
| 
 | ||||
|     if heirs: | ||||
|             if not Will.check_willexecutors_and_heirs(will,heirs,willexecutors,self_willexecutor,timestamp_to_check,tx_fees): | ||||
|         if not check_willexecutors_and_heirs(will,heirs,willexecutors,self_willexecutor,timestamp_to_check,tx_fees): | ||||
|             raise NotCompleteWillException() | ||||
| 
 | ||||
| 
 | ||||
|         all_inputs=Will.get_all_inputs(will,only_valid = True) | ||||
|     all_inputs=get_all_inputs(will,only_valid = True) | ||||
| 
 | ||||
|     _logger.info('check all utxo in wallet are spent') | ||||
|     if all_inputs: | ||||
| @ -522,12 +544,13 @@ class Will: | ||||
|     no_willexecutor = 0 | ||||
|     willexecutors_found = {} | ||||
|     heirs_found = {} | ||||
|         will_only_valid = Will.only_valid_list(will) | ||||
|     will_only_valid = only_valid_list(will) | ||||
|     if len(will_only_valid)<1: | ||||
|         return False | ||||
|         for wid in Will.only_valid_list(will): | ||||
|     for wid in only_valid_list(will): | ||||
|         w = will[wid] | ||||
|         if w.tx_fees != tx_fees: | ||||
|             #w.set_status('VALID',False) | ||||
|             raise TxFeesChangedException(f"{tx_fees}:",w.tx_fees) | ||||
|         for wheir in w.heirs: | ||||
|             if not 'w!ll3x3c"' == wheir[:9]: | ||||
| @ -607,6 +630,8 @@ class WillItem(Logger): | ||||
|                 self.STATUS['PUSH_FAIL'][1] = False | ||||
|                 self.STATUS['CHECK_FAIL'][1] = False | ||||
| 
 | ||||
|             #if status in ['CHECK_FAIL']: | ||||
|             #    self.STATUS['PUSHED'][1] = False | ||||
| 
 | ||||
|             if status in ['CHECKED']: | ||||
|                 self.STATUS['PUSHED'][1] = True | ||||
| @ -621,7 +646,7 @@ class WillItem(Logger): | ||||
|         if isinstance(w,WillItem,): | ||||
|             self.__dict__ = w.__dict__.copy() | ||||
|         else: | ||||
|             self.tx = Will.get_tx_from_any(w['tx']) | ||||
|             self.tx = get_tx_from_any(w['tx']) | ||||
|             self.heirs = w.get('heirs',None)  | ||||
|             self.we = w.get('willexecutor',None)  | ||||
|             self.status = w.get('status',None)  | ||||
| @ -675,11 +700,13 @@ class WillItem(Logger): | ||||
|         return str(self.to_dict()) | ||||
| 
 | ||||
|     def set_anticipate(self, ow:'WillItem'): | ||||
|         nl = min(ow.tx.locktime,Will.check_anticipate(ow,self)) | ||||
|         nl = min(ow.tx.locktime,check_anticipate(ow,self)) | ||||
|         if int(nl) < self.tx.locktime: | ||||
|             #_logger.debug("actually anticipating") | ||||
|             self.tx.locktime = int(nl) | ||||
|             return True | ||||
|         else: | ||||
|             #_logger.debug("keeping the same locktime") | ||||
|             return False | ||||
| 
 | ||||
| 
 | ||||
| @ -748,11 +775,10 @@ class WillItem(Logger): | ||||
|         else: | ||||
|             return "#ffffff" | ||||
| 
 | ||||
| class WillException(Exception): | ||||
| 
 | ||||
| class WillExpiredException(Exception): | ||||
|     pass | ||||
| class WillExpiredException(WillException): | ||||
|     pass | ||||
| class NotCompleteWillException(WillException): | ||||
| class NotCompleteWillException(Exception): | ||||
|     pass | ||||
| class HeirChangeException(NotCompleteWillException): | ||||
|     pass | ||||
| @ -766,9 +792,9 @@ class NoWillExecutorNotPresent(NotCompleteWillException): | ||||
|     pass | ||||
| class WillExecutorNotPresent(NotCompleteWillException): | ||||
|     pass | ||||
| class NoHeirsException(WillException): | ||||
| class NoHeirsException(Exception): | ||||
|     pass | ||||
| class AmountException(WillException): | ||||
| class AmountException(Exception): | ||||
|     pass | ||||
| class PercAmountException(AmountException): | ||||
|     pass | ||||
|  | ||||
							
								
								
									
										121
									
								
								willexecutors.py
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								willexecutors.py
									
									
									
									
									
								
							| @ -8,54 +8,40 @@ from electrum import constants | ||||
| from electrum.logging import get_logger | ||||
| from electrum.gui.qt.util import WaitingDialog | ||||
| from electrum.i18n import _ | ||||
| from .bal import BalPlugin | ||||
| from .util import Util | ||||
| 
 | ||||
| from .balqt.baldialog import BalWaitingDialog | ||||
| from . import util as Util | ||||
| 
 | ||||
| DEFAULT_TIMEOUT = 5 | ||||
| _logger = get_logger(__name__) | ||||
| class Willexecutors: | ||||
| 
 | ||||
|     def save(bal_plugin, willexecutors): | ||||
|         aw=bal_plugin.WILLEXECUTORS.get() | ||||
|         aw[constants.net.NET_NAME]=willexecutors | ||||
|         bal_plugin.WILLEXECUTORS.set(aw) | ||||
| 
 | ||||
| def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True): | ||||
|         willexecutors = bal_plugin.WILLEXECUTORS.get() | ||||
|         willexecutors=willexecutors.get(constants.net.NET_NAME,{}) | ||||
|         to_del=[] | ||||
|     willexecutors = bal_plugin.config_get(bal_plugin.WILLEXECUTORS) | ||||
|     for w in willexecutors: | ||||
|             if not  isinstance(willexecutors[w],dict): | ||||
|                 to_del.append(w) | ||||
|                 continue | ||||
|             Willexecutors.initialize_willexecutor(willexecutors[w],w) | ||||
|         for w in to_del: | ||||
|             print("ERROR: WILLEXECUTOR TO DELETE:", w) | ||||
|             del willexecutors[w] | ||||
|         bal = bal_plugin.WILLEXECUTORS.default.get(constants.net.NET_NAME,{}) | ||||
|         initialize_willexecutor(willexecutors[w],w) | ||||
| 
 | ||||
|     bal=bal_plugin.DEFAULT_SETTINGS[bal_plugin.WILLEXECUTORS] | ||||
|     for bal_url,bal_executor in bal.items(): | ||||
|         if not bal_url in willexecutors: | ||||
|                 _logger.debug(f"force add {bal_url} willexecutor") | ||||
|             _logger.debug("replace bal") | ||||
|             willexecutors[bal_url]=bal_executor | ||||
|     if update: | ||||
|         found = False | ||||
|         for url,we in willexecutors.items(): | ||||
|                 if Willexecutors.is_selected(we): | ||||
|             if is_selected(we): | ||||
|                 found = True | ||||
|         if found or force: | ||||
|                 if bal_plugin.PING_WILLEXECUTORS.get() or force: | ||||
|             if bal_plugin.config_get(bal_plugin.PING_WILLEXECUTORS) or force: | ||||
|                 ping_willexecutors = True | ||||
|                     if bal_plugin.ASK_PING_WILLEXECUTORS.get() and not force: | ||||
|                         if bal_window: | ||||
|                 if bal_plugin.config_get(bal_plugin.ASK_PING_WILLEXECUTORS) and not force: | ||||
|                     ping_willexecutors = bal_window.window.question(_("Contact willexecutors servers to update payment informations?")) | ||||
| 
 | ||||
|                 if ping_willexecutors: | ||||
|                     if task: | ||||
|                             bal_window.ping_willexecutors(willexecutors,task) | ||||
|                         bal_window.ping_willexecutors(willexecutors) | ||||
|                     else: | ||||
|                         bal_window.ping_willexecutors_task(willexecutors) | ||||
|         w_sorted = dict(sorted(willexecutors.items(), key=lambda w:w[1].get('sort',0),reverse=True)) | ||||
|         return w_sorted | ||||
|     return willexecutors | ||||
| 
 | ||||
| def is_selected(willexecutor,value=None): | ||||
|     if not willexecutor: | ||||
|         return False | ||||
| @ -75,7 +61,7 @@ class Willexecutors: | ||||
|                 if not willitem.get_status('PUSHED') or force: | ||||
|                     if willexecutor := willitem.we: | ||||
|                         url=willexecutor['url'] | ||||
|                             if  willexecutor and Willexecutors.is_selected(willexecutor): | ||||
|                         if  willexecutor and is_selected(willexecutor): | ||||
|                             if not url in willexecutors: | ||||
|                                 willexecutor['txs']="" | ||||
|                                 willexecutor['txsids']=[] | ||||
| @ -88,16 +74,16 @@ class Willexecutors: | ||||
| 
 | ||||
| def only_selected_list(willexecutors): | ||||
|     out = {} | ||||
|         for url,v in willexecutors.items(): | ||||
|             if Willexecutors.is_selected(willexecutor): | ||||
|     for url,v in willexectors.items(): | ||||
|         if is_selected(willexecutor): | ||||
|             out[url]=v | ||||
| def push_transactions_to_willexecutors(will): | ||||
|     willexecutors = get_transactions_to_be_pushed() | ||||
|     for url in willexecutors: | ||||
|         willexecutor = willexecutors[url] | ||||
|             if Willexecutors.is_selected(willexecutor): | ||||
|         if is_selected(willexecutor): | ||||
|             if 'txs' in willexecutor: | ||||
|                     Willexecutors.push_transactions_to_willexecutor(willexecutors[url]['txs'],url) | ||||
|                 push_transactions_to_willexecutor(willexecutors[url]['txs'],url) | ||||
| 
 | ||||
| def send_request(method, url, data=None, *, timeout=10): | ||||
|     network = Network.get_instance() | ||||
| @ -105,7 +91,7 @@ class Willexecutors: | ||||
|         raise ErrorConnectingServer('You are offline.') | ||||
|     _logger.debug(f'<-- {method} {url} {data}') | ||||
|     headers = {} | ||||
|         headers['user-agent'] = f"BalPlugin v:{BalPlugin.version()}" | ||||
|     headers['user-agent'] = 'BalPlugin' | ||||
|     headers['Content-Type']='text/plain' | ||||
| 
 | ||||
|     try: | ||||
| @ -113,13 +99,13 @@ class Willexecutors: | ||||
|             response = Network.send_http_on_proxy(method, url, | ||||
|                                                   params=data, | ||||
|                                                   headers=headers, | ||||
|                                                       on_finish=Willexecutors.handle_response, | ||||
|                                                   on_finish=handle_response, | ||||
|                                                   timeout=timeout) | ||||
|         elif method == 'post': | ||||
|             response = Network.send_http_on_proxy(method, url, | ||||
|                                                   body=data, | ||||
|                                                   headers=headers, | ||||
|                                                       on_finish=Willexecutors.handle_response, | ||||
|                                                   on_finish=handle_response, | ||||
|                                                   timeout=timeout) | ||||
|         else: | ||||
|             raise Exception(f"unexpected {method=!r}") | ||||
| @ -134,7 +120,7 @@ class Willexecutors: | ||||
|     try: | ||||
|         r=json.loads(r) | ||||
|         r['status'] = resp.status | ||||
|             r['selected']=Willexecutors.is_selected(willexecutor) | ||||
|         r['selected']=is_selected(willexecutor) | ||||
|         r['url']=url | ||||
|     except: | ||||
|         pass     | ||||
| @ -145,10 +131,9 @@ class Willexecutors: | ||||
| def push_transactions_to_willexecutor(willexecutor): | ||||
|     out=True | ||||
|     try: | ||||
| 
 | ||||
|         _logger.debug(f"willexecutor['txs']") | ||||
|             if w:=Willexecutors.send_request('post', willexecutor['url']+"/"+constants.net.NET_NAME+"/pushtxs", data=willexecutor['txs'].encode('ascii')): | ||||
|                 willexecutor['broadcast_status'] = _("Success") | ||||
|         if w:=send_request('post', willexecutor['url']+"/"+constants.net.NET_NAME+"/pushtxs", data=willexecutor['txs'].encode('ascii')): | ||||
|             willexecutor['broadcast_stauts'] = _("Success") | ||||
|             _logger.debug(f"pushed: {w}") | ||||
|             if w !='thx': | ||||
|                 _logger.debug(f"error: {w}") | ||||
| @ -158,15 +143,15 @@ class Willexecutors: | ||||
|     except Exception as e: | ||||
|         _logger.debug(f"error:{e}") | ||||
|         if str(e) == "already present": | ||||
|                 raise Willexecutors.AlreadyPresentException() | ||||
|             raise AlreadyPresentException() | ||||
|         out=False | ||||
|             willexecutor['broadcast_status'] = _("Failed") | ||||
|         willexecutor['broadcast_stauts'] = _("Failed") | ||||
| 
 | ||||
|     return out | ||||
| 
 | ||||
| def ping_servers(willexecutors): | ||||
|     for url,we in willexecutors.items(): | ||||
|             Willexecutors.get_info_task(url,we) | ||||
|         get_info_task(url,we) | ||||
| 
 | ||||
| 
 | ||||
| def get_info_task(url,willexecutor): | ||||
| @ -174,11 +159,7 @@ class Willexecutors: | ||||
|     try: | ||||
|         _logger.info("GETINFO_WILLEXECUTOR") | ||||
|         _logger.debug(url) | ||||
|             netname="bitcoin" | ||||
|             if constants.net.NET_NAME!="mainnet": | ||||
|                 netname=constants.net.NET_NAME | ||||
|             w = Willexecutors.send_request('get',url+"/"+netname+"/info") | ||||
| 
 | ||||
|         w = send_request('get',url+"/"+constants.net.NET_NAME+"/info") | ||||
|         willexecutor['url']=url | ||||
|         willexecutor['status'] = w['status'] | ||||
|         willexecutor['base_fee'] = w['base_fee'] | ||||
| @ -197,60 +178,26 @@ class Willexecutors: | ||||
|     willexecutor['url']=url | ||||
|     if not status is None: | ||||
|         willexecutor['status'] = status | ||||
|         willexecutor['selected'] = Willexecutors.is_selected(willexecutor,selected) | ||||
|     willexecutor['selected'] = is_selected(willexecutor,selected) | ||||
| 
 | ||||
|     def download_list(bal_plugin): | ||||
|         try: | ||||
|             l = Willexecutors.send_request('get',"https://welist.bitcoin-after.life/data/bitcoin?page=0&limit=100") | ||||
|             del l['status'] | ||||
|             for w in l: | ||||
|                 willexecutor=l[w] | ||||
|                 Willexecutors.initialize_willexecutor(willexecutor,w,'New',False) | ||||
|             #bal_plugin.WILLEXECUTORS.set(l) | ||||
|             #bal_plugin.config.set_key(bal_plugin.WILLEXECUTORS,l,save=True) | ||||
|             return l | ||||
| 
 | ||||
|         except Exception as e: | ||||
|             _logger.error(f"Failed to download willexecutors list: {e}") | ||||
|             return {} | ||||
| def get_willexecutors_list_from_json(bal_plugin): | ||||
|     try: | ||||
|         with open("willexecutors.json") as f: | ||||
|             willexecutors = json.load(f) | ||||
|             for w in willexecutors: | ||||
|                 willexecutor=willexecutors[w] | ||||
|                     Willexecutors.initialize_willexecutor(willexecutor,w,'New',False) | ||||
|                 #bal_plugin.WILLEXECUTORS.set(willexecutors) | ||||
|                 willexecutors.initialize_willexecutor(willexecutor,w,'New',False) | ||||
|             bal_plugin.config.set_key(bal_plugin.WILLEXECUTORS,willexecutors,save=True) | ||||
|             return h | ||||
|     except Exception as e: | ||||
|             _logger.error(f"error opening willexecutors json: {e}") | ||||
| 
 | ||||
|         _logger.error(f"errore aprendo willexecutors.json: {e}") | ||||
|         return {} | ||||
| 
 | ||||
| def check_transaction(txid,url): | ||||
|     _logger.debug(f"{url}:{txid}") | ||||
|     try: | ||||
|             w = Willexecutors.send_request('post',url+"/searchtx",data=txid.encode('ascii')) | ||||
|         w = send_request('post',url+"/searchtx",data=txid.encode('ascii')) | ||||
|         return w | ||||
|     except Exception as e: | ||||
|         _logger.error(f"error contacting {url} for checking txs {e}") | ||||
|         raise e | ||||
| 
 | ||||
| class WillExecutor: | ||||
|     def __init__(self,url,base_fee,chain,info,version): | ||||
|         self.url            = url | ||||
|         self.base_fee       = base_fee | ||||
|         self.chain          = chain | ||||
|         self.info           = info | ||||
|         self.version        = version | ||||
| 
 | ||||
|     def from_dict(d): | ||||
|         we = WillExecutor( | ||||
|                     d['url'], | ||||
|                     d['base_fee'], | ||||
|                     d['chain'], | ||||
|                     d['info'], | ||||
|                     d['version'] | ||||
|         ) | ||||
| 
 | ||||
|          | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user