Compare commits
	
		
			6 Commits
		
	
	
		
			a90d187a48
			...
			1b8d90c66c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1b8d90c66c | |||
| 884f06e34b | |||
| 799b809d38 | |||
| a21ae1ee7d | |||
| c9466dd299 | |||
| 157356436a | 
							
								
								
									
										20
									
								
								__init__.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								__init__.py
									
									
									
									
									
								
							| @ -1,20 +0,0 @@ | ||||
| from electrum.i18n import _ | ||||
| import subprocess | ||||
| from . import bal_resources | ||||
| BUILD_NUMBER = 0  | ||||
| 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'] | ||||
							
								
								
									
										17
									
								
								bal.py
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								bal.py
									
									
									
									
									
								
							| @ -1,15 +1,10 @@ | ||||
| import random | ||||
| import os | ||||
| 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) | ||||
| @ -17,11 +12,10 @@ 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 | ||||
| @ -69,11 +63,12 @@ class BalPlugin(BasePlugin): | ||||
|         HIDE_INVALIDATED:True, | ||||
|         ALLOW_REPUSH: False, | ||||
|         WILLEXECUTORS:  { | ||||
|             'http://bitcoin-after.life:9137': { | ||||
|             'https://bitcoin-after.life:9137': { | ||||
|                 "base_fee": 100000, | ||||
|                 "status": "New", | ||||
|                 "info":"Bitcoin After Life Will Executor", | ||||
|                 "address":"bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7" | ||||
|                 "address":"bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7", | ||||
|                 "selected":True | ||||
|             } | ||||
|         }, | ||||
|     } | ||||
| @ -102,7 +97,7 @@ class BalPlugin(BasePlugin): | ||||
|     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) | ||||
|             self.config.set_key(key,self.DEFAULT_SETTINGS[key]) | ||||
|             v = self.DEFAULT_SETTINGS[key] | ||||
|         return v | ||||
| 
 | ||||
|  | ||||
| @ -95,25 +95,8 @@ 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 == 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() | ||||
|             plugin.config.set_key(variable,  v == 2) | ||||
|             plugin.config_get(variable) | ||||
|         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 | ||||
|         print("have to sign",self.have_to_sign) | ||||
|         _logger.debug("have to sign {}".format(self.have_to_sign)) | ||||
|         password=None | ||||
|         if self.have_to_sign is None: | ||||
|             self.msg_set_invalidating() | ||||
|  | ||||
| @ -199,7 +199,6 @@ 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 | ||||
|  | ||||
							
								
								
									
										7
									
								
								heirs.py
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								heirs.py
									
									
									
									
									
								
							| @ -15,8 +15,8 @@ import datetime | ||||
| import urllib.request | ||||
| import urllib.parse | ||||
| from .bal import BalPlugin | ||||
| from . import util as Util | ||||
| from . import willexecutors as Willexecutors | ||||
| from .util import Util | ||||
| from .willexecutors import Willexecutors | ||||
| if TYPE_CHECKING: | ||||
|     from .wallet_db import WalletDB | ||||
|     from .simple_config import SimpleConfig | ||||
| @ -38,6 +38,7 @@ 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 +58,7 @@ def get_current_height(network:'Network'): | ||||
|     # discourage "fee sniping" | ||||
|     height = min(chain_height, server_height) | ||||
|     return height | ||||
| 
 | ||||
| """ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										8
									
								
								manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								manifest.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| { | ||||
|   "name": "BAL", | ||||
|   "fullname": "Bitcoin After Life", | ||||
|   "description": "Provides free and decentralized inheritance support", | ||||
|   "author":"Svātantrya", | ||||
|   "available_for": ["qt"], | ||||
|   "icon":"icons/bal32x32.png" | ||||
| } | ||||
							
								
								
									
										809
									
								
								util.py
									
									
									
									
									
								
							
							
						
						
									
										809
									
								
								util.py
									
									
									
									
									
								
							| @ -8,451 +8,430 @@ import urllib.parse | ||||
| from electrum.util import write_json_file,FileImportFailed,FileExportFailed | ||||
| 
 | ||||
| LOCKTIME_THRESHOLD = 500000000 | ||||
| def locktime_to_str(locktime): | ||||
|     try: | ||||
|         locktime=int(locktime) | ||||
|         if locktime > LOCKTIME_THRESHOLD: | ||||
|             dt = datetime.fromtimestamp(locktime).isoformat() | ||||
|             return dt | ||||
| 
 | ||||
|     except Exception as e: | ||||
|         #print(e) | ||||
|         pass | ||||
|     return str(locktime) | ||||
| 
 | ||||
| def str_to_locktime(locktime): | ||||
|     try: | ||||
|         if locktime[-1] in ('y','d','b'): | ||||
|           return locktime | ||||
|         else: return int(locktime) | ||||
|     except Exception as e: | ||||
|         pass | ||||
|         #print(e) | ||||
|     dt_object = datetime.fromisoformat(locktime) | ||||
|     timestamp = dt_object.timestamp() | ||||
|     return int(timestamp) | ||||
| 
 | ||||
| def parse_locktime_string(locktime,w=None):  | ||||
|     try:  | ||||
|         return int(locktime)  | ||||
|   | ||||
|     except Exception as e:  | ||||
|         pass | ||||
|         #print("parse_locktime_string",e)  | ||||
|     try:  | ||||
|         now = datetime.now()  | ||||
|         if locktime[-1] == 'y':  | ||||
|             locktime = str(int(locktime[:-1])*365) + "d"  | ||||
|         if locktime[-1] == 'd':  | ||||
|             return int((now + timedelta(days = int(locktime[:-1]))).replace(hour=0,minute=0,second=0,microsecond=0).timestamp())  | ||||
|         if locktime[-1] == 'b':  | ||||
|             locktime = int(locktime[:-1])  | ||||
|             height = 0  | ||||
|             if w:  | ||||
|                 height = get_current_height(w.network)  | ||||
|             locktime+=int(height)  | ||||
|         return int(locktime)  | ||||
|     except Exception as e:  | ||||
|         print("parse_locktime_string",e)  | ||||
|         #raise e | ||||
|     return 0 | ||||
| 
 | ||||
| 
 | ||||
| def int_locktime(seconds=0,minutes=0,hours=0, days=0, blocks = 0): | ||||
|     return int(seconds + minutes*60 + hours*60*60 + days*60*60*24 + blocks * 600) | ||||
| 
 | ||||
| def encode_amount(amount, decimal_point): | ||||
|     if is_perc(amount): | ||||
|         return amount | ||||
|     else: | ||||
| class Util: | ||||
|     def locktime_to_str(locktime): | ||||
|         try: | ||||
|             return int(float(amount)*pow(10,decimal_point)) | ||||
|         except: | ||||
|             return 0 | ||||
|             locktime=int(locktime) | ||||
|             if locktime > LOCKTIME_THRESHOLD: | ||||
|                 dt = datetime.fromtimestamp(locktime).isoformat() | ||||
|                 return dt | ||||
| 
 | ||||
| def decode_amount(amount,decimal_point): | ||||
|     if is_perc(amount): | ||||
|         return amount | ||||
|     else: | ||||
|         num=8-decimal_point | ||||
|         basestr="{{:0{}.{}f}}".format(num,num) | ||||
|         return "{:08.8f}".format(float(amount)/pow(10,decimal_point)) | ||||
|         except Exception as e: | ||||
|             pass | ||||
|         return str(locktime) | ||||
| 
 | ||||
| def is_perc(value):  | ||||
|     def str_to_locktime(locktime): | ||||
|         try: | ||||
|             if locktime[-1] in ('y','d','b'): | ||||
|               return locktime | ||||
|             else: return int(locktime) | ||||
|         except Exception as e: | ||||
|             pass | ||||
|         dt_object = datetime.fromisoformat(locktime) | ||||
|         timestamp = dt_object.timestamp() | ||||
|         return int(timestamp) | ||||
| 
 | ||||
|     def parse_locktime_string(locktime,w=None):  | ||||
|         try:  | ||||
|             return int(locktime)  | ||||
|       | ||||
|         except Exception as e:  | ||||
|             pass | ||||
|         try:  | ||||
|             now = datetime.now()  | ||||
|             if locktime[-1] == 'y':  | ||||
|                 locktime = str(int(locktime[:-1])*365) + "d"  | ||||
|             if locktime[-1] == 'd':  | ||||
|                 return int((now + timedelta(days = int(locktime[:-1]))).replace(hour=0,minute=0,second=0,microsecond=0).timestamp())  | ||||
|             if locktime[-1] == 'b':  | ||||
|                 locktime = int(locktime[:-1])  | ||||
|                 height = 0  | ||||
|                 if w:  | ||||
|                     height = Util.get_current_height(w.network)  | ||||
|                 locktime+=int(height)  | ||||
|             return int(locktime)  | ||||
|         except Exception as e:  | ||||
|             pass | ||||
|         return 0 | ||||
| 
 | ||||
| 
 | ||||
|     def int_locktime(seconds=0,minutes=0,hours=0, days=0, blocks = 0): | ||||
|         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): | ||||
|             return amount | ||||
|         else: | ||||
|             try: | ||||
|                 return int(float(amount)*pow(10,decimal_point)) | ||||
|             except: | ||||
|                 return 0 | ||||
| 
 | ||||
|     def decode_amount(amount,decimal_point): | ||||
|         if Util.is_perc(amount): | ||||
|             return amount | ||||
|         else: | ||||
|             num=8-decimal_point | ||||
|             basestr="{{:0{}.{}f}}".format(num,num) | ||||
|             return "{:08.8f}".format(float(amount)/pow(10,decimal_point)) | ||||
| 
 | ||||
|     def is_perc(value):  | ||||
|         try: | ||||
|             return value[-1] == '%' | ||||
|         except: | ||||
|             return False | ||||
| 
 | ||||
| def cmp_array(heira,heirb): | ||||
|     try: | ||||
|         if not len(heira) == len(heirb): | ||||
|             return False | ||||
|         for h in range(0,len(heira)): | ||||
|             if not heira[h] == heirb[h]: | ||||
|     def cmp_array(heira,heirb): | ||||
|         try: | ||||
|             if not len(heira) == len(heirb): | ||||
|                 return False | ||||
|         return True | ||||
|     except: | ||||
|         return False | ||||
| 
 | ||||
| def cmp_heir(heira,heirb): | ||||
|     if heira[0] == heirb[0] and heira[1] == heirb[1]:  | ||||
|         return True | ||||
|     return False | ||||
| 
 | ||||
| def cmp_willexecutor(willexecutora,willexecutorb): | ||||
|     if willexecutora == willexecutorb: | ||||
|         return True | ||||
|     try: | ||||
|         if willexecutora['url']==willexecutorb['url'] and willexecutora['address'] == willexecutorb['address'] and willexecutora['base_fee']==willexecutorb['base_fee']: | ||||
|             for h in range(0,len(heira)): | ||||
|                 if not heira[h] == heirb[h]: | ||||
|                     return False | ||||
|             return True | ||||
|     except: | ||||
|         return False | ||||
|     return False | ||||
| 
 | ||||
| def search_heir_by_values(heirs,heir,values): | ||||
|     #print() | ||||
|     for h,v in heirs.items(): | ||||
|         found = False | ||||
|         for val in values: | ||||
|             if val in v and v[val] != heir[val]: | ||||
|                 found = True | ||||
| 
 | ||||
|         if not found: | ||||
|             return h | ||||
|     return False | ||||
| 
 | ||||
| def cmp_heir_by_values(heira,heirb,values): | ||||
|     for v in values: | ||||
|         if heira[v] != heirb[v]: | ||||
|         except: | ||||
|             return False | ||||
|     return True | ||||
| 
 | ||||
| def cmp_heirs_by_values(heirsa,heirsb,values,exclude_willexecutors=False,reverse = True): | ||||
|     for heira in heirsa: | ||||
|         if (exclude_willexecutors and not "w!ll3x3c\"" in heira) or not exclude_willexecutors: | ||||
|     def cmp_heir(heira,heirb): | ||||
|         if heira[0] == heirb[0] and heira[1] == heirb[1]:  | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def cmp_willexecutor(willexecutora,willexecutorb): | ||||
|         if willexecutora == willexecutorb: | ||||
|             return True | ||||
|         try: | ||||
|             if willexecutora['url']==willexecutorb['url'] and willexecutora['address'] == willexecutorb['address'] and willexecutora['base_fee']==willexecutorb['base_fee']: | ||||
|                 return True | ||||
|         except: | ||||
|             return False | ||||
|         return False | ||||
| 
 | ||||
|     def search_heir_by_values(heirs,heir,values): | ||||
|         for h,v in heirs.items(): | ||||
|             found = False | ||||
|             for heirb in heirsb: | ||||
|                 if cmp_heir_by_values(heirsa[heira],heirsb[heirb],values): | ||||
|                     found=True | ||||
|             for val in values: | ||||
|                 if val in v and v[val] != heir[val]: | ||||
|                     found = True | ||||
| 
 | ||||
|             if not found: | ||||
|                 #print(f"not_found {heira}--{heirsa[heira]}") | ||||
|                 return h | ||||
|         return False | ||||
| 
 | ||||
|     def cmp_heir_by_values(heira,heirb,values): | ||||
|         for v in values: | ||||
|             if heira[v] != heirb[v]: | ||||
|                 return False | ||||
|     if reverse: | ||||
|         return cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False) | ||||
|     else: | ||||
|         return True | ||||
| 
 | ||||
| def cmp_heirs(heirsa,heirsb,cmp_function = lambda x,y: x[0]==y[0] and x[3]==y[3],reverse=True): | ||||
|     try: | ||||
|         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 search_heir_by_values(heirsb,heirsa[heir],[0,3]): | ||||
|                         return False | ||||
|     def cmp_heirs_by_values(heirsa,heirsb,values,exclude_willexecutors=False,reverse = True): | ||||
|         for heira in heirsa: | ||||
|             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): | ||||
|                         found=True | ||||
|                 if not found: | ||||
|                     return False | ||||
|         if reverse: | ||||
|             return cmp_heirs(heirsb,heirsa,cmp_function,False) | ||||
|             return Util.cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False) | ||||
|         else: | ||||
|             return True | ||||
|     except Exception as e: | ||||
|         raise e | ||||
|         return False | ||||
|          | ||||
| def cmp_inputs(inputsa,inputsb): | ||||
|     if len(inputsa) != len(inputsb):  | ||||
|         return False  | ||||
|     for inputa in inputsa: | ||||
|         if not in_utxo(inputa,inputsb): | ||||
|             return False | ||||
|     return True | ||||
| 
 | ||||
| def cmp_outputs(outputsa,outputsb,willexecutor_output = None): | ||||
|     if len(outputsa) != len(outputsb):  | ||||
|         return False  | ||||
|     for outputa in outputsa:  | ||||
|         if not cmp_output(outputa,willexecutor_output): | ||||
|             if not in_output(outputa,outputsb):  | ||||
|                 return False | ||||
|     return True | ||||
| 
 | ||||
| def cmp_txs(txa,txb): | ||||
|     if not cmp_inputs(txa.inputs(),txb.inputs()): | ||||
|         return False | ||||
|     if not cmp_outputs(txa.outputs(),txb.outputs()): | ||||
|         return False | ||||
|     return True | ||||
| 
 | ||||
| def get_value_amount(txa,txb): | ||||
|     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 = 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 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def chk_locktime(timestamp_to_check,block_height_to_check,locktime): | ||||
|     #TODO BUG:  WHAT HAPPEN AT THRESHOLD? | ||||
|     locktime=int(locktime) | ||||
|     if locktime > LOCKTIME_THRESHOLD and locktime > timestamp_to_check: | ||||
|         return True | ||||
|     elif locktime < LOCKTIME_THRESHOLD and locktime > block_height_to_check: | ||||
|         return True | ||||
|     else: | ||||
|         return False | ||||
| 
 | ||||
| def anticipate_locktime(locktime,blocks=0,hours=0,days=0): | ||||
|     locktime = int(locktime) | ||||
|     out=0 | ||||
|     if locktime> LOCKTIME_THRESHOLD: | ||||
|         seconds = blocks*600 + hours*3600 + days*86400 | ||||
|         dt = datetime.fromtimestamp(locktime) | ||||
|         dt -= timedelta(seconds=seconds) | ||||
|         out = dt.timestamp() | ||||
|     else: | ||||
|         blocks -= hours*6 + days*144 | ||||
|         out = locktime + blocks | ||||
| 
 | ||||
|     if out < 1: | ||||
|         out = 1  | ||||
|     return out | ||||
| 
 | ||||
| def cmp_locktime(locktimea,locktimeb): | ||||
|     if locktimea==locktimeb: | ||||
|         return 0 | ||||
|     strlocktime = str(locktimea) | ||||
|     strlocktimeb = str(locktimeb) | ||||
|     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]) | ||||
|         else: | ||||
|             return int(locktimea)-(locktimeb) | ||||
|      | ||||
| 
 | ||||
| def get_lowest_valid_tx(available_utxos,will): | ||||
|     will = sorted(will.items(),key = lambda x: x[1]['tx'].locktime) | ||||
|     for txid,willitem in will.items(): | ||||
|         pass | ||||
| 
 | ||||
| def get_locktimes(will): | ||||
|     locktimes = {} | ||||
|     for txid,willitem in will.items(): | ||||
|         locktimes[willitem['tx'].locktime]=True | ||||
|     return locktimes.keys() | ||||
| 
 | ||||
| def get_lowest_locktimes(locktimes): | ||||
|     sorted_timestamp=[] | ||||
|     sorted_block=[] | ||||
|     for l in locktimes: | ||||
|         #print("locktime:",parse_locktime_string(l)) | ||||
|         l=parse_locktime_string(l) | ||||
|         if l < LOCKTIME_THRESHOLD: | ||||
|             bisect.insort(sorted_block,l) | ||||
|         else: | ||||
|             bisect.insort(sorted_timestamp,l) | ||||
| 
 | ||||
|     return sorted(sorted_timestamp), sorted(sorted_block) | ||||
| 
 | ||||
| def get_lowest_locktimes_from_will(will): | ||||
|     return get_lowest_locktimes(get_locktimes(will)) | ||||
| 
 | ||||
| def search_willtx_per_io(will,tx): | ||||
|     for wid, w in will.items(): | ||||
|         if cmp_txs(w['tx'],tx['tx']): | ||||
|             return wid,w | ||||
|     return None, None | ||||
| 
 | ||||
| def invalidate_will(will): | ||||
|     raise Exception("not implemented") | ||||
| 
 | ||||
| def get_will_spent_utxos(will): | ||||
|     utxos=[] | ||||
|     for txid,willitem in will.items(): | ||||
|         utxos+=willitem['tx'].inputs() | ||||
|          | ||||
|     return utxos | ||||
| 
 | ||||
| def utxo_to_str(utxo): | ||||
|     try: return utxo.to_str() | ||||
|     except Exception as e: pass | ||||
|     try: return utxo.prevout.to_str() | ||||
|     except Exception as e: pass | ||||
|     return str(utxo) | ||||
| 
 | ||||
| def cmp_utxo(utxoa,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 cmp_utxo(s_u,utxo): | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| def txid_in_utxo(txid,utxos): | ||||
|     for s_u in utxos: | ||||
|         if s_u.prevout.txid == txid: | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| def cmp_output(outputa,outputb): | ||||
|     return outputa.address == outputb.address and outputa.value == outputb.value | ||||
| 
 | ||||
| def in_output(output,outputs): | ||||
|     for s_o in outputs: | ||||
|         if cmp_output(s_o,output): | ||||
|             return True | ||||
|     return False | ||||
| 
 | ||||
| #check all output with the same amount if none have the same address it can be a change | ||||
| #return true true same address same amount  | ||||
| #return true false same amount different address | ||||
| #return false false different amount, different address not found | ||||
| 
 | ||||
| 
 | ||||
| def din_output(out,outputs): | ||||
|     same_amount=[] | ||||
|     for s_o in outputs: | ||||
|         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 | ||||
|     def cmp_heirs(heirsa,heirsb,cmp_function = lambda x,y: x[0]==y[0] and x[3]==y[3],reverse=True): | ||||
|         try: | ||||
|             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]): | ||||
|                             return False | ||||
|             if reverse: | ||||
|                 return Util.cmp_heirs(heirsb,heirsa,cmp_function,False) | ||||
|             else: | ||||
|                 return True | ||||
|         except Exception as e: | ||||
|             raise e | ||||
|             return False | ||||
| 
 | ||||
|     def cmp_inputs(inputsa,inputsb): | ||||
|         if len(inputsa) != len(inputsb):  | ||||
|             return False  | ||||
|         for inputa in inputsa: | ||||
|             if not Util.in_utxo(inputa,inputsb): | ||||
|                 return False | ||||
|         return True | ||||
| 
 | ||||
|     def cmp_outputs(outputsa,outputsb,willexecutor_output = None): | ||||
|         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):  | ||||
|                     return False | ||||
|         return True | ||||
| 
 | ||||
|     def cmp_txs(txa,txb): | ||||
|         if not Util.cmp_inputs(txa.inputs(),txb.inputs()): | ||||
|             return False | ||||
|         if not Util.cmp_outputs(txa.outputs(),txb.outputs()): | ||||
|             return False | ||||
|         return True | ||||
| 
 | ||||
|     def get_value_amount(txa,txb): | ||||
|         outputsa=txa.outputs() | ||||
|         outputsb=txb.outputs() | ||||
|         value_amount = 0 | ||||
| 
 | ||||
|         for outa in outputsa: | ||||
|             same_amount,same_address = Util.in_output(outa,txb.outputs()) | ||||
|             if not (same_amount or same_address): | ||||
|                 return False | ||||
|             if same_amount and same_address: | ||||
|                 value_amount+=outa.value | ||||
|             if same_amount: | ||||
|                 pass | ||||
|             if same_address: | ||||
|                 pass | ||||
|                 #print("NOT  SAME_:",out.address,s_o.address) | ||||
| 
 | ||||
|     if len(same_amount)>0: | ||||
|         return True, False | ||||
|     else:return False, False | ||||
|         return value_amount | ||||
| 
 | ||||
| 
 | ||||
| def get_change_output(wallet,in_amount,out_amount,fee):  | ||||
|     change_amount = int(in_amount - out_amount - fee)  | ||||
|     if change_amount > wallet.dust_threshold():  | ||||
|         change_addresses = wallet.get_change_addresses_for_new_transaction()  | ||||
|         out = PartialTxOutput.from_address_and_value(change_addresses[0], change_amount)  | ||||
|         out.is_change = True  | ||||
| 
 | ||||
|     def chk_locktime(timestamp_to_check,block_height_to_check,locktime): | ||||
|         #TODO BUG:  WHAT HAPPEN AT THRESHOLD? | ||||
|         locktime=int(locktime) | ||||
|         if locktime > LOCKTIME_THRESHOLD and locktime > timestamp_to_check: | ||||
|             return True | ||||
|         elif locktime < LOCKTIME_THRESHOLD and locktime > block_height_to_check: | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
| 
 | ||||
|     def anticipate_locktime(locktime,blocks=0,hours=0,days=0): | ||||
|         locktime = int(locktime) | ||||
|         out=0 | ||||
|         if locktime> LOCKTIME_THRESHOLD: | ||||
|             seconds = blocks*600 + hours*3600 + days*86400 | ||||
|             dt = datetime.fromtimestamp(locktime) | ||||
|             dt -= timedelta(seconds=seconds) | ||||
|             out = dt.timestamp() | ||||
|         else: | ||||
|             blocks -= hours*6 + days*144 | ||||
|             out = locktime + blocks | ||||
| 
 | ||||
|         if out < 1: | ||||
|             out = 1  | ||||
|         return out | ||||
| 
 | ||||
| 
 | ||||
| def get_current_height(network:'Network'): | ||||
|     #if no network or not up to date, just set locktime to zero | ||||
|     if not network: | ||||
|         return 0 | ||||
|     chain = network.blockchain() | ||||
|     if chain.is_tip_stale(): | ||||
|         return 0 | ||||
|     # figure out current block height | ||||
|     chain_height = chain.height()  # learnt from all connected servers, SPV-checked | ||||
|     server_height = network.get_server_height()  # height claimed by main server, unverified | ||||
|     # note: main server might be lagging (either is slow, is malicious, or there is an SPV-invisible-hard-fork) | ||||
|     #       - if it's lagging too much, it is the network's job to switch away | ||||
|     if server_height < chain_height - 10: | ||||
|         # the diff is suspiciously large... give up and use something non-fingerprintable | ||||
|         return 0 | ||||
|     # discourage "fee sniping" | ||||
|     height = min(chain_height, server_height) | ||||
|     return height | ||||
|     def cmp_locktime(locktimea,locktimeb): | ||||
|         if locktimea==locktimeb: | ||||
|             return 0 | ||||
|         strlocktime = str(locktimea) | ||||
|         strlocktimeb = str(locktimeb) | ||||
|         intlocktimea = Util.str_to_locktime(strlocktimea) | ||||
|         intlocktimeb = Util.str_to_locktime(strlocktimeb) | ||||
|         if locktimea[-1] in "ydb": | ||||
|             if locktimeb[-1] == locktimea[-1]: | ||||
|                 return int(strlocktimea[-1])-int(strlocktimeb[-1]) | ||||
|             else: | ||||
|                 return int(locktimea)-(locktimeb) | ||||
|          | ||||
| 
 | ||||
| def print_var(var,name = "",veryverbose=False): | ||||
|     print(f"---{name}---") | ||||
|     if not var is None: | ||||
|     def get_lowest_valid_tx(available_utxos,will): | ||||
|         will = sorted(will.items(),key = lambda x: x[1]['tx'].locktime) | ||||
|         for txid,willitem in will.items(): | ||||
|             pass | ||||
| 
 | ||||
|     def get_locktimes(will): | ||||
|         locktimes = {} | ||||
|         for txid,willitem in will.items(): | ||||
|             locktimes[willitem['tx'].locktime]=True | ||||
|         return locktimes.keys() | ||||
| 
 | ||||
|     def get_lowest_locktimes(locktimes): | ||||
|         sorted_timestamp=[] | ||||
|         sorted_block=[] | ||||
|         for l in locktimes: | ||||
|             l=Util.parse_locktime_string(l) | ||||
|             if l < LOCKTIME_THRESHOLD: | ||||
|                 bisect.insort(sorted_block,l) | ||||
|             else: | ||||
|                 bisect.insort(sorted_timestamp,l) | ||||
| 
 | ||||
|         return sorted(sorted_timestamp), sorted(sorted_block) | ||||
| 
 | ||||
|     def get_lowest_locktimes_from_will(will): | ||||
|         return Util.get_lowest_locktimes(Util.get_locktimes(will)) | ||||
| 
 | ||||
|     def search_willtx_per_io(will,tx): | ||||
|         for wid, w in will.items(): | ||||
|             if Util.cmp_txs(w['tx'],tx['tx']): | ||||
|                 return wid,w | ||||
|         return None, None | ||||
| 
 | ||||
|     def invalidate_will(will): | ||||
|         raise Exception("not implemented") | ||||
| 
 | ||||
|     def get_will_spent_utxos(will): | ||||
|         utxos=[] | ||||
|         for txid,willitem in will.items(): | ||||
|             utxos+=willitem['tx'].inputs() | ||||
|              | ||||
|         return utxos | ||||
| 
 | ||||
|     def utxo_to_str(utxo): | ||||
|         try: return utxo.to_str() | ||||
|         except Exception as e: pass | ||||
|         try: return utxo.prevout.to_str() | ||||
|         except Exception as e: pass | ||||
|         return str(utxo) | ||||
| 
 | ||||
|     def cmp_utxo(utxoa,utxob): | ||||
|         utxoa=Util.utxo_to_str(utxoa) | ||||
|         utxob=Util.utxo_to_str(utxob) | ||||
|         if utxoa == utxob: | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
| 
 | ||||
|     def in_utxo(utxo, utxos): | ||||
|         for s_u in utxos: | ||||
|             if Util.cmp_utxo(s_u,utxo): | ||||
|                 return True | ||||
|         return False | ||||
| 
 | ||||
|     def txid_in_utxo(txid,utxos): | ||||
|         for s_u in utxos: | ||||
|             if s_u.prevout.txid == txid: | ||||
|                 return True | ||||
|         return False | ||||
| 
 | ||||
|     def cmp_output(outputa,outputb): | ||||
|         return outputa.address == outputb.address and outputa.value == outputb.value | ||||
| 
 | ||||
|     def in_output(output,outputs): | ||||
|         for s_o in outputs: | ||||
|             if Util.cmp_output(s_o,output): | ||||
|                 return True | ||||
|         return False | ||||
| 
 | ||||
|     #check all output with the same amount if none have the same address it can be a change | ||||
|     #return true true same address same amount  | ||||
|     #return true false same amount different address | ||||
|     #return false false different amount, different address not found | ||||
| 
 | ||||
| 
 | ||||
|     def din_output(out,outputs): | ||||
|         same_amount=[] | ||||
|         for s_o in outputs: | ||||
|             if int(out.value) == int(s_o.value): | ||||
|                 same_amount.append(s_o) | ||||
|                 if out.address==s_o.address: | ||||
|                     return True, True | ||||
|                 else: | ||||
|                     pass | ||||
| 
 | ||||
|         if len(same_amount)>0: | ||||
|             return True, False | ||||
|         else:return False, False | ||||
| 
 | ||||
| 
 | ||||
|     def get_change_output(wallet,in_amount,out_amount,fee):  | ||||
|         change_amount = int(in_amount - out_amount - fee)  | ||||
|         if change_amount > wallet.dust_threshold():  | ||||
|             change_addresses = wallet.get_change_addresses_for_new_transaction()  | ||||
|             out = PartialTxOutput.from_address_and_value(change_addresses[0], change_amount)  | ||||
|             out.is_change = True  | ||||
|             return out | ||||
| 
 | ||||
| 
 | ||||
|     def get_current_height(network:'Network'): | ||||
|         #if no network or not up to date, just set locktime to zero | ||||
|         if not network: | ||||
|             return 0 | ||||
|         chain = network.blockchain() | ||||
|         if chain.is_tip_stale(): | ||||
|             return 0 | ||||
|         # figure out current block height | ||||
|         chain_height = chain.height()  # learnt from all connected servers, SPV-checked | ||||
|         server_height = network.get_server_height()  # height claimed by main server, unverified | ||||
|         # note: main server might be lagging (either is slow, is malicious, or there is an SPV-invisible-hard-fork) | ||||
|         #       - if it's lagging too much, it is the network's job to switch away | ||||
|         if server_height < chain_height - 10: | ||||
|             # the diff is suspiciously large... give up and use something non-fingerprintable | ||||
|             return 0 | ||||
|         # discourage "fee sniping" | ||||
|         height = min(chain_height, server_height) | ||||
|         return height | ||||
| 
 | ||||
| 
 | ||||
|     def print_var(var,name = "",veryverbose=False): | ||||
|         print(f"---{name}---") | ||||
|         if not var is None: | ||||
|             try: | ||||
|                 print("doc:",doc(var)) | ||||
|             except: pass | ||||
|             try: | ||||
|                 print("str:",str(var)) | ||||
|             except: pass | ||||
|             try: | ||||
|                 print("repr",repr(var)) | ||||
|             except:pass | ||||
|             try: | ||||
|                 print("dict",dict(var)) | ||||
|             except:pass | ||||
|             try: | ||||
|                 print("dir",dir(var)) | ||||
|             except:pass | ||||
|             try: | ||||
|                 print("type",type(var)) | ||||
|             except:pass | ||||
|             try: | ||||
|                 print("to_json",var.to_json()) | ||||
|             except: pass | ||||
|             try: | ||||
|                 print("__slotnames__",var.__slotnames__) | ||||
|             except:pass | ||||
| 
 | ||||
|         print(f"---end {name}---") | ||||
| 
 | ||||
|     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("_TxInput__address:",utxo._TxInput__address) | ||||
|         print("_TxInput__scriptpubkey:",utxo._TxInput__scriptpubkey) | ||||
|         print("_TxInput__value_sats:",utxo._TxInput__value_sats) | ||||
|         print(f"---utxo-end {name}---") | ||||
| 
 | ||||
|     def print_prevout(prevout, name = ""): | ||||
|         print(f"---prevout-{name}---") | ||||
|         Util.print_var(prevout,f"{name}-prevout") | ||||
|         Util.print_var(prevout._asdict()) | ||||
|         print(f"---prevout-end {name}---") | ||||
| 
 | ||||
|     def export_meta_gui(electrum_window: 'ElectrumWindow', title, exporter): | ||||
|         filter_ = "All files (*)" | ||||
|         filename = getSaveFileName( | ||||
|             parent=electrum_window, | ||||
|             title=_("Select file to save your {}").format(title), | ||||
|             filename='BALplugin_{}'.format(title), | ||||
|             filter=filter_, | ||||
|             config=electrum_window.config, | ||||
|         ) | ||||
|         if not filename: | ||||
|             return | ||||
|         try: | ||||
|             print("doc:",doc(var)) | ||||
|         except: pass | ||||
|         try: | ||||
|             print("str:",str(var)) | ||||
|         except: pass | ||||
|         try: | ||||
|             print("repr",repr(var)) | ||||
|         except:pass | ||||
|         try: | ||||
|             print("dict",dict(var)) | ||||
|         except:pass | ||||
|         try: | ||||
|             print("dir",dir(var)) | ||||
|         except:pass | ||||
|         try: | ||||
|             print("type",type(var)) | ||||
|         except:pass | ||||
|         try: | ||||
|             print("to_json",var.to_json()) | ||||
|         except: pass | ||||
|         try: | ||||
|             print("__slotnames__",var.__slotnames__) | ||||
|         except:pass | ||||
| 
 | ||||
|     print(f"---end {name}---") | ||||
| 
 | ||||
| def print_utxo(utxo, name = ""): | ||||
|     print(f"---utxo-{name}---") | ||||
|     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) | ||||
|     print(f"---utxo-end {name}---") | ||||
| 
 | ||||
| def print_prevout(prevout, name = ""): | ||||
|     print(f"---prevout-{name}---") | ||||
|     print_var(prevout,f"{name}-prevout") | ||||
|     print_var(prevout._asdict()) | ||||
|     print(f"---prevout-end {name}---") | ||||
| 
 | ||||
| def export_meta_gui(electrum_window: 'ElectrumWindow', title, exporter): | ||||
|     filter_ = "All files (*)" | ||||
|     filename = getSaveFileName( | ||||
|         parent=electrum_window, | ||||
|         title=_("Select file to save your {}").format(title), | ||||
|         filename='BALplugin_{}'.format(title), | ||||
|         filter=filter_, | ||||
|         config=electrum_window.config, | ||||
|     ) | ||||
|     if not filename: | ||||
|         return | ||||
|     try: | ||||
|         exporter(filename) | ||||
|     except FileExportFailed as e: | ||||
|         electrum_window.show_critical(str(e)) | ||||
|     else: | ||||
|         electrum_window.show_message(_("Your {0} were exported to '{1}'") | ||||
|                                  .format(title, str(filename))) | ||||
|             exporter(filename) | ||||
|         except FileExportFailed as e: | ||||
|             electrum_window.show_critical(str(e)) | ||||
|         else: | ||||
|             electrum_window.show_message(_("Your {0} were exported to '{1}'") | ||||
|                                      .format(title, str(filename))) | ||||
| 
 | ||||
| 
 | ||||
| def copy(dicto,dictfrom): | ||||
|     for k,v in dictfrom.items(): | ||||
|         dicto[k]=v | ||||
|     def copy(dicto,dictfrom): | ||||
|         for k,v in dictfrom.items(): | ||||
|             dicto[k]=v | ||||
|  | ||||
							
								
								
									
										362
									
								
								willexecutors.py
									
									
									
									
									
								
							
							
						
						
									
										362
									
								
								willexecutors.py
									
									
									
									
									
								
							| @ -9,195 +9,211 @@ from electrum.logging import get_logger | ||||
| from electrum.gui.qt.util import WaitingDialog | ||||
| from electrum.i18n import _ | ||||
| 
 | ||||
| from .balqt.baldialog import BalWaitingDialog | ||||
| from . import util as Util | ||||
| from .util import Util | ||||
| 
 | ||||
| DEFAULT_TIMEOUT = 5 | ||||
| _logger = get_logger(__name__) | ||||
| class Willexecutors: | ||||
|     def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True): | ||||
|         willexecutors = bal_plugin.config_get(bal_plugin.WILLEXECUTORS) | ||||
|         for w in willexecutors: | ||||
|             Willexecutors.initialize_willexecutor(willexecutors[w],w) | ||||
| 
 | ||||
| def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True): | ||||
|     willexecutors = bal_plugin.config_get(bal_plugin.WILLEXECUTORS) | ||||
|     for w in willexecutors: | ||||
|         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("replace bal") | ||||
|                 willexecutors[bal_url]=bal_executor | ||||
|         if update: | ||||
|             found = False | ||||
|             for url,we in willexecutors.items(): | ||||
|                 if Willexecutors.is_selected(we): | ||||
|                     found = True | ||||
|             if found or force: | ||||
|                 if bal_plugin.config_get(bal_plugin.PING_WILLEXECUTORS) or force: | ||||
|                     ping_willexecutors = True | ||||
|                     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) | ||||
|                         else: | ||||
|                             bal_window.ping_willexecutors_task(willexecutors) | ||||
|         return willexecutors | ||||
| 
 | ||||
|     bal=bal_plugin.DEFAULT_SETTINGS[bal_plugin.WILLEXECUTORS] | ||||
|     for bal_url,bal_executor in bal.items(): | ||||
|         if not bal_url in willexecutors: | ||||
|             _logger.debug("replace bal") | ||||
|             willexecutors[bal_url]=bal_executor | ||||
|     if update: | ||||
|         found = False | ||||
|         for url,we in willexecutors.items(): | ||||
|             if is_selected(we): | ||||
|                 found = True | ||||
|         if found or force: | ||||
|             if bal_plugin.config_get(bal_plugin.PING_WILLEXECUTORS) or force: | ||||
|                 ping_willexecutors = True | ||||
|                 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) | ||||
|                     else: | ||||
|                         bal_window.ping_willexecutors_task(willexecutors) | ||||
|     return willexecutors | ||||
|     def is_selected(willexecutor,value=None): | ||||
|         if not willexecutor: | ||||
|             return False | ||||
|         if not value is None: | ||||
|             willexecutor['selected']=value | ||||
|         try: | ||||
|             return willexecutor['selected'] | ||||
|         except: | ||||
|             willexecutor['selected']=False | ||||
|             return False | ||||
| 
 | ||||
| def is_selected(willexecutor,value=None): | ||||
|     if not willexecutor: | ||||
|         return False | ||||
|     if not value is None: | ||||
|         willexecutor['selected']=value | ||||
|     try: | ||||
|         return willexecutor['selected'] | ||||
|     except: | ||||
|         willexecutor['selected']=False | ||||
|         return False | ||||
|     def get_willexecutor_transactions(will, force=False): | ||||
|         willexecutors ={} | ||||
|         for wid,willitem in will.items(): | ||||
|             if willitem.get_status('VALID'): | ||||
|                 if willitem.get_status('COMPLETE'): | ||||
|                     if not willitem.get_status('PUSHED') or force: | ||||
|                         if willexecutor := willitem.we: | ||||
|                             url=willexecutor['url'] | ||||
|                             if  willexecutor and Willexecutors.is_selected(willexecutor): | ||||
|                                 if not url in willexecutors: | ||||
|                                     willexecutor['txs']="" | ||||
|                                     willexecutor['txsids']=[] | ||||
|                                     willexecutor['broadcast_status']= _("Waiting...") | ||||
|                                     willexecutors[url]=willexecutor | ||||
|                                 willexecutors[url]['txs']+=str(willitem.tx)+"\n" | ||||
|                                 willexecutors[url]['txsids'].append(wid) | ||||
| 
 | ||||
| def get_willexecutor_transactions(will, force=False): | ||||
|     willexecutors ={} | ||||
|     for wid,willitem in will.items(): | ||||
|         if willitem.get_status('VALID'): | ||||
|             if willitem.get_status('COMPLETE'): | ||||
|                 if not willitem.get_status('PUSHED') or force: | ||||
|                     if willexecutor := willitem.we: | ||||
|                         url=willexecutor['url'] | ||||
|                         if  willexecutor and is_selected(willexecutor): | ||||
|                             if not url in willexecutors: | ||||
|                                 willexecutor['txs']="" | ||||
|                                 willexecutor['txsids']=[] | ||||
|                                 willexecutor['broadcast_status']= _("Waiting...") | ||||
|                                 willexecutors[url]=willexecutor | ||||
|                             willexecutors[url]['txs']+=str(willitem.tx)+"\n" | ||||
|                             willexecutors[url]['txsids'].append(wid) | ||||
|         return willexecutors | ||||
| 
 | ||||
|     return willexecutors | ||||
|     def only_selected_list(willexecutors): | ||||
|         out = {} | ||||
|         for url,v in willexecutors.items(): | ||||
|             if Willexecutors.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 'txs' in willexecutor: | ||||
|                     Willexecutors.push_transactions_to_willexecutor(willexecutors[url]['txs'],url) | ||||
| 
 | ||||
| def only_selected_list(willexecutors): | ||||
|     out = {} | ||||
|     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 is_selected(willexecutor): | ||||
|             if 'txs' in willexecutor: | ||||
|                 push_transactions_to_willexecutor(willexecutors[url]['txs'],url) | ||||
|     def send_request(method, url, data=None, *, timeout=10): | ||||
|         network = Network.get_instance() | ||||
|         if not network: | ||||
|             raise ErrorConnectingServer('You are offline.') | ||||
|         _logger.debug(f'<-- {method} {url} {data}') | ||||
|         headers = {} | ||||
|         headers['user-agent'] = 'BalPlugin' | ||||
|         headers['Content-Type']='text/plain' | ||||
| 
 | ||||
| def send_request(method, url, data=None, *, timeout=10): | ||||
|     network = Network.get_instance() | ||||
|     if not network: | ||||
|         raise ErrorConnectingServer('You are offline.') | ||||
|     _logger.debug(f'<-- {method} {url} {data}') | ||||
|     headers = {} | ||||
|     headers['user-agent'] = 'BalPlugin' | ||||
|     headers['Content-Type']='text/plain' | ||||
| 
 | ||||
|     try: | ||||
|         if method == 'get': | ||||
|             response = Network.send_http_on_proxy(method, url, | ||||
|                                                   params=data, | ||||
|                                                   headers=headers, | ||||
|                                                   on_finish=handle_response, | ||||
|                                                   timeout=timeout) | ||||
|         elif method == 'post': | ||||
|             response = Network.send_http_on_proxy(method, url, | ||||
|                                                   body=data, | ||||
|                                                   headers=headers, | ||||
|                                                   on_finish=handle_response, | ||||
|                                                   timeout=timeout) | ||||
|         try: | ||||
|             if method == 'get': | ||||
|                 response = Network.send_http_on_proxy(method, url, | ||||
|                                                       params=data, | ||||
|                                                       headers=headers, | ||||
|                                                       on_finish=Willexecutors.handle_response, | ||||
|                                                       timeout=timeout) | ||||
|             elif method == 'post': | ||||
|                 response = Network.send_http_on_proxy(method, url, | ||||
|                                                       body=data, | ||||
|                                                       headers=headers, | ||||
|                                                       on_finish=Willexecutors.handle_response, | ||||
|                                                       timeout=timeout) | ||||
|             else: | ||||
|                 raise Exception(f"unexpected {method=!r}") | ||||
|         except Exception as e: | ||||
|             _logger.error(f"exception sending request {e}") | ||||
|             raise e | ||||
|         else: | ||||
|             raise Exception(f"unexpected {method=!r}") | ||||
|     except Exception as e: | ||||
|         _logger.error(f"exception sending request {e}") | ||||
|         raise e | ||||
|     else: | ||||
|         _logger.debug(f'--> {response}') | ||||
|         return response | ||||
| async def handle_response(resp:ClientResponse): | ||||
|     r=await resp.text() | ||||
|     try: | ||||
|         r=json.loads(r) | ||||
|         r['status'] = resp.status | ||||
|         r['selected']=is_selected(willexecutor) | ||||
|         r['url']=url | ||||
|     except: | ||||
|             _logger.debug(f'--> {response}') | ||||
|             return response | ||||
|     async def handle_response(resp:ClientResponse): | ||||
|         r=await resp.text() | ||||
|         try: | ||||
|             r=json.loads(r) | ||||
|             r['status'] = resp.status | ||||
|             r['selected']=Willexecutors.is_selected(willexecutor) | ||||
|             r['url']=url | ||||
|         except: | ||||
|             pass     | ||||
|         return r | ||||
| 
 | ||||
|     class AlreadyPresentException(Exception): | ||||
|         pass | ||||
|     return r | ||||
|     def push_transactions_to_willexecutor(willexecutor): | ||||
|         out=True | ||||
|         try: | ||||
| 
 | ||||
| class AlreadyPresentException(Exception): | ||||
|     pass | ||||
| def push_transactions_to_willexecutor(willexecutor): | ||||
|     out=True | ||||
|     try: | ||||
|         _logger.debug(f"willexecutor['txs']") | ||||
|         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}") | ||||
|                 raise Exception(w) | ||||
|         else: | ||||
|             raise Exception("empty reply from:{willexecutor['url']}") | ||||
|     except Exception as e: | ||||
|         _logger.debug(f"error:{e}") | ||||
|         if str(e) == "already present": | ||||
|             raise AlreadyPresentException() | ||||
|         out=False | ||||
|         willexecutor['broadcast_stauts'] = _("Failed") | ||||
|             _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") | ||||
|                 _logger.debug(f"pushed: {w}") | ||||
|                 if w !='thx': | ||||
|                     _logger.debug(f"error: {w}") | ||||
|                     raise Exception(w) | ||||
|             else: | ||||
|                 raise Exception("empty reply from:{willexecutor['url']}") | ||||
|         except Exception as e: | ||||
|             _logger.debug(f"error:{e}") | ||||
|             if str(e) == "already present": | ||||
|                 raise Willexecutors.AlreadyPresentException() | ||||
|             out=False | ||||
|             willexecutor['broadcast_status'] = _("Failed") | ||||
| 
 | ||||
|     return out | ||||
|         return out | ||||
| 
 | ||||
| def ping_servers(willexecutors): | ||||
|     for url,we in willexecutors.items(): | ||||
|         get_info_task(url,we) | ||||
|     def ping_servers(willexecutors): | ||||
|         for url,we in willexecutors.items(): | ||||
|             Willexecutors.get_info_task(url,we) | ||||
| 
 | ||||
| 
 | ||||
| def get_info_task(url,willexecutor): | ||||
|     w=None | ||||
|     try: | ||||
|         _logger.info("GETINFO_WILLEXECUTOR") | ||||
|         _logger.debug(url) | ||||
|         w = send_request('get',url+"/"+constants.net.NET_NAME+"/info") | ||||
|     def get_info_task(url,willexecutor): | ||||
|         w=None | ||||
|         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") | ||||
|             willexecutor['url']=url | ||||
|             willexecutor['status'] = w['status'] | ||||
|             willexecutor['base_fee'] = w['base_fee'] | ||||
|             willexecutor['address'] = w['address'] | ||||
|             if not willexecutor['info']: | ||||
|                 willexecutor['info'] = w['info'] | ||||
|             _logger.debug(f"response_data {w['address']}") | ||||
|         except Exception as e: | ||||
|             _logger.error(f"error {e} contacting {url}: {w}") | ||||
|             willexecutor['status']="KO" | ||||
| 
 | ||||
|         willexecutor['last_update'] = datetime.now().timestamp() | ||||
|         return willexecutor | ||||
| 
 | ||||
|     def initialize_willexecutor(willexecutor,url,status=None,selected=None): | ||||
|         print("1",willexecutor) | ||||
|         willexecutor['url']=url | ||||
|         willexecutor['status'] = w['status'] | ||||
|         willexecutor['base_fee'] = w['base_fee'] | ||||
|         willexecutor['address'] = w['address'] | ||||
|         if not willexecutor['info']: | ||||
|             willexecutor['info'] = w['info'] | ||||
|         _logger.debug(f"response_data {w['address']}") | ||||
|     except Exception as e: | ||||
|         _logger.error(f"error {e} contacting {url}: {w}") | ||||
|         willexecutor['status']="KO" | ||||
|         print("2",status) | ||||
|         if not status is None: | ||||
|             willexecutor['status'] = status | ||||
|         willexecutor['selected'] = Willexecutors.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.config.set_key(bal_plugin.WILLEXECUTORS,l,save=True) | ||||
|             return l | ||||
|         except Exception as e: | ||||
|             _logger.error(f"error downloading 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.config.set_key(bal_plugin.WILLEXECUTORS,willexecutors,save=True) | ||||
|                 return h | ||||
|         except Exception as e: | ||||
|             _logger.error(f"errore aprendo willexecutors.json: {e}") | ||||
|             return {} | ||||
| 
 | ||||
|     willexecutor['last_update'] = datetime.now().timestamp() | ||||
|     return willexecutor | ||||
| 
 | ||||
| def initialize_willexecutor(willexecutor,url,status=None,selected=None): | ||||
|     willexecutor['url']=url | ||||
|     if not status is None: | ||||
|         willexecutor['status'] = status | ||||
|     willexecutor['selected'] = is_selected(willexecutor,selected) | ||||
| 
 | ||||
| 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.config.set_key(bal_plugin.WILLEXECUTORS,willexecutors,save=True) | ||||
|             return h | ||||
|     except Exception as e: | ||||
|         _logger.error(f"errore aprendo willexecutors.json: {e}") | ||||
|         return {} | ||||
| 
 | ||||
| def check_transaction(txid,url): | ||||
|     _logger.debug(f"{url}:{txid}") | ||||
|     try: | ||||
|         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 | ||||
|     def check_transaction(txid,url): | ||||
|         _logger.debug(f"{url}:{txid}") | ||||
|         try: | ||||
|             w = Willexecutors.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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user