Skip to content
Draft
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
24 changes: 24 additions & 0 deletions src/AAB.EBA/Blockchains/Bitcoin/GraphModel/BlockNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,24 @@ public override string GetIdPropertyName()
nameof(BlockMetadata.Weight),
nameof(BlockMetadata.CoinbaseOutputsCount),
nameof(BlockMetadata.MintedBitcoins),
nameof(BlockMetadata.TotalSupply),
nameof(BlockMetadata.TotalSupplyNominal),
nameof(BlockMetadata.RealizedCap),
nameof(BlockMetadata.UnrealizedLoss),
nameof(BlockMetadata.UnrealizedProfit),
nameof(BlockMetadata.MarketCap),
nameof(BlockMetadata.NUL),
nameof(BlockMetadata.NUP),
nameof(BlockMetadata.NUPL),
nameof(BlockMetadata.MVRV),
nameof(BlockMetadata.Thermocap),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.InputCountsStats)),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.OutputCountsStats)),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.InputValuesStats)),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.OutputValuesStats)),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.SpentOutputAgeStats)),
.. DescriptiveStatistics.GetFeaturesName(nameof(BlockMetadata.FeesStats)),
.. OHLCV.GetFeaturesName(),
.. Node.GetFeaturesName()
];
}
Expand All @@ -80,12 +92,24 @@ public override string[] GetFeatures()
BlockMetadata.Weight.ToString(),
BlockMetadata.CoinbaseOutputsCount.ToString(),
BlockMetadata.MintedBitcoins.ToString(),
BlockMetadata.TotalSupply?.ToString() ?? "NA",
BlockMetadata.TotalSupplyNominal?.ToString() ?? "NA",
BlockMetadata.RealizedCap?.ToString() ?? "NA",
BlockMetadata.UnrealizedLoss?.ToString() ?? "NA",
BlockMetadata.UnrealizedProfit?.ToString() ?? "NA",
BlockMetadata.MarketCap?.ToString() ?? "NA",
BlockMetadata.NUL?.ToString() ?? "NA",
BlockMetadata.NUP?.ToString() ?? "NA",
BlockMetadata.NUPL?.ToString() ?? "NA",
BlockMetadata.MVRV?.ToString() ?? "NA",
BlockMetadata.Thermocap?.ToString() ?? "NA",
.. BlockMetadata.InputCountsStats.GetFeatures(),
.. BlockMetadata.OutputCountsStats.GetFeatures(),
.. BlockMetadata.InputValuesStats.GetFeatures(),
.. BlockMetadata.OutputValuesStats.GetFeatures(),
.. BlockMetadata.SpentOutputAgeStats.GetFeatures(),
.. BlockMetadata.FeesStats.GetFeatures(),
.. BlockMetadata.Ohlcv?.GetFeatures() ?? OHLCV.GetEmptyFeatures(),
.. base.GetFeatures()
];
}
Expand Down
22 changes: 22 additions & 0 deletions src/AAB.EBA/Blockchains/Bitcoin/GraphModel/S2TEdge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,26 @@ public S2TEdge(
Generated = generated;
CreationHeight = creationHeight;
}

public static new string[] GetFeaturesName()
{
return
[
.. Edge<ScriptNode, TxNode>.GetFeaturesName(),
nameof(Generated),
nameof(CreationHeight),
nameof(SpentHeight)
];
}

public override double[] GetFeatures()
{
return
[
.. base.GetFeatures(),
Generated ? 1.0 : 0.0,
CreationHeight,
SpentHeight,
];
}
}
20 changes: 20 additions & 0 deletions src/AAB.EBA/Blockchains/Bitcoin/GraphModel/T2SEdge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ public T2SEdge(
SpentHeight = spentHeight;
}

public static new string[] GetFeaturesName()
{
return
[
.. Edge<TxNode, ScriptNode>.GetFeaturesName(),
nameof(CreationHeight),
nameof(SpentHeight)
];
}

public override double[] GetFeatures()
{
return
[
.. base.GetFeatures(),
CreationHeight,
SpentHeight,
];
}

public override int GetHashCode()
{
return HashCode.Combine(base.GetHashCode(), Vout);
Expand Down
15 changes: 0 additions & 15 deletions src/AAB.EBA/CLI/Config/BitcoinGraphSampleOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,6 @@ namespace AAB.EBA.CLI.Config;

public enum GraphTraversal
{
// path search algorithm
// traverse the graph using the given algorithm
// deterministic sampling algorithm
// stops when a criteria is met (e.g., max number of nodes or edges sampled)
// Breadth-first Search
//BFS,

// path search algorithm
// traverse the graph using the given algorithm
// deterministic sampling algorithm
// stops when a criteria is met (e.g., max number of nodes or edges sampled)
// Depth-first Search
//DFS,

// sampling algorithm
// non-deterministic sampling algorithm
Panorama
}
Expand Down
47 changes: 40 additions & 7 deletions src/AAB.EBA/CLI/Config/BitcoinPanoramaSamplingAlgorithmOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,34 @@ public class BitcoinPanoramaSamplingAlgorithmOptions
[JsonPropertyName("queryLimit")]
public int QueryLimit { init; get; } = 1000;

[JsonPropertyName("reductionFactor")]
public double NodeCountReductionFactorByHop { init; get; } = 4.0;
[JsonPropertyName("neighborhoodSamplePercentagePerHop")]
public double NeighborhoodSamplePercentagePerHop { init; get; } = 10.0;

/// <summary>
/// This could be used to exclude high degree nodes,
/// such as mixer nodes or nodes belonging to exchanges;
/// since two nodes connected such nodes cannot necessarily indicate they are related.
/// Sets the percentage of the immediate neighbors of the root node
/// to be included in the sampled community.
/// The value should be between 0 and 100,
/// where 100 means all immediate neighbors of the root node will be included.
/// </summary>
[JsonPropertyName("nodeCountAtRoot")]
public int NodeSamplingCountAtRoot { init; get; } = 100;
[JsonPropertyName("nodeSamplingPercentageAtRoot")]
public double NodeSamplingPercentageAtRoot
{
init
{
if (value < 0 || value > 100)
{
throw new ArgumentOutOfRangeException(
nameof(NodeSamplingPercentageAtRoot),
"Value must be between 0 and 100.");
}
_nodeSamplingPercentageAtOtherHops = value;
}
get
{
return _nodeSamplingPercentageAtOtherHops;
}
}
private double _nodeSamplingPercentageAtOtherHops = 100;

/// <summary>
/// This could be used to exclude high degree nodes,
Expand All @@ -30,11 +48,26 @@ public class BitcoinPanoramaSamplingAlgorithmOptions
[JsonPropertyName("maxOriginalOutDegree")]
public int MaxOriginalOutDegree { init; get; } = 1000;

[JsonPropertyName("maxNeighborsPerNode")]
public int MaxNeighborsPerNode { init; get; } = 100;

/// <summary>
/// This ensures a block context for each transaction is
/// also included in the sampled communities.
/// This can provide more macro context for transactions.
/// </summary>
[JsonPropertyName("includeBlockTxEdges")]
public bool IncludeB2TEdges { init; get; } = false;

/// <summary>
/// As part of the random expansion, coinbase node gets
/// the same selection probability as other nodes;
/// hence, it may or may not be included in the sampled community.
/// If this property is set to true,
/// if the coinbase node is included in the traversed neighborhood,
/// the algorithm will include it in the pseudo-randomly sampled subset
/// of the traversed neighborhood.
/// </summary>
[JsonPropertyName("forceIncludeCoinbaseNode")]
public bool ForceIncludeCoinbaseNode { init; get; } = true;
}
2 changes: 0 additions & 2 deletions src/AAB.EBA/Graph/Bitcoin/BitcoinGraphOrchestrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ public async Task SampleAsync(CancellationToken ct)
ITraversalAlgorithm sampler = _options.Bitcoin.GraphSample.TraversalAlgorithm switch
{
GraphTraversal.Panorama => new Panorama(_options, _db, _logger),
//GraphTraversal.BFS => throw new NotImplementedException(),
//GraphTraversal.DFS => throw new NotImplementedException(),
_ => throw new NotImplementedException("Unsupported graph traversal algorithm."),
};

Expand Down
68 changes: 68 additions & 0 deletions src/AAB.EBA/Graph/Bitcoin/FeaturesSchema.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
namespace AAB.EBA.Graph.Bitcoin;

public class FeaturesSchema
{
public class Metadata
{
[JsonPropertyName("filename")]
public string Filename { get; }

[JsonPropertyName("kind")]
public string Kind { get; }

[JsonPropertyName("features")]
public List<string> Features { get; }

public Metadata(NodeKind kind, List<string> features)
{
Filename = GetElementFilename(kind);
Kind = kind.ToString();
Features = features;
}

public Metadata(EdgeKind kind, List<string> features)
{
Filename = GetElementFilename(kind);
Kind = kind.ToString();
Features = features;
}
}

[JsonPropertyName("nodeTypes")]
public Dictionary<string, Metadata> NodeTypes =>
StaticNodeTypes.ToDictionary(k => k.Key.ToString(), v => v.Value);

[JsonPropertyName("edgeTypes")]
public Dictionary<string, Metadata> EdgeTypes =>
StaticEdgeTypes.ToDictionary(k => k.Key.ToString(), v => v.Value);

public static Dictionary<NodeKind, Metadata> StaticNodeTypes { get; } = new()
{
{ BlockNode.Kind, new Metadata(BlockNode.Kind, ["Index", .. BlockNode.GetFeaturesName()]) },
{ TxNode.Kind, new Metadata(TxNode.Kind, ["Index", .. TxNode.GetFeaturesName()]) },
{ ScriptNode.Kind, new Metadata(ScriptNode.Kind, ["Index", .. ScriptNode.GetFeaturesName()]) },
{ CoinbaseNode.Kind, new Metadata(CoinbaseNode.Kind, ["Index", .. CoinbaseNode.GetFeaturesName()]) }
};

private static readonly string[] SourceAndTarget = ["Source", "Target"];
public static Dictionary<EdgeKind, Metadata> StaticEdgeTypes { get; } = new()
{
{ C2TEdge.Kind, new Metadata(C2TEdge.Kind, [.. SourceAndTarget, .. C2TEdge.GetFeaturesName()]) },
{ B2TEdge.Kind, new Metadata(B2TEdge.Kind, [.. SourceAndTarget, .. B2TEdge.GetFeaturesName()]) },
{ S2TEdge.Kind, new Metadata(S2TEdge.Kind, [.. SourceAndTarget, .. S2TEdge.GetFeaturesName()]) },
{ T2SEdge.Kind, new Metadata(T2SEdge.Kind, [.. SourceAndTarget, .. T2SEdge.GetFeaturesName()]) },
{ T2TEdge.KindFee, new Metadata(T2TEdge.KindFee, [.. SourceAndTarget, .. T2TEdge.GetFeaturesName()]) },
{ T2TEdge.KindTransfers, new Metadata(T2TEdge.KindTransfers, [.. SourceAndTarget, .. T2TEdge.GetFeaturesName()]) },
{ B2BEdge.Kind, new Metadata(B2BEdge.Kind, [.. SourceAndTarget, .. B2BEdge.GetFeaturesName()]) }
};

public static string GetElementFilename(NodeKind nodeKind)
{
return $"node_features_{nodeKind.ToString().ToLower().Replace('-', '_')}.tsv";
}

public static string GetElementFilename(EdgeKind edgeKind)
{
return $"edge_features_{edgeKind.ToString().ToLower().Replace('-', '_')}.tsv";
}
}
Loading
Loading