def compose_genesis_tx_spec(self, op_tx_spec): targets = op_tx_spec.get_targets()[:] if len(targets) != 1: raise InvalidTargetError( 'genesis transaction spec needs exactly one target') target = targets[0] if target.get_colordef() != GENESIS_OUTPUT_MARKER: raise InvalidColorError( 'genesis transaction target should use -1 color_id') fee = op_tx_spec.get_required_fee(300) uncolored_value = SimpleColorValue(colordef=UNCOLORED_MARKER, value=target.get_value()) colorvalue = fee + uncolored_value inputs, total = op_tx_spec.select_coins(colorvalue) change = total - fee - uncolored_value if change > 0: targets.append( ColorTarget(op_tx_spec.get_change_addr(UNCOLORED_MARKER), change)) txouts = [ txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in targets ] return txspec.ComposedTxSpec(inputs, txouts)
def compose_genesis_tx_spec(cls, op_tx_spec): if len(op_tx_spec.get_targets()) != 1: raise InvalidTargetError( 'genesis transaction spec needs exactly one target') g_target = op_tx_spec.get_targets()[0] if g_target.get_colordef() != GENESIS_OUTPUT_MARKER: raise InvalidColorError( 'genesis transaction target should use -1 color_id') fee = op_tx_spec.get_required_fee(300) g_value = g_target.get_value() padding_needed = op_tx_spec.get_dust_threshold().get_value() - g_value tag = cls.Tag(cls.Tag.closest_padding_code(padding_needed), True) padding = tag.get_padding() uncolored_needed = SimpleColorValue(colordef=UNCOLORED_MARKER, value=padding + g_value) uncolored_inputs, uncolored_total = op_tx_spec.select_coins( uncolored_needed + fee) change = uncolored_total - uncolored_needed - fee txouts = [] txouts.append( txspec.ComposedTxSpec.TxOut(padding + g_value, g_target.get_address())) if change > 0: txouts.append( txspec.ComposedTxSpec.TxOut( change.get_value(), op_tx_spec.get_change_addr(UNCOLORED_MARKER))) uncolored_inputs[0].set_nSequence(tag.to_nSequence()) return txspec.ComposedTxSpec(uncolored_inputs, txouts)
def compose_tx_spec(self, op_tx_spec): targets_by_color = group_targets_by_color(op_tx_spec.get_targets(), self.__class__) uncolored_targets = targets_by_color.pop(UNCOLORED_MARKER.color_id, []) # get inputs for each color colored_inputs = [] colored_targets = [] for color_id, targets in targets_by_color.items(): color_def = targets[0].get_colordef() needed_sum = ColorTarget.sum(targets) inputs, total = op_tx_spec.select_coins(needed_sum) change = total - needed_sum if change > 0: targets.append( ColorTarget(op_tx_spec.get_change_addr(color_def), change)) colored_inputs += inputs colored_targets += targets uncolored_needed = ColorTarget.sum(uncolored_targets) fee = op_tx_spec.get_required_fee(250 * (len(colored_inputs) + 1)) uncolored_inputs, uncolored_total = op_tx_spec.select_coins( uncolored_needed + fee) uncolored_change = uncolored_total - uncolored_needed - fee if uncolored_change > 0: uncolored_targets.append( ColorTarget(op_tx_spec.get_change_addr(UNCOLORED_MARKER), uncolored_change)) txins = colored_inputs + uncolored_inputs txouts = [ txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in (colored_targets + uncolored_targets) ] return txspec.ComposedTxSpec(txins, txouts)
def compose_tx_spec(self, op_tx_spec): colored_targets = [] uncolored_targets = [] for target in op_tx_spec.get_targets(): color_id = target[1] if color_id == self.color_id: colored_targets.append(target) elif color_id == 0: uncolored_targets.append(target) else: raise Exception('ColorDef cannot work with this color_id') colored_needed = sum([target[2] for target in colored_targets]) uncolored_needed = sum([target[2] for target in uncolored_targets]) colored_inputs, colored_total = op_tx_spec.select_coins( self.color_id, colored_needed) fee = op_tx_spec.get_required_fee(750) uncolored_inputs, uncolored_total = op_tx_spec.select_coins( 0, uncolored_needed + fee) colored_change = colored_total - colored_needed if colored_change > 0: colored_targets.append((op_tx_spec.get_change_addr(self.color_id), self.color_id, colored_change)) uncolored_change = uncolored_total - uncolored_needed - fee if uncolored_change > 0: uncolored_targets.append( (op_tx_spec.get_change_addr(0), 0, uncolored_change)) txins = [ txspec.ComposedTxSpec.TxIn(utxo) for utxo in (colored_inputs + uncolored_inputs) ] txouts = [ txspec.ComposedTxSpec.TxOut(target[2], target[0]) for target in (colored_targets + uncolored_targets) ] return txspec.ComposedTxSpec(txins, txouts)
def compose_tx_spec(self, op_tx_spec): # group targets by color targets_by_color = defaultdict(list) # group targets by color for target in op_tx_spec.get_targets(): color_def = target.get_colordef() if color_def == UNCOLORED_MARKER \ or isinstance(color_def, POBColorDefinition): targets_by_color[color_def.color_id].append(target) else: raise InvalidColorError('incompatible color definition') uncolored_targets = targets_by_color.pop(UNCOLORED_MARKER.color_id, []) # get inputs for each color colored_inputs = [] colored_targets = [] for color_id, targets in targets_by_color.items(): color_def = targets[0].get_colordef() needed_sum = ColorTarget.sum(targets) inputs, total = op_tx_spec.select_coins(needed_sum) change = total - needed_sum if change > 0: targets.append(ColorTarget( op_tx_spec.get_change_addr(color_def), change)) colored_inputs += inputs colored_targets += targets # we also need some amount of extra "uncolored" coins # for padding purposes, possibly padding_needed = (len(colored_targets) - len(colored_inputs)) \ * self.PADDING uncolored_needed = ColorTarget.sum(uncolored_targets) \ + SimpleColorValue(colordef=UNCOLORED_MARKER, value=padding_needed) fee = op_tx_spec.get_required_fee(250 * (len(colored_inputs) + 1)) amount_needed = uncolored_needed + fee zero = SimpleColorValue(colordef=UNCOLORED_MARKER, value=0) if amount_needed == zero: uncolored_change = zero uncolored_inputs = [] else: uncolored_inputs, uncolored_total = op_tx_spec.select_coins(amount_needed) uncolored_change = uncolored_total - amount_needed if uncolored_change > zero: uncolored_targets.append( ColorTarget(op_tx_spec.get_change_addr(UNCOLORED_MARKER), uncolored_change)) # compose the TxIn and TxOut elements txins = colored_inputs + uncolored_inputs txouts = [ txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in colored_targets] txouts += [txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in uncolored_targets] return txspec.ComposedTxSpec(txins, txouts)
def compose_tx_spec(self, op_tx_spec): # group targets by color targets_by_color = defaultdict(list) for target in op_tx_spec.get_targets(): color_def = target[1] targets_by_color[color_def.color_id].append(target) uncolored_targets = targets_by_color.pop(UNCOLORED_MARKER.color_id, []) # get inputs for each color colored_inputs = [] colored_targets = [] for color_id, targets in targets_by_color.items(): color_def = targets[0][1] needed_sum = sum([target[2] for target in targets]) inputs, total = op_tx_spec.select_coins(color_def, needed_sum) change = total - needed_sum if change > 0: targets.append( (op_tx_spec.get_change_addr(color_def), color_def, change)) colored_inputs += inputs colored_targets += targets # we also need some amount of extra "uncolored" coins # for padding purposes, possibly padding_needed = (len(colored_targets) - len(colored_inputs)) \ * self.PADDING uncolored_needed = sum([target[2] for target in uncolored_targets]) \ + padding_needed fee = op_tx_spec.get_required_fee(250 * (len(colored_inputs) + 1)) amount_needed = uncolored_needed + fee if amount_needed == 0: uncolored_change = 0 uncolored_inputs = [] else: uncolored_inputs, uncolored_total = \ op_tx_spec.select_coins(UNCOLORED_MARKER, amount_needed) uncolored_change = uncolored_total - amount_needed if uncolored_change > 0: uncolored_targets.append( (op_tx_spec.get_change_addr(UNCOLORED_MARKER), None, uncolored_change)) # compose the TxIn and TxOut elements txins = colored_inputs + uncolored_inputs txouts = [ txspec.ComposedTxSpec.TxOut(self.color_to_satoshi(target[2]), target[0]) for target in colored_targets ] txouts += [ txspec.ComposedTxSpec.TxOut(target[2], target[0]) for target in uncolored_targets ] return txspec.ComposedTxSpec(txins, txouts)
def compose_genesis_tx_spec(self, op_tx_spec): targets = op_tx_spec.get_targets()[:] if len(targets) != 1: raise Exception( 'genesis transaction spec needs exactly one target') target_addr, color_def, value = targets[0] if color_def != GENESIS_OUTPUT_MARKER: raise Exception( 'genesis transaction target should use -1 color_id') fee = op_tx_spec.get_required_fee(300) inputs, total = op_tx_spec.select_coins(UNCOLORED_MARKER, fee + value) change = total - fee - value if change > 0: targets.append((op_tx_spec.get_change_addr(UNCOLORED_MARKER), UNCOLORED_MARKER, change)) txouts = [txspec.ComposedTxSpec.TxOut(target[2], target[0]) for target in targets] return txspec.ComposedTxSpec(inputs, txouts)
def compose_genesis_tx_spec(self, op_tx_spec): targets = op_tx_spec.get_targets()[:] if len(targets) != 1: raise Exception( 'genesis transaction spec needs exactly one target') target_addr, color_id, value = targets[0] if color_id != -1: raise Exception( 'genesis transaction target should use -1 color_id') fee = op_tx_spec.get_required_fee(300) inputs, total = op_tx_spec.select_coins(0, fee + value) change = total - fee - value if change > 0: targets.append((op_tx_spec.get_change_addr(0), 0, change)) txins = [txspec.ComposedTxSpec.TxIn(utxo) for utxo in inputs] txouts = [ txspec.ComposedTxSpec.TxOut(target[2], target[0]) for target in targets ] return txspec.ComposedTxSpec(txins, txouts)
def compose_tx_spec(self, op_tx_spec): targets_by_color = defaultdict(list) uncolored_targets = [] # group targets by color for target in op_tx_spec.get_targets(): color_def = target[1] if color_def == UNCOLORED_MARKER: uncolored_targets.append(target) elif isinstance(color_def, OBColorDefinition): targets_by_color[color_def.color_id].append(target) else: raise Exception('incompatible color definition') # get inputs for each color colored_inputs = [] colored_targets = [] for color_id, targets in targets_by_color.items(): color_def = targets[0][1] needed_sum = sum([target[2] for target in targets]) inputs, total = op_tx_spec.select_coins(color_def, needed_sum) change = total - needed_sum if change > 0: targets.append( (op_tx_spec.get_change_addr(color_def), color_def, change)) colored_inputs += inputs colored_targets += targets uncolored_needed = sum([target[2] for target in uncolored_targets]) fee = op_tx_spec.get_required_fee(250 * (len(colored_inputs) + 1)) uncolored_inputs, uncolored_total = \ op_tx_spec.select_coins(UNCOLORED_MARKER, uncolored_needed + fee) uncolored_change = uncolored_total - uncolored_needed - fee if uncolored_change > 0: uncolored_targets.append( (op_tx_spec.get_change_addr(UNCOLORED_MARKER), None, uncolored_change)) txins = colored_inputs + uncolored_inputs txouts = [ txspec.ComposedTxSpec.TxOut(target[2], target[0]) for target in (colored_targets + uncolored_targets) ] return txspec.ComposedTxSpec(txins, txouts)
def compose_genesis_tx_spec(cls, op_tx_spec): targets = op_tx_spec.get_targets()[:] if len(targets) != 1: raise Exception( 'genesis transaction spec needs exactly one target') target_addr, color_def, colorvalue = targets[0] if color_def != GENESIS_OUTPUT_MARKER: raise Exception( 'genesis transaction target should use -1 color_id') fee = op_tx_spec.get_required_fee(300) satoshivalue = cls.color_to_satoshi(colorvalue) # select uncolored coins to create the genesis inputs, total = op_tx_spec.select_coins(UNCOLORED_MARKER, fee + satoshivalue) change = total - fee - satoshivalue txouts = [txspec.ComposedTxSpec.TxOut(satoshivalue, target_addr)] if change > 0: txouts.append( txspec.ComposedTxSpec.TxOut( change, op_tx_spec.get_change_addr(UNCOLORED_MARKER))) return txspec.ComposedTxSpec(inputs, txouts)
def compose_tx_spec(self, op_tx_spec): targets_by_color = defaultdict(list) uncolored_targets = [] # group targets by color for target in op_tx_spec.get_targets(): color_def = target.get_colordef() if color_def == UNCOLORED_MARKER: uncolored_targets.append(target) elif isinstance(color_def, OBColorDefinition): targets_by_color[color_def.color_id].append(target) else: raise InvalidColorError('incompatible color definition') # get inputs for each color colored_inputs = [] colored_targets = [] for color_id, targets in targets_by_color.items(): color_def = targets[0].get_colordef() needed_sum = ColorTarget.sum(targets) inputs, total = op_tx_spec.select_coins(needed_sum) change = total - needed_sum if change > 0: targets.append( ColorTarget(op_tx_spec.get_change_addr(color_def), change)) colored_inputs += inputs colored_targets += targets uncolored_needed = ColorTarget.sum(uncolored_targets) fee = op_tx_spec.get_required_fee(250 * (len(colored_inputs) + 1)) uncolored_inputs, uncolored_total = op_tx_spec.select_coins(uncolored_needed + fee) uncolored_change = uncolored_total - uncolored_needed - fee if uncolored_change > 0: uncolored_targets.append( ColorTarget(op_tx_spec.get_change_addr(UNCOLORED_MARKER), uncolored_change)) txins = colored_inputs + uncolored_inputs txouts = [txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in (colored_targets + uncolored_targets)] return txspec.ComposedTxSpec(txins, txouts)
def compose_tx_spec(self, op_tx_spec): targets_by_color = group_targets_by_color(op_tx_spec.get_targets(), self.__class__) uncolored_targets = targets_by_color.pop(UNCOLORED_MARKER.color_id, []) colored_txins = [] colored_txouts = [] if uncolored_targets: uncolored_needed = ColorTarget.sum(uncolored_targets) else: uncolored_needed = SimpleColorValue(colordef=UNCOLORED_MARKER, value=0) dust_threshold = op_tx_spec.get_dust_threshold().get_value() inputs_by_color = dict() min_padding = 0 # step 1: get inputs, create change targets, compute min padding for color_id, targets in targets_by_color.items(): color_def = targets[0].get_colordef() needed_sum = ColorTarget.sum(targets) inputs, total = op_tx_spec.select_coins(needed_sum) inputs_by_color[color_id] = inputs change = total - needed_sum if change > 0: targets.append( ColorTarget(op_tx_spec.get_change_addr(color_def), change)) for target in targets: padding_needed = dust_threshold - target.get_value() if padding_needed > min_padding: min_padding = padding_needed tag = self.Tag(self.Tag.closest_padding_code(min_padding), False) padding = tag.get_padding() # step 2: create txins & txouts, compute uncolored requirements for color_id, targets in targets_by_color.items(): color_def = targets[0].get_colordef() for inp in inputs_by_color[color_id]: colored_txins.append(inp) uncolored_needed -= SimpleColorValue(colordef=UNCOLORED_MARKER, value=inp.value) print uncolored_needed for target in targets: svalue = target.get_value() + padding colored_txouts.append( txspec.ComposedTxSpec.TxOut(svalue, target.get_address())) uncolored_needed += SimpleColorValue(colordef=UNCOLORED_MARKER, value=svalue) print uncolored_needed fee = op_tx_spec.get_required_fee(250 * (len(colored_txins) + 1)) uncolored_txouts = [] uncolored_inputs = [] uncolored_change = None if uncolored_needed + fee > 0: uncolored_inputs, uncolored_total = op_tx_spec.select_coins( uncolored_needed + fee) uncolored_txouts = [ txspec.ComposedTxSpec.TxOut(target.get_satoshi(), target.get_address()) for target in uncolored_targets ] uncolored_change = uncolored_total - uncolored_needed - fee else: uncolored_change = (-uncolored_needed) - fee if uncolored_change > 0: uncolored_txouts.append( txspec.ComposedTxSpec.TxOut( uncolored_change.get_value(), op_tx_spec.get_change_addr(UNCOLORED_MARKER))) all_inputs = colored_txins + uncolored_inputs all_inputs[0].set_nSequence(tag.to_nSequence()) return txspec.ComposedTxSpec(all_inputs, colored_txouts + uncolored_txouts)