예제 #1
0
 def _loop_size2(self):
     size = len(self.utxos)
     iteration = 0
     for i in range(size):
         iteration += 1
         if self.utxos[i] > self.amount:
             change = self.utxos[i] - self.amount
             expense = utils.get_solution_expense(self.problem.fee, change)
             if expense < self.solution.expense:
                 self.solution = Solution(change, [self.utxos[i]], expense)
                 if self._verbose > 1:
                     self._print_solution(iteration)
         else:
             for j in range(i + 1, size):
                 iteration += 1
                 if self.utxos[i] + self.utxos[j] > self.amount:
                     # solution
                     change = (self.utxos[i] + self.utxos[j]) - self.amount
                     expense = utils.get_solution_expense(
                         self.problem.fee, change)
                     if expense < self.solution.expense:
                         self.solution = Solution(
                             change, [self.utxos[i], self.utxos[j]],
                             expense)
                         if self._verbose > 1:
                             self._print_solution(iteration)
예제 #2
0
    def _init(self):
        fee = self.problem.fee
        self._filter_pay_requests(self.problem.payRequests, fee)
        if is_empty(self._payRequests):
            raise RuntimeError("No pay request")

        # utxos = utxos - cost of using it in tx
        utxos = map(lambda v: v - fee * utils.inputSizeBytes,
                    self.problem.utxos)
        utxos = filter(lambda v: v > 0, utxos)
        utxos = list(utxos)
        if is_empty(utxos):
            raise RuntimeError("Insufficient funds")

        amount = utils.get_tx_amount(self._payRequests, fee)
        if amount > sum(utxos):
            raise RuntimeError("Insufficient funds")
        largeUtxos = list(filter(lambda v: v >= amount, utxos))
        if is_not_empty(largeUtxos):
            minUtxo = min(largeUtxos)
            change = minUtxo - amount
            solution = Solution(change, [minUtxo],
                                utils.get_solution_expense(fee, change))
            utxos = list(filter(lambda v: v < minUtxo, utxos))
        else:
            solution = Solver._build_solution_min_inputs_with_change(
                utxos, amount, fee)
        # solution - the best solution so far
        if solution is None or len(solution.inputs) > self._inputCountMax:
            raise RuntimeError("No solution")

        self.utxos = utxos
        self.amount = amount
        self.solution = solution
예제 #3
0
 def _build_any_solution(utxos, amount, fee):
     inputs = []
     s = 0
     for a in utxos:
         inputs.append(a)
         s += a
         if s >= amount:
             break
     change = s - amount
     return Solution(s - amount, inputs,
                     utils.get_solution_expense(fee, change))
예제 #4
0
 def _build_any_solution(utxos, amount, fee):
     inputInds = []
     s = 0
     for i, a in enumerate(utxos):
         inputInds.append(i)
         s += a
         if s >= amount:
             break
     change = s - amount
     return Solution(change, inputInds,
                     utils.get_solution_expense(fee, change))
예제 #5
0
 def _build_solution_min_inputs_with_change(utxos, amount, fee):
     # add change
     amount += fee * utils.outputSizeBytes
     utxos = sorted(utxos, reverse=True)
     inputs = []
     s = 0
     for a in utxos:
         inputs.append(a)
         s += a
         if s >= amount:
             break
     if s < amount:
         return None
     change = s - amount
     return Solution(s - amount, inputs,
                     utils.get_solution_expense(fee, change))
예제 #6
0
    def _loop(self, timeout):
        if self._verbose > 1:
            self._print_solution(0)
        if is_empty(self.utxos):
            # solution found or does not exist
            return
        if self.solution is not None and self.solution.change == 0:
            return

        self.utxos = sorted(self.utxos, reverse=True)
        #random.shuffle(self.utxos)
        i = 0
        reserved = [
            None for _ in self.utxos
        ]  # None - default, True - utxos used, False - utxos unused
        inputAmount = 0
        inputCount = 0
        iteration = 0
        self.startTime = datetime.now()

        while True:
            iteration += 1
            if iteration % 100000 == 0 and datetime.now(
            ) - self.startTime > timeout:
                print("iter {} timeout reached".format(iteration))
                break
            if reserved[i] is None:
                reserved[i] = True
                inputAmount += self.utxos[i]
                inputCount += 1

                # Note. amount does not include commision of change output.
                if inputAmount >= self.amount:
                    # solution found
                    change = inputAmount - self.amount
                    expense = utils.get_solution_expense(
                        self.problem.fee, change)
                    if self.solution is None or expense < self.solution.expense or (
                            self._allSolutions and expense == 0):
                        inputs = Solver._build_input_by_reserv(
                            self.utxos, reserved)
                        self.solution = Solution(change, inputs, expense)
                        self.solution.iteration = iteration
                        if self._verbose > 1:
                            self._print_solution(iteration)
                        if change == 0 and not self._allSolutions:
                            break  # optimal solution found
                elif inputCount < self._inputCountMax and i + 1 < len(
                        reserved):
                    i += 1
            elif reserved[i]:
                reserved[i] = False
                inputAmount -= self.utxos[i]
                inputCount -= 1
                if inputCount < self._inputCountMax and i + 1 < len(reserved):
                    i += 1
            else:  # reserved[i] == False
                reserved[i] = None
                i -= 1
                if i < 0:
                    break