private Task TryPrefetchAsync(ConsensusFlags flags) { Task prefetching = Task.FromResult <bool>(true); if (UTXOSet is CachedCoinView) { var nextBlock = this.Puller.TryGetLookahead(0); if (nextBlock != null) { prefetching = UTXOSet.FetchCoinsAsync(GetIdsToFetch(nextBlock, flags.EnforceBIP30)); } } return(prefetching); }
public void Initialize() { var utxoHash = UTXOSet.GetBlockHashAsync().GetAwaiter().GetResult(); while (true) { Tip = Chain.GetBlock(utxoHash); if (Tip != null) { break; } utxoHash = UTXOSet.Rewind().GetAwaiter().GetResult(); } Puller.SetLocation(Tip); BIP9 = new ThresholdConditionCache(Validator.ConsensusParams); }
public void AcceptBlock(BlockResult result) { ContextInformation context; ConsensusFlags flags; using (watch.Start(o => Validator.PerformanceCounter.AddBlockProcessingTime(o))) { Validator.CheckBlockHeader(result.Block.Header); if (result.Block.Header.HashPrevBlock != Tip.HashBlock) { return; // reorg } result.ChainedBlock = new ChainedBlock(result.Block.Header, result.Block.Header.GetHash(), Tip); result.ChainedBlock = Chain.GetBlock(result.ChainedBlock.HashBlock) ?? result.ChainedBlock; //Liberate from memory the block created above if possible context = new ContextInformation(result.ChainedBlock, Validator.ConsensusParams); Validator.ContextualCheckBlockHeader(result.Block.Header, context); flags = GetFlags(result.ChainedBlock); Validator.ContextualCheckBlock(result.Block, flags, context); Validator.CheckBlock(result.Block); } var set = new UnspentOutputSet(); using (watch.Start(o => Validator.PerformanceCounter.AddUTXOFetchingTime(o))) { var ids = GetIdsToFetch(result.Block, flags.EnforceBIP30); var coins = UTXOSet.FetchCoinsAsync(ids).GetAwaiter().GetResult(); set.SetCoins(coins); } TryPrefetchAsync(flags); using (watch.Start(o => Validator.PerformanceCounter.AddBlockProcessingTime(o))) { Validator.ExecuteBlock(result.Block, result.ChainedBlock, flags, set, null); } UTXOSet.SaveChangesAsync(set.GetCoins(UTXOSet), null, Tip.HashBlock, result.ChainedBlock.HashBlock); _Tip = result.ChainedBlock; }
public BlockResult ExecuteNextBlock(CancellationToken cancellationToken) { BlockResult result = new BlockResult(); try { using (watch.Start(o => Validator.PerformanceCounter.AddBlockFetchingTime(o))) { while (true) { result.Block = Puller.NextBlock(cancellationToken); if (result.Block != null) { break; } else { while (true) { var hash = UTXOSet.Rewind().GetAwaiter().GetResult(); var rewinded = Chain.GetBlock(hash); if (rewinded == null) { continue; } _Tip = rewinded; Puller.SetLocation(rewinded); break; } } } } this.AcceptBlock(result); } catch (ConsensusErrorException ex) { result.Error = ex.ConsensusError; } return(result); }
private void MineTransactions() { miningInProgress = true; logger.Debug("Mining started"); var startTime = DateTime.Now; var txList = new List <Transaction>(); var coinBaseTx = Transaction.CoinBaseTx(_loggedUser.Address, ""); //add later coinBaseTx.Inputs[0].MagicValue = chain.GetBestHeight() + 1; coinBaseTx.MagicVK = chain.GetBestHeight() + 1; coinBaseTx.Id = coinBaseTx.CalculateHash(); txList.Add(coinBaseTx); //fill txList from TransactionPool foreach (var txPair in TransactionPool) { var tx = txPair.Value; if (chain.VerifyTransaction(tx)) { txList.Add(tx); } } if (txList.Count == 0) { logger.Debug("All txs invalid"); miningInProgress = false; return; } chain.HashDiscovered += HashDiscovered; NotifyGUIisMining(true); var newBlock = chain.MineBlock(txList); if (newBlock != null) { //skew for synch if (handlingNewBlock || (DateTime.Now - timeSkewBetweenHandlingBlock).Milliseconds < 200) { // mined same time as block came logger.Debug($"!New block mined, mining duration: {DateTime.Now - startTime} But discard it, cause handling newRemoteBlock"); miningInProgress = false; return; } NotifyGUIisMining(false); handlingNewBlock = true; logger.Debug($"New block mined, mining duration: {DateTime.Now - startTime}"); chain.AddBlock(newBlock); //30.4 var utxoSet = new UTXOSet(chain); utxoSet.Update(newBlock); // //7.4.19 if (InMemoryBlockChains.Count > 0) { logger.Debug("Find best chain"); InMemoryBlockChain bestChain = null; var count = 1; var bestIndex = chain.GetBestHeight(); foreach (var chain in InMemoryBlockChains) { var currentIndex = chain.GetLastIndex(); if (currentIndex > bestIndex) { bestIndex = currentIndex; count = 1; bestChain = chain; } else if (currentIndex == bestIndex) { count++; } } if (count == 1) { logger.Debug("Best chain found"); BreakMining();//redundant if (bestChain != null) { logger.Debug("Best chain found in subchains, restructualize chain"); //if not restruct to new one chain.RestructualizeSubchain(bestChain); InMemoryBlockChains.Clear(); //clear InMemoryChains } else { //if bestChain is null, chain stays local logger.Debug("Best chain found in localchain, do nothing"); } } else { logger.Debug("Best chain not found"); } } handlingNewBlock = false; if (IncomingMinedNewBlocksMessages.Count > 0) { ProcessMessage(IncomingMinedNewBlocksMessages.Dequeue()); } //7.4.19 //this means pow was broke chain.ReindexUTXO(); chain.HashDiscovered -= HashDiscovered; WholeChainDownloaded?.Invoke(this, EventArgs.Empty); SendNewBlockMined(newBlock); //remove txs from Transaction pool RemoveTransactionsFromPool(txList); } else { logger.Debug("block added by remote client"); //I delete txs from txpool in NewBlockMined //chain.ReindexUTXO(); } miningInProgress = false; if (TransactionPool.Count > 0) { MineTransactions(); } }
public void Send(string from, string to, int amount) { var utxoSet = new UTXOSet(chain); var tx = Transaction.NewTransaction(from, to, amount, utxoSet); if (tx == null) { logger.Debug("Couldn't create new TX to send"); InsufficientFund?.Invoke(this, EventArgs.Empty); return; } //old ver //var block = chain.MineBlock(new List<Transaction>() { tx }); //utxoSet.Update(block); //WholeChainDownloaded?.Invoke(this, EventArgs.Empty); //chain.ReindexUTXO(); //check if not referencing same output, TODO BUG FIX //var referencingSameOutput = false; //foreach (var transaction in TransactionPool) //{ // var txOutputs = tx.Outputs; // var poolOutputs = transaction.Value.Outputs; // foreach (var outp in poolOutputs) // { // foreach (var txOutp in txOutputs) // { // if (outp.Equals(txOutp)) // { // referencingSameOutput = true; // break; // } // } // if (referencingSameOutput) break; // } // if (referencingSameOutput) break; //} //if (referencingSameOutput) //{ // logger.Debug("Referencing same output in tx. Tx not added to TPool"); // return; //} //add to pool TransactionPool.Add(HexadecimalEncoding.ToHexString(tx.Id), tx); TransactionPoolChanged?.Invoke(this, new TransactionPoolEventArgs(new List <string>(TransactionPool.Keys))); //send to all except me and the one who send the tx var addressesToExclude = new string[] { _blockchainPeer.ClientDetails().ToString() }; var msg = new CommandMessage(); msg.Command = CommandType.Transaction; msg.Client = _blockchainPeer.ClientDetails(); msg.Data = tx.Serialize(); _blockchainPeer.BroadcastMessageAsyncExceptAddress(addressesToExclude, msg); logger.Debug("Sending tx over nettwork"); if (!miningInProgress) { if (TransactionPool.Count >= numberOfTransactionsToStartMining) { var thread = new Thread(MineTransactions); thread.Start(); } } }
private void HandleNewBlockMined(CommandMessage rxMsg) { try { handlingNewBlock = true; PauseMining(); //pause mining if mining Block minedBlock = new Block().DeSerialize(rxMsg.Data); var transactions = minedBlock.Transactions; logger.Debug("Recieved block, somebody mined: " + Convert.ToBase64String(minedBlock.Hash)); var isValid = IsPreviousHashValid(minedBlock.PreviousHash); if (!isValid) { logger.Debug("Previous hash invalid, try add to fork subchain"); if (!VerifyTransactions(transactions)) { logger.Debug("Transactions not valid"); ResumeMining(); handlingNewBlock = false; return; } //try to add to fork chains var added = false; foreach (var memChain in InMemoryBlockChains) { if (memChain.BelongsToThisChain(minedBlock)) { added = memChain.AddBlock(minedBlock); RemoveTransactionsFromPool(minedBlock.Transactions); logger.Debug("Added to subchain"); } } if (!added) { var newForkChain = new InMemoryBlockChain(); newForkChain.AddBlock(minedBlock); InMemoryBlockChains.Add(newForkChain); logger.Debug("Created new subchain"); } PrintCurrentForkChains(InMemoryBlockChains); } else { logger.Debug("Previous hash VALID, add to local chain"); if (!VerifyTransactions(transactions)) { ResumeMining(); handlingNewBlock = false; timeSkewBetweenHandlingBlock = DateTime.Now; return; } BreakMining(); RemoveTransactionsFromPool(minedBlock.Transactions); //remove new block transactions from pool chain.AddBlock(minedBlock); //30.4 var utxoSet = new UTXOSet(chain); utxoSet.Update(minedBlock); // } if (InMemoryBlockChains.Count > 0) { logger.Debug("Find best chain"); InMemoryBlockChain bestChain = null; var count = 1; var bestIndex = chain.GetBestHeight(); //local blockchain foreach (var chain in InMemoryBlockChains) //subchains { var currentIndex = chain.GetLastIndex(); if (currentIndex > bestIndex) { bestIndex = currentIndex; count = 1; bestChain = chain; } else if (currentIndex == bestIndex) { count++; } } if (count == 1) { logger.Debug("Best chain found"); BreakMining(); if (bestChain != null) { logger.Debug("Best chain found in subchains, restructualize chain"); //if not restruct to new one chain.RestructualizeSubchain(bestChain); InMemoryBlockChains.Clear(); //clear InMemoryChains } else { //if bestChain is null, chain stays local logger.Debug("Best chain found in localchain, do nothing"); } } else { logger.Debug("Best chain not found"); } } WholeChainDownloaded?.Invoke(this, EventArgs.Empty); chain.ReindexUTXO(); // asynch handlingNewBlock = false; if (IncomingMinedNewBlocksMessages.Count > 0) { ProcessMessage(IncomingMinedNewBlocksMessages.Dequeue()); } } catch (Exception e) { logger.Error(e.Message); logger.Error(e.StackTrace); } }
static void Main(string[] args) { var startTime = DateTime.Now; //var wBank = new WalletBank(); //for (var i = 0; i < 100; i++) wBank.CreateWallet(); //foreach (var wallet in wBank) //{ // var isOk = wallet.VerifyAddress(wallet.Address); // Console.WriteLine(isOk); //} //var blockChain = new BlockChain(); //blockChain.Print(); //var txList = new List<Transaction>(); //for(var i = 0; i<10000; i++) { //Transaction tx1 = new Transaction() //{ // Id = null, // Inputs = new List<TxInput>() // { // new TxInput() { // Id = new byte[] {}, // PubKey = new byte[]{0x01}, // Out = i // } // } , // Outputs = new List<TxOutput>() { new TxOutput() // { // Value = i, // } } //}; //tx1.CalculateHash(); // txList.Add(tx1); //} //var merkleTree = new MerkleTree(txList); //merkleTree.LevelOrder(); var list = new List <Transaction>(); var bank = new WalletBank(); var _loggedUserWallet = bank.FindWallet("112H2TcYAvxWGPSWXz4bzGvm5RXEdFDCms"); var _friChain = new BlockChain("x"); var utxoSet = new UTXOSet(_friChain); for (int i = 0; i < 20; i++) { var tx = Transaction.NewTransaction("112H2TcYAvxWGPSWXz4bzGvm5RXEdFDCms", "1fp9JwtnMMnYVLaABMEQuKGtpXUnJm7Cz", 2, utxoSet); if (tx == null) { return; } list.Add(tx); } var block = _friChain.MineBlock(list); utxoSet.Update(block); _friChain.GetBalance("112H2TcYAvxWGPSWXz4bzGvm5RXEdFDCms"); var endTime = DateTime.Now; Console.WriteLine($"Duration: {endTime - startTime}"); Console.Read(); }