From f456d62d3c7635aaefae60df4fa6dc5321776801 Mon Sep 17 00:00:00 2001 From: NicolasDorier Date: Fri, 6 Oct 2017 10:37:38 +0900 Subject: [PATCH] Properly map addresses to invoice, use new nbxplorer --- BTCPayServer.Tests/docker-compose.yml | 2 +- BTCPayServer/BTCPayServer.csproj | 2 +- .../Configuration/BTCPayServerRuntime.cs | 6 - BTCPayServer/Controllers/InvoiceController.cs | 2 +- BTCPayServer/Data/AddressInvoiceData.cs | 25 ++ BTCPayServer/Data/ApplicationDbContext.cs | 8 + BTCPayServer/Hosting/BTCPayServerServices.cs | 3 +- .../20171006013443_AddressMapping.Designer.cs | 392 ++++++++++++++++++ .../20171006013443_AddressMapping.cs | 41 ++ .../ApplicationDbContextModelSnapshot.cs | 21 + .../Services/Invoices/InvoiceWatcher.cs | 14 +- BTCPayServer/Services/Wallets/BTCPayWallet.cs | 56 +-- 12 files changed, 535 insertions(+), 37 deletions(-) create mode 100644 BTCPayServer/Data/AddressInvoiceData.cs create mode 100644 BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs create mode 100644 BTCPayServer/Migrations/20171006013443_AddressMapping.cs diff --git a/BTCPayServer.Tests/docker-compose.yml b/BTCPayServer.Tests/docker-compose.yml index 13e57da53..abd75a49b 100644 --- a/BTCPayServer.Tests/docker-compose.yml +++ b/BTCPayServer.Tests/docker-compose.yml @@ -14,7 +14,7 @@ services: - nbxplorer nbxplorer: - image: nicolasdorier/nbxplorer:1.0.0.14 + image: nicolasdorier/nbxplorer:1.0.0.16 ports: - "32838:32838" expose: diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 9f9dd3f0a..a70fca227 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -24,7 +24,7 @@ - + diff --git a/BTCPayServer/Configuration/BTCPayServerRuntime.cs b/BTCPayServer/Configuration/BTCPayServerRuntime.cs index 57cc748ac..b03a7ca08 100644 --- a/BTCPayServer/Configuration/BTCPayServerRuntime.cs +++ b/BTCPayServer/Configuration/BTCPayServerRuntime.cs @@ -74,7 +74,6 @@ namespace BTCPayServer.Configuration db = new DBreezeEngine(CreateDBPath(opts, "AddressMapping")); _Resources.Add(db); - Wallet = new BTCPayWallet(Explorer, db); } private static string CreateDBPath(BTCPayServerOptions opts, string name) @@ -113,11 +112,6 @@ namespace BTCPayServer.Configuration get; set; } - public BTCPayWallet Wallet - { - get; - set; - } public ApplicationDbContextFactory DBFactory { get; diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index dbea966fb..a69de783c 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -99,7 +99,7 @@ namespace BTCPayServer.Controllers entity.DepositAddress = await _Wallet.ReserveAddressAsync(derivationStrategy); entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity); - await _Wallet.MapAsync(entity.DepositAddress, entity.Id); + await _Wallet.MapAsync(entity.DepositAddress.ScriptPubKey, entity.Id); await _Watcher.WatchAsync(entity.Id); var resp = entity.EntityToDTO(); return new DataWrapper(resp) { Facade = "pos/invoice" }; diff --git a/BTCPayServer/Data/AddressInvoiceData.cs b/BTCPayServer/Data/AddressInvoiceData.cs new file mode 100644 index 000000000..45899b081 --- /dev/null +++ b/BTCPayServer/Data/AddressInvoiceData.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BTCPayServer.Data +{ + public class AddressInvoiceData + { + public string Address + { + get; set; + } + + public InvoiceData InvoiceData + { + get; set; + } + + public string InvoiceDataId + { + get; set; + } + } +} diff --git a/BTCPayServer/Data/ApplicationDbContext.cs b/BTCPayServer/Data/ApplicationDbContext.cs index 3ad386d14..b210f72b8 100644 --- a/BTCPayServer/Data/ApplicationDbContext.cs +++ b/BTCPayServer/Data/ApplicationDbContext.cs @@ -46,6 +46,11 @@ namespace BTCPayServer.Data get; set; } + public DbSet AddressInvoices + { + get; set; + } + public DbSet Settings { get; set; @@ -86,6 +91,9 @@ namespace BTCPayServer.Data .HasOne(pt => pt.StoreData) .WithMany(t => t.UserStores) .HasForeignKey(pt => pt.StoreDataId); + + builder.Entity() + .HasKey(o => o.Address); } } } diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index b7723b8c1..3a2331725 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -31,6 +31,7 @@ using Microsoft.AspNetCore.Identity; using BTCPayServer.Models; using System.Threading.Tasks; using System.Threading; +using BTCPayServer.Services.Wallets; namespace BTCPayServer.Hosting { @@ -111,7 +112,7 @@ namespace BTCPayServer.Hosting services.TryAddSingleton(o => o.GetRequiredService().Network); services.TryAddSingleton(o => o.GetRequiredService().DBFactory); services.TryAddSingleton(); - services.TryAddSingleton(o => o.GetRequiredService().Wallet); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(o => new NBXplorerFeeProvider() { diff --git a/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs new file mode 100644 index 000000000..c2b8f6bc6 --- /dev/null +++ b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs @@ -0,0 +1,392 @@ +// +using BTCPayServer.Data; +using BTCPayServer.Servcices.Invoices; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; + +namespace BTCPayServer.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20171006013443_AddressMapping")] + partial class AddressMapping + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b => + { + b.Property("Address") + .ValueGeneratedOnAdd(); + + b.Property("InvoiceDataId"); + + b.HasKey("Address"); + + b.HasIndex("InvoiceDataId"); + + b.ToTable("AddressInvoices"); + }); + + modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Blob"); + + b.Property("Created"); + + b.Property("CustomerEmail"); + + b.Property("ExceptionStatus"); + + b.Property("ItemCode"); + + b.Property("OrderId"); + + b.Property("Status"); + + b.Property("StoreDataId"); + + b.HasKey("Id"); + + b.HasIndex("StoreDataId"); + + b.ToTable("Invoices"); + }); + + modelBuilder.Entity("BTCPayServer.Data.PaymentData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Blob"); + + b.Property("InvoiceDataId"); + + b.HasKey("Id"); + + b.HasIndex("InvoiceDataId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Blob"); + + b.Property("InvoiceDataId"); + + b.HasKey("Id"); + + b.HasIndex("InvoiceDataId"); + + b.ToTable("RefundAddresses"); + }); + + modelBuilder.Entity("BTCPayServer.Data.SettingData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("BTCPayServer.Data.StoreData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DerivationStrategy"); + + b.Property("SpeedPolicy"); + + b.Property("StoreCertificate"); + + b.Property("StoreName"); + + b.Property("StoreWebsite"); + + b.HasKey("Id"); + + b.ToTable("Stores"); + }); + + modelBuilder.Entity("BTCPayServer.Data.UserStore", b => + { + b.Property("ApplicationUserId"); + + b.Property("StoreDataId"); + + b.Property("Role"); + + b.HasKey("ApplicationUserId", "StoreDataId"); + + b.HasIndex("StoreDataId"); + + b.ToTable("UserStore"); + }); + + modelBuilder.Entity("BTCPayServer.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("RequiresEmailConfirmation"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider"); + + b.Property("ProviderKey"); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider"); + + b.Property("Name"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b => + { + b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData") + .WithMany() + .HasForeignKey("InvoiceDataId"); + }); + + modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b => + { + b.HasOne("BTCPayServer.Data.StoreData", "StoreData") + .WithMany() + .HasForeignKey("StoreDataId"); + }); + + modelBuilder.Entity("BTCPayServer.Data.PaymentData", b => + { + b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData") + .WithMany("Payments") + .HasForeignKey("InvoiceDataId"); + }); + + modelBuilder.Entity("BTCPayServer.Data.RefundAddressesData", b => + { + b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData") + .WithMany("RefundAddresses") + .HasForeignKey("InvoiceDataId"); + }); + + modelBuilder.Entity("BTCPayServer.Data.UserStore", b => + { + b.HasOne("BTCPayServer.Models.ApplicationUser", "ApplicationUser") + .WithMany("UserStores") + .HasForeignKey("ApplicationUserId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("BTCPayServer.Data.StoreData", "StoreData") + .WithMany("UserStores") + .HasForeignKey("StoreDataId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("BTCPayServer.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("BTCPayServer.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("BTCPayServer.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("BTCPayServer.Models.ApplicationUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BTCPayServer/Migrations/20171006013443_AddressMapping.cs b/BTCPayServer/Migrations/20171006013443_AddressMapping.cs new file mode 100644 index 000000000..aba4aa2ed --- /dev/null +++ b/BTCPayServer/Migrations/20171006013443_AddressMapping.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace BTCPayServer.Migrations +{ + public partial class AddressMapping : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AddressInvoices", + columns: table => new + { + Address = table.Column(type: "TEXT", nullable: false), + InvoiceDataId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AddressInvoices", x => x.Address); + table.ForeignKey( + name: "FK_AddressInvoices_Invoices_InvoiceDataId", + column: x => x.InvoiceDataId, + principalTable: "Invoices", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AddressInvoices_InvoiceDataId", + table: "AddressInvoices", + column: "InvoiceDataId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AddressInvoices"); + } + } +} diff --git a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs index 457503c0d..2b972fd63 100644 --- a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs @@ -20,6 +20,20 @@ namespace BTCPayServer.Migrations modelBuilder .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b => + { + b.Property("Address") + .ValueGeneratedOnAdd(); + + b.Property("InvoiceDataId"); + + b.HasKey("Address"); + + b.HasIndex("InvoiceDataId"); + + b.ToTable("AddressInvoices"); + }); + modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b => { b.Property("Id") @@ -286,6 +300,13 @@ namespace BTCPayServer.Migrations b.ToTable("AspNetUserTokens"); }); + modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b => + { + b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData") + .WithMany() + .HasForeignKey("InvoiceDataId"); + }); + modelBuilder.Entity("BTCPayServer.Data.InvoiceData", b => { b.HasOne("BTCPayServer.Data.StoreData", "StoreData") diff --git a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs index 0f9309b76..67e963fa1 100644 --- a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs +++ b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs @@ -12,6 +12,7 @@ using System.Threading; using Microsoft.Extensions.Hosting; using System.Collections.Concurrent; using Hangfire; +using BTCPayServer.Services.Wallets; namespace BTCPayServer.Servcices.Invoices { @@ -21,11 +22,14 @@ namespace BTCPayServer.Servcices.Invoices ExplorerClient _ExplorerClient; DerivationStrategyFactory _DerivationFactory; InvoiceNotificationManager _NotificationManager; + BTCPayWallet _Wallet; public InvoiceWatcher(ExplorerClient explorerClient, InvoiceRepository invoiceRepository, + BTCPayWallet wallet, InvoiceNotificationManager notificationManager) { + _Wallet = wallet ?? throw new ArgumentNullException(nameof(wallet)); _ExplorerClient = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient)); _DerivationFactory = new DerivationStrategyFactory(_ExplorerClient.Network); _InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository)); @@ -93,10 +97,18 @@ namespace BTCPayServer.Servcices.Invoices { var strategy = _DerivationFactory.Parse(invoice.DerivationStrategy); changes = await _ExplorerClient.SyncAsync(strategy, changes, false, _Cts.Token).ConfigureAwait(false); + + var utxos = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).ToArray(); + var invoiceIds = utxos.Select(u => _Wallet.GetInvoiceId(u.Output.ScriptPubKey)).ToArray(); + utxos = + utxos + .Where((u,i) => invoiceIds[i].GetAwaiter().GetResult() == invoice.Id) + .ToArray(); + shouldWait = false; //should not wait, Sync is blocking call List receivedCoins = new List(); - foreach(var received in changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs)) + foreach(var received in utxos) if(received.Output.ScriptPubKey == invoice.DepositAddress.ScriptPubKey) receivedCoins.Add(new Coin(received.Outpoint, received.Output)); diff --git a/BTCPayServer/Services/Wallets/BTCPayWallet.cs b/BTCPayServer/Services/Wallets/BTCPayWallet.cs index ce5941101..754d61c6b 100644 --- a/BTCPayServer/Services/Wallets/BTCPayWallet.cs +++ b/BTCPayServer/Services/Wallets/BTCPayWallet.cs @@ -1,5 +1,4 @@ -using DBreeze; -using NBitcoin; +using NBitcoin; using NBXplorer; using NBXplorer.DerivationStrategy; using System; @@ -7,56 +6,61 @@ using System.Collections.Generic; using System.Text; using System.Linq; using System.Threading.Tasks; +using BTCPayServer.Data; namespace BTCPayServer.Services.Wallets { - public class BTCPayWallet - { + public class BTCPayWallet + { private ExplorerClient _Client; - private DBreezeEngine _Engine; private Serializer _Serializer; private DerivationStrategyFactory _DerivationStrategyFactory; + ApplicationDbContextFactory _DBFactory; - public BTCPayWallet(ExplorerClient client, DBreezeEngine dbreeze) + public BTCPayWallet(ExplorerClient client, ApplicationDbContextFactory factory) { if(client == null) throw new ArgumentNullException(nameof(client)); - if(dbreeze == null) - throw new ArgumentNullException(nameof(dbreeze)); + if(factory == null) + throw new ArgumentNullException(nameof(factory)); _Client = client; - _Engine = dbreeze; + _DBFactory = factory; _Serializer = new NBXplorer.Serializer(_Client.Network); _DerivationStrategyFactory = new DerivationStrategyFactory(_Client.Network); } - + public async Task ReserveAddressAsync(string walletIdentifier) { var pathInfo = await _Client.GetUnusedAsync(_DerivationStrategyFactory.Parse(walletIdentifier), DerivationFeature.Deposit, 0, true).ConfigureAwait(false); - using(var tx = _Engine.GetTransaction()) - { - var pathInfoBytes = ToBytes(pathInfo); - tx.Insert(AddressToKeyInfo, pathInfo.Address.ToString(), pathInfoBytes); - tx.Commit(); - } - return pathInfo.Address; + return pathInfo.ScriptPubKey.GetDestinationAddress(_DerivationStrategyFactory.Network); } - public async Task TrackAsync(string walletIdentifier) + public Task TrackAsync(string walletIdentifier) { - await _Client.SyncAsync(_DerivationStrategyFactory.Parse(walletIdentifier), null, null, true).ConfigureAwait(false); + return _Client.TrackAsync(_DerivationStrategyFactory.Parse(walletIdentifier)); } - const string AddressToId = "AtI"; - const string AddressToKeyInfo = "AtK"; - public Task MapAsync(BitcoinAddress address, string id) + public async Task GetInvoiceId(Script scriptPubKey) { - using(var tx = _Engine.GetTransaction()) + using(var db = _DBFactory.CreateContext()) { - tx.Insert(AddressToId, address.ToString(), id); - tx.Commit(); + var result = await db.AddressInvoices.FindAsync(scriptPubKey.Hash.ToString()); + return result?.InvoiceDataId; + } + } + + public async Task MapAsync(Script address, string invoiceId) + { + using(var db = _DBFactory.CreateContext()) + { + db.AddressInvoices.Add(new AddressInvoiceData() + { + Address = address.Hash.ToString(), + InvoiceDataId = invoiceId + }); + await db.SaveChangesAsync(); } - return Task.FromResult(true); } private byte[] ToBytes(T obj)