<commit_before>#! /usr/bin/env python3

import sys, io, asyncio, random, decimal, collections, getpass, pprint


from connectrum.client import StratumClient
from pycoin.ui import standard_tx_out_script
from pycoin.tx.tx_utils import distribute_from_split_pool, sign_tx
from pycoin.tx.Tx import Tx

from subclasses import MyServerInfo, LexSpendable, LexTxOut, SegwitBIP32Node
from keys import derive_key
from scrape import scrape_onion_servers

class Connection:
    def __init__(self, loop, server, port):
        """
        Connection object constructor. Connects to an Electrum server.

        :param loop: an asyncio event loop
        :param server: a string containing a hostname
        :param port: port number that the server listens on
        :returns: A new Connection object
        """
        print("Connecting...")

        self.server_info = MyServerInfo(server, hostname=server, ports=port)
        print(self.server_info.get_port("t"))
        self.client = StratumClient()
        self.connection = self.client.connect(
                            self.server_info,
                            proto_code="t",
                            use_tor=self.server_info.is_onion,
                            disable_cert_verify=True)

        loop.run_until_complete(self._do_connect())
        self.queue = None

    async def _do_connect(self):
        """
        Coroutine. Establishes a persistent connection to an Electrum server.
        Awaits the connection because AFAIK an init method can't be async.
        """
        try:
            await self.connection
        except Exception as e:
            print("Unable to connect to server:", e)
            sys.exit(1)

        print("\nConnected to server")

    async def listen_RPC(self, method, args):
        """
        Coroutine. Sends a normal RPC message to the server and awaits response.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        :returns: Future. Response from server for this method(args)
        """
        return await self.client.RPC(method, *args)

    def listen_subscribe(self, method, args):
        """
        Sends a "subscribe" message to the server and adds to the queue.
        Throws away the immediate future containing the "history" hash.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        """
        future, self.queue = self.client.subscribe(method, *args)

    async def consume_queue(self, queue_func):
        """
        Coroutine. Infinite loop that consumes the current subscription queue.

        :param queue_func: A function to call when new responses arrive
        """
        while True:
            result = await self.queue.get()
            await queue_func(result)

Chain = collections.namedtuple("Chain", ["netcode", "chain_1209k", "bip44"])
BTC = Chain(netcode="BTC",
            chain_1209k="btc",
            bip44=0)
TBTC = Chain(netcode="XTN",
            chain_1209k="tbtc",
            bip44=1)

class Wallet:
    """
    Provides all functionality required for a fully functional and secure
    HD brainwallet based on the Warpwallet technique.
    """
    _COIN = 100000000
    _GAP_LIMIT = 20

    def __init__(self, salt, passphrase, connection, loop, chain, account=0):
        """
        Wallet object constructor. Use discover_keys() and listen_to_addresses()
        coroutine method to construct wallet data, and listen for new data from
        the server.

        :param salt: a string to use as a salt for key derivation
        :param passphrase: a string containing a secure passphrase
        :param connection: a Connection object
        :param loop: an asyncio event loop
        :param chain: a namedtuple containing chain-specific info
        :param account: account number, defaults to 0
        :returns: A new, empty Wallet object
        """
        self.connection = connection
        self.loop = loop
        self.chain = chain

        (se, cc) = derive_key(salt, passphrase)
        self.mpk = SegwitBIP32Node(netcode=self.chain.netcode,
                                chain_code=cc, secret_exponent=se)
        path = "49H/{}H/{}H/".format(chain.bip44, account)
        self.root_spend_key = self.mpk.subkey_for_path("{}0".format(path))
        self.root_change_key = self.mpk.subkey_for_path("{}1".format(path))
        self.balance = decimal.Decimal("0")

        # Boolean lists, True = used / False = unused
        self.spend_indicies = list()
        self.change_indicies = list()

        # All wallet TX info. (Does not persist!)
        self.utxos = list()
        self.spent_utxos = list()
        self.history = dict()

    def get_xpub(self):
        """
        Returns the wallet's extended public key.

        :returns: a string containing the wallet's XPUB.
        """
        return self.mpk.hwif()
<commit_msg>Generate XPUB from account master key instead of wallet master.<commit_after>#! /usr/bin/env python3

import sys, io, asyncio, random, decimal, collections, getpass, pprint


from connectrum.client import StratumClient
from pycoin.ui import standard_tx_out_script
from pycoin.tx.tx_utils import distribute_from_split_pool, sign_tx
from pycoin.tx.Tx import Tx

from subclasses import MyServerInfo, LexSpendable, LexTxOut, SegwitBIP32Node
from keys import derive_key
from scrape import scrape_onion_servers

class Connection:
    def __init__(self, loop, server, port):
        """
        Connection object constructor. Connects to an Electrum server.

        :param loop: an asyncio event loop
        :param server: a string containing a hostname
        :param port: port number that the server listens on
        :returns: A new Connection object
        """
        print("Connecting...")

        self.server_info = MyServerInfo(server, hostname=server, ports=port)
        print(self.server_info.get_port("t"))
        self.client = StratumClient()
        self.connection = self.client.connect(
                            self.server_info,
                            proto_code="t",
                            use_tor=self.server_info.is_onion,
                            disable_cert_verify=True)

        loop.run_until_complete(self._do_connect())
        self.queue = None

    async def _do_connect(self):
        """
        Coroutine. Establishes a persistent connection to an Electrum server.
        Awaits the connection because AFAIK an init method can't be async.
        """
        try:
            await self.connection
        except Exception as e:
            print("Unable to connect to server:", e)
            sys.exit(1)

        print("\nConnected to server")

    async def listen_RPC(self, method, args):
        """
        Coroutine. Sends a normal RPC message to the server and awaits response.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        :returns: Future. Response from server for this method(args)
        """
        return await self.client.RPC(method, *args)

    def listen_subscribe(self, method, args):
        """
        Sends a "subscribe" message to the server and adds to the queue.
        Throws away the immediate future containing the "history" hash.

        :param method: The Electrum API method to use
        :param args: Params associated with current method
        """
        future, self.queue = self.client.subscribe(method, *args)

    async def consume_queue(self, queue_func):
        """
        Coroutine. Infinite loop that consumes the current subscription queue.

        :param queue_func: A function to call when new responses arrive
        """
        while True:
            result = await self.queue.get()
            await queue_func(result)

Chain = collections.namedtuple("Chain", ["netcode", "chain_1209k", "bip44"])
BTC = Chain(netcode="BTC",
            chain_1209k="btc",
            bip44=0)
TBTC = Chain(netcode="XTN",
            chain_1209k="tbtc",
            bip44=1)

class Wallet:
    """
    Provides all functionality required for a fully functional and secure
    HD brainwallet based on the Warpwallet technique.
    """
    _COIN = 100000000
    _GAP_LIMIT = 20

    def __init__(self, salt, passphrase, connection, loop, chain, account=0):
        """
        Wallet object constructor. Use discover_keys() and listen_to_addresses()
        coroutine method to construct wallet data, and listen for new data from
        the server.

        :param salt: a string to use as a salt for key derivation
        :param passphrase: a string containing a secure passphrase
        :param connection: a Connection object
        :param loop: an asyncio event loop
        :param chain: a namedtuple containing chain-specific info
        :param account: account number, defaults to 0
        :returns: A new, empty Wallet object
        """
        self.connection = connection
        self.loop = loop
        self.chain = chain

        (se, cc) = derive_key(salt, passphrase)
        self.mpk = SegwitBIP32Node(netcode=self.chain.netcode,
                                chain_code=cc, secret_exponent=se)

        path = "49H/{}H/{}H".format(chain.bip44, account)
        self.account_master = self.mpk.subkey_for_path(path)
        self.root_spend_key = self.account_master.subkey_for_path("0")
        self.root_change_key = self.account_master.subkey_for_path("1")

        # Boolean lists, True = used / False = unused
        self.spend_indicies = list()
        self.change_indicies = list()

        # All wallet TX info. (Does not persist!)
        self.utxos = list()
        self.spent_utxos = list()
        self.history = dict()
        self.balance = decimal.Decimal("0")

    def get_xpub(self):
        """
        Returns this account's extended public key.

        :returns: a string containing the account's XPUB.
        """
        return self.account_master.hwif()

{'fraction_non_alphanumeric': 0.0838909417756916, 'fraction_numerical': 0.009188055527813842, 'mean_word_length': 2.3502843760455003, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2697872', 'n_tokens_mistral': 2827, 'n_tokens_neox': 2735, 'n_words': 891}