private async Task SaveAndRemoveOldBlocksAsync(long blockId)
        {
            using (BlockchainDbContext context = new BlockchainDbContext())
            {
                long maxId = await context.Blocks.MaxAsync(opt => opt.Id).ConfigureAwait(false);

                byte limit = 100;
                if (maxId < blockId)
                {
                    return;
                }
                for (long i = blockId; i < maxId; i += limit)
                {
                    var blocks = await context.Blocks
                                 .Include(opt => opt.BlockSegments)
                                 .ThenInclude(opt => opt.SegmentHeader)
                                 .Include(opt => opt.Header)
                                 .Where(opt => opt.Id > i)
                                 .Take(limit)
                                 .ToListAsync().ConfigureAwait(false);

                    var obsoleteBlocks = blocks.Select(opt => new ObsoleteBlock
                    {
                        Id   = opt.Id,
                        Data = ObjectSerializer.ObjectToByteArray(BlockBuilder.GetBlockVm(opt))
                    });
                    await context.ObsoleteBlocks.AddRangeAsync(obsoleteBlocks).ConfigureAwait(false);

                    await context.SaveChangesAsync().ConfigureAwait(false);
                }
                NpgsqlParameter blockIdParam = new NpgsqlParameter("blockId", blockId);
                RawSqlString    sqlString    = new RawSqlString(@"DELETE FROM ""Blocks"" WHERE ""Id"" > @blockId");
                await context.Database.ExecuteSqlCommandAsync(sqlString, blockIdParam).ConfigureAwait(false);
            }
        }
예제 #2
0
        public List <TransactionView> GetTransactions(int blockHeight = 0)
        {
            var transactionViews = new List <TransactionView>();
            var walletAddresses  = Addresses.Select(a => a.Key).ToArray();

            using (BlockchainDbContext db = new BlockchainDbContext())
            {
                var transactions = db.Transactions.Include(t => t.Inputs).Include(t => t.Outputs).Where(t => t.BlockHeight > blockHeight && (t.Inputs.Select(i => i.Key).Intersect(walletAddresses).Any() || t.Outputs.Select(i => i.Key).Intersect(walletAddresses).Any())).OrderByDescending(t => t.BlockHeight).ThenByDescending(t => t.Id).Take(10).ToList();

                foreach (var transaction in transactions)
                {
                    var isIncome = transaction.Inputs == null ? true : transaction.Inputs.Select(i => i.Key).All(o => !walletAddresses.Contains(o));
                    transactionViews.Add(new TransactionView()
                    {
                        Inputs = transaction.Inputs.Select(i => new IOView()
                        {
                            Key = i.Key, Amount = BalanceHelper.GetBalanceOfAddress(i.Key)
                        }).ToArray(),
                        Message     = transaction.Data == null ? string.Empty : Encoding.Unicode.GetString(transaction.Data),
                        BlockHeight = transaction.BlockHeight,
                        Outputs     = transaction.Outputs.Select(o => new IOView()
                        {
                            Key = o.Key, Amount = o.Amount
                        }).ToArray(),
                        Amount = transaction.Inputs == null || transaction.Inputs.Count == 0 ? transaction.Outputs.Select(o => o.Amount).Sum() : isIncome?transaction.Outputs.Select(o => o.Amount).Sum() : -transaction.Outputs.Where(o => !walletAddresses.Contains(o.Key)).Select(o => o.Amount).Sum(),
                                     IsIncome = isIncome
                    });
                }
            }
            return(transactionViews.OrderBy(t => t.BlockHeight).ToList());
        }
예제 #3
0
 public BlockChain(Wallet wallet)
 {
     Wallet   = wallet;
     _memPool = new List <Transaction>();
     BlockchainDbContext.InitializeMigrations();
     _networkSynchronizer = new NetworkSynchronizer(this);
 }
예제 #4
0
 private static async Task ApplyMigrationsAsync()
 {
     try
     {
         DbContextOptionsBuilder <MessengerDbContext> optionsBuilder = new DbContextOptionsBuilder <MessengerDbContext>();
         optionsBuilder.UseNpgsql(NodeSettings.Configs.MessengerDbConnection.ToString());
         using (MessengerDbContext messengerContext = new MessengerDbContext(optionsBuilder.Options))
         {
             await messengerContext.Database.MigrateAsync().ConfigureAwait(false);
         }
         BlockchainDbContext.InitConnectionString(NodeSettings.Configs.BlockchainDbConnection.ToString());
         using (BlockchainDbContext blockchainContext = new BlockchainDbContext())
         {
             await blockchainContext.Database.MigrateAsync().ConfigureAwait(false);
         }
         DbContextOptionsBuilder <AdminDbContext> adminDbContextOptBuilder = new DbContextOptionsBuilder <AdminDbContext>();
         adminDbContextOptBuilder.UseNpgsql(NodeSettings.Configs.AdminDbConnection.ToString());
         using (AdminDbContext adminDbContext = new AdminDbContext(adminDbContextOptBuilder.Options))
         {
             adminDbContext.Database.MigrateAsync().Wait(TimeSpan.FromSeconds(1));
         }
         await SqlFunctionsUpdator.UpdateFunctionsAsync("DbBackup").ConfigureAwait(false);
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex);
     }
 }
예제 #5
0
 public Block LastBlock()
 {
     using (BlockchainDbContext db = new BlockchainDbContext())
     {
         return(db.Blocks.OrderBy(b => b.Height).LastOrDefault());
     }
 }
예제 #6
0
        public Block IsBlockValid(Block block)
        {
            if (block == null)
            {
                return(block);
            }
            using (BlockchainDbContext db = new BlockchainDbContext())
            {
                var chainUnderBlock = db.Blocks.Include("Transactions.Outputs").Include("Transactions.Inputs").Where(b => b.Height < block.Height).OrderByDescending(b => b.Height).ToList();

                if (chainUnderBlock.Count() > 0)
                {
                    var baseHash = block.PreviousHash;
                    foreach (var actBlock in chainUnderBlock)
                    {
                        actBlock.MerkleTreeHash = actBlock.CreateMerkleTreeHash();
                        var hashFromBlock = HashHelper.ByteArrayToHexString(actBlock.GenerateHash());

                        if (hashFromBlock != baseHash)
                        {
                            return(actBlock);
                        }
                        baseHash = actBlock.PreviousHash;
                    }
                }
            }
            return(null);
        }
예제 #7
0
        public async Task <KeyVm> GetUserKeyAsync(long publicKeyId, long userId, bool isSignKey)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                KeyType keyType = isSignKey ? KeyType.SignAsymKey : KeyType.EncryptionAsymKey;
                Key     key     = await context.Keys.FirstOrDefaultAsync(opt => opt.UserId == userId && opt.KeyId == publicKeyId && opt.Type == keyType).ConfigureAwait(false);

                KeyVm userKey = KeyConverter.GetKeyVm(key);
                if (userKey == null)
                {
                    using (BlockchainDbContext blockchainCtx = new BlockchainDbContext())
                    {
                        var userKeys = await blockchainCtx.BlockSegments
                                       .Where(opt => opt.SegmentHeader.Type == ObjectsLibrary.Blockchain.BlockSegmentType.NewUserKeys && opt.SegmentHeader.Uid == userId)
                                       .Where(opt => ((NewUserKeysBlockData)opt.PublicData).Keys.Any(p => p.KeyId == publicKeyId && p.Type == keyType))
                                       .Select(opt => (NewUserKeysBlockData)opt.PublicData)
                                       .FirstOrDefaultAsync()
                                       .ConfigureAwait(false);

                        if (userKeys == null)
                        {
                            throw new ObjectDoesNotExistsException();
                        }
                        userKey = userKeys.Keys.FirstOrDefault(opt => opt.KeyId == publicKeyId);
                    }
                }
                return(userKey);
            }
        }
예제 #8
0
 private BlockVm GenerateBlock(object @object)
 {
     try
     {
         BlockVm       block = (BlockVm)@object;
         Task <byte[]> hashGenerationProcess = new Task <byte[]>((obj) => BlockHashing.ComputeBlockHashPoW((BlockVm)obj), block);
         hashGenerationProcess.Start();
         while (!hashGenerationProcess.IsCompleted)
         {
             blockGenerationCancellToken.ThrowIfCancellationRequested();
             Task.Delay(250).Wait();
         }
         block.Header.Hash      = hashGenerationProcess.Result;
         block.Header.Sign      = Encryptor.GetSign(BlockHashing.GetBlockBytes(block), NodeData.Instance.NodeKeys.SignPrivateKey, NodeData.Instance.NodeKeys.Password);
         block.Header.SignKeyId = NodeData.Instance.NodeKeys.KeyId;
         using (BlockchainDbContext context = new BlockchainDbContext())
         {
             var resultBlock = context.Add(BlockBuilder.GetBlock(block));
             context.SaveChanges();
             return(BlockBuilder.GetBlockVm(resultBlock.Entity));
         }
     }
     catch (Exception ex)
     {
         throw new BlockGenerationException("An error occurred while generating the block.", ex);
     }
 }
예제 #9
0
 public string BlockchainHash(int blockHeight)
 {
     using (BlockchainDbContext db = new BlockchainDbContext())
     {
         var blockHashes = db.Blocks.Where(b => b.Height <= blockHeight).Select(b => b.PreviousHash).ToList();
         return(HashHelper.Sha256(string.Join("", blockHashes)));
     }
 }
예제 #10
0
 public List <string> BlockHashes()
 {
     using (BlockchainDbContext db = new BlockchainDbContext())
     {
         var blockHashes = db.Blocks.Select(b => b.PreviousHash).ToList();
         return(blockHashes);
     }
 }
예제 #11
0
 public static bool EverUsedAsInput(string address)
 {
     if (!string.IsNullOrEmpty(address))
     {
         using (BlockchainDbContext db = new BlockchainDbContext())
         {
             return(db.Transactions.Any(t => t.Inputs.Select(i => i.Key).Contains(address)));
         }
     }
     return(false);
 }
예제 #12
0
 public List <Block> GetBlocks(List <int> blockHeights, bool includeTransactions = false)
 {
     using (BlockchainDbContext db = new BlockchainDbContext())
     {
         if (includeTransactions)
         {
             return(db.Blocks.Include("Transactions.Outputs").Include("Transactions.Inputs").Where(b => blockHeights.Contains(b.Height)).ToList());
         }
         return(db.Blocks.Where(b => blockHeights.Contains(b.Height)).ToList());
     }
 }
예제 #13
0
 public Block GetBlock(int height, bool includeTransactions = false)
 {
     using (BlockchainDbContext db = new BlockchainDbContext())
     {
         if (includeTransactions)
         {
             return(db.Blocks.Include("Transactions.Outputs").Include("Transactions.Inputs").FirstOrDefault(b => b.Height == height));
         }
         return(db.Blocks.FirstOrDefault(b => b.Height == height));
     }
 }
예제 #14
0
        public void AddBlocks(List <Block> blocks)
        {
            var start = DateTime.Now;

            using (BlockchainDbContext db = new BlockchainDbContext())
            {
                db.ChangeTracker.AutoDetectChangesEnabled = false;
                db.Blocks.AddRange(blocks);
                db.SaveChangesAsync();
            }
            var ts = DateTime.Now - start;
        }
예제 #15
0
        public static long GetBalanceOfAddress(string address)
        {
            long balance = 0;

            if (!string.IsNullOrEmpty(address))
            {
                using (BlockchainDbContext db = new BlockchainDbContext())
                {
                    balance = db.Outputs.Where(o => o.Key == address).Select(t => t.Amount).Sum();
                }
            }
            return(balance);
        }
        private async Task DownloadBlockchainAsync(long startId)
        {
            var webInfo = await LicensorClient.Instance.GetBlockchainInfoAsync().ConfigureAwait(false);

            BlockchainDataRestorer dataRestorer = new BlockchainDataRestorer();

            try
            {
                BlockchainInfo ownInfo = await BlockchainReadService.GetBlockchainInformationAsync().ConfigureAwait(false);

                List <BlockVm> newBlocks = default;
                for (long i = startId; i < webInfo.Count; i += 100)
                {
                    if (webInfo.Count - ownInfo.Count > 100)
                    {
                        newBlocks = await LicensorClient.Instance.GetBlockchainBlocksAsync(i, i + 100).ConfigureAwait(false);
                    }
                    else
                    {
                        newBlocks = await LicensorClient.Instance.GetBlockchainBlocksAsync(ownInfo.Count, webInfo.Count).ConfigureAwait(false);
                    }
                    if (newBlocks != null)
                    {
                        foreach (BlockVm block in newBlocks)
                        {
                            using (BlockchainDbContext context = new BlockchainDbContext())
                            {
                                try
                                {
                                    await context.Blocks.AddAsync(BlockBuilder.GetBlock(block)).ConfigureAwait(false);

                                    await context.SaveChangesAsync().ConfigureAwait(false);

                                    await dataRestorer.SaveBlockDataAsync(block).ConfigureAwait(false);
                                }
                                catch (Exception ex)
                                {
                                    Logger.WriteLog(ex);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
            }
        }
예제 #17
0
 public static bool EverUsedAsInput(string[] addresses)
 {
     if (addresses != null)
     {
         using (BlockchainDbContext db = new BlockchainDbContext())
         {
             foreach (var address in addresses)
             {
                 if (db.Transactions.Any(t => t.Inputs.Select(i => i.Key).Contains(address)))
                 {
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
예제 #18
0
        public List <Output> GetBalancesPerOutput()
        {
            var balancesPerAddress = new Dictionary <string, decimal>();
            var walletAddresses    = Addresses.Select(a => a.Key).ToArray();

            using (BlockchainDbContext db = new BlockchainDbContext())
            {
                var usedOutputs        = db.Outputs.Where(o => walletAddresses.Contains(o.Key)).ToList();
                var usedInputs         = db.Inputs.Where(o => walletAddresses.Contains(o.Key)).Select(i => i.Key).ToList();
                var outputsWithBalance = new List <Output>();
                foreach (var output in usedOutputs)
                {
                    if (!usedInputs.Contains(output.Key))
                    {
                        outputsWithBalance.Add(output);
                    }
                }
                return(outputsWithBalance);
            }
        }
        private async Task RestoreOldBlockchainDataAsync()
        {
            using (BlockchainDbContext context = new BlockchainDbContext())
            {
                long maxId = await context.ObsoleteBlocks.MaxAsync(opt => opt.Id).ConfigureAwait(false);

                long minId = await context.ObsoleteBlocks.MinAsync(opt => opt.Id).ConfigureAwait(false);

                byte limit = 100;
                for (long i = minId; i < maxId; i += limit)
                {
                    var obsoleteBlocks = await context.ObsoleteBlocks
                                         .Where(block => block.Id >= i)
                                         .Take(limit)
                                         .ToListAsync().ConfigureAwait(false);

                    List <BlockVm>        blocks             = obsoleteBlocks.Select(block => ObjectSerializer.ByteArrayToObject <BlockVm>(block.Data)).ToList();
                    List <BlockSegmentVm> allSegments        = new List <BlockSegmentVm>();
                    List <BlockSegmentVm> noexistentSegments = new List <BlockSegmentVm>();
                    foreach (var block in blocks)
                    {
                        allSegments.AddRange(block.BlockSegments);
                    }
                    var segmentsCondition = PredicateBuilder.New <BlockSegment>();
                    segmentsCondition = allSegments.Aggregate(segmentsCondition,
                                                              (current, value) => current.Or(opt => opt.SegmentHash.SequenceEqual(value.SegmentHash)).Expand());
                    var existentSegments = await context.BlockSegments.Where(segmentsCondition).ToListAsync().ConfigureAwait(false);

                    noexistentSegments = allSegments
                                         .Where(segment => !existentSegments.Any(exSegment => segment.SegmentHash.SequenceEqual(exSegment.SegmentHash)))
                                         ?.ToList();
                    if (!noexistentSegments.IsNullOrEmpty())
                    {
                        BlockGenerationHelper.Instance.AddSegments(noexistentSegments);
                    }
                }
                NpgsqlParameter blockIdParam = new NpgsqlParameter("blockId", minId);
                RawSqlString    sqlString    = new RawSqlString(@"DELETE FROM ""ObsoleteBlocks"" WHERE ""Id"" >= @blockId");
                await context.Database.ExecuteSqlCommandAsync(sqlString, blockIdParam).ConfigureAwait(false);
            }
        }
예제 #20
0
        public static long GetBalanceOfAddresses(string[] addresses)
        {
            long balance = 0;

            if (addresses != null)
            {
                using (BlockchainDbContext db = new BlockchainDbContext())
                {
                    var usedOutputs = db.Outputs.Where(o => addresses.Contains(o.Key)).ToList();
                    var usedInputs  = db.Inputs.Where(o => addresses.Contains(o.Key)).Select(i => i.Key).ToList();
                    foreach (var output in usedOutputs)
                    {
                        if (!usedInputs.Contains(output.Key))
                        {
                            balance += output.Amount;
                        }
                    }
                }
            }
            return(balance);
        }
예제 #21
0
        private void miningBlocks()
        {
            while (_isMining)
            {
                if (_networkSynchronizer.IsSynced)
                {
                    var lastBlock = LastBlock();

                    lock (_memPool)
                    {
                        var miningAddress = Wallet.NewAddress();
                        using (BlockchainDbContext db = new BlockchainDbContext())
                        {
                            var mempoolHashes = _memPool.Select(m => m.GenerateHash());
                            var existingTransactionsInBlockchain = db.Transactions.Where(t => mempoolHashes.Contains(t.Hash)).ToList();
                            existingTransactionsInBlockchain.ForEach(t => _memPool.Remove(_memPool.First(m => m.Hash == t.Hash)));
                            var transactionsInBlock = _memPool.OrderByDescending(t => t.TransactionFee).Take(100).ToList();
                            transactionsInBlock.Insert(0, new Transaction(null, Wallet, new[] { new Output(miningAddress.Key, MiningReward) }.ToList()));
                            _nextBlock = lastBlock == null ? new Block(1, null, transactionsInBlock) : new Block(lastBlock.Height + 1, HashHelper.ByteArrayToHexString(lastBlock.GenerateHash()), transactionsInBlock);
                        }
                    }
                    _nextBlock.MineBlock(CalculateDifficulty(_nextBlock));
                    if (AddBlock(_nextBlock))
                    {
                        BlockchainConsole.WriteLine($"MINED BLOCK: {_nextBlock}", ConsoleEventType.MINEDBLOCK);
                    }
                    else
                    {
                        BlockchainConsole.WriteLine($"MINING FAILED: {_nextBlock}", ConsoleEventType.MININGFAILED);
                    }
                }
                else
                {
                    Task.Delay(500);
                }
            }
        }
예제 #22
0
 public TransactionRepository(BlockchainDbContext context) : base(context)
 {
 }
예제 #23
0
        private async void syncBlockchains(List <NodeConnection> notSyncNodeConnections, Block lastBlock)
        {
            var tasks = new List <Task <List <Transaction> > >();

            foreach (var connection in notSyncNodeConnections)
            {
                var lastBlockHeight = await connection.LastBlockHeight();

                if (lastBlockHeight > lastBlock.Height)
                {
                    var conBlockHashes = await connection.BlockHashes();

                    if (conBlockHashes != null)
                    {
                        var localBlockHashes = _blockChain.BlockHashes();
                        var smallerListEnd   = conBlockHashes.Count < localBlockHashes.Count ? conBlockHashes.Count : localBlockHashes.Count;
                        var indexNotSame     = 0;
                        for (int i = 0; i < smallerListEnd; i++)
                        {
                            if (conBlockHashes[i] != localBlockHashes[i])
                            {
                                indexNotSame = i + 1;
                                break;
                            }
                        }
                        if (indexNotSame > 0)
                        {
                            try
                            {
                                if (conBlockHashes.Count - indexNotSame < 50)
                                {
                                    var alternateBlockChain = await connection.GetBlocks(Enumerable.Range(indexNotSame, conBlockHashes.Count + 1).ToList());

                                    using (BlockchainDbContext db = new BlockchainDbContext())
                                    {
                                        var blocksToDelete = db.Blocks.Where(b => b.Height >= indexNotSame).ToList();
                                        blocksToDelete.ForEach(b => db.Blocks.Remove(b));
                                        db.SaveChanges();
                                        alternateBlockChain.ForEach(b => db.Blocks.Add(b));
                                        db.SaveChanges();
                                    }
                                }
                                else
                                {
                                    if (_blockChain.NextBlock != null)
                                    {
                                        _blockChain.NextBlock.StopMining();
                                        await Task.Delay(5000);
                                    }
                                    using (BlockchainDbContext db = new BlockchainDbContext())
                                    {
                                        var blocksToDelete = db.Blocks.ToList();
                                        blocksToDelete.ForEach(b => db.Blocks.Remove(b));
                                        db.SaveChanges();
                                    }
                                }
                            }
                            catch (Exception exc)
                            {
                            }
                        }
                    }
                }
            }
        }
예제 #24
0
 public bool AddBlock(Block block)
 {
     if (block == null)
     {
         return(false);
     }
     //Check if Proof of Work is correct
     if (block.Difficulty > BigInteger.Log(new BigInteger(block.GenerateHash().Concat(new byte[] { 0, 0 }).ToArray())))
     {
         //Check if difficulty correct
         if (block.Difficulty == CalculateDifficulty(block))
         {
             //Check if MerkleTree from transactions is correct
             if (block.MerkleTreeHash == block.CreateMerkleTreeHash())
             {
                 //Check if only one Coinbase transaction
                 if (block.Transactions.Count(t => t.Inputs == null || (t.Inputs != null && t.Inputs.Count == 0)) == 1)
                 {
                     //Check if first transaction is coinbase and the output of the transaction is mining reward and transaction fee not more not les
                     if (block.Transactions.Count > 0 && block.Transactions.First().Outputs.Count == 1 && block.Transactions.First().Outputs.First().Amount == (block.Transactions.Select(t => t.TransactionFee).Sum() + MiningReward))
                     {
                         //Check signatures and validity of transactions
                         bool transactionsValid = true;
                         if (block.Transactions != null)
                         {
                             var inputAddresses = new List <string>();
                             foreach (var actTransaction in block.Transactions)
                             {
                                 if (actTransaction.Inputs != null)
                                 {
                                     inputAddresses.AddRange(actTransaction.Inputs.Select(i => i.Key));
                                 }
                             }
                             foreach (var transaction in block.Transactions)
                             {
                                 if (!transaction.Verify())
                                 {
                                     transactionsValid = false;
                                     break;
                                 }
                                 else if (inputAddresses.Any(i => transaction.Inputs.Select(ip => ip.Key).Contains(i)))
                                 {
                                     transactionsValid = false;
                                     break;
                                 }
                             }
                         }
                         if (transactionsValid)
                         {
                             using (BlockchainDbContext db = new BlockchainDbContext())
                             {
                                 var existingBlock = db.Blocks.FirstOrDefault(b => b.Height == block.Height);
                                 if (existingBlock == null)
                                 {
                                     var findLastBlock = block.Height == 1 ? null : db.Blocks.FirstOrDefault(b => b.Height == block.Height - 1);
                                     if (block.Height == 1 || (findLastBlock != null && HashHelper.ByteArrayToHexString(findLastBlock.GenerateHash()) == block.PreviousHash))
                                     {
                                         db.Blocks.Add(block);
                                         db.SaveChanges();
                                         foreach (var transactionToDelete in block.Transactions)
                                         {
                                             var foundTransaction = _memPool.FirstOrDefault(t => t.GenerateHash() == transactionToDelete.GenerateHash());
                                             if (foundTransaction != null)
                                             {
                                                 _memPool.Remove(foundTransaction);
                                             }
                                         }
                                         block.StopMining();
                                         _networkSynchronizer.BroadcastBlock(block);
                                         return(true);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return(false);
 }