Topup functions
This commit is contained in:
@ -2,11 +2,16 @@ namespace NostrStreamer;
|
|||||||
|
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Bitcoin network
|
||||||
|
/// </summary>
|
||||||
|
public string Network { get; init; } = "mainnet";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ingest URL
|
/// Ingest URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Uri RtmpHost { get; init; } = null!;
|
public Uri RtmpHost { get; init; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SRS app name
|
/// SRS app name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -16,7 +21,7 @@ public class Config
|
|||||||
/// SRS api server host
|
/// SRS api server host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Uri SrsApiHost { get; init; } = null!;
|
public Uri SrsApiHost { get; init; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SRS Http server host
|
/// SRS Http server host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -29,4 +34,15 @@ public class Config
|
|||||||
|
|
||||||
public string PrivateKey { get; init; } = null!;
|
public string PrivateKey { get; init; } = null!;
|
||||||
public string[] Relays { get; init; } = Array.Empty<string>();
|
public string[] Relays { get; init; } = Array.Empty<string>();
|
||||||
}
|
|
||||||
|
public LndConfig Lnd { get; init; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LndConfig
|
||||||
|
{
|
||||||
|
public Uri Endpoint { get; init; } = null!;
|
||||||
|
|
||||||
|
public string CertPath { get; init; } = null!;
|
||||||
|
|
||||||
|
public string MacaroonPath { get; init; } = null!;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Nostr.Client.Json;
|
using Nostr.Client.Json;
|
||||||
using Nostr.Client.Messages;
|
using Nostr.Client.Messages;
|
||||||
|
using Nostr.Client.Utils;
|
||||||
using NostrStreamer.ApiModel;
|
using NostrStreamer.ApiModel;
|
||||||
using NostrStreamer.Database;
|
using NostrStreamer.Database;
|
||||||
using NostrStreamer.Services;
|
using NostrStreamer.Services;
|
||||||
@ -18,12 +19,14 @@ public class NostrController : Controller
|
|||||||
private readonly StreamerContext _db;
|
private readonly StreamerContext _db;
|
||||||
private readonly Config _config;
|
private readonly Config _config;
|
||||||
private readonly StreamManager _streamManager;
|
private readonly StreamManager _streamManager;
|
||||||
|
private readonly LndNode _lnd;
|
||||||
|
|
||||||
public NostrController(StreamerContext db, Config config, StreamManager streamManager)
|
public NostrController(StreamerContext db, Config config, StreamManager streamManager, LndNode lnd)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_config = config;
|
_config = config;
|
||||||
_streamManager = streamManager;
|
_streamManager = streamManager;
|
||||||
|
_lnd = lnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("account")]
|
[HttpGet("account")]
|
||||||
@ -63,7 +66,7 @@ public class NostrController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("event")]
|
[HttpPatch("event")]
|
||||||
public async Task<IActionResult> UpdateStreamInfo([FromBody]PatchEvent req)
|
public async Task<IActionResult> UpdateStreamInfo([FromBody] PatchEvent req)
|
||||||
{
|
{
|
||||||
var pubkey = GetPubKey();
|
var pubkey = GetPubKey();
|
||||||
if (string.IsNullOrEmpty(pubkey)) return Unauthorized();
|
if (string.IsNullOrEmpty(pubkey)) return Unauthorized();
|
||||||
@ -71,7 +74,30 @@ public class NostrController : Controller
|
|||||||
await _streamManager.PatchEvent(pubkey, req.Title, req.Summary, req.Image);
|
await _streamManager.PatchEvent(pubkey, req.Title, req.Summary, req.Image);
|
||||||
return Accepted();
|
return Accepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("topup")]
|
||||||
|
public async Task<IActionResult> TopUp([FromQuery] ulong amount)
|
||||||
|
{
|
||||||
|
var pubkey = GetPubKey();
|
||||||
|
if (string.IsNullOrEmpty(pubkey)) return Unauthorized();
|
||||||
|
|
||||||
|
var invoice = await _lnd.AddInvoice(amount * 1000, TimeSpan.FromMinutes(10), $"Top up for {pubkey}");
|
||||||
|
_db.Payments.Add(new()
|
||||||
|
{
|
||||||
|
PubKey = pubkey,
|
||||||
|
Amount = amount,
|
||||||
|
Invoice = invoice.PaymentRequest,
|
||||||
|
PaymentHash = invoice.RHash.ToByteArray().ToHex()
|
||||||
|
});
|
||||||
|
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
pr = invoice.PaymentRequest
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<User?> GetUser()
|
private async Task<User?> GetUser()
|
||||||
{
|
{
|
||||||
var pk = GetPubKey();
|
var pk = GetPubKey();
|
||||||
|
@ -7,11 +7,21 @@ public class PaymentsConfiguration : IEntityTypeConfiguration<Payment>
|
|||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<Payment> builder)
|
public void Configure(EntityTypeBuilder<Payment> builder)
|
||||||
{
|
{
|
||||||
builder.HasKey(a => a.PubKey);
|
builder.HasKey(a => a.PaymentHash);
|
||||||
builder.Property(a => a.Invoice)
|
builder.Property(a => a.Invoice)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
builder.Property(a => a.IsPaid)
|
builder.Property(a => a.IsPaid)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(a => a.Amount)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(a => a.Created)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.HasOne(a => a.User)
|
||||||
|
.WithMany(a => a.Payments)
|
||||||
|
.HasForeignKey(a => a.PubKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,8 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
builder.Property(a => a.Event);
|
builder.Property(a => a.Event);
|
||||||
builder.Property(a => a.Balance)
|
builder.Property(a => a.Balance)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(a => a.Version)
|
||||||
|
.IsRowVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,16 @@ namespace NostrStreamer.Database;
|
|||||||
|
|
||||||
public class Payment
|
public class Payment
|
||||||
{
|
{
|
||||||
|
public string PaymentHash { get; init; } = null!;
|
||||||
|
|
||||||
public string PubKey { get; init; } = null!;
|
public string PubKey { get; init; } = null!;
|
||||||
|
public User User { get; init; } = null!;
|
||||||
|
|
||||||
public string Invoice { get; init; } = null!;
|
public string Invoice { get; init; } = null!;
|
||||||
|
|
||||||
public bool IsPaid { get; init; }
|
public bool IsPaid { get; set; }
|
||||||
|
|
||||||
|
public ulong Amount { get; init; }
|
||||||
|
|
||||||
|
public DateTime Created { get; init; } = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
@ -38,4 +38,11 @@ public class User
|
|||||||
/// Comma seperated tags
|
/// Comma seperated tags
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Tags { get; set; }
|
public string? Tags { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Concurrency token
|
||||||
|
/// </summary>
|
||||||
|
public uint Version { get; set; }
|
||||||
|
|
||||||
|
public List<Payment> Payments { get; init; } = new();
|
||||||
}
|
}
|
||||||
|
113
NostrStreamer/Migrations/20230704123736_PaymentSetup.Designer.cs
generated
Normal file
113
NostrStreamer/Migrations/20230704123736_PaymentSetup.Designer.cs
generated
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using NostrStreamer.Database;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NostrStreamer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(StreamerContext))]
|
||||||
|
[Migration("20230704123736_PaymentSetup")]
|
||||||
|
partial class PaymentSetup
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "7.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.Payment", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("PaymentHash")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasColumnType("numeric(20,0)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Invoice")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPaid")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("PubKey")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("PaymentHash");
|
||||||
|
|
||||||
|
b.HasIndex("PubKey");
|
||||||
|
|
||||||
|
b.ToTable("Payments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("PubKey")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long>("Balance")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Event")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Image")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("StreamKey")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Summary")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tags")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<uint>("Version")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("xid")
|
||||||
|
.HasColumnName("xmin");
|
||||||
|
|
||||||
|
b.HasKey("PubKey");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.Payment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NostrStreamer.Database.User", "User")
|
||||||
|
.WithMany("Payments")
|
||||||
|
.HasForeignKey("PubKey")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Payments");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
NostrStreamer/Migrations/20230704123736_PaymentSetup.cs
Normal file
103
NostrStreamer/Migrations/20230704123736_PaymentSetup.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NostrStreamer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class PaymentSetup : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Payments",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<uint>(
|
||||||
|
name: "xmin",
|
||||||
|
table: "Users",
|
||||||
|
type: "xid",
|
||||||
|
rowVersion: true,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0u);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "PaymentHash",
|
||||||
|
table: "Payments",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<decimal>(
|
||||||
|
name: "Amount",
|
||||||
|
table: "Payments",
|
||||||
|
type: "numeric(20,0)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0m);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "Created",
|
||||||
|
table: "Payments",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Payments",
|
||||||
|
table: "Payments",
|
||||||
|
column: "PaymentHash");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Payments_PubKey",
|
||||||
|
table: "Payments",
|
||||||
|
column: "PubKey");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Payments_Users_PubKey",
|
||||||
|
table: "Payments",
|
||||||
|
column: "PubKey",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "PubKey",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Payments_Users_PubKey",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Payments",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Payments_PubKey",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "xmin",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PaymentHash",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Amount",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Created",
|
||||||
|
table: "Payments");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Payments",
|
||||||
|
table: "Payments",
|
||||||
|
column: "PubKey");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
@ -23,9 +24,15 @@ namespace NostrStreamer.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("NostrStreamer.Database.Payment", b =>
|
modelBuilder.Entity("NostrStreamer.Database.Payment", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("PubKey")
|
b.Property<string>("PaymentHash")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasColumnType("numeric(20,0)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<string>("Invoice")
|
b.Property<string>("Invoice")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@ -33,7 +40,13 @@ namespace NostrStreamer.Migrations
|
|||||||
b.Property<bool>("IsPaid")
|
b.Property<bool>("IsPaid")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
b.HasKey("PubKey");
|
b.Property<string>("PubKey")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("PaymentHash");
|
||||||
|
|
||||||
|
b.HasIndex("PubKey");
|
||||||
|
|
||||||
b.ToTable("Payments");
|
b.ToTable("Payments");
|
||||||
});
|
});
|
||||||
@ -65,10 +78,32 @@ namespace NostrStreamer.Migrations
|
|||||||
b.Property<string>("Title")
|
b.Property<string>("Title")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<uint>("Version")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("xid")
|
||||||
|
.HasColumnName("xmin");
|
||||||
|
|
||||||
b.HasKey("PubKey");
|
b.HasKey("PubKey");
|
||||||
|
|
||||||
b.ToTable("Users");
|
b.ToTable("Users");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.Payment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NostrStreamer.Database.User", "User")
|
||||||
|
.WithMany("Payments")
|
||||||
|
.HasForeignKey("PubKey")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NostrStreamer.Database.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Payments");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="proto/*.proto" GrpcServices="Client" ProtoRoot="proto" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\.dockerignore">
|
<Content Include="..\.dockerignore">
|
||||||
<Link>.dockerignore</Link>
|
<Link>.dockerignore</Link>
|
||||||
@ -23,6 +26,12 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||||
|
<PackageReference Include="Grpc.Net.Client" Version="2.54.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="2.56.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@ -31,5 +40,4 @@
|
|||||||
<PackageReference Include="Nostr.Client" Version="1.4.2" />
|
<PackageReference Include="Nostr.Client" Version="1.4.2" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -49,6 +49,10 @@ internal static class Program
|
|||||||
// streaming services
|
// streaming services
|
||||||
services.AddTransient<StreamManager>();
|
services.AddTransient<StreamManager>();
|
||||||
|
|
||||||
|
// lnd services
|
||||||
|
services.AddSingleton<LndNode>();
|
||||||
|
services.AddHostedService<LndInvoicesStream>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
|
106
NostrStreamer/Services/LndInvoiceStream.cs
Normal file
106
NostrStreamer/Services/LndInvoiceStream.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
using Google.Protobuf;
|
||||||
|
using Grpc.Core;
|
||||||
|
using Lnrpc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Nostr.Client.Utils;
|
||||||
|
using NostrStreamer.Database;
|
||||||
|
|
||||||
|
namespace NostrStreamer.Services;
|
||||||
|
|
||||||
|
public class LndInvoicesStream : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly LndNode _lnd;
|
||||||
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
private readonly ILogger<LndInvoicesStream> _logger;
|
||||||
|
|
||||||
|
public LndInvoicesStream(LndNode lnd, ILogger<LndInvoicesStream> logger, IServiceScopeFactory scopeFactory)
|
||||||
|
{
|
||||||
|
_lnd = lnd;
|
||||||
|
_logger = logger;
|
||||||
|
_scopeFactory = scopeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lastIndex = await GetLastSettleIndex();
|
||||||
|
_logger.LogInformation("Starting stream from add_index {idx}", lastIndex);
|
||||||
|
var stream = _lnd.LightningClient.SubscribeInvoices(new()
|
||||||
|
{
|
||||||
|
SettleIndex = lastIndex
|
||||||
|
});
|
||||||
|
|
||||||
|
await foreach (var msg in stream.ResponseStream.ReadAllAsync(stoppingToken))
|
||||||
|
{
|
||||||
|
if (msg == default) continue;
|
||||||
|
|
||||||
|
var pHash = msg.RHash.ToByteArray().ToHex();
|
||||||
|
_logger.LogInformation("{hash} changed to {state}", pHash, msg.State);
|
||||||
|
if (msg.State is Invoice.Types.InvoiceState.Settled or Invoice.Types.InvoiceState.Canceled)
|
||||||
|
{
|
||||||
|
using var scope = _scopeFactory.CreateScope();
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<StreamerContext>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var payment = await db.Payments
|
||||||
|
.Include(a => a.User)
|
||||||
|
.SingleOrDefaultAsync(a => a.PaymentHash == pHash,
|
||||||
|
cancellationToken: stoppingToken);
|
||||||
|
|
||||||
|
if (payment is {IsPaid: false} && msg.State is Invoice.Types.InvoiceState.Settled)
|
||||||
|
{
|
||||||
|
payment.IsPaid = true;
|
||||||
|
payment.User.Balance += (long)payment.Amount;
|
||||||
|
await db.SaveChangesAsync(stoppingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to process payment {hash}", pHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Subscribe invoices failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ulong> GetLastSettleIndex()
|
||||||
|
{
|
||||||
|
using var scope = _scopeFactory.CreateScope();
|
||||||
|
await using var ctx = scope.ServiceProvider.GetRequiredService<StreamerContext>();
|
||||||
|
var latestUnpaid = await ctx.Payments
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(a => a.IsPaid)
|
||||||
|
.OrderByDescending(a => a.Created)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (latestUnpaid == default)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var invoice = await _lnd.LightningClient.LookupInvoiceAsync(new()
|
||||||
|
{
|
||||||
|
RHash = ByteString.CopyFrom(Convert.FromHexString(latestUnpaid.PaymentHash))
|
||||||
|
});
|
||||||
|
|
||||||
|
return invoice?.SettleIndex ?? 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
NostrStreamer/Services/LndNode.cs
Normal file
177
NostrStreamer/Services/LndNode.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using BTCPayServer.Lightning;
|
||||||
|
using Google.Protobuf;
|
||||||
|
using Grpc.Core;
|
||||||
|
using Grpc.Net.Client;
|
||||||
|
using NBitcoin;
|
||||||
|
using Lnrpc;
|
||||||
|
using Routerrpc;
|
||||||
|
|
||||||
|
namespace NostrStreamer.Services;
|
||||||
|
|
||||||
|
public class LndNode
|
||||||
|
{
|
||||||
|
private readonly Network _network;
|
||||||
|
|
||||||
|
public LndNode(Config config)
|
||||||
|
{
|
||||||
|
_network = Network.GetNetwork(config.Network) ?? Network.RegTest;
|
||||||
|
var channelOptions = new GrpcChannelOptions();
|
||||||
|
ConfigureClient(channelOptions, config.Lnd);
|
||||||
|
|
||||||
|
var channel = GrpcChannel.ForAddress(config.Lnd.Endpoint, channelOptions);
|
||||||
|
LightningClient = new(channel);
|
||||||
|
InvoicesClient = new(channel);
|
||||||
|
RouterClient = new(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lightning.LightningClient LightningClient { get; }
|
||||||
|
|
||||||
|
public Router.RouterClient RouterClient { get; }
|
||||||
|
|
||||||
|
public Invoicesrpc.Invoices.InvoicesClient InvoicesClient { get; }
|
||||||
|
|
||||||
|
public async Task<AddInvoiceResponse> AddInvoice(ulong mSats, TimeSpan? expire = null, string? memo = null,
|
||||||
|
string? descriptionHash = null)
|
||||||
|
{
|
||||||
|
var req = new Invoice()
|
||||||
|
{
|
||||||
|
ValueMsat = (long)mSats,
|
||||||
|
Expiry = (long)(expire ?? TimeSpan.FromHours(1)).TotalSeconds
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(descriptionHash))
|
||||||
|
{
|
||||||
|
req.DescriptionHash = ByteString.CopyFrom(Convert.FromHexString(descriptionHash));
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(memo))
|
||||||
|
{
|
||||||
|
req.Memo = memo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await LightningClient.AddInvoiceAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Payment?> GetPayment(string paymentHash)
|
||||||
|
{
|
||||||
|
using var trackPayment = RouterClient.TrackPaymentV2(new()
|
||||||
|
{
|
||||||
|
NoInflightUpdates = true,
|
||||||
|
PaymentHash = ByteString.CopyFrom(Convert.FromHexString(paymentHash))
|
||||||
|
});
|
||||||
|
|
||||||
|
if (await trackPayment.ResponseStream.MoveNext())
|
||||||
|
{
|
||||||
|
return trackPayment.ResponseStream.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Payment?> SendPayment(string paymentRequest, long feeLimit = 0)
|
||||||
|
{
|
||||||
|
using var payment = RouterClient.SendPaymentV2(new()
|
||||||
|
{
|
||||||
|
PaymentRequest = paymentRequest,
|
||||||
|
TimeoutSeconds = 120,
|
||||||
|
FeeLimitMsat = feeLimit,
|
||||||
|
NoInflightUpdates = true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (await payment.ResponseStream.MoveNext())
|
||||||
|
{
|
||||||
|
return payment.ResponseStream.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GenerateAddress()
|
||||||
|
{
|
||||||
|
var rsp = await LightningClient.NewAddressAsync(new());
|
||||||
|
return rsp.Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Invoicesrpc.AddHoldInvoiceResp?> WrapInvoice(string pr, ulong fee)
|
||||||
|
{
|
||||||
|
const double minExpireMins = 8;
|
||||||
|
const long minCltvDelta = 10;
|
||||||
|
const long maxCltvDelta = 2016;
|
||||||
|
var now = DateTimeOffset.UtcNow;
|
||||||
|
var decoded = BOLT11PaymentRequest.Parse(pr, _network);
|
||||||
|
var newAmount = decoded.MinimumAmount.MilliSatoshi + (long)fee;
|
||||||
|
|
||||||
|
if (decoded.ExpiryDate <= now)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invoice already expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((decoded.ExpiryDate - now).TotalMinutes < minExpireMins)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Expiry too soon");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoded.MinFinalCLTVExpiry < minCltvDelta)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("CLTV delta too low");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoded.MinFinalCLTVExpiry > maxCltvDelta)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("CLTV delta too high");
|
||||||
|
}
|
||||||
|
|
||||||
|
var knownBits = new[] {8, 9, 14, 15, 16, 17};
|
||||||
|
for (var x = 0; x < 64; x++)
|
||||||
|
{
|
||||||
|
var n = 1L << x;
|
||||||
|
var fb = (FeatureBits)n;
|
||||||
|
if (decoded.FeatureBits.HasFlag(fb) && (!knownBits.Contains(x) || !Enum.IsDefined(fb)))
|
||||||
|
{
|
||||||
|
throw new InvalidCastException("Unknown feature bit set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = new Invoicesrpc.AddHoldInvoiceRequest
|
||||||
|
{
|
||||||
|
CltvExpiry = (ulong)decoded.MinFinalCLTVExpiry + 18,
|
||||||
|
Expiry = (long)(decoded.ExpiryDate - DateTimeOffset.UtcNow).TotalSeconds,
|
||||||
|
Hash = ByteString.CopyFrom(decoded.PaymentHash!.ToBytes(false)),
|
||||||
|
ValueMsat = newAmount
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(decoded.ShortDescription))
|
||||||
|
{
|
||||||
|
req.Memo = decoded.ShortDescription;
|
||||||
|
}
|
||||||
|
else if (decoded.DescriptionHash != default)
|
||||||
|
{
|
||||||
|
req.DescriptionHash = ByteString.CopyFrom(decoded.DescriptionHash.ToBytes(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await InvoicesClient.AddHoldInvoiceAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureClient(GrpcChannelOptions opt, LndConfig conf)
|
||||||
|
{
|
||||||
|
var macaroon = File.ReadAllBytes(Environment.ExpandEnvironmentVariables(conf.MacaroonPath));
|
||||||
|
var cert = File.ReadAllBytes(Environment.ExpandEnvironmentVariables(conf.CertPath));
|
||||||
|
|
||||||
|
var asyncInterceptor = new AsyncAuthInterceptor((_, meta) =>
|
||||||
|
{
|
||||||
|
meta.Add("macaroon", Convert.ToHexString(macaroon));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
var httpHandler = new HttpClientHandler();
|
||||||
|
httpHandler.ServerCertificateCustomValidationCallback = (_, certificate2, _, _) =>
|
||||||
|
{
|
||||||
|
var serverCert = new X509Certificate2(cert);
|
||||||
|
return certificate2!.Thumbprint == serverCert.Thumbprint;
|
||||||
|
};
|
||||||
|
|
||||||
|
opt.HttpHandler = httpHandler;
|
||||||
|
opt.Credentials = ChannelCredentials.Create(ChannelCredentials.SecureSsl,
|
||||||
|
CallCredentials.FromInterceptor(asyncInterceptor));
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,11 @@
|
|||||||
"DataHost": "http://localhost:5295/api/playlist/",
|
"DataHost": "http://localhost:5295/api/playlist/",
|
||||||
"App": "test",
|
"App": "test",
|
||||||
"Relays": ["ws://localhost:8081"],
|
"Relays": ["ws://localhost:8081"],
|
||||||
"PrivateKey": "nsec1yqtv8s8y9krh6l8pwp09lk2jkulr9e0klu95tlk7dgus9cklr4ssdv3d88"
|
"PrivateKey": "nsec1yqtv8s8y9krh6l8pwp09lk2jkulr9e0klu95tlk7dgus9cklr4ssdv3d88",
|
||||||
|
"Lnd": {
|
||||||
|
"Endpoint": "https://localhost:10002",
|
||||||
|
"CertPath": "/Users/kieran/.polar/networks/1/volumes/lnd/bob/tls.cert",
|
||||||
|
"MacaroonPath": "/Users/kieran/.polar/networks/1/volumes/lnd/bob/data/chain/bitcoin/regtest/admin.macaroon"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
175
NostrStreamer/proto/invoices.proto
Normal file
175
NostrStreamer/proto/invoices.proto
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "lightning.proto";
|
||||||
|
|
||||||
|
package invoicesrpc;
|
||||||
|
|
||||||
|
option go_package = "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc";
|
||||||
|
|
||||||
|
// Invoices is a service that can be used to create, accept, settle and cancel
|
||||||
|
// invoices.
|
||||||
|
service Invoices {
|
||||||
|
/*
|
||||||
|
SubscribeSingleInvoice returns a uni-directional stream (server -> client)
|
||||||
|
to notify the client of state transitions of the specified invoice.
|
||||||
|
Initially the current invoice state is always sent out.
|
||||||
|
*/
|
||||||
|
rpc SubscribeSingleInvoice (SubscribeSingleInvoiceRequest)
|
||||||
|
returns (stream lnrpc.Invoice);
|
||||||
|
|
||||||
|
/*
|
||||||
|
CancelInvoice cancels a currently open invoice. If the invoice is already
|
||||||
|
canceled, this call will succeed. If the invoice is already settled, it will
|
||||||
|
fail.
|
||||||
|
*/
|
||||||
|
rpc CancelInvoice (CancelInvoiceMsg) returns (CancelInvoiceResp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
AddHoldInvoice creates a hold invoice. It ties the invoice to the hash
|
||||||
|
supplied in the request.
|
||||||
|
*/
|
||||||
|
rpc AddHoldInvoice (AddHoldInvoiceRequest) returns (AddHoldInvoiceResp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
SettleInvoice settles an accepted invoice. If the invoice is already
|
||||||
|
settled, this call will succeed.
|
||||||
|
*/
|
||||||
|
rpc SettleInvoice (SettleInvoiceMsg) returns (SettleInvoiceResp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
LookupInvoiceV2 attempts to look up at invoice. An invoice can be refrenced
|
||||||
|
using either its payment hash, payment address, or set ID.
|
||||||
|
*/
|
||||||
|
rpc LookupInvoiceV2 (LookupInvoiceMsg) returns (lnrpc.Invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
message CancelInvoiceMsg {
|
||||||
|
// Hash corresponding to the (hold) invoice to cancel. When using
|
||||||
|
// REST, this field must be encoded as base64.
|
||||||
|
bytes payment_hash = 1;
|
||||||
|
}
|
||||||
|
message CancelInvoiceResp {
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddHoldInvoiceRequest {
|
||||||
|
/*
|
||||||
|
An optional memo to attach along with the invoice. Used for record keeping
|
||||||
|
purposes for the invoice's creator, and will also be set in the description
|
||||||
|
field of the encoded payment request if the description_hash field is not
|
||||||
|
being used.
|
||||||
|
*/
|
||||||
|
string memo = 1;
|
||||||
|
|
||||||
|
// The hash of the preimage
|
||||||
|
bytes hash = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The value of this invoice in satoshis
|
||||||
|
|
||||||
|
The fields value and value_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 value = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The value of this invoice in millisatoshis
|
||||||
|
|
||||||
|
The fields value and value_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 value_msat = 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hash (SHA-256) of a description of the payment. Used if the description of
|
||||||
|
payment (memo) is too long to naturally fit within the description field
|
||||||
|
of an encoded payment request.
|
||||||
|
*/
|
||||||
|
bytes description_hash = 4;
|
||||||
|
|
||||||
|
// Payment request expiry time in seconds. Default is 86400 (24 hours).
|
||||||
|
int64 expiry = 5;
|
||||||
|
|
||||||
|
// Fallback on-chain address.
|
||||||
|
string fallback_addr = 6;
|
||||||
|
|
||||||
|
// Delta to use for the time-lock of the CLTV extended to the final hop.
|
||||||
|
uint64 cltv_expiry = 7;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Route hints that can each be individually used to assist in reaching the
|
||||||
|
invoice's destination.
|
||||||
|
*/
|
||||||
|
repeated lnrpc.RouteHint route_hints = 8;
|
||||||
|
|
||||||
|
// Whether this invoice should include routing hints for private channels.
|
||||||
|
bool private = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddHoldInvoiceResp {
|
||||||
|
/*
|
||||||
|
A bare-bones invoice for a payment within the Lightning Network. With the
|
||||||
|
details of the invoice, the sender has all the data necessary to send a
|
||||||
|
payment to the recipient.
|
||||||
|
*/
|
||||||
|
string payment_request = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The "add" index of this invoice. Each newly created invoice will increment
|
||||||
|
this index making it monotonically increasing. Callers to the
|
||||||
|
SubscribeInvoices call can use this to instantly get notified of all added
|
||||||
|
invoices with an add_index greater than this one.
|
||||||
|
*/
|
||||||
|
uint64 add_index = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The payment address of the generated invoice. This value should be used
|
||||||
|
in all payments for this invoice as we require it for end to end
|
||||||
|
security.
|
||||||
|
*/
|
||||||
|
bytes payment_addr = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SettleInvoiceMsg {
|
||||||
|
// Externally discovered pre-image that should be used to settle the hold
|
||||||
|
// invoice.
|
||||||
|
bytes preimage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SettleInvoiceResp {
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribeSingleInvoiceRequest {
|
||||||
|
reserved 1;
|
||||||
|
|
||||||
|
// Hash corresponding to the (hold) invoice to subscribe to. When using
|
||||||
|
// REST, this field must be encoded as base64url.
|
||||||
|
bytes r_hash = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LookupModifier {
|
||||||
|
// The default look up modifier, no look up behavior is changed.
|
||||||
|
DEFAULT = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Indicates that when a look up is done based on a set_id, then only that set
|
||||||
|
of HTLCs related to that set ID should be returned.
|
||||||
|
*/
|
||||||
|
HTLC_SET_ONLY = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Indicates that when a look up is done using a payment_addr, then no HTLCs
|
||||||
|
related to the payment_addr should be returned. This is useful when one
|
||||||
|
wants to be able to obtain the set of associated setIDs with a given
|
||||||
|
invoice, then look up the sub-invoices "projected" by that set ID.
|
||||||
|
*/
|
||||||
|
HTLC_SET_BLANK = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LookupInvoiceMsg {
|
||||||
|
oneof invoice_ref {
|
||||||
|
// When using REST, this field must be encoded as base64.
|
||||||
|
bytes payment_hash = 1;
|
||||||
|
bytes payment_addr = 2;
|
||||||
|
bytes set_id = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupModifier lookup_modifier = 4;
|
||||||
|
}
|
4760
NostrStreamer/proto/lightning.proto
Normal file
4760
NostrStreamer/proto/lightning.proto
Normal file
File diff suppressed because it is too large
Load Diff
952
NostrStreamer/proto/routerrpc.proto
Normal file
952
NostrStreamer/proto/routerrpc.proto
Normal file
@ -0,0 +1,952 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "lightning.proto";
|
||||||
|
|
||||||
|
package routerrpc;
|
||||||
|
|
||||||
|
option go_package = "github.com/lightningnetwork/lnd/lnrpc/routerrpc";
|
||||||
|
|
||||||
|
// Router is a service that offers advanced interaction with the router
|
||||||
|
// subsystem of the daemon.
|
||||||
|
service Router {
|
||||||
|
/*
|
||||||
|
SendPaymentV2 attempts to route a payment described by the passed
|
||||||
|
PaymentRequest to the final destination. The call returns a stream of
|
||||||
|
payment updates.
|
||||||
|
*/
|
||||||
|
rpc SendPaymentV2 (SendPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
TrackPaymentV2 returns an update stream for the payment identified by the
|
||||||
|
payment hash.
|
||||||
|
*/
|
||||||
|
rpc TrackPaymentV2 (TrackPaymentRequest) returns (stream lnrpc.Payment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
TrackPayments returns an update stream for every payment that is not in a
|
||||||
|
terminal state. Note that if payments are in-flight while starting a new
|
||||||
|
subscription, the start of the payment stream could produce out-of-order
|
||||||
|
and/or duplicate events. In order to get updates for every in-flight
|
||||||
|
payment attempt make sure to subscribe to this method before initiating any
|
||||||
|
payments.
|
||||||
|
*/
|
||||||
|
rpc TrackPayments (TrackPaymentsRequest) returns (stream lnrpc.Payment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
||||||
|
may cost to send an HTLC to the target end destination.
|
||||||
|
*/
|
||||||
|
rpc EstimateRouteFee (RouteFeeRequest) returns (RouteFeeResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
|
||||||
|
the specified route. This method differs from SendPayment in that it
|
||||||
|
allows users to specify a full route manually. This can be used for
|
||||||
|
things like rebalancing, and atomic swaps. It differs from the newer
|
||||||
|
SendToRouteV2 in that it doesn't return the full HTLC information.
|
||||||
|
*/
|
||||||
|
rpc SendToRoute (SendToRouteRequest) returns (SendToRouteResponse) {
|
||||||
|
option deprecated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SendToRouteV2 attempts to make a payment via the specified route. This
|
||||||
|
method differs from SendPayment in that it allows users to specify a full
|
||||||
|
route manually. This can be used for things like rebalancing, and atomic
|
||||||
|
swaps.
|
||||||
|
*/
|
||||||
|
rpc SendToRouteV2 (SendToRouteRequest) returns (lnrpc.HTLCAttempt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
ResetMissionControl clears all mission control state and starts with a clean
|
||||||
|
slate.
|
||||||
|
*/
|
||||||
|
rpc ResetMissionControl (ResetMissionControlRequest)
|
||||||
|
returns (ResetMissionControlResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
QueryMissionControl exposes the internal mission control state to callers.
|
||||||
|
It is a development feature.
|
||||||
|
*/
|
||||||
|
rpc QueryMissionControl (QueryMissionControlRequest)
|
||||||
|
returns (QueryMissionControlResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
XImportMissionControl is an experimental API that imports the state provided
|
||||||
|
to the internal mission control's state, using all results which are more
|
||||||
|
recent than our existing values. These values will only be imported
|
||||||
|
in-memory, and will not be persisted across restarts.
|
||||||
|
*/
|
||||||
|
rpc XImportMissionControl (XImportMissionControlRequest)
|
||||||
|
returns (XImportMissionControlResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetMissionControlConfig returns mission control's current config.
|
||||||
|
*/
|
||||||
|
rpc GetMissionControlConfig (GetMissionControlConfigRequest)
|
||||||
|
returns (GetMissionControlConfigResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
SetMissionControlConfig will set mission control's config, if the config
|
||||||
|
provided is valid.
|
||||||
|
*/
|
||||||
|
rpc SetMissionControlConfig (SetMissionControlConfigRequest)
|
||||||
|
returns (SetMissionControlConfigResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated. QueryProbability returns the current success probability
|
||||||
|
estimate for a given node pair and amount. The call returns a zero success
|
||||||
|
probability if no channel is available or if the amount violates min/max
|
||||||
|
HTLC constraints.
|
||||||
|
*/
|
||||||
|
rpc QueryProbability (QueryProbabilityRequest)
|
||||||
|
returns (QueryProbabilityResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
BuildRoute builds a fully specified route based on a list of hop public
|
||||||
|
keys. It retrieves the relevant channel policies from the graph in order to
|
||||||
|
calculate the correct fees and time locks.
|
||||||
|
*/
|
||||||
|
rpc BuildRoute (BuildRouteRequest) returns (BuildRouteResponse);
|
||||||
|
|
||||||
|
/*
|
||||||
|
SubscribeHtlcEvents creates a uni-directional stream from the server to
|
||||||
|
the client which delivers a stream of htlc events.
|
||||||
|
*/
|
||||||
|
rpc SubscribeHtlcEvents (SubscribeHtlcEventsRequest)
|
||||||
|
returns (stream HtlcEvent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
|
||||||
|
described by the passed PaymentRequest to the final destination. The call
|
||||||
|
returns a stream of payment status updates.
|
||||||
|
*/
|
||||||
|
rpc SendPayment (SendPaymentRequest) returns (stream PaymentStatus) {
|
||||||
|
option deprecated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
|
||||||
|
the payment identified by the payment hash.
|
||||||
|
*/
|
||||||
|
rpc TrackPayment (TrackPaymentRequest) returns (stream PaymentStatus) {
|
||||||
|
option deprecated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
HtlcInterceptor dispatches a bi-directional streaming RPC in which
|
||||||
|
Forwarded HTLC requests are sent to the client and the client responds with
|
||||||
|
a boolean that tells LND if this htlc should be intercepted.
|
||||||
|
In case of interception, the htlc can be either settled, cancelled or
|
||||||
|
resumed later by using the ResolveHoldForward endpoint.
|
||||||
|
*/
|
||||||
|
rpc HtlcInterceptor (stream ForwardHtlcInterceptResponse)
|
||||||
|
returns (stream ForwardHtlcInterceptRequest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
UpdateChanStatus attempts to manually set the state of a channel
|
||||||
|
(enabled, disabled, or auto). A manual "disable" request will cause the
|
||||||
|
channel to stay disabled until a subsequent manual request of either
|
||||||
|
"enable" or "auto".
|
||||||
|
*/
|
||||||
|
rpc UpdateChanStatus (UpdateChanStatusRequest)
|
||||||
|
returns (UpdateChanStatusResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendPaymentRequest {
|
||||||
|
// The identity pubkey of the payment recipient
|
||||||
|
bytes dest = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Number of satoshis to send.
|
||||||
|
|
||||||
|
The fields amt and amt_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 amt = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Number of millisatoshis to send.
|
||||||
|
|
||||||
|
The fields amt and amt_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 amt_msat = 12;
|
||||||
|
|
||||||
|
// The hash to use within the payment's HTLC
|
||||||
|
bytes payment_hash = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The CLTV delta from the current height that should be used to set the
|
||||||
|
timelock for the final hop.
|
||||||
|
*/
|
||||||
|
int32 final_cltv_delta = 4;
|
||||||
|
|
||||||
|
// An optional payment addr to be included within the last hop of the route.
|
||||||
|
bytes payment_addr = 20;
|
||||||
|
|
||||||
|
/*
|
||||||
|
A bare-bones invoice for a payment within the Lightning Network. With the
|
||||||
|
details of the invoice, the sender has all the data necessary to send a
|
||||||
|
payment to the recipient. The amount in the payment request may be zero. In
|
||||||
|
that case it is required to set the amt field as well. If no payment request
|
||||||
|
is specified, the following fields are required: dest, amt and payment_hash.
|
||||||
|
*/
|
||||||
|
string payment_request = 5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An upper limit on the amount of time we should spend when attempting to
|
||||||
|
fulfill the payment. This is expressed in seconds. If we cannot make a
|
||||||
|
successful payment within this time frame, an error will be returned.
|
||||||
|
This field must be non-zero.
|
||||||
|
*/
|
||||||
|
int32 timeout_seconds = 6;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximum number of satoshis that will be paid as a fee of the payment.
|
||||||
|
If this field is left to the default value of 0, only zero-fee routes will
|
||||||
|
be considered. This usually means single hop routes connecting directly to
|
||||||
|
the destination. To send the payment without a fee limit, use max int here.
|
||||||
|
|
||||||
|
The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 fee_limit_sat = 7;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximum number of millisatoshis that will be paid as a fee of the
|
||||||
|
payment. If this field is left to the default value of 0, only zero-fee
|
||||||
|
routes will be considered. This usually means single hop routes connecting
|
||||||
|
directly to the destination. To send the payment without a fee limit, use
|
||||||
|
max int here.
|
||||||
|
|
||||||
|
The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
|
||||||
|
*/
|
||||||
|
int64 fee_limit_msat = 13;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use outgoing_chan_ids. The channel id of the channel that must
|
||||||
|
be taken to the first hop. If zero, any channel may be used (unless
|
||||||
|
outgoing_chan_ids are set).
|
||||||
|
*/
|
||||||
|
uint64 outgoing_chan_id = 8 [jstype = JS_STRING, deprecated = true];
|
||||||
|
|
||||||
|
/*
|
||||||
|
The channel ids of the channels are allowed for the first hop. If empty,
|
||||||
|
any channel may be used.
|
||||||
|
*/
|
||||||
|
repeated uint64 outgoing_chan_ids = 19;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The pubkey of the last hop of the route. If empty, any hop may be used.
|
||||||
|
*/
|
||||||
|
bytes last_hop_pubkey = 14;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An optional maximum total time lock for the route. This should not exceed
|
||||||
|
lnd's `--max-cltv-expiry` setting. If zero, then the value of
|
||||||
|
`--max-cltv-expiry` is enforced.
|
||||||
|
*/
|
||||||
|
int32 cltv_limit = 9;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optional route hints to reach the destination through private channels.
|
||||||
|
*/
|
||||||
|
repeated lnrpc.RouteHint route_hints = 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An optional field that can be used to pass an arbitrary set of TLV records
|
||||||
|
to a peer which understands the new records. This can be used to pass
|
||||||
|
application specific data during the payment attempt. Record types are
|
||||||
|
required to be in the custom range >= 65536. When using REST, the values
|
||||||
|
must be encoded as base64.
|
||||||
|
*/
|
||||||
|
map<uint64, bytes> dest_custom_records = 11;
|
||||||
|
|
||||||
|
// If set, circular payments to self are permitted.
|
||||||
|
bool allow_self_payment = 15;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Features assumed to be supported by the final node. All transitive feature
|
||||||
|
dependencies must also be set properly. For a given feature bit pair, either
|
||||||
|
optional or remote may be set, but not both. If this field is nil or empty,
|
||||||
|
the router will try to load destination features from the graph as a
|
||||||
|
fallback.
|
||||||
|
*/
|
||||||
|
repeated lnrpc.FeatureBit dest_features = 16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximum number of partial payments that may be use to complete the full
|
||||||
|
amount.
|
||||||
|
*/
|
||||||
|
uint32 max_parts = 17;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If set, only the final payment update is streamed back. Intermediate updates
|
||||||
|
that show which htlcs are still in flight are suppressed.
|
||||||
|
*/
|
||||||
|
bool no_inflight_updates = 18;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The largest payment split that should be attempted when making a payment if
|
||||||
|
splitting is necessary. Setting this value will effectively cause lnd to
|
||||||
|
split more aggressively, vs only when it thinks it needs to. Note that this
|
||||||
|
value is in milli-satoshis.
|
||||||
|
*/
|
||||||
|
uint64 max_shard_size_msat = 21;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If set, an AMP-payment will be attempted.
|
||||||
|
*/
|
||||||
|
bool amp = 22;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The time preference for this payment. Set to -1 to optimize for fees
|
||||||
|
only, to 1 to optimize for reliability only or a value inbetween for a mix.
|
||||||
|
*/
|
||||||
|
double time_pref = 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TrackPaymentRequest {
|
||||||
|
// The hash of the payment to look up.
|
||||||
|
bytes payment_hash = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If set, only the final payment update is streamed back. Intermediate updates
|
||||||
|
that show which htlcs are still in flight are suppressed.
|
||||||
|
*/
|
||||||
|
bool no_inflight_updates = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TrackPaymentsRequest {
|
||||||
|
/*
|
||||||
|
If set, only the final payment updates are streamed back. Intermediate
|
||||||
|
updates that show which htlcs are still in flight are suppressed.
|
||||||
|
*/
|
||||||
|
bool no_inflight_updates = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RouteFeeRequest {
|
||||||
|
/*
|
||||||
|
The destination once wishes to obtain a routing fee quote to.
|
||||||
|
*/
|
||||||
|
bytes dest = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The amount one wishes to send to the target destination.
|
||||||
|
*/
|
||||||
|
int64 amt_sat = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RouteFeeResponse {
|
||||||
|
/*
|
||||||
|
A lower bound of the estimated fee to the target destination within the
|
||||||
|
network, expressed in milli-satoshis.
|
||||||
|
*/
|
||||||
|
int64 routing_fee_msat = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An estimate of the worst case time delay that can occur. Note that callers
|
||||||
|
will still need to factor in the final CLTV delta of the last hop into this
|
||||||
|
value.
|
||||||
|
*/
|
||||||
|
int64 time_lock_delay = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendToRouteRequest {
|
||||||
|
// The payment hash to use for the HTLC.
|
||||||
|
bytes payment_hash = 1;
|
||||||
|
|
||||||
|
// Route that should be used to attempt to complete the payment.
|
||||||
|
lnrpc.Route route = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Whether the payment should be marked as failed when a temporary error is
|
||||||
|
returned from the given route. Set it to true so the payment won't be
|
||||||
|
failed unless a terminal error is occurred, such as payment timeout, no
|
||||||
|
routes, incorrect payment details, or insufficient funds.
|
||||||
|
*/
|
||||||
|
bool skip_temp_err = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendToRouteResponse {
|
||||||
|
// The preimage obtained by making the payment.
|
||||||
|
bytes preimage = 1;
|
||||||
|
|
||||||
|
// The failure message in case the payment failed.
|
||||||
|
lnrpc.Failure failure = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ResetMissionControlRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message ResetMissionControlResponse {
|
||||||
|
}
|
||||||
|
|
||||||
|
message QueryMissionControlRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryMissionControlResponse contains mission control state.
|
||||||
|
message QueryMissionControlResponse {
|
||||||
|
reserved 1;
|
||||||
|
|
||||||
|
// Node pair-level mission control state.
|
||||||
|
repeated PairHistory pairs = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message XImportMissionControlRequest {
|
||||||
|
// Node pair-level mission control state to be imported.
|
||||||
|
repeated PairHistory pairs = 1;
|
||||||
|
|
||||||
|
// Whether to force override MC pair history. Note that even with force
|
||||||
|
// override the failure pair is imported before the success pair and both
|
||||||
|
// still clamp existing failure/success amounts.
|
||||||
|
bool force = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message XImportMissionControlResponse {
|
||||||
|
}
|
||||||
|
|
||||||
|
// PairHistory contains the mission control state for a particular node pair.
|
||||||
|
message PairHistory {
|
||||||
|
// The source node pubkey of the pair.
|
||||||
|
bytes node_from = 1;
|
||||||
|
|
||||||
|
// The destination node pubkey of the pair.
|
||||||
|
bytes node_to = 2;
|
||||||
|
|
||||||
|
reserved 3, 4, 5, 6;
|
||||||
|
|
||||||
|
PairData history = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PairData {
|
||||||
|
// Time of last failure.
|
||||||
|
int64 fail_time = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lowest amount that failed to forward rounded to whole sats. This may be
|
||||||
|
set to zero if the failure is independent of amount.
|
||||||
|
*/
|
||||||
|
int64 fail_amt_sat = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lowest amount that failed to forward in millisats. This may be
|
||||||
|
set to zero if the failure is independent of amount.
|
||||||
|
*/
|
||||||
|
int64 fail_amt_msat = 4;
|
||||||
|
|
||||||
|
reserved 3;
|
||||||
|
|
||||||
|
// Time of last success.
|
||||||
|
int64 success_time = 5;
|
||||||
|
|
||||||
|
// Highest amount that we could successfully forward rounded to whole sats.
|
||||||
|
int64 success_amt_sat = 6;
|
||||||
|
|
||||||
|
// Highest amount that we could successfully forward in millisats.
|
||||||
|
int64 success_amt_msat = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetMissionControlConfigRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetMissionControlConfigResponse {
|
||||||
|
/*
|
||||||
|
Mission control's currently active config.
|
||||||
|
*/
|
||||||
|
MissionControlConfig config = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetMissionControlConfigRequest {
|
||||||
|
/*
|
||||||
|
The config to set for mission control. Note that all values *must* be set,
|
||||||
|
because the full config will be applied.
|
||||||
|
*/
|
||||||
|
MissionControlConfig config = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetMissionControlConfigResponse {
|
||||||
|
}
|
||||||
|
|
||||||
|
message MissionControlConfig {
|
||||||
|
/*
|
||||||
|
Deprecated, use AprioriParameters. The amount of time mission control will
|
||||||
|
take to restore a penalized node or channel back to 50% success probability,
|
||||||
|
expressed in seconds. Setting this value to a higher value will penalize
|
||||||
|
failures for longer, making mission control less likely to route through
|
||||||
|
nodes and channels that we have previously recorded failures for.
|
||||||
|
*/
|
||||||
|
uint64 half_life_seconds = 1 [deprecated = true];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use AprioriParameters. The probability of success mission
|
||||||
|
control should assign to hop in a route where it has no other information
|
||||||
|
available. Higher values will make mission control more willing to try hops
|
||||||
|
that we have no information about, lower values will discourage trying these
|
||||||
|
hops.
|
||||||
|
*/
|
||||||
|
float hop_probability = 2 [deprecated = true];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deprecated, use AprioriParameters. The importance that mission control
|
||||||
|
should place on historical results, expressed as a value in [0;1]. Setting
|
||||||
|
this value to 1 will ignore all historical payments and just use the hop
|
||||||
|
probability to assess the probability of success for each hop. A zero value
|
||||||
|
ignores hop probability completely and relies entirely on historical
|
||||||
|
results, unless none are available.
|
||||||
|
*/
|
||||||
|
float weight = 3 [deprecated = true];
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximum number of payment results that mission control will store.
|
||||||
|
*/
|
||||||
|
uint32 maximum_payment_results = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The minimum time that must have passed since the previously recorded failure
|
||||||
|
before we raise the failure amount.
|
||||||
|
*/
|
||||||
|
uint64 minimum_failure_relax_interval = 5;
|
||||||
|
|
||||||
|
enum ProbabilityModel {
|
||||||
|
APRIORI = 0;
|
||||||
|
BIMODAL = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ProbabilityModel defines which probability estimator should be used in
|
||||||
|
pathfinding. Note that the bimodal estimator is experimental.
|
||||||
|
*/
|
||||||
|
ProbabilityModel model = 6;
|
||||||
|
|
||||||
|
/*
|
||||||
|
EstimatorConfig is populated dependent on the estimator type.
|
||||||
|
*/
|
||||||
|
oneof EstimatorConfig {
|
||||||
|
AprioriParameters apriori = 7;
|
||||||
|
BimodalParameters bimodal = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message BimodalParameters {
|
||||||
|
/*
|
||||||
|
NodeWeight defines how strongly other previous forwardings on channels of a
|
||||||
|
router should be taken into account when computing a channel's probability
|
||||||
|
to route. The allowed values are in the range [0, 1], where a value of 0
|
||||||
|
means that only direct information about a channel is taken into account.
|
||||||
|
*/
|
||||||
|
double node_weight = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ScaleMsat describes the scale over which channels statistically have some
|
||||||
|
liquidity left. The value determines how quickly the bimodal distribution
|
||||||
|
drops off from the edges of a channel. A larger value (compared to typical
|
||||||
|
channel capacities) means that the drop off is slow and that channel
|
||||||
|
balances are distributed more uniformly. A small value leads to the
|
||||||
|
assumption of very unbalanced channels.
|
||||||
|
*/
|
||||||
|
uint64 scale_msat = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
DecayTime describes the information decay of knowledge about previous
|
||||||
|
successes and failures in channels. The smaller the decay time, the quicker
|
||||||
|
we forget about past forwardings.
|
||||||
|
*/
|
||||||
|
uint64 decay_time = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AprioriParameters {
|
||||||
|
/*
|
||||||
|
The amount of time mission control will take to restore a penalized node
|
||||||
|
or channel back to 50% success probability, expressed in seconds. Setting
|
||||||
|
this value to a higher value will penalize failures for longer, making
|
||||||
|
mission control less likely to route through nodes and channels that we
|
||||||
|
have previously recorded failures for.
|
||||||
|
*/
|
||||||
|
uint64 half_life_seconds = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The probability of success mission control should assign to hop in a route
|
||||||
|
where it has no other information available. Higher values will make mission
|
||||||
|
control more willing to try hops that we have no information about, lower
|
||||||
|
values will discourage trying these hops.
|
||||||
|
*/
|
||||||
|
double hop_probability = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The importance that mission control should place on historical results,
|
||||||
|
expressed as a value in [0;1]. Setting this value to 1 will ignore all
|
||||||
|
historical payments and just use the hop probability to assess the
|
||||||
|
probability of success for each hop. A zero value ignores hop probability
|
||||||
|
completely and relies entirely on historical results, unless none are
|
||||||
|
available.
|
||||||
|
*/
|
||||||
|
double weight = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The fraction of a channel's capacity that we consider to have liquidity. For
|
||||||
|
amounts that come close to or exceed the fraction, an additional penalty is
|
||||||
|
applied. A value of 1.0 disables the capacity factor. Allowed values are in
|
||||||
|
[0.75, 1.0].
|
||||||
|
*/
|
||||||
|
double capacity_fraction = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message QueryProbabilityRequest {
|
||||||
|
// The source node pubkey of the pair.
|
||||||
|
bytes from_node = 1;
|
||||||
|
|
||||||
|
// The destination node pubkey of the pair.
|
||||||
|
bytes to_node = 2;
|
||||||
|
|
||||||
|
// The amount for which to calculate a probability.
|
||||||
|
int64 amt_msat = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message QueryProbabilityResponse {
|
||||||
|
// The success probability for the requested pair.
|
||||||
|
double probability = 1;
|
||||||
|
|
||||||
|
// The historical data for the requested pair.
|
||||||
|
PairData history = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BuildRouteRequest {
|
||||||
|
/*
|
||||||
|
The amount to send expressed in msat. If set to zero, the minimum routable
|
||||||
|
amount is used.
|
||||||
|
*/
|
||||||
|
int64 amt_msat = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CLTV delta from the current height that should be used for the timelock
|
||||||
|
of the final hop
|
||||||
|
*/
|
||||||
|
int32 final_cltv_delta = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The channel id of the channel that must be taken to the first hop. If zero,
|
||||||
|
any channel may be used.
|
||||||
|
*/
|
||||||
|
uint64 outgoing_chan_id = 3 [jstype = JS_STRING];
|
||||||
|
|
||||||
|
/*
|
||||||
|
A list of hops that defines the route. This does not include the source hop
|
||||||
|
pubkey.
|
||||||
|
*/
|
||||||
|
repeated bytes hop_pubkeys = 4;
|
||||||
|
|
||||||
|
// An optional payment addr to be included within the last hop of the route.
|
||||||
|
bytes payment_addr = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BuildRouteResponse {
|
||||||
|
/*
|
||||||
|
Fully specified route that can be used to execute the payment.
|
||||||
|
*/
|
||||||
|
lnrpc.Route route = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribeHtlcEventsRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
HtlcEvent contains the htlc event that was processed. These are served on a
|
||||||
|
best-effort basis; events are not persisted, delivery is not guaranteed
|
||||||
|
(in the event of a crash in the switch, forward events may be lost) and
|
||||||
|
some events may be replayed upon restart. Events consumed from this package
|
||||||
|
should be de-duplicated by the htlc's unique combination of incoming and
|
||||||
|
outgoing channel id and htlc id. [EXPERIMENTAL]
|
||||||
|
*/
|
||||||
|
message HtlcEvent {
|
||||||
|
/*
|
||||||
|
The short channel id that the incoming htlc arrived at our node on. This
|
||||||
|
value is zero for sends.
|
||||||
|
*/
|
||||||
|
uint64 incoming_channel_id = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The short channel id that the outgoing htlc left our node on. This value
|
||||||
|
is zero for receives.
|
||||||
|
*/
|
||||||
|
uint64 outgoing_channel_id = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Incoming id is the index of the incoming htlc in the incoming channel.
|
||||||
|
This value is zero for sends.
|
||||||
|
*/
|
||||||
|
uint64 incoming_htlc_id = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Outgoing id is the index of the outgoing htlc in the outgoing channel.
|
||||||
|
This value is zero for receives.
|
||||||
|
*/
|
||||||
|
uint64 outgoing_htlc_id = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The time in unix nanoseconds that the event occurred.
|
||||||
|
*/
|
||||||
|
uint64 timestamp_ns = 5;
|
||||||
|
|
||||||
|
enum EventType {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
SEND = 1;
|
||||||
|
RECEIVE = 2;
|
||||||
|
FORWARD = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The event type indicates whether the htlc was part of a send, receive or
|
||||||
|
forward.
|
||||||
|
*/
|
||||||
|
EventType event_type = 6;
|
||||||
|
|
||||||
|
oneof event {
|
||||||
|
ForwardEvent forward_event = 7;
|
||||||
|
ForwardFailEvent forward_fail_event = 8;
|
||||||
|
SettleEvent settle_event = 9;
|
||||||
|
LinkFailEvent link_fail_event = 10;
|
||||||
|
SubscribedEvent subscribed_event = 11;
|
||||||
|
FinalHtlcEvent final_htlc_event = 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message HtlcInfo {
|
||||||
|
// The timelock on the incoming htlc.
|
||||||
|
uint32 incoming_timelock = 1;
|
||||||
|
|
||||||
|
// The timelock on the outgoing htlc.
|
||||||
|
uint32 outgoing_timelock = 2;
|
||||||
|
|
||||||
|
// The amount of the incoming htlc.
|
||||||
|
uint64 incoming_amt_msat = 3;
|
||||||
|
|
||||||
|
// The amount of the outgoing htlc.
|
||||||
|
uint64 outgoing_amt_msat = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ForwardEvent {
|
||||||
|
// Info contains details about the htlc that was forwarded.
|
||||||
|
HtlcInfo info = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ForwardFailEvent {
|
||||||
|
}
|
||||||
|
|
||||||
|
message SettleEvent {
|
||||||
|
// The revealed preimage.
|
||||||
|
bytes preimage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FinalHtlcEvent {
|
||||||
|
bool settled = 1;
|
||||||
|
bool offchain = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribedEvent {
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinkFailEvent {
|
||||||
|
// Info contains details about the htlc that we failed.
|
||||||
|
HtlcInfo info = 1;
|
||||||
|
|
||||||
|
// FailureCode is the BOLT error code for the failure.
|
||||||
|
lnrpc.Failure.FailureCode wire_failure = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
FailureDetail provides additional information about the reason for the
|
||||||
|
failure. This detail enriches the information provided by the wire message
|
||||||
|
and may be 'no detail' if the wire message requires no additional metadata.
|
||||||
|
*/
|
||||||
|
FailureDetail failure_detail = 3;
|
||||||
|
|
||||||
|
// A string representation of the link failure.
|
||||||
|
string failure_string = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FailureDetail {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
NO_DETAIL = 1;
|
||||||
|
ONION_DECODE = 2;
|
||||||
|
LINK_NOT_ELIGIBLE = 3;
|
||||||
|
ON_CHAIN_TIMEOUT = 4;
|
||||||
|
HTLC_EXCEEDS_MAX = 5;
|
||||||
|
INSUFFICIENT_BALANCE = 6;
|
||||||
|
INCOMPLETE_FORWARD = 7;
|
||||||
|
HTLC_ADD_FAILED = 8;
|
||||||
|
FORWARDS_DISABLED = 9;
|
||||||
|
INVOICE_CANCELED = 10;
|
||||||
|
INVOICE_UNDERPAID = 11;
|
||||||
|
INVOICE_EXPIRY_TOO_SOON = 12;
|
||||||
|
INVOICE_NOT_OPEN = 13;
|
||||||
|
MPP_INVOICE_TIMEOUT = 14;
|
||||||
|
ADDRESS_MISMATCH = 15;
|
||||||
|
SET_TOTAL_MISMATCH = 16;
|
||||||
|
SET_TOTAL_TOO_LOW = 17;
|
||||||
|
SET_OVERPAID = 18;
|
||||||
|
UNKNOWN_INVOICE = 19;
|
||||||
|
INVALID_KEYSEND = 20;
|
||||||
|
MPP_IN_PROGRESS = 21;
|
||||||
|
CIRCULAR_ROUTE = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PaymentState {
|
||||||
|
/*
|
||||||
|
Payment is still in flight.
|
||||||
|
*/
|
||||||
|
IN_FLIGHT = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Payment completed successfully.
|
||||||
|
*/
|
||||||
|
SUCCEEDED = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
There are more routes to try, but the payment timeout was exceeded.
|
||||||
|
*/
|
||||||
|
FAILED_TIMEOUT = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
All possible routes were tried and failed permanently. Or were no
|
||||||
|
routes to the destination at all.
|
||||||
|
*/
|
||||||
|
FAILED_NO_ROUTE = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
A non-recoverable error has occurred.
|
||||||
|
*/
|
||||||
|
FAILED_ERROR = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Payment details incorrect (unknown hash, invalid amt or
|
||||||
|
invalid final cltv delta)
|
||||||
|
*/
|
||||||
|
FAILED_INCORRECT_PAYMENT_DETAILS = 5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Insufficient local balance.
|
||||||
|
*/
|
||||||
|
FAILED_INSUFFICIENT_BALANCE = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PaymentStatus {
|
||||||
|
// Current state the payment is in.
|
||||||
|
PaymentState state = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The pre-image of the payment when state is SUCCEEDED.
|
||||||
|
*/
|
||||||
|
bytes preimage = 2;
|
||||||
|
|
||||||
|
reserved 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The HTLCs made in attempt to settle the payment [EXPERIMENTAL].
|
||||||
|
*/
|
||||||
|
repeated lnrpc.HTLCAttempt htlcs = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CircuitKey {
|
||||||
|
/// The id of the channel that the is part of this circuit.
|
||||||
|
uint64 chan_id = 1;
|
||||||
|
|
||||||
|
/// The index of the incoming htlc in the incoming channel.
|
||||||
|
uint64 htlc_id = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ForwardHtlcInterceptRequest {
|
||||||
|
/*
|
||||||
|
The key of this forwarded htlc. It defines the incoming channel id and
|
||||||
|
the index in this channel.
|
||||||
|
*/
|
||||||
|
CircuitKey incoming_circuit_key = 1;
|
||||||
|
|
||||||
|
// The incoming htlc amount.
|
||||||
|
uint64 incoming_amount_msat = 5;
|
||||||
|
|
||||||
|
// The incoming htlc expiry.
|
||||||
|
uint32 incoming_expiry = 6;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The htlc payment hash. This value is not guaranteed to be unique per
|
||||||
|
request.
|
||||||
|
*/
|
||||||
|
bytes payment_hash = 2;
|
||||||
|
|
||||||
|
// The requested outgoing channel id for this forwarded htlc. Because of
|
||||||
|
// non-strict forwarding, this isn't necessarily the channel over which the
|
||||||
|
// packet will be forwarded eventually. A different channel to the same peer
|
||||||
|
// may be selected as well.
|
||||||
|
uint64 outgoing_requested_chan_id = 7;
|
||||||
|
|
||||||
|
// The outgoing htlc amount.
|
||||||
|
uint64 outgoing_amount_msat = 3;
|
||||||
|
|
||||||
|
// The outgoing htlc expiry.
|
||||||
|
uint32 outgoing_expiry = 4;
|
||||||
|
|
||||||
|
// Any custom records that were present in the payload.
|
||||||
|
map<uint64, bytes> custom_records = 8;
|
||||||
|
|
||||||
|
// The onion blob for the next hop
|
||||||
|
bytes onion_blob = 9;
|
||||||
|
|
||||||
|
// The block height at which this htlc will be auto-failed to prevent the
|
||||||
|
// channel from force-closing.
|
||||||
|
int32 auto_fail_height = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
ForwardHtlcInterceptResponse enables the caller to resolve a previously hold
|
||||||
|
forward. The caller can choose either to:
|
||||||
|
- `Resume`: Execute the default behavior (usually forward).
|
||||||
|
- `Reject`: Fail the htlc backwards.
|
||||||
|
- `Settle`: Settle this htlc with a given preimage.
|
||||||
|
*/
|
||||||
|
message ForwardHtlcInterceptResponse {
|
||||||
|
/**
|
||||||
|
The key of this forwarded htlc. It defines the incoming channel id and
|
||||||
|
the index in this channel.
|
||||||
|
*/
|
||||||
|
CircuitKey incoming_circuit_key = 1;
|
||||||
|
|
||||||
|
// The resolve action for this intercepted htlc.
|
||||||
|
ResolveHoldForwardAction action = 2;
|
||||||
|
|
||||||
|
// The preimage in case the resolve action is Settle.
|
||||||
|
bytes preimage = 3;
|
||||||
|
|
||||||
|
// Encrypted failure message in case the resolve action is Fail.
|
||||||
|
//
|
||||||
|
// If failure_message is specified, the failure_code field must be set
|
||||||
|
// to zero.
|
||||||
|
bytes failure_message = 4;
|
||||||
|
|
||||||
|
// Return the specified failure code in case the resolve action is Fail. The
|
||||||
|
// message data fields are populated automatically.
|
||||||
|
//
|
||||||
|
// If a non-zero failure_code is specified, failure_message must not be set.
|
||||||
|
//
|
||||||
|
// For backwards-compatibility reasons, TEMPORARY_CHANNEL_FAILURE is the
|
||||||
|
// default value for this field.
|
||||||
|
lnrpc.Failure.FailureCode failure_code = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ResolveHoldForwardAction {
|
||||||
|
SETTLE = 0;
|
||||||
|
FAIL = 1;
|
||||||
|
RESUME = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateChanStatusRequest {
|
||||||
|
lnrpc.ChannelPoint chan_point = 1;
|
||||||
|
|
||||||
|
ChanStatusAction action = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ChanStatusAction {
|
||||||
|
ENABLE = 0;
|
||||||
|
DISABLE = 1;
|
||||||
|
AUTO = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateChanStatusResponse {
|
||||||
|
}
|
Reference in New Issue
Block a user