Compare commits

...

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

13 changed files with 1512 additions and 3727 deletions

View File

@ -1 +0,0 @@
0.2.2a

View File

@ -1 +1,20 @@
from electrum.i18n import _
import subprocess
from . import bal_resources
BUILD_NUMBER = 1
REVISION_NUMBER = 1
VERSION_NUMBER = 0
def _version():
return f'{VERSION_NUMBER}.{REVISION_NUMBER}-{BUILD_NUMBER}'
version = _version()
author = "Bal Enterprise inc."
fullname = _('B.A.L.')
description = ''.join([
"<img src='",bal_resources.icon_path('bal16x16.png'),"'>", _("Bitcoin After Life"), '<br/>',
_("For more information, visit"),
" <a href=\"https://bitcoin-after.life/\">https://bitcoin-after.life/</a><br/>",
"<p style='font-size:8pt;vertialAlign:bottom'>Version: ", _version(),"</p>"
])
#available_for = ['qt', 'cmdline', 'qml']
available_for = ['qt']

162
bal.py
View File

@ -1,128 +1,126 @@
import random import random
import os 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.plugin import BasePlugin
from electrum.util import to_bytes, bfh
from electrum import json_db from electrum import json_db
from electrum.transaction import tx_from_any from electrum.transaction import tx_from_any
from . import util as Util
from . import willexecutors as Willexecutors
import os import os
json_db.register_dict('heirs', tuple, None) json_db.register_dict('heirs', tuple, None)
json_db.register_dict('will', lambda x: get_will(x), None) json_db.register_dict('will', lambda x: get_will(x), None)
json_db.register_dict('will_settings', lambda x:x, None) json_db.register_dict('will_settings', lambda x:x, None)
from electrum.logging import get_logger from electrum.logging import get_logger
def get_will(x): def get_will(x):
try: try:
#print("______________________________________________________________________________________________________")
#print(x)
x['tx']=tx_from_any(x['tx']) x['tx']=tx_from_any(x['tx'])
except Exception as e: except Exception as e:
#Util.print_var(x)
raise e raise e
return x return x
class BalConfig():
def __init__(self, config, name, default):
self.config = config
self.name = name
self.default = default
def get(self,default=None):
v = self.config.get(self.name, default)
if v is None:
if not default is None:
v = default
else:
v = self.default
return v
def set(self,value,save=True):
self.config.set_key(self.name,value,save=save)
class BalPlugin(BasePlugin): class BalPlugin(BasePlugin):
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"
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
}
},
}
LATEST_VERSION = '1' LATEST_VERSION = '1'
KNOWN_VERSIONS = ('0', '1') KNOWN_VERSIONS = ('0', '1')
assert LATEST_VERSION in KNOWN_VERSIONS 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) SIZE = (159, 97)
def __init__(self, parent, config, name): def __init__(self, parent, config, name):
self.logger = get_logger(__name__) self.logger= get_logger(__name__)
BasePlugin.__init__(self, parent, config, name) BasePlugin.__init__(self, parent, config, name)
self.base_dir = os.path.join(config.electrum_path(), 'bal') self.base_dir = os.path.join(config.electrum_path(), 'bal')
self.plugin_dir = os.path.split(os.path.realpath(__file__))[0] self.logger.info(self.base_dir)
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.parent = parent
self.config = config self.config = config
self.name = name self.name = name
self._hide_invalidated= self.config_get(self.HIDE_INVALIDATED)
self.ASK_BROADCAST = BalConfig(config, "bal_ask_broadcast", True) self._hide_replaced= self.config_get(self.HIDE_REPLACED)
self.BROADCAST = BalConfig(config, "bal_broadcast", True) self.plugin_dir = os.path.split(os.path.realpath(__file__))[0]
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': {
"base_fee": 100000,
"status": "New",
"info":"Bitcoin After Life Will Executor",
"address":"bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7",
"selected":True
}
}
})
self.WILL_SETTINGS = BalConfig(config, "bal_will_settings", {
'tx_fees':100,
'threshold':'180d',
'locktime':'1y',
})
self._hide_invalidated= self.HIDE_INVALIDATED.get()
self._hide_replaced= self.HIDE_REPLACED.get()
def resource_path(self,*parts): def resource_path(self,*parts):
return os.path.join(self.plugin_dir, *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): def hide_invalidated(self):
self._hide_invalidated = not self._hide_invalidated 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): def hide_replaced(self):
self._hide_replaced = not self._hide_replaced 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): def validate_will_settings(self,will_settings):
if int(will_settings.get('tx_fees',1))<1: if int(will_settings.get('tx_fees',1))<1:
will_settings['tx_fees']=1 will_settings['tx_fees']=1

View File

@ -2,7 +2,7 @@ import os
PLUGIN_DIR = os.path.split(os.path.realpath(__file__))[0] PLUGIN_DIR = os.path.split(os.path.realpath(__file__))[0]
DEFAULT_ICON = 'bal32x32.png' DEFAULT_ICON = 'bal32x32.png'
DEFAULT_ICON_PATH = '' DEFAULT_ICON_PATH = 'icons'
def icon_path(icon_basename: str = DEFAULT_ICON): 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): def __init__(self, plugin,variable,window=None):
QCheckBox.__init__(self) QCheckBox.__init__(self)
self.setChecked(plugin.config_get(variable)) self.setChecked(plugin.config_get(variable))
window=window
def on_check(v): def on_check(v):
plugin.config.set_key(variable, v == 2) plugin.config.set_key(variable, v == Qt.CheckState.Checked, save=True)
plugin.config_get(variable) 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) 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._stopping=True
#self.on_success_phase2() #self.on_success_phase2()
# return # return
_logger.debug("have to sign {}".format(self.have_to_sign)) _logger.debug("have to sign",self.have_to_sign)
password=None password=None
if self.have_to_sign is None: if self.have_to_sign is None:
self.msg_set_invalidating() self.msg_set_invalidating()

View File

@ -199,6 +199,7 @@ class WillExecutorDialog(BalDialog,MessageBoxMixin):
def __init__(self, bal_window): def __init__(self, bal_window):
BalDialog.__init__(self,bal_window.window) BalDialog.__init__(self,bal_window.window)
self.bal_plugin = bal_window.bal_plugin self.bal_plugin = bal_window.bal_plugin
self.gui_object = self.bal_plugin.gui_object
self.config = self.bal_plugin.config self.config = self.bal_plugin.config
self.window = bal_window.window self.window = bal_window.window
self.bal_window = bal_window self.bal_window = bal_window

View File

@ -14,8 +14,9 @@ from electrum.transaction import PartialTxInput, PartialTxOutput,TxOutpoint,Part
import datetime import datetime
import urllib.request import urllib.request
import urllib.parse import urllib.parse
from .util import Util from .bal import BalPlugin
from .willexecutors import Willexecutors from . import util as Util
from . import willexecutors as Willexecutors
if TYPE_CHECKING: if TYPE_CHECKING:
from .wallet_db import WalletDB from .wallet_db import WalletDB
from .simple_config import SimpleConfig from .simple_config import SimpleConfig
@ -37,7 +38,6 @@ def reduce_outputs(in_amount, out_amount, fee, outputs):
for output in outputs: for output in outputs:
output.value = math.floor((in_amount-fee)/out_amount * output.value) 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 #TODO: put this method inside wallet.db to replace or complete get_locktime_for_new_transaction
def get_current_height(network:'Network'): def get_current_height(network:'Network'):
#if no network or not up to date, just set locktime to zero #if no network or not up to date, just set locktime to zero
@ -57,7 +57,7 @@ def get_current_height(network:'Network'):
# discourage "fee sniping" # discourage "fee sniping"
height = min(chain_height, server_height) height = min(chain_height, server_height)
return height return height
"""
@ -386,7 +386,7 @@ class Heirs(dict, Logger):
utxos = wallet.get_utxos() utxos = wallet.get_utxos()
willexecutors = Willexecutors.get_willexecutors(bal_plugin) or {} willexecutors = Willexecutors.get_willexecutors(bal_plugin) or {}
self.decimal_point=bal_plugin.config.get_decimal_point() self.decimal_point=bal_plugin.config.get_decimal_point()
no_willexecutors = bal_plugin.NO_WILLEXECUTOR.get() no_willexecutors = bal_plugin.config_get(BalPlugin.NO_WILLEXECUTOR)
for utxo in utxos: for utxo in utxos:
if utxo.value_sats()> 0*tx_fees: if utxo.value_sats()> 0*tx_fees:
balance += utxo.value_sats() balance += utxo.value_sats()
@ -563,7 +563,10 @@ class Heirs(dict, Logger):
def validate_amount(amount): def validate_amount(amount):
try: 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: if famount <= 0.00000001:
raise AmountNotValid(f"amount have to be positive {famount} < 0") raise AmountNotValid(f"amount have to be positive {famount} < 0")
except Exception as e: except Exception as e:
@ -572,8 +575,9 @@ class Heirs(dict, Logger):
def validate_locktime(locktime,timestamp_to_check=False): def validate_locktime(locktime,timestamp_to_check=False):
try: try:
locktime = Util.parse_locktime_string(locktime,None)
if timestamp_to_check: if timestamp_to_check:
if Util.parse_locktime_string(locktime,None) < timestamp_to_check: if locktime < timestamp_to_check:
raise HeirExpiredException() raise HeirExpiredException()
except Exception as e: except Exception as e:
raise LocktimeNotValid(f"locktime string not properly formatted, {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.2a",
"author":"Svatantrya",
"available_for": ["qt"],
"icon":"icons/bal32x32.png"
}

2688
qt.py

File diff suppressed because it is too large Load Diff

811
util.py
View File

@ -8,430 +8,451 @@ import urllib.parse
from electrum.util import write_json_file,FileImportFailed,FileExportFailed from electrum.util import write_json_file,FileImportFailed,FileExportFailed
LOCKTIME_THRESHOLD = 500000000 LOCKTIME_THRESHOLD = 500000000
class Util: def locktime_to_str(locktime):
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:
try: try:
locktime=int(locktime) return int(float(amount)*pow(10,decimal_point))
if locktime > LOCKTIME_THRESHOLD: except:
dt = datetime.fromtimestamp(locktime).isoformat() return 0
return dt
except Exception as e: def decode_amount(amount,decimal_point):
pass if is_perc(amount):
return str(locktime) return amount
else:
num=8-decimal_point
basestr="{{:0{}.{}f}}".format(num,num)
return "{:08.8f}".format(float(amount)/pow(10,decimal_point))
def str_to_locktime(locktime): def is_perc(value):
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: try:
return value[-1] == '%' return value[-1] == '%'
except: except:
return False return False
def cmp_array(heira,heirb): def cmp_array(heira,heirb):
try: try:
if not len(heira) == len(heirb): if not len(heira) == len(heirb):
return False
for h in range(0,len(heira)):
if not heira[h] == heirb[h]:
return False return False
for h in range(0,len(heira)): return True
if not heira[h] == heirb[h]: except:
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 return False
def cmp_willexecutor(willexecutora,willexecutorb): def cmp_heir(heira,heirb):
if willexecutora == willexecutorb: if heira[0] == heirb[0] and heira[1] == heirb[1]:
return True return True
try: return False
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): def cmp_willexecutor(willexecutora,willexecutorb):
for h,v in heirs.items(): 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):
#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]:
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:
found = False found = False
for val in values: for heirb in heirsb:
if val in v and v[val] != heir[val]: if cmp_heir_by_values(heirsa[heira],heirsb[heirb],values):
found = True found=True
if not found: if not found:
return h #print(f"not_found {heira}--{heirsa[heira]}")
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
if reverse:
return cmp_heirs(heirsb,heirsa,cmp_function,False)
else:
return True
except Exception as e:
raise e
return False return False
def cmp_heir_by_values(heira,heirb,values): def cmp_inputs(inputsa,inputsb):
for v in values: if len(inputsa) != len(inputsb):
if heira[v] != heirb[v]: return False
return False for inputa in inputsa:
return True if not in_utxo(inputa,inputsb):
return False
return True
def cmp_heirs_by_values(heirsa,heirsb,values,exclude_willexecutors=False,reverse = True): def cmp_outputs(outputsa,outputsb,willexecutor_output = None):
for heira in heirsa: if len(outputsa) != len(outputsb):
if (exclude_willexecutors and not "w!ll3x3c\"" in heira) or not exclude_willexecutors: return False
found = False for outputa in outputsa:
for heirb in heirsb: if not cmp_output(outputa,willexecutor_output):
if Util.cmp_heir_by_values(heirsa[heira],heirsb[heirb],values): if not in_output(outputa,outputsb):
found=True return False
if not found: return True
return False
if reverse: def cmp_txs(txa,txb):
return Util.cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False) 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: else:
return True 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()
def cmp_heirs(heirsa,heirsb,cmp_function = lambda x,y: x[0]==y[0] and x[3]==y[3],reverse=True): return utxos
try:
for heir in heirsa: def utxo_to_str(utxo):
if not "w!ll3x3c\"" in heir: try: return utxo.to_str()
if not heir in heirsb or not cmp_function(heirsa[heir],heirsb[heir]): except Exception as e: pass
if not Util.search_heir_by_values(heirsb,heirsa[heir],[0,3]): try: return utxo.prevout.to_str()
return False except Exception as e: pass
if reverse: return str(utxo)
return Util.cmp_heirs(heirsb,heirsa,cmp_function,False)
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
else: 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 pass
#print("NOT SAME_:",out.address,s_o.address)
return value_amount if len(same_amount)>0:
return True, False
else:return False, False
def get_change_output(wallet,in_amount,out_amount,fee):
def chk_locktime(timestamp_to_check,block_height_to_check,locktime): change_amount = int(in_amount - out_amount - fee)
#TODO BUG: WHAT HAPPEN AT THRESHOLD? if change_amount > wallet.dust_threshold():
locktime=int(locktime) change_addresses = wallet.get_change_addresses_for_new_transaction()
if locktime > LOCKTIME_THRESHOLD and locktime > timestamp_to_check: out = PartialTxOutput.from_address_and_value(change_addresses[0], change_amount)
return True out.is_change = 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 return out
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 get_lowest_valid_tx(available_utxos,will): def get_current_height(network:'Network'):
will = sorted(will.items(),key = lambda x: x[1]['tx'].locktime) #if no network or not up to date, just set locktime to zero
for txid,willitem in will.items(): if not network:
pass return 0
chain = network.blockchain()
def get_locktimes(will): if chain.is_tip_stale():
locktimes = {} return 0
for txid,willitem in will.items(): # figure out current block height
locktimes[willitem['tx'].locktime]=True chain_height = chain.height() # learnt from all connected servers, SPV-checked
return locktimes.keys() 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)
def get_lowest_locktimes(locktimes): # - if it's lagging too much, it is the network's job to switch away
sorted_timestamp=[] if server_height < chain_height - 10:
sorted_block=[] # the diff is suspiciously large... give up and use something non-fingerprintable
for l in locktimes: return 0
l=Util.parse_locktime_string(l) # discourage "fee sniping"
if l < LOCKTIME_THRESHOLD: height = min(chain_height, server_height)
bisect.insort(sorted_block,l) return height
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): def print_var(var,name = "",veryverbose=False):
same_amount=[] print(f"---{name}---")
for s_o in outputs: if not var is None:
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: try:
exporter(filename) print("doc:",doc(var))
except FileExportFailed as e: except: pass
electrum_window.show_critical(str(e)) try:
else: print("str:",str(var))
electrum_window.show_message(_("Your {0} were exported to '{1}'") except: pass
.format(title, str(filename))) 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)))
def copy(dicto,dictfrom): def copy(dicto,dictfrom):
for k,v in dictfrom.items(): for k,v in dictfrom.items():
dicto[k]=v dicto[k]=v

1092
will.py

File diff suppressed because it is too large Load Diff

View File

@ -8,249 +8,196 @@ from electrum import constants
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.gui.qt.util import WaitingDialog from electrum.gui.qt.util import WaitingDialog
from electrum.i18n import _ 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 DEFAULT_TIMEOUT = 5
_logger = get_logger(__name__) _logger = get_logger(__name__)
class Willexecutors:
def save(bal_plugin, willexecutors): def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True):
aw=bal_plugin.WILLEXECUTORS.get() willexecutors = bal_plugin.config_get(bal_plugin.WILLEXECUTORS)
aw[constants.net.NET_NAME]=willexecutors for w in willexecutors:
bal_plugin.WILLEXECUTORS.set(aw) initialize_willexecutor(willexecutors[w],w)
def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True): bal=bal_plugin.DEFAULT_SETTINGS[bal_plugin.WILLEXECUTORS]
willexecutors = bal_plugin.WILLEXECUTORS.get() for bal_url,bal_executor in bal.items():
willexecutors=willexecutors.get(constants.net.NET_NAME,{}) if not bal_url in willexecutors:
to_del=[] _logger.debug("replace bal")
for w in willexecutors: willexecutors[bal_url]=bal_executor
if not isinstance(willexecutors[w],dict): if update:
to_del.append(w) found = False
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,{})
for bal_url,bal_executor in bal.items():
if not bal_url in willexecutors:
_logger.debug(f"force add {bal_url} willexecutor")
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.PING_WILLEXECUTORS.get() or force:
ping_willexecutors = True
if bal_plugin.ASK_PING_WILLEXECUTORS.get() and not force:
if bal_window:
ping_willexecutors = bal_window.window.question(_("Contact willexecutors servers to update payment informations?"))
if ping_willexecutors:
if task:
bal_window.ping_willexecutors(willexecutors,task)
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
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)
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 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'] = f"BalPlugin v:{BalPlugin.version()}"
headers['Content-Type']='text/plain'
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:
_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
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")
_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
def ping_servers(willexecutors):
for url,we in willexecutors.items(): for url,we in willexecutors.items():
Willexecutors.get_info_task(url,we) 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 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
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'
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)
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:
pass
return r
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")
return out
def ping_servers(willexecutors):
for url,we in willexecutors.items():
get_info_task(url,we)
def get_info_task(url,willexecutor): def get_info_task(url,willexecutor):
w=None w=None
try: try:
_logger.info("GETINFO_WILLEXECUTOR") _logger.info("GETINFO_WILLEXECUTOR")
_logger.debug(url) _logger.debug(url)
netname="bitcoin" w = send_request('get',url+"/"+constants.net.NET_NAME+"/info")
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):
willexecutor['url']=url willexecutor['url']=url
if not status is None: willexecutor['status'] = w['status']
willexecutor['status'] = status willexecutor['base_fee'] = w['base_fee']
willexecutor['selected'] = Willexecutors.is_selected(willexecutor,selected) 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"
def download_list(bal_plugin): willexecutor['last_update'] = datetime.now().timestamp()
try: return willexecutor
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: def initialize_willexecutor(willexecutor,url,status=None,selected=None):
_logger.error(f"Failed to download willexecutors list: {e}") willexecutor['url']=url
return {} if not status is None:
def get_willexecutors_list_from_json(bal_plugin): willexecutor['status'] = status
try: willexecutor['selected'] = is_selected(willexecutor,selected)
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)
return h
except Exception as e:
_logger.error(f"error opening willexecutors json: {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 {}
def check_transaction(txid,url): def check_transaction(txid,url):
_logger.debug(f"{url}:{txid}") _logger.debug(f"{url}:{txid}")
try: try:
w = Willexecutors.send_request('post',url+"/searchtx",data=txid.encode('ascii')) w = send_request('post',url+"/searchtx",data=txid.encode('ascii'))
return w return w
except Exception as e: except Exception as e:
_logger.error(f"error contacting {url} for checking txs {e}") _logger.error(f"error contacting {url} for checking txs {e}")
raise 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']
)