Example #1
0
    def select_coins(self, colorvalue, use_fee_estimator=None):
        #FIXME
        if type(colorvalue) is int:
            colorvalue = SimpleColorValue(
                colordef=UNCOLORED_MARKER,
                value=colorvalue
            )
        self._validate_select_coins_parameters(colorvalue, use_fee_estimator)
        colordef = colorvalue.get_colordef()
        if colordef == UNCOLORED_MARKER:
            return self.select_uncolored_coins(colorvalue, use_fee_estimator)

        color_id = colordef.get_color_id()
        if color_id in self.inputs:
            # use inputs provided in proposal
            total = SimpleColorValue.sum([cv_u[0]
                                          for cv_u in self.inputs[color_id]])
            if total < colorvalue:
                raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                             % (colorvalue, total))
            return [cv_u[1] for cv_u in self.inputs[color_id]], total
        
        if colorvalue != self.our_value_limit:
            raise InsufficientFundsError("%s requested, %s found"
                                         % (colorvalue, our_value_limit))
        return super(OperationalETxSpec, self).select_coins(colorvalue)
Example #2
0
    def setUp(self):
        self.colordef0 = POBColorDefinition(1, {
            'txhash': 'genesis',
            'outindex': 0
        })
        self.colordef1 = OBColorDefinition(2, {
            'txhash': 'genesis',
            'outindex': 0
        })
        self.colorvalue0 = SimpleColorValue(colordef=self.colordef0,
                                            value=1,
                                            label='test')
        self.colorvalue1 = SimpleColorValue(colordef=self.colordef0,
                                            value=2,
                                            label='test2')
        self.colorvalue2 = SimpleColorValue(colordef=self.colordef1, value=1)

        self.e0 = MyEOffer.from_data({
            'oid': 1,
            'A': self.colorvalue0,
            'B': self.colorvalue1
        })
        self.e1 = MyEOffer.from_data({
            'oid': 2,
            'A': self.colorvalue0,
            'B': self.colorvalue1
        })
Example #3
0
 def select_uncolored_coins(self, colorvalue, use_fee_estimator):
     selected_inputs = []
     selected_value = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                       value=0)
     needed = colorvalue + use_fee_estimator.estimate_required_fee()
     color_id = 0
     if color_id in self.inputs:
         total = SimpleColorValue.sum([cv_u[0]
                                       for cv_u in self.inputs[color_id]])
         needed -= total
         selected_inputs += [cv_u[1]
                            for cv_u in self.inputs[color_id]]
         selected_value += total
     if needed > 0:
         value_limit = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                        value=10000+8192)
         if self.our_value_limit.is_uncolored():
             value_limit += self.our_value_limit
         if needed > value_limit:
             raise InsufficientFundsError("exceeded limits: %s requested, %s found"
                                          % (needed, value_limit))
         our_inputs, our_value = super(OperationalETxSpec, self).\
             select_coins(colorvalue - selected_value, use_fee_estimator)
         selected_inputs += our_inputs
         selected_value += our_value
     return selected_inputs, selected_value
Example #4
0
    def test_tx_spec(self):
        self.add_colors()

        our = SimpleColorValue(colordef=UNCOLORED_MARKER, value=500)
        colormap = self.model.get_color_map()
        colordef = colormap.get_color_def(self.cspec)
        their = SimpleColorValue(colordef=colordef, value=10)
        etx = self.ewc.make_etx_spec(our, their)
        self.assertTrue(isinstance(etx, ETxSpec))
        for target in etx.targets:
            self.assertTrue(isinstance(target, ColorTarget))
        signed = self.ewc.make_reply_tx(etx, our, their)
        self.assertTrue(isinstance(signed, RawTxSpec))

        self.ewc.publish_tx(signed)

        etx = self.ewc.make_etx_spec(their, our)
        self.assertTrue(isinstance(etx, ETxSpec))
        for target in etx.targets:
            self.assertTrue(isinstance(target, ColorTarget))
        signed = self.ewc.make_reply_tx(etx, their, our)
        self.assertTrue(isinstance(signed, RawTxSpec))

        oets = OperationalETxSpec(self.model, self.ewc)
        zero = SimpleColorValue(colordef=UNCOLORED_MARKER, value=0)
        self.assertRaises(ZeroSelectError, oets.select_coins, zero)
        toomuch = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                   value=10000000000000)
        self.assertRaises(InsufficientFundsError, oets.select_coins, toomuch)
Example #5
0
    def test_tx_spec(self):
        alice_cv = {'color_spec': self.color_spec, 'value': 10}
        bob_cv = {'color_spec': "", 'value': 500}
        alice_offer = MyEOffer(None, alice_cv, bob_cv)
        bob_offer = MyEOffer(None, bob_cv, alice_cv)
        bob_etx = self.ewc.make_etx_spec(bob_cv, alice_cv)
        self.assertTrue(isinstance(bob_etx, ETxSpec))
        for target in bob_etx.targets:
            # check address
            address = target[0]
            self.assertTrue(isinstance(address, type(u"unicode")))
            # TODO check address is correct format

            # check color_spec
            color_spec = target[1]
            self.assertTrue(isinstance(color_spec, type("str")))
            color_spec_parts = len(color_spec.split(":"))
            self.assertTrue(color_spec_parts == 4 or color_spec_parts == 1)

            # check value
            value = target[2]
            self.assertTrue(isinstance(value, type(10)))
        signed = self.ewc.make_reply_tx(bob_etx, alice_cv, bob_cv)
        self.assertTrue(isinstance(signed, RawTxSpec))

        self.ewc.publish_tx(signed, alice_offer)

        alice_etx = self.ewc.make_etx_spec(alice_cv, bob_cv)
        self.assertTrue(isinstance(alice_etx, ETxSpec))
        for target in alice_etx.targets:
            # check address
            address = target[0]
            self.assertTrue(isinstance(address, type(u"unicode")))
            # TODO check address is correct format

            # check color_spec
            color_spec = target[1]
            self.assertTrue(isinstance(color_spec, type("str")))
            color_spec_parts = len(color_spec.split(":"))
            self.assertTrue(color_spec_parts == 4 or color_spec_parts == 1)

            # check value
            value = target[2]
            self.assertTrue(isinstance(value, type(10)))
        signed = self.ewc.make_reply_tx(alice_etx, bob_cv, alice_cv)
        self.assertTrue(isinstance(signed, RawTxSpec))

        oets = OperationalETxSpec(self.model, self.ewc)
        oets.set_our_value_limit(bob_cv)
        oets.prepare_inputs(alice_etx)
        zero = SimpleColorValue(colordef=UNCOLORED_MARKER, value=0)
        self.assertRaises(ZeroSelectError, oets.select_coins, zero)
        toomuch = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                   value=10000000000000)
        self.assertRaises(InsufficientFundsError, oets.select_coins, toomuch)
Example #6
0
 def _select_enough_coins(self, colordef, utxo_list, required_sum_fn):
     ssum = SimpleColorValue(colordef=colordef, value=0)
     selection = []
     required_sum = None
     for utxo in utxo_list:
         ssum += SimpleColorValue.sum(utxo.colorvalues)
         selection.append(utxo)
         required_sum = required_sum_fn(utxo_list)
         if ssum >= required_sum:
             return selection, ssum
     raise InsufficientFundsError(
         'Not enough coins: %s requested, %s found!' % (required_sum, ssum))
Example #7
0
    def select_coins(self, colorvalue):
        colordef = colorvalue.get_colordef()
        color_id = colordef.get_color_id()

        if color_id in self.inputs:
            total = SimpleColorValue.sum([cv_u[0]
                                          for cv_u in self.inputs[color_id]])
            if total < colorvalue:
                raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                             % (colorvalue, total))
            return [cv_u[1]
                    for cv_u in self.inputs[color_id]], total

        cq = self.model.make_coin_query({"color_id_set": set([color_id])})
        utxo_list = cq.get_result()

        zero = ssum = SimpleColorValue(colordef=colordef, value=0)
        selection = []
        if colorvalue == zero:
            raise ZeroSelectError('cannot select 0 coins')
        for utxo in utxo_list:
            if utxo.colorvalues:
                ssum += utxo.colorvalues[0]
                selection.append(utxo)
                if ssum >= colorvalue:
                    return selection, ssum
        raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                     % (colorvalue, ssum))
Example #8
0
 def prepare_inputs(self, etx_spec):
     self.inputs = defaultdict(list)
     colordata = self.model.ccc.colordata
     for color_spec, inps in etx_spec.inputs.items():
         colordef = self.ewctrl.resolve_color_spec(color_spec)
         color_id_set = set([colordef.get_color_id()])
         for inp in inps:
             txhash, outindex = inp
             tx = self.model.ccc.blockchain_state.get_tx(txhash)
             prevout = tx.outputs[outindex]
             utxo = UTXO({"txhash": txhash,
                          "outindex": outindex,
                          "value": prevout.value,
                          "script": prevout.script})
             colorvalue = None
             if colordef == UNCOLORED_MARKER:
                 colorvalue = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                               value=prevout.value)
             else:
                 css = colordata.get_colorvalues(color_id_set,
                                                 txhash,
                                                 outindex)
                 if (css and len(css) == 1):
                     colorvalue = css[0]
             if colorvalue:
                 self.inputs[colordef.get_color_id()].append(
                     (colorvalue, utxo))
Example #9
0
 def prepare_targets(self, etx_spec, their):
     self.targets = []
     for address, color_spec, value in etx_spec.targets:
         colordef = self.ewctrl.resolve_color_spec(color_spec)
         self.targets.append(ColorTarget(address, 
                                    SimpleColorValue(colordef=colordef,
                                                     value=value)))
     wam = self.model.get_address_manager()
     colormap = self.model.get_color_map()
     their_colordef = self.ewctrl.resolve_color_spec(their['color_spec'])
     their_color_set = ColorSet.from_color_ids(self.model.get_color_map(),
                                               [their_colordef.get_color_id()])
     ct = ColorTarget(wam.get_change_address(their_color_set).get_address(),
                      SimpleColorValue(colordef=their_colordef,
                                       value=their['value']))
     self.targets.append(ct)
Example #10
0
 def make_etx_spec(self, our, their):
     our_color_def = self.resolve_color_spec(our['color_spec'])
     our_color_set = ColorSet.from_color_ids(self.model.get_color_map(),
                                               [our_color_def.get_color_id()])
     their_color_def = self.resolve_color_spec(their['color_spec'])
     their_color_set = ColorSet.from_color_ids(self.model.get_color_map(),
                                               [their_color_def.get_color_id()])
     extra_value = 0
     if our_color_def == UNCOLORED_MARKER:
         # pay fee + padding for one colored outputs
         extra_value = 10000 + 8192 * 1
     c_utxos, c_change = self.select_inputs(
         SimpleColorValue(colordef=our_color_def,
                          value=our['value'] + extra_value))
     inputs = {our['color_spec']: 
               [utxo.get_outpoint() for utxo in c_utxos]}
     wam = self.model.get_address_manager()
     our_address = wam.get_change_address(their_color_set)
     targets = [(our_address.get_address(),
                 their['color_spec'], their['value'])]
     if c_change > 0:
         our_change_address = wam.get_change_address(our_color_set)
         targets.append((our_change_address.get_address(),
                         our['color_spec'], c_change.get_value()))
     return ETxSpec(inputs, targets, c_utxos)
Example #11
0
 def get_required_fee(self, tx_size):
     """Given a transaction that is of size <tx_size>,
     return the transaction fee in Satoshi that needs to be
     paid out to miners.
     """
     # TODO: this should change to something dependent on tx_size
     return SimpleColorValue(colordef=UNCOLORED_MARKER, value=10000)
Example #12
0
    def issue_coins(self, moniker, pck, units, atoms_in_unit):
        """Issues a new color of name <moniker> using coloring scheme
        <pck> with <units> per share and <atoms_in_unit> total.
        """

        color_definition_cls = ColorDefinition.get_color_def_cls_for_code(pck)
        if not color_definition_cls:
            raise InvalidColorDefinitionError(
                'color scheme %s not recognized' % pck)

        total = units * atoms_in_unit
        op_tx_spec = SimpleOperationalTxSpec(self.model, None)
        wam = self.model.get_address_manager()
        address = wam.get_new_genesis_address()
        colorvalue = SimpleColorValue(colordef=GENESIS_OUTPUT_MARKER,
                                      value=total)
        color_target = ColorTarget(address.get_address(), colorvalue)
        op_tx_spec.add_target(color_target)
        genesis_ctxs = color_definition_cls.compose_genesis_tx_spec(op_tx_spec)
        genesis_tx = self.model.transform_tx_spec(genesis_ctxs, 'signed')
        height = self.model.ccc.blockchain_state.bitcoind.getblockcount() \
            - 1
        genesis_tx_hash = self.publish_tx(genesis_tx)
        color_desc = ':'.join([pck, genesis_tx_hash, '0', str(height)])
        adm = self.model.get_asset_definition_manager()
        asset = adm.add_asset_definition({
            "monikers": [moniker],
            "color_set": [color_desc],
            "unit": atoms_in_unit
        })
        wam.update_genesis_address(address, asset.get_color_set())

        # scan the tx so that the rest of the system knows
        self.model.ccc.colordata.cdbuilder_manager.scan_txhash(
            asset.color_set.color_id_set, genesis_tx_hash)
Example #13
0
    def select_inputs(self, colorvalue):
        cs = ColorSet.from_color_ids(self.model.get_color_map(),
                                     [colorvalue.get_color_id()])

        cq = self.model.make_coin_query({"color_set": cs})
        utxo_list = cq.get_result()
        selection = []
        csum = SimpleColorValue(colordef=colorvalue.get_colordef(), value=0)

        for utxo in utxo_list:
            csum += SimpleColorValue.sum(utxo.colorvalues)
            selection.append(utxo)
            if csum >= colorvalue:
                break
        if csum < colorvalue:
            raise InsufficientFundsError('not enough money')
        return selection, (csum - colorvalue)
Example #14
0
    def select_coins(self, colorvalue):
        colordef = colorvalue.get_colordef()
        color_id = colordef.get_color_id()
        cq = self.model.make_coin_query({"color_id_set": set([color_id])})
        utxo_list = cq.get_result()

        zero = ssum = SimpleColorValue(colordef=colordef, value=0)
        selection = []
        if colorvalue == zero:
            raise ZeroSelectError('cannot select 0 coins')
        for utxo in utxo_list:
            ssum += SimpleColorValue.sum(utxo.colorvalues)
            selection.append(utxo)
            if ssum >= colorvalue:
                return selection, ssum
        raise InsufficientFundsError(
            'not enough coins: %s requested, %s found' % (colorvalue, ssum))
Example #15
0
 def get_required_fee(self, tx_size):
     """Given a transaction that is of size <tx_size>,
     return the transaction fee in Satoshi that needs to be
     paid out to miners.
     """
     base_fee = 11000.0
     fee_value = math.ceil((tx_size * base_fee) / 1000)
     return SimpleColorValue(colordef=UNCOLORED_MARKER, value=fee_value)
Example #16
0
 def get_balance(self, asset):
     """Returns an integer value corresponding to the total number
     of Satoshis owned of asset/color <asset>.
     """
     cq = self.model.make_coin_query({"asset": asset})
     utxo_list = cq.get_result()
     value_list = [asset.get_colorvalue(utxo) for utxo in utxo_list]
     if len(value_list) == 0:
         return 0
     else:
         return SimpleColorValue.sum(value_list).get_value()
Example #17
0
    def test_get_colorvalue(self):
        g = {'txhash': 'blah', 'height': 1, 'outindex': 0}
        cid0 = list(self.colorset0.color_id_set)[0]
        cdef0 = OBColorDefinition(cid0, g)
        cid1 = list(self.colorset1.color_id_set)[0]
        cdef1 = OBColorDefinition(cid1, g)
        cid2 = list(self.colorset2.color_id_set)[0]
        cdef2 = OBColorDefinition(cid2, g)
        cv0 = SimpleColorValue(colordef=cdef0, value=1)
        cv1 = SimpleColorValue(colordef=cdef1, value=2)
        cv2 = SimpleColorValue(colordef=cdef2, value=3)

        utxo = MockUTXO([cv0, cv1, cv2])

        self.assertEquals(self.asset0.get_colorvalue(utxo), cv0)
        self.assertEquals(self.asset1.get_colorvalue(utxo), cv1)
        self.assertEquals(self.asset2.get_colorvalue(utxo), cv2)

        utxo = MockUTXO([cv0, cv2])
        self.assertRaises(Exception, self.asset1.get_colorvalue, utxo)
 def get_balance(self, asset):
     """Returns an integer value corresponding to the total number
     of Satoshis owned of asset/color <asset>.
     """
     cq = self.model.make_coin_query({"asset": asset})
     utxo_list = cq.get_result()
     value_list = [asset.get_colorvalue(utxo) for utxo in utxo_list]
     if len(value_list) == 0:
         return 0
     else:
         return SimpleColorValue.sum(value_list).get_value()
Example #19
0
 def test_operational(self):
     self.basic.add_target(self.assettarget0)
     self.basic.add_target(self.assettarget1)
     self.basic.add_target(self.assettarget2)
     op = self.transformer.transform_basic(self.basic, 'operational')
     self.assertTrue(self.transformer.classify_tx_spec(op), 'operational')
     self.assertRaises(InvalidTargetError, op.add_target, 1)
     self.assertEqual(ColorTarget.sum(op.get_targets()),
                      ColorTarget.sum(self.targets))
     self.assertEqual(op.get_change_addr(self.colordef0), self.addr0)
     self.assertEqual(op.get_change_addr(UNCOLORED_MARKER), self.baddr)
     self.assertEqual(op.get_required_fee(1).get_value(), 10000)
     self.assertRaises(InvalidColorIdError, op.get_change_addr,
                       self.colordef1)
     cv = SimpleColorValue(colordef=self.colordef0, value=0)
     self.assertRaises(ZeroSelectError, op.select_coins, cv)
     cv = SimpleColorValue(colordef=self.colordef0, value=5)
     self.assertRaises(InsufficientFundsError, op.select_coins, cv)
     self.add_coins()
     self.assertEqual(op.select_coins(cv)[1].get_value(), 100)
Example #20
0
    def select_coins(self, colorvalue):
        """Return a list of utxos and sum that corresponds to
        the colored coins identified by <color_def> of amount <colorvalue>
        that we'll be spending from our wallet.
        """
        colordef = colorvalue.get_colordef()
        color_id = colordef.get_color_id()
        cq = self.model.make_coin_query({"color_id_set": set([color_id])})
        utxo_list = cq.get_result()

        zero = ssum = SimpleColorValue(colordef=colordef, value=0)
        selection = []
        if colorvalue == zero:
            raise ZeroSelectError('cannot select 0 coins')
        for utxo in utxo_list:
            ssum += SimpleColorValue.sum(utxo.colorvalues)
            selection.append(utxo)
            if ssum >= colorvalue:
                return selection, ssum
        raise InsufficientFundsError(
            'not enough coins: %s requested, %s found' % (colorvalue, ssum))
Example #21
0
 def _select_enough_coins(self, colordef, utxo_list, required_sum_fn):
     ssum = SimpleColorValue(colordef=colordef, value=0)
     selection = []
     required_sum = None
     for utxo in utxo_list:
         ssum += SimpleColorValue.sum(utxo.colorvalues)
         selection.append(utxo)
         required_sum = required_sum_fn(utxo_list)
         if ssum >= required_sum:
             return selection, ssum
     raise InsufficientFundsError('Not enough coins: %s requested, %s found!'
                                  % (required_sum, ssum))
Example #22
0
 def sendmany_coins(self, entries):
     """Sendmany coins given in entries [(asset, address, value), ...] """
     self.validate_sendmany_entries(entries)
     tx_spec = SimpleOperationalTxSpec(self.model, None)
     for asset, address, value in entries:
         color_id = asset.get_color_id()
         colordef = self.model.get_color_def(color_id)
         colorvalue = SimpleColorValue(colordef=colordef, value=value)
         tx_spec.add_target(ColorTarget(address, colorvalue))
     signed_tx_spec = self.model.transform_tx_spec(tx_spec, 'signed')
     txhash = self.publish_tx(signed_tx_spec)
     # TODO add to history
     return txhash
Example #23
0
    def test_basic(self):
        model = MockModel()
        ewctrl = EWalletController(model, None)
        config = {"offer_expiry_interval": 30, "ep_expiry_interval": 30}
        comm = MockComm()
        agent = EAgent(ewctrl, config, comm)

        # At this point the agent should not have an active proposal
        self.assertFalse(agent.has_active_ep())
        # no messages should have been sent to the network
        self.assertEqual(len(comm.get_messages()), 0)

        self.cd = OBColorDefinition(1, {
            'txhash': 'xxx',
            'outindex': 0,
            'height': 0
        })

        cv0 = SimpleColorValue(colordef=UNCOLORED_MARKER, value=100)
        cv1 = SimpleColorValue(colordef=self.cd, value=200)

        my_offer = MyEOffer(None, cv0, cv1)

        their_offer = EOffer('abcdef', cv1, cv0)

        agent.register_my_offer(my_offer)
        agent.register_their_offer(their_offer)
        agent.update()

        # Agent should have an active exchange proposal
        self.assertTrue(agent.has_active_ep())
        # Exchange proposal should have been sent over comm
        # it should be the only message, as we should not resend our offer
        # if their is an active proposal to match it
        self.assertTrue(len(comm.get_messages()), 1)
        [proposal] = comm.get_messages()
        # The offer data should be in the proposal
        their_offer_data = their_offer.get_data()
        self.assertEquals(their_offer_data, proposal["offer"])
Example #24
0
 def compute_colorvalues(self, coin):
     wam = self.model.get_address_manager()
     address_rec = wam.find_address_record(coin.address)
     if not address_rec:
         raise Exception('address record not found')
     color_set = address_rec.get_color_set()
     if color_set.uncolored_only():
         return [
             SimpleColorValue(colordef=UNCOLORED_MARKER, value=coin.value)
         ]
     else:
         cdata = self.model.ccc.colordata
         return cdata.get_colorvalues(color_set.color_id_set, coin.txhash,
                                      coin.outindex)
Example #25
0
 def select_inputs(self, colorvalue):
     op_tx_spec = SimpleOperationalTxSpec(self.model, None)
     if colorvalue.is_uncolored():
         composed_tx_spec = op_tx_spec.make_composed_tx_spec()
         selection, total = op_tx_spec.select_coins(colorvalue, composed_tx_spec)
         change = total - colorvalue - \
             composed_tx_spec.estimate_required_fee(extra_txins=len(selection))
         if change < op_tx_spec.get_dust_threshold():
             change = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                       value=0)
         return selection, change            
     else:
         selection, total = op_tx_spec.select_coins(colorvalue)
         change = total - colorvalue
         return selection, change
Example #26
0
 def make_operational_tx_spec(self, asset):
     """Given a <tx_spec> of type BasicTxSpec, return
     a SimpleOperationalTxSpec.
     """
     if not self.is_monocolor():
         raise InvalidTransformationError('tx spec type not supported')
     op_tx_spec = SimpleOperationalTxSpec(self.model, asset)
     color_id = list(asset.get_color_set().color_id_set)[0]
     color_def = self.model.get_color_def(color_id)
     for target in self.targets:
         colorvalue = SimpleColorValue(colordef=color_def,
                                       value=target.get_value())
         colortarget = ColorTarget(target.get_address(), colorvalue)
         op_tx_spec.add_target(colortarget)
     return op_tx_spec
Example #27
0
    def select_inputs(self, colorvalue):
        cs = ColorSet.from_color_ids(self.model.get_color_map(),
                                     [colorvalue.get_color_id()])

        cq = self.model.make_coin_query({"color_set": cs})
        utxo_list = cq.get_result()
        selection = []
        csum = SimpleColorValue(colordef=colorvalue.get_colordef(), value=0)

        for utxo in utxo_list:
            csum += SimpleColorValue.sum(utxo.colorvalues)
            selection.append(utxo)
            if csum >= colorvalue:
                break
        if csum < colorvalue:
            raise InsufficientFundsError('not enough money')
        return selection, (csum - colorvalue)
Example #28
0
    def get_coins_for_address(self, address_rec):
        """Given an address <address_rec>, return the list of coin's
        straight from the DB. Note this specifically does NOT return
        COIN objects.
        """
        color_set = self.color_set
        addr_color_set = address_rec.get_color_set()
        all_coins = filter(
            self.coin_matches_filter,
            self.coin_manager.get_coins_for_address(address_rec.get_address()))
        cdata = self.model.ccc.colordata
        address_is_uncolored = addr_color_set.color_id_set == set([0])
        if address_is_uncolored:
            for coin in all_coins:
                coin.address_rec = address_rec
                coin.colorvalues = [
                    SimpleColorValue(colordef=UNCOLORED_MARKER,
                                     value=coin.value)
                ]
            return all_coins
        for coin in all_coins:
            coin.address_rec = address_rec
            coin.colorvalues = None
            try:
                coin.colorvalues = cdata.get_colorvalues(
                    addr_color_set.color_id_set, coin.txhash, coin.outindex)
            except Exception as e:
                print e
                raise

        def relevant(coin):
            cvl = coin.colorvalues
            if coin.colorvalues is None:
                return False  # None indicates failure
            if cvl == []:
                return color_set.has_color_id(0)
            for cv in cvl:
                if color_set.has_color_id(cv.get_color_id()):
                    return True
                return False

        return filter(relevant, all_coins)
Example #29
0
    def select_coins(self, colorvalue, use_fee_estimator=None):
        self._validate_select_coins_parameters(colorvalue, use_fee_estimator)
        colordef = colorvalue.get_colordef()
        if colordef == UNCOLORED_MARKER:
            return self.select_uncolored_coins(colorvalue, use_fee_estimator)

        color_id = colordef.get_color_id()
        if color_id in self.inputs:
            # use inputs provided in proposal
            total = SimpleColorValue.sum([cv_u[0]
                                          for cv_u in self.inputs[color_id]])
            if total < colorvalue:
                raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                             % (colorvalue, total))
            return [cv_u[1] for cv_u in self.inputs[color_id]], total
        
        if colorvalue != self.our_value_limit:
            raise InsufficientFundsError("%s requested, %s found"
                                         % (colorvalue, our_value_limit))
        return super(OperationalETxSpec, self).select_coins(colorvalue)
Example #30
0
    def select_coins(self, colorvalue):
        """Return a list of utxos and sum that corresponds to
        the colored coins identified by <color_def> of amount <colorvalue>
        that we'll be spending from our wallet.
        """
        colordef = colorvalue.get_colordef()
        color_id = colordef.get_color_id()
        cq = self.model.make_coin_query({"color_id_set": set([color_id])})
        utxo_list = cq.get_result()

        zero = ssum = SimpleColorValue(colordef=colordef, value=0)
        selection = []
        if colorvalue == zero:
            raise ZeroSelectError('cannot select 0 coins')
        for utxo in utxo_list:
            ssum += SimpleColorValue.sum(utxo.colorvalues)
            selection.append(utxo)
            if ssum >= colorvalue:
                return selection, ssum
        raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                     % (colorvalue, ssum))
Example #31
0
    def get_utxos_for_address(self, address_rec):
        """Given an address <address_rec>, return the list of utxo's
        straight from the DB. Note this specifically does NOT return
        UTXO objects.
        """
        color_set = self.color_set
        addr_color_set = address_rec.get_color_set()
        all_utxos = self.utxo_manager.get_utxos_for_address(
            address_rec.get_address())
        cdata = self.model.ccc.colordata
        address_is_uncolored = addr_color_set.color_id_set == set([0])
        if address_is_uncolored:
            for utxo in all_utxos:
                utxo.address_rec = address_rec
                utxo.colorvalues = [
                    SimpleColorValue(colordef=UNCOLORED_MARKER,
                                     value=utxo.value)
                ]
            return all_utxos
        for utxo in all_utxos:
            utxo.address_rec = address_rec
            utxo.colorvalues = None
            try:
                utxo.colorvalues = cdata.get_colorvalues(
                    addr_color_set.color_id_set, utxo.txhash, utxo.outindex)
            except Exception as e:
                print e

        def relevant(utxo):
            cvl = utxo.colorvalues
            if utxo.colorvalues is None:
                return False  # None indicates failure
            if cvl == []:
                return color_set.has_color_id(0)
            for cv in cvl:
                if color_set.has_color_id(cv.get_color_id()):
                    return True
                return False

        return filter(relevant, all_utxos)
Example #32
0
 def set_our_value_limit(self, our):
     our_colordef = self.ewctrl.resolve_color_spec(our['color_spec'])
     self.our_value_limit = SimpleColorValue(colordef=our_colordef,
                                             value=our['value'])      
Example #33
0
 def offer_side_to_colorvalue(self, side):
     colordef = self.resolve_color_spec(side['color_spec'])
     return SimpleColorValue(colordef=colordef,
                             value=side['value'])
Example #34
0
class OperationalETxSpec(SimpleOperationalTxSpec):
    def __init__(self, model, ewctrl):
        self.model = model
        self.ewctrl = ewctrl
        self.our_value_limit = None

    def get_targets(self):
        return self.targets

    def get_change_addr(self, color_def):
        color_id = color_def.color_id
        cs = ColorSet.from_color_ids(self.model.get_color_map(), [color_id])
        wam = self.model.get_address_manager()
        return wam.get_change_address(cs).get_address()

    def set_our_value_limit(self, our):
        our_colordef = self.ewctrl.resolve_color_spec(our['color_spec'])
        self.our_value_limit = SimpleColorValue(colordef=our_colordef,
                                                value=our['value'])      

    def prepare_inputs(self, etx_spec):
        self.inputs = defaultdict(list)
        colordata = self.model.ccc.colordata
        for color_spec, inps in etx_spec.inputs.items():
            colordef = self.ewctrl.resolve_color_spec(color_spec)
            color_id_set = set([colordef.get_color_id()])
            for inp in inps:
                txhash, outindex = inp
                tx = self.model.ccc.blockchain_state.get_tx(txhash)
                prevout = tx.outputs[outindex]
                utxo = UTXO({"txhash": txhash,
                             "outindex": outindex,
                             "value": prevout.value,
                             "script": prevout.script})
                colorvalue = None
                if colordef == UNCOLORED_MARKER:
                    colorvalue = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                                  value=prevout.value)
                else:
                    css = colordata.get_colorvalues(color_id_set,
                                                    txhash,
                                                    outindex)
                    if (css and len(css) == 1):
                        colorvalue = css[0]
                if colorvalue:
                    self.inputs[colordef.get_color_id()].append(
                        (colorvalue, utxo))

    def prepare_targets(self, etx_spec, their):
        self.targets = []
        for address, color_spec, value in etx_spec.targets:
            colordef = self.ewctrl.resolve_color_spec(color_spec)
            self.targets.append(ColorTarget(address, 
                                       SimpleColorValue(colordef=colordef,
                                                        value=value)))
        wam = self.model.get_address_manager()
        colormap = self.model.get_color_map()
        their_colordef = self.ewctrl.resolve_color_spec(their['color_spec'])
        their_color_set = ColorSet.from_color_ids(self.model.get_color_map(),
                                                  [their_colordef.get_color_id()])
        ct = ColorTarget(wam.get_change_address(their_color_set).get_address(),
                         SimpleColorValue(colordef=their_colordef,
                                          value=their['value']))
        self.targets.append(ct)

    def select_uncolored_coins(self, colorvalue, use_fee_estimator):
        selected_inputs = []
        selected_value = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                          value=0)
        needed = colorvalue + use_fee_estimator.estimate_required_fee()
        color_id = 0
        if color_id in self.inputs:
            total = SimpleColorValue.sum([cv_u[0]
                                          for cv_u in self.inputs[color_id]])
            needed -= total
            selected_inputs += [cv_u[1]
                               for cv_u in self.inputs[color_id]]
            selected_value += total
        if needed > 0:
            value_limit = SimpleColorValue(colordef=UNCOLORED_MARKER,
                                           value=10000+8192)
            if self.our_value_limit.is_uncolored():
                value_limit += self.our_value_limit
            if needed > value_limit:
                raise InsufficientFundsError("exceeded limits: %s requested, %s found"
                                             % (needed, value_limit))
            our_inputs, our_value = super(OperationalETxSpec, self).\
                select_coins(colorvalue - selected_value, use_fee_estimator)
            selected_inputs += our_inputs
            selected_value += our_value
        return selected_inputs, selected_value

    def select_coins(self, colorvalue, use_fee_estimator=None):
        self._validate_select_coins_parameters(colorvalue, use_fee_estimator)
        colordef = colorvalue.get_colordef()
        if colordef == UNCOLORED_MARKER:
            return self.select_uncolored_coins(colorvalue, use_fee_estimator)

        color_id = colordef.get_color_id()
        if color_id in self.inputs:
            # use inputs provided in proposal
            total = SimpleColorValue.sum([cv_u[0]
                                          for cv_u in self.inputs[color_id]])
            if total < colorvalue:
                raise InsufficientFundsError('not enough coins: %s requested, %s found'
                                             % (colorvalue, total))
            return [cv_u[1] for cv_u in self.inputs[color_id]], total
        
        if colorvalue != self.our_value_limit:
            raise InsufficientFundsError("%s requested, %s found"
                                         % (colorvalue, our_value_limit))
        return super(OperationalETxSpec, self).select_coins(colorvalue)
Example #35
0
    def setUp(self):
        self.path = ":memory:"
        self.pwallet = PersistentWallet(self.path)
        self.config = {
            'dw_master_key': 'test',
            'testnet': True,
            'ccc': {
                'colordb_path': self.path
            },
            'bip0032': False
        }
        self.pwallet.wallet_config = self.config
        self.pwallet.init_model()
        self.model = self.pwallet.get_model()
        self.colormap = self.model.get_color_map()

        self.colordesc0 = "obc:color0:0:0"
        self.colordesc1 = "obc:color1:0:0"
        self.colordesc2 = "obc:color2:0:0"

        # add some colordescs
        self.colorid0 = self.colormap.resolve_color_desc(self.colordesc0)
        self.colorid1 = self.colormap.resolve_color_desc(self.colordesc1)
        self.colorid2 = self.colormap.resolve_color_desc(self.colordesc2)

        self.colordef0 = OBColorDefinition(self.colorid0, {
            'txhash': 'color0',
            'outindex': 0
        })
        self.colordef1 = OBColorDefinition(self.colorid1, {
            'txhash': 'color1',
            'outindex': 0
        })
        self.colordef2 = OBColorDefinition(self.colorid2, {
            'txhash': 'color2',
            'outindex': 0
        })

        self.asset_config = {
            'monikers': ['blue'],
            'color_set': [self.colordesc0],
        }
        self.basset_config = {
            'monikers': ['bitcoin'],
            'color_set': [''],
        }
        self.asset = AssetDefinition(self.colormap, self.asset_config)
        self.basset = AssetDefinition(self.colormap, self.basset_config)
        self.basic = BasicTxSpec(self.model)
        self.bbasic = BasicTxSpec(self.model)

        wam = self.model.get_address_manager()
        self.address0 = wam.get_new_address(self.asset.get_color_set())
        self.addr0 = self.address0.get_address()

        self.bcolorset = ColorSet(self.colormap, [''])
        self.baddress = wam.get_new_address(self.bcolorset)
        self.baddr = self.baddress.get_address()

        self.assetvalue0 = AdditiveAssetValue(asset=self.asset, value=5)
        self.assetvalue1 = AdditiveAssetValue(asset=self.asset, value=6)
        self.assetvalue2 = AdditiveAssetValue(asset=self.asset, value=7)
        self.bassetvalue = AdditiveAssetValue(asset=self.basset, value=8)
        self.assettarget0 = AssetTarget(self.addr0, self.assetvalue0)
        self.assettarget1 = AssetTarget(self.addr0, self.assetvalue1)
        self.assettarget2 = AssetTarget(self.addr0, self.assetvalue2)
        self.bassettarget = AssetTarget(self.baddr, self.bassetvalue)

        self.atargets = [
            self.assettarget0, self.assettarget1, self.assettarget2
        ]

        # add some targets
        self.colorvalue0 = SimpleColorValue(colordef=self.colordef0, value=5)
        self.colortarget0 = ColorTarget(self.addr0, self.colorvalue0)
        self.colorvalue1 = SimpleColorValue(colordef=self.colordef0, value=6)
        self.colortarget1 = ColorTarget(self.addr0, self.colorvalue1)
        self.colorvalue2 = SimpleColorValue(colordef=self.colordef0, value=7)
        self.colortarget2 = ColorTarget(self.addr0, self.colorvalue2)
        self.bcolorvalue = SimpleColorValue(colordef=UNCOLORED_MARKER, value=8)
        self.bcolortarget = ColorTarget(self.baddr, self.bcolorvalue)

        self.targets = [
            self.colortarget0, self.colortarget1, self.colortarget2
        ]
        self.transformer = TransactionSpecTransformer(self.model, self.config)
        self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c'
        self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7'
Example #36
0
 def get_dust_threshold(self):
     return SimpleColorValue(colordef=UNCOLORED_MARKER, value=10000)