diff --git a/Slp.API/Startup.cs b/Slp.API/Startup.cs index 3076570..40ccba7 100644 --- a/Slp.API/Startup.cs +++ b/Slp.API/Startup.cs @@ -12,6 +12,7 @@ using Slp.Common.Interfaces; using Slp.Common.Options; using Slp.Common.Services; +using Slp.Common.Utility; using System; namespace Slp.API @@ -49,14 +50,24 @@ public void ConfigureServices(IServiceCollection services) c.EnableAnnotations(); c.SwaggerDoc("v2", new OpenApiInfo { Title = "Slp.API", Version = "v2" }); }); - var connectionString = Configuration.GetConnectionString("SlpDbConnection"); + var connectionString = Configuration.GetConnectionString("SlpDbConnection"); services.AddDbContext( options => { #if DEBUG options.EnableSensitiveDataLogging(); #endif - options.UseSqlServer(connectionString); + var databaseType = Configuration.GetValue(nameof(SD.DatabaseBackend), SD.DatabaseBackend); + if (databaseType == SD.DatabaseBackendType.POSTGRESQL) + { + options.UseNpgsql(connectionString, x => x.MigrationsAssembly("Slp.Migrations.POSTGRESQL")); + } + else if (databaseType == SD.DatabaseBackendType.MSSQL) + { + options.UseSqlServer(connectionString, x => x.MigrationsAssembly("Slp.Migrations.MSSQL")); + } + else + throw new NotSupportedException(); }, contextLifetime: ServiceLifetime.Scoped,ServiceLifetime.Scoped ); diff --git a/Slp.Common/Models/DbModels/SlpAddress.cs b/Slp.Common/Models/DbModels/SlpAddress.cs index 08fab48..65315f8 100644 --- a/Slp.Common/Models/DbModels/SlpAddress.cs +++ b/Slp.Common/Models/DbModels/SlpAddress.cs @@ -9,9 +9,10 @@ public class SlpAddress [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } [MaxLength(SD.AddressSize)] - [ForeignKey(nameof(Block))] + //[ForeignKey(nameof(Block))] + [NotMapped] public int? BlockHeight { get; set; } - public SlpBlock Block { get; set; } + //public SlpBlock Block { get; set; } public string Address { get; set; } [NotMapped] diff --git a/Slp.Common/Models/DbModels/SlpTransactionInput.cs b/Slp.Common/Models/DbModels/SlpTransactionInput.cs index 00bf61e..a621629 100644 --- a/Slp.Common/Models/DbModels/SlpTransactionInput.cs +++ b/Slp.Common/Models/DbModels/SlpTransactionInput.cs @@ -31,5 +31,7 @@ public class SlpTransactionInput [MaxLength(SD.HashSize)] public byte[] SourceTxHash { get; set; } public int VOut { get; set; } + + // public int? BlockHeight { get; set; } } } diff --git a/Slp.Common/Models/DbModels/SlpTransactionOutput.cs b/Slp.Common/Models/DbModels/SlpTransactionOutput.cs index b859591..b9b831c 100644 --- a/Slp.Common/Models/DbModels/SlpTransactionOutput.cs +++ b/Slp.Common/Models/DbModels/SlpTransactionOutput.cs @@ -35,5 +35,6 @@ public class SlpTransactionOutput public long SlpTransactionId { get; set; } public virtual SlpTransaction SlpTransaction { get; set; } + // public int? BlockHeight { get; set; } } } diff --git a/Slp.Indexer/Services/SlpIndexerService.cs b/Slp.Indexer/Services/SlpIndexerService.cs index f8ac961..465e33a 100644 --- a/Slp.Indexer/Services/SlpIndexerService.cs +++ b/Slp.Indexer/Services/SlpIndexerService.cs @@ -22,6 +22,7 @@ using Slp.Common.Extensions; using PostgreSQLCopyHelper; using Npgsql; +using System.Threading; namespace Slp.Indexer.Services { @@ -95,8 +96,8 @@ public class SlpIndexerService : IndexerServiceBase, IIndexerService PostgreSQLCopyHelper addressCopyHelper = new PostgreSQLCopyHelper("public", nameof(SlpAddress)) .UsePostgresQuoting() .MapInteger(nameof(SlpAddress.Id), x => x.Id) - .MapVarchar(nameof(SlpAddress.Address), x => x.Address) - .MapInteger(nameof(SlpToken.BlockHeight), x => x.BlockHeight); + .MapVarchar(nameof(SlpAddress.Address), x => x.Address); + //.MapInteger(nameof(SlpToken.BlockHeight), x => x.BlockHeight); PostgreSQLCopyHelper inputCopyHelper = new PostgreSQLCopyHelper("public", nameof(SlpTransactionInput)) .UsePostgresQuoting() @@ -149,18 +150,25 @@ ISlpDbInitializer slpDbInitializer SlpAddress GetAddress(string address) { - if (!_usedAddresses.TryGetValue(address, out var addr)) + if (_usedAddresses.TryGetValue(address, out var addr)) return addr; return null; } + int _addressIndex=0; SlpAddress GetOrCreateAddress(string address,int? blockHeight) { //using var db = new SlpDbContext(_dbOptions); if (!_usedAddresses.TryGetValue(address, out var addr)) { - var nextId = _usedAddresses.Any() ? _usedAddresses.Max(a => a.Value.Id) + 1 : 1; - addr = new SlpAddress { Id = nextId, Address = address, BlockHeight = blockHeight, InDatabase = false }; - _usedAddresses.TryAdd(address, addr); + var nextId = Interlocked.Increment(ref _addressIndex); // _usedAddresses.Any() ? _usedAddresses.Max(a => a.Value.Id) + 1 : 1; + addr = new SlpAddress { Id = (int)nextId, Address = address, InDatabase = false }; + var res = _usedAddresses.TryAdd(address, addr); + if (!res) + { + if (!_usedAddresses.TryGetValue(address, out var addr2)) + throw new Exception("Failed to retrieve address"); + return addr2; + } } return addr; } @@ -198,7 +206,7 @@ public async Task CommitBatchToDb( List localBatch, List localBlocks) { - _log.LogInformation("Saving batch {0} to db async...", batchCounter); + _log.LogInformation("Saving batch {0} of {1} blocks and {2} txs to db async...", batchCounter,localBlocks.Count, localBatch.Count); var tokens = localBatch.Where(t => t.SlpToken != null && t.Type == SlpTransactionType.GENESIS).Select(t => (t.SlpToken,t.BlockHeight)).ToList(); tokens.ForEach(t => { @@ -209,59 +217,72 @@ public async Task CommitBatchToDb( var outputs = new List(); var inputs = new List(); var newAddresses = new Dictionary(); + _log.LogInformation("Collecting inputs and outputs..."); foreach (var tr in localBatch) { - //inputs.AddRange(tr.SlpTransactionInputs); - foreach (var o in tr.SlpTransactionOutputs) - { - try - { - outputs.Add(o); - var addr = GetOrCreateAddress(o.Address.Address, tr.BlockHeight); - o.Address = addr; - o.AddressId = addr.Id; - if (!newAddresses.ContainsKey(o.Address.Address) && addr.InDatabase==false) - { - newAddresses.Add(o.Address.Address, addr); - addr.InDatabase = true; - } - } - catch (Exception e) + outputs.AddRange(tr.SlpTransactionOutputs); + //foreach (var o in tr.SlpTransactionOutputs) + //{ + // //outputs.Add(o); + // //var addr = GetOrCreateAddress(o.Address.Address, tr.BlockHeight); + // //o.Address = addr; + // //o.AddressId = addr.Id; + // if (!newAddresses.ContainsKey(o.Address.Address) && addr.InDatabase==false) + // { + // newAddresses.Add(o.Address.Address, addr); + // addr.InDatabase = true; + // } + //} + //foreach (var i in tr.SlpTransactionInputs) + // inputs.Add(i); + inputs.AddRange(tr.SlpTransactionInputs); + //Console.Write("."); + //_log.LogInformation(tr.Hash.ToHex()); + //_slpTrCache.AddOrReplace(tr.Hash.ToHex(), tr); + } + _log.LogInformation("Checking for new addresses..."); + foreach (var o in outputs) + { + if (_usedAddresses.TryGetValue(o.Address.Address, out var value) && !value.InDatabase) + if (!newAddresses.ContainsKey(o.Address.Address)) { - throw; + newAddresses.Add(o.Address.Address, value); + value.InDatabase = true; } - } - foreach (var i in tr.SlpTransactionInputs) - inputs.Add(i); - _slpTrCache.AddOrReplace(tr.Hash.ToHex(), tr); - } - outputs.ForEach(o => { o.AddressId = o.Address.Id;}); + } + + //_log.LogInformation("Setting address ids..."); + //outputs.ForEach(o => { o.AddressId = o.Address.Id;}); { - using var db = new SlpDbContext(_dbOptions); + using var db = new SlpDbContext(_dbOptions); //fast relink based on local _slpTrCache and then bulk insert them - this is possible since we are // settting id on client side + _log.LogInformation("Processing inputs...", batchCounter); var outputsToUpdate = new List(); foreach (var input in inputs) { var outputSlpTx = _slpTrCache.TryGet(input.SourceTxHash.ToHex()); //pointing to non slp transaction - not relevant at the moment - to set bch data we need to gather data from bch indexer - if (outputSlpTx == null) + if (outputSlpTx == null) + { continue; + } //throw new Exception($"Invalid output tx reference {input.SlpSourceTransactionHex}! Make sure slpTrCache is valid!"); var referencedOutput = outputSlpTx.SlpTransactionOutputs.ElementAt(input.VOut); - var outputAddress = GetOrCreateAddress(referencedOutput.Address.Address, input.SlpTransaction.BlockHeight); - if (outputAddress.InDatabase == false) - { - newAddresses.Add(outputAddress.Address, outputAddress); - outputAddress.InDatabase = true; - } + var outputAddress = GetAddress(referencedOutput.Address.Address); if (outputAddress == null) { _log.LogWarning("Input does not have valid slp output"); continue; // } - + if (outputAddress.InDatabase == false) + { + newAddresses.Add(outputAddress.Address, outputAddress); + outputAddress.InDatabase = true; + //throw new Exception($"Cannot find input address from ref output {outputAddress.Address} at tx {input.SourceTxHash.ToHex()}:{input.VOut}"); + } + input.Address = outputAddress; input.AddressId = outputAddress.Id; input.SlpAmount = referencedOutput.Amount; @@ -278,13 +299,14 @@ public async Task CommitBatchToDb( if (!localBatch.Contains(outputSlpTx)) outputsToUpdate.Add(referencedOutput); } + _log.LogInformation("Update slp state..."); //before anything is changed in database make sure that counter is set to first block //this would be probaby better - if(localBlocks.Any()) + if (localBlocks.Any()) await db.UpdateSlpStateAsync(localBlocks.First().Height, localBlocks.First().Hash.ToHex()); if (_databaseBackendType == SD.DatabaseBackendType.POSTGRESQL) //bulk extensions does not support postgre backend yet so we use postgrebulkcopy to insert - { + { try { var dgConnection = db.Database.GetDbConnection(); @@ -576,12 +598,19 @@ private async Task LoadSlpTransactionsCacheFromDb() _usedAddresses.TryAdd(a.Value.Address, a.Value); a.Value.InDatabase = true; } + _addressIndex = _usedAddresses.Any() ? _usedAddresses.Max(a => a.Value.Id) : 0; + + //var addr = GetAddress("simpleledger:qpnemhrgtwnegp0z5d5lm6fqvnj3cpv5jg45rrslgk"); + _log.LogInformation("Adding transaction inputs to transactions..."); foreach (var i in slpTxIns) { var tx = slpTxs.TryGet(i.Value.SlpTransactionId); i.Value.SlpTransaction = tx; - i.Value.Address = allAddresses.TryGet(i.Value.AddressId??-1); + + if (i.Value.AddressId.HasValue && allAddresses.TryGetValue(i.Value.AddressId.Value, out var addr)) + i.Value.Address = addr; + tx.SlpTransactionInputs.Add(i.Value); } _log.LogInformation("Adding transaction outpus to transactions..."); @@ -589,7 +618,10 @@ private async Task LoadSlpTransactionsCacheFromDb() { var tx = slpTxs.TryGet(o.Value.SlpTransactionId); o.Value.SlpTransaction = tx; - o.Value.Address = allAddresses.TryGet(o.Value.AddressId); + + if (allAddresses.TryGetValue(o.Value.AddressId, out var addr)) + o.Value.Address = addr; + //o.Value.Address = allAddresses.TryGet(o.Value.AddressId); tx.SlpTransactionOutputs.Add(o.Value); } _log.LogInformation("Preparing slp transaction cache..."); @@ -837,6 +869,11 @@ ConcurrentDictionary, List>> var slpTr = _slpService.GetSlpTransaction(tr); if (slpTr != null) { + foreach (var o in slpTr.SlpTransactionOutputs) + { + var address = GetOrCreateAddress(o.Address.Address, h); + o.AddressId = address.Id; + } slpTxs.Add(slpTr); _slpTrCache.AddOrReplace(slpTr.Hash.ToHex(), slpTr); if (slpTr.Type == SlpTransactionType.GENESIS && !_tokenMap.ContainsKey(slpTr.Hash.ToHex())) @@ -1074,13 +1111,14 @@ private SlpTransaction CheckNonSlpTransactionForSlpBurn(Transaction tr, int? blo continue; bchAddress = output.ScriptPubKey.GetDestinationAddress(_rpcClient.Network).ToString(); } + var address = GetOrCreateAddress(bchAddress.ToString(), burnTransaction.BlockHeight); burnTransaction.SlpTransactionOutputs.Add( new SlpTransactionOutput { BlockchainSatoshis = output.Value.ToDecimal(MoneyUnit.Satoshi), Amount = 0, - AddressId = -1, - Address = new SlpAddress { Address = bchAddress.ToString(), BlockHeight = burnTransaction.BlockHeight }, + AddressId = address.Id, + Address = address, VOut = i, SlpTransaction = burnTransaction, }); @@ -1106,7 +1144,7 @@ private SlpTransaction CheckNonSlpTransactionForSlpBurn(Transaction tr, int? blo outAddress = output.Address; else { - outAddress = new SlpAddress { Address = address, BlockHeight = burnTransaction.BlockHeight }; + outAddress = new SlpAddress { Address = address }; //if (!_usedAddresses.TryGetValue(address, out var usedAddr)) //{ // var nextId = _usedAddresses.Any() ? _usedAddresses.Max(a => a.Value.Id) + 1 : 1; @@ -1457,7 +1495,7 @@ async Task CheckForBlockReorg(Block newBlock, SlpDbContext db) return result; } - public async Task DeleteSlpTransactionsNewerThanBlockHeightRawPostgreAsync(int blockHeight, ILogger log = null, int commandsTimeout = SD.TimeConsumingQueryTimeoutSeconds) + public async Task DeleteSlpTransactionsNewerThanBlockHeightRawPostgreAsync(int blockHeight, int commandsTimeout = SD.TimeConsumingQueryTimeoutSeconds) { using var db = new SlpDbContext(_dbOptions); db.Database.SetCommandTimeout(commandsTimeout); @@ -1469,32 +1507,60 @@ public async Task DeleteSlpTransactionsNewerThanBlockHeightRawPostgreAsync(int b pgConnection.Open(); { - log?.LogInformation("Reseting all outputs spent in inputs >= than block height {0}", blockHeight); + _log.LogInformation("Reseting all outputs spent in inputs >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); - cmd.CommandText = - $@"update ""SlpTransactionOutput"" - set ""NextInputId"" = null + cmd.CommandText = +$@"select o.""Id"" from ""SlpTransactionOutput"" o left join ""SlpTransactionInput"" i on o.""NextInputId"" = i.""Id"" inner join ""SlpTransaction"" t on i.""SlpTransactionId"" = t.""Id"" -where o.""NextInputId"" <> null and not(t.""BlockHeight"" is null) and t.""BlockHeight"" >= {blockHeight}"; - var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Reset {0} outputs spent in inputs >= than block height {0}", count); +where not(o.""NextInputId"" is null) and not(t.""BlockHeight"" is null) and t.""BlockHeight"" >= {blockHeight} + "; + _log.LogInformation(cmd.CommandText); + var ids = new List(); + using (var reader = await cmd.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + ids.Add(reader.GetInt32(0)); + } + } + _log.LogInformation("Read {0} ids from db.", ids.Count); + for (var i = 0; i < ids.Count; i += 50) + { + var idSet = ids.Skip(i).Take(50); + if (!idSet.Any()) + break; + var idStrSet = idSet.MergeToDelimitedString(); + _log.LogInformation($"Updating outputs {idStrSet}..."); + cmd.CommandText = @$"update ""SlpTransactionOutput"" set ""NextInputId""=null where ""Id"" in ({idStrSet})"; + var res = await cmd.ExecuteNonQueryAsync(); + } + + // cmd.CommandText = + // $@"update ""SlpTransactionOutput"" + // set ""NextInputId"" = null + //from ""SlpTransactionOutput"" o + //left join ""SlpTransactionInput"" i on o.""NextInputId"" = i.""Id"" + //inner join ""SlpTransaction"" t on i.""SlpTransactionId"" = t.""Id"" + //where not(o.""NextInputId"" is null) and not(t.""BlockHeight"" is null) and t.""BlockHeight"" >= {blockHeight}"; + // var count = await cmd.ExecuteNonQueryAsync(); + _log.LogInformation("Reset {0} outputs spent in inputs >= than block height {1}", ids.Count, blockHeight); } { - log?.LogInformation("Deleting all outputs >= than block height {0}", blockHeight); + _log?.LogInformation("Deleting all outputs >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); cmd.CommandText = $@"delete from ""SlpTransactionOutput"" o where o.""SlpTransactionId"" in (select ""Id"" from ""SlpTransaction"" where ""BlockHeight"" > {blockHeight} and ""Id"" = o.""SlpTransactionId"" )"; var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} outputs", count); + _log?.LogInformation("Deleted {0} outputs", count); } { - log?.LogInformation("Deleting all inputs >= than block height {0}", blockHeight); + _log?.LogInformation("Deleting all inputs >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); cmd.CommandText = $@"delete from @@ -1502,39 +1568,40 @@ where o.""SlpTransactionId"" in where i.""SlpTransactionId"" in (select ""Id"" from ""SlpTransaction"" where ""BlockHeight"" > {blockHeight} and ""Id"" = i.""SlpTransactionId"" )"; var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} inputs", count); + _log?.LogInformation("Deleted {0} inputs", count); } { - log?.LogInformation("Deleting all txs >= than block height {0}", blockHeight); + _log?.LogInformation("Deleting all txs >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); cmd.CommandText = $@"delete from ""SlpTransaction"" t where t.""BlockHeight"" >= {blockHeight}"; var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} txs", count); + _log?.LogInformation("Deleted {0} txs", count); } - { - log?.LogInformation("Deleting all addresses >= than block height {0}", blockHeight); - using var cmd = dbConnection.CreateCommand(); - cmd.CommandText = $@"delete from ""SlpAddress"" a where a.""BlockHeight"" >= {blockHeight}"; - var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} txs", count); - } + //leave addresses in database - no need to delete and read then since they are mapped via dictionary + //{ + // _log?.LogInformation("Deleting all addresses >= than block height {0}", blockHeight); + // using var cmd = dbConnection.CreateCommand(); + // cmd.CommandText = $@"delete from ""SlpAddress"" a where a.""BlockHeight"" >= {blockHeight}"; + // var count = await cmd.ExecuteNonQueryAsync(); + // _log?.LogInformation("Deleted {0} txs", count); + //} { - log?.LogInformation("Deleting all tokens >= than block height {0}", blockHeight); + _log?.LogInformation("Deleting all tokens >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); cmd.CommandText = $@"delete from ""SlpToken"" a where a.""BlockHeight"" >= {blockHeight}"; var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} txs", count); + _log?.LogInformation("Deleted {0} txs", count); } { - log?.LogInformation("Deleting all blocks >= than block height {0}", blockHeight); + _log?.LogInformation("Deleting all blocks >= than block height {0}", blockHeight); using var cmd = dbConnection.CreateCommand(); cmd.CommandText = $@"delete from ""SlpBlock"" b where b.""Height"" >= {blockHeight}"; var count = await cmd.ExecuteNonQueryAsync(); - log?.LogInformation("Deleted {0} blocks", count); + _log?.LogInformation("Deleted {0} blocks", count); } ////token are never deleted - once inserted into database it can stay there since hex is key and diff --git a/Slp.Indexer/Slp.Indexer.csproj b/Slp.Indexer/Slp.Indexer.csproj index 682b03d..2ecaa7e 100644 --- a/Slp.Indexer/Slp.Indexer.csproj +++ b/Slp.Indexer/Slp.Indexer.csproj @@ -2,7 +2,7 @@ net5.0 - 1.0.0 + 1.0.1 true Slp indexer that listens to BCH node and builds SQL databases with SLP data. c5ef8d94-2d0f-4b35-8176-f9f2ea8449aa diff --git a/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.Designer.cs b/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.Designer.cs new file mode 100644 index 0000000..58773ff --- /dev/null +++ b/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.Designer.cs @@ -0,0 +1,358 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Slp.Common.DataAccess; + +namespace Slp.Migrations.POSTGRESQL.Migrations +{ + [DbContext(typeof(SlpDbContext))] + [Migration("20220203112100_RemoveAddressBlockHeightFromDb")] + partial class RemoveAddressBlockHeightFromDb + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.11") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("Slp.Common.Models.DbModels.DatabaseState", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("BlockTip") + .HasColumnType("integer"); + + b.Property("BlockTipHash") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("LastStatusUpdate") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.ToTable("SlpDatabaseState"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpAddress", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Address") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Address") + .IsUnique(); + + b.ToTable("SlpAddress"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpBlock", b => + { + b.Property("Height") + .HasColumnType("integer"); + + b.Property("BlockTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Hash") + .HasMaxLength(32) + .HasColumnType("bytea"); + + b.Property("IsSlp") + .HasColumnType("boolean"); + + b.HasKey("Height"); + + b.HasIndex("Hash"); + + b.ToTable("SlpBlock"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpToken", b => + { + b.Property("Hash") + .HasMaxLength(32) + .HasColumnType("bytea"); + + b.Property("ActiveMint") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("BlockHeight") + .HasColumnType("integer"); + + b.Property("BlockLastActiveMint") + .HasColumnType("integer"); + + b.Property("BlockLastActiveSend") + .HasColumnType("integer"); + + b.Property("CirculatingSupply") + .HasColumnType("numeric(38,0)"); + + b.Property("Decimals") + .HasColumnType("integer"); + + b.Property("DocumentSha256Hex") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DocumentUri") + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("LastActiveSend") + .HasColumnType("integer"); + + b.Property("MintingBatonStatus") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Name") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("SatoshisLockedUp") + .HasColumnType("integer"); + + b.Property("Symbol") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TotalBurned") + .HasColumnType("numeric(38,0)"); + + b.Property("TotalMinted") + .HasColumnType("numeric(38,0)"); + + b.Property("TxnsSinceGenesis") + .HasColumnType("integer"); + + b.Property("ValidAddresses") + .HasColumnType("integer"); + + b.Property("ValidTokenUtxos") + .HasColumnType("integer"); + + b.Property("VersionType") + .HasColumnType("integer"); + + b.HasKey("Hash"); + + b.HasIndex("BlockHeight"); + + b.ToTable("SlpToken"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransaction", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("AdditionalTokenQuantity") + .HasColumnType("numeric(38,0)"); + + b.Property("BlockHeight") + .HasColumnType("integer"); + + b.Property("Hash") + .HasMaxLength(32) + .HasColumnType("bytea"); + + b.Property("InvalidReason") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("MintBatonVOut") + .HasColumnType("integer"); + + b.Property("SlpTokenId") + .HasMaxLength(32) + .HasColumnType("bytea"); + + b.Property("SlpTokenType") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TokenInputSum") + .HasColumnType("numeric(38,0)"); + + b.Property("TokenOutputSum") + .HasColumnType("numeric(38,0)"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BlockHeight"); + + b.HasIndex("Hash"); + + b.HasIndex("SlpTokenId"); + + b.ToTable("SlpTransaction"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransactionInput", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("AddressId") + .HasColumnType("integer"); + + b.Property("BlockchainSatoshis") + .HasColumnType("numeric(38,0)"); + + b.Property("SlpAmount") + .HasColumnType("numeric(38,0)"); + + b.Property("SlpTransactionId") + .HasColumnType("bigint"); + + b.Property("SourceTxHash") + .HasMaxLength(32) + .HasColumnType("bytea"); + + b.Property("VOut") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("SlpTransactionId"); + + b.ToTable("SlpTransactionInput"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransactionOutput", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("AddressId") + .HasMaxLength(128) + .HasColumnType("integer"); + + b.Property("Amount") + .HasColumnType("numeric(38,0)"); + + b.Property("BlockchainSatoshis") + .HasColumnType("numeric(38,0)"); + + b.Property("NextInputId") + .HasColumnType("bigint"); + + b.Property("SlpTransactionId") + .HasColumnType("bigint"); + + b.Property("VOut") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("NextInputId"); + + b.HasIndex("SlpTransactionId"); + + b.ToTable("SlpTransactionOutput"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpToken", b => + { + b.HasOne("Slp.Common.Models.DbModels.SlpBlock", "Block") + .WithMany() + .HasForeignKey("BlockHeight"); + + b.Navigation("Block"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransaction", b => + { + b.HasOne("Slp.Common.Models.DbModels.SlpBlock", "Block") + .WithMany() + .HasForeignKey("BlockHeight"); + + b.HasOne("Slp.Common.Models.DbModels.SlpToken", "SlpToken") + .WithMany("Transactions") + .HasForeignKey("SlpTokenId"); + + b.Navigation("Block"); + + b.Navigation("SlpToken"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransactionInput", b => + { + b.HasOne("Slp.Common.Models.DbModels.SlpAddress", "Address") + .WithMany() + .HasForeignKey("AddressId"); + + b.HasOne("Slp.Common.Models.DbModels.SlpTransaction", "SlpTransaction") + .WithMany("SlpTransactionInputs") + .HasForeignKey("SlpTransactionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Address"); + + b.Navigation("SlpTransaction"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransactionOutput", b => + { + b.HasOne("Slp.Common.Models.DbModels.SlpAddress", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Slp.Common.Models.DbModels.SlpTransactionInput", "NextInput") + .WithMany() + .HasForeignKey("NextInputId"); + + b.HasOne("Slp.Common.Models.DbModels.SlpTransaction", "SlpTransaction") + .WithMany("SlpTransactionOutputs") + .HasForeignKey("SlpTransactionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Address"); + + b.Navigation("NextInput"); + + b.Navigation("SlpTransaction"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpToken", b => + { + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Slp.Common.Models.DbModels.SlpTransaction", b => + { + b.Navigation("SlpTransactionInputs"); + + b.Navigation("SlpTransactionOutputs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.cs b/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.cs new file mode 100644 index 0000000..535e153 --- /dev/null +++ b/Slp.Migrations.POSTGRESQL/Migrations/20220203112100_RemoveAddressBlockHeightFromDb.cs @@ -0,0 +1,45 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Slp.Migrations.POSTGRESQL.Migrations +{ + public partial class RemoveAddressBlockHeightFromDb : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_SlpAddress_SlpBlock_BlockHeight", + table: "SlpAddress"); + + migrationBuilder.DropIndex( + name: "IX_SlpAddress_BlockHeight", + table: "SlpAddress"); + + migrationBuilder.DropColumn( + name: "BlockHeight", + table: "SlpAddress"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BlockHeight", + table: "SlpAddress", + type: "integer", + maxLength: 128, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_SlpAddress_BlockHeight", + table: "SlpAddress", + column: "BlockHeight"); + + migrationBuilder.AddForeignKey( + name: "FK_SlpAddress_SlpBlock_BlockHeight", + table: "SlpAddress", + column: "BlockHeight", + principalTable: "SlpBlock", + principalColumn: "Height", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/Slp.Migrations.POSTGRESQL/Migrations/SlpDbContextModelSnapshot.cs b/Slp.Migrations.POSTGRESQL/Migrations/SlpDbContextModelSnapshot.cs index f82772b..2bac525 100644 --- a/Slp.Migrations.POSTGRESQL/Migrations/SlpDbContextModelSnapshot.cs +++ b/Slp.Migrations.POSTGRESQL/Migrations/SlpDbContextModelSnapshot.cs @@ -47,17 +47,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Address") .HasColumnType("text"); - b.Property("BlockHeight") - .HasMaxLength(128) - .HasColumnType("integer"); - b.HasKey("Id"); b.HasIndex("Address") .IsUnique(); - b.HasIndex("BlockHeight"); - b.ToTable("SlpAddress"); }); @@ -279,15 +273,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("SlpTransactionOutput"); }); - modelBuilder.Entity("Slp.Common.Models.DbModels.SlpAddress", b => - { - b.HasOne("Slp.Common.Models.DbModels.SlpBlock", "Block") - .WithMany() - .HasForeignKey("BlockHeight"); - - b.Navigation("Block"); - }); - modelBuilder.Entity("Slp.Common.Models.DbModels.SlpToken", b => { b.HasOne("Slp.Common.Models.DbModels.SlpBlock", "Block")