Skip to content

Commit

Permalink
bot-gui
Browse files Browse the repository at this point in the history
  • Loading branch information
clifordsymack committed Jul 23, 2018
1 parent dfd75a5 commit 4fd8aca
Show file tree
Hide file tree
Showing 5 changed files with 445 additions and 94 deletions.
169 changes: 91 additions & 78 deletions shuffle/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@
import argparse
import requests
import schedule

import imp
imp.load_module('electroncash', *imp.find_module('lib'))
imp.load_module('electroncash_gui', *imp.find_module('gui'))
imp.load_module('electroncash_plugins', *imp.find_module('plugins'))

from electroncash.network import Network, SimpleConfig
from electroncash.address import Address
from electroncash.bitcoin import deserialize_privkey, regenerate_key
from electroncash.networks import NetworkConstants
from electroncash_plugins.shuffle.client import ProtocolThread
# from electroncash_plugins.shuffle.client import ProtocolThread
from electroncash_plugins.shuffle.client import bot_job
from electroncash_plugins.shuffle.coin import Coin
from electroncash.storage import WalletStorage
from electroncash.wallet import Wallet



def parse_args():
parser = argparse.ArgumentParser(description="CashShuffle bot")
parser.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet")
Expand Down Expand Up @@ -43,11 +51,13 @@ def is_protocol_done(pThread):

class SimpleLogger(object):

def __init__(self):
def __init__(self, logchan = None):
self.pThread = None
self.logchan = logchan

def send(self, message):
print("[CashShuffle Bot] {}".format(message))
if self.logchan == None:
print("[CashShuffle Bot] {}".format(message))
if message.startswith("Error"):
self.pThread.done.set()
elif message.startswith("Blame"):
Expand All @@ -58,82 +68,85 @@ def send(self, message):
else:
self.pThread.done.set()

# def job():
# job_start_time = time()
# pools = []
# pool_size = None
# try:
# res = requests.get(stat_endpoint, verify=False)
# pools = res.json().get("pools", [])
# pool_size = res.json().get("PoolSize", None)
# except:
# basic_logger.send("[CashShuffle Bot] Stat server not respond")
# return
# if len(pools) > 0:
# # Select not full pools with members more then limit
# members = [pool for pool in pools
# if not pool.get("full", False) and
# pool.get("members", 0) >= args.limit]
# # Select unspent outputs in the wallet
# utxos = wallet.get_utxos(exclude_frozen=True, confirmed_only=False)
# # Select fresh inputs
# fresh_outputs = wallet.get_unused_addresses()
# if len(members) == 0:
# basic_logger.send("[CashShuffle] No pools sutisfiying the requirments")
# else:
# basic_logger.send("[CashShuffle] Trying to support {} pools".format(len(members)))
# for member in members:
# number_of_players = member['members']
# threshold = min(number_of_players + args.maximum_per_pool, pool_size)
# member.update({"addresses" : []})
# amount = member['amount'] + fee
# good_utxos = [utxo for utxo in utxos if utxo['value'] > amount]
# for good_utxo in good_utxos:
# addr = Address.to_string(good_utxo['address'], Address.FMT_LEGACY)
# try:
# first_utxo = coin.get_first_sufficient_utxo(addr, amount)
# if first_utxo:
# address = {}
# address.update({"input_address": good_utxo['address']})
# address.update({"change_address": addr})
# address.update({"shuffle_address": Address.to_string(fresh_outputs[0], Address.FMT_LEGACY)})
# member['addresses'].append(address)
# del fresh_outputs[0]
# utxos.remove(good_utxo)
# number_of_players += 1
# if number_of_players == threshold:
# break
# except Exception as e:
# basic_logger.send("[CashShuffle Bot] {}".format(e))
# basic_logger.send("[CashShuffle Bot] Network problems")
# # Define Protocol threads
# pThreads = []
# for member in members:
# amount = member["amount"]
# if member.get("addresses", None):
# for address in member.get("addresses"):
# priv_key = wallet.export_private_key(address["input_address"], password)
# sk, pubk = keys_from_priv(priv_key)
# new_addr = address["shuffle_address"]
# change = address["change_address"]
# logger = SimpleLogger()
# pThread = (ProtocolThread(host, port, network, amount, fee, sk, pubk, new_addr, change, logger=logger, ssl=ssl))
# logger.pThread = pThread
# pThreads.append(pThread)
# # start Threads
# for pThread in pThreads:
# pThread.start()
# done = False
# while not done:
# sleep(1)
# done = all([is_protocol_done(pThread) for pThread in pThreads])
# if (time() - job_start_time) > 1000:
# "Protocol execution Time Out"
# done = True
# for pThread in pThreads:
# pThread.join()
# else:
# basic_logger.send("[CashShuffle Bot] Nobody in the pools")

def job():
job_start_time = time()
pools = []
pool_size = None
try:
res = requests.get(stat_endpoint, verify=False)
pools = res.json().get("pools", [])
pool_size = res.json().get("PoolSize", None)
except:
basic_logger.send("[CashShuffle Bot] Stat server not respond")
return
if len(pools) > 0:
# Select not full pools with members more then limit
members = [pool for pool in pools
if not pool.get("full", False) and
pool.get("members", 0) >= args.limit]
# Select unspent outputs in the wallet
utxos = wallet.get_utxos(exclude_frozen=True, confirmed_only=False)
# Select fresh inputs
fresh_outputs = wallet.get_unused_addresses()
if len(members) == 0:
basic_logger.send("[CashShuffle] No pools sutisfiying the requirments")
else:
basic_logger.send("[CashShuffle] Trying to support {} pools".format(len(members)))
for member in members:
number_of_players = member['members']
threshold = min(number_of_players + args.maximum_per_pool, pool_size)
member.update({"addresses" : []})
amount = member['amount'] + fee
good_utxos = [utxo for utxo in utxos if utxo['value'] > amount]
for good_utxo in good_utxos:
addr = Address.to_string(good_utxo['address'], Address.FMT_LEGACY)
try:
first_utxo = coin.get_first_sufficient_utxo(addr, amount)
if first_utxo:
address = {}
address.update({"input_address": good_utxo['address']})
address.update({"change_address": addr})
address.update({"shuffle_address": Address.to_string(fresh_outputs[0], Address.FMT_LEGACY)})
member['addresses'].append(address)
del fresh_outputs[0]
utxos.remove(good_utxo)
number_of_players += 1
if number_of_players == threshold:
break
except Exception as e:
basic_logger.send("[CashShuffle Bot] {}".format(e))
basic_logger.send("[CashShuffle Bot] Network problems")
# Define Protocol threads
pThreads = []
for member in members:
amount = member["amount"]
if member.get("addresses", None):
for address in member.get("addresses"):
priv_key = wallet.export_private_key(address["input_address"], password)
sk, pubk = keys_from_priv(priv_key)
new_addr = address["shuffle_address"]
change = address["change_address"]
logger = SimpleLogger()
pThread = (ProtocolThread(host, port, network, amount, fee, sk, pubk, new_addr, change, logger=logger, ssl=ssl))
logger.pThread = pThread
pThreads.append(pThread)
# start Threads
for pThread in pThreads:
pThread.start()
done = False
while not done:
sleep(1)
done = all([is_protocol_done(pThread) for pThread in pThreads])
if (time() - job_start_time) > 1000:
"Protocol execution Time Out"
done = True
for pThread in pThreads:
pThread.join()
else:
basic_logger.send("[CashShuffle Bot] Nobody in the pools")
bot_job(stat_endpoint, host, port, network, ssl, args.limit, args.maximum_per_pool, basic_logger, SimpleLogger, wallet, password, coin, fee)

basic_logger = SimpleLogger()
args = parse_args()
Expand Down
143 changes: 143 additions & 0 deletions shuffle/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import time
import threading
import requests
from electroncash.bitcoin import deserialize_privkey, regenerate_key
from electroncash.address import Address
from .coin import Coin
from .crypto import Crypto
from .messages import Messages
Expand Down Expand Up @@ -186,3 +189,143 @@ def join(self, timeout=None):
"This method Joins the protocol thread"
self.stop()
threading.Thread.join(self, timeout)


def is_protocol_done(pThread):
if pThread.protocol:
return pThread.protocol.done
else:
return pThread.done.is_set()

def keys_from_priv(priv_key):
address, secret, compressed = deserialize_privkey(priv_key)
sk = regenerate_key(secret)
pubk = sk.get_public_key(compressed)
return sk, pubk

def bot_job(stat_endpoint, host, port, network, ssl,
limit, maximum_per_pool, basic_logger, simple_logger,
wallet, password, coin, fee, logchan = None, stopper = None):
job_start_time = time.time()
pools = []
pool_size = None
try:
res = requests.get(stat_endpoint, verify=False)
pools = res.json().get("pools", [])
pool_size = res.json().get("PoolSize", None)
except:
basic_logger.send("[CashShuffle Bot] Stat server not respond")
return
if len(pools) > 0:
# Select not full pools with members more then limit
members = [pool for pool in pools
if not pool.get("full", False) and
pool.get("members", 0) >= limit]
# Select unspent outputs in the wallet
utxos = wallet.get_utxos(exclude_frozen=True, confirmed_only=False)
# Select fresh inputs
fresh_outputs = wallet.get_unused_addresses()
if len(members) == 0:
basic_logger.send("[CashShuffle] No pools sutisfiying the requirments")
else:
basic_logger.send("[CashShuffle] Trying to support {} pools".format(len(members)))
for member in members:
number_of_players = member['members']
threshold = min(number_of_players + maximum_per_pool, pool_size)
member.update({"addresses" : []})
amount = member['amount'] + fee
good_utxos = [utxo for utxo in utxos if utxo['value'] > amount]
for good_utxo in good_utxos:
addr = Address.to_string(good_utxo['address'], Address.FMT_LEGACY)
try:
first_utxo = coin.get_first_sufficient_utxo(addr, amount)
if first_utxo:
address = {}
address.update({"input_address": good_utxo['address']})
address.update({"change_address": addr})
address.update({"shuffle_address": Address.to_string(fresh_outputs[0], Address.FMT_LEGACY)})
member['addresses'].append(address)
del fresh_outputs[0]
utxos.remove(good_utxo)
number_of_players += 1
if number_of_players == threshold:
break
except Exception as e:
basic_logger.send("[CashShuffle Bot] {}".format(e))
basic_logger.send("[CashShuffle Bot] Network problems")
# Define Protocol threads
pThreads = []
for member in members:
amount = member["amount"]
if member.get("addresses", None):
for address in member.get("addresses"):
priv_key = wallet.export_private_key(address["input_address"], password)
sk, pubk = keys_from_priv(priv_key)
new_addr = address["shuffle_address"]
change = address["change_address"]
logger = simple_logger(logchan=logchan)
pThread = (ProtocolThread(host, port, network, amount, fee, sk, pubk, new_addr, change, logger=logger, ssl=ssl))
logger.pThread = pThread
pThreads.append(pThread)
# start Threads
for pThread in pThreads:
pThread.start()
done = False
while not done:
time.sleep(1)
done = all([is_protocol_done(pThread) for pThread in pThreads])
if (time.time() - job_start_time) > 300:
"Protocol execution Time Out"
done = True
if stopper:
if stopper.is_set():
done = True
for pThread in pThreads:
pThread.join()
else:
basic_logger.send("[CashShuffle Bot] Nobody in the pools")

# bot_job(stat_endpoint, host, port, network, ssl, limit, maximum_per_pool, basic_logger, simple_logger, wallet, password, coin, fee, logchan = None):
class BotThread(threading.Thread):

def __init__(self, stat_endpoint, host, port, network, ssl, limit, maximum_per_pool, logger, wallet, password, fee, logchan, stopper, period):
threading.Thread.__init__(self)
self.daemon = True
self.stat_endpoint = stat_endpoint
self.host = host
self.port = port
self.ssl = ssl
self.network = network
self.limit = limit
self.maximum_per_pool = maximum_per_pool
self.basic_logger = logger(logchan=logchan)
self.simple_logger = logger
self.wallet = wallet
self.password = password
self.fee = fee
self.coin = Coin(network)
self.logchan = logchan
if stopper:
self.stopper = threading.Event()
else:
self.stopper = None
self.period = period * 60

def check(self):
bot_job(self.stat_endpoint, self.host, self.port, self.network, self.ssl,
self.limit, self.maximum_per_pool, self.basic_logger, self.simple_logger,
self.wallet, self.password, self.coin, self.fee,
logchan = self.logchan, stopper = self.stopper)
if not self.stopper.is_set():
self.t = threading.Timer(self.period, self.check)
self.t.start()

def run(self):
self.t = threading.Timer(self.period, self.check)
self.t.start()

def join(self):
self.t.cancel()
self.stopper.set()

threading.Thread.join(self)
Loading

0 comments on commit 4fd8aca

Please sign in to comment.