Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/v2 pathfinder #25

Merged
merged 5 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading