Skip to content

Commit

Permalink
Csharpify DependencyGraph (WalletWasabi#13356)
Browse files Browse the repository at this point in the history
* Simplify code

* Simplify nodes to discharge selection
  • Loading branch information
lontivero authored Sep 3, 2024
1 parent 6b40b15 commit 7712ac8
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 295 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public class CredentialDependencyTests
public async void AsyncDependencyGraphTraversalAsync()
{
var g = DependencyGraph.ResolveCredentialDependencies(
inputValues: new[] { new[] { 10000L, 1930L }, new[] { 1000L, 1930L } },
outputValues: new[] { new[] { 5000L, 31L }, new[] { 3500L, 31L }, new[] { 2500L, 31L } });
inputValues: new[] { (10000L, 1930L), (1000L, 1930L) },
outputValues: new[] { (5000L, 31L), (3500L, 31L), (2500L, 31L) });

await SimulateAsyncRequestsAsync(g);
}
Expand Down Expand Up @@ -123,8 +123,8 @@ public void ResolveCredentialDependenciesBasic()
{
// Whitebox test of simple case, ensuring that edge values are
// correct
var inputValues = new long[][] { new[] { 3L, 3L } };
var outputValues = new long[][] { new[] { 1L, 1L }, new[] { 1L, 1L }, new[] { 1L, 1L } };
var inputValues = new [] { (3L, 3L)};
var outputValues = new [] { (1L, 1L), (1L, 1L), (1L, 1L)};
var g = DependencyGraph.ResolveCredentialDependencies(inputValues, outputValues);

Assert.Equal(5, g.Vertices.Count);
Expand Down Expand Up @@ -159,8 +159,8 @@ public void ResolveCredentialDependenciesBasic()
[Fact]
public void ResolveCredentialDependenciesNoVsize()
{
var inputValues = new long[][] { new[] { 1L, 0L } };
var outputValues = new long[][] { new[] { 1L, 0L } };
var inputValues = new [] { (1L, 0L)};
var outputValues = new [] { (1L, 0L)};
var g = DependencyGraph.ResolveCredentialDependencies(inputValues, outputValues);

Assert.Equal(2, g.Vertices.Count);
Expand Down Expand Up @@ -262,8 +262,10 @@ public async void ResolveCredentialDependenciesAsync(string inputs, string outpu
// of inputs with various corner cases that must be handled.

// Parse values out of strings because InputData can't contain arrays
var inputValues = inputs.Split(" ").Select(x => x.Split(",").Select(y => long.Parse(y)));
var outputValues = outputs.Split(" ").Select(x => x.Split(",").Select(y => long.Parse(y)));
long[] ParseTupla (string s) => s.Split(",").Select(long.Parse).ToArray();
(long, long)[] ParseTuplas(string s) => s.Split(" ").Select(ParseTupla).Select(x => (x[0], x[1])).ToArray();
var inputValues = ParseTuplas(inputs);
var outputValues = ParseTuplas(outputs);

var g = DependencyGraph.ResolveCredentialDependencies(inputValues, outputValues);

Expand All @@ -279,7 +281,7 @@ public async void ResolveCredentialDependenciesAsync(string inputs, string outpu
await SimulateAsyncRequestsAsync(g);
}

private void AssertResolvedGraphInvariants(DependencyGraph graph, IEnumerable<IEnumerable<long>> inputValues, IEnumerable<IEnumerable<long>> outputValues)
private void AssertResolvedGraphInvariants(DependencyGraph graph, IEnumerable<(long, long)> inputValues, IEnumerable<(long, long)> outputValues)
{
foreach (var credentialType in DependencyGraph.CredentialTypes)
{
Expand Down Expand Up @@ -335,7 +337,7 @@ private void AssertResolvedGraphInvariants(DependencyGraph graph, IEnumerable<IE
}

// Ensure that vsize credentials do not exceed the range proof width
foreach (var edge in graph.EdgeSets[CredentialType.Vsize].Successors.Values.SelectMany(x => x))
foreach (var edge in graph.EdgeSets[(int)CredentialType.Vsize].OutEdges.Values.SelectMany(x => x))
{
Assert.InRange(edge.Value, 0, ProtocolConstants.MaxVsizeCredentialValue);
}
Expand All @@ -345,30 +347,13 @@ private void AssertResolvedGraphInvariants(DependencyGraph graph, IEnumerable<IE
// TODO assert max depth < ceil(log count)?
}

[Fact]
public void ResolveCredentialDependenciesThrows()
{
foreach ((var inputValues, var outputAmounts) in new (long[][], long[][])[]
{
(new[] { new[] { 1L, 0L } }, new[] { new[] { 2L, 0L } }),
(new[] { Array.Empty<long>() }, new[] { new[] { 1L, 0L } }),
(new[] { new[] { 1L } }, new[] { new[] { 1L, 0L } }),
(new[] { new[] { 1L, 1L, 1L, } }, new[] { new[] { 1L, 0L } }),
(new[] { new[] { 1L, 0L } }, new[] { new[] { 1L } }),
(new[] { new[] { 1L, 0L } }, new[] { new[] { 1L, 0L, 0L } }),
})
{
Assert.Throws<ArgumentException>(() => DependencyGraph.ResolveCredentialDependencies(inputValues, outputAmounts));
}
}

[Fact]
public void EdgeConstraints()
{
var g = DependencyGraph.FromValues(new[] { new[] { 11L, 0L }, new[] { 8L, 0L } }, new[] { new[] { 7L, 0L }, new[] { 11L, 0L } });
var g = DependencyGraph.FromValues(new[] { ( 11L, 0L), (8L, 0L) }, new[] { (7L, 0L), (11L, 0L) });

var i = g.Inputs[0];
var o = g.Outputs[0];
var i = g.GetInputs().First();
var o = g.GetOutputs().First();

var edgeSet = g.EdgeSets[0];

Expand Down Expand Up @@ -398,7 +383,7 @@ public void EdgeConstraints()
// max indegree exceeded
Assert.Throws<InvalidOperationException>(() => edgeSet.AddEdge(i, o, 7).AddEdge(i, o, 0).AddEdge(i, o, 0));

var o2 = g.Outputs[1];
var o2 = g.GetOutputs().ElementAt(1);
Assert.Equal(0, edgeSet.AddEdge(i, o2, 7).AddEdge(i, o2, 4).Balance(i));
Assert.Equal(0, edgeSet.AddEdge(i, o2, 7).AddEdge(i, o2, 4).Balance(o2));
Assert.Equal(0, edgeSet.AddEdge(i, o, 7).AddEdge(i, o, 0).AddEdge(i, o2, 4).Balance(i));
Expand All @@ -415,3 +400,10 @@ public void EdgeConstraints()
Assert.Throws<InvalidOperationException>(() => edgeSet.AddEdge(i, o, 7).AddEdge(i, o2, 3));
}
}

public static class CredentialDependencyExtensions
{
public static long Balance(this DependencyGraph me, RequestNode node, CredentialType credentialType) => me.EdgeSets[(int)credentialType].Balance(node);
public static int InDegree(this DependencyGraph me, RequestNode node, CredentialType credentialType) => me.EdgeSets[(int)credentialType].InDegree(node);
public static int OutDegree(this DependencyGraph me, RequestNode node, CredentialType credentialType) => me.EdgeSets[(int)credentialType].OutDegree(node);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public DependencyGraphTaskScheduler(DependencyGraph graph)
{
Graph = graph;
var allInEdges = Enum.GetValues<CredentialType>()
.SelectMany(type => Graph.Reissuances.Concat<RequestNode>(Graph.Outputs)
.SelectMany(node => Graph.EdgeSets[type].InEdges(node)));
.SelectMany(type => Graph.GetReissuances().Concat<RequestNode>(Graph.GetOutputs())
.SelectMany(node => Graph.EdgeSets[(int)type].InEdges[node]));
DependencyTasks = allInEdges.ToDictionary(edge => edge, _ => new TaskCompletionSource<Credential>(TaskCreationOptions.RunContinuationsAsynchronously));
}

Expand Down Expand Up @@ -77,8 +77,8 @@ private async Task CompleteConnectionConfirmationAsync(IEnumerable<AliceClient>

await Task.WhenAll(connectionConfirmationTasks).ConfigureAwait(false);

var amountEdges = Graph.Inputs.SelectMany(node => Graph.OutEdges(node, CredentialType.Amount));
var vsizeEdges = Graph.Inputs.SelectMany(node => Graph.OutEdges(node, CredentialType.Vsize));
var amountEdges = Graph.GetInputs().SelectMany(node => Graph.OutEdges(node, CredentialType.Amount));
var vsizeEdges = Graph.GetInputs().SelectMany(node => Graph.OutEdges(node, CredentialType.Vsize));

// Check if all tasks were finished, otherwise Task.Result will block.
if (!amountEdges.Concat(vsizeEdges).All(edge => DependencyTasks[edge].Task.IsCompletedSuccessfully))
Expand All @@ -105,7 +105,7 @@ public async Task StartReissuancesAsync(IEnumerable<AliceClient> aliceClients, B
using CancellationTokenSource ctsOnError = new();
using CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ctsOnError.Token);

foreach (var node in Graph.Reissuances)
foreach (var node in Graph.GetReissuances())
{
var inputAmountEdgeTasks = Graph.InEdges(node, CredentialType.Amount).Select(edge => DependencyTasks[edge].Task);
var inputVsizeEdgeTasks = Graph.InEdges(node, CredentialType.Vsize).Select(edge => DependencyTasks[edge].Task);
Expand Down Expand Up @@ -141,8 +141,8 @@ public async Task StartReissuancesAsync(IEnumerable<AliceClient> aliceClients, B

await Task.WhenAll(allTasks).ConfigureAwait(false);

var amountEdges = Graph.Outputs.SelectMany(node => Graph.InEdges(node, CredentialType.Amount));
var vsizeEdges = Graph.Outputs.SelectMany(node => Graph.InEdges(node, CredentialType.Vsize));
var amountEdges = Graph.GetOutputs().SelectMany(node => Graph.InEdges(node, CredentialType.Amount));
var vsizeEdges = Graph.GetOutputs().SelectMany(node => Graph.InEdges(node, CredentialType.Vsize));

// Check if all tasks were finished, otherwise Task.Result will block.
if (!amountEdges.Concat(vsizeEdges).All(edge => DependencyTasks[edge].Task.IsCompletedSuccessfully))
Expand All @@ -161,7 +161,7 @@ public async Task<Result<OutputRegistrationError[]>> StartOutputRegistrationsAsy
using CancellationTokenSource ctsOnError = new();
using CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ctsOnError.Token);

var nodes = Graph.Outputs.Select(node =>
var nodes = Graph.GetOutputs().Select(node =>
{
var amountCredsToPresentTasks = Graph.InEdges(node, CredentialType.Amount).Select(edge => DependencyTasks[edge].Task);
var vsizeCredsToPresentTasks = Graph.InEdges(node, CredentialType.Vsize).Select(edge => DependencyTasks[edge].Task);
Expand Down Expand Up @@ -208,9 +208,9 @@ public async Task<Result<OutputRegistrationError[]>> StartOutputRegistrationsAsy

private IEnumerable<(AliceClient AliceClient, InputNode Node)> PairAliceClientAndRequestNodes(IEnumerable<AliceClient> aliceClients, DependencyGraph graph)
{
var inputNodes = graph.Inputs;
var inputNodes = graph.GetInputs();

if (aliceClients.Count() != inputNodes.Count)
if (aliceClients.Count() != inputNodes.Count())
{
throw new InvalidOperationException("Graph vs Alice inputs mismatch");
}
Expand Down

This file was deleted.

Loading

0 comments on commit 7712ac8

Please sign in to comment.