Skip to content

Commit

Permalink
feat: lightning backend interface
Browse files Browse the repository at this point in the history
  • Loading branch information
StringNick committed Sep 16, 2024
1 parent 3c82013 commit 5065446
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/core/lightning/lightning.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
const root = @import("../../lib.zig");
const std = @import("std");

pub const MintLightning = @import("mint.zig");

const Bolt11Invoice = root.lightning_invoices.Bolt11Invoice;
const Amount = root.core.amount.Amount;
const MeltQuoteState = root.core.nuts.nut05.QuoteState;
Expand Down
115 changes: 115 additions & 0 deletions src/core/lightning/mint.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/// MintLightning interface for backend
const Self = @This();

const std = @import("std");
const core = @import("../lib.zig");

const Channel = @import("../../channels/channels.zig").Channel;
const Amount = core.amount.Amount;
const PaymentQuoteResponse = core.lightning.PaymentQuoteResponse;
const CreateInvoiceResponse = core.lightning.CreateInvoiceResponse;
const PayInvoiceResponse = core.lightning.PayInvoiceResponse;
const MeltQuoteBolt11Request = core.nuts.nut05.MeltQuoteBolt11Request;
const Settings = core.lightning.Settings;
const MintMeltSettings = core.lightning.MintMeltSettings;
const FeeReserve = core.mint.FeeReserve;
const MintQuoteState = core.nuts.nut04.QuoteState;

// _type: type,
allocator: std.mem.Allocator,
ptr: *anyopaque,

deinitFn: *const fn (ptr: *anyopaque) void,
getSettingsFn: *const fn (ptr: *anyopaque) Settings,
waitAnyInvoiceFn: *const fn (ptr: *anyopaque) anyerror!Channel(std.ArrayList(u8)).Rx,
getPaymentQuoteFn: *const fn (ptr: *anyopaque, alloc: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) anyerror!PaymentQuoteResponse,
payInvoiceFn: *const fn (ptr: *anyopaque, alloc: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) anyerror!PayInvoiceResponse,
checkInvoiceStatusFn: *const fn (ptr: *anyopaque, request_lookup_id: []const u8) anyerror!MintQuoteState,
createInvoiceFn: *const fn (ptr: *anyopaque, gpa: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) anyerror!CreateInvoiceResponse,

pub fn initFrom(comptime T: type, allocator: std.mem.Allocator, value: T) !Self {
const gen = struct {
pub fn getSettings(pointer: *anyopaque) Settings {
const self: *T = @ptrCast(@alignCast(pointer));
return self.getSettings();
}

pub fn waitAnyInvoice(pointer: *anyopaque) anyerror!Channel(std.ArrayList(u8)).Rx {
const self: *T = @ptrCast(@alignCast(pointer));
return self.waitAnyInvoice();
}

pub fn getPaymentQuote(pointer: *anyopaque, arena: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) anyerror!PaymentQuoteResponse {
const self: *T = @ptrCast(@alignCast(pointer));
return self.getPaymentQuote(arena, melt_quote_request);
}

pub fn payInvoice(pointer: *anyopaque, arena: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) !PayInvoiceResponse {
const self: *T = @ptrCast(@alignCast(pointer));
return self.payInvoice(arena, melt_quote, partial_msats, max_fee_msats);
}

pub fn checkInvoiceStatus(pointer: *anyopaque, request_lookup_id: []const u8) !MintQuoteState {
const self: *T = @ptrCast(@alignCast(pointer));
return self.checkInvoiceStatus(request_lookup_id);
}

pub fn createInvoice(pointer: *anyopaque, arena: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) !CreateInvoiceResponse {
const self: *T = @ptrCast(@alignCast(pointer));
return self.createInvoice(arena, amount, unit, description, unix_expiry);
}

pub fn deinit(pointer: *anyopaque) void {
if (std.meta.hasFn(T, "deinit")) {
const self: *T = @ptrCast(@alignCast(pointer));
self.deinit();
}
}
};

const ptr = try allocator.create(T);
ptr.* = value;

return .{
// ._type = T,
.allocator = allocator,
.ptr = ptr,
.getSettingsFn = gen.getSettings,
.waitAnyInvoiceFn = gen.waitAnyInvoice,
.getPaymentQuoteFn = gen.getPaymentQuote,
.payInvoiceFn = gen.payInvoice,
.checkInvoiceStatusFn = gen.checkInvoiceStatus,
.createInvoiceFn = gen.createInvoice,
.deinitFn = gen.deinit,
};
}

pub fn deinit(self: Self) void {
self.deinitFn(self.ptr);
// clearing pointer
// self.allocator.destroy(@as(self._type, @ptrCast(self.ptr)));
}

pub fn getSettings(self: Self) Settings {
return self.getSettingsFn(self.ptr);
}

pub fn waitAnyInvoice(self: Self) !Channel(std.ArrayList(u8)).Rx {
return self.waitAnyInvoiceFn(self.ptr);
}

pub fn getPaymentQuote(self: Self, arena: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) !PaymentQuoteResponse {
return self.getPaymentQuoteFn(self.ptr, arena, melt_quote_request);
}

pub fn payInvoice(self: Self, arena: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) !PayInvoiceResponse {
return self.payInvoiceFn(self.ptr, arena, melt_quote, partial_msats, max_fee_msats);
}

pub fn checkInvoiceStatus(self: Self, request_lookup_id: []const u8) !MintQuoteState {
return self.checkInvoiceStatusFn(self.ptr, request_lookup_id);
}

pub fn createInvoice(self: Self, arena: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) !CreateInvoiceResponse {
return self.createInvoiceFn(self.ptr, arena, amount, unit, description, unix_expiry);
}
10 changes: 10 additions & 0 deletions src/core/mint/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ pub const MeltQuote = struct {
/// Value used by ln backend to look up state of request
request_lookup_id: []const u8,

/// formatting mint quote
pub fn format(
self: MeltQuote,
comptime _: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) !void {
try writer.print("{}", .{std.json.fmt(self, .{})});
}

/// Create new [`MeltQuote`]
pub fn init(
request: []const u8,
Expand Down
18 changes: 17 additions & 1 deletion src/fake_wallet/fake_wallet.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const MintMeltSettings = core.lightning.MintMeltSettings;
const FeeReserve = core.mint.FeeReserve;
const Channel = @import("../channels/channels.zig").Channel;
const MintQuoteState = core.nuts.nut04.QuoteState;
const MintLightning = core.lightning.MintLightning;

// TODO: wait any invoices, here we need create a new listener, that will receive
// message like pub sub channel
Expand Down Expand Up @@ -68,6 +69,10 @@ pub const FakeWallet = struct {
};
}

pub fn toMintLightning(self: *const Self, gpa: std.mem.Allocator) error{OutOfMemory}!MintLightning {
return MintLightning.initFrom(Self, gpa, self.*);
}

pub fn deinit(self: *FakeWallet) void {
self.chan.deinit();
self.thread_pool.deinit(self.allocator);
Expand Down Expand Up @@ -229,4 +234,15 @@ pub const FakeWallet = struct {
}
};

test {}
test {
var mint = try FakeWallet.init(std.testing.allocator, .{}, .{}, .{});
defer mint.deinit();

const ln = mint.toMintLightning();
const settings = try ln.getSettings();

const _settings = mint.getSettings();

std.testing.expectEqual(settings, _settings);
std.log.warn("qq", .{});
}
1 change: 0 additions & 1 deletion src/fake_wallet/pub_sub.zig

This file was deleted.

7 changes: 6 additions & 1 deletion src/mint.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const builtin = @import("builtin");
const config = @import("mintd/config.zig");
const clap = @import("clap");

const MintLightning = core.lightning.MintLightning;
const MintState = @import("router/router.zig").MintState;
const LnKey = @import("router/router.zig").LnKey;
const FakeWallet = @import("fake_wallet/fake_wallet.zig").FakeWallet;
Expand Down Expand Up @@ -135,6 +136,7 @@ pub fn main() !void {
var ln_backends = router.LnBackendsMap.init(gpa.allocator());
defer {
var it = ln_backends.valueIterator();

while (it.next()) |v| {
v.deinit();
}
Expand All @@ -153,7 +155,10 @@ pub fn main() !void {
var wallet = try FakeWallet.init(gpa.allocator(), fee_reserve, .{}, .{});
errdefer wallet.deinit();

try ln_backends.put(ln_key, wallet);
const ln_mint = try wallet.toMintLightning(gpa.allocator());
errdefer ln_mint.deinit();

try ln_backends.put(ln_key, ln_mint);

try supported_units.put(unit, .{ input_fee_ppk, 64 });
}
Expand Down
4 changes: 2 additions & 2 deletions src/router/router.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ const router_handlers = @import("router_handlers.zig");
const zul = @import("zul");
const fake_wallet = @import("../fake_wallet/fake_wallet.zig");

const MintLightning = core.lightning.MintLightning;
const Mint = core.mint.Mint;
const CurrencyUnit = core.nuts.CurrencyUnit;
const PaymentMethod = core.nuts.PaymentMethod;
const FakeWallet = fake_wallet.FakeWallet;

pub const LnBackendsMap = std.HashMap(LnKey, FakeWallet, LnKeyContext, 80);
pub const LnBackendsMap = std.HashMap(LnKey, MintLightning, LnKeyContext, 80);

/// Create mint [`Server`] with required endpoints for cashu mint
/// Caller responsible for free resources
Expand Down
14 changes: 4 additions & 10 deletions src/router/router_handlers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const core = @import("../core/lib.zig");
const zul = @import("zul");
const ln_invoice = @import("../lightning_invoices/invoice.zig");

const FakeWallet = @import("../fake_wallet/fake_wallet.zig").FakeWallet;
const MintLightning = core.lightning.MintLightning;
const MintState = @import("router.zig").MintState;
const LnKey = @import("router.zig").LnKey;

Expand Down Expand Up @@ -96,9 +96,7 @@ pub fn getMintBolt11Quote(

const payload = (try req.json(core.nuts.nut04.MintQuoteBolt11Request)) orelse return error.WrongRequest;

const ln: FakeWallet = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
std.log.err("Bolt11 mint request for unsupported unit, unit = {any}", .{payload.unit});

const ln: MintLightning = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
return error.UnsupportedUnit;
};

Expand Down Expand Up @@ -164,9 +162,7 @@ pub fn getMeltBolt11Quote(

const payload = (try req.json(core.nuts.nut05.MeltQuoteBolt11Request)) orelse return error.WrongRequest;

const ln: FakeWallet = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
std.log.err("Bolt11 mint request for unsupported unit, unit = {any}", .{payload.unit});

const ln: MintLightning = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
return error.UnsupportedUnit;
};

Expand Down Expand Up @@ -323,9 +319,7 @@ pub fn postMeltBolt11(
}
}

const ln: FakeWallet = state.ln.get(.{ .unit = quote.unit, .method = .bolt11 }) orelse {
std.log.debug("Could not get ln backend for {}, bolt11 ", .{quote.unit});

const ln: MintLightning = state.ln.get(.{ .unit = quote.unit, .method = .bolt11 }) orelse {
state.mint.processUnpaidMelt(payload) catch |e| {
std.log.err("Could not reset melt quote state: {}", .{e});
};
Expand Down

0 comments on commit 5065446

Please sign in to comment.