public void ReorgOne() { UnprocessedBlockBuffer.Clear(); // remove the last block if (MerkleChain.Count != 0) { var bestBlock = MerkleChain.Max(); if (MerkleChain.TryRemove(bestBlock)) { List <SmartTransaction> affectedTxs = TrackedTransactions.Where(x => x.Height == bestBlock.Height).Select(x => x).ToList(); foreach (var tx in affectedTxs) { TrackedTransactions.TryRemove(tx); // add it back as a mempool transaction, it'll drop out anyway TrackedTransactions.TryAdd(new SmartTransaction(tx.Transaction, Height.MemPool)); } if (MerkleChain.Count != 0) { BestHeight = MerkleChain.Max().Height; } else { BestHeight = Height.Unknown; } } } }
public async Task SaveAsync(string trackerFolderPath) { await Saving.WaitAsync().ConfigureAwait(false); try { if (TrackedScriptPubKeys.Count > 0 || TrackedTransactions.Count > 0 || MerkleChain.Count > 0) { Directory.CreateDirectory(trackerFolderPath); } if (TrackedScriptPubKeys.Count > 0) { File.WriteAllLines( Path.Combine(trackerFolderPath, TrackedScriptPubKeysFileName), TrackedScriptPubKeys.Select(x => x.ToString())); } if (TrackedTransactions.Count > 0) { File.WriteAllLines( Path.Combine(trackerFolderPath, TrackedTransactionsFileName), TrackedTransactions .Select(x => $"{x.Transaction.ToHex()}:{x.Height}")); } if (MerkleChain.Count > 0) { var path = Path.Combine(trackerFolderPath, MerkleChainFileName); if (File.Exists(path)) { const string backupName = MerkleChainFileName + "_backup"; var backupPath = Path.Combine(trackerFolderPath, backupName); File.Copy(path, backupPath, overwrite: true); File.Delete(path); } using (FileStream stream = File.OpenWrite(path)) { var toFile = MerkleChain.First().ToBytes(); await stream.WriteAsync(toFile, 0, toFile.Length).ConfigureAwait(false); foreach (var block in MerkleChain.Skip(1)) { await stream.WriteAsync(blockSep, 0, blockSep.Length).ConfigureAwait(false); var blockBytes = block.ToBytes(); await stream.WriteAsync(blockBytes, 0, blockBytes.Length).ConfigureAwait(false); } } } } finally { Saving.Release(); } }
public async Task LoadAsync(string trackerFolderPath) { await Saving.WaitAsync().ConfigureAwait(false); try { if (!Directory.Exists(trackerFolderPath)) { throw new DirectoryNotFoundException($"No Blockchain found at {trackerFolderPath}"); } var tspb = Path.Combine(trackerFolderPath, TrackedScriptPubKeysFileName); if (File.Exists(tspb) && new FileInfo(tspb).Length != 0) { foreach (var line in File.ReadAllLines(tspb)) { TrackedScriptPubKeys.Add(new Script(line)); } } var tt = Path.Combine(trackerFolderPath, TrackedTransactionsFileName); if (File.Exists(tt) && new FileInfo(tt).Length != 0) { foreach (var line in File.ReadAllLines(tt)) { var pieces = line.Split(':'); //ProcessTransaction(new SmartTransaction(new Transaction(pieces[0]), new Height(pieces[1]))); } } var pbc = Path.Combine(trackerFolderPath, MerkleChainFileName); if (File.Exists(pbc) && new FileInfo(pbc).Length != 0) { foreach (var block in Util.Separate(File.ReadAllBytes(pbc), blockSep)) { try { SmartMerkleBlock smartMerkleBlock = SmartMerkleBlock.FromBytes(block); MerkleChain.Add(smartMerkleBlock); } catch (EndOfStreamException) { // Some corruption is fine, the software will self correct and save the right data } } if (MerkleChain.Count != 0) { BestHeight = MerkleChain.Max().Height; } } } finally { Saving.Release(); } }
public void ReorgOne() { // remove the last block if (MerkleChain.Count != 0) { if (MerkleChain.TryRemove(MerkleChain.Max())) { BestHeight = MerkleChain.Max().Height; } } }
public async Task SaveAsync(string trackerFolderPath) { using (await AsyncLockSaving.LockAsync()) { if (TrackedScriptPubKeys.Count > 0 || TrackedTransactions.Count > 0 || MerkleChain.Count > 0) { Directory.CreateDirectory(trackerFolderPath); } if (TrackedScriptPubKeys.Count > 0) { await File.WriteAllLinesAsync( Path.Combine(trackerFolderPath, TrackedScriptPubKeysFileName), TrackedScriptPubKeys.Select(x => x.ToString())); } if (TrackedTransactions.Count > 0) { await File.WriteAllLinesAsync( Path.Combine(trackerFolderPath, TrackedTransactionsFileName), TrackedTransactions .Select(x => $"{x.Transaction.ToHex()}:{x.Height}")); } if (MerkleChain.Count > 0) { var path = Path.Combine(trackerFolderPath, MerkleChainFileName); // remove legacy backup file if (File.Exists(path + "_backup")) { File.Delete(path + "_backup"); } using (FileStream stream = File.Open(path, FileMode.Create, FileAccess.Write)) { var toFile = MerkleChain.First().ToBytes(); await stream.WriteAsync(toFile, 0, toFile.Length); foreach (var block in MerkleChain.Skip(1)) { await stream.WriteAsync(BlockSep, 0, BlockSep.Length); var blockBytes = block.ToBytes(); await stream.WriteAsync(blockBytes, 0, blockBytes.Length); } } } } }
/// <returns>transactions it processed, empty if not processed any</returns> private HashSet <SmartTransaction> ProcessBlock(Height height, Block block) { var foundTransactions = ProcessTransactions(block.Transactions, height); var smartMerkleBlock = new SmartMerkleBlock(height, block, foundTransactions.Select(x => x.GetHash()).ToArray()); var sameHeights = MerkleChain.Where(x => x.Height == height); foreach (var elem in sameHeights) { MerkleChain.TryRemove(elem); } MerkleChain.Add(smartMerkleBlock); BestHeight = height; return(foundTransactions); }