def get_balance(self, node, dst, edge_data): return balance_with_interests( get_balance(edge_data, node, dst), get_interest_rate(edge_data, node, dst), get_interest_rate(edge_data, dst, node), self.timestamp - get_mtime(edge_data), )
def get_balances_along_path(self, path): balances = [] for i in range(0, len(path) - 1): data = self.graph.get_edge_data(path[i], path[i + 1]) balances.append(get_balance(data, path[i], path[i + 1])) return balances
def total_cost_from_start_to_dst( self, cost_from_start_to_node, node, dst, edge_data ): if dst == self.ignore or node == self.ignore: return None if get_is_frozen(edge_data): return None sum_fees, num_hops = cost_from_start_to_node if num_hops + 1 > self.max_hops: return None # fee computation has been inlined here, since the comment in # Graph._get_fee suggests it should be as fast as possible. This means # we do have some code duplication, but I couldn't use some of the # methods in Graph anyway, because they don't take a timestamp argument # and rather use the current time. # # We should profile this at some point in time. # # We do the pathfinding in reverse, when the sender pays. In this # method this means that the payment is done from dst to node, i.e. the # order of arguments node and dst is reversed in the following code pre_balance = balance_with_interests( get_balance(edge_data, dst, node), get_interest_rate(edge_data, dst, node), get_interest_rate(edge_data, node, dst), self.timestamp - get_mtime(edge_data), ) if num_hops == 0: fee = 0 else: fee = calculate_fees_reverse( imbalance_generated=imbalance_generated( value=self.value + sum_fees, balance=pre_balance ), capacity_imbalance_fee_divisor=self.capacity_imbalance_fee_divisor, ) if sum_fees + fee > self.max_fees: return None # check that we don't exceed the creditline capacity = pre_balance + get_creditline(edge_data, node, dst) if self.value + sum_fees + fee > capacity: # creditline exceeded return None return self.Cost(fees=sum_fees + fee, num_hops=num_hops + 1)
def total_cost_from_start_to_dst( self, cost_from_start_to_node: Cost, node, dst, edge_data ): if dst == self.ignore or node == self.ignore: return None if get_is_frozen(edge_data): return None # For this case the pathfinding is not done in reverse. # # we maintain the computed fee for the previous hop, since that is only # 'paid out' when we jump to the next hop The first element in this # tuple has to be the sum of the fees not including the fee for the # previous hop, since the graph finding algorithm needs to sort by that # and not by what would be paid out if there is another hop sum_fees, num_hops, previous_hop_fee = cost_from_start_to_node if num_hops + 1 > self.max_hops: return None pre_balance = balance_with_interests( get_balance(edge_data, node, dst), get_interest_rate(edge_data, node, dst), get_interest_rate(edge_data, dst, node), self.timestamp - get_mtime(edge_data), ) fee = calculate_fees( imbalance_generated=imbalance_generated( value=self.value - sum_fees - previous_hop_fee, balance=pre_balance ), capacity_imbalance_fee_divisor=self.capacity_imbalance_fee_divisor, ) if sum_fees + previous_hop_fee > self.max_fees: return None # check that we don't exceed the creditline capacity = pre_balance + get_creditline(edge_data, dst, node) if self.value - sum_fees - previous_hop_fee > capacity: # creditline exceeded return None return self.Cost( fees=sum_fees + previous_hop_fee, num_hops=num_hops + 1, previous_hop_fee=fee, )
def transfer_path(self, path, value, expected_fees, timestamp=0): assert value > 0 cost_accumulator = SenderPaysCostAccumulatorSnapshot( timestamp=timestamp, value=value, capacity_imbalance_fee_divisor=self.capacity_imbalance_fee_divisor, ) cost = cost_accumulator.zero() path = list(reversed(path)) for source, target in zip(path, path[1:]): edge_data = self.graph.get_edge_data(source, target) cost = cost_accumulator.total_cost_from_start_to_dst( cost, source, target, edge_data ) if cost is None: raise nx.NetworkXNoPath("no path found") new_balance = get_balance(edge_data, target, source) - value - cost[0] set_balance(edge_data, target, source, new_balance) assert expected_fees == cost[0] return cost[0]
def test_balance(data): set_balance(data, a, b, 100) assert get_balance(data, a, b) == 100 assert get_balance(data, b, a) == -100
def balance(self) -> int: """Returns the balance without interests""" return get_balance(self.data, self.a, self.b)