Compare commits

..

No commits in common. "main" and "v0.1.0" have entirely different histories.
main ... v0.1.0

15 changed files with 1527 additions and 4030 deletions

View File

@ -1 +0,0 @@
0.2.2b

View File

@ -1 +1,20 @@
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']

181
bal.py
View File

@ -1,149 +1,132 @@
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
def get_will_settings(x):
print(x)
json_db.register_dict('heirs', tuple, None)
json_db.register_dict('will', dict,None)
json_db.register_dict('will', lambda x: get_will(x), None)
json_db.register_dict('will_settings', lambda x:x, None)
#{'rubiconda': ['bcrt1qgv0wu4v6kjzef5mnxfh2m9z6y7mez0ja0tt8mu', '45%', '1y'], 'veronica': ['bcrt1q6vxuvwrt8x5c9u9u29y5uq7frscr0vgc2dy60j', '15%', '1y']}
from electrum.logging import get_logger
def get_will_settings(x):
print(x)
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):
print("init bal_config")
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):
print("init bal_plugin")
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", {
'baltx_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):
print(type(will_settings))
print(will_settings.get('baltx_fees',1),1)
if int(will_settings.get('baltx_fees',1))<1:
will_settings['baltx_fees']=1
if int(will_settings.get('tx_fees',1))<1:
will_settings['tx_fees']=1
if not will_settings.get('threshold'):
will_settings['threshold']='180d'
if not will_settings.get('locktime')=='':
will_settings['locktime']='1y'
return will_settings
def default_will_settings(self):
return {
'baltx_fees':100,
'threshold':'180d',
'locktime':'1y'
}

View File

@ -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):

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -14,9 +14,9 @@ from electrum.transaction import PartialTxInput, PartialTxOutput,TxOutpoint,Part
import datetime
import urllib.request
import urllib.parse
import random
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
@ -38,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
@ -58,7 +57,7 @@ def get_current_height(network:'Network'):
# discourage "fee sniping"
height = min(chain_height, server_height)
return height
"""
@ -113,9 +112,7 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet):
change = get_change_output(wallet, in_amount, out_amount, fee)
if change:
outputs.append(change)
for i in range(0,100):
random.shuffle(outputs)
print(outputs)
tx = PartialTransaction.from_io(used_utxos, outputs, locktime=Util.parse_locktime_string(locktime,wallet), version=2)
if len(description)>0: tx.description = description[:-1]
else: tx.description = ""
@ -388,8 +385,8 @@ class Heirs(dict, Logger):
if not utxos:
utxos = wallet.get_utxos()
willexecutors = Willexecutors.get_willexecutors(bal_plugin) or {}
self.decimal_point=bal_plugin.get_decimal_point()
no_willexecutors = bal_plugin.NO_WILLEXECUTOR.get()
self.decimal_point=bal_plugin.config.get_decimal_point()
no_willexecutors = bal_plugin.config_get(BalPlugin.NO_WILLEXECUTOR)
for utxo in utxos:
if utxo.value_sats()> 0*tx_fees:
balance += utxo.value_sats()
@ -566,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:
@ -575,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}")

View File

@ -1,9 +0,0 @@
{
"name": "BAL",
"fullname": "Bitcoin After Life",
"description": "Provides free and decentralized inheritance support<br> Version: 0.2.2b",
"author":"Svatantrya",
"available_for": ["qt"],
"icon":"icons/bal32x32.png"
}

2701
qt.py

File diff suppressed because it is too large Load Diff

81
util.py
View File

@ -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):

View File

@ -1,69 +0,0 @@
#!env/bin/python3
from electrum.storage import WalletStorage
from electrum.util import MyEncoder
import json
import sys
import getpass
import os
default_fees= 100
def fix_will_settings_tx_fees(json_wallet):
tx_fees = json_wallet.get('will_settings',{}).get('tx_fees',False)
have_to_update=False
if tx_fees:
json_wallet['will_settings']['baltx_fees']=tx_fees
del json_wallet['will_settings']['tx_fees']
have_to_update=True
for txid,willitem in json_wallet['will'].items():
tx_fees=willitem.get('tx_fees',False)
if tx_fees:
json_wallet['will'][txid]['baltx_fees']=tx_fees
del json_wallet['will'][txid]['tx_fees']
have_to_update=True
return have_to_update
def uninstall_bal(json_wallet):
del json_wallet['will_settings']
del json_wallet['will']
del json_wallet['heirs']
return True
def save(json_wallet,storage):
human_readable=not storage.is_encrypted()
storage.write(json.dumps(
json_wallet,
indent=4 if human_readable else None,
sort_keys=bool(human_readable),
cls=MyEncoder,
))
def read_wallet(path,password=False):
storage=WalletStorage(path)
if storage.is_encrypted():
if password==False:
password = getpass.getpass("Enter wallet password: ", stream = None)
storage.decrypt(password)
data=storage.read()
json_wallet=json.loads('['+data+']')[0]
return json_wallet
if __name__ == '__main__':
if len(sys.argv) <3:
print("usage: ./bal_wallet_utils <command> <wallet path>")
print("available commands: uninstall, fix")
exit(1)
if not os.path.exists(sys.argv[2]):
print("Error: wallet not found")
exit(1)
command = sys.argv[1]
path = sys.argv[2]
json_wallet = read_wallet(path)
have_to_save=False
if command == 'fix':
have_to_save = fix_will_settings_tx_fees(json_wallet)
if command == 'uninstall':
have_to_save = uninstall_bal(json_wallet)
if have_to_save:
save(json_wallet,storage)
else:
print("nothing to do")

View File

@ -1,188 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import json
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QWidget, QFileDialog,
QGroupBox, QTextEdit)
from PyQt6.QtCore import Qt
from electrum.storage import WalletStorage
from electrum.util import MyEncoder
from bal_wallet_utils import fix_will_settings_tx_fees,uninstall_bal,read_wallet
class WalletUtilityGUI(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('BAL Wallet Utility')
self.setFixedSize(500, 400)
# Central widget
central_widget = QWidget()
self.setCentralWidget(central_widget)
# Main layout
layout = QVBoxLayout(central_widget)
# Wallet input group
wallet_group = QGroupBox("Wallet Settings")
wallet_layout = QVBoxLayout(wallet_group)
# Wallet path
wallet_path_layout = QHBoxLayout()
wallet_path_layout.addWidget(QLabel("Wallet Path:"))
self.wallet_path_edit = QLineEdit()
self.wallet_path_edit.setPlaceholderText("Select wallet path...")
wallet_path_layout.addWidget(self.wallet_path_edit)
self.browse_btn = QPushButton("Browse...")
self.browse_btn.clicked.connect(self.browse_wallet)
wallet_path_layout.addWidget(self.browse_btn)
wallet_layout.addLayout(wallet_path_layout)
# Password
password_layout = QHBoxLayout()
password_layout.addWidget(QLabel("Password:"))
self.password_edit = QLineEdit()
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
self.password_edit.setPlaceholderText("Enter password (if encrypted)")
password_layout.addWidget(self.password_edit)
wallet_layout.addLayout(password_layout)
layout.addWidget(wallet_group)
# Output area
output_group = QGroupBox("Output")
output_layout = QVBoxLayout(output_group)
self.output_text = QTextEdit()
self.output_text.setReadOnly(True)
output_layout.addWidget(self.output_text)
layout.addWidget(output_group)
# Action buttons
buttons_layout = QHBoxLayout()
self.fix_btn = QPushButton("Fix")
self.fix_btn.clicked.connect(self.fix_wallet)
self.fix_btn.setEnabled(False)
buttons_layout.addWidget(self.fix_btn)
self.uninstall_btn = QPushButton("Uninstall")
self.uninstall_btn.clicked.connect(self.uninstall_wallet)
self.uninstall_btn.setEnabled(False)
buttons_layout.addWidget(self.uninstall_btn)
layout.addLayout(buttons_layout)
# Connections to enable buttons when path is entered
self.wallet_path_edit.textChanged.connect(self.check_inputs)
def browse_wallet(self):
file_path, _ = QFileDialog.getOpenFileName(
self,
"Select Wallet",
"*",
"Electrum Wallet (*)"
)
if file_path:
self.wallet_path_edit.setText(file_path)
def check_inputs(self):
wallet_path = self.wallet_path_edit.text().strip()
has_path = bool(wallet_path) and os.path.exists(wallet_path)
self.fix_btn.setEnabled(has_path)
self.uninstall_btn.setEnabled(has_path)
def log_message(self, message):
self.output_text.append(message)
def fix_wallet(self):
self.process_wallet('fix')
def uninstall_wallet(self):
self.log_message("WARNING: This will remove all BAL settings. This operation cannot be undone.")
self.process_wallet('uninstall')
def process_wallet(self, command):
wallet_path = self.wallet_path_edit.text().strip()
password = self.password_edit.text()
if not wallet_path:
self.log_message("ERROR: Please enter wallet path")
return
if not os.path.exists(wallet_path):
self.log_message("ERROR: Wallet not found")
return
try:
self.log_message(f"Processing wallet: {wallet_path}")
storage = WalletStorage(wallet_path)
# Decrypt if necessary
if storage.is_encrypted():
if not password:
self.log_message("ERROR: Wallet is encrypted, please enter password")
return
try:
storage.decrypt(password)
self.log_message("Wallet decrypted successfully")
except Exception as e:
self.log_message(f"ERROR: Wrong password: {str(e)}")
return
# Read wallet
data = storage.read()
json_wallet = json.loads('[' + data + ']')[0]
have_to_save = False
message = ""
if command == 'fix':
have_to_save = fix_will_settings_tx_fees(json_wallet)
message = "Fix applied successfully" if have_to_save else "No fix needed"
elif command == 'uninstall':
have_to_save = uninstall_bal(json_wallet)
message = "BAL uninstalled successfully" if have_to_save else "No BAL settings found to uninstall"
if have_to_save:
try:
save_wallet(json_wallet, storage)
self.log_message(f"SUCCESS: {message}")
except Exception as e:
self.log_message(f"Save error: {str(e)}")
else:
self.log_message(f"INFO: {message}")
except Exception as e:
error_msg = f"ERROR: Processing failed: {str(e)}"
self.log_message(error_msg)
def main():
app = QApplication(sys.argv)
# Check if dependencies are available
try:
from electrum.storage import WalletStorage
from electrum.util import MyEncoder
except ImportError as e:
print(f"ERROR: Cannot import Electrum dependencies: {str(e)}")
return 1
window = WalletUtilityGUI()
window.show()
return app.exec()
if __name__ == '__main__':
sys.exit(main())

138
will.py
View File

@ -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,14 +646,14 @@ 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)
self.description = w.get('description',None)
self.time = w.get('time',None)
self.change = w.get('change',None)
self.tx_fees = w.get('baltx_fees',0)
self.tx_fees = w.get('tx_fees',0)
self.father = w.get('Father',None)
self.children = w.get('Children',None)
self.STATUS = copy.deepcopy(WillItem.STATUS_DEFAULT)
@ -658,7 +683,7 @@ class WillItem(Logger):
'description':self.description,
'time':self.time,
'change':self.change,
'baltx_fees':self.tx_fees
'tx_fees':self.tx_fees
}
for key in self.STATUS:
try:
@ -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

View File

@ -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']
)