diff --git a/BitcoinKernel.NET.sln b/BitcoinKernel.NET.sln
index b23123f..dc51df9 100644
--- a/BitcoinKernel.NET.sln
+++ b/BitcoinKernel.NET.sln
@@ -11,19 +11,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{F8E63A4F-7D3E-4B2A-9C1D-8A5F6E9B3C2D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Tests", "tests\BitcoinKernel.Tests\BitcoinKernel.Tests.csproj", "{BC90EFB4-1692-CBCC-EF52-778255F591E2}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicUsage", "examples\BasicUsage\BasicUsage.csproj", "{0E2DDF4A-A1FE-5424-03EA-7A8E76751354}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Interop", "src\BitcoinKernel.Interop\BitcoinKernel.Interop.csproj", "{9C4AFB5E-ED75-909E-FC61-1BD17BB6BC23}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Core", "src\BitcoinKernel.Core\BitcoinKernel.Core.csproj", "{2BDCF8E8-DD35-3BA0-0148-5A2588335678}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel", "src\BitcoinKernel\BitcoinKernel.csproj", "{D6F509B1-C990-0533-2DD1-CFFBA7506249}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel", "src\BitcoinKernel\BitcoinKernel.csproj", "{2BDCF8E8-DD35-3BA0-0148-5A2588335678}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlockProcessing", "examples\BlockProcessing\BlockProcessing.csproj", "{23E19BC3-8829-42BE-BCB4-A2050BE04975}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Core.Tests", "tests\BitcoinKernel.Core.Tests\BitcoinKernel.Core.Tests.csproj", "{267842B2-D915-4B9E-8448-F9B5816D4A0A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinKernel.Tests", "tests\BitcoinKernel.Tests\BitcoinKernel.Tests.csproj", "{267842B2-D915-4B9E-8448-F9B5816D4A0A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "kernel-bindings-test-handler", "tools\kernel-bindings-test-handler\kernel-bindings-test-handler.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
@@ -37,18 +33,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|x64.Build.0 = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Debug|x86.Build.0 = Debug|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|Any CPU.Build.0 = Release|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|x64.ActiveCfg = Release|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|x64.Build.0 = Release|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|x86.ActiveCfg = Release|Any CPU
- {BC90EFB4-1692-CBCC-EF52-778255F591E2}.Release|x86.Build.0 = Release|Any CPU
{0E2DDF4A-A1FE-5424-03EA-7A8E76751354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0E2DDF4A-A1FE-5424-03EA-7A8E76751354}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E2DDF4A-A1FE-5424-03EA-7A8E76751354}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -85,18 +69,6 @@ Global
{2BDCF8E8-DD35-3BA0-0148-5A2588335678}.Release|x64.Build.0 = Release|Any CPU
{2BDCF8E8-DD35-3BA0-0148-5A2588335678}.Release|x86.ActiveCfg = Release|Any CPU
{2BDCF8E8-DD35-3BA0-0148-5A2588335678}.Release|x86.Build.0 = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|x64.Build.0 = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Debug|x86.Build.0 = Debug|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|Any CPU.Build.0 = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|x64.ActiveCfg = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|x64.Build.0 = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|x86.ActiveCfg = Release|Any CPU
- {D6F509B1-C990-0533-2DD1-CFFBA7506249}.Release|x86.Build.0 = Release|Any CPU
{23E19BC3-8829-42BE-BCB4-A2050BE04975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23E19BC3-8829-42BE-BCB4-A2050BE04975}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23E19BC3-8829-42BE-BCB4-A2050BE04975}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -138,11 +110,9 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {BC90EFB4-1692-CBCC-EF52-778255F591E2} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{0E2DDF4A-A1FE-5424-03EA-7A8E76751354} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F}
{9C4AFB5E-ED75-909E-FC61-1BD17BB6BC23} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{2BDCF8E8-DD35-3BA0-0148-5A2588335678} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
- {D6F509B1-C990-0533-2DD1-CFFBA7506249} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{23E19BC3-8829-42BE-BCB4-A2050BE04975} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F}
{267842B2-D915-4B9E-8448-F9B5816D4A0A} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890} = {F8E63A4F-7D3E-4B2A-9C1D-8A5F6E9B3C2D}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c578f89..3e8e471 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.0] - 2026-03-03
+
+### Breaking Changes
+- Removed `BitcoinKernel` facade package and `KernelLibrary` fluent builder; consumers now use the managed API directly
+- Renamed package/namespaces from `BitcoinKernel.Core` to `BitcoinKernel`
+- `Chain` class moved from `BitcoinKernel.Abstractions` to `BitcoinKernel.Chain`; import `using BitcoinKernel.Chain;` to access it
+- `BitcoinKernel.Abstractions` namespace renamed to `BitcoinKernel.Primatives`; update any `using BitcoinKernel.Abstractions;` imports accordingly
+- `LoggingConnection` moved from the global namespace into `BitcoinKernel`; add `using BitcoinKernel;` if not already present
+
+### Changed
+- Examples rewritten to use the managed API directly without the fluent builder
+
## [0.1.2] - 2026-01-26
### Added
diff --git a/README.md b/README.md
index fe83811..637326e 100644
--- a/README.md
+++ b/README.md
@@ -1,59 +1,36 @@
# BitcoinKernel.NET
-.NET bindings and high-level library for [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel), providing access to Bitcoin Core's consensus and validation logic.
+.NET bindings for [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel), providing access to Bitcoin Core's consensus and validation logic.
+β οΈπ§ This library is still under construction. β οΈπ§
-β οΈπ§ This library is still under contruction. β οΈπ§
-
-This library uses [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel) which is in an experimental state, do not use for production purposes.
-
-## Overview
-
-BitcoinKernel.NET brings Bitcoin Core's robust consensus engine to .NET applications through a clean, idiomatic C# API. Built on top of libbitcoinkernel, it provides everything from low-level P/Invoke bindings to high-level abstractions for common Bitcoin operations.
+This library uses [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel) which is in an experimental state, do not use for production purposes.
## Packages
| Package | Version | Description |
|---------|---------|-------------|
-| **BitcoinKernel** | 0.1.2 | High-level API with fluent builder pattern |
-| **BitcoinKernel.Core** | 0.1.2 | Managed wrappers and native bindings |
-
-
-## Quick Start
-
-### Installation
+| **BitcoinKernel** | 0.2.0 | Managed wrappers and native bindings |
```bash
dotnet add package BitcoinKernel
```
-or
-
-```bash
-dotnet add package BitcoinKernel.Core
-```
-
## Architecture
-The library is organized in three layers:
+The library is organized in two layers:
1. **BitcoinKernel.Interop** - P/Invoke bindings to libbitcoinkernel (bundled, not published separately)
-2. **BitcoinKernel.Core** - Managed C# wrappers with automatic memory management
-3. **BitcoinKernel** - High-level facade with fluent API
+2. **BitcoinKernel** - Managed C# wrappers with automatic memory management
```
βββββββββββββββββββββββββββββββ
-β BitcoinKernel β β Fluent API, simple usage
-β (Facade Layer) β
-βββββββββββββββ¬ββββββββββββββββ
- β
-βββββββββββββββΌββββββββββββββββ
-β BitcoinKernel.Core β β Managed wrappers, IDisposable
+β BitcoinKernel β β Managed wrappers, IDisposable
β (Wrapper Layer) β
βββββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββΌββββββββββββββββ
-β BitcoinKernel.Interop β β P/Invoke bindings
+β BitcoinKernel.Interop β β P/Invoke bindings (bundled)
β (Binding Layer) β
βββββββββββββββ¬ββββββββββββββββ
β
@@ -63,26 +40,44 @@ The library is organized in three layers:
βββββββββββββββββββββββββββββββ
```
+## Quick Start
+
+```csharp
+using BitcoinKernel;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Interop.Enums;
+
+using var logging = new LoggingConnection((category, message, level) =>
+ Console.WriteLine($"[{category}] {message}"));
+
+using var chainParams = new ChainParameters(ChainType.MAINNET);
+using var contextOptions = new KernelContextOptions().SetChainParams(chainParams);
+using var context = new KernelContext(contextOptions);
+using var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+using var chainstate = new ChainstateManager(context, chainParams, options);
+
+var chain = chainstate.GetActiveChain();
+Console.WriteLine($"Height: {chain.Height}");
+Console.WriteLine($"Genesis: {Convert.ToHexString(chain.GetGenesis().GetBlockHash())}");
+```
+
## Examples
Explore the [examples](examples/) directory for complete working samples:
-- **[BasicUsage](examples/BasicUsage/)** - Getting started with the high-level API
-- **[BlockProcessing](examples/BlockProcessing/)** - Block validation and chain management
+- **[BasicUsage](examples/BasicUsage/)** - Getting started with chain queries
+- **[BlockProcessing](examples/BlockProcessing/)** - Block validation and processing
## Tools
### Kernel Bindings Test Handler
-A conformance test handler for Kernel bindings Test handler framework, see [tools/kernel-bindings-test-handler](tools/kernel-bindings-test-handler/) for details.
+A conformance test handler for the Kernel bindings test framework, see [tools/kernel-bindings-test-handler](tools/kernel-bindings-test-handler/) for details.
-**Usage:**
```bash
dotnet run --project tools/kernel-bindings-test-handler
```
-The handler communicates via stdin/stdout and is designed for automated conformance testing.
-
## Building from Source
### Prerequisites
@@ -109,7 +104,7 @@ This package includes pre-built `libbitcoinkernel` binaries for:
- macOS (x64, ARM64)
- others will follow
-For other platforms, for now, you'll need to build libbitcoinkernel from the [Bitcoin Core repository](https://github.com/bitcoin/bitcoin).
+For other platforms, you'll need to build libbitcoinkernel from the [Bitcoin Core repository](https://github.com/bitcoin/bitcoin).
## Documentation
@@ -135,4 +130,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
- Built on [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/master/src/kernel) from Bitcoin Core
-**Note**: This library provides access to Bitcoin Core's consensus engine. The libbitcoinkernel and this package is stil experimental and not ready for production use.
+**Note**: This library provides access to Bitcoin Core's consensus engine. libbitcoinkernel and this package are still experimental and not ready for production use.
diff --git a/examples/BasicUsage/Program.cs b/examples/BasicUsage/Program.cs
index b2ff21c..d7c21db 100644
--- a/examples/BasicUsage/Program.cs
+++ b/examples/BasicUsage/Program.cs
@@ -1,76 +1,63 @@
-ο»Ώusing System;
-using BitcoinKernel;
-
-namespace FacadeExample
-{
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("=== Bitcoin Kernel Basic Builder Example ===\n");
-
- FullChainstateExample();
-
- }
-
- static void FullChainstateExample()
- {
- Console.WriteLine("2. Full Chainstate Example:");
-
- Console.WriteLine(" Creating builder...");
- var builder = KernelLibrary.Create()
- .ForMainnet()
- .WithWorkerThreads(2)
- .WithDirectories("/tmp/regtest-data2", "/tmp/regtest-data/blocks2");
-
- Console.WriteLine(" Configuring logging...");
- builder = builder.WithLogging((category, message, level) =>
- {
- if (level <= (int)BitcoinKernel.Interop.Enums.LogLevel.INFO) // Only INFO and above
- Console.WriteLine($" [{category}] {message}");
- });
-
- Console.WriteLine(" Building kernel...");
- using var kernel = builder.Build();
-
- Console.WriteLine(" Kernel built successfully!");
- Console.WriteLine(" β Chainstate initialized automatically");
-
- // Process blocks
- try
- {
-
- Console.WriteLine(" β Ready to process blocks");
-
- // Show new query methods
- Console.WriteLine($" Chain height: {kernel.GetChainHeight()}");
- Console.WriteLine($" Genesis hash: {Convert.ToHexString(kernel.GetGenesisBlockHash())}");
-
- if (kernel.GetChainHeight() > 0)
- {
- var tipHash = kernel.GetChainTipHash();
- Console.WriteLine($" Tip hash: {Convert.ToHexString(tipHash)}");
-
- var blockInfo = kernel.GetBlockInfo(0);
- if (blockInfo != null)
- {
- Console.WriteLine($" Block 0 hash: {Convert.ToHexString(blockInfo.Hash)}");
- }
- }
-
- Console.WriteLine(" β Chain queries working");
- }
- catch (Exception ex)
- {
- Console.WriteLine($" β Error: {ex.Message}");
+using BitcoinKernel;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Interop.Enums;
+
+namespace BasicUsage;
+
+class Program
+{
+ static void Main(string[] args)
+ {
+ Console.WriteLine("=== Bitcoin Kernel Basic Usage Example ===\n");
+ FullChainstateExample();
+ }
+
+ static void FullChainstateExample()
+ {
+ Console.WriteLine("Creating kernel...");
+
+ var dataDir = "/tmp/regtest-data2";
+ var blocksDir = "/tmp/regtest-data/blocks2";
+
+ using var logging = new LoggingConnection((category, message, level) =>
+ {
+ if (level <= (int)LogLevel.INFO)
+ Console.WriteLine($" [{category}] {message}");
+ });
+
+ using var chainParams = new ChainParameters(ChainType.MAINNET);
+ using var contextOptions = new KernelContextOptions().SetChainParams(chainParams);
+ using var context = new KernelContext(contextOptions);
+ using var options = new ChainstateManagerOptions(context, dataDir, blocksDir)
+ .SetWorkerThreads(2);
+ using var chainstate = new ChainstateManager(context, chainParams, options);
+
+ Console.WriteLine(" Kernel created successfully!");
+
+ try
+ {
+ var chain = chainstate.GetActiveChain();
+ Console.WriteLine($" Chain height: {chain.Height}");
+ Console.WriteLine($" Genesis hash: {Convert.ToHexString(chain.GetGenesis().GetBlockHash())}");
+
+ if (chain.Height > 0)
+ {
+ var tip = chain.GetTip();
+ Console.WriteLine($" Tip hash: {Convert.ToHexString(tip.GetBlockHash())}");
+
+ var genesis = chain.GetBlockByHeight(0);
+ if (genesis != null)
+ Console.WriteLine($" Block 0 hash: {Convert.ToHexString(genesis.GetBlockHash())}");
}
-
- Console.WriteLine("\nPress any key to exit...");
- Console.ReadKey();
-
- kernel.Dispose();
- Console.WriteLine(" Kernel disposed.");
- }
- }
-}
\ No newline at end of file
+ Console.WriteLine(" Chain queries working");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($" Error: {ex.Message}");
+ }
+
+ Console.WriteLine("\nPress any key to exit...");
+ Console.ReadKey();
+ }
+}
diff --git a/examples/BlockProcessing/Program.cs b/examples/BlockProcessing/Program.cs
index 3cadbc9..8b48deb 100644
--- a/examples/BlockProcessing/Program.cs
+++ b/examples/BlockProcessing/Program.cs
@@ -1,167 +1,135 @@
-ο»Ώusing System;
using System.IO;
using BitcoinKernel;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Interop.Enums;
-namespace BlockProcessing
+namespace BlockProcessing;
+
+class Program
{
- class Program
+ static void Main(string[] args)
{
- static void Main(string[] args)
+ Console.WriteLine("Bitcoin Kernel Block Processing Example");
+ Console.WriteLine("=====================================");
+
+ var dataDir = Path.Combine(Path.GetTempPath(), $"bitcoinkernel_{Guid.NewGuid()}");
+ var blocksDir = Path.Combine(dataDir, "blocks");
+
+ try
{
- Console.WriteLine("Bitcoin Kernel Block Processing Example");
- Console.WriteLine("=====================================");
+ using var logging = new LoggingConnection((category, message, level) =>
+ {
+ if (level <= 2)
+ Console.WriteLine($"[{category}] {message}");
+ });
+
+ using var chainParams = new ChainParameters(ChainType.MAINNET);
+ using var contextOptions = new KernelContextOptions().SetChainParams(chainParams);
+ using var context = new KernelContext(contextOptions);
+ using var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+ using var chainstate = new ChainstateManager(context, chainParams, options);
+ Console.WriteLine("Created kernel for mainnet");
+ Console.WriteLine("Chainstate initialized");
+
+ byte[] sampleBlockData;
try
{
- // Step 1: Create kernel library with fluent builder
- using var kernel = KernelLibrary.Create()
- .ForMainnet()
- .WithLogging((category, message, level) =>
- {
- // Simple logging callback - only show important messages
- if (level <= 2) // Info and below
- {
- Console.WriteLine($"[{category}] {message}");
- }
- })
- .Build();
-
- Console.WriteLine("β Created kernel library for mainnet");
- Console.WriteLine("β Chainstate automatically initialized by builder");
-
- // Step 3: Create a sample block for processing
- // For demonstration, we'll try to create a block
- // Note: This is a simplified example - real blocks are complex
- byte[] sampleBlockData;
- try
- {
- sampleBlockData = CreateSampleBlock();
- Console.WriteLine("β Created sample block data");
- }
- catch (Exception ex)
- {
- Console.WriteLine($"β Block creation failed: {ex.Message}");
- Console.WriteLine(" This is expected for simplified block data.");
- Console.WriteLine(" The kernel library setup was successful!");
- return;
- }
+ sampleBlockData = CreateSampleBlock();
+ Console.WriteLine("Created sample block data");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Block creation failed: {ex.Message}");
+ Console.WriteLine("This is expected for simplified block data.");
+ return;
+ }
+
+ DisplayBlockInfo(sampleBlockData);
- // Step 4: Display block information before processing
- DisplayBlockInfo(sampleBlockData);
+ Console.WriteLine("\nProcessing block...");
+ try
+ {
+ using var block = Block.FromBytes(sampleBlockData);
+ bool isNew = chainstate.ProcessBlock(block);
- // Step 5: Process the block through validation
- Console.WriteLine("\nProcessing block...");
- try
+ if (isNew)
{
- bool success = kernel.ProcessBlock(sampleBlockData);
-
- if (success)
- {
- Console.WriteLine("β Block processed successfully!");
-
- // Step 6: Get active chain information
- var activeChain = kernel.Chainstate.GetActiveChain();
- Console.WriteLine($" - Active chain height: {activeChain.Height}");
-
- var tip = activeChain.GetTip();
- Console.WriteLine($" - Active chain tip: {BitConverter.ToString(tip.GetBlockHash()).Replace("-", "")}");
- }
- else
- {
- Console.WriteLine("β Block processing failed - this may be expected for invalid block data");
- }
+ var activeChain = chainstate.GetActiveChain();
+ Console.WriteLine($"Block processed! Chain height: {activeChain.Height}");
+ var tip = activeChain.GetTip();
+ Console.WriteLine($" - Tip: {BitConverter.ToString(tip.GetBlockHash()).Replace("-", "")}");
}
- catch (Exception ex)
+ else
{
- Console.WriteLine($"β Block processing error: {ex.Message}");
- Console.WriteLine(" This is expected for simplified/invalid block data.");
+ Console.WriteLine("Block processing failed - expected for invalid block data");
}
-
- Console.WriteLine("\nβ Block processing example completed successfully!");
- Console.WriteLine(" (Note: Block processing may fail with simplified data, but the kernel setup works!)");
}
catch (Exception ex)
{
- Console.WriteLine($"β Error: {ex.Message}");
- if (ex.InnerException != null)
- {
- Console.WriteLine($"Inner exception: {ex.InnerException.Message}");
- }
- Console.WriteLine($"Stack trace: {ex.StackTrace}");
+ Console.WriteLine($"Block processing error: {ex.Message}");
+ Console.WriteLine("This is expected for simplified/invalid block data.");
}
- }
- private static byte[] CreateSampleBlock()
+ Console.WriteLine("\nBlock processing example completed!");
+ }
+ catch (Exception ex)
{
- // Create a minimal block for demonstration
- // This is a simplified example - real blocks would be much more complex
- // In practice, you'd typically read block data from files or create from templates
-
- // For this example, we'll create a block with minimal valid structure
- // Note: This won't be a real Bitcoin block, just demonstrates the API
-
- // A very basic block header structure (simplified)
- // Version (4 bytes) + Previous Block Hash (32 bytes) + Merkle Root (32 bytes) +
- // Timestamp (4 bytes) + Bits (4 bytes) + Nonce (4 bytes) = 80 bytes minimum
+ Console.WriteLine($"Error: {ex.Message}");
+ if (ex.InnerException != null)
+ Console.WriteLine($"Inner exception: {ex.InnerException.Message}");
+ }
+ }
- byte[] blockData = new byte[80];
+ private static byte[] CreateSampleBlock()
+ {
+ byte[] blockData = new byte[80];
- // Version: 1 (little endian)
- BitConverter.GetBytes(1).CopyTo(blockData, 0);
+ // Version: 1 (little endian)
+ BitConverter.GetBytes(1).CopyTo(blockData, 0);
- // Previous block hash: all zeros for genesis-like block
- // (indices 4-35 remain 0)
+ // Previous block hash: all zeros (indices 4-35)
+ // Merkle root: all zeros (indices 36-67)
- // Merkle root: all zeros for simplicity
- // (indices 36-67 remain 0)
+ // Timestamp: current Unix timestamp
+ uint timestamp = (uint)(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
+ BitConverter.GetBytes(timestamp).CopyTo(blockData, 68);
- // Timestamp: current Unix timestamp
- uint timestamp = (uint)(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
- BitConverter.GetBytes(timestamp).CopyTo(blockData, 68);
+ // Bits: 0x1d00ffff (Bitcoin mainnet difficulty)
+ BitConverter.GetBytes(0x1d00ffffu).CopyTo(blockData, 72);
- // Bits: 0x1d00ffff (Bitcoin mainnet difficulty)
- BitConverter.GetBytes(0x1d00ffffu).CopyTo(blockData, 72);
+ // Nonce: 0 (indices 76-79)
- // Nonce: 0 for this example
- // (indices 76-79 remain 0)
+ return blockData;
+ }
- return blockData;
- }
+ private static void DisplayBlockInfo(byte[] blockData)
+ {
+ Console.WriteLine("\nBlock Information:");
+ Console.WriteLine("-----------------");
- private static void DisplayBlockInfo(byte[] blockData)
+ try
{
- Console.WriteLine("\nBlock Information:");
- Console.WriteLine("-----------------");
+ Console.WriteLine($"Block Size: {blockData.Length} bytes");
+ Console.WriteLine($"Block Data (first 32 bytes): {BitConverter.ToString(blockData.Take(32).ToArray()).Replace("-", " ")}");
- try
- {
- // Display basic block info
- Console.WriteLine($"Block Size: {blockData.Length} bytes");
-
- // Display first 32 bytes of block data for inspection
- Console.WriteLine($"Block Data (first 32 bytes): {BitConverter.ToString(blockData.Take(32).ToArray()).Replace("-", " ")}");
+ uint version = BitConverter.ToUInt32(blockData, 0);
+ Console.WriteLine($"Version: {version}");
- // Parse version (first 4 bytes, little endian)
- uint version = BitConverter.ToUInt32(blockData, 0);
- Console.WriteLine($"Version: {version}");
+ uint timestamp = BitConverter.ToUInt32(blockData, 68);
+ DateTime blockTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
+ Console.WriteLine($"Timestamp: {timestamp} ({blockTime:yyyy-MM-dd HH:mm:ss UTC})");
- // Parse timestamp (bytes 68-71, little endian)
- uint timestamp = BitConverter.ToUInt32(blockData, 68);
- DateTime blockTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
- Console.WriteLine($"Timestamp: {timestamp} ({blockTime:yyyy-MM-dd HH:mm:ss UTC})");
+ uint bits = BitConverter.ToUInt32(blockData, 72);
+ Console.WriteLine($"Bits: 0x{bits:X8}");
- // Parse bits (bytes 72-75, little endian)
- uint bits = BitConverter.ToUInt32(blockData, 72);
- Console.WriteLine($"Bits: 0x{bits:X8}");
-
- // Parse nonce (bytes 76-79, little endian)
- uint nonce = BitConverter.ToUInt32(blockData, 76);
- Console.WriteLine($"Nonce: {nonce}");
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Error parsing block info: {ex.Message}");
- }
+ uint nonce = BitConverter.ToUInt32(blockData, 76);
+ Console.WriteLine($"Nonce: {nonce}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error parsing block info: {ex.Message}");
}
}
}
diff --git a/src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs b/src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs
deleted file mode 100644
index 532cd74..0000000
--- a/src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-namespace BitcoinKernel.Core.Abstractions
-{
- using BitcoinKernel.Interop;
- using System;
-
- ///
- /// Represents the spent outputs for all transactions in a block.
- ///
- public class BlockSpentOutputs : IDisposable
- {
- private IntPtr _handle;
- private bool _disposed;
-
- internal BlockSpentOutputs(IntPtr handle)
- {
- if (handle == IntPtr.Zero)
- {
- throw new ArgumentException("Invalid block spent outputs handle", nameof(handle));
- }
-
- _handle = handle;
- }
-
- ///
- /// Gets the number of transactions with spent outputs in this block.
- /// This excludes the coinbase transaction.
- ///
- public int Count
- {
- get
- {
- ThrowIfDisposed();
- return (int)NativeMethods.BlockSpentOutputsCount(_handle);
- }
- }
-
- ///
- /// Gets the spent outputs for a transaction at the specified index.
- /// The returned object is only valid for the lifetime of this BlockSpentOutputs.
- ///
- /// The zero-based index of the transaction (excluding coinbase).
- /// A TransactionSpentOutputs object for the specified transaction.
- public TransactionSpentOutputs GetTransactionSpentOutputs(int transactionIndex)
- {
- ThrowIfDisposed();
-
- if (transactionIndex < 0 || transactionIndex >= Count)
- {
- throw new ArgumentOutOfRangeException(nameof(transactionIndex));
- }
-
- var txSpentOutputsPtr = NativeMethods.BlockSpentOutputsGetTransactionSpentOutputsAt(
- _handle, (nuint)transactionIndex);
-
- if (txSpentOutputsPtr == IntPtr.Zero)
- {
- throw new InvalidOperationException($"Failed to get transaction spent outputs at index {transactionIndex}");
- }
-
- // Don't own the handle - it's only valid for the lifetime of BlockSpentOutputs
- return new TransactionSpentOutputs(txSpentOutputsPtr, ownsHandle: false);
- }
-
- ///
- /// Enumerates all transaction spent outputs in the block.
- ///
- /// An enumerable of TransactionSpentOutputs for each transaction (excluding coinbase).
- public IEnumerable EnumerateTransactionSpentOutputs()
- {
- ThrowIfDisposed();
-
- int count = Count;
- for (int i = 0; i < count; i++)
- {
- yield return GetTransactionSpentOutputs(i);
- }
- }
-
- internal IntPtr Handle
- {
- get
- {
- ThrowIfDisposed();
- return _handle;
- }
- }
-
- private void ThrowIfDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(nameof(BlockSpentOutputs));
- }
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (_handle != IntPtr.Zero)
- {
- NativeMethods.BlockSpentOutputsDestroy(_handle);
- _handle = IntPtr.Zero;
- }
-
- _disposed = true;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~BlockSpentOutputs()
- {
- Dispose(false);
- }
- }
-}
diff --git a/src/BitcoinKernel.Core/Abstractions/Coin.cs b/src/BitcoinKernel.Core/Abstractions/Coin.cs
deleted file mode 100644
index 17266b6..0000000
--- a/src/BitcoinKernel.Core/Abstractions/Coin.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-namespace BitcoinKernel.Core.Abstractions
-{
- using BitcoinKernel.Interop;
- using System;
-
- ///
- /// Represents a coin (unspent transaction output) with confirmation height information.
- ///
- public class Coin : IDisposable
- {
- private IntPtr _handle;
- private bool _disposed;
- private readonly bool _ownsHandle;
-
- internal Coin(IntPtr handle, bool ownsHandle = true)
- {
- if (handle == IntPtr.Zero)
- {
- throw new ArgumentException("Invalid coin handle", nameof(handle));
- }
-
- _handle = handle;
- _ownsHandle = ownsHandle;
- }
-
- ///
- /// Gets the block height where the transaction that created this coin was included.
- ///
- public uint ConfirmationHeight
- {
- get
- {
- ThrowIfDisposed();
- return NativeMethods.CoinConfirmationHeight(_handle);
- }
- }
-
- ///
- /// Gets a value indicating whether this coin is from a coinbase transaction.
- ///
- public bool IsCoinbase
- {
- get
- {
- ThrowIfDisposed();
- return NativeMethods.CoinIsCoinbase(_handle) != 0;
- }
- }
-
- ///
- /// Gets the transaction output of this coin.
- /// The returned object is only valid for the lifetime of this Coin.
- ///
- public TxOut GetOutput()
- {
- ThrowIfDisposed();
- var outputPtr = NativeMethods.CoinGetOutput(_handle);
- if (outputPtr == IntPtr.Zero)
- {
- throw new InvalidOperationException("Failed to get coin output");
- }
-
- // Don't own the handle - it's only valid for the lifetime of the Coin
- return new TxOut(outputPtr, ownsHandle: false);
- }
-
- ///
- /// Creates a copy of this coin.
- ///
- public Coin Copy()
- {
- ThrowIfDisposed();
- var copiedHandle = NativeMethods.CoinCopy(_handle);
- if (copiedHandle == IntPtr.Zero)
- {
- throw new InvalidOperationException("Failed to copy coin");
- }
-
- return new Coin(copiedHandle, ownsHandle: true);
- }
-
- internal IntPtr Handle
- {
- get
- {
- ThrowIfDisposed();
- return _handle;
- }
- }
-
- private void ThrowIfDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(nameof(Coin));
- }
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (_ownsHandle && _handle != IntPtr.Zero)
- {
- NativeMethods.CoinDestroy(_handle);
- _handle = IntPtr.Zero;
- }
-
- _disposed = true;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~Coin()
- {
- Dispose(false);
- }
- }
-}
diff --git a/src/BitcoinKernel.Core/BitcoinKernel.Core.csproj b/src/BitcoinKernel.Core/BitcoinKernel.Core.csproj
deleted file mode 100644
index e414cfd..0000000
--- a/src/BitcoinKernel.Core/BitcoinKernel.Core.csproj
+++ /dev/null
@@ -1,48 +0,0 @@
-ο»Ώ
-
-
- net9.0
- enable
- enable
- true
-
-
- BitcoinKernel.Core
- 0.1.2
- JanB84
- .NET bindings and managed wrappers for libbitcoinkernel. Provides direct access to Bitcoin Core consensus and validation logic with automatic memory management.
- MIT
- https://github.com/JanB84/BitcoinKernel.NET
- https://github.com/JanB84/BitcoinKernel.NET
- git
- bitcoin;kernel;libbitcoinkernel;wrapper;core;blockchain
- false
- true
- snupkg
-
- $(TargetsForTfmSpecificContentInPackage);IncludeReferencedProjectsInPackage
-
-
-
-
-
-
-
-
-
-
-
- <_PackageFiles Include="$(OutputPath)BitcoinKernel.Interop.dll">
- Content
- lib/$(TargetFramework)/BitcoinKernel.Interop.dll
-
-
-
- <_PackageFiles Include="$(OutputPath)runtimes\**\*.*" Condition="Exists('$(OutputPath)runtimes')">
- Content
- runtimes/%(RecursiveDir)%(Filename)%(Extension)
-
-
-
-
-
diff --git a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj
index 0b39cd6..ca9447e 100644
--- a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj
+++ b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj
@@ -7,6 +7,12 @@
true
+
+
+ <_Parameter1>BitcoinKernel
+
+
+
diff --git a/src/BitcoinKernel.Interop/Delegates/DestroyCallback.cs b/src/BitcoinKernel.Interop/Delegates/DestroyCallback.cs
index db7bd40..c4dfe17 100644
--- a/src/BitcoinKernel.Interop/Delegates/DestroyCallback.cs
+++ b/src/BitcoinKernel.Interop/Delegates/DestroyCallback.cs
@@ -6,4 +6,4 @@ namespace BitcoinKernel.Interop.Delegates;
/// Function signature for freeing user data.
///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void DestroyCallback(IntPtr user_data);
+internal delegate void DestroyCallback(IntPtr user_data);
diff --git a/src/BitcoinKernel.Interop/Delegates/LoggingCallback.cs b/src/BitcoinKernel.Interop/Delegates/LoggingCallback.cs
index 963599f..00b2265 100644
--- a/src/BitcoinKernel.Interop/Delegates/LoggingCallback.cs
+++ b/src/BitcoinKernel.Interop/Delegates/LoggingCallback.cs
@@ -7,7 +7,7 @@ namespace BitcoinKernel.Interop.Delegates;
/// internal logs will pass through this callback.
///
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void LoggingCallback(
+internal delegate void LoggingCallback(
IntPtr user_data,
IntPtr message,
nuint message_len);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyBlockTip.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyBlockTip.cs
index 0a3bb53..e6ca914 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyBlockTip.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyBlockTip.cs
@@ -3,7 +3,7 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyBlockTip(
+internal delegate void NotifyBlockTip(
IntPtr user_data,
IntPtr block_index);
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFatalError.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFatalError.cs
index a919608..4ba4cf1 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFatalError.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFatalError.cs
@@ -3,6 +3,6 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyFatalError(
+internal delegate void NotifyFatalError(
IntPtr user_data,
[MarshalAs(UnmanagedType.LPUTF8Str)] string error_message);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFlushError.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFlushError.cs
index f524baa..3e583b0 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFlushError.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyFlushError.cs
@@ -4,6 +4,6 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyFlushError(
+internal delegate void NotifyFlushError(
IntPtr user_data,
[MarshalAs(UnmanagedType.LPUTF8Str)] string error_message);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyHeaderTip.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyHeaderTip.cs
index ed12508..5e01408 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyHeaderTip.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyHeaderTip.cs
@@ -3,7 +3,7 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyHeaderTip(
+internal delegate void NotifyHeaderTip(
IntPtr user_data,
IntPtr block_index,
long timestamp);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyProgress.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyProgress.cs
index 3919a0f..9e8ce0f 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyProgress.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyProgress.cs
@@ -4,7 +4,7 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyProgress(
+internal delegate void NotifyProgress(
IntPtr user_data,
[MarshalAs(UnmanagedType.LPUTF8Str)] string title,
int progress_percent,
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningSet.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningSet.cs
index e7f2170..0dc8758 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningSet.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningSet.cs
@@ -4,6 +4,6 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyWarningSet(
+internal delegate void NotifyWarningSet(
IntPtr user_data,
Warning warning);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningUnset.cs b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningUnset.cs
index 64f3779..13b6bea 100644
--- a/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningUnset.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Notification/NotifyWarningUnset.cs
@@ -4,6 +4,6 @@
namespace BitcoinKernel.Interop.Delegates.Notification;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void NotifyWarningUnset(
+internal delegate void NotifyWarningUnset(
IntPtr user_data,
Warning warning);
diff --git a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockChecked.cs b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockChecked.cs
index 9ed384a..9e7ee9b 100644
--- a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockChecked.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockChecked.cs
@@ -3,7 +3,7 @@
namespace BitcoinKernel.Interop.Delegates.Validation;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void ValidationBlockChecked(
+internal delegate void ValidationBlockChecked(
IntPtr user_data,
IntPtr block,
IntPtr validation_state);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockConnected.cs b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockConnected.cs
index ed9525c..57e0a9e 100644
--- a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockConnected.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockConnected.cs
@@ -3,7 +3,7 @@
namespace BitcoinKernel.Interop.Delegates.Validation;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void ValidationBlockConnected(
+internal delegate void ValidationBlockConnected(
IntPtr user_data,
IntPtr block_index,
IntPtr block);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockDisconnected.cs b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockDisconnected.cs
index fbd73e2..c7f501a 100644
--- a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockDisconnected.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationBlockDisconnected.cs
@@ -3,6 +3,6 @@
namespace BitcoinKernel.Interop.Delegates.Validation;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void ValidationBlockDisconnected(
+internal delegate void ValidationBlockDisconnected(
IntPtr user_data,
IntPtr block);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationNewPoWValidBlock.cs b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationNewPoWValidBlock.cs
index 238894d..da2ece4 100644
--- a/src/BitcoinKernel.Interop/Delegates/Validation/ValidationNewPoWValidBlock.cs
+++ b/src/BitcoinKernel.Interop/Delegates/Validation/ValidationNewPoWValidBlock.cs
@@ -3,7 +3,7 @@
namespace BitcoinKernel.Interop.Delegates.Validation;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-public delegate void ValidationNewPoWValidBlock(
+internal delegate void ValidationNewPoWValidBlock(
IntPtr user_data,
IntPtr block_index,
IntPtr block);
\ No newline at end of file
diff --git a/src/BitcoinKernel.Interop/Enums/ChainType.cs b/src/BitcoinKernel.Interop/Enums/ChainType.cs
index 80e0993..f7e9ea1 100644
--- a/src/BitcoinKernel.Interop/Enums/ChainType.cs
+++ b/src/BitcoinKernel.Interop/Enums/ChainType.cs
@@ -1,11 +1,10 @@
-namespace BitcoinKernel.Interop.Enums
+namespace BitcoinKernel.Interop.Enums;
+
+public enum ChainType : uint
{
- public enum ChainType : uint
- {
- MAINNET = 0,
- TESTNET = 1,
- TESTNET_4 = 2,
- SIGNET = 3,
- REGTEST = 4
- }
-}
\ No newline at end of file
+ MAINNET = 0,
+ TESTNET = 1,
+ TESTNET_4 = 2,
+ SIGNET = 3,
+ REGTEST = 4
+}
diff --git a/src/BitcoinKernel.Interop/Enums/LogCategory.cs b/src/BitcoinKernel.Interop/Enums/LogCategory.cs
index 16e5c56..d503355 100644
--- a/src/BitcoinKernel.Interop/Enums/LogCategory.cs
+++ b/src/BitcoinKernel.Interop/Enums/LogCategory.cs
@@ -1,63 +1,61 @@
-namespace BitcoinKernel.Interop.Enums
+namespace BitcoinKernel.Interop.Enums;
+///
+/// A collection of logging categories that may be encountered by kernel code.
+///
+public enum LogCategory : byte
{
///
- /// A collection of logging categories that may be encountered by kernel code.
- ///
- public enum LogCategory : byte
- {
- ///
- /// All categories.
- ///
- All = 0,
-
- ///
- /// Benchmark logging.
- ///
- Bench = 1,
-
- ///
- /// Block storage operations.
- ///
- BlockStorage = 2,
-
- ///
- /// Coin database operations.
- ///
- CoinDb = 3,
-
- ///
- /// LevelDB operations.
- ///
- LevelDb = 4,
-
- ///
- /// Memory pool operations.
- ///
- Mempool = 5,
-
- ///
- /// Pruning operations.
- ///
- Prune = 6,
-
- ///
- /// Random number generation.
- ///
- Rand = 7,
-
- ///
- /// Reindexing operations.
- ///
- Reindex = 8,
-
- ///
- /// Validation operations.
- ///
- Validation = 9,
-
- ///
- /// Kernel operations.
- ///
- Kernel = 10
- }
+ /// All categories.
+ ///
+ All = 0,
+
+ ///
+ /// Benchmark logging.
+ ///
+ Bench = 1,
+
+ ///
+ /// Block storage operations.
+ ///
+ BlockStorage = 2,
+
+ ///
+ /// Coin database operations.
+ ///
+ CoinDb = 3,
+
+ ///
+ /// LevelDB operations.
+ ///
+ LevelDb = 4,
+
+ ///
+ /// Memory pool operations.
+ ///
+ Mempool = 5,
+
+ ///
+ /// Pruning operations.
+ ///
+ Prune = 6,
+
+ ///
+ /// Random number generation.
+ ///
+ Rand = 7,
+
+ ///
+ /// Reindexing operations.
+ ///
+ Reindex = 8,
+
+ ///
+ /// Validation operations.
+ ///
+ Validation = 9,
+
+ ///
+ /// Kernel operations.
+ ///
+ Kernel = 10
}
diff --git a/src/BitcoinKernel.Interop/Enums/ScriptVerificationFlags.cs b/src/BitcoinKernel.Interop/Enums/ScriptVerificationFlags.cs
index fd9ddd1..b978bbe 100644
--- a/src/BitcoinKernel.Interop/Enums/ScriptVerificationFlags.cs
+++ b/src/BitcoinKernel.Interop/Enums/ScriptVerificationFlags.cs
@@ -1,59 +1,57 @@
-namespace BitcoinKernel.Interop.Enums
+namespace BitcoinKernel.Interop.Enums;
+///
+/// Script verification flags that may be composed with each other.
+///
+[Flags]
+public enum ScriptVerificationFlags : uint
{
///
- /// Script verification flags that may be composed with each other.
- ///
- [Flags]
- public enum ScriptVerificationFlags : uint
- {
- ///
- /// No script verification flags.
- ///
- None = 0,
-
- ///
- /// Evaluate P2SH (BIP16) subscripts.
- ///
- P2SH = 1U << 0,
-
- ///
- /// Enforce strict DER (BIP66) compliance.
- ///
- DerSig = 1U << 2,
-
- ///
- /// Enforce NULLDUMMY (BIP147).
- ///
- NullDummy = 1U << 4,
-
- ///
- /// Enable CHECKLOCKTIMEVERIFY (BIP65).
- ///
- CheckLockTimeVerify = 1U << 9,
-
- ///
- /// Enable CHECKSEQUENCEVERIFY (BIP112).
- ///
- CheckSequenceVerify = 1U << 10,
-
- ///
- /// Enable WITNESS (BIP141).
- ///
- Witness = 1U << 11,
-
- ///
- /// Enable TAPROOT (BIPs 341 & 342).
- ///
- Taproot = 1U << 17,
-
- ///
- /// All standard script verification flags.
- ///
- All = P2SH | DerSig | NullDummy | CheckLockTimeVerify | CheckSequenceVerify | Witness | Taproot,
-
- ///
- /// All script verification flags pre taproot(P2SH + Witness).
- ///
- AllPreTaproot = P2SH | DerSig | NullDummy | CheckLockTimeVerify | CheckSequenceVerify | Witness
- }
-}
\ No newline at end of file
+ /// No script verification flags.
+ ///
+ None = 0,
+
+ ///
+ /// Evaluate P2SH (BIP16) subscripts.
+ ///
+ P2SH = 1U << 0,
+
+ ///
+ /// Enforce strict DER (BIP66) compliance.
+ ///
+ DerSig = 1U << 2,
+
+ ///
+ /// Enforce NULLDUMMY (BIP147).
+ ///
+ NullDummy = 1U << 4,
+
+ ///
+ /// Enable CHECKLOCKTIMEVERIFY (BIP65).
+ ///
+ CheckLockTimeVerify = 1U << 9,
+
+ ///
+ /// Enable CHECKSEQUENCEVERIFY (BIP112).
+ ///
+ CheckSequenceVerify = 1U << 10,
+
+ ///
+ /// Enable WITNESS (BIP141).
+ ///
+ Witness = 1U << 11,
+
+ ///
+ /// Enable TAPROOT (BIPs 341 & 342).
+ ///
+ Taproot = 1U << 17,
+
+ ///
+ /// All standard script verification flags.
+ ///
+ All = P2SH | DerSig | NullDummy | CheckLockTimeVerify | CheckSequenceVerify | Witness | Taproot,
+
+ ///
+ /// All script verification flags pre taproot(P2SH + Witness).
+ ///
+ AllPreTaproot = P2SH | DerSig | NullDummy | CheckLockTimeVerify | CheckSequenceVerify | Witness
+}
diff --git a/src/BitcoinKernel.Interop/Enums/ScriptVerifyStatus.cs b/src/BitcoinKernel.Interop/Enums/ScriptVerifyStatus.cs
index 6364e27..9521e4f 100644
--- a/src/BitcoinKernel.Interop/Enums/ScriptVerifyStatus.cs
+++ b/src/BitcoinKernel.Interop/Enums/ScriptVerifyStatus.cs
@@ -1,38 +1,36 @@
-namespace BitcoinKernel.Interop.Enums
+namespace BitcoinKernel.Interop.Enums;
+///
+/// Status codes that may be returned by script verification operations.
+///
+public enum ScriptVerifyStatus : byte
{
///
- /// Status codes that may be returned by script verification operations.
+ /// Script verified successfully.
///
- public enum ScriptVerifyStatus : byte
- {
- ///
- /// Script verified successfully.
- ///
- OK = 0,
+ OK = 0,
- ///
- /// The flags were combined in an invalid way.
- ///
- ERROR_INVALID_FLAGS_COMBINATION = 1,
+ ///
+ /// The flags were combined in an invalid way.
+ ///
+ ERROR_INVALID_FLAGS_COMBINATION = 1,
- ///
- /// The taproot flag was set, so valid spent_outputs have to be provided.
- ///
- ERROR_SPENT_OUTPUTS_REQUIRED = 2,
+ ///
+ /// The taproot flag was set, so valid spent_outputs have to be provided.
+ ///
+ ERROR_SPENT_OUTPUTS_REQUIRED = 2,
- ///
- /// The input index is out of bounds for the transaction.
- ///
- ERROR_TX_INPUT_INDEX = 3,
+ ///
+ /// The input index is out of bounds for the transaction.
+ ///
+ ERROR_TX_INPUT_INDEX = 3,
- ///
- /// The number of spent outputs doesn't match the number of transaction inputs.
- ///
- ERROR_SPENT_OUTPUTS_MISMATCH = 4,
+ ///
+ /// The number of spent outputs doesn't match the number of transaction inputs.
+ ///
+ ERROR_SPENT_OUTPUTS_MISMATCH = 4,
- ///
- /// The verification flags value is invalid.
- ///
- ERROR_INVALID_FLAGS = 5
- }
-}
\ No newline at end of file
+ ///
+ /// The verification flags value is invalid.
+ ///
+ ERROR_INVALID_FLAGS = 5
+}
diff --git a/src/BitcoinKernel.Interop/Enums/Warning.cs b/src/BitcoinKernel.Interop/Enums/Warning.cs
index 5a98118..d59136c 100644
--- a/src/BitcoinKernel.Interop/Enums/Warning.cs
+++ b/src/BitcoinKernel.Interop/Enums/Warning.cs
@@ -1,8 +1,7 @@
-namespace BitcoinKernel.Interop.Enums
+namespace BitcoinKernel.Interop.Enums;
+
+public enum Warning
{
- public enum Warning
- {
- UnknownNewRulesActivated = 0,
- LargeWorkInvalidChain = 1
- }
-}
\ No newline at end of file
+ UnknownNewRulesActivated = 0,
+ LargeWorkInvalidChain = 1
+}
diff --git a/src/BitcoinKernel.Interop/NativeMethods.cs b/src/BitcoinKernel.Interop/NativeMethods.cs
index 17e7669..1b5c770 100644
--- a/src/BitcoinKernel.Interop/NativeMethods.cs
+++ b/src/BitcoinKernel.Interop/NativeMethods.cs
@@ -5,898 +5,896 @@
using BitcoinKernel.Interop.Enums;
using BitcoinKernel.Interop.Delegates;
-namespace BitcoinKernel.Interop
+namespace BitcoinKernel.Interop;
+///
+/// Low-level P/Invoke declarations for the Bitcoin Kernel C API.
+/// Maps directly to the bitcoinkernel.h C header.
+///
+internal static class NativeMethods
{
+ #region Library Configuration
+
+ private const string LibName = "bitcoinkernel";
+
+ // For loading platform-specific libraries
+ static NativeMethods()
+ {
+ NativeLibraryLoader.EnsureLoaded();
+ }
+
+ #endregion
+
+ #region Context Management
+
///
- /// Low-level P/Invoke declarations for the Bitcoin Kernel C API.
- /// Maps directly to the bitcoinkernel.h C header.
+ /// Creates a new kernel context.
///
- public static class NativeMethods
- {
- #region Library Configuration
-
- private const string LibName = "bitcoinkernel";
-
- // For loading platform-specific libraries
- static NativeMethods()
- {
- NativeLibraryLoader.EnsureLoaded();
- }
-
- #endregion
-
- #region Context Management
-
- ///
- /// Creates a new kernel context.
- ///
- /// Pointer to kernel context, or IntPtr.Zero on failure
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_create")]
- public static extern IntPtr ContextCreate(IntPtr options);
-
- ///
- /// Destroys a kernel context and frees associated resources.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_destroy")]
- public static extern void ContextDestroy(IntPtr context);
-
- ///
- /// Interrupts long-running operations associated with this context.
- /// Returns 0 on success.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_interrupt")]
- public static extern int ContextInterrupt(IntPtr context);
-
- #endregion
-
- #region Context Options
-
- ///
- /// Creates context options with default values.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_create")]
- public static extern IntPtr ContextOptionsCreate();
-
- ///
- /// Destroys context options.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_destroy")]
- public static extern void ContextOptionsDestroy(IntPtr options);
-
- ///
- /// Sets the chain parameters for the context.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_chainparams")]
- public static extern void ContextOptionsSetChainParams(IntPtr options, IntPtr chain_params);
-
- ///
- /// Sets the notification callbacks for the context.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_notifications")]
- public static extern void ContextOptionsSetNotifications(IntPtr options, NotificationInterfaceCallbacks callbacks);
-
- ///
- /// Sets the validation interface for the context.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_validation_interface")]
- public static extern void ContextOptionsSetValidationInterface(IntPtr options, ValidationInterfaceCallbacks callbacks);
-
- #endregion
-
- #region Chain Parameters
-
- ///
- /// Creates chain parameters for the specified chain type.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_create")]
- public static extern IntPtr ChainParametersCreate(ChainType chain_type);
-
- ///
- /// Destroys chain parameters.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_destroy")]
- public static extern void ChainParametersDestroy(IntPtr chain_params);
-
- #endregion
-
- #region Chainstate Manager
-
- ///
- /// Creates a chainstate manager.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_create")]
- public static extern IntPtr ChainstateManagerCreate(IntPtr options);
-
- ///
- /// Destroys a chainstate manager.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_destroy")]
- public static extern void ChainstateManagerDestroy(IntPtr manager);
-
- ///
- /// Processes a block through validation.
- /// Returns 0 on success.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_process_block")]
- public static extern int ChainstateManagerProcessBlock(
- IntPtr manager,
- IntPtr block,
- ref int new_block);
-
- ///
- /// Gets a block tree entry by its block hash.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_block_tree_entry_by_hash")]
- public static extern IntPtr ChainstateManagerGetBlockTreeEntryByHash(
- IntPtr manager,
- IntPtr block_hash);
-
- ///
- /// Gets the active chain from the chainstate manager.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_active_chain")]
- public static extern IntPtr ChainstateManagerGetActiveChain(IntPtr manager);
-
- ///
- /// Gets the block tree entry with the most cumulative proof of work.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_best_entry")]
- public static extern IntPtr ChainstateManagerGetBestEntry(IntPtr manager);
-
- ///
- /// Processes and validates a block header.
- /// Returns 0 on success.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_process_block_header")]
- public static extern int ChainstateManagerProcessBlockHeader(
- IntPtr manager,
- IntPtr header,
- IntPtr block_validation_state);
-
- ///
- /// Imports blocks from an array of file paths.
- /// Returns 0 on success.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_import_blocks")]
- public static extern int ChainstateManagerImportBlocks(
- IntPtr manager,
- [MarshalAs(UnmanagedType.LPArray)] string[] block_file_paths_data,
- nuint[] block_file_paths_lens,
- nuint block_file_paths_data_len);
-
- #endregion
-
- #region Chainstate Manager Options
-
- ///
- /// Creates chainstate manager options.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_create")]
- public static extern IntPtr ChainstateManagerOptionsCreate(
- IntPtr context,
- [MarshalAs(UnmanagedType.LPUTF8Str)] string data_directory,
- nuint data_directory_len,
- [MarshalAs(UnmanagedType.LPUTF8Str)] string blocks_directory,
- nuint blocks_directory_len);
-
- ///
- /// Destroys chainstate manager options.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_destroy")]
- public static extern void ChainstateManagerOptionsDestroy(IntPtr options);
-
- ///
- /// Sets the number of worker threads for script verification.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_set_worker_threads_num")]
- public static extern void ChainstateManagerOptionsSetWorkerThreads(
- IntPtr options,
- int worker_threads);
-
- ///
- /// Sets whether to wipe the databases on load.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_set_wipe_dbs")]
- public static extern int ChainstateManagerOptionsSetWipeDbs(
- IntPtr options,
- int wipe_block_tree_db,
- int wipe_chainstate_db);
-
- ///
- /// Sets block tree db in memory.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_update_block_tree_db_in_memory")]
- public static extern void ChainstateManagerOptionsUpdateBlockTreeDbInMemory(
- IntPtr options,
- int block_tree_db_in_memory);
-
- ///
- /// Sets chainstate db in memory.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_update_chainstate_db_in_memory")]
- public static extern void ChainstateManagerOptionsUpdateChainstateDbInMemory(
- IntPtr options,
- int chainstate_db_in_memory);
-
- #endregion
-
- #region Block Operations
-
- ///
- /// Creates a block from raw data.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_create")]
- public static extern IntPtr BlockCreate(
- byte[] raw_block,
- UIntPtr raw_block_len);
-
- ///
- /// Destroys a block.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_destroy")]
- public static extern void BlockDestroy(IntPtr block);
-
- ///
- /// Reads a block from disk by its block tree entry.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_read")]
- public static extern IntPtr BlockRead(
- IntPtr chainstate_manager,
- IntPtr block_tree_entry);
-
- ///
- /// Gets the number of transactions in a block.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_count_transactions")]
- public static extern nuint BlockCountTransactions(IntPtr block);
-
- ///
- /// Gets the block hash.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_hash")]
- public static extern IntPtr BlockGetHash(IntPtr block);
-
- ///
- /// Gets the block header from a block.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_header")]
- public static extern IntPtr BlockGetHeader(IntPtr block);
-
- ///
- /// Serializes the block to bytes.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_to_bytes")]
- public static extern int BlockToBytes(
- IntPtr block,
- WriteBytes writer,
- IntPtr user_data);
-
- ///
- /// Delegate for writing bytes during serialization.
- ///
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int WriteBytes(IntPtr bytes, nuint size, IntPtr userdata);
-
- ///
- /// Gets the block hash from a block tree entry.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_block_hash")]
- public static extern IntPtr BlockTreeEntryGetBlockHash(IntPtr block_tree_entry);
-
- ///
- /// Gets the block height from a block tree entry.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_height")]
- public static extern int BlockTreeEntryGetHeight(IntPtr block_tree_entry);
-
- ///
- /// Gets the previous block tree entry from a block tree entry.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_previous")]
- public static extern IntPtr BlockTreeEntryGetPrevious(IntPtr block_tree_entry);
-
- ///
- /// Gets the block header from a block tree entry.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_block_header")]
- public static extern IntPtr BlockTreeEntryGetBlockHeader(IntPtr block_tree_entry);
-
- ///
- /// Checks if two block tree entries are equal. Two block tree entries are equal when they
- /// point to the same block.
- /// Returns 1 if equal, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_equals")]
- public static extern int BlockTreeEntryEquals(IntPtr entry1, IntPtr entry2);
-
- ///
- /// Copies a block (reference counted).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_copy")]
- public static extern IntPtr BlockCopy(IntPtr block);
-
- ///
- /// Gets a transaction at the specified index in a block.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_transaction_at")]
- public static extern IntPtr BlockGetTransactionAt(IntPtr block, nuint index);
-
- #endregion
-
- #region BlockHash Operations
-
- ///
- /// Creates a block hash from 32 bytes.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_create")]
- public static extern IntPtr BlockHashCreate(IntPtr hash);
-
- ///
- /// Creates a block hash from 32 bytes (unsafe version).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_create")]
- public static extern unsafe IntPtr BlockHashCreate(byte* hash);
-
- ///
- /// Serializes the block hash to bytes (32 bytes).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_to_bytes")]
- public static extern void BlockHashToBytes(IntPtr block_hash, [MarshalAs(UnmanagedType.LPArray, SizeConst = 32)] byte[] output);
-
- ///
- /// Destroys a block hash.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_destroy")]
- public static extern void BlockHashDestroy(IntPtr block_hash);
-
- #endregion
-
- #region Block Header Operations
-
- ///
- /// Creates a block header from raw serialized data (80 bytes).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_create")]
- public static extern IntPtr BlockHeaderCreate(
- byte[] raw_block_header,
- UIntPtr raw_block_header_len);
-
- ///
- /// Copies a block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_copy")]
- public static extern IntPtr BlockHeaderCopy(IntPtr header);
-
- ///
- /// Gets the block hash from a block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_hash")]
- public static extern IntPtr BlockHeaderGetHash(IntPtr header);
-
- ///
- /// Gets the previous block hash from a block header.
- /// The returned hash is unowned and only valid for the lifetime of the block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_prev_hash")]
- public static extern IntPtr BlockHeaderGetPrevHash(IntPtr header);
-
- ///
- /// Gets the timestamp from a block header (Unix epoch seconds).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_timestamp")]
- public static extern uint BlockHeaderGetTimestamp(IntPtr header);
-
- ///
- /// Gets the nBits difficulty target from a block header (compact format).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_bits")]
- public static extern uint BlockHeaderGetBits(IntPtr header);
-
- ///
- /// Gets the version from a block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_version")]
- public static extern int BlockHeaderGetVersion(IntPtr header);
-
- ///
- /// Gets the nonce from a block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_nonce")]
- public static extern uint BlockHeaderGetNonce(IntPtr header);
-
- ///
- /// Destroys a block header.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_destroy")]
- public static extern void BlockHeaderDestroy(IntPtr header);
-
- #endregion
-
- #region Chain Operations
-
- ///
- /// Gets the height of the chain.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_get_height")]
- public static extern int ChainGetHeight(IntPtr chain);
-
- ///
- /// Gets a block tree entry by height.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_get_by_height")]
- public static extern IntPtr ChainGetByHeight(IntPtr chain, int height);
-
- ///
- /// Checks if a block tree entry is in the chain.
- /// Returns 1 if in chain, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_contains")]
- public static extern int ChainContains(IntPtr chain, IntPtr block_tree_entry);
-
- #endregion
-
- #region Transaction Operations
-
- ///
- /// Creates a transaction from serialized data.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_create")]
- public static extern IntPtr TransactionCreate(IntPtr raw_transaction, nuint raw_transaction_len);
-
- ///
- /// Copies a transaction (reference counted).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_copy")]
- public static extern IntPtr TransactionCopy(IntPtr transaction);
-
- ///
- /// Serializes a transaction to bytes.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_to_bytes")]
- public static extern int TransactionToBytes(
- IntPtr transaction,
- WriteBytes writer,
- IntPtr user_data);
-
- ///
- /// Gets the transaction ID (txid).
- /// Returns a pointer to btck_Txid (not owned, lifetime depends on transaction).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_txid")]
- public static extern IntPtr TransactionGetTxid(IntPtr transaction);
-
- ///
- /// Gets the number of outputs in a transaction.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_count_outputs")]
- public static extern nuint TransactionCountOutputs(IntPtr transaction);
-
- ///
- /// Gets the number of inputs in a transaction.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_count_inputs")]
- public static extern nuint TransactionCountInputs(IntPtr transaction);
-
- ///
- /// Gets a transaction output at the specified index.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_output_at")]
- public static extern IntPtr TransactionGetOutputAt(IntPtr transaction, nuint index);
-
- ///
- /// Gets a transaction input at the specified index.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_input_at")]
- public static extern IntPtr TransactionGetInputAt(IntPtr transaction, nuint index);
-
- ///
- /// Destroys a transaction.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_destroy")]
- public static extern void TransactionDestroy(IntPtr transaction);
-
- ///
- /// Gets the script pubkey from a transaction output.
- /// Returns a pointer to btck_ScriptPubkey.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_get_script_pubkey")]
- public static extern IntPtr TransactionOutputGetScriptPubkey(IntPtr output);
-
- ///
- /// Gets the value (amount) from a transaction output.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_get_amount")]
- public static extern long TransactionOutputGetAmount(IntPtr output);
-
- ///
- /// Copy a transaction output.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_copy")]
- public static extern IntPtr TransactionOutputCopy(IntPtr output);
-
- ///
- /// Destroys a transaction output.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_destroy")]
- public static extern void TransactionOutputDestroy(IntPtr output);
-
- #endregion
-
- #region PrecomputedTransactionData Operations
-
- ///
- /// Creates precomputed transaction data for script verification.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_create")]
- public static extern IntPtr PrecomputedTransactionDataCreate(
- IntPtr tx_to,
- IntPtr[] spent_outputs,
- nuint spent_outputs_len);
-
- ///
- /// Copies precomputed transaction data.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_copy")]
- public static extern IntPtr PrecomputedTransactionDataCopy(IntPtr precomputed_txdata);
-
- ///
- /// Destroys precomputed transaction data.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_destroy")]
- public static extern void PrecomputedTransactionDataDestroy(IntPtr precomputed_txdata);
-
- #endregion
-
- #region ScriptPubkey Operations
-
- ///
- /// Creates a script pubkey from serialized data.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_create")]
- public static extern IntPtr ScriptPubkeyCreate(IntPtr script_pubkey_data, nuint script_pubkey_len);
-
- ///
- /// Copies a script pubkey.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_copy")]
- public static extern IntPtr ScriptPubkeyCopy(IntPtr script_pubkey);
-
- ///
- /// Verifies a script pubkey.
- /// Returns 1 if valid, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_verify")]
- public static extern int ScriptPubkeyVerify(
- IntPtr script_pubkey,
- long amount,
- IntPtr tx_to,
- IntPtr precomputed_txdata,
- uint input_index,
- uint flags,
- IntPtr status);
-
- ///
- /// Serializes a script pubkey to bytes.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_to_bytes")]
- public static extern int ScriptPubkeyToBytes(
- IntPtr script_pubkey,
- WriteBytes writer,
- IntPtr user_data);
-
- ///
- /// Destroys a script pubkey.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_destroy")]
- public static extern void ScriptPubkeyDestroy(IntPtr script_pubkey);
-
- #endregion
-
- #region TransactionOutput Operations (Additional)
-
- ///
- /// Creates a transaction output from a script pubkey and amount.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_create")]
- public static extern IntPtr TransactionOutputCreate(IntPtr script_pubkey, long amount);
-
- #endregion
-
- #region Logging
-
- ///
- /// Creates a logging connection with a callback.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_connection_create")]
- public static extern IntPtr LoggingConnectionCreate(
- LoggingCallback callback,
- IntPtr user_data,
- DestroyCallback? user_data_destroy_callback);
-
- ///
- /// Destroys a logging connection.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_connection_destroy")]
- public static extern void LoggingConnectionDestroy(IntPtr connection);
-
- ///
- /// Disables logging permanently.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_disable")]
- public static extern void LoggingDisable();
-
- ///
- /// Sets the log level for a category.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_set_level_category")]
- public static extern void LoggingSetLevelCategory(LogCategory category, LogLevel level);
-
- ///
- /// Sets logging options.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_set_options")]
- public static extern void LoggingSetOptions(LoggingOptions options);
-
- ///
- /// Enables a log category.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_enable_category")]
- public static extern void LoggingEnableCategory(LogCategory category);
-
- ///
- /// Disables a log category.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_disable_category")]
- public static extern void LoggingDisableCategory(LogCategory category);
-
- #endregion
-
- #region Block Validation State
-
- ///
- /// Creates a new block validation state.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_create")]
- public static extern IntPtr BlockValidationStateCreate();
-
- ///
- /// Gets the validation mode from a block validation state.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_get_validation_mode")]
- public static extern ValidationMode BlockValidationStateGetValidationMode(IntPtr validation_state);
-
- ///
- /// Gets the block validation result from a block validation state.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_get_block_validation_result")]
- public static extern BlockValidationResult BlockValidationStateGetBlockValidationResult(IntPtr validation_state);
-
- ///
- /// Copies a block validation state.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_copy")]
- public static extern IntPtr BlockValidationStateCopy(IntPtr validation_state);
-
- ///
- /// Destroys a block validation state.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_destroy")]
- public static extern void BlockValidationStateDestroy(IntPtr validation_state);
-
- #endregion
-
- #region Txid Operations
-
- ///
- /// Copies a txid.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_copy")]
- public static extern IntPtr TxidCopy(IntPtr txid);
-
- ///
- /// Checks if two txids are equal.
- /// Returns 1 if equal, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_equals")]
- public static extern int TxidEquals(IntPtr txid1, IntPtr txid2);
-
- ///
- /// Serializes a txid to bytes (32 bytes).
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_to_bytes")]
- public static extern void TxidToBytes(IntPtr txid, [MarshalAs(UnmanagedType.LPArray, SizeConst = 32)] byte[] output);
-
- ///
- /// Destroys a txid.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_destroy")]
- public static extern void TxidDestroy(IntPtr txid);
-
- #endregion
-
- #region Coin Operations
-
- ///
- /// Copies a coin.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_copy")]
- public static extern IntPtr CoinCopy(IntPtr coin);
-
- ///
- /// Returns the block height where the transaction that created this coin was included.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_confirmation_height")]
- public static extern uint CoinConfirmationHeight(IntPtr coin);
-
- ///
- /// Returns whether the containing transaction was a coinbase.
- /// Returns 1 if coinbase, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_is_coinbase")]
- public static extern int CoinIsCoinbase(IntPtr coin);
-
- ///
- /// Gets the transaction output of a coin.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_get_output")]
- public static extern IntPtr CoinGetOutput(IntPtr coin);
-
- ///
- /// Destroys a coin.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_destroy")]
- public static extern void CoinDestroy(IntPtr coin);
-
- #endregion
-
-
-
- #region BlockSpentOutputs Operations
-
- ///
- /// Reads block spent outputs (undo data) from disk.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_read")]
- public static extern IntPtr BlockSpentOutputsRead(
- IntPtr chainstate_manager,
- IntPtr block_tree_entry);
-
- ///
- /// Copies block spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_copy")]
- public static extern IntPtr BlockSpentOutputsCopy(IntPtr block_spent_outputs);
-
- ///
- /// Gets the count of transaction spent outputs in block spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_count")]
- public static extern nuint BlockSpentOutputsCount(IntPtr block_spent_outputs);
-
- ///
- /// Gets transaction spent outputs at the specified index.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_get_transaction_spent_outputs_at")]
- public static extern IntPtr BlockSpentOutputsGetTransactionSpentOutputsAt(
- IntPtr block_spent_outputs,
- nuint index);
-
- ///
- /// Destroys block spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_destroy")]
- public static extern void BlockSpentOutputsDestroy(IntPtr block_spent_outputs);
-
- #endregion
-
- #region TransactionSpentOutputs Operations
-
- ///
- /// Copies transaction spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_copy")]
- public static extern IntPtr TransactionSpentOutputsCopy(IntPtr transaction_spent_outputs);
-
- ///
- /// Gets the count of coins in transaction spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_count")]
- public static extern nuint TransactionSpentOutputsCount(IntPtr transaction_spent_outputs);
-
- ///
- /// Gets a coin at the specified index.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_get_coin_at")]
- public static extern IntPtr TransactionSpentOutputsGetCoinAt(
- IntPtr transaction_spent_outputs,
- nuint index);
-
- ///
- /// Destroys transaction spent outputs.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_destroy")]
- public static extern void TransactionSpentOutputsDestroy(IntPtr transaction_spent_outputs);
-
- #endregion
-
- #region Missing Functions
-
- ///
- /// Copy a context.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_copy")]
- public static extern IntPtr ContextCopy(IntPtr context);
-
- ///
- /// Copy chain parameters.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_copy")]
- public static extern IntPtr ChainParametersCopy(IntPtr chain_params);
-
- ///
- /// Checks if two block hashes are equal.
- /// Returns 1 if equal, 0 otherwise.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_equals")]
- public static extern int BlockHashEquals(IntPtr hash1, IntPtr hash2);
-
- ///
- /// Copy a block hash.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_copy")]
- public static extern IntPtr BlockHashCopy(IntPtr block_hash);
-
- #endregion
-
- #region TransactionInput Operations
-
- ///
- /// Copies a transaction input.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_copy")]
- public static extern IntPtr TransactionInputCopy(IntPtr transaction_input);
-
- ///
- /// Gets the transaction out point from a transaction input.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_get_out_point")]
- public static extern IntPtr TransactionInputGetOutPoint(IntPtr transaction_input);
-
- ///
- /// Destroys a transaction input.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_destroy")]
- public static extern void TransactionInputDestroy(IntPtr transaction_input);
-
- #endregion
-
- #region TransactionOutPoint Operations
-
- ///
- /// Copies a transaction out point.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_copy")]
- public static extern IntPtr TransactionOutPointCopy(IntPtr transaction_out_point);
-
- ///
- /// Gets the output index from a transaction out point.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_get_index")]
- public static extern uint TransactionOutPointGetIndex(IntPtr transaction_out_point);
-
- ///
- /// Gets the txid from a transaction out point.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_get_txid")]
- public static extern IntPtr TransactionOutPointGetTxid(IntPtr transaction_out_point);
-
- ///
- /// Destroys a transaction out point.
- ///
- [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_destroy")]
- public static extern void TransactionOutPointDestroy(IntPtr transaction_out_point);
-
- #endregion
+ /// Pointer to kernel context, or IntPtr.Zero on failure
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_create")]
+ public static extern IntPtr ContextCreate(IntPtr options);
- }
-}
\ No newline at end of file
+ ///
+ /// Destroys a kernel context and frees associated resources.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_destroy")]
+ public static extern void ContextDestroy(IntPtr context);
+
+ ///
+ /// Interrupts long-running operations associated with this context.
+ /// Returns 0 on success.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_interrupt")]
+ public static extern int ContextInterrupt(IntPtr context);
+
+ #endregion
+
+ #region Context Options
+
+ ///
+ /// Creates context options with default values.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_create")]
+ public static extern IntPtr ContextOptionsCreate();
+
+ ///
+ /// Destroys context options.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_destroy")]
+ public static extern void ContextOptionsDestroy(IntPtr options);
+
+ ///
+ /// Sets the chain parameters for the context.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_chainparams")]
+ public static extern void ContextOptionsSetChainParams(IntPtr options, IntPtr chain_params);
+
+ ///
+ /// Sets the notification callbacks for the context.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_notifications")]
+ public static extern void ContextOptionsSetNotifications(IntPtr options, NotificationInterfaceCallbacks callbacks);
+
+ ///
+ /// Sets the validation interface for the context.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_options_set_validation_interface")]
+ public static extern void ContextOptionsSetValidationInterface(IntPtr options, ValidationInterfaceCallbacks callbacks);
+
+ #endregion
+
+ #region Chain Parameters
+
+ ///
+ /// Creates chain parameters for the specified chain type.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_create")]
+ public static extern IntPtr ChainParametersCreate(ChainType chain_type);
+
+ ///
+ /// Destroys chain parameters.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_destroy")]
+ public static extern void ChainParametersDestroy(IntPtr chain_params);
+
+ #endregion
+
+ #region Chainstate Manager
+
+ ///
+ /// Creates a chainstate manager.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_create")]
+ public static extern IntPtr ChainstateManagerCreate(IntPtr options);
+
+ ///
+ /// Destroys a chainstate manager.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_destroy")]
+ public static extern void ChainstateManagerDestroy(IntPtr manager);
+
+ ///
+ /// Processes a block through validation.
+ /// Returns 0 on success.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_process_block")]
+ public static extern int ChainstateManagerProcessBlock(
+ IntPtr manager,
+ IntPtr block,
+ ref int new_block);
+
+ ///
+ /// Gets a block tree entry by its block hash.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_block_tree_entry_by_hash")]
+ public static extern IntPtr ChainstateManagerGetBlockTreeEntryByHash(
+ IntPtr manager,
+ IntPtr block_hash);
+
+ ///
+ /// Gets the active chain from the chainstate manager.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_active_chain")]
+ public static extern IntPtr ChainstateManagerGetActiveChain(IntPtr manager);
+
+ ///
+ /// Gets the block tree entry with the most cumulative proof of work.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_get_best_entry")]
+ public static extern IntPtr ChainstateManagerGetBestEntry(IntPtr manager);
+
+ ///
+ /// Processes and validates a block header.
+ /// Returns 0 on success.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_process_block_header")]
+ public static extern int ChainstateManagerProcessBlockHeader(
+ IntPtr manager,
+ IntPtr header,
+ IntPtr block_validation_state);
+
+ ///
+ /// Imports blocks from an array of file paths.
+ /// Returns 0 on success.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_import_blocks")]
+ public static extern int ChainstateManagerImportBlocks(
+ IntPtr manager,
+ [MarshalAs(UnmanagedType.LPArray)] string[] block_file_paths_data,
+ nuint[] block_file_paths_lens,
+ nuint block_file_paths_data_len);
+
+ #endregion
+
+ #region Chainstate Manager Options
+
+ ///
+ /// Creates chainstate manager options.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_create")]
+ public static extern IntPtr ChainstateManagerOptionsCreate(
+ IntPtr context,
+ [MarshalAs(UnmanagedType.LPUTF8Str)] string data_directory,
+ nuint data_directory_len,
+ [MarshalAs(UnmanagedType.LPUTF8Str)] string blocks_directory,
+ nuint blocks_directory_len);
+
+ ///
+ /// Destroys chainstate manager options.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_destroy")]
+ public static extern void ChainstateManagerOptionsDestroy(IntPtr options);
+
+ ///
+ /// Sets the number of worker threads for script verification.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_set_worker_threads_num")]
+ public static extern void ChainstateManagerOptionsSetWorkerThreads(
+ IntPtr options,
+ int worker_threads);
+
+ ///
+ /// Sets whether to wipe the databases on load.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_set_wipe_dbs")]
+ public static extern int ChainstateManagerOptionsSetWipeDbs(
+ IntPtr options,
+ int wipe_block_tree_db,
+ int wipe_chainstate_db);
+
+ ///
+ /// Sets block tree db in memory.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_update_block_tree_db_in_memory")]
+ public static extern void ChainstateManagerOptionsUpdateBlockTreeDbInMemory(
+ IntPtr options,
+ int block_tree_db_in_memory);
+
+ ///
+ /// Sets chainstate db in memory.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chainstate_manager_options_update_chainstate_db_in_memory")]
+ public static extern void ChainstateManagerOptionsUpdateChainstateDbInMemory(
+ IntPtr options,
+ int chainstate_db_in_memory);
+
+ #endregion
+
+ #region Block Operations
+
+ ///
+ /// Creates a block from raw data.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_create")]
+ public static extern IntPtr BlockCreate(
+ byte[] raw_block,
+ UIntPtr raw_block_len);
+
+ ///
+ /// Destroys a block.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_destroy")]
+ public static extern void BlockDestroy(IntPtr block);
+
+ ///
+ /// Reads a block from disk by its block tree entry.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_read")]
+ public static extern IntPtr BlockRead(
+ IntPtr chainstate_manager,
+ IntPtr block_tree_entry);
+
+ ///
+ /// Gets the number of transactions in a block.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_count_transactions")]
+ public static extern nuint BlockCountTransactions(IntPtr block);
+
+ ///
+ /// Gets the block hash.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_hash")]
+ public static extern IntPtr BlockGetHash(IntPtr block);
+
+ ///
+ /// Gets the block header from a block.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_header")]
+ public static extern IntPtr BlockGetHeader(IntPtr block);
+
+ ///
+ /// Serializes the block to bytes.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_to_bytes")]
+ public static extern int BlockToBytes(
+ IntPtr block,
+ WriteBytes writer,
+ IntPtr user_data);
+
+ ///
+ /// Delegate for writing bytes during serialization.
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int WriteBytes(IntPtr bytes, nuint size, IntPtr userdata);
+
+ ///
+ /// Gets the block hash from a block tree entry.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_block_hash")]
+ public static extern IntPtr BlockTreeEntryGetBlockHash(IntPtr block_tree_entry);
+
+ ///
+ /// Gets the block height from a block tree entry.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_height")]
+ public static extern int BlockTreeEntryGetHeight(IntPtr block_tree_entry);
+
+ ///
+ /// Gets the previous block tree entry from a block tree entry.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_previous")]
+ public static extern IntPtr BlockTreeEntryGetPrevious(IntPtr block_tree_entry);
+
+ ///
+ /// Gets the block header from a block tree entry.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_get_block_header")]
+ public static extern IntPtr BlockTreeEntryGetBlockHeader(IntPtr block_tree_entry);
+
+ ///
+ /// Checks if two block tree entries are equal. Two block tree entries are equal when they
+ /// point to the same block.
+ /// Returns 1 if equal, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_tree_entry_equals")]
+ public static extern int BlockTreeEntryEquals(IntPtr entry1, IntPtr entry2);
+
+ ///
+ /// Copies a block (reference counted).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_copy")]
+ public static extern IntPtr BlockCopy(IntPtr block);
+
+ ///
+ /// Gets a transaction at the specified index in a block.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_get_transaction_at")]
+ public static extern IntPtr BlockGetTransactionAt(IntPtr block, nuint index);
+
+ #endregion
+
+ #region BlockHash Operations
+
+ ///
+ /// Creates a block hash from 32 bytes.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_create")]
+ public static extern IntPtr BlockHashCreate(IntPtr hash);
+
+ ///
+ /// Creates a block hash from 32 bytes (unsafe version).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_create")]
+ public static extern unsafe IntPtr BlockHashCreate(byte* hash);
+
+ ///
+ /// Serializes the block hash to bytes (32 bytes).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_to_bytes")]
+ public static extern void BlockHashToBytes(IntPtr block_hash, [MarshalAs(UnmanagedType.LPArray, SizeConst = 32)] byte[] output);
+
+ ///
+ /// Destroys a block hash.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_destroy")]
+ public static extern void BlockHashDestroy(IntPtr block_hash);
+
+ #endregion
+
+ #region Block Header Operations
+
+ ///
+ /// Creates a block header from raw serialized data (80 bytes).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_create")]
+ public static extern IntPtr BlockHeaderCreate(
+ byte[] raw_block_header,
+ UIntPtr raw_block_header_len);
+
+ ///
+ /// Copies a block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_copy")]
+ public static extern IntPtr BlockHeaderCopy(IntPtr header);
+
+ ///
+ /// Gets the block hash from a block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_hash")]
+ public static extern IntPtr BlockHeaderGetHash(IntPtr header);
+
+ ///
+ /// Gets the previous block hash from a block header.
+ /// The returned hash is unowned and only valid for the lifetime of the block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_prev_hash")]
+ public static extern IntPtr BlockHeaderGetPrevHash(IntPtr header);
+
+ ///
+ /// Gets the timestamp from a block header (Unix epoch seconds).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_timestamp")]
+ public static extern uint BlockHeaderGetTimestamp(IntPtr header);
+
+ ///
+ /// Gets the nBits difficulty target from a block header (compact format).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_bits")]
+ public static extern uint BlockHeaderGetBits(IntPtr header);
+
+ ///
+ /// Gets the version from a block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_version")]
+ public static extern int BlockHeaderGetVersion(IntPtr header);
+
+ ///
+ /// Gets the nonce from a block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_get_nonce")]
+ public static extern uint BlockHeaderGetNonce(IntPtr header);
+
+ ///
+ /// Destroys a block header.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_header_destroy")]
+ public static extern void BlockHeaderDestroy(IntPtr header);
+
+ #endregion
+
+ #region Chain Operations
+
+ ///
+ /// Gets the height of the chain.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_get_height")]
+ public static extern int ChainGetHeight(IntPtr chain);
+
+ ///
+ /// Gets a block tree entry by height.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_get_by_height")]
+ public static extern IntPtr ChainGetByHeight(IntPtr chain, int height);
+
+ ///
+ /// Checks if a block tree entry is in the chain.
+ /// Returns 1 if in chain, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_contains")]
+ public static extern int ChainContains(IntPtr chain, IntPtr block_tree_entry);
+
+ #endregion
+
+ #region Transaction Operations
+
+ ///
+ /// Creates a transaction from serialized data.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_create")]
+ public static extern IntPtr TransactionCreate(IntPtr raw_transaction, nuint raw_transaction_len);
+
+ ///
+ /// Copies a transaction (reference counted).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_copy")]
+ public static extern IntPtr TransactionCopy(IntPtr transaction);
+
+ ///
+ /// Serializes a transaction to bytes.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_to_bytes")]
+ public static extern int TransactionToBytes(
+ IntPtr transaction,
+ WriteBytes writer,
+ IntPtr user_data);
+
+ ///
+ /// Gets the transaction ID (txid).
+ /// Returns a pointer to btck_Txid (not owned, lifetime depends on transaction).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_txid")]
+ public static extern IntPtr TransactionGetTxid(IntPtr transaction);
+
+ ///
+ /// Gets the number of outputs in a transaction.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_count_outputs")]
+ public static extern nuint TransactionCountOutputs(IntPtr transaction);
+
+ ///
+ /// Gets the number of inputs in a transaction.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_count_inputs")]
+ public static extern nuint TransactionCountInputs(IntPtr transaction);
+
+ ///
+ /// Gets a transaction output at the specified index.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_output_at")]
+ public static extern IntPtr TransactionGetOutputAt(IntPtr transaction, nuint index);
+
+ ///
+ /// Gets a transaction input at the specified index.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_get_input_at")]
+ public static extern IntPtr TransactionGetInputAt(IntPtr transaction, nuint index);
+
+ ///
+ /// Destroys a transaction.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_destroy")]
+ public static extern void TransactionDestroy(IntPtr transaction);
+
+ ///
+ /// Gets the script pubkey from a transaction output.
+ /// Returns a pointer to btck_ScriptPubkey.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_get_script_pubkey")]
+ public static extern IntPtr TransactionOutputGetScriptPubkey(IntPtr output);
+
+ ///
+ /// Gets the value (amount) from a transaction output.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_get_amount")]
+ public static extern long TransactionOutputGetAmount(IntPtr output);
+
+ ///
+ /// Copy a transaction output.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_copy")]
+ public static extern IntPtr TransactionOutputCopy(IntPtr output);
+
+ ///
+ /// Destroys a transaction output.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_destroy")]
+ public static extern void TransactionOutputDestroy(IntPtr output);
+
+ #endregion
+
+ #region PrecomputedTransactionData Operations
+
+ ///
+ /// Creates precomputed transaction data for script verification.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_create")]
+ public static extern IntPtr PrecomputedTransactionDataCreate(
+ IntPtr tx_to,
+ IntPtr[] spent_outputs,
+ nuint spent_outputs_len);
+
+ ///
+ /// Copies precomputed transaction data.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_copy")]
+ public static extern IntPtr PrecomputedTransactionDataCopy(IntPtr precomputed_txdata);
+
+ ///
+ /// Destroys precomputed transaction data.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_precomputed_transaction_data_destroy")]
+ public static extern void PrecomputedTransactionDataDestroy(IntPtr precomputed_txdata);
+
+ #endregion
+
+ #region ScriptPubkey Operations
+
+ ///
+ /// Creates a script pubkey from serialized data.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_create")]
+ public static extern IntPtr ScriptPubkeyCreate(IntPtr script_pubkey_data, nuint script_pubkey_len);
+
+ ///
+ /// Copies a script pubkey.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_copy")]
+ public static extern IntPtr ScriptPubkeyCopy(IntPtr script_pubkey);
+
+ ///
+ /// Verifies a script pubkey.
+ /// Returns 1 if valid, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_verify")]
+ public static extern int ScriptPubkeyVerify(
+ IntPtr script_pubkey,
+ long amount,
+ IntPtr tx_to,
+ IntPtr precomputed_txdata,
+ uint input_index,
+ uint flags,
+ IntPtr status);
+
+ ///
+ /// Serializes a script pubkey to bytes.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_to_bytes")]
+ public static extern int ScriptPubkeyToBytes(
+ IntPtr script_pubkey,
+ WriteBytes writer,
+ IntPtr user_data);
+
+ ///
+ /// Destroys a script pubkey.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_script_pubkey_destroy")]
+ public static extern void ScriptPubkeyDestroy(IntPtr script_pubkey);
+
+ #endregion
+
+ #region TransactionOutput Operations (Additional)
+
+ ///
+ /// Creates a transaction output from a script pubkey and amount.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_output_create")]
+ public static extern IntPtr TransactionOutputCreate(IntPtr script_pubkey, long amount);
+
+ #endregion
+
+ #region Logging
+
+ ///
+ /// Creates a logging connection with a callback.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_connection_create")]
+ public static extern IntPtr LoggingConnectionCreate(
+ LoggingCallback callback,
+ IntPtr user_data,
+ DestroyCallback? user_data_destroy_callback);
+
+ ///
+ /// Destroys a logging connection.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_connection_destroy")]
+ public static extern void LoggingConnectionDestroy(IntPtr connection);
+
+ ///
+ /// Disables logging permanently.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_disable")]
+ public static extern void LoggingDisable();
+
+ ///
+ /// Sets the log level for a category.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_set_level_category")]
+ public static extern void LoggingSetLevelCategory(LogCategory category, LogLevel level);
+
+ ///
+ /// Sets logging options.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_set_options")]
+ public static extern void LoggingSetOptions(LoggingOptions options);
+
+ ///
+ /// Enables a log category.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_enable_category")]
+ public static extern void LoggingEnableCategory(LogCategory category);
+
+ ///
+ /// Disables a log category.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_logging_disable_category")]
+ public static extern void LoggingDisableCategory(LogCategory category);
+
+ #endregion
+
+ #region Block Validation State
+
+ ///
+ /// Creates a new block validation state.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_create")]
+ public static extern IntPtr BlockValidationStateCreate();
+
+ ///
+ /// Gets the validation mode from a block validation state.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_get_validation_mode")]
+ public static extern ValidationMode BlockValidationStateGetValidationMode(IntPtr validation_state);
+
+ ///
+ /// Gets the block validation result from a block validation state.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_get_block_validation_result")]
+ public static extern BlockValidationResult BlockValidationStateGetBlockValidationResult(IntPtr validation_state);
+
+ ///
+ /// Copies a block validation state.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_copy")]
+ public static extern IntPtr BlockValidationStateCopy(IntPtr validation_state);
+
+ ///
+ /// Destroys a block validation state.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_validation_state_destroy")]
+ public static extern void BlockValidationStateDestroy(IntPtr validation_state);
+
+ #endregion
+
+ #region Txid Operations
+
+ ///
+ /// Copies a txid.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_copy")]
+ public static extern IntPtr TxidCopy(IntPtr txid);
+
+ ///
+ /// Checks if two txids are equal.
+ /// Returns 1 if equal, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_equals")]
+ public static extern int TxidEquals(IntPtr txid1, IntPtr txid2);
+
+ ///
+ /// Serializes a txid to bytes (32 bytes).
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_to_bytes")]
+ public static extern void TxidToBytes(IntPtr txid, [MarshalAs(UnmanagedType.LPArray, SizeConst = 32)] byte[] output);
+
+ ///
+ /// Destroys a txid.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_txid_destroy")]
+ public static extern void TxidDestroy(IntPtr txid);
+
+ #endregion
+
+ #region Coin Operations
+
+ ///
+ /// Copies a coin.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_copy")]
+ public static extern IntPtr CoinCopy(IntPtr coin);
+
+ ///
+ /// Returns the block height where the transaction that created this coin was included.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_confirmation_height")]
+ public static extern uint CoinConfirmationHeight(IntPtr coin);
+
+ ///
+ /// Returns whether the containing transaction was a coinbase.
+ /// Returns 1 if coinbase, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_is_coinbase")]
+ public static extern int CoinIsCoinbase(IntPtr coin);
+
+ ///
+ /// Gets the transaction output of a coin.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_get_output")]
+ public static extern IntPtr CoinGetOutput(IntPtr coin);
+
+ ///
+ /// Destroys a coin.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_coin_destroy")]
+ public static extern void CoinDestroy(IntPtr coin);
+
+ #endregion
+
+
+
+ #region BlockSpentOutputs Operations
+
+ ///
+ /// Reads block spent outputs (undo data) from disk.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_read")]
+ public static extern IntPtr BlockSpentOutputsRead(
+ IntPtr chainstate_manager,
+ IntPtr block_tree_entry);
+
+ ///
+ /// Copies block spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_copy")]
+ public static extern IntPtr BlockSpentOutputsCopy(IntPtr block_spent_outputs);
+
+ ///
+ /// Gets the count of transaction spent outputs in block spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_count")]
+ public static extern nuint BlockSpentOutputsCount(IntPtr block_spent_outputs);
+
+ ///
+ /// Gets transaction spent outputs at the specified index.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_get_transaction_spent_outputs_at")]
+ public static extern IntPtr BlockSpentOutputsGetTransactionSpentOutputsAt(
+ IntPtr block_spent_outputs,
+ nuint index);
+
+ ///
+ /// Destroys block spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_spent_outputs_destroy")]
+ public static extern void BlockSpentOutputsDestroy(IntPtr block_spent_outputs);
+
+ #endregion
+
+ #region TransactionSpentOutputs Operations
+
+ ///
+ /// Copies transaction spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_copy")]
+ public static extern IntPtr TransactionSpentOutputsCopy(IntPtr transaction_spent_outputs);
+
+ ///
+ /// Gets the count of coins in transaction spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_count")]
+ public static extern nuint TransactionSpentOutputsCount(IntPtr transaction_spent_outputs);
+
+ ///
+ /// Gets a coin at the specified index.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_get_coin_at")]
+ public static extern IntPtr TransactionSpentOutputsGetCoinAt(
+ IntPtr transaction_spent_outputs,
+ nuint index);
+
+ ///
+ /// Destroys transaction spent outputs.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_spent_outputs_destroy")]
+ public static extern void TransactionSpentOutputsDestroy(IntPtr transaction_spent_outputs);
+
+ #endregion
+
+ #region Missing Functions
+
+ ///
+ /// Copy a context.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_context_copy")]
+ public static extern IntPtr ContextCopy(IntPtr context);
+
+ ///
+ /// Copy chain parameters.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_chain_parameters_copy")]
+ public static extern IntPtr ChainParametersCopy(IntPtr chain_params);
+
+ ///
+ /// Checks if two block hashes are equal.
+ /// Returns 1 if equal, 0 otherwise.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_equals")]
+ public static extern int BlockHashEquals(IntPtr hash1, IntPtr hash2);
+
+ ///
+ /// Copy a block hash.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_block_hash_copy")]
+ public static extern IntPtr BlockHashCopy(IntPtr block_hash);
+
+ #endregion
+
+ #region TransactionInput Operations
+
+ ///
+ /// Copies a transaction input.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_copy")]
+ public static extern IntPtr TransactionInputCopy(IntPtr transaction_input);
+
+ ///
+ /// Gets the transaction out point from a transaction input.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_get_out_point")]
+ public static extern IntPtr TransactionInputGetOutPoint(IntPtr transaction_input);
+
+ ///
+ /// Destroys a transaction input.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_input_destroy")]
+ public static extern void TransactionInputDestroy(IntPtr transaction_input);
+
+ #endregion
+
+ #region TransactionOutPoint Operations
+
+ ///
+ /// Copies a transaction out point.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_copy")]
+ public static extern IntPtr TransactionOutPointCopy(IntPtr transaction_out_point);
+
+ ///
+ /// Gets the output index from a transaction out point.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_get_index")]
+ public static extern uint TransactionOutPointGetIndex(IntPtr transaction_out_point);
+
+ ///
+ /// Gets the txid from a transaction out point.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_get_txid")]
+ public static extern IntPtr TransactionOutPointGetTxid(IntPtr transaction_out_point);
+
+ ///
+ /// Destroys a transaction out point.
+ ///
+ [DllImport(LibName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "btck_transaction_out_point_destroy")]
+ public static extern void TransactionOutPointDestroy(IntPtr transaction_out_point);
+
+ #endregion
+
+}
diff --git a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs
index b623e51..42cc099 100644
--- a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs
+++ b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs
@@ -1,14 +1,13 @@
using System.Runtime.InteropServices;
-namespace BitcoinKernel.Interop.Structs
+namespace BitcoinKernel.Interop.Structs;
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct LoggingOptions
{
- [StructLayout(LayoutKind.Sequential)]
- public struct LoggingOptions
- {
- public int LogTimestamps;
- public int LogTimeMicros;
- public int LogThreadNames;
- public int LogSourceLocations;
- public int AlwaysPrintCategoryLevels;
- }
-}
\ No newline at end of file
+ public int LogTimestamps;
+ public int LogTimeMicros;
+ public int LogThreadNames;
+ public int LogSourceLocations;
+ public int AlwaysPrintCategoryLevels;
+}
diff --git a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs
index 599ba14..583a013 100644
--- a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs
+++ b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs
@@ -1,18 +1,17 @@
using System.Runtime.InteropServices;
using BitcoinKernel.Interop.Delegates.Notification;
-namespace BitcoinKernel.Interop.Structs
+namespace BitcoinKernel.Interop.Structs;
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct NotificationInterfaceCallbacks
{
- [StructLayout(LayoutKind.Sequential)]
- public struct NotificationInterfaceCallbacks
- {
- public IntPtr UserData;
- public NotifyBlockTip BlockTip;
- public NotifyHeaderTip HeaderTip;
- public NotifyProgress Progress;
- public NotifyWarningSet WarningSet;
- public NotifyWarningUnset WarningUnset;
- public NotifyFlushError FlushError;
- public NotifyFatalError FatalError;
- }
-}
\ No newline at end of file
+ public IntPtr UserData;
+ public NotifyBlockTip BlockTip;
+ public NotifyHeaderTip HeaderTip;
+ public NotifyProgress Progress;
+ public NotifyWarningSet WarningSet;
+ public NotifyWarningUnset WarningUnset;
+ public NotifyFlushError FlushError;
+ public NotifyFatalError FatalError;
+}
diff --git a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs
index 8bd4a36..6215fae 100644
--- a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs
+++ b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs
@@ -1,15 +1,14 @@
using System.Runtime.InteropServices;
using BitcoinKernel.Interop.Delegates.Validation;
-namespace BitcoinKernel.Interop.Structs
+namespace BitcoinKernel.Interop.Structs;
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct ValidationInterfaceCallbacks
{
- [StructLayout(LayoutKind.Sequential)]
- public struct ValidationInterfaceCallbacks
- {
- public IntPtr UserData;
- public ValidationBlockChecked BlockChecked;
- public ValidationNewPoWValidBlock NewPoWValidBlock;
- public ValidationBlockConnected BlockConnected;
- public ValidationBlockDisconnected BlockDisconnected;
- }
-}
\ No newline at end of file
+ public IntPtr UserData;
+ public ValidationBlockChecked BlockChecked;
+ public ValidationNewPoWValidBlock NewPoWValidBlock;
+ public ValidationBlockConnected BlockConnected;
+ public ValidationBlockDisconnected BlockDisconnected;
+}
diff --git a/src/BitcoinKernel/BitcoinKernel.csproj b/src/BitcoinKernel/BitcoinKernel.csproj
index 985896a..ee489a7 100644
--- a/src/BitcoinKernel/BitcoinKernel.csproj
+++ b/src/BitcoinKernel/BitcoinKernel.csproj
@@ -4,31 +4,45 @@
net9.0
enable
enable
- false
+ true
BitcoinKernel
- 0.1.2
+ 0.2.0
JanB84
- .NET library for Bitcoin Core functionality. Provides a simple, fluent API for Bitcoin consensus validation, script verification, and blockchain operations powered by libbitcoinkernel.
+ .NET bindings and managed wrappers for libbitcoinkernel. Provides direct access to Bitcoin Core consensus and validation logic with automatic memory management.
MIT
https://github.com/JanB84/BitcoinKernel.NET
https://github.com/JanB84/BitcoinKernel.NET
git
- bitcoin;kernel;libbitcoinkernel;blockchain;facade;easy
+ bitcoin;kernel;libbitcoinkernel;wrapper;core;blockchain
false
true
snupkg
- README.md
+
+ $(TargetsForTfmSpecificContentInPackage);IncludeReferencedProjectsInPackage
-
-
-
-
-
+
+
+
+
+
+
+ <_PackageFiles Include="$(OutputPath)BitcoinKernel.Interop.dll">
+ Content
+ lib/$(TargetFramework)/BitcoinKernel.Interop.dll
+
+
+
+ <_PackageFiles Include="$(OutputPath)runtimes\**\*.*" Condition="Exists('$(OutputPath)runtimes')">
+ Content
+ runtimes/%(RecursiveDir)%(Filename)%(Extension)
+
+
+
diff --git a/src/BitcoinKernel.Core/BlockProcessing/BlockProcessor.cs b/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs
similarity index 97%
rename from src/BitcoinKernel.Core/BlockProcessing/BlockProcessor.cs
rename to src/BitcoinKernel/BlockProcessing/BlockProcessor.cs
index c0834ba..98fbf25 100644
--- a/src/BitcoinKernel.Core/BlockProcessing/BlockProcessor.cs
+++ b/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs
@@ -1,12 +1,12 @@
using System;
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.Chain;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Chain;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
using BitcoinKernel.Interop.Enums;
-namespace BitcoinKernel.Core.BlockProcessing;
+namespace BitcoinKernel.BlockProcessing;
///
/// Handles block processing operations including validation and chain integration.
diff --git a/src/BitcoinKernel.Core/BlockProcessing/BlockTreeEntry.cs b/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs
similarity index 95%
rename from src/BitcoinKernel.Core/BlockProcessing/BlockTreeEntry.cs
rename to src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs
index 4f481f2..30a8c58 100644
--- a/src/BitcoinKernel.Core/BlockProcessing/BlockTreeEntry.cs
+++ b/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.BlockProcessing;
+namespace BitcoinKernel.BlockProcessing;
///
/// Represents an entry in the block tree (block index).
diff --git a/src/BitcoinKernel.Core/BlockProcessing/BlockValidationResult.cs b/src/BitcoinKernel/BlockProcessing/BlockValidationResult.cs
similarity index 95%
rename from src/BitcoinKernel.Core/BlockProcessing/BlockValidationResult.cs
rename to src/BitcoinKernel/BlockProcessing/BlockValidationResult.cs
index db1149d..79e228d 100644
--- a/src/BitcoinKernel.Core/BlockProcessing/BlockValidationResult.cs
+++ b/src/BitcoinKernel/BlockProcessing/BlockValidationResult.cs
@@ -1,6 +1,6 @@
using BitcoinKernel.Interop.Enums;
-namespace BitcoinKernel.Core.BlockProcessing;
+namespace BitcoinKernel.BlockProcessing;
///
/// Result of a block validation operation.
diff --git a/src/BitcoinKernel.Core/Abstractions/Chain.cs b/src/BitcoinKernel/Chain/Chain.cs
similarity index 92%
rename from src/BitcoinKernel.Core/Abstractions/Chain.cs
rename to src/BitcoinKernel/Chain/Chain.cs
index ce10e3a..271c168 100644
--- a/src/BitcoinKernel.Core/Abstractions/Chain.cs
+++ b/src/BitcoinKernel/Chain/Chain.cs
@@ -1,93 +1,93 @@
-
-
-using System.Dynamic;
-using BitcoinKernel.Core.Exceptions;
-using BitcoinKernel.Interop;
-
-namespace BitcoinKernel.Core.Abstractions;
-
-
-///
-/// Represents the active blockchain.
-///
-public sealed class Chain
-{
- private readonly IntPtr _handle;
-
- internal Chain(IntPtr handle)
- {
- _handle = handle != IntPtr.Zero
- ? handle
- : throw new ArgumentException("Invalid chain handle", nameof(handle));
- }
-
- ///
- /// Gets the height of the chain.
- ///
- public int Height => NativeMethods.ChainGetHeight(_handle);
-
- ///
- /// Gets the tip of the chain.
- ///
- public BlockIndex GetTip()
- {
-
- //get chain by height
- IntPtr tipPtr = NativeMethods.ChainGetByHeight(_handle, Height);
- if (tipPtr == IntPtr.Zero)
- throw new KernelException("Failed to get chain tip");
-
-
- return new BlockIndex(tipPtr, ownsHandle: false);
- }
-
- ///
- /// Gets a block index by height.
- ///
- public BlockIndex? GetBlockByHeight(int height)
- {
- ArgumentOutOfRangeException.ThrowIfNegative(height, nameof(height));
-
- IntPtr blockPtr = NativeMethods.ChainGetByHeight(_handle, height);
- return blockPtr != IntPtr.Zero
- ? new BlockIndex(blockPtr, ownsHandle: false)
- : null;
- }
-
- ///
- /// Gets the genesis block.
- ///
- public BlockIndex GetGenesis()
- {
- IntPtr genesisPtr = NativeMethods.ChainGetByHeight(_handle, 0);
- if (genesisPtr == IntPtr.Zero)
- throw new KernelException("Failed to get genesis block");
-
- return new BlockIndex(genesisPtr, ownsHandle: false);
- }
-
- ///
- /// Checks if a block index is part of this chain.
- ///
- public bool Contains(BlockIndex blockIndex)
- {
- ArgumentNullException.ThrowIfNull(blockIndex);
-
- return NativeMethods.ChainContains(_handle, blockIndex.Handle) != 0;
- }
-
- ///
- /// Enumerates all blocks in the chain from genesis to tip.
- ///
- public IEnumerable EnumerateBlocks()
- {
- for (int height = 0; height <= Height; height++)
- {
- var block = GetBlockByHeight(height);
- if (block != null)
- {
- yield return block;
- }
- }
- }
-}
\ No newline at end of file
+
+
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Exceptions;
+using BitcoinKernel.Interop;
+
+namespace BitcoinKernel.Chain;
+
+
+///
+/// Represents the active blockchain.
+///
+public sealed class Chain
+{
+ private readonly IntPtr _handle;
+
+ internal Chain(IntPtr handle)
+ {
+ _handle = handle != IntPtr.Zero
+ ? handle
+ : throw new ArgumentException("Invalid chain handle", nameof(handle));
+ }
+
+ ///
+ /// Gets the height of the chain.
+ ///
+ public int Height => NativeMethods.ChainGetHeight(_handle);
+
+ ///
+ /// Gets the tip of the chain.
+ ///
+ public BlockIndex GetTip()
+ {
+
+ //get chain by height
+ IntPtr tipPtr = NativeMethods.ChainGetByHeight(_handle, Height);
+ if (tipPtr == IntPtr.Zero)
+ throw new KernelException("Failed to get chain tip");
+
+
+ return new BlockIndex(tipPtr, ownsHandle: false);
+ }
+
+ ///
+ /// Gets a block index by height.
+ ///
+ public BlockIndex? GetBlockByHeight(int height)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(height, nameof(height));
+
+ IntPtr blockPtr = NativeMethods.ChainGetByHeight(_handle, height);
+ return blockPtr != IntPtr.Zero
+ ? new BlockIndex(blockPtr, ownsHandle: false)
+ : null;
+ }
+
+ ///
+ /// Gets the genesis block.
+ ///
+ public BlockIndex GetGenesis()
+ {
+ IntPtr genesisPtr = NativeMethods.ChainGetByHeight(_handle, 0);
+ if (genesisPtr == IntPtr.Zero)
+ throw new KernelException("Failed to get genesis block");
+
+ return new BlockIndex(genesisPtr, ownsHandle: false);
+ }
+
+ ///
+ /// Checks if a block index is part of this chain.
+ ///
+ public bool Contains(BlockIndex blockIndex)
+ {
+ ArgumentNullException.ThrowIfNull(blockIndex);
+
+ return NativeMethods.ChainContains(_handle, blockIndex.Handle) != 0;
+ }
+
+ ///
+ /// Enumerates all blocks in the chain from genesis to tip.
+ ///
+ public IEnumerable EnumerateBlocks()
+ {
+ for (int height = 0; height <= Height; height++)
+ {
+ var block = GetBlockByHeight(height);
+ if (block != null)
+ {
+ yield return block;
+ }
+ }
+ }
+}
diff --git a/src/BitcoinKernel.Core/Chain/ChainParameters.cs b/src/BitcoinKernel/Chain/ChainParameters.cs
similarity index 96%
rename from src/BitcoinKernel.Core/Chain/ChainParameters.cs
rename to src/BitcoinKernel/Chain/ChainParameters.cs
index 3d51d38..52f66ff 100644
--- a/src/BitcoinKernel.Core/Chain/ChainParameters.cs
+++ b/src/BitcoinKernel/Chain/ChainParameters.cs
@@ -1,7 +1,7 @@
using BitcoinKernel.Interop;
using BitcoinKernel.Interop.Enums;
-namespace BitcoinKernel.Core.Chain;
+namespace BitcoinKernel.Chain;
public sealed class ChainParameters : IDisposable
{
diff --git a/src/BitcoinKernel.Core/Chain/ChainStateManager.cs b/src/BitcoinKernel/Chain/ChainStateManager.cs
similarity index 98%
rename from src/BitcoinKernel.Core/Chain/ChainStateManager.cs
rename to src/BitcoinKernel/Chain/ChainStateManager.cs
index 000c639..f44e048 100644
--- a/src/BitcoinKernel.Core/Chain/ChainStateManager.cs
+++ b/src/BitcoinKernel/Chain/ChainStateManager.cs
@@ -1,10 +1,10 @@
using System;
using System.Runtime.InteropServices;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-using BitcoinKernel.Core.Abstractions;
+using BitcoinKernel.Primatives;
-namespace BitcoinKernel.Core.Chain;
+namespace BitcoinKernel.Chain;
///
/// Manages the blockchain state and validation operations.
@@ -54,14 +54,14 @@ internal IntPtr Handle
///
/// Gets the active chain.
///
- public Abstractions.Chain GetActiveChain()
+ public Chain GetActiveChain()
{
ThrowIfDisposed();
IntPtr chainPtr = NativeMethods.ChainstateManagerGetActiveChain(_handle);
if (chainPtr == IntPtr.Zero)
throw new KernelException("Failed to get active chain");
- return new Abstractions.Chain(chainPtr);
+ return new Chain(chainPtr);
}
///
diff --git a/src/BitcoinKernel.Core/Exceptions/Exceptions.cs b/src/BitcoinKernel/Exceptions/Exceptions.cs
similarity index 99%
rename from src/BitcoinKernel.Core/Exceptions/Exceptions.cs
rename to src/BitcoinKernel/Exceptions/Exceptions.cs
index 3b05ae1..d53d73a 100644
--- a/src/BitcoinKernel.Core/Exceptions/Exceptions.cs
+++ b/src/BitcoinKernel/Exceptions/Exceptions.cs
@@ -1,6 +1,6 @@
using BitcoinKernel.Interop.Enums;
-namespace BitcoinKernel.Core.Exceptions;
+namespace BitcoinKernel.Exceptions;
///
/// Base exception for all Bitcoin Kernel-related errors.
diff --git a/src/BitcoinKernel.Core/KernelContext.cs b/src/BitcoinKernel/KernelContext.cs
similarity index 91%
rename from src/BitcoinKernel.Core/KernelContext.cs
rename to src/BitcoinKernel/KernelContext.cs
index dd2240c..728bf94 100644
--- a/src/BitcoinKernel.Core/KernelContext.cs
+++ b/src/BitcoinKernel/KernelContext.cs
@@ -1,7 +1,7 @@
-ο»Ώusing BitcoinKernel.Core.Exceptions;
+ο»Ώusing BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core;
+namespace BitcoinKernel;
///
/// Represents a Bitcoin Kernel context - the main entry point for the library.
diff --git a/src/BitcoinKernel.Core/KernelContextOptions.cs b/src/BitcoinKernel/KernelContextOptions.cs
similarity index 94%
rename from src/BitcoinKernel.Core/KernelContextOptions.cs
rename to src/BitcoinKernel/KernelContextOptions.cs
index 15cd981..1ccca0b 100644
--- a/src/BitcoinKernel.Core/KernelContextOptions.cs
+++ b/src/BitcoinKernel/KernelContextOptions.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Chain;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core;
+namespace BitcoinKernel;
///
/// Options for creating a kernel context.
///
diff --git a/src/BitcoinKernel/KernelLibrary.cs b/src/BitcoinKernel/KernelLibrary.cs
deleted file mode 100644
index 38ba7d6..0000000
--- a/src/BitcoinKernel/KernelLibrary.cs
+++ /dev/null
@@ -1,602 +0,0 @@
-ο»Ώusing BitcoinKernel.Core;
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.BlockProcessing;
-using BitcoinKernel.Core.Chain;
-using BitcoinKernel.Core.ScriptVerification;
-using BitcoinKernel.Interop.Enums;
-using System.IO;
-
-
-namespace BitcoinKernel
-{
- ///
- /// Simplified facade for common Bitcoin Kernel operations.
- /// Provides a fluent, easy-to-use API for typical scenarios.
- ///
- public sealed class KernelLibrary : IDisposable
- {
- private readonly KernelContext _context;
- private readonly ChainParameters _chainParams;
- private ChainstateManager? _chainstateManager;
- private LoggingConnection? _loggingConnection;
- private BlockProcessor? _blockProcessor;
- private bool _disposed;
-
- ///
- /// Gets the block processor for validation and processing operations.
- ///
- private BlockProcessor Processor
- {
- get
- {
- ThrowIfDisposed();
- return _blockProcessor ??= new BlockProcessor(Chainstate);
- }
- }
-
- private KernelLibrary(
- KernelContext context,
- ChainParameters chainParams)
- {
- _context = context;
- _chainParams = chainParams;
- }
-
- ///
- /// Creates a new kernel library instance with fluent builder.
- ///
- public static KernelBuilder Create() => new KernelBuilder();
-
- ///
- /// Gets the active chainstate manager (if initialized).
- ///
- public ChainstateManager Chainstate
- {
- get
- {
- ThrowIfDisposed();
- if (_chainstateManager == null)
- throw new InvalidOperationException("Chainstate not initialized. Call InitializeChainstate() first.");
- return _chainstateManager;
- }
- }
-
- ///
- /// Initializes the chainstate manager with the specified data directory.
- /// Internal use only - chainstate is automatically initialized by the builder.
- ///
- internal KernelLibrary InitializeChainstate(
- string dataDirectory,
- string? blocksDirectory = null,
- int workerThreads = 4)
- {
- ThrowIfDisposed();
-
- // Use dataDirectory/blocks if blocks directory not specified
- string blocksDir = blocksDirectory ?? System.IO.Path.Combine(dataDirectory, "blocks");
-
- var options = new ChainstateManagerOptions(_context, dataDirectory, blocksDir)
- .SetWorkerThreads(workerThreads);
-
- _chainstateManager = new ChainstateManager(_context, _chainParams, options);
-
- // Reset block processor when chainstate changes
- _blockProcessor = null;
-
- return this;
- }
-
-
- public KernelLibrary EnableLogging(Action callback)
- {
- ThrowIfDisposed();
- _loggingConnection?.Dispose();
- _loggingConnection = new LoggingConnection(callback);
- return this;
- }
-
- ///
- /// Processes a block through validation and potentially adds it to the chain.
- ///
- /// The serialized block data.
- /// True if the block was successfully processed and was new.
- public bool ProcessBlock(byte[] blockData)
- {
- ThrowIfDisposed();
- if (blockData == null) throw new ArgumentNullException(nameof(blockData));
- if (blockData.Length == 0) throw new ArgumentException("Block data cannot be empty", nameof(blockData));
-
- var result = Processor.ProcessBlock(blockData);
- return result.Success && result.IsNewBlock;
- }
-
- ///
- /// Processes a block from hex string through validation and potentially adds it to the chain.
- ///
- /// The block data as a hex string.
- /// True if the block was successfully processed and was new.
- public bool ProcessBlock(string blockHex)
- {
- ThrowIfDisposed();
- if (string.IsNullOrWhiteSpace(blockHex))
- throw new ArgumentException("Block hex cannot be null or empty", nameof(blockHex));
-
- byte[] blockData = Convert.FromHexString(blockHex);
- return ProcessBlock(blockData);
- }
-
- ///
- /// Verifies a script pubkey against a transaction input.
- /// This is a high-level convenience method that handles object creation from hex strings.
- ///
- /// The hex representation of the output script to verify against.
- /// The amount of the output being spent.
- /// The hex representation of the transaction containing the input to verify.
- /// The index of the transaction input to verify.
- /// A list of hex strings, where each string is a spent output.
- /// Script verification flags.
- /// True if the script is valid, otherwise false.
- public bool VerifyScript(
- string scriptPubKeyHex,
- long amount,
- string transactionHex,
- uint inputIndex,
- List spentOutputsHex,
- ScriptVerificationFlags flags = ScriptVerificationFlags.All)
- {
- using var scriptPubKey = ScriptPubKey.FromHex(scriptPubKeyHex);
- using var transaction = Transaction.FromHex(transactionHex);
- var spentOutputs = spentOutputsHex.Select(hex =>
- {
- // This is a simplification. We assume the spent output is just a script pubkey.
- // A proper implementation would need to decode the full TxOut structure.
- // For now, we create a TxOut with the script and a default amount.
- return new TxOut(ScriptPubKey.FromHex(hex), 0);
- }).ToList();
-
- try
- {
- return ScriptVerifier.VerifyScript(scriptPubKey, amount, transaction, inputIndex, spentOutputs, flags);
- }
- finally
- {
- foreach (var txOut in spentOutputs)
- {
- txOut.Dispose();
- }
- }
- }
-
- public bool ImportBlocks(string blockFilePath)
- {
- ThrowIfDisposed();
- if (_chainstateManager == null)
- throw new InvalidOperationException("Chainstate not initialized");
-
- return _chainstateManager.ImportBlocks(new[] { blockFilePath });
- }
-
- ///
- /// Gets the current chain height (number of blocks).
- ///
- public int GetChainHeight()
- {
- ThrowIfDisposed();
- return Chainstate.GetActiveChain().Height;
- }
-
- ///
- /// Gets the hash of the chain tip (best block).
- ///
- public byte[] GetChainTipHash()
- {
- ThrowIfDisposed();
- var tip = Chainstate.GetActiveChain().GetTip();
- return tip.GetBlockHash();
- }
-
- ///
- /// Gets the hash of the genesis block.
- ///
- public byte[] GetGenesisBlockHash()
- {
- ThrowIfDisposed();
- var genesis = Chainstate.GetActiveChain().GetGenesis();
- return genesis.GetBlockHash();
- }
-
- ///
- /// Gets a block hash by height.
- ///
- /// The block height.
- /// The block hash, or null if height is invalid.
- public byte[]? GetBlockHash(int height)
- {
- ThrowIfDisposed();
- try
- {
- var chain = Chainstate.GetActiveChain();
- var blockIndex = chain.GetBlockByHeight(height);
- return blockIndex?.GetBlockHash();
- }
- catch (ArgumentOutOfRangeException)
- {
- return null;
- }
- }
-
- ///
- /// Gets the spent outputs (UTXOs) for a block at the specified height.
- ///
- /// The block height.
- /// The spent outputs for the block, or null if height is invalid.
- public BlockSpentOutputs? GetSpentOutputs(int height)
- {
- ThrowIfDisposed();
- try
- {
- var chain = Chainstate.GetActiveChain();
- var blockIndex = chain.GetBlockByHeight(height);
- if (blockIndex == null) return null;
- return Chainstate.ReadSpentOutputs(blockIndex);
- }
- catch (ArgumentOutOfRangeException)
- {
- return null;
- }
- }
-
- ///
- /// Enumerates all block hashes from genesis to tip.
- ///
- public IEnumerable EnumerateBlockHashes()
- {
- ThrowIfDisposed();
- var chain = Chainstate.GetActiveChain();
- foreach (var blockIndex in chain.EnumerateBlocks())
- {
- yield return blockIndex.GetBlockHash();
- }
- }
-
- ///
- /// Gets basic information about a block at the specified height.
- ///
- /// The block height.
- /// Block information, or null if height is invalid.
- public BlockInfo? GetBlockInfo(int height)
- {
- ThrowIfDisposed();
- try
- {
- var chain = Chainstate.GetActiveChain();
- var blockIndex = chain.GetBlockByHeight(height);
- if (blockIndex == null) return null;
-
- return new BlockInfo
- {
- Height = blockIndex.Height,
- Hash = blockIndex.GetBlockHash(),
- PreviousHash = blockIndex.GetPrevious()?.GetBlockHash()
- };
- }
- catch (ArgumentOutOfRangeException)
- {
- return null;
- }
- }
-
- ///
- /// Gets block tree entry (metadata) by block hash.
- ///
- /// The hash of the block (32 bytes).
- /// The block tree entry, or null if not found.
- public Core.BlockProcessing.BlockTreeEntry? GetBlockTreeEntry(byte[] blockHash)
- {
- ThrowIfDisposed();
- if (blockHash == null) throw new ArgumentNullException(nameof(blockHash));
- if (blockHash.Length != 32) throw new ArgumentException("Block hash must be 32 bytes", nameof(blockHash));
-
- return Processor.GetBlockTreeEntry(blockHash);
- }
-
- ///
- /// Gets block tree entry (metadata) by block hash from hex string.
- ///
- /// The hash of the block as a hex string.
- /// The block tree entry, or null if not found.
- public Core.BlockProcessing.BlockTreeEntry? GetBlockTreeEntry(string blockHashHex)
- {
- ThrowIfDisposed();
- if (string.IsNullOrWhiteSpace(blockHashHex))
- throw new ArgumentException("Block hash hex cannot be null or empty", nameof(blockHashHex));
-
- try
- {
- byte[] blockHash = Convert.FromHexString(blockHashHex);
- return GetBlockTreeEntry(blockHash);
- }
- catch (FormatException ex)
- {
- throw new ArgumentException($"Invalid hex string: {ex.Message}", nameof(blockHashHex), ex);
- }
- }
-
- ///
- /// Represents basic block information.
- ///
- public class BlockInfo
- {
- public int Height { get; set; }
- public byte[] Hash { get; set; } = Array.Empty();
- public byte[]? PreviousHash { get; set; }
- }
-
- private void ThrowIfDisposed()
- {
- if (_disposed)
- throw new ObjectDisposedException(nameof(KernelLibrary));
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- _chainstateManager?.Dispose();
- _loggingConnection?.Dispose();
- _chainParams?.Dispose();
- _context?.Dispose();
- _disposed = true;
- }
- GC.SuppressFinalize(this);
- }
-
- ~KernelLibrary() => Dispose();
-
- ///
- /// Fluent builder for KernelLibrary.
- ///
- public sealed class KernelBuilder
- {
- private ChainType _chainType = ChainType.MAINNET;
- private Action? _loggingCallback;
- private int _workerThreads = 4;
- private string? _dataDirectory;
- private string? _blocksDirectory;
- private bool _wipeBlockTree;
- private bool _wipeChainstate;
-
- internal KernelBuilder() { }
-
- ///
- /// Sets the chain type (Mainnet, Testnet, Testnet_4, Regtest, Signet).
- ///
- private KernelBuilder ForChain(ChainType chainType)
- {
- _chainType = chainType;
- return this;
- }
-
- ///
- /// Configures mainnet.
- ///
- public KernelBuilder ForMainnet() => ForChain(ChainType.MAINNET);
-
- ///
- /// Configures testnet.
- ///
- public KernelBuilder ForTestnet() => ForChain(ChainType.TESTNET);
-
- ///
- /// Configures testnet_4.
- ///
- public KernelBuilder ForTestnet4() => ForChain(ChainType.TESTNET_4);
-
- ///
- /// Configures regtest.
- ///
- public KernelBuilder ForRegtest() => ForChain(ChainType.REGTEST);
-
- ///
- /// Configures signet.
- ///
- public KernelBuilder ForSignet() => ForChain(ChainType.SIGNET);
-
- ///
- /// Sets up logging with a callback.
- ///
- public KernelBuilder WithLogging(Action callback)
- {
- _loggingCallback = callback;
- return this;
- }
-
- ///
- /// Sets the number of worker threads for validation.
- ///
- /// Number of worker threads (must be at least 1).
- public KernelBuilder WithWorkerThreads(int threads)
- {
- if (threads < 1)
- throw new ArgumentOutOfRangeException(nameof(threads), "Worker threads must be at least 1");
-
- _workerThreads = threads;
- return this;
- }
-
- ///
- /// Sets custom data and blocks directories.
- ///
- /// The data directory path.
- /// The blocks directory path.
- public KernelBuilder WithDirectories(string dataDirectory, string blocksDirectory)
- {
- if (string.IsNullOrWhiteSpace(dataDirectory))
- throw new ArgumentException("Data directory cannot be null or empty", nameof(dataDirectory));
- if (string.IsNullOrWhiteSpace(blocksDirectory))
- throw new ArgumentException("Blocks directory cannot be null or empty", nameof(blocksDirectory));
-
- _dataDirectory = dataDirectory;
- _blocksDirectory = blocksDirectory;
- return this;
- }
-
- ///
- /// Enables database wiping on startup (useful for testing).
- ///
- public KernelBuilder WithWipeDatabases(bool wipeBlockTree = false, bool wipeChainstate = false)
- {
- _wipeBlockTree = wipeBlockTree;
- _wipeChainstate = wipeChainstate;
- return this;
- }
-
- ///
- /// Builds the KernelLibrary instance.
- ///
- public KernelLibrary Build()
- {
- var chainParams = new ChainParameters(_chainType);
-
- var contextOptions = new KernelContextOptions()
- .SetChainParams(chainParams);
-
- var context = new KernelContext(contextOptions);
-
- var library = new KernelLibrary(context, chainParams);
-
- if (_loggingCallback != null)
- {
- library.EnableLogging(_loggingCallback);
- }
-
- // Initialize chainstate with builder options
- string dataDir = _dataDirectory ?? Path.Combine(Path.GetTempPath(), $"bitcoinkernel_{Guid.NewGuid()}");
- string blocksDir = _blocksDirectory ?? Path.Combine(dataDir, "blocks");
-
- var options = new ChainstateManagerOptions(context, dataDir, blocksDir)
- .SetWorkerThreads(_workerThreads);
-
- if (_wipeBlockTree || _wipeChainstate)
- {
- options.SetWipeDbs(_wipeBlockTree, _wipeChainstate);
- }
-
- library.InitializeChainstate(dataDir, blocksDir, _workerThreads);
-
- return library;
- }
- }
-
- ///
- /// Validates a block without adding it to the chain.
- ///
- /// The block data to validate.
- /// True if the block is valid, false otherwise.
- public bool ValidateBlock(byte[] blockData)
- {
- ThrowIfDisposed();
-
- if (blockData == null || blockData.Length < 80)
- return false;
-
- try
- {
- using var block = Block.FromBytes(blockData);
- var result = Processor.ValidateBlock(block);
- return result.IsValid;
- }
- catch
- {
- // If parsing or validation fails, the block is invalid
- return false;
- }
- }
-
- ///
- /// Validates a block from hex string without adding it to the chain.
- ///
- /// The block data as a hex string.
- /// True if the block is valid, false otherwise.
- public bool ValidateBlock(string blockHex)
- {
- ThrowIfDisposed();
-
- if (string.IsNullOrWhiteSpace(blockHex))
- return false;
-
- try
- {
- byte[] blockData = Convert.FromHexString(blockHex);
- return ValidateBlock(blockData);
- }
- catch
- {
- return false;
- }
- }
-
- ///
- /// Validates a block and returns detailed validation results.
- ///
- /// The block data to validate.
- /// Detailed validation result.
- public Core.BlockProcessing.BlockValidationResult ValidateBlockDetailed(byte[] blockData)
- {
- ThrowIfDisposed();
-
- if (blockData == null || blockData.Length < 80)
- {
- return new Core.BlockProcessing.BlockValidationResult(
- isValid: false,
- mode: ValidationMode.INVALID,
- errorMessage: "Block data is null or too small");
- }
-
- try
- {
- using var block = Block.FromBytes(blockData);
- return Processor.ValidateBlock(block);
- }
- catch (Exception ex)
- {
- return new Core.BlockProcessing.BlockValidationResult(
- isValid: false,
- mode: ValidationMode.INTERNAL_ERROR,
- errorMessage: ex.Message);
- }
- }
-
- ///
- /// Validates a block from hex string and returns detailed validation results.
- ///
- /// The block data as a hex string.
- /// Detailed validation result.
- public Core.BlockProcessing.BlockValidationResult ValidateBlockDetailed(string blockHex)
- {
- ThrowIfDisposed();
-
- if (string.IsNullOrWhiteSpace(blockHex))
- {
- return new Core.BlockProcessing.BlockValidationResult(
- isValid: false,
- mode: ValidationMode.INVALID,
- errorMessage: "Block hex cannot be null or empty");
- }
-
- try
- {
- byte[] blockData = Convert.FromHexString(blockHex);
- return ValidateBlockDetailed(blockData);
- }
- catch (Exception ex)
- {
- return new Core.BlockProcessing.BlockValidationResult(
- isValid: false,
- mode: ValidationMode.INTERNAL_ERROR,
- errorMessage: $"Failed to parse hex string: {ex.Message}");
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/src/BitcoinKernel.Core/LoggingConnection.cs b/src/BitcoinKernel/LoggingConnection.cs
similarity index 98%
rename from src/BitcoinKernel.Core/LoggingConnection.cs
rename to src/BitcoinKernel/LoggingConnection.cs
index 280c263..309e92c 100644
--- a/src/BitcoinKernel.Core/LoggingConnection.cs
+++ b/src/BitcoinKernel/LoggingConnection.cs
@@ -2,6 +2,8 @@
using BitcoinKernel.Interop;
using BitcoinKernel.Interop.Delegates;
+namespace BitcoinKernel;
+
public sealed class LoggingConnection : IDisposable
{
private IntPtr _handle;
diff --git a/src/BitcoinKernel.Core/Abstractions/Block.cs b/src/BitcoinKernel/Primatives/Block.cs
similarity index 98%
rename from src/BitcoinKernel.Core/Abstractions/Block.cs
rename to src/BitcoinKernel/Primatives/Block.cs
index 993f7ed..69d3a8d 100644
--- a/src/BitcoinKernel.Core/Abstractions/Block.cs
+++ b/src/BitcoinKernel/Primatives/Block.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents a block in the blockchain.
diff --git a/src/BitcoinKernel.Core/Abstractions/BlockHash.cs b/src/BitcoinKernel/Primatives/BlockHash.cs
similarity index 95%
rename from src/BitcoinKernel.Core/Abstractions/BlockHash.cs
rename to src/BitcoinKernel/Primatives/BlockHash.cs
index 9fce4cf..b322e54 100644
--- a/src/BitcoinKernel.Core/Abstractions/BlockHash.cs
+++ b/src/BitcoinKernel/Primatives/BlockHash.cs
@@ -1,7 +1,7 @@
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents a block hash.
///
diff --git a/src/BitcoinKernel.Core/Abstractions/BlockHeader.cs b/src/BitcoinKernel/Primatives/BlockHeader.cs
similarity index 97%
rename from src/BitcoinKernel.Core/Abstractions/BlockHeader.cs
rename to src/BitcoinKernel/Primatives/BlockHeader.cs
index 5abdc7c..d9acf18 100644
--- a/src/BitcoinKernel.Core/Abstractions/BlockHeader.cs
+++ b/src/BitcoinKernel/Primatives/BlockHeader.cs
@@ -1,7 +1,7 @@
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents a block header containing metadata about a block.
diff --git a/src/BitcoinKernel.Core/Abstractions/BlockIndex.cs b/src/BitcoinKernel/Primatives/BlockIndex.cs
similarity index 97%
rename from src/BitcoinKernel.Core/Abstractions/BlockIndex.cs
rename to src/BitcoinKernel/Primatives/BlockIndex.cs
index a0cdd1c..d12fcd8 100644
--- a/src/BitcoinKernel.Core/Abstractions/BlockIndex.cs
+++ b/src/BitcoinKernel/Primatives/BlockIndex.cs
@@ -1,6 +1,6 @@
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents a block index entry in the block tree.
diff --git a/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs
new file mode 100644
index 0000000..96d4535
--- /dev/null
+++ b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs
@@ -0,0 +1,120 @@
+using System;
+using BitcoinKernel.Interop;
+
+namespace BitcoinKernel.Primatives;
+
+///
+/// Represents the spent outputs for all transactions in a block.
+///
+public class BlockSpentOutputs : IDisposable
+{
+ private IntPtr _handle;
+ private bool _disposed;
+
+ internal BlockSpentOutputs(IntPtr handle)
+ {
+ if (handle == IntPtr.Zero)
+ {
+ throw new ArgumentException("Invalid block spent outputs handle", nameof(handle));
+ }
+
+ _handle = handle;
+ }
+
+ ///
+ /// Gets the number of transactions with spent outputs in this block.
+ /// This excludes the coinbase transaction.
+ ///
+ public int Count
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return (int)NativeMethods.BlockSpentOutputsCount(_handle);
+ }
+ }
+
+ ///
+ /// Gets the spent outputs for a transaction at the specified index.
+ /// The returned object is only valid for the lifetime of this BlockSpentOutputs.
+ ///
+ /// The zero-based index of the transaction (excluding coinbase).
+ /// A TransactionSpentOutputs object for the specified transaction.
+ public TransactionSpentOutputs GetTransactionSpentOutputs(int transactionIndex)
+ {
+ ThrowIfDisposed();
+
+ if (transactionIndex < 0 || transactionIndex >= Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(transactionIndex));
+ }
+
+ var txSpentOutputsPtr = NativeMethods.BlockSpentOutputsGetTransactionSpentOutputsAt(
+ _handle, (nuint)transactionIndex);
+
+ if (txSpentOutputsPtr == IntPtr.Zero)
+ {
+ throw new InvalidOperationException($"Failed to get transaction spent outputs at index {transactionIndex}");
+ }
+
+ // Don't own the handle - it's only valid for the lifetime of BlockSpentOutputs
+ return new TransactionSpentOutputs(txSpentOutputsPtr, ownsHandle: false);
+ }
+
+ ///
+ /// Enumerates all transaction spent outputs in the block.
+ ///
+ /// An enumerable of TransactionSpentOutputs for each transaction (excluding coinbase).
+ public IEnumerable EnumerateTransactionSpentOutputs()
+ {
+ ThrowIfDisposed();
+
+ int count = Count;
+ for (int i = 0; i < count; i++)
+ {
+ yield return GetTransactionSpentOutputs(i);
+ }
+ }
+
+ internal IntPtr Handle
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return _handle;
+ }
+ }
+
+ private void ThrowIfDisposed()
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(nameof(BlockSpentOutputs));
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (_handle != IntPtr.Zero)
+ {
+ NativeMethods.BlockSpentOutputsDestroy(_handle);
+ _handle = IntPtr.Zero;
+ }
+
+ _disposed = true;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ~BlockSpentOutputs()
+ {
+ Dispose(false);
+ }
+}
diff --git a/src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs b/src/BitcoinKernel/Primatives/BlockValidationState.cs
similarity index 96%
rename from src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs
rename to src/BitcoinKernel/Primatives/BlockValidationState.cs
index 240a4a4..8c04870 100644
--- a/src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs
+++ b/src/BitcoinKernel/Primatives/BlockValidationState.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
using BitcoinKernel.Interop.Enums;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents the validation state of a block.
diff --git a/src/BitcoinKernel/Primatives/Coin.cs b/src/BitcoinKernel/Primatives/Coin.cs
new file mode 100644
index 0000000..d556c55
--- /dev/null
+++ b/src/BitcoinKernel/Primatives/Coin.cs
@@ -0,0 +1,123 @@
+using System;
+using BitcoinKernel.Interop;
+
+namespace BitcoinKernel.Primatives;
+
+///
+/// Represents a coin (unspent transaction output) with confirmation height information.
+///
+public class Coin : IDisposable
+{
+ private IntPtr _handle;
+ private bool _disposed;
+ private readonly bool _ownsHandle;
+
+ internal Coin(IntPtr handle, bool ownsHandle = true)
+ {
+ if (handle == IntPtr.Zero)
+ {
+ throw new ArgumentException("Invalid coin handle", nameof(handle));
+ }
+
+ _handle = handle;
+ _ownsHandle = ownsHandle;
+ }
+
+ ///
+ /// Gets the block height where the transaction that created this coin was included.
+ ///
+ public uint ConfirmationHeight
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return NativeMethods.CoinConfirmationHeight(_handle);
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this coin is from a coinbase transaction.
+ ///
+ public bool IsCoinbase
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return NativeMethods.CoinIsCoinbase(_handle) != 0;
+ }
+ }
+
+ ///
+ /// Gets the transaction output of this coin.
+ /// The returned object is only valid for the lifetime of this Coin.
+ ///
+ public TxOut GetOutput()
+ {
+ ThrowIfDisposed();
+ var outputPtr = NativeMethods.CoinGetOutput(_handle);
+ if (outputPtr == IntPtr.Zero)
+ {
+ throw new InvalidOperationException("Failed to get coin output");
+ }
+
+ // Don't own the handle - it's only valid for the lifetime of the Coin
+ return new TxOut(outputPtr, ownsHandle: false);
+ }
+
+ ///
+ /// Creates a copy of this coin.
+ ///
+ public Coin Copy()
+ {
+ ThrowIfDisposed();
+ var copiedHandle = NativeMethods.CoinCopy(_handle);
+ if (copiedHandle == IntPtr.Zero)
+ {
+ throw new InvalidOperationException("Failed to copy coin");
+ }
+
+ return new Coin(copiedHandle, ownsHandle: true);
+ }
+
+ internal IntPtr Handle
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return _handle;
+ }
+ }
+
+ private void ThrowIfDisposed()
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(nameof(Coin));
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (_ownsHandle && _handle != IntPtr.Zero)
+ {
+ NativeMethods.CoinDestroy(_handle);
+ _handle = IntPtr.Zero;
+ }
+
+ _disposed = true;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ~Coin()
+ {
+ Dispose(false);
+ }
+}
diff --git a/src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs b/src/BitcoinKernel/Primatives/ScriptPubKey.cs
similarity index 96%
rename from src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs
rename to src/BitcoinKernel/Primatives/ScriptPubKey.cs
index 4c4093f..f1bd5ad 100644
--- a/src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs
+++ b/src/BitcoinKernel/Primatives/ScriptPubKey.cs
@@ -1,8 +1,8 @@
using System.Net;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
/// A single script pubkey containing spending conditions for a transaction output.
///
diff --git a/src/BitcoinKernel.Core/Abstractions/Transaction.cs b/src/BitcoinKernel/Primatives/Transaction.cs
similarity index 98%
rename from src/BitcoinKernel.Core/Abstractions/Transaction.cs
rename to src/BitcoinKernel/Primatives/Transaction.cs
index ffe3702..3bc4247 100644
--- a/src/BitcoinKernel.Core/Abstractions/Transaction.cs
+++ b/src/BitcoinKernel/Primatives/Transaction.cs
@@ -1,9 +1,9 @@
using System;
using System.Runtime.InteropServices;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Managed wrapper for Bitcoin transactions with automatic memory management.
diff --git a/src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs b/src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs
similarity index 98%
rename from src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs
rename to src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs
index 3e1109d..c8836c0 100644
--- a/src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs
+++ b/src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs
@@ -1,4 +1,4 @@
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
using BitcoinKernel.Interop;
using System;
diff --git a/src/BitcoinKernel.Core/Abstractions/TxOut.cs b/src/BitcoinKernel/Primatives/TxOut.cs
similarity index 97%
rename from src/BitcoinKernel.Core/Abstractions/TxOut.cs
rename to src/BitcoinKernel/Primatives/TxOut.cs
index 1bb6923..5bfac9d 100644
--- a/src/BitcoinKernel.Core/Abstractions/TxOut.cs
+++ b/src/BitcoinKernel/Primatives/TxOut.cs
@@ -1,9 +1,9 @@
using System.Runtime.InteropServices;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.Abstractions;
+namespace BitcoinKernel.Primatives;
///
/// Represents a transaction output (TxOut) in a Bitcoin transaction.
diff --git a/src/BitcoinKernel/README.md b/src/BitcoinKernel/README.md
deleted file mode 100644
index 69e2f73..0000000
--- a/src/BitcoinKernel/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# BitcoinKernel
-
-A high-level C# library for Bitcoin Core functionality, providing a simple and fluent API for working with Bitcoin blockchain operations via libbitcoinkernel.
-β οΈπ§ This library is still under contruction. β οΈπ§
-
-## Installation
-
-```bash
-dotnet add package BitcoinKernel
-```
-
-## Quick Start
-
-```csharp
-using BitcoinKernel;
-using BitcoinKernel.Interop.Enums;
-
-// Create a kernel instance for regtest
-using var kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
-// Get chain information
-int height = kernel.GetChainHeight();
-byte[] tipHash = kernel.GetChainTipHash();
-
-// Verify a script
-bool isValid = kernel.VerifyScript(
- scriptPubKeyHex: "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac",
- amount: 100000,
- transactionHex: "02000000...",
- inputIndex: 0,
- spentOutputsHex: new List(),
- flags: ScriptVerificationFlags.All
-);
-```
-
-
-## Documentation
-
-For more information, visit the [GitHub repository](https://github.com/janB84/BitcoinKernel.NET).
-
-## License
-
-MIT
diff --git a/src/BitcoinKernel.Core/ScriptVerification/PrecomputedTransactionData.cs b/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs
similarity index 94%
rename from src/BitcoinKernel.Core/ScriptVerification/PrecomputedTransactionData.cs
rename to src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs
index 19d6ebd..75b0839 100644
--- a/src/BitcoinKernel.Core/ScriptVerification/PrecomputedTransactionData.cs
+++ b/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
-namespace BitcoinKernel.Core.ScriptVerification;
+namespace BitcoinKernel.ScriptVerification;
///
/// Holds precomputed transaction data used to accelerate repeated script verification
diff --git a/src/BitcoinKernel.Core/ScriptVerification/ScriptVerifier.cs b/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs
similarity index 97%
rename from src/BitcoinKernel.Core/ScriptVerification/ScriptVerifier.cs
rename to src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs
index ca63fbc..fbc6d64 100644
--- a/src/BitcoinKernel.Core/ScriptVerification/ScriptVerifier.cs
+++ b/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs
@@ -1,13 +1,13 @@
using System;
using System.Runtime.InteropServices;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop;
using BitcoinKernel.Interop.Enums;
-using BitcoinKernel.Core.Abstractions;
+using BitcoinKernel.Primatives;
-namespace BitcoinKernel.Core.ScriptVerification;
+namespace BitcoinKernel.ScriptVerification;
///
/// Handles script verification operations.
diff --git a/tests/BitcoinKernel.Core.Tests/BitcoinKernel.Core.Tests.csproj b/tests/BitcoinKernel.Core.Tests/BitcoinKernel.Core.Tests.csproj
deleted file mode 100644
index 11925a3..0000000
--- a/tests/BitcoinKernel.Core.Tests/BitcoinKernel.Core.Tests.csproj
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- false
-
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/BitcoinKernel.Core.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Core.Tests/BlockProcessingTests.cs
deleted file mode 100644
index 843157d..0000000
--- a/tests/BitcoinKernel.Core.Tests/BlockProcessingTests.cs
+++ /dev/null
@@ -1,497 +0,0 @@
-using BitcoinKernel.Core.Chain;
-using BitcoinKernel.Core.Exceptions;
-using BitcoinKernel.Interop.Enums;
-using Xunit;
-
-namespace BitcoinKernel.Core.Tests
-{
- public class BlockProcessingTests : IDisposable
- {
- private KernelContext? _context;
- private ChainParameters? _chainParams;
- private string? _tempDir;
-
- public void Dispose()
- {
- _chainParams?.Dispose();
- _context?.Dispose();
-
- if (!string.IsNullOrEmpty(_tempDir) && Directory.Exists(_tempDir))
- {
- Directory.Delete(_tempDir, true);
- }
- }
-
- private (KernelContext, ChainParameters, string) TestingSetup()
- {
- // Create kernel context for regtest
- _chainParams = new ChainParameters(ChainType.REGTEST);
- var contextOptions = new KernelContextOptions()
- .SetChainParams(_chainParams);
- _context = new KernelContext(contextOptions);
-
- // Create temporary directory
- _tempDir = Path.Combine(Path.GetTempPath(), $"test_chainman_regtest_{Guid.NewGuid()}");
- Directory.CreateDirectory(_tempDir);
-
- return (_context, _chainParams, _tempDir);
- }
-
- private List ReadBlockData()
- {
- var blockData = new List();
- // The file is in the test project directory
- var testAssemblyDir = Path.GetDirectoryName(typeof(BlockProcessingTests).Assembly.Location);
- var projectDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(testAssemblyDir)));
- var blockDataFile = Path.Combine(projectDir!, "TestData", "block_data.txt");
-
- if (!File.Exists(blockDataFile))
- {
- throw new FileNotFoundException($"Block data file not found: {blockDataFile}");
- }
-
- foreach (var line in File.ReadLines(blockDataFile))
- {
- if (!string.IsNullOrWhiteSpace(line))
- {
- blockData.Add(Convert.FromHexString(line.Trim()));
- }
- }
-
- return blockData;
- }
-
- private void ProcessBlockData(ChainstateManager chainstateManager, List blockData)
- {
- foreach (var rawBlock in blockData)
- {
- using var block = Abstractions.Block.FromBytes(rawBlock);
- chainstateManager.ProcessBlock(block);
- }
- }
-
- private (ChainstateManager, List) SetupChainstateManager()
- {
- var (context, chainParams, dataDir) = TestingSetup();
- var blockData = ReadBlockData();
-
- var options = new ChainstateManagerOptions(context, dataDir, Path.Combine(dataDir, "blocks"));
- var chainstateManager = new ChainstateManager(context, chainParams, options);
-
- return (chainstateManager, blockData);
- }
-
- [Fact]
- public void TestProcessData()
- {
- // Arrange
- var (context, chainParams, dataDir) = TestingSetup();
- var blocksDir = Path.Combine(dataDir, "blocks");
- var blockData = ReadBlockData();
-
-
- var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
- using var chainstateManager = new ChainstateManager(context, chainParams, options);
-
- // Act & Assert
- foreach (var rawBlock in blockData)
- {
- using var block = Abstractions.Block.FromBytes(rawBlock);
- var result = chainstateManager.ProcessBlock(block);
-
- // Assert the block was processed successfully (is new)
- Assert.True(result, "Block should be new and processed successfully");
- }
- }
-
- [Fact]
- public void TestValidateAny()
- {
- // Arrange
- var (context, chainParams, dataDir) = TestingSetup();
- var blocksDir = Path.Combine(dataDir, "blocks");
- var blockData = ReadBlockData();
-
- var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
- using var chainstateManager = new ChainstateManager(context, chainParams, options);
-
- // Act & Assert
- chainstateManager.ImportBlocks();
- using var block2 = Abstractions.Block.FromBytes(blockData[1]);
-
- // The block should be invalid and processing should fail
- var exception = Assert.Throws(() =>
- chainstateManager.ProcessBlock(block2));
-
- // Verify it's a validation error (non-zero error code)
- Assert.Contains("Failed to process block", exception.Message);
- }
-
- [Fact]
- public void TestReindex()
- {
- // Arrange
- var (context, chainParams, dataDir) = TestingSetup();
- var blocksDir = Path.Combine(dataDir, "blocks");
- var blockData = ReadBlockData();
-
- // Act - Process blocks
- {
- var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
- using var chainstateManager = new ChainstateManager(context, chainParams, options);
-
- foreach (var rawBlock in blockData)
- {
- using var block = Abstractions.Block.FromBytes(rawBlock);
- var result = chainstateManager.ProcessBlock(block);
- Assert.True(result, "Block should be new and processed successfully");
- }
- }
-
-
- // Act - Reindex
- var reindexOptions = new ChainstateManagerOptions(context, dataDir, blocksDir)
- .SetWipeDbs(false, true);
- using var chainstateManagerReindex = new ChainstateManager(context, chainParams, reindexOptions);
- var result_reindex = chainstateManagerReindex.ImportBlocks();
-
- Assert.True(result_reindex, "Reindexing should be successful");
-
- // Assert - Verify chainstate is intact after reindex
- var activeChain = chainstateManagerReindex.GetActiveChain();
- Assert.Equal(blockData.Count, activeChain.Height);
- }
-
- [Fact]
- public void TestInvalidBlock()
- {
- // Arrange
- var (context, chainParams, dataDir) = TestingSetup();
- var blocksDir = Path.Combine(dataDir, "blocks");
-
- for (int i = 0; i < 10; i++)
- {
- var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
- using var chainstateManager = new ChainstateManager(context, chainParams, options);
-
- // Not a block
- var invalidBlockData = Convert.FromHexString("deadbeef");
- Assert.Throws(() => Abstractions.Block.FromBytes(invalidBlockData));
-
- // Invalid block
- var invalidBlockHex = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd" +
- "1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299" +
- "0101000000010000000000000000000000000000000000000000000000000000000000000000ffff" +
- "ffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec1" +
- "1600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf62" +
- "1e73a82cbf2342c858eeac00000000";
-
- using var block = Abstractions.Block.FromBytes(Convert.FromHexString(invalidBlockHex));
-
- // The block should be invalid and processing should fail
- var exception = Assert.Throws(() =>
- chainstateManager.ProcessBlock(block));
-
- // Verify it's a validation error (non-zero error code)
- Assert.Contains("Failed to process block", exception.Message);
- }
- }
-
- [Fact]
- public void TestScanTransactions()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Act - Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var activeChain = chainstateManager.GetActiveChain();
-
- // Verify we can iterate through the chain by height
- for (int height = 0; height <= activeChain.Height; height++)
- {
- var blockIndex = activeChain.GetBlockByHeight(height);
- Assert.NotNull(blockIndex);
- Assert.Equal(height, blockIndex.Height);
- }
-
- // Get the tip and read its spent outputs
- var tipBlockIndex = activeChain.GetTip();
- Assert.NotNull(tipBlockIndex);
-
- using var spentOutputsTip = chainstateManager.ReadSpentOutputs(tipBlockIndex);
- Assert.NotNull(spentOutputsTip);
-
- // The number of transaction spent outputs should match transactions minus coinbase
- // This is validated by checking that Count returns a valid value
- var tipSpentOutputsCount = spentOutputsTip.Count;
- Assert.True(tipSpentOutputsCount >= 0, "Spent outputs count should be non-negative");
-
- // If we have a previous block, scan its transactions in detail
- var previousBlock = tipBlockIndex.GetPrevious();
- if (previousBlock != null)
- {
- using var spentOutputs = chainstateManager.ReadSpentOutputs(previousBlock);
- var spentOutputsCount = spentOutputs.Count;
-
- // Scan each transaction's spent outputs
- for (int txIndex = 0; txIndex < spentOutputsCount; txIndex++)
- {
- using var txSpentOutputs = spentOutputs.GetTransactionSpentOutputs(txIndex);
- var coinsCount = txSpentOutputs.Count;
-
- // Verify we can access each coin
- for (int coinIndex = 0; coinIndex < coinsCount; coinIndex++)
- {
- using var coin = txSpentOutputs.GetCoin(coinIndex);
-
- // Verify coin properties
- Assert.True(coin.ConfirmationHeight >= 0, "Confirmation height should be non-negative");
-
- // We should be able to get the output
- using var output = coin.GetOutput();
- Assert.NotNull(output);
-
- // Verify we can get the script pubkey from the output
- var scriptPubkeyBytes = output.GetScriptPubkey();
- Assert.NotNull(scriptPubkeyBytes);
- Assert.True(scriptPubkeyBytes.Length >= 0, "Script pubkey should have valid length");
-
- // Verify we can get the amount
- var amount = output.Amount;
- Assert.True(amount >= 0, "Amount should be non-negative");
- }
- }
- }
- }
-
- [Fact]
- public void TestChainOperations()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var chain = chainstateManager.GetActiveChain();
-
- // Test genesis via GetGenesis() method
- var genesis = chain.GetGenesis();
- Assert.NotNull(genesis);
- Assert.Equal(0, genesis.Height);
- var genesisHash = genesis.GetBlockHash();
- Assert.NotNull(genesisHash);
-
- // Test tip block
- var tip = chain.GetTip();
- Assert.NotNull(tip);
- var tipHeight = tip.Height;
- var tipHash = tip.GetBlockHash();
-
- Assert.True(tipHeight > 0);
- Assert.False(genesisHash.SequenceEqual(tipHash));
-
- // Test accessing block by height - genesis
- var genesisViaHeight = chain.GetBlockByHeight(0);
- Assert.NotNull(genesisViaHeight);
- Assert.Equal(0, genesisViaHeight.Height);
- Assert.True(genesisHash.SequenceEqual(genesisViaHeight.GetBlockHash()));
-
- // Test accessing block by height - tip
- var tipViaHeight = chain.GetBlockByHeight(tipHeight);
- Assert.NotNull(tipViaHeight);
- Assert.Equal(tipHeight, tipViaHeight.Height);
- Assert.True(tipHash.SequenceEqual(tipViaHeight.GetBlockHash()));
-
- // Test invalid height returns null
- var invalidEntry = chain.GetBlockByHeight(9999);
- Assert.Null(invalidEntry);
-
- // Test Contains method
- Assert.True(chain.Contains(genesis));
- Assert.True(chain.Contains(tip));
-
- // Test iteration through chain
- int count = 0;
- foreach (var currentBlockIndex in chain.EnumerateBlocks())
- {
- Assert.True(chain.Contains(currentBlockIndex));
- Assert.Equal(count, currentBlockIndex.Height);
- count++;
- }
-
- // Verify we iterated through the entire chain
- Assert.Equal(tipHeight + 1, count);
- }
-
- [Fact]
- public void TestBlockSpentOutputsIterator()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var activeChain = chainstateManager.GetActiveChain();
- var blockIndexTip = activeChain.GetTip();
- using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip);
-
- // Test count via iterator matches Count property
- var countViaIterator = spentOutputs.EnumerateTransactionSpentOutputs().Count();
- Assert.Equal(spentOutputs.Count, countViaIterator);
-
- // Test collecting all transaction spent outputs
- var txSpentVec = spentOutputs.EnumerateTransactionSpentOutputs().ToList();
- Assert.Equal(spentOutputs.Count, txSpentVec.Count);
-
- // Test that each transaction spent output from iterator matches by index
- int i = 0;
- foreach (var txSpent in spentOutputs.EnumerateTransactionSpentOutputs())
- {
- using var txSpentViaIndex = spentOutputs.GetTransactionSpentOutputs(i);
- Assert.Equal(txSpent.Count, txSpentViaIndex.Count);
- i++;
- }
-
- // Test iterator length tracking
- var initialLen = spentOutputs.Count;
-
- if (initialLen > 0)
- {
- // After skipping one element, we have initialLen - 1 remaining
- var remaining = spentOutputs.EnumerateTransactionSpentOutputs().Skip(1).Count();
- Assert.Equal(initialLen - 1, remaining);
- }
- }
-
- [Fact]
- public void TestTransactionSpentOutputsIterator()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var activeChain = chainstateManager.GetActiveChain();
- var blockIndexTip = activeChain.GetTip();
- using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip);
-
- using var txSpent = spentOutputs.GetTransactionSpentOutputs(0);
-
- // Test count via iterator matches Count property
- var countViaIterator = txSpent.EnumerateCoins().Count();
- Assert.Equal(txSpent.Count, countViaIterator);
-
- // Test collecting all coins
- var coins = txSpent.EnumerateCoins().ToList();
- Assert.Equal(txSpent.Count, coins.Count);
-
- // Test that each coin from iterator matches coin by index
- int i = 0;
- foreach (var coin in txSpent.EnumerateCoins())
- {
- using var coinViaIndex = txSpent.GetCoin(i);
- Assert.Equal(coin.ConfirmationHeight, coinViaIndex.ConfirmationHeight);
- Assert.Equal(coin.IsCoinbase, coinViaIndex.IsCoinbase);
- i++;
- }
-
- // Test iterator length tracking
- var initialLen = txSpent.Count;
-
- if (initialLen > 0)
- {
- // After skipping one element, we have initialLen - 1 remaining
- var remaining = txSpent.EnumerateCoins().Skip(1).Count();
- Assert.Equal(initialLen - 1, remaining);
- }
-
- // Test filtering coinbase coins
- var coinbaseCoins = txSpent.EnumerateCoins().Where(coin => coin.IsCoinbase).ToList();
-
- foreach (var coin in coinbaseCoins)
- {
- Assert.True(coin.IsCoinbase);
- }
- }
-
- [Fact]
- public void TestNestedIteration()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var activeChain = chainstateManager.GetActiveChain();
- var blockIndex = activeChain.GetBlockByHeight(1);
- Assert.NotNull(blockIndex);
-
- using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex);
-
- // Count total coins by nested iteration
- int totalCoins = 0;
- foreach (var txSpent in spentOutputs.EnumerateTransactionSpentOutputs())
- {
- foreach (var coin in txSpent.EnumerateCoins())
- {
- totalCoins++;
- }
- }
-
- // Calculate expected total using LINQ
- int expectedTotal = spentOutputs.EnumerateTransactionSpentOutputs()
- .Sum(txSpent => txSpent.Count);
-
- Assert.Equal(expectedTotal, totalCoins);
- }
-
- [Fact]
- public void TestIteratorWithBlockTransactions()
- {
- // Arrange - Setup test environment with blocks
- var setup = SetupChainstateManager();
- using var chainstateManager = setup.Item1;
- var blockData = setup.Item2;
-
- // Process all test blocks
- ProcessBlockData(chainstateManager, blockData);
-
- var activeChain = chainstateManager.GetActiveChain();
- var blockIndex = activeChain.GetBlockByHeight(1);
- Assert.NotNull(blockIndex);
-
- // Use the block data we already have (index 1 corresponds to blockData[1])
- using var block = Abstractions.Block.FromBytes(blockData[1]);
- using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex);
-
- // Zip block transactions (skipping coinbase) with spent outputs
- // Each transaction's input count should match its spent outputs count
- int txIndex = 0;
- foreach (var tx in block.GetTransactions().Skip(1))
- {
- using var txSpent = spentOutputs.GetTransactionSpentOutputs(txIndex);
- Assert.Equal(tx.InputCount, txSpent.Count);
- txIndex++;
- }
-
- // Verify we processed all spent outputs
- Assert.Equal(spentOutputs.Count, txIndex);
- }
- }
-}
\ No newline at end of file
diff --git a/tests/BitcoinKernel.Core.Tests/BlockTests.cs b/tests/BitcoinKernel.Core.Tests/BlockTests.cs
deleted file mode 100644
index 0188108..0000000
--- a/tests/BitcoinKernel.Core.Tests/BlockTests.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using BitcoinKernel.Core.Abstractions;
-using Xunit;
-
-namespace BitcoinKernel.Core.Tests
-{
- public class BlockTests
- {
- private List ReadBlockData()
- {
- var blockData = new List();
- var testAssemblyDir = Path.GetDirectoryName(typeof(BlockTests).Assembly.Location);
- var projectDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(testAssemblyDir)));
- var blockDataFile = Path.Combine(projectDir!, "TestData", "block_data.txt");
-
- if (!File.Exists(blockDataFile))
- {
- throw new FileNotFoundException($"Block data file not found: {blockDataFile}");
- }
-
- foreach (var line in File.ReadLines(blockDataFile))
- {
- if (!string.IsNullOrWhiteSpace(line))
- {
- blockData.Add(Convert.FromHexString(line.Trim()));
- }
- }
-
- return blockData;
- }
-
- [Fact]
- public void TestBlockTransactionsIterator()
- {
- var blockData = ReadBlockData();
-
- using var block = Block.FromBytes(blockData[5]);
-
- // Test that iterator count matches transaction count
- var txCountViaIterator = block.GetTransactions().Count();
- Assert.Equal(block.TransactionCount, txCountViaIterator);
-
- // Test collecting all transactions
- var txs = block.GetTransactions().ToList();
- Assert.Equal(block.TransactionCount, txs.Count);
-
- // Test that each transaction from iterator matches transaction by index
- int i = 0;
- foreach (var tx in block.GetTransactions())
- {
- using var txViaIndex = block.GetTransaction(i);
- Assert.NotNull(txViaIndex);
- Assert.Equal(tx.InputCount, txViaIndex.InputCount);
- Assert.Equal(tx.OutputCount, txViaIndex.OutputCount);
- i++;
- }
-
- // Test iterator length decreases as we consume it
- var iter = block.GetTransactions().GetEnumerator();
- var initialLen = block.TransactionCount;
-
- // Move to first element
- Assert.True(iter.MoveNext());
- // After consuming one element, we have initialLen - 1 remaining
- var remaining = block.GetTransactions().Skip(1).Count();
- Assert.Equal(initialLen - 1, remaining);
-
- // Test skipping coinbase transaction
- var nonCoinbaseTxs = block.GetTransactions().Skip(1).ToList();
- Assert.Equal(block.TransactionCount - 1, nonCoinbaseTxs.Count);
- }
- }
-}
diff --git a/tests/BitcoinKernel.Tests/BitcoinKernel.Tests.csproj b/tests/BitcoinKernel.Tests/BitcoinKernel.Tests.csproj
index f48e5a5..d60dcac 100644
--- a/tests/BitcoinKernel.Tests/BitcoinKernel.Tests.csproj
+++ b/tests/BitcoinKernel.Tests/BitcoinKernel.Tests.csproj
@@ -1,24 +1,26 @@
-
-
-
- net9.0
- enable
- enable
- false
-
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ net9.0
+ enable
+ enable
+ false
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/BitcoinKernel.Core.Tests/BlockHeaderTests.cs b/tests/BitcoinKernel.Tests/BlockHeaderTests.cs
similarity index 98%
rename from tests/BitcoinKernel.Core.Tests/BlockHeaderTests.cs
rename to tests/BitcoinKernel.Tests/BlockHeaderTests.cs
index 59b9e0c..9b0563a 100644
--- a/tests/BitcoinKernel.Core.Tests/BlockHeaderTests.cs
+++ b/tests/BitcoinKernel.Tests/BlockHeaderTests.cs
@@ -1,12 +1,12 @@
-using BitcoinKernel.Core;
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.BlockProcessing;
-using BitcoinKernel.Core.Chain;
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.BlockProcessing;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Exceptions;
using BitcoinKernel.Interop.Enums;
using Xunit;
-namespace BitcoinKernel.Core.Tests;
+namespace BitcoinKernel.Tests;
public class BlockHeaderTests : IDisposable
{
diff --git a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs
new file mode 100644
index 0000000..741267f
--- /dev/null
+++ b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs
@@ -0,0 +1,497 @@
+using BitcoinKernel.Chain;
+using BitcoinKernel.Exceptions;
+using BitcoinKernel.Interop.Enums;
+using BitcoinKernel.Primatives;
+using Xunit;
+
+namespace BitcoinKernel.Tests;
+
+public class BlockProcessingTests : IDisposable
+{
+ private KernelContext? _context;
+ private ChainParameters? _chainParams;
+ private string? _tempDir;
+
+ public void Dispose()
+ {
+ _chainParams?.Dispose();
+ _context?.Dispose();
+
+ if (!string.IsNullOrEmpty(_tempDir) && Directory.Exists(_tempDir))
+ {
+ Directory.Delete(_tempDir, true);
+ }
+ }
+
+ private (KernelContext, ChainParameters, string) TestingSetup()
+ {
+ // Create kernel context for regtest
+ _chainParams = new ChainParameters(ChainType.REGTEST);
+ var contextOptions = new KernelContextOptions()
+ .SetChainParams(_chainParams);
+ _context = new KernelContext(contextOptions);
+
+ // Create temporary directory
+ _tempDir = Path.Combine(Path.GetTempPath(), $"test_chainman_regtest_{Guid.NewGuid()}");
+ Directory.CreateDirectory(_tempDir);
+
+ return (_context, _chainParams, _tempDir);
+ }
+
+ private List ReadBlockData()
+ {
+ var blockData = new List();
+ // The file is in the test project directory
+ var testAssemblyDir = Path.GetDirectoryName(typeof(BlockProcessingTests).Assembly.Location);
+ var projectDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(testAssemblyDir)));
+ var blockDataFile = Path.Combine(projectDir!, "TestData", "block_data.txt");
+
+ if (!File.Exists(blockDataFile))
+ {
+ throw new FileNotFoundException($"Block data file not found: {blockDataFile}");
+ }
+
+ foreach (var line in File.ReadLines(blockDataFile))
+ {
+ if (!string.IsNullOrWhiteSpace(line))
+ {
+ blockData.Add(Convert.FromHexString(line.Trim()));
+ }
+ }
+
+ return blockData;
+ }
+
+ private void ProcessBlockData(ChainstateManager chainstateManager, List blockData)
+ {
+ foreach (var rawBlock in blockData)
+ {
+ using var block = Block.FromBytes(rawBlock);
+ chainstateManager.ProcessBlock(block);
+ }
+ }
+
+ private (ChainstateManager, List) SetupChainstateManager()
+ {
+ var (context, chainParams, dataDir) = TestingSetup();
+ var blockData = ReadBlockData();
+
+ var options = new ChainstateManagerOptions(context, dataDir, Path.Combine(dataDir, "blocks"));
+ var chainstateManager = new ChainstateManager(context, chainParams, options);
+
+ return (chainstateManager, blockData);
+ }
+
+ [Fact]
+ public void TestProcessData()
+ {
+ // Arrange
+ var (context, chainParams, dataDir) = TestingSetup();
+ var blocksDir = Path.Combine(dataDir, "blocks");
+ var blockData = ReadBlockData();
+
+
+ var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+ using var chainstateManager = new ChainstateManager(context, chainParams, options);
+
+ // Act & Assert
+ foreach (var rawBlock in blockData)
+ {
+ using var block = Block.FromBytes(rawBlock);
+ var result = chainstateManager.ProcessBlock(block);
+
+ // Assert the block was processed successfully (is new)
+ Assert.True(result, "Block should be new and processed successfully");
+ }
+ }
+
+ [Fact]
+ public void TestValidateAny()
+ {
+ // Arrange
+ var (context, chainParams, dataDir) = TestingSetup();
+ var blocksDir = Path.Combine(dataDir, "blocks");
+ var blockData = ReadBlockData();
+
+ var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+ using var chainstateManager = new ChainstateManager(context, chainParams, options);
+
+ // Act & Assert
+ chainstateManager.ImportBlocks();
+ using var block2 = Block.FromBytes(blockData[1]);
+
+ // The block should be invalid and processing should fail
+ var exception = Assert.Throws(() =>
+ chainstateManager.ProcessBlock(block2));
+
+ // Verify it's a validation error (non-zero error code)
+ Assert.Contains("Failed to process block", exception.Message);
+ }
+
+ [Fact]
+ public void TestReindex()
+ {
+ // Arrange
+ var (context, chainParams, dataDir) = TestingSetup();
+ var blocksDir = Path.Combine(dataDir, "blocks");
+ var blockData = ReadBlockData();
+
+ // Act - Process blocks
+ {
+ var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+ using var chainstateManager = new ChainstateManager(context, chainParams, options);
+
+ foreach (var rawBlock in blockData)
+ {
+ using var block = Block.FromBytes(rawBlock);
+ var result = chainstateManager.ProcessBlock(block);
+ Assert.True(result, "Block should be new and processed successfully");
+ }
+ }
+
+
+ // Act - Reindex
+ var reindexOptions = new ChainstateManagerOptions(context, dataDir, blocksDir)
+ .SetWipeDbs(false, true);
+ using var chainstateManagerReindex = new ChainstateManager(context, chainParams, reindexOptions);
+ var result_reindex = chainstateManagerReindex.ImportBlocks();
+
+ Assert.True(result_reindex, "Reindexing should be successful");
+
+ // Assert - Verify chainstate is intact after reindex
+ var activeChain = chainstateManagerReindex.GetActiveChain();
+ Assert.Equal(blockData.Count, activeChain.Height);
+ }
+
+ [Fact]
+ public void TestInvalidBlock()
+ {
+ // Arrange
+ var (context, chainParams, dataDir) = TestingSetup();
+ var blocksDir = Path.Combine(dataDir, "blocks");
+
+ for (int i = 0; i < 10; i++)
+ {
+ var options = new ChainstateManagerOptions(context, dataDir, blocksDir);
+ using var chainstateManager = new ChainstateManager(context, chainParams, options);
+
+ // Not a block
+ var invalidBlockData = Convert.FromHexString("deadbeef");
+ Assert.Throws(() => Block.FromBytes(invalidBlockData));
+
+ // Invalid block
+ var invalidBlockHex = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd" +
+ "1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299" +
+ "0101000000010000000000000000000000000000000000000000000000000000000000000000ffff" +
+ "ffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec1" +
+ "1600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf62" +
+ "1e73a82cbf2342c858eeac00000000";
+
+ using var block = Block.FromBytes(Convert.FromHexString(invalidBlockHex));
+
+ // The block should be invalid and processing should fail
+ var exception = Assert.Throws(() =>
+ chainstateManager.ProcessBlock(block));
+
+ // Verify it's a validation error (non-zero error code)
+ Assert.Contains("Failed to process block", exception.Message);
+ }
+ }
+
+ [Fact]
+ public void TestScanTransactions()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Act - Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var activeChain = chainstateManager.GetActiveChain();
+
+ // Verify we can iterate through the chain by height
+ for (int height = 0; height <= activeChain.Height; height++)
+ {
+ var blockIndex = activeChain.GetBlockByHeight(height);
+ Assert.NotNull(blockIndex);
+ Assert.Equal(height, blockIndex.Height);
+ }
+
+ // Get the tip and read its spent outputs
+ var tipBlockIndex = activeChain.GetTip();
+ Assert.NotNull(tipBlockIndex);
+
+ using var spentOutputsTip = chainstateManager.ReadSpentOutputs(tipBlockIndex);
+ Assert.NotNull(spentOutputsTip);
+
+ // The number of transaction spent outputs should match transactions minus coinbase
+ // This is validated by checking that Count returns a valid value
+ var tipSpentOutputsCount = spentOutputsTip.Count;
+ Assert.True(tipSpentOutputsCount >= 0, "Spent outputs count should be non-negative");
+
+ // If we have a previous block, scan its transactions in detail
+ var previousBlock = tipBlockIndex.GetPrevious();
+ if (previousBlock != null)
+ {
+ using var spentOutputs = chainstateManager.ReadSpentOutputs(previousBlock);
+ var spentOutputsCount = spentOutputs.Count;
+
+ // Scan each transaction's spent outputs
+ for (int txIndex = 0; txIndex < spentOutputsCount; txIndex++)
+ {
+ using var txSpentOutputs = spentOutputs.GetTransactionSpentOutputs(txIndex);
+ var coinsCount = txSpentOutputs.Count;
+
+ // Verify we can access each coin
+ for (int coinIndex = 0; coinIndex < coinsCount; coinIndex++)
+ {
+ using var coin = txSpentOutputs.GetCoin(coinIndex);
+
+ // Verify coin properties
+ Assert.True(coin.ConfirmationHeight >= 0, "Confirmation height should be non-negative");
+
+ // We should be able to get the output
+ using var output = coin.GetOutput();
+ Assert.NotNull(output);
+
+ // Verify we can get the script pubkey from the output
+ var scriptPubkeyBytes = output.GetScriptPubkey();
+ Assert.NotNull(scriptPubkeyBytes);
+ Assert.True(scriptPubkeyBytes.Length >= 0, "Script pubkey should have valid length");
+
+ // Verify we can get the amount
+ var amount = output.Amount;
+ Assert.True(amount >= 0, "Amount should be non-negative");
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public void TestChainOperations()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var chain = chainstateManager.GetActiveChain();
+
+ // Test genesis via GetGenesis() method
+ var genesis = chain.GetGenesis();
+ Assert.NotNull(genesis);
+ Assert.Equal(0, genesis.Height);
+ var genesisHash = genesis.GetBlockHash();
+ Assert.NotNull(genesisHash);
+
+ // Test tip block
+ var tip = chain.GetTip();
+ Assert.NotNull(tip);
+ var tipHeight = tip.Height;
+ var tipHash = tip.GetBlockHash();
+
+ Assert.True(tipHeight > 0);
+ Assert.False(genesisHash.SequenceEqual(tipHash));
+
+ // Test accessing block by height - genesis
+ var genesisViaHeight = chain.GetBlockByHeight(0);
+ Assert.NotNull(genesisViaHeight);
+ Assert.Equal(0, genesisViaHeight.Height);
+ Assert.True(genesisHash.SequenceEqual(genesisViaHeight.GetBlockHash()));
+
+ // Test accessing block by height - tip
+ var tipViaHeight = chain.GetBlockByHeight(tipHeight);
+ Assert.NotNull(tipViaHeight);
+ Assert.Equal(tipHeight, tipViaHeight.Height);
+ Assert.True(tipHash.SequenceEqual(tipViaHeight.GetBlockHash()));
+
+ // Test invalid height returns null
+ var invalidEntry = chain.GetBlockByHeight(9999);
+ Assert.Null(invalidEntry);
+
+ // Test Contains method
+ Assert.True(chain.Contains(genesis));
+ Assert.True(chain.Contains(tip));
+
+ // Test iteration through chain
+ int count = 0;
+ foreach (var currentBlockIndex in chain.EnumerateBlocks())
+ {
+ Assert.True(chain.Contains(currentBlockIndex));
+ Assert.Equal(count, currentBlockIndex.Height);
+ count++;
+ }
+
+ // Verify we iterated through the entire chain
+ Assert.Equal(tipHeight + 1, count);
+ }
+
+ [Fact]
+ public void TestBlockSpentOutputsIterator()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var activeChain = chainstateManager.GetActiveChain();
+ var blockIndexTip = activeChain.GetTip();
+ using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip);
+
+ // Test count via iterator matches Count property
+ var countViaIterator = spentOutputs.EnumerateTransactionSpentOutputs().Count();
+ Assert.Equal(spentOutputs.Count, countViaIterator);
+
+ // Test collecting all transaction spent outputs
+ var txSpentVec = spentOutputs.EnumerateTransactionSpentOutputs().ToList();
+ Assert.Equal(spentOutputs.Count, txSpentVec.Count);
+
+ // Test that each transaction spent output from iterator matches by index
+ int i = 0;
+ foreach (var txSpent in spentOutputs.EnumerateTransactionSpentOutputs())
+ {
+ using var txSpentViaIndex = spentOutputs.GetTransactionSpentOutputs(i);
+ Assert.Equal(txSpent.Count, txSpentViaIndex.Count);
+ i++;
+ }
+
+ // Test iterator length tracking
+ var initialLen = spentOutputs.Count;
+
+ if (initialLen > 0)
+ {
+ // After skipping one element, we have initialLen - 1 remaining
+ var remaining = spentOutputs.EnumerateTransactionSpentOutputs().Skip(1).Count();
+ Assert.Equal(initialLen - 1, remaining);
+ }
+ }
+
+ [Fact]
+ public void TestTransactionSpentOutputsIterator()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var activeChain = chainstateManager.GetActiveChain();
+ var blockIndexTip = activeChain.GetTip();
+ using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip);
+
+ using var txSpent = spentOutputs.GetTransactionSpentOutputs(0);
+
+ // Test count via iterator matches Count property
+ var countViaIterator = txSpent.EnumerateCoins().Count();
+ Assert.Equal(txSpent.Count, countViaIterator);
+
+ // Test collecting all coins
+ var coins = txSpent.EnumerateCoins().ToList();
+ Assert.Equal(txSpent.Count, coins.Count);
+
+ // Test that each coin from iterator matches coin by index
+ int i = 0;
+ foreach (var coin in txSpent.EnumerateCoins())
+ {
+ using var coinViaIndex = txSpent.GetCoin(i);
+ Assert.Equal(coin.ConfirmationHeight, coinViaIndex.ConfirmationHeight);
+ Assert.Equal(coin.IsCoinbase, coinViaIndex.IsCoinbase);
+ i++;
+ }
+
+ // Test iterator length tracking
+ var initialLen = txSpent.Count;
+
+ if (initialLen > 0)
+ {
+ // After skipping one element, we have initialLen - 1 remaining
+ var remaining = txSpent.EnumerateCoins().Skip(1).Count();
+ Assert.Equal(initialLen - 1, remaining);
+ }
+
+ // Test filtering coinbase coins
+ var coinbaseCoins = txSpent.EnumerateCoins().Where(coin => coin.IsCoinbase).ToList();
+
+ foreach (var coin in coinbaseCoins)
+ {
+ Assert.True(coin.IsCoinbase);
+ }
+ }
+
+ [Fact]
+ public void TestNestedIteration()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var activeChain = chainstateManager.GetActiveChain();
+ var blockIndex = activeChain.GetBlockByHeight(1);
+ Assert.NotNull(blockIndex);
+
+ using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex);
+
+ // Count total coins by nested iteration
+ int totalCoins = 0;
+ foreach (var txSpent in spentOutputs.EnumerateTransactionSpentOutputs())
+ {
+ foreach (var coin in txSpent.EnumerateCoins())
+ {
+ totalCoins++;
+ }
+ }
+
+ // Calculate expected total using LINQ
+ int expectedTotal = spentOutputs.EnumerateTransactionSpentOutputs()
+ .Sum(txSpent => txSpent.Count);
+
+ Assert.Equal(expectedTotal, totalCoins);
+ }
+
+ [Fact]
+ public void TestIteratorWithBlockTransactions()
+ {
+ // Arrange - Setup test environment with blocks
+ var setup = SetupChainstateManager();
+ using var chainstateManager = setup.Item1;
+ var blockData = setup.Item2;
+
+ // Process all test blocks
+ ProcessBlockData(chainstateManager, blockData);
+
+ var activeChain = chainstateManager.GetActiveChain();
+ var blockIndex = activeChain.GetBlockByHeight(1);
+ Assert.NotNull(blockIndex);
+
+ // Use the block data we already have (index 1 corresponds to blockData[1])
+ using var block = Block.FromBytes(blockData[1]);
+ using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex);
+
+ // Zip block transactions (skipping coinbase) with spent outputs
+ // Each transaction's input count should match its spent outputs count
+ int txIndex = 0;
+ foreach (var tx in block.GetTransactions().Skip(1))
+ {
+ using var txSpent = spentOutputs.GetTransactionSpentOutputs(txIndex);
+ Assert.Equal(tx.InputCount, txSpent.Count);
+ txIndex++;
+ }
+
+ // Verify we processed all spent outputs
+ Assert.Equal(spentOutputs.Count, txIndex);
+ }
+}
diff --git a/tests/BitcoinKernel.Tests/BlockTests.cs b/tests/BitcoinKernel.Tests/BlockTests.cs
new file mode 100644
index 0000000..ce87f8e
--- /dev/null
+++ b/tests/BitcoinKernel.Tests/BlockTests.cs
@@ -0,0 +1,71 @@
+using BitcoinKernel.Primatives;
+using Xunit;
+
+namespace BitcoinKernel.Tests;
+
+public class BlockTests
+{
+ private List ReadBlockData()
+ {
+ var blockData = new List();
+ var testAssemblyDir = Path.GetDirectoryName(typeof(BlockTests).Assembly.Location);
+ var projectDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(testAssemblyDir)));
+ var blockDataFile = Path.Combine(projectDir!, "TestData", "block_data.txt");
+
+ if (!File.Exists(blockDataFile))
+ {
+ throw new FileNotFoundException($"Block data file not found: {blockDataFile}");
+ }
+
+ foreach (var line in File.ReadLines(blockDataFile))
+ {
+ if (!string.IsNullOrWhiteSpace(line))
+ {
+ blockData.Add(Convert.FromHexString(line.Trim()));
+ }
+ }
+
+ return blockData;
+ }
+
+ [Fact]
+ public void TestBlockTransactionsIterator()
+ {
+ var blockData = ReadBlockData();
+
+ using var block = Block.FromBytes(blockData[5]);
+
+ // Test that iterator count matches transaction count
+ var txCountViaIterator = block.GetTransactions().Count();
+ Assert.Equal(block.TransactionCount, txCountViaIterator);
+
+ // Test collecting all transactions
+ var txs = block.GetTransactions().ToList();
+ Assert.Equal(block.TransactionCount, txs.Count);
+
+ // Test that each transaction from iterator matches transaction by index
+ int i = 0;
+ foreach (var tx in block.GetTransactions())
+ {
+ using var txViaIndex = block.GetTransaction(i);
+ Assert.NotNull(txViaIndex);
+ Assert.Equal(tx.InputCount, txViaIndex.InputCount);
+ Assert.Equal(tx.OutputCount, txViaIndex.OutputCount);
+ i++;
+ }
+
+ // Test iterator length decreases as we consume it
+ var iter = block.GetTransactions().GetEnumerator();
+ var initialLen = block.TransactionCount;
+
+ // Move to first element
+ Assert.True(iter.MoveNext());
+ // After consuming one element, we have initialLen - 1 remaining
+ var remaining = block.GetTransactions().Skip(1).Count();
+ Assert.Equal(initialLen - 1, remaining);
+
+ // Test skipping coinbase transaction
+ var nonCoinbaseTxs = block.GetTransactions().Skip(1).ToList();
+ Assert.Equal(block.TransactionCount - 1, nonCoinbaseTxs.Count);
+ }
+}
diff --git a/tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs
similarity index 96%
rename from tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs
rename to tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs
index 729f7c2..b9a3e62 100644
--- a/tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs
+++ b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs
@@ -1,9 +1,10 @@
-using BitcoinKernel.Core.BlockProcessing;
-using BitcoinKernel.Core.Chain;
+using BitcoinKernel.BlockProcessing;
+using BitcoinKernel.Chain;
using BitcoinKernel.Interop.Enums;
+using BitcoinKernel.Primatives;
-namespace BitcoinKernel.Core.Tests;
+namespace BitcoinKernel.Tests;
public class BlockTreeEntryTests : IDisposable
{
@@ -41,7 +42,7 @@ private void SetupWithBlocks()
// Process test blocks
foreach (var rawBlock in ReadBlockData())
{
- using var block = Abstractions.Block.FromBytes(rawBlock);
+ using var block = Block.FromBytes(rawBlock);
_chainstateManager.ProcessBlock(block);
}
}
diff --git a/tests/BitcoinKernel.Core.Tests/BlockValidationStateTests.cs b/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs
similarity index 96%
rename from tests/BitcoinKernel.Core.Tests/BlockValidationStateTests.cs
rename to tests/BitcoinKernel.Tests/BlockValidationStateTests.cs
index 3c46c89..66c15aa 100644
--- a/tests/BitcoinKernel.Core.Tests/BlockValidationStateTests.cs
+++ b/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core.Abstractions;
+using BitcoinKernel.Primatives;
using BitcoinKernel.Interop.Enums;
using Xunit;
-namespace BitcoinKernel.Core.Tests;
+namespace BitcoinKernel.Tests;
public class BlockValidationStateTests
{
diff --git a/tests/BitcoinKernel.Core.Tests/KernelContextTest.cs b/tests/BitcoinKernel.Tests/KernelContextTest.cs
similarity index 90%
rename from tests/BitcoinKernel.Core.Tests/KernelContextTest.cs
rename to tests/BitcoinKernel.Tests/KernelContextTest.cs
index 86daf19..ab4153e 100644
--- a/tests/BitcoinKernel.Core.Tests/KernelContextTest.cs
+++ b/tests/BitcoinKernel.Tests/KernelContextTest.cs
@@ -1,7 +1,7 @@
-using BitcoinKernel.Core.Exceptions;
+using BitcoinKernel.Exceptions;
using Xunit;
-namespace BitcoinKernel.Core.Tests;
+namespace BitcoinKernel.Tests;
public class KernelContextTest
{
diff --git a/tests/BitcoinKernel.Tests/KernelLibraryIntegrationTests.cs b/tests/BitcoinKernel.Tests/KernelLibraryIntegrationTests.cs
deleted file mode 100644
index d5cf44c..0000000
--- a/tests/BitcoinKernel.Tests/KernelLibraryIntegrationTests.cs
+++ /dev/null
@@ -1,493 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using BitcoinKernel;
-using Xunit;
-
-namespace BitcoinKernel.Tests
-{
- ///
- /// Integration tests for the BitcoinKernel facade.
- /// These tests verify end-to-end functionality of the library.
- ///
- public class KernelLibraryIntegrationTests : IDisposable
- {
- private KernelLibrary? _kernel;
-
- ///
- /// Helper property to ensure previous kernel is disposed before assigning a new one.
- ///
- private KernelLibrary Kernel
- {
- get => _kernel ?? throw new InvalidOperationException("Kernel not initialized");
- set
- {
- _kernel?.Dispose();
- _kernel = value;
- }
- }
-
- public void Dispose()
- {
- _kernel?.Dispose();
- _kernel = null;
- }
-
- [Fact]
- public void KernelLibrary_CanCreateAndDispose()
- {
- // Arrange & Act
- Kernel = KernelLibrary.Create()
- .ForMainnet()
- .Build();
-
- // Assert
- Assert.NotNull(_kernel);
- }
-
- [Fact]
- public void KernelLibrary_CanCreateForDifferentChains()
- {
- // Test mainnet
- using var mainnetKernel = KernelLibrary.Create()
- .ForMainnet()
- .Build();
- Assert.NotNull(mainnetKernel);
-
- // Test testnet
- using var testnetKernel = KernelLibrary.Create()
- .ForTestnet()
- .Build();
- Assert.NotNull(testnetKernel);
-
- // test testnet_4
- using var testnet4Kernel = KernelLibrary.Create()
- .ForTestnet4()
- .Build();
- Assert.NotNull(testnet4Kernel);
-
- // Test signet
- using var signetKernel = KernelLibrary.Create()
- .ForSignet()
- .Build();
- Assert.NotNull(signetKernel);
-
- // Test regtest
- using var regtestKernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
- Assert.NotNull(regtestKernel);
- }
-
- [Fact]
- public void KernelLibrary_CanEnableLogging()
- {
- // Arrange
- string? lastLogMessage = null;
- void LogCallback(string category, string message, int level)
- {
- lastLogMessage = $"[{category}] {message} (level: {level})";
- }
-
- // Act
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .WithLogging(LogCallback)
- .Build();
-
- // Assert
- Assert.NotNull(_kernel);
- // Note: We can't easily test actual logging without triggering log events,
- // but we can verify the kernel was created successfully with logging enabled
- }
-
- [Fact]
- public void KernelLibrary_CanVerifyScript()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Test data: Simple P2PKH script verification
- // This is a basic test - in real scenarios you'd use actual transaction data
- string scriptPubkeyHex = "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac";
- string transactionHex = "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700";
-
- // Act & Assert
- // This should succeed with valid test data
- bool result = Kernel.VerifyScript(scriptPubkeyHex, 0, transactionHex, 0, new List { scriptPubkeyHex });
- Assert.True(result);
- }
-
- // [Fact]
- // public void KernelLibrary_ScriptVerificationFailsWithInvalidData()
- // {
- // Arrange
- // Kernel = KernelLibrary.Create()
- // .ForRegtest()
- // .Build();
-
- // Use invalid script pubkey (modified last byte)
- // string invalidScriptPubkeyHex = "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ff";
- // ScriptPubKey invalidScriptPubKey = ScriptPubKey.FromHex(invalidScriptPubkeyHex);
- // string transactionHex = "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700";
- // Transaction transaction = Transaction.FromHex(transactionHex);
- // List spentOutputs = new List();
-
- // Act & Assert
- // This should fail with invalid script data
- // bool result = Kernel.VerifyScript(invalidScriptPubKey, 0, transaction, 0, spentOutputs, ScriptVerificationFlags.All);
- // Assert.False(result);
- // }
-
- [Fact]
- public void KernelLibrary_AutoInitializesChainstate()
- {
- // Arrange & Act
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Assert
- // Chainstate should be automatically initialized by the builder
- Assert.NotNull(Kernel.Chainstate);
-
- // Should be able to query chain information immediately
- int height = Kernel.GetChainHeight();
- Assert.True(height >= 0);
- }
-
- [Fact]
- public void KernelLibrary_CanGetChainHeight()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act
- int height = Kernel.GetChainHeight();
-
- // Assert
- Assert.True(height >= 0); // Chain height should be non-negative
- }
-
- [Fact]
- public void KernelLibrary_CanGetChainTipHash()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act
- byte[] tipHash = Kernel.GetChainTipHash();
-
- // Assert
- Assert.NotNull(tipHash);
- Assert.Equal(32, tipHash.Length); // Bitcoin hashes are 32 bytes
- }
-
- [Fact]
- public void KernelLibrary_CanGetGenesisBlockHash()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act
- byte[] genesisHash = Kernel.GetGenesisBlockHash();
-
- // Assert
- Assert.NotNull(genesisHash);
- Assert.Equal(32, genesisHash.Length); // Bitcoin hashes are 32 bytes
- }
-
- [Fact]
- public void KernelLibrary_CanGetBlockHash()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act - Get genesis block hash (height 0)
- byte[]? genesisHash = Kernel.GetBlockHash(0);
-
- // Assert
- Assert.NotNull(genesisHash);
- Assert.Equal(32, genesisHash.Length);
-
- // Test invalid height
- byte[]? invalidHash = Kernel.GetBlockHash(-1);
- Assert.Null(invalidHash);
- }
-
- [Fact]
- public void KernelLibrary_CanEnumerateBlockHashes()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act
- var blockHashes = Kernel.EnumerateBlockHashes().ToList();
-
- // Assert
- Assert.NotEmpty(blockHashes);
- Assert.True(blockHashes.Count >= 1); // At least genesis block
-
- // All hashes should be 32 bytes
- foreach (var hash in blockHashes)
- {
- Assert.Equal(32, hash.Length);
- }
- }
-
- [Fact]
- public void KernelLibrary_CanGetBlockInfo()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Act - Get genesis block info
- var genesisInfo = Kernel.GetBlockInfo(0);
-
- // Assert
- Assert.NotNull(genesisInfo);
- Assert.Equal(0, genesisInfo.Height);
- Assert.NotNull(genesisInfo.Hash);
- Assert.Equal(32, genesisInfo.Hash.Length);
- Assert.Null(genesisInfo.PreviousHash); // Genesis has no previous
-
- // Test invalid height
- var invalidInfo = Kernel.GetBlockInfo(-1);
- Assert.Null(invalidInfo);
- }
-
- [Fact]
- public void KernelLibrary_CanValidateBlock()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Test that ValidateBlock properly calls the core validation
- // With invalid block data, it should return false
- byte[] invalidBlockData = new byte[80 + 1 + 60]; // Header + tx count + minimal data
- invalidBlockData[80] = 1; // 1 transaction (but not a valid block)
-
- // Act
- bool isValid = Kernel.ValidateBlock(invalidBlockData);
-
- // Assert
- // Now using real validation from BlockProcessor, this should correctly fail
- Assert.False(isValid);
-
- // Test invalid block (too small for header)
- byte[] tooSmallBlockData = new byte[40]; // Too small
- bool isTooSmallValid = Kernel.ValidateBlock(tooSmallBlockData);
- Assert.False(isTooSmallValid);
-
- // Test null block data
- bool isNullValid = Kernel.ValidateBlock((byte[])null!);
- Assert.False(isNullValid);
- }
-
- [Fact]
- public void KernelLibrary_CanValidateBlockDetailed()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Test that ValidateBlockDetailed returns detailed validation results
- byte[] invalidBlockData = new byte[80 + 1 + 60]; // Invalid block data
- invalidBlockData[80] = 1;
-
- // Act
- var result = Kernel.ValidateBlockDetailed(invalidBlockData);
-
- // Assert
- Assert.NotNull(result);
- Assert.False(result.IsValid);
-
- // Test with too small block data
- byte[] tooSmallData = new byte[40];
- var smallResult = Kernel.ValidateBlockDetailed(tooSmallData);
- Assert.False(smallResult.IsValid);
- Assert.Contains("too small", smallResult.ErrorMessage ?? "", StringComparison.OrdinalIgnoreCase);
-
- // Test with null data
- var nullResult = Kernel.ValidateBlockDetailed((byte[])null!);
- Assert.False(nullResult.IsValid);
- }
-
- [Fact]
- public void KernelLibrary_BuilderCanConfigureWorkerThreads()
- {
- // Arrange & Act
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .WithWorkerThreads(8)
- .Build();
-
- // Assert
- Assert.NotNull(_kernel);
- }
-
- [Fact]
- public void KernelLibrary_BuilderCanConfigureDirectories()
- {
- // Arrange
- string customDataDir = Path.Combine(Path.GetTempPath(), $"BitcoinKernel_Data_{Guid.NewGuid()}");
- string customBlocksDir = Path.Combine(Path.GetTempPath(), $"BitcoinKernel_Blocks_{Guid.NewGuid()}");
-
- try
- {
- // Act
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .WithDirectories(customDataDir, customBlocksDir)
- .Build();
-
- // Assert
- Assert.NotNull(_kernel);
- Assert.NotNull(Kernel.Chainstate); // Should be auto-initialized
- }
- finally
- {
- // Cleanup
- if (Directory.Exists(customDataDir))
- Directory.Delete(customDataDir, true);
- if (Directory.Exists(customBlocksDir))
- Directory.Delete(customBlocksDir, true);
- }
- }
-
- [Fact]
- public void KernelLibrary_BuilderCanConfigureWipeDatabases()
- {
- // Arrange & Act
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .WithWipeDatabases(wipeBlockTree: true, wipeChainstate: true)
- .Build();
-
- // Assert
- Assert.NotNull(_kernel);
- Assert.NotNull(Kernel.Chainstate); // Should be auto-initialized
- // Note: Database wiping behavior would be tested in integration scenarios
- // with actual data persistence
- }
-
- [Fact]
- public void KernelLibrary_CanProcessBlockWithHexString()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Create some hex block data (this will fail to parse)
- string blockHex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c01010000000100000000000000000000";
-
- // Act & Assert
- // Invalid block data should throw BlockException during parsing
- Assert.Throws(() => Kernel.ProcessBlock(blockHex));
- }
-
- [Fact]
- public void KernelLibrary_CanValidateBlockWithHexString()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Create some hex block data
- string blockHex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c01010000000100000000000000000000";
-
- // Act
- bool isValid = Kernel.ValidateBlock(blockHex);
-
- // Assert - Invalid block should return false
- Assert.False(isValid);
- }
-
- [Fact]
- public void KernelLibrary_CanValidateBlockDetailedWithHexString()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- string blockHex = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c01010000000100000000000000000000";
-
- // Act
- var result = Kernel.ValidateBlockDetailed(blockHex);
-
- // Assert
- Assert.NotNull(result);
- Assert.False(result.IsValid);
- }
-
- [Fact]
- public void KernelLibrary_CanGetBlockTreeEntry()
- {
- // Arrange
- Kernel = KernelLibrary.Create()
- .ForRegtest()
- .Build();
-
- // Get genesis block hash
- byte[] genesisHash = Kernel.GetGenesisBlockHash();
-
- // Act
- var entry = Kernel.GetBlockTreeEntry(genesisHash);
-
- // Assert - May be null if block tree entry not available
- // This is acceptable as it depends on kernel implementation
- if (entry != null)
- {
- Assert.NotNull(entry);
- }
- }
-
- [Fact]
- public void KernelLibrary_BuilderValidatesWorkerThreads()
- {
- // Act & Assert
- Assert.Throws(() =>
- KernelLibrary.Create()
- .ForRegtest()
- .WithWorkerThreads(0) // Invalid - must be at least 1
- .Build());
- }
-
- [Fact]
- public void KernelLibrary_BuilderValidatesDirectories()
- {
- // Act & Assert
- Assert.Throws(() =>
- KernelLibrary.Create()
- .ForRegtest()
- .WithDirectories("", "/some/path") // Empty data directory
- .Build());
-
- Assert.Throws(() =>
- KernelLibrary.Create()
- .ForRegtest()
- .WithDirectories("/some/path", "") // Empty blocks directory
- .Build());
- }
- }
-}
\ No newline at end of file
diff --git a/tests/BitcoinKernel.Core.Tests/ScriptVerificationTests.cs b/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs
similarity index 98%
rename from tests/BitcoinKernel.Core.Tests/ScriptVerificationTests.cs
rename to tests/BitcoinKernel.Tests/ScriptVerificationTests.cs
index 35b8534..b9c9828 100644
--- a/tests/BitcoinKernel.Core.Tests/ScriptVerificationTests.cs
+++ b/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs
@@ -1,12 +1,12 @@
using System;
-using BitcoinKernel.Core.ScriptVerification;
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.Exceptions;
-using BitcoinKernel.Core.Chain;
+using BitcoinKernel.ScriptVerification;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Exceptions;
+using BitcoinKernel.Chain;
using BitcoinKernel.Interop.Enums;
using Xunit;
-namespace BitcoinKernel.Core.Tests;
+namespace BitcoinKernel.Tests;
public class ScriptVerificationFixture : IDisposable
{
diff --git a/tests/BitcoinKernel.Core.Tests/TestData/block_data.txt b/tests/BitcoinKernel.Tests/TestData/block_data.txt
similarity index 100%
rename from tests/BitcoinKernel.Core.Tests/TestData/block_data.txt
rename to tests/BitcoinKernel.Tests/TestData/block_data.txt
diff --git a/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs
index 08749a0..41cce44 100644
--- a/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs
+++ b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs
@@ -1,8 +1,8 @@
-using BitcoinKernel.Core;
-using BitcoinKernel.Core.Abstractions;
-using BitcoinKernel.Core.Chain;
-using BitcoinKernel.Core.Exceptions;
-using BitcoinKernel.Core.ScriptVerification;
+using BitcoinKernel;
+using BitcoinKernel.Primatives;
+using BitcoinKernel.Chain;
+using BitcoinKernel.Exceptions;
+using BitcoinKernel.ScriptVerification;
using BitcoinKernel.Interop.Enums;
using BitcoinKernel.TestHandler.Protocol;
using BitcoinKernel.TestHandler.Registry;
@@ -11,7 +11,7 @@ namespace BitcoinKernel.TestHandler.Handlers;
///
/// Routes all incoming method calls to the appropriate handler and manages the object registry.
-/// Uses BitcoinKernel.Core managed types throughout.
+/// Uses BitcoinKernel managed types throughout.
///
public sealed class MethodDispatcher : IDisposable
{
@@ -100,7 +100,7 @@ public Response ChainstateManagerGetActiveChain(string id, string? refName, Btck
var manager = Get(csmRef).Manager;
var chain = manager.GetActiveChain();
- _registry.Register(refName, new NonOwningRef(chain));
+ _registry.Register(refName, new NonOwningRef(chain));
return Responses.Ref(id, refName);
}
@@ -133,7 +133,7 @@ public Response ChainstateManagerDestroy(string id, BtckChainstateManagerDestroy
public Response ChainGetHeight(string id, BtckChainGetHeightParams p)
{
if (p.Chain?.Ref is not { } chainRef) return RefError(id);
- return Responses.Ok(id, GetVal(chainRef).Height);
+ return Responses.Ok(id, GetVal(chainRef).Height);
}
public Response ChainGetByHeight(string id, string? refName, BtckChainGetByHeightParams p)
@@ -141,7 +141,7 @@ public Response ChainGetByHeight(string id, string? refName, BtckChainGetByHeigh
if (refName == null) return RefError(id);
if (p.Chain?.Ref is not { } chainRef) return RefError(id);
- var blockIndex = GetVal(chainRef).GetBlockByHeight(p.BlockHeight);
+ var blockIndex = GetVal(chainRef).GetBlockByHeight(p.BlockHeight);
if (blockIndex == null) return Responses.EmptyError(id);
_registry.Register(refName, new NonOwningRef(blockIndex));
@@ -153,7 +153,7 @@ public Response ChainContains(string id, BtckChainContainsParams p)
if (p.Chain?.Ref is not { } chainRef) return RefError(id);
if (p.BlockTreeEntry?.Ref is not { } bteRef) return RefError(id);
- bool contains = GetVal(chainRef).Contains(GetVal(bteRef));
+ bool contains = GetVal(chainRef).Contains(GetVal(bteRef));
return Responses.Ok(id, contains);
}
diff --git a/tools/kernel-bindings-test-handler/README.md b/tools/kernel-bindings-test-handler/README.md
index 9825654..a94db28 100644
--- a/tools/kernel-bindings-test-handler/README.md
+++ b/tools/kernel-bindings-test-handler/README.md
@@ -7,7 +7,7 @@ It implements the protocol specification [kernel-bindings-test handler-spec](htt
The handler is a console application that:
- Reads JSON requests line-by-line from stdin
-- Processes each request using the BitcoinKernel.Core library
+- Processes each request using the BitcoinKernel library
- Writes JSON responses to stdout
- Exits cleanly when stdin closes
@@ -137,12 +137,12 @@ tools/kernel-bindings-test-handler/
## Dependencies
-- BitcoinKernel.Core: The core library being tested
+- BitcoinKernel: The core library being tested
- System.Text.Json: JSON serialization
## Error Handling
-The handler maps BitcoinKernel.Core exceptions to protocol error responses:
+The handler maps BitcoinKernel exceptions to protocol error responses:
| Exception | Error Type | Error Variant |
|-----------|-----------|---------------|
diff --git a/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj b/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj
index 45fef66..58097f3 100644
--- a/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj
+++ b/tools/kernel-bindings-test-handler/kernel-bindings-test-handler.csproj
@@ -9,7 +9,7 @@
-
+