TX_STATUS_UNKNOWN = 0
TX_STATUS_UNCONFIRMED = 1
TX_STATUS_CONFIRMED = 2
TX_STATUS_INVALID = 3
class TxDataStore(DataStore):
class BaseTxDb(object):
class NaiveTxDb(BaseTxDb):
class TrustingTxDb(BaseTxDb):
class VerifiedTxDb(BaseTxDb):
    def __init__(self, conn):
    def purge_tx_data(self):
    def add_tx(self, txhash, txdata, status=TX_STATUS_UNKNOWN):
    def set_tx_status(self, txhash, status):
    def get_tx_status(self, txhash):
    def get_tx_by_hash(self, txhash):
    def get_all_tx_hashes(self):
    def set_block_height(self, txhash, height):
    def reset_from_height(self, height):
    def __init__(self, model, config):
    def purge_tx_db(self):
    def get_all_tx_hashes(self):
    def get_tx_by_hash(self, txhash):
    def update_tx_block_height(self, txhash, status):
    def add_raw_tx(self, raw_tx, status=TX_STATUS_UNCONFIRMED):
    def add_tx_by_hash(self, txhash, status=None):
    def add_tx(self, txhash, txdata, raw_tx, status=None):
    def recheck_tx_status(self, txhash):
    def maybe_recheck_tx_status(self, txhash, status):
    def is_tx_valid(self, txhash):
    def is_tx_confirmed(self, txhash):
    def identify_tx_status(self, txhash):
    def __init__(self, model, config, get_tx_confirmations):
    def identify_tx_status(self, txhash):
    def __init__(self, model, config):
    def __del__(self):
    def _get_merkle_root(self, merkle_s, start_hash, pos):
    def _verify_merkle(self, txhash):
    def update_tx_block_height(self, txhash, status):
    def drop_from_height(self, height):
    def get_confirmations(self, txhash):
    def identify_tx_status(self, txhash): class InsufficientFundsError(Exception):
class InvalidTargetError(Exception):
class InvalidTransformationError(Exception):
class BasicTxSpec(object):
class BaseOperationalTxSpec(OperationalTxSpec):
class SimpleOperationalTxSpec(BaseOperationalTxSpec):
class RawTxSpec(object):
class TransactionSpecTransformer(object):
    def __init__(self, model):
    def add_target(self, asset_target):
    def is_monoasset(self):
    def is_monocolor(self):
    def make_operational_tx_spec(self, asset):
    def get_required_fee(self, tx_size):
    def get_dust_threshold(self):
    def _select_enough_coins(self, colordef, utxo_list, required_sum_fn):
    def _validate_select_coins_parameters(self, colorvalue, use_fee_estimator):
    def __init__(self, model, asset):
    def add_target(self, color_target):
    def get_targets(self):
    def get_change_addr(self, color_def):
    def select_coins(self, colorvalue, use_fee_estimator=None):
        def required_sum_fn(selection):
    def __init__(self, model, pycoin_tx, composed_tx_spec=None):
    def get_intent(self):
    def get_hex_txhash(self):
    def update_tx_data(self):
    def from_composed_tx_spec(cls, model, composed_tx_spec):
    def from_tx_data(cls, model, tx_data):
    def sign(self, utxo_list):
    def get_tx_data(self):
    def get_hex_tx_data(self):
    def get_input_addresses(self):
def compose_uncolored_tx(tx_spec):
    def __init__(self, model, config):
    def get_tx_composer(self, op_tx_spec):
    def classify_tx_spec(self, tx_spec):
    def transform_basic(self, tx_spec, target_spec_kind):
    def transform_operational(self, tx_spec, target_spec_kind):
    def transform_composed(self, tx_spec, target_spec_kind):
    def transform_signed(self, tx_spec, target_spec_kind):
    def transform(self, tx_spec, target_spec_kind): class LooseAddressRecord(AddressRecord):
    """Subclass of AddressRecord which is entirely imported.
    The address may be an existing one.
    """
    def __init__(self, **kwargs):
        """Create a LooseAddressRecord for a given wallet <model>,
        color <color_set> and address <address_data>. Also let the constructor
        know whether it's on <testnet> (optional).
        <address_data> is the privKey in base58 format
        """
        super(LooseAddressRecord, self).__init__(**kwargs)

        bin_privkey = a2b_hashed_base58(kwargs['address_data'])
        key_type = bin_privkey[0]
        if key_type != self.prefix:
            raise InvalidAddressError

        self.rawPrivKey = from_bytes_32(bin_privkey[1:])
        self.publicPoint = BasePoint * self.rawPrivKey
        self.address = public_pair_to_bitcoin_address(
            self.publicPoint.pair(), compressed=False, address_prefix=self.prefix) class ElectrumInterface(object):
    """Interface for interacting with Electrum servers using the
    stratum tcp protocol
    """

    def __init__(self, host, port, debug=False):
        """Make an interface object for connecting to electrum server
        """
        self.message_counter = 0
        self.connection = (host, port)
        self.debug = debug
        self.is_connected = False
        self.connect()

    def connected(self):
        return self.is_connected

    def connect(self):
        """Connects to an electrum server via TCP.
        Uses a socket so we can listen for a response
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(1)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

        try:
            sock.connect(self.connection)
        except:
            msg = "Unable to connect to %s:%s!"
            raise ConnectionError(msg % self.connection)

        sock.settimeout(60)
        self.sock = sock
        self.is_connected = True
        if self.debug:
            print ("Connected to %s:%s!" % self.connection ) # pragma: no cover
        return True

    def wait_for_response(self, target_id):
        """Get a response message from an electrum server with
        the id of <target_id>
        """
        try:
            out = ''
            while self.is_connected or self.connect():
                try:
                    msg = self.sock.recv(1024)
                    if self.debug:
                        print (msg)  # pragma: no cover
                except socket.timeout:         # pragma: no cover
                    self.is_connected = False  # pragma: no cover
                    continue                   # pragma: no cover
                except socket.error:                      # pragma: no cover
                    traceback.print_exc(file=sys.stdout)  # pragma: no cover
                    raise                                 # pragma: no cover

                out += msg
                if msg == '':
                    self.is_connected = False  # pragma: no cover

                # get the list of messages by splitting on newline
                raw_messages = out.split("\n")

                # the last one isn't complete
                out = raw_messages.pop()
                for raw_message in raw_messages:
                    message = json.loads(raw_message)

                    id = message.get('id')
                    error = message.get('error')
                    result = message.get('result')

                    if id == target_id:
                        if error:
                            raise Exception("Received error '%s'!" % message)
                        else:
                            return result
        except:
            traceback.print_exc(file=sys.stdout)
        self.is_connected = False

    def get_response(self, method, params):
        """Given a message that consists of <method> which
        has <params>,
        Return the string response of the message sent to electrum"""
        current_id = self.message_counter
        self.message_counter += 1
        try:
            self.sock.send(
                json.dumps({
                    'id': current_id,
                    'method': method,
                    'params': params})
                + "\n")
        except socket.error:                       # pragma: no cover
            traceback.print_exc(file=sys.stdout)   # pragma: no cover
            return None                            # pragma: no cover
        return self.wait_for_response(current_id)

    def get_version(self):
        """Get the server version of the electrum server
        that it's connected to.
        """
        return self.get_response('server.version', ["1.9", "0.6"])

    def get_height(self):
        return self.get_response('blockchain.numblocks.subscribe', [])

    def get_merkle(self, tx_hash, height):
        return self.get_response('blockchain.transaction.get_merkle', [tx_hash,
                                                                       height])

    def get_header(self, height):
        return self.get_response('blockchain.block.get_header', [height])

    def get_raw_transaction(self, tx_id, height):
        """Get the raw transaction that has the transaction hash
        of <tx_id> and height <height>.
        Note you may need to use another method to get the height
        from the transaction id hash.
        """
        return self.get_response('blockchain.transaction.get', [tx_id, height])

    def get_utxo(self, address):
        """Gets all the Unspent Transaction Outs from a given <address>
        """
        script_pubkey = CBitcoinAddress(address).to_scriptPubKey()
        txs = self.get_response('blockchain.address.get_history', [address])
        spent = {}
        utxos = []
        for tx in txs:
            raw = self.get_raw_transaction(tx['tx_hash'], tx['height'])
            data = CTransaction.deserialize(to_binary(raw))
            for vin in data.vin:
                spent[(to_little_endian_hex(vin.prevout.hash),
                       vin.prevout.n)] = 1
            for outindex, vout in enumerate(data.vout):
                if vout.scriptPubKey == script_pubkey:
                    utxos += [(tx['tx_hash'], outindex, vout.nValue,
                               to_hex(vout.scriptPubKey))]
        return [u for u in utxos if not u[0:2] in spent]

    def get_chunk(self, index):
        return self.get_response('blockchain.block.get_chunk', [index]) class EnhancedBlockchainState(blockchain.BlockchainState):
    """Subclass of coloredcoinlib's BlockchainState for
    getting the raw transaction from electrum instead of a local
    bitcoind server. This is more convenient than reindexing
    the bitcoind server which can take an hour or more.
    """

    def __init__(self, url, port):
        """Initialization takes the url and port of the electrum server.
        We use the normal bitcoind interface, except for
        get_raw_transaction, where we have to do separate lookups
        to blockchain and electrum.
        """
        self.interface = ElectrumInterface(url, port)
        self.bitcoind = bitcoin.rpc.RawProxy()
        self.cur_height = None

    def get_tx_block_height(self, txhash):
        """Get the tx_block_height given a txhash from blockchain.
        This is necessary since the electrum interface requires
        the height in order to get the raw transaction. The parent
        class, BlockchainStatus, uses get_raw_transaction to get
        the height, which would cause a circular dependency.
        """
        url = "http://blockchain.info/rawtx/%s" % txhash
        jsonData = urllib2.urlopen(url).read()
        if jsonData[0] != '{':
            return (None, False)  # pragma: no cover
        data = json.loads(jsonData)
        return (data.get("block_height", None), True)

    def get_raw_transaction(self, txhash):
        try:
            # first, grab the tx height
            height = self.get_tx_block_height(txhash)[0]
            if not height:
                raise Exception("Couldn't get blockchain height!")

            # grab the transaction from electrum which
            #  unlike bitcoind requires the height
            raw = self.interface.get_raw_transaction(txhash, height)
        except:
            raise Exception("Could not connect to blockchain/electrum server!")
        return raw

    def get_tx(self, txhash):
        """Get the transaction object given a transaction hash.
        """
        txhex = self.get_raw_transaction(txhash)
        tx = CTransaction.deserialize(to_binary(txhex))
        return blockchain.CTransaction.from_bitcoincore(txhash, tx, self)

    def get_height(self):
        """Get the current height at the server
        """
        return self.interface.get_height()

    def get_merkle(self, tx_hash):
        height, _ = self.get_tx_block_height(tx_hash)
        return self.interface.get_merkle(tx_hash, height)

    def get_header(self, height):
        return self.interface.get_header(height)

    def get_chunk(self, index):
        return self.interface.get_chunk(index) TX_STATUS_UNKNOWN = 0 TX_STATUS_UNCONFIRMED = 1 TX_STATUS_CONFIRMED = 2 TX_STATUS_INVALID = 3 class InvalidColorIdError(Exception):
class ZeroSelectError(Exception):
class ColorTarget(object):
class OperationalTxSpec(object):
class ComposedTxSpec(object):
    class TxIn(CTxIn):
    class TxOut(object):
    class FeeChangeTxOut(TxOut):
    def __init__(self, address, colorvalue):
    def get_colordef(self):
    def get_color_id(self):
    def is_uncolored(self):
    def get_address(self):
    def get_value(self):
    def get_satoshi(self):
    def __repr__(self):
    def sum(cls, targets):
    def get_targets(self):
    def select_coins(self, colorvalue, use_fee_estimator=None):
    def get_change_addr(self, color_def):
    def get_required_fee(self, tx_size):
    def get_dust_threshold(self):
    def is_monocolor(self):
    def make_composed_tx_spec(self):
        def __init__(self, value, target_addr):
    def __init__(self, operational_tx_spec=None):
    def add_txin(self, txin):
    def add_txout(self, txout=None, value=None, target_addr=None,
                  target=None, is_fee_change=False):
    def add_txouts(self, txouts):
    def add_txins(self, txins):
    def get_txins(self):
    def get_txouts(self):
    def estimate_size(self, extra_txins=0, extra_txouts=0, extra_bytes=0):
    def estimate_required_fee(self, extra_txins=0, extra_txouts=1, extra_bytes=0):
    def get_fee(self):
import unittest
import sqlite3
from ngcccbase import txdb, txcons, utxodb
from ngcccbase.address import LooseAddressRecord
from ngcccbase.services.electrum import (ElectrumInterface,
                                         EnhancedBlockchainState)
from ngcccbase.txdb import (TX_STATUS_UNKNOWN, TX_STATUS_UNCONFIRMED,
                            TX_STATUS_CONFIRMED, TX_STATUS_INVALID)
from coloredcoinlib import txspec
from pycoin.tx.script import tools
#!/usr/bin/env python






class TestTxDataStoreInitialization(unittest.TestCase):
    def test_initialization(self):
        connection = sqlite3.connect(":memory:")
        store = txdb.TxDataStore(connection)
        self.assertTrue(store.table_exists("tx_data"))


class MockConn(object):
    def __init__(self):
        self.conn = sqlite3.connect(":memory:")

class MockModel(object):
    def __init__(self):
        self.store_conn = MockConn()

    def is_testnet(self):
        return False
    def get_blockchain_state(self):
        server_url = "electrum.pdmc.net"
        ei = ElectrumInterface(server_url, 50001)
        return EnhancedBlockchainState(server_url, 50001)


def fake_transaction(model=MockModel()):
    key = "5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF"

    address = LooseAddressRecord(address_data=key)
    script = tools.compile(
        "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format(
            address.rawPubkey().encode("hex"))).encode("hex")

    txin = utxodb.UTXO("D34DB33F", 0, 1, script)
    txin.address_rec = address
    txout = txspec.ComposedTxSpec.TxOut(1, address.get_address())
    composed = txspec.ComposedTxSpec([txin], [txout])
    return txcons.RawTxSpec.from_composed_tx_spec(model, composed), address


class TestTxDataStore(unittest.TestCase):
    def setUp(self):
        connection = sqlite3.connect(":memory:")
        self.store = txdb.TxDataStore(connection)
        self.model = MockModel()

    def test_add_tx(self):
        txhash = "FAKEHASH"
        transaction, address = fake_transaction(self.model)
        txdata = transaction.get_hex_tx_data()
        self.store.add_tx(txhash, txdata)

        stored_id, stored_hash, stored_data, stored_status = \
            self.store.get_tx_by_hash(txhash)

        self.assertEqual(stored_hash, txhash)
        self.assertEqual(stored_data, transaction.get_hex_tx_data())

        self.assertEqual(stored_status, TX_STATUS_UNKNOWN)
        self.store.set_tx_status(txhash, TX_STATUS_CONFIRMED)
        self.assertEqual(self.store.get_tx_status(txhash), TX_STATUS_CONFIRMED)
        self.store.purge_tx_data()
        self.assertEqual(self.store.get_tx_by_hash(txhash), None)


class TestVerifiedTxDb(unittest.TestCase):
    def setUp(self):
        self.model = MockModel()
        self.txdb = txdb.VerifiedTxDb(MockModel(), {})

    def test_identify_tx_status(self):
        status = self.txdb.identify_tx_status(
            'b1c68049c1349399fb867266fa146a854c16cd8a18a01d3cd7921ab9d5af1a8b')
        self.assertEqual(status, TX_STATUS_CONFIRMED)
        status = self.txdb.identify_tx_status(
            'b1c68049c1349399fb867266fa146a854c16cd8a18a01d3cd7921ab9d5af1a8b')
        self.assertEqual(status, TX_STATUS_CONFIRMED)
        status = self.txdb.identify_tx_status(
            'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')

        self.assertEqual(status, TX_STATUS_INVALID)