Skip to content

Commit

Permalink
Merge pull request #25 from aboutcircles/feature/v2-pathfinder
Browse files Browse the repository at this point in the history
Feature/v2 pathfinder
  • Loading branch information
jaensen authored Oct 24, 2024
2 parents adeb20c + 3f11066 commit b3e0e09
Show file tree
Hide file tree
Showing 34 changed files with 1,130 additions and 159 deletions.
15 changes: 2 additions & 13 deletions Circles.Index.Query.Tests/TestConversionUtils.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Numerics;
using Circles.Index.Utils;

namespace Circles.Index.Query.Tests;
Expand Down Expand Up @@ -37,18 +38,6 @@ public class TestConversionUtils
[Test]
public void TestConvertCirclesToStaticCircles()
{
var inflation = 0.07m;
var year = 4;
var baseAmount = 8m;
var inflatedAmount = baseAmount;
for (int i = 0; i < year; i++)
{
inflatedAmount *= 1 + inflation;
}



decimal circlesBalance = 20;
decimal staticCirclesBalance = ConversionUtils.CirclesToStaticCircles(circlesBalance, DateTime.Now);
decimal staticCirclesBalance = ConversionUtils.CirclesToCrc(0.13151319940322485m);
}
}
15 changes: 15 additions & 0 deletions Circles.Index.Query.Tests/TestSelect.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Data;
using System.Numerics;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -368,4 +369,18 @@ public void JsonSerialization_Deserialization_Complex()
Assert.That(deserializedOrderBy.Column, Is.EqualTo(orderBy.Column));
Assert.That(deserializedOrderBy.SortOrder, Is.EqualTo(orderBy.SortOrder));
}

[Test]
public void B()
{
var t = BigInteger.Parse("238208892873504508097789456176502153024265176387")
* (
BigInteger.Parse("31556952")
- BigInteger.Parse("4142484904995219")
)
+ BigInteger.Parse("238208892873504508097789456176502153024265176387")
* BigInteger.Parse("4142484904995219");


}
}
1 change: 1 addition & 0 deletions Circles.Index.Rpc/Circles.Index.Rpc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<ProjectReference Include="..\Circles.Index.Common\Circles.Index.Common.csproj" />
<ProjectReference Include="..\Circles.Index.Query\Circles.Index.Query.csproj" />
<ProjectReference Include="..\Circles.Index.Utils\Circles.Index.Utils.csproj" />
<ProjectReference Include="..\Circles.Pathfinder\Circles.Pathfinder.csproj" />
</ItemGroup>

</Project>
12 changes: 12 additions & 0 deletions Circles.Index.Rpc/CirclesRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
using Circles.Index.Query;
using Circles.Index.Query.Dto;
using Circles.Index.Utils;
using Circles.Pathfinder;
using Circles.Pathfinder.Data;
using Circles.Pathfinder.DTOs;
using Circles.Pathfinder.Graphs;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
Expand Down Expand Up @@ -343,6 +347,14 @@ public ResultWrapper<CirclesEvent[]> circles_events(Address? address, long? from
eventTypes, filterPredicates, sortAscending));
}

public async Task<ResultWrapper<MaxFlowResponse>> circlesV2_findPath(FlowRequest flowRequest)
{
var loadGraph = new LoadGraph(_indexerContext.Settings.IndexDbConnectionString);
var graphFactory = new GraphFactory();
var pathfinder = new V2Pathfinder(loadGraph, graphFactory);
return ResultWrapper<MaxFlowResponse>.Success(await pathfinder.ComputeMaxFlow(flowRequest));
}

private string[] GetTokenExposureIds(Address address)
{
var selectTokenExposure = new Select(
Expand Down
6 changes: 6 additions & 0 deletions Circles.Index.Rpc/ICirclesRpcModule.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Circles.Index.Common;
using Circles.Index.Query.Dto;
using Circles.Pathfinder.DTOs;
using Nethermind.Core;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Modules;
Expand Down Expand Up @@ -59,4 +60,9 @@ public interface ICirclesRpcModule : IRpcModule
IsImplemented = true)]
ResultWrapper<CirclesEvent[]> circles_events(Address? address, long? fromBlock, long? toBlock = null,
string[]? eventTypes = null, FilterPredicateDto[]? filters = null, bool? sortAscending = false);

[JsonRpcMethod(
Description = "Tries to find a transitive transfer path between two addresses in the Circles V2 graph",
IsImplemented = true)]
Task<ResultWrapper<MaxFlowResponse>> circlesV2_findPath(FlowRequest flowRequest);
}
4 changes: 2 additions & 2 deletions Circles.Index/Circles.Index.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
<Authors>Daniel Janz (Gnosis Service GmbH)</Authors>
<Copyright>Gnosis Service GmbH</Copyright>
<Product>Circles</Product>
<AssemblyVersion>1.9.1</AssemblyVersion>
<FileVersion>1.9.1</FileVersion>
<AssemblyVersion>1.10.0</AssemblyVersion>
<FileVersion>1.10.0</FileVersion>
</PropertyGroup>


Expand Down
13 changes: 13 additions & 0 deletions Circles.Pathfinder/Circles.Pathfinder.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Npgsql" Version="8.0.5" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions Circles.Pathfinder/DTOs/FlowRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Circles.Pathfinder.DTOs;

public class FlowRequest
{
public string? Source { get; set; }
public string? Sink { get; set; }
public string? TargetFlow { get; set; }
}
13 changes: 13 additions & 0 deletions Circles.Pathfinder/DTOs/MaxFlowResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Circles.Pathfinder.DTOs;

public class MaxFlowResponse
{
public string MaxFlow { get; set; }
public List<TransferPathStep> Transfers { get; set; }

public MaxFlowResponse(string maxFlow, List<TransferPathStep> transfers)
{
MaxFlow = maxFlow;
Transfers = transfers;
}
}
9 changes: 9 additions & 0 deletions Circles.Pathfinder/DTOs/TransferPathStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Circles.Pathfinder.DTOs;

public class TransferPathStep
{
public string From { get; set; } = string.Empty;
public string To { get; set; } = string.Empty;
public string TokenOwner { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
}
54 changes: 54 additions & 0 deletions Circles.Pathfinder/Data/LoadGraph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Npgsql;

namespace Circles.Pathfinder.Data
{
// TODO: Use CirclesQuery<T> and remove the Npgsql dependency
public class LoadGraph(string connectionString)
{
public IEnumerable<(string Balance, string Account, string TokenAddress)> LoadV2Balances()
{
var balanceQuery = @"
select ""demurragedTotalBalance""::text, ""account"", ""tokenAddress""
from ""V_CrcV2_BalancesByAccountAndToken""
where ""demurragedTotalBalance"" > 0;
";

using var connection = new NpgsqlConnection(connectionString);
connection.Open();

using var command = new NpgsqlCommand(balanceQuery, connection);
using var reader = command.ExecuteReader();

while (reader.Read())
{
var balance = reader.GetString(0);
var account = reader.GetString(1);
var tokenAddress = reader.GetString(2);

yield return (balance, account, tokenAddress);
}
}

public IEnumerable<(string Truster, string Trustee, int Limit)> LoadV2Trust()
{
var trustQuery = @"
select truster, trustee
from ""V_CrcV2_TrustRelations"";
";

using var connection = new NpgsqlConnection(connectionString);
connection.Open();

using var command = new NpgsqlCommand(trustQuery, connection);
using var reader = command.ExecuteReader();

while (reader.Read())
{
var truster = reader.GetString(0);
var trustee = reader.GetString(1);

yield return (truster, trustee, 100); // Assuming a default trust limit of 100 in V2
}
}
}
}
18 changes: 18 additions & 0 deletions Circles.Pathfinder/Edges/CapacityEdge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Numerics;

namespace Circles.Pathfinder.Edges;

/// <summary>
/// Represents a capacity edge for potential token transfers between nodes.
/// </summary>
public class CapacityEdge : Edge
{
public string Token { get; }
public BigInteger InitialCapacity { get; }

public CapacityEdge(string from, string to, string token, BigInteger initialCapacity) : base(from, to)
{
Token = token;
InitialCapacity = initialCapacity;
}
}
13 changes: 13 additions & 0 deletions Circles.Pathfinder/Edges/Edge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Circles.Pathfinder.Edges;

public abstract class Edge
{
public string From { get; }
public string To { get; }

public Edge(string from, string to)
{
From = from;
To = to;
}
}
20 changes: 20 additions & 0 deletions Circles.Pathfinder/Edges/FlowEdge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Numerics;

namespace Circles.Pathfinder.Edges;

/// <summary>
/// Represents a flow edge for actual token transfers between nodes.
/// </summary>
public class FlowEdge : CapacityEdge
{
public BigInteger CurrentCapacity { get; set; }
public BigInteger Flow { get; set; }
public FlowEdge? ReverseEdge { get; set; }

public FlowEdge(string from, string to, string token, BigInteger initialCapacity)
: base(from, to, token, initialCapacity)
{
CurrentCapacity = initialCapacity;
Flow = 0;
}
}
11 changes: 11 additions & 0 deletions Circles.Pathfinder/Edges/TrustEdge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Circles.Pathfinder.Edges;

/// <summary>
/// Represents a trust relationship between two nodes.
/// </summary>
public class TrustEdge : Edge
{
public TrustEdge(string from, string to) : base(from, to)
{
}
}
38 changes: 38 additions & 0 deletions Circles.Pathfinder/Graphs/BalanceGraph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Numerics;
using Circles.Pathfinder.Edges;
using Circles.Pathfinder.Nodes;

namespace Circles.Pathfinder.Graphs;

public class BalanceGraph : IGraph<CapacityEdge>
{
public IDictionary<string, Node> Nodes { get; } = new Dictionary<string, Node>();
public HashSet<CapacityEdge> Edges { get; } = new();
public IDictionary<string, BalanceNode> BalanceNodes { get; } = new Dictionary<string, BalanceNode>();
public IDictionary<string, AvatarNode> AvatarNodes { get; } = new Dictionary<string, AvatarNode>();

public void AddAvatar(string avatarAddress)
{
Nodes.Add(avatarAddress, new AvatarNode(avatarAddress));
}

public void AddBalance(string address, string token, BigInteger balance)
{
address = address.ToLower();
token = token.ToLower();
if (!AvatarNodes.ContainsKey(address))
{
AvatarNodes.Add(address, new AvatarNode(address));
}

var balanceNode = new BalanceNode(address, token, balance);
Nodes.Add(balanceNode.Address, balanceNode);
BalanceNodes.Add(balanceNode.Address, balanceNode);

var capacityEdge = new CapacityEdge(address, balanceNode.Address, token, balance);
Edges.Add(capacityEdge);

AvatarNodes[address].OutEdges.Add(capacityEdge);
BalanceNodes[balanceNode.Address].InEdges.Add(capacityEdge);
}
}
63 changes: 63 additions & 0 deletions Circles.Pathfinder/Graphs/CapacityGraph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Numerics;
using Circles.Pathfinder.Edges;
using Circles.Pathfinder.Nodes;

namespace Circles.Pathfinder.Graphs;

public class CapacityGraph : IGraph<CapacityEdge>
{
public IDictionary<string, Node> Nodes { get; } = new Dictionary<string, Node>();
public IDictionary<string, AvatarNode> AvatarNodes { get; } = new Dictionary<string, AvatarNode>();
public IDictionary<string, BalanceNode> BalanceNodes { get; } = new Dictionary<string, BalanceNode>();
public HashSet<CapacityEdge> Edges { get; } = new();

public void AddAvatar(string avatarAddress)
{
avatarAddress = avatarAddress.ToLower();
if (!AvatarNodes.ContainsKey(avatarAddress))
{
AvatarNodes.Add(avatarAddress, new AvatarNode(avatarAddress));
Nodes.Add(avatarAddress, AvatarNodes[avatarAddress]);
}
}

public void AddBalanceNode(string address, string token, BigInteger amount)
{
address = address.ToLower();
token = token.ToLower();

var balanceNode = new BalanceNode(address, token, amount);
balanceNode.Address = address;
BalanceNodes.TryAdd(balanceNode.Address, balanceNode);
Nodes.TryAdd(balanceNode.Address, balanceNode);
}

public void AddCapacityEdge(string from, string to, string token, BigInteger capacity)
{
from = from.ToLower();
to = to.ToLower();
token = token.ToLower();

var edge = new CapacityEdge(from, to, token, capacity);
Edges.Add(edge);

// Optionally, you can manage adjacency lists if needed
if (AvatarNodes.TryGetValue(from, out var node))
{
node.OutEdges.Add(edge);
}
else if (BalanceNodes.TryGetValue(from, out var balanceNode))
{
balanceNode.OutEdges.Add(edge);
}

if (AvatarNodes.TryGetValue(to, out var avatarNode))
{
avatarNode.InEdges.Add(edge);
}
else if (BalanceNodes.TryGetValue(to, out var balanceNode))
{
balanceNode.InEdges.Add(edge);
}
}
}
Loading

0 comments on commit b3e0e09

Please sign in to comment.