public Chain(Chain previous, TransactionManager transact, Immutable.Deposit deposit, Immutable.Withdrawal withdrawal, Immutable.Book book, Block currentBlock, Block lastBlock, Pool pool) : this(previous) { this.BookManager = book; this.CurrentBlock = currentBlock; this.DepositManager = deposit; this.LastBlock = lastBlock; this.TransactManager = transact; this.WithdrawalManager = withdrawal; this.Pool = pool; }
public async Task <Chain> StartMining() { try { await commitLocker.WaitAsync(); if (!CancelToken.IsCancellationRequested && !Mining) { Mining = true; } else { Log.Warning("Already Mining..."); return(null); } } finally { commitLocker.Release(); } Mining = true; if (CurrentBlock == null) { var genesis = await Genesis(); if (genesis != null) { var tx = TransactManager.ProcessTransaction(genesis.Transactions.First()); return(new Chain(this, genesis, Pool, tx, threads)); } } else { var block = new Block(); block.Header.Depth = CurrentBlock.Header.Depth + 1; block.Header.PreviousBlockHash = CurrentBlock.Header.Hash; block.Header.Difficult = GetTargetDiff(); byte[] root = new byte[0]; var deposit = new Immutable.Deposit(DepositManager, TransactManager); List <Deposit> ellegibleDeposits = null; (deposit, ellegibleDeposits, root) = deposit.ProcessDeposits(root, await GetDepositPool()); var transact = deposit.TransactManager; block.Deposits = ellegibleDeposits; var book = new Book(BookManager, transact); var ellegibleOffers = new List <Offer>(); (book, ellegibleOffers, root) = book.ProcessOffers(root, await GetOfferPool()); transact = book.TransactManager; block.Offers = ellegibleOffers; var ellegibleOfferCancels = new List <OfferCancel>(); (book, ellegibleOfferCancels, root) = book.ProcessOfferCancels(root, await GetOfferCancelPool()); transact = book.TransactManager; block.OfferCancels = ellegibleOfferCancels; List <Transaction> ellegibleTransactions = null; (transact, ellegibleTransactions, root) = transact.ProcessTransactions(root, minerWallet, await GetTransactionPool(), CancelToken); block.Transactions = ellegibleTransactions; if (CancelToken.IsCancellationRequested) { return(null); } var withdrawal = new Immutable.Withdrawal(WithdrawalManager, transact); List <Withdrawal> ellegibleWithdrawals = null; (withdrawal, ellegibleWithdrawals, root) = withdrawal.ProcessWithdrawals(root, await GetWithdrawalPool()); transact = withdrawal.TransactManager; block.Withdrawals = ellegibleWithdrawals; block.Offers = ellegibleOffers; Log.Information("Mining New Block"); Log.Information(ellegibleTransactions.Count + " transactions"); Log.Information(ellegibleDeposits.Count + " deposits"); Log.Information(ellegibleWithdrawals.Count + " withdrawals"); Log.Information(ellegibleOffers.Count + " offers"); block.Header.MerkleRoot = root; block.Header.TimeStamp = DateTime.Now; var result = await Mine(block, CancelToken); if (result != null) { Log.Debug("Getting commit lock"); try { await commitLocker.WaitAsync(); if (!CancelToken.IsCancellationRequested) { Log.Debug("Got commit lock"); CancelToken.Cancel(); Mining = false; Mined = true; transact.Balance.BlockHash = result.HashStr; transact.Balance.Timestamp = result.Timestamp; book.BlockHash = result.HashStr; book.Timestamp = result.Timestamp; return(new Chain(this, transact, deposit, withdrawal, book, result, CurrentBlock, Pool, threads)); } } finally { commitLocker.Release(); } } } return(await Task <Chain> .FromResult((Chain)null)); }
private async Task <Chain> ProcessBlock(Block block) { Log.Debug("Starting process block"); if (Previous == null && CurrentBlock == null && block.Header.PreviousBlockHash == null) { Log.Debug("Creating genesis chain"); CancelToken.Cancel(); Mining = false; Log.Debug("Genesis chain pool created"); if (block.Transactions.Count() != 1 || block.Transactions.First().Outputs[0].Wallet != "VMBxDa9XQbsAW67k7avuo7HcXKxz4nizetAPi4FB5Upcj3eCD" || block.Transactions.First().Outputs[0].Size != 28987200) { Log.Error("Genesis block with invalid transaction"); return(null); } var tx = TransactManager.ProcessTransaction(block.Transactions.First()); return(new Chain(this, block, Pool, tx, threads)); } Log.Debug("Certifying dificulty"); var lastDeth = this.GetLastBlockDepth(); if (CurrentBlock != null && (CurrentBlock.Header.Depth - 20) >= lastDeth && block.Header.Difficult != GetTargetDiff()) { Log.Error("Invalid Block Difficulty"); return(null); } Log.Debug("Verifying Depth"); if (CurrentBlock != null && block.Header.Depth != CurrentBlock.Header.Depth + 1) { Log.Error("Invalid Block Depth"); Log.Error("Current Block Depth " + CurrentBlock.Header.Depth); Log.Error("Current Block Hash " + CurrentBlock.HashStr); Log.Error("Received Block Depth " + block.Header.Depth); Log.Error("Received Block Previous Hash " + block.PreviousHashStr); return(null); } Log.Debug("Verifying previous hash null"); if (block.Header.PreviousBlockHash == null) { Log.Error("Received Empty previous block hash after genesis"); return(null); } Log.Debug("Verifying previous block hash match"); if (CurrentBlock != null && !block.Header.PreviousBlockHash.SequenceEqual(CurrentBlock.Header.Hash)) { Log.Error("Invalid Previous Block Hash"); Log.Error("PreviusBlockHash " + Base58.Bitcoin.Encode(new Span <Byte>(block.Header.PreviousBlockHash))); Log.Error("LastBlockHash " + Base58.Bitcoin.Encode(new Span <Byte>(CurrentBlock.Header.Hash))); return(null); } if (block.Timestamp < CurrentBlock.Timestamp || block.Timestamp > DateTime.Now.ToUniversalTime()) { Log.Error("Block with invalid timestamp"); return(null); } Log.Debug("Block Header validated."); var transact = TransactManager; var result = false; byte[] root = new byte[0]; Log.Debug("Validatig deposits"); var deposit = new Immutable.Deposit(DepositManager, transact); if (block.Deposits != null && block.DepositsDictionary.Count > 0) { foreach (var dp in block.Deposits) { if (CancelToken.IsCancellationRequested) { return(null); } if (!await Pool.Contains(dp)) { Log.Error("Block with invalid deposit"); return(null); } deposit = deposit.ProcessDeposit(dp); root = CryptoHelper.Hash(Base58.Bitcoin.Encode(new Span <Byte>(root)) + dp.ToString()); } } transact = deposit.TransactManager; Log.Debug("Deposits validated"); Log.Debug("Validating book"); var book = new Book(BookManager, transact); var trades = new List <Trade>(); if (block.OffersDictionary.Count > 0) { foreach (var of in block.Offers) { if (CancelToken.IsCancellationRequested) { return(null); } if (!await Pool.Contains(of)) { Log.Error("Block with invalid offer"); return(null); } var clone = of.Clone(); clone.CleanTrades(); (result, book) = book.ProcessOffer(clone); if (!result) { Log.Error("Block with invalid offer"); return(null); } foreach (var t in of.Trades) { if (!clone.Trades.Any(c => c.Equals(t))) { Log.Error("Block with invalid trade"); return(null); } root = CryptoHelper.Hash(Base58.Bitcoin.Encode(new Span <Byte>(root)) + t.ToString()); } clone.Trades = of.Trades; trades.AddRange(of.Trades); root = CryptoHelper.Hash(Base58.Bitcoin.Encode(new Span <Byte>(root)) + clone.ToString()); } } book.Trades = trades.ToImmutableList(); transact = book.TransactManager; if (block.OffersCancelDictionary.Count > 0) { foreach (var of in block.OfferCancels) { if (CancelToken.IsCancellationRequested) { return(null); } if (!await Pool.Contains(of)) { Log.Error("Block with invalid offer cancel"); return(null); } var clone = of.Clone(); (result, book) = book.ProcessOfferCancel(clone); if (!result) { Log.Error("Block with invalid offer cancel"); return(null); } root = CryptoHelper.Hash(Base58.Bitcoin.Encode(new Span <Byte>(root)) + clone.ToString()); } } transact = book.TransactManager; Log.Debug("Book validated, validating transactions"); (result, transact, root) = await ValidateTransactions(root, block, transact); if (!result) { return(null); } Log.Debug("Transactions validated, validating withdrawals"); var withdrawal = new Immutable.Withdrawal(WithdrawalManager, transact); if (block.Withdrawals != null && block.WithdrawalsDictionary.Count > 0) { foreach (var wd in block.Withdrawals) { if (CancelToken.IsCancellationRequested) { return(null); } if (!await Pool.Contains(wd) && !withdrawal.CanProcess(wd)) { Log.Error("Block with invalid withdrawal."); return(null); } withdrawal = withdrawal.ProcessWithdrawal(wd); root = CryptoHelper.Hash(Base58.Bitcoin.Encode(new Span <Byte>(root)) + wd.ToString()); } } transact = withdrawal.TransactManager; Log.Debug("withdrawals validated"); if (!block.Header.MerkleRoot.SequenceEqual(root)) { Log.Error("Block with invalid merkle root"); return(null); } Log.Debug("Merkle root validated, getting commit lock"); try { await commitLocker.WaitAsync(); Log.Debug("commit lock gained"); if (!CancelToken.IsCancellationRequested) { CancelToken.Cancel(); Log.Debug("Block references last block, appending"); Mining = false; transact.Balance.BlockHash = block.HashStr; transact.Balance.Timestamp = block.Timestamp; book.BlockHash = block.HashStr; book.Timestamp = block.Timestamp; return(new Chain(this, transact, deposit, withdrawal, book, block, CurrentBlock, Pool, threads)); } } finally { commitLocker.Release(); } return(null); }
public Deposit(Deposit previous, TransactionManager transactManager) : this(previous) { TransactManager = transactManager; }