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)
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
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))
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))
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))
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