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); } }
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()); }
public BlockChain(Wallet wallet) { Wallet = wallet; _memPool = new List <Transaction>(); BlockchainDbContext.InitializeMigrations(); _networkSynchronizer = new NetworkSynchronizer(this); }
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); } }
public Block LastBlock() { using (BlockchainDbContext db = new BlockchainDbContext()) { return(db.Blocks.OrderBy(b => b.Height).LastOrDefault()); } }
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); }
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); } }
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); } }
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))); } }
public List <string> BlockHashes() { using (BlockchainDbContext db = new BlockchainDbContext()) { var blockHashes = db.Blocks.Select(b => b.PreviousHash).ToList(); return(blockHashes); } }
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); }
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()); } }
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)); } }
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; }
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); } }
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); }
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); } }
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); }
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); } } }
public TransactionRepository(BlockchainDbContext context) : base(context) { }
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) { } } } } } }
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); }