commit cbc0cd988cd92b4205493a622799d6825a6ae05e Author: feie9454 Date: Wed Apr 22 16:56:13 2026 +0800 Initial commit: BSV blockchain parser diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0415b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Build output +bin/ +obj/ + +# User-specific files +*.user +*.suo +*.userosscache +*.sln.docstates +.vs/ + +# NuGet +*.nupkg +*.snupkg +project.lock.json +project.fragment.lock.json +artifacts/ +packages/ + +# .NET +*.cache + +# Bitcoin blockchain data files (binary, large) +blk*.dat +rev*.dat + +# OS +.DS_Store +Thumbs.db + +# IDE +.idea/ +*.swp diff --git a/BSVTest.csproj b/BSVTest.csproj new file mode 100644 index 0000000..92ffa2e --- /dev/null +++ b/BSVTest.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..fc8e4dd --- /dev/null +++ b/Program.cs @@ -0,0 +1,114 @@ +using BitcoinBlockchain.Data; +using BitcoinBlockchain.Parser; + +var blockchainFilePath = @"C:\Users\feie9454\source\repos\BSVTest\BSVTest\blk00000.dat"; + +if (!File.Exists(blockchainFilePath)) +{ + Console.Error.WriteLine($"找不到区块文件: {blockchainFilePath}"); + return; +} + +var blockchainDirectory = Path.GetDirectoryName(blockchainFilePath); +var firstBlockchainFileName = Path.GetFileName(blockchainFilePath); + +if (string.IsNullOrWhiteSpace(blockchainDirectory)) +{ + Console.Error.WriteLine("无法确定区块文件所在目录。"); + return; +} + +IBlockchainParser blockchainParser = new BlockchainParser(blockchainDirectory, firstBlockchainFileName, 1); + +var blockCount = 0; +var transactionCount = 0; +var transactionInputCount = 0; +var transactionOutputCount = 0; +ulong movedSatoshis = 0; +var blocks = new List(); + +foreach (ParserBlock block in blockchainParser.ParseBlockchain()) +{ + blocks.Add(block); + blockCount++; + transactionCount += block.Transactions.Count; + + foreach (var transaction in block.Transactions) + { + transactionInputCount += transaction.Inputs.Count; + transactionOutputCount += transaction.Outputs.Count; + + foreach (var transactionOutput in transaction.Outputs) + { + movedSatoshis += (ulong)transactionOutput.Value.Satoshi; + } + } +} + +var blocksByHash = blocks.ToDictionary(block => block.GetHash().ToString(), StringComparer.OrdinalIgnoreCase); +var chainLengthCache = new Dictionary(StringComparer.OrdinalIgnoreCase); + +var longestChainLength = 0; +ParserBlock? longestChainTip = null; + +foreach (var block in blocks) +{ + var currentLength = GetChainLength(block); + if (currentLength > longestChainLength) + { + longestChainLength = currentLength; + longestChainTip = block; + } +} + +string? longestChainStartHash = null; +string? longestChainEndHash = longestChainTip?.GetHash().ToString(); + +if (longestChainTip is not null) +{ + var current = longestChainTip; + while (true) + { + longestChainStartHash = current.GetHash().ToString(); + var previousHash = current.Header.HashPrevBlock.ToString(); + if (!blocksByHash.TryGetValue(previousHash, out var parentBlock)) + { + break; + } + + current = parentBlock; + } +} + +Console.WriteLine($"区块数: {blockCount}"); +Console.WriteLine($"交易数: {transactionCount}"); +Console.WriteLine($"交易输入数: {transactionInputCount}"); +Console.WriteLine($"交易输出数: {transactionOutputCount}"); +Console.WriteLine($"所有交易输出累计: {movedSatoshis} sat"); +Console.WriteLine($"最长链片段长度: {longestChainLength}"); + +if (longestChainStartHash is not null && longestChainEndHash is not null) +{ + Console.WriteLine($"最长链片段起点块哈希: {longestChainStartHash}"); + Console.WriteLine($"最长链片段终点块哈希: {longestChainEndHash}"); +} + +int GetChainLength(ParserBlock block) +{ + var blockHash = block.GetHash().ToString(); + if (chainLengthCache.TryGetValue(blockHash, out var cachedLength)) + { + return cachedLength; + } + + var previousHash = block.Header.HashPrevBlock.ToString(); + var currentLength = 1; + + if (blocksByHash.TryGetValue(previousHash, out var parentBlock)) + { + currentLength += GetChainLength(parentBlock); + } + + chainLengthCache[blockHash] = currentLength; + return currentLength; +}