From 66f8763c08f6f64ed1c721171ccc91e18019e55e Mon Sep 17 00:00:00 2001 From: jan Date: Mon, 2 Mar 2026 13:03:31 +0000 Subject: [PATCH 1/8] refactor(Interop): restrict NativeMethods and P/Invoke internals to internal visibility Make NativeMethods, all delegate types, and all P/Invoke structs internal in BitcoinKernel.Interop so they are not part of the public API surface. Public enums (ChainType, ScriptVerifyStatus, ScriptVerificationFlags, etc.) remain public as they appear in the Core public API. --- src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj | 6 ++++++ src/BitcoinKernel.Interop/Delegates/DestroyCallback.cs | 2 +- src/BitcoinKernel.Interop/Delegates/LoggingCallback.cs | 2 +- .../Delegates/Notification/NotifyBlockTip.cs | 2 +- .../Delegates/Notification/NotifyFatalError.cs | 2 +- .../Delegates/Notification/NotifyFlushError.cs | 2 +- .../Delegates/Notification/NotifyHeaderTip.cs | 2 +- .../Delegates/Notification/NotifyProgress.cs | 2 +- .../Delegates/Notification/NotifyWarningSet.cs | 2 +- .../Delegates/Notification/NotifyWarningUnset.cs | 2 +- .../Delegates/Validation/ValidationBlockChecked.cs | 2 +- .../Delegates/Validation/ValidationBlockConnected.cs | 2 +- .../Delegates/Validation/ValidationBlockDisconnected.cs | 2 +- .../Delegates/Validation/ValidationNewPoWValidBlock.cs | 2 +- src/BitcoinKernel.Interop/NativeMethods.cs | 2 +- src/BitcoinKernel.Interop/Structs/LoggingOptions.cs | 2 +- .../Structs/NotificationInterfaceCallbacks.cs | 2 +- .../Structs/ValidationInterfaceCallbacks.cs | 2 +- 18 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj index 0b39cd6..0880e7d 100644 --- a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj +++ b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj @@ -7,6 +7,12 @@ true + + + <_Parameter1>BitcoinKernel.Core + + + 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/NativeMethods.cs b/src/BitcoinKernel.Interop/NativeMethods.cs index 17e7669..ec9a79d 100644 --- a/src/BitcoinKernel.Interop/NativeMethods.cs +++ b/src/BitcoinKernel.Interop/NativeMethods.cs @@ -11,7 +11,7 @@ namespace BitcoinKernel.Interop /// Low-level P/Invoke declarations for the Bitcoin Kernel C API. /// Maps directly to the bitcoinkernel.h C header. /// - public static class NativeMethods + internal static class NativeMethods { #region Library Configuration diff --git a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs index b623e51..0dd46ae 100644 --- a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs +++ b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs @@ -3,7 +3,7 @@ namespace BitcoinKernel.Interop.Structs { [StructLayout(LayoutKind.Sequential)] - public struct LoggingOptions + internal struct LoggingOptions { public int LogTimestamps; public int LogTimeMicros; diff --git a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs index 599ba14..b899ac8 100644 --- a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs @@ -4,7 +4,7 @@ namespace BitcoinKernel.Interop.Structs { [StructLayout(LayoutKind.Sequential)] - public struct NotificationInterfaceCallbacks + internal struct NotificationInterfaceCallbacks { public IntPtr UserData; public NotifyBlockTip BlockTip; diff --git a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs index 8bd4a36..aad75b0 100644 --- a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs @@ -4,7 +4,7 @@ namespace BitcoinKernel.Interop.Structs { [StructLayout(LayoutKind.Sequential)] - public struct ValidationInterfaceCallbacks + internal struct ValidationInterfaceCallbacks { public IntPtr UserData; public ValidationBlockChecked BlockChecked; From 6da7f6a641c14968bf038af3a99367d6ad8f7650 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:11:47 +0100 Subject: [PATCH 2/8] refactor: remove BitcoinKernel facade, rename Core to BitcoinKernel - Delete src/BitcoinKernel/ (KernelLibrary fluent builder) and its tests - Rename BitcoinKernel.Core project/namespaces to BitcoinKernel - Rewrite examples to use the managed API directly --- BitcoinKernel.NET.sln | 34 +- README.md | 73 +-- examples/BasicUsage/Program.cs | 86 ++- examples/BlockProcessing/Program.cs | 107 ++-- .../BitcoinKernel.Core.csproj | 48 -- .../BitcoinKernel.Interop.csproj | 2 +- .../Abstractions/Block.cs | 4 +- .../Abstractions/BlockHash.cs | 4 +- .../Abstractions/BlockHeader.cs | 4 +- .../Abstractions/BlockIndex.cs | 2 +- .../Abstractions/BlockSpentOutputs.cs | 2 +- .../Abstractions/BlockValidationState.cs | 4 +- .../Abstractions/Chain.cs | 4 +- .../Abstractions/Coin.cs | 2 +- .../Abstractions/ScriptPubKey.cs | 4 +- .../Abstractions/Transaction.cs | 4 +- .../Abstractions/TransactionSpentOutputs.cs | 2 +- .../Abstractions/TxOut.cs | 4 +- src/BitcoinKernel/BitcoinKernel.csproj | 32 +- .../BlockProcessing/BlockProcessor.cs | 8 +- .../BlockProcessing/BlockTreeEntry.cs | 6 +- .../BlockProcessing/BlockValidationResult.cs | 2 +- .../Chain/ChainParameters.cs | 2 +- .../Chain/ChainStateManager.cs | 6 +- .../Exceptions/Exceptions.cs | 2 +- .../KernelContext.cs | 4 +- .../KernelContextOptions.cs | 6 +- src/BitcoinKernel/KernelLibrary.cs | 602 ------------------ .../LoggingConnection.cs | 0 src/BitcoinKernel/README.md | 45 -- .../PrecomputedTransactionData.cs | 6 +- .../ScriptVerification/ScriptVerifier.cs | 6 +- .../BitcoinKernel.Core.Tests.csproj | 26 - .../BitcoinKernel.Tests.csproj | 50 +- .../BlockHeaderTests.cs | 12 +- .../BlockProcessingTests.cs | 6 +- .../BlockTests.cs | 4 +- .../BlockTreeEntryTests.cs | 6 +- .../BlockValidationStateTests.cs | 4 +- .../KernelContextTest.cs | 4 +- .../KernelLibraryIntegrationTests.cs | 493 -------------- .../ScriptVerificationTests.cs | 10 +- .../TestData/block_data.txt | 0 .../Handlers/MethodDispatcher.cs | 20 +- tools/kernel-bindings-test-handler/README.md | 6 +- .../kernel-bindings-test-handler.csproj | 2 +- 46 files changed, 242 insertions(+), 1518 deletions(-) delete mode 100644 src/BitcoinKernel.Core/BitcoinKernel.Core.csproj rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/Block.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/BlockHash.cs (95%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/BlockHeader.cs (97%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/BlockIndex.cs (97%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/BlockSpentOutputs.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/BlockValidationState.cs (96%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/Chain.cs (96%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/Coin.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/ScriptPubKey.cs (96%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/Transaction.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/TransactionSpentOutputs.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Abstractions/TxOut.cs (97%) rename src/{BitcoinKernel.Core => BitcoinKernel}/BlockProcessing/BlockProcessor.cs (97%) rename src/{BitcoinKernel.Core => BitcoinKernel}/BlockProcessing/BlockTreeEntry.cs (95%) rename src/{BitcoinKernel.Core => BitcoinKernel}/BlockProcessing/BlockValidationResult.cs (95%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Chain/ChainParameters.cs (96%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Chain/ChainStateManager.cs (98%) rename src/{BitcoinKernel.Core => BitcoinKernel}/Exceptions/Exceptions.cs (99%) rename src/{BitcoinKernel.Core => BitcoinKernel}/KernelContext.cs (91%) rename src/{BitcoinKernel.Core => BitcoinKernel}/KernelContextOptions.cs (94%) delete mode 100644 src/BitcoinKernel/KernelLibrary.cs rename src/{BitcoinKernel.Core => BitcoinKernel}/LoggingConnection.cs (100%) delete mode 100644 src/BitcoinKernel/README.md rename src/{BitcoinKernel.Core => BitcoinKernel}/ScriptVerification/PrecomputedTransactionData.cs (94%) rename src/{BitcoinKernel.Core => BitcoinKernel}/ScriptVerification/ScriptVerifier.cs (97%) delete mode 100644 tests/BitcoinKernel.Core.Tests/BitcoinKernel.Core.Tests.csproj rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/BlockHeaderTests.cs (98%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/BlockProcessingTests.cs (99%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/BlockTests.cs (97%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/BlockTreeEntryTests.cs (97%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/BlockValidationStateTests.cs (96%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/KernelContextTest.cs (90%) delete mode 100644 tests/BitcoinKernel.Tests/KernelLibraryIntegrationTests.cs rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/ScriptVerificationTests.cs (98%) rename tests/{BitcoinKernel.Core.Tests => BitcoinKernel.Tests}/TestData/block_data.txt (100%) 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/README.md b/README.md index fe83811..4fcea9c 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.1.2 | 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..69c6b11 100644 --- a/examples/BasicUsage/Program.cs +++ b/examples/BasicUsage/Program.cs @@ -1,76 +1,64 @@ -ο»Ώusing System; using BitcoinKernel; +using BitcoinKernel.Chain; +using BitcoinKernel.Interop.Enums; -namespace FacadeExample +namespace BasicUsage { class Program { static void Main(string[] args) { - Console.WriteLine("=== Bitcoin Kernel Basic Builder Example ===\n"); - - FullChainstateExample(); - + Console.WriteLine("=== Bitcoin Kernel Basic Usage Example ===\n"); + FullChainstateExample(); } static void FullChainstateExample() { - Console.WriteLine("2. Full Chainstate Example:"); + Console.WriteLine("Creating kernel..."); + + var dataDir = "/tmp/regtest-data2"; + var blocksDir = "/tmp/regtest-data/blocks2"; - 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) => + using var logging = new LoggingConnection((category, message, level) => { - if (level <= (int)BitcoinKernel.Interop.Enums.LogLevel.INFO) // Only INFO and above + if (level <= (int)LogLevel.INFO) Console.WriteLine($" [{category}] {message}"); - }); - - Console.WriteLine(" Building kernel..."); - using var kernel = builder.Build(); - - Console.WriteLine(" Kernel built successfully!"); - Console.WriteLine(" βœ“ Chainstate initialized automatically"); + }); + + 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!"); - // Process blocks try { + var chain = chainstate.GetActiveChain(); + Console.WriteLine($" Chain height: {chain.Height}"); + Console.WriteLine($" Genesis hash: {Convert.ToHexString(chain.GetGenesis().GetBlockHash())}"); - 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) + if (chain.Height > 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)}"); - } + 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(" βœ“ Chain queries working"); + Console.WriteLine(" Chain queries working"); } catch (Exception ex) { - Console.WriteLine($" βœ— Error: {ex.Message}"); - } - - + Console.WriteLine($" Error: {ex.Message}"); + } + Console.WriteLine("\nPress any key to exit..."); - Console.ReadKey(); - - kernel.Dispose(); - Console.WriteLine(" Kernel disposed."); + Console.ReadKey(); } } -} \ No newline at end of file +} diff --git a/examples/BlockProcessing/Program.cs b/examples/BlockProcessing/Program.cs index 3cadbc9..e9b0b1e 100644 --- a/examples/BlockProcessing/Program.cs +++ b/examples/BlockProcessing/Program.cs @@ -1,6 +1,8 @@ -ο»Ώusing System; using System.IO; using BitcoinKernel; +using BitcoinKernel.Abstractions; +using BitcoinKernel.Chain; +using BitcoinKernel.Interop.Enums; namespace BlockProcessing { @@ -11,109 +13,84 @@ 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 { - // 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 + 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 { sampleBlockData = CreateSampleBlock(); - Console.WriteLine("βœ“ Created sample block data"); + 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!"); + Console.WriteLine($"Block creation failed: {ex.Message}"); + Console.WriteLine("This is expected for simplified block data."); return; } - // Step 4: Display block information before processing DisplayBlockInfo(sampleBlockData); - // Step 5: Process the block through validation Console.WriteLine("\nProcessing block..."); try { - bool success = kernel.ProcessBlock(sampleBlockData); + using var block = Block.FromBytes(sampleBlockData); + bool isNew = chainstate.ProcessBlock(block); - if (success) + if (isNew) { - Console.WriteLine("βœ“ Block processed successfully!"); - - // Step 6: Get active chain information - var activeChain = kernel.Chainstate.GetActiveChain(); - Console.WriteLine($" - Active chain height: {activeChain.Height}"); - + var activeChain = chainstate.GetActiveChain(); + Console.WriteLine($"Block processed! Chain height: {activeChain.Height}"); var tip = activeChain.GetTip(); - Console.WriteLine($" - Active chain tip: {BitConverter.ToString(tip.GetBlockHash()).Replace("-", "")}"); + Console.WriteLine($" - Tip: {BitConverter.ToString(tip.GetBlockHash()).Replace("-", "")}"); } else { - Console.WriteLine("βœ— Block processing failed - this may be expected for invalid block data"); + Console.WriteLine("Block processing failed - expected for invalid block data"); } } catch (Exception ex) { - Console.WriteLine($"βœ— Block processing error: {ex.Message}"); - Console.WriteLine(" This is expected for simplified/invalid block data."); + Console.WriteLine($"Block processing error: {ex.Message}"); + Console.WriteLine("This is expected for simplified/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!)"); + Console.WriteLine("\nBlock processing example completed!"); } catch (Exception ex) { - Console.WriteLine($"βœ— Error: {ex.Message}"); + Console.WriteLine($"Error: {ex.Message}"); if (ex.InnerException != null) - { Console.WriteLine($"Inner exception: {ex.InnerException.Message}"); - } - Console.WriteLine($"Stack trace: {ex.StackTrace}"); } } private static byte[] CreateSampleBlock() { - // 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 - byte[] blockData = new byte[80]; // Version: 1 (little endian) BitConverter.GetBytes(1).CopyTo(blockData, 0); - // Previous block hash: all zeros for genesis-like block - // (indices 4-35 remain 0) - - // Merkle root: all zeros for simplicity - // (indices 36-67 remain 0) + // Previous block hash: all zeros (indices 4-35) + // Merkle root: all zeros (indices 36-67) // Timestamp: current Unix timestamp uint timestamp = (uint)(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); @@ -122,8 +99,7 @@ private static byte[] CreateSampleBlock() // Bits: 0x1d00ffff (Bitcoin mainnet difficulty) BitConverter.GetBytes(0x1d00ffffu).CopyTo(blockData, 72); - // Nonce: 0 for this example - // (indices 76-79 remain 0) + // Nonce: 0 (indices 76-79) return blockData; } @@ -135,26 +111,19 @@ private static void DisplayBlockInfo(byte[] blockData) 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("-", " ")}"); - // Parse version (first 4 bytes, little endian) uint version = BitConverter.ToUInt32(blockData, 0); Console.WriteLine($"Version: {version}"); - // 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})"); - // 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}"); } 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 0880e7d..ca9447e 100644 --- a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj +++ b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj @@ -9,7 +9,7 @@ - <_Parameter1>BitcoinKernel.Core + <_Parameter1>BitcoinKernel diff --git a/src/BitcoinKernel.Core/Abstractions/Block.cs b/src/BitcoinKernel/Abstractions/Block.cs similarity index 98% rename from src/BitcoinKernel.Core/Abstractions/Block.cs rename to src/BitcoinKernel/Abstractions/Block.cs index 993f7ed..37d22e8 100644 --- a/src/BitcoinKernel.Core/Abstractions/Block.cs +++ b/src/BitcoinKernel/Abstractions/Block.cs @@ -1,8 +1,8 @@ -using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; /// /// Represents a block in the blockchain. diff --git a/src/BitcoinKernel.Core/Abstractions/BlockHash.cs b/src/BitcoinKernel/Abstractions/BlockHash.cs similarity index 95% rename from src/BitcoinKernel.Core/Abstractions/BlockHash.cs rename to src/BitcoinKernel/Abstractions/BlockHash.cs index 9fce4cf..ae41752 100644 --- a/src/BitcoinKernel.Core/Abstractions/BlockHash.cs +++ b/src/BitcoinKernel/Abstractions/BlockHash.cs @@ -1,7 +1,7 @@ -using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; /// /// Represents a block hash. /// diff --git a/src/BitcoinKernel.Core/Abstractions/BlockHeader.cs b/src/BitcoinKernel/Abstractions/BlockHeader.cs similarity index 97% rename from src/BitcoinKernel.Core/Abstractions/BlockHeader.cs rename to src/BitcoinKernel/Abstractions/BlockHeader.cs index 5abdc7c..4b0df10 100644 --- a/src/BitcoinKernel.Core/Abstractions/BlockHeader.cs +++ b/src/BitcoinKernel/Abstractions/BlockHeader.cs @@ -1,7 +1,7 @@ -using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; /// /// Represents a block header containing metadata about a block. diff --git a/src/BitcoinKernel.Core/Abstractions/BlockIndex.cs b/src/BitcoinKernel/Abstractions/BlockIndex.cs similarity index 97% rename from src/BitcoinKernel.Core/Abstractions/BlockIndex.cs rename to src/BitcoinKernel/Abstractions/BlockIndex.cs index a0cdd1c..981889e 100644 --- a/src/BitcoinKernel.Core/Abstractions/BlockIndex.cs +++ b/src/BitcoinKernel/Abstractions/BlockIndex.cs @@ -1,6 +1,6 @@ using BitcoinKernel.Interop; -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; /// /// Represents a block index entry in the block tree. diff --git a/src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs b/src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs similarity index 98% rename from src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs rename to src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs index 532cd74..9505f75 100644 --- a/src/BitcoinKernel.Core/Abstractions/BlockSpentOutputs.cs +++ b/src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Core.Abstractions +namespace BitcoinKernel.Abstractions { using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs b/src/BitcoinKernel/Abstractions/BlockValidationState.cs similarity index 96% rename from src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs rename to src/BitcoinKernel/Abstractions/BlockValidationState.cs index 240a4a4..412d12b 100644 --- a/src/BitcoinKernel.Core/Abstractions/BlockValidationState.cs +++ b/src/BitcoinKernel/Abstractions/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.Abstractions; /// /// Represents the validation state of a block. diff --git a/src/BitcoinKernel.Core/Abstractions/Chain.cs b/src/BitcoinKernel/Abstractions/Chain.cs similarity index 96% rename from src/BitcoinKernel.Core/Abstractions/Chain.cs rename to src/BitcoinKernel/Abstractions/Chain.cs index ce10e3a..0fa8cad 100644 --- a/src/BitcoinKernel.Core/Abstractions/Chain.cs +++ b/src/BitcoinKernel/Abstractions/Chain.cs @@ -1,10 +1,10 @@ using System.Dynamic; -using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; /// diff --git a/src/BitcoinKernel.Core/Abstractions/Coin.cs b/src/BitcoinKernel/Abstractions/Coin.cs similarity index 98% rename from src/BitcoinKernel.Core/Abstractions/Coin.cs rename to src/BitcoinKernel/Abstractions/Coin.cs index 17266b6..e79fdf6 100644 --- a/src/BitcoinKernel.Core/Abstractions/Coin.cs +++ b/src/BitcoinKernel/Abstractions/Coin.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Core.Abstractions +namespace BitcoinKernel.Abstractions { using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs b/src/BitcoinKernel/Abstractions/ScriptPubKey.cs similarity index 96% rename from src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs rename to src/BitcoinKernel/Abstractions/ScriptPubKey.cs index 4c4093f..cc90e88 100644 --- a/src/BitcoinKernel.Core/Abstractions/ScriptPubKey.cs +++ b/src/BitcoinKernel/Abstractions/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.Abstractions; /// A single script pubkey containing spending conditions for a transaction output. /// diff --git a/src/BitcoinKernel.Core/Abstractions/Transaction.cs b/src/BitcoinKernel/Abstractions/Transaction.cs similarity index 98% rename from src/BitcoinKernel.Core/Abstractions/Transaction.cs rename to src/BitcoinKernel/Abstractions/Transaction.cs index ffe3702..288817d 100644 --- a/src/BitcoinKernel.Core/Abstractions/Transaction.cs +++ b/src/BitcoinKernel/Abstractions/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.Abstractions; /// /// Managed wrapper for Bitcoin transactions with automatic memory management. diff --git a/src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs b/src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs similarity index 98% rename from src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs rename to src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs index 3e1109d..190d398 100644 --- a/src/BitcoinKernel.Core/Abstractions/TransactionSpentOutputs.cs +++ b/src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Core.Abstractions; +namespace BitcoinKernel.Abstractions; using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel.Core/Abstractions/TxOut.cs b/src/BitcoinKernel/Abstractions/TxOut.cs similarity index 97% rename from src/BitcoinKernel.Core/Abstractions/TxOut.cs rename to src/BitcoinKernel/Abstractions/TxOut.cs index 1bb6923..9a8bd4d 100644 --- a/src/BitcoinKernel.Core/Abstractions/TxOut.cs +++ b/src/BitcoinKernel/Abstractions/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.Abstractions; /// /// Represents a transaction output (TxOut) in a Bitcoin transaction. diff --git a/src/BitcoinKernel/BitcoinKernel.csproj b/src/BitcoinKernel/BitcoinKernel.csproj index 985896a..823221c 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 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..695781a 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.Abstractions; +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..5b01bad 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.Abstractions; +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/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..1603d10 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.Abstractions; -namespace BitcoinKernel.Core.Chain; +namespace BitcoinKernel.Chain; /// /// Manages the blockchain state and validation operations. 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 100% rename from src/BitcoinKernel.Core/LoggingConnection.cs rename to src/BitcoinKernel/LoggingConnection.cs 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..3cb6f65 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.Abstractions; +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..4b5cefd 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.Abstractions; -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.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..c1edb06 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.Abstractions; +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.Core.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs similarity index 99% rename from tests/BitcoinKernel.Core.Tests/BlockProcessingTests.cs rename to tests/BitcoinKernel.Tests/BlockProcessingTests.cs index 843157d..4881267 100644 --- a/tests/BitcoinKernel.Core.Tests/BlockProcessingTests.cs +++ b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs @@ -1,9 +1,9 @@ -using BitcoinKernel.Core.Chain; -using BitcoinKernel.Core.Exceptions; +using BitcoinKernel.Chain; +using BitcoinKernel.Exceptions; using BitcoinKernel.Interop.Enums; using Xunit; -namespace BitcoinKernel.Core.Tests +namespace BitcoinKernel.Tests { public class BlockProcessingTests : IDisposable { diff --git a/tests/BitcoinKernel.Core.Tests/BlockTests.cs b/tests/BitcoinKernel.Tests/BlockTests.cs similarity index 97% rename from tests/BitcoinKernel.Core.Tests/BlockTests.cs rename to tests/BitcoinKernel.Tests/BlockTests.cs index 0188108..5ed352c 100644 --- a/tests/BitcoinKernel.Core.Tests/BlockTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTests.cs @@ -1,7 +1,7 @@ -using BitcoinKernel.Core.Abstractions; +using BitcoinKernel.Abstractions; using Xunit; -namespace BitcoinKernel.Core.Tests +namespace BitcoinKernel.Tests { public class BlockTests { diff --git a/tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs similarity index 97% rename from tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs rename to tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs index 729f7c2..6c8ebce 100644 --- a/tests/BitcoinKernel.Core.Tests/BlockTreeEntryTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs @@ -1,9 +1,9 @@ -using BitcoinKernel.Core.BlockProcessing; -using BitcoinKernel.Core.Chain; +using BitcoinKernel.BlockProcessing; +using BitcoinKernel.Chain; using BitcoinKernel.Interop.Enums; -namespace BitcoinKernel.Core.Tests; +namespace BitcoinKernel.Tests; public class BlockTreeEntryTests : IDisposable { 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..d7ce45c 100644 --- a/tests/BitcoinKernel.Core.Tests/BlockValidationStateTests.cs +++ b/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs @@ -1,8 +1,8 @@ -using BitcoinKernel.Core.Abstractions; +using BitcoinKernel.Abstractions; 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..19cafa4 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.Abstractions; +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..0d4457a 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.Abstractions; +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 @@ - + From 436fe9ac3e8ec53ff46218a5e0660ddd5d201d85 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:16:58 +0100 Subject: [PATCH 3/8] refactor: move Chain class into BitcoinKernel.Chain namespace Eliminates the latent name collision between the Chain class (previously in BitcoinKernel.Abstractions) and the BitcoinKernel.Chain namespace. Users can now access Chain via a single import. --- .../{Abstractions => Chain}/Chain.cs | 186 +++++++++--------- src/BitcoinKernel/Chain/ChainStateManager.cs | 4 +- .../Handlers/MethodDispatcher.cs | 8 +- 3 files changed, 99 insertions(+), 99 deletions(-) rename src/BitcoinKernel/{Abstractions => Chain}/Chain.cs (93%) diff --git a/src/BitcoinKernel/Abstractions/Chain.cs b/src/BitcoinKernel/Chain/Chain.cs similarity index 93% rename from src/BitcoinKernel/Abstractions/Chain.cs rename to src/BitcoinKernel/Chain/Chain.cs index 0fa8cad..5b9eba7 100644 --- a/src/BitcoinKernel/Abstractions/Chain.cs +++ b/src/BitcoinKernel/Chain/Chain.cs @@ -1,93 +1,93 @@ - - -using System.Dynamic; -using BitcoinKernel.Exceptions; -using BitcoinKernel.Interop; - -namespace BitcoinKernel.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.Abstractions; +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/Chain/ChainStateManager.cs b/src/BitcoinKernel/Chain/ChainStateManager.cs index 1603d10..0e56e09 100644 --- a/src/BitcoinKernel/Chain/ChainStateManager.cs +++ b/src/BitcoinKernel/Chain/ChainStateManager.cs @@ -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/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs index 0d4457a..6d170c4 100644 --- a/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs +++ b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs @@ -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); } From e40be836d86adf78b952f7c746093266f81832d4 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:18:37 +0100 Subject: [PATCH 4/8] refactor: add namespace to LoggingConnection.cs --- src/BitcoinKernel/LoggingConnection.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BitcoinKernel/LoggingConnection.cs b/src/BitcoinKernel/LoggingConnection.cs index 280c263..309e92c 100644 --- a/src/BitcoinKernel/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; From 28bcd74e69c96ed6f988b15a09ba1d8bd678cb47 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:35:54 +0100 Subject: [PATCH 5/8] refactor: rename Abstractions namespace to Primatives --- examples/BlockProcessing/Program.cs | 2 +- .../BlockProcessing/BlockProcessor.cs | 2 +- .../BlockProcessing/BlockTreeEntry.cs | 2 +- src/BitcoinKernel/Chain/Chain.cs | 2 +- src/BitcoinKernel/Chain/ChainStateManager.cs | 2 +- .../{Abstractions => Primatives}/Block.cs | 2 +- .../{Abstractions => Primatives}/BlockHash.cs | 2 +- .../{Abstractions => Primatives}/BlockHeader.cs | 2 +- .../{Abstractions => Primatives}/BlockIndex.cs | 2 +- .../BlockSpentOutputs.cs | 2 +- .../BlockValidationState.cs | 2 +- .../{Abstractions => Primatives}/Coin.cs | 2 +- .../{Abstractions => Primatives}/ScriptPubKey.cs | 2 +- .../{Abstractions => Primatives}/Transaction.cs | 2 +- .../TransactionSpentOutputs.cs | 2 +- .../{Abstractions => Primatives}/TxOut.cs | 2 +- .../PrecomputedTransactionData.cs | 2 +- .../ScriptVerification/ScriptVerifier.cs | 2 +- tests/BitcoinKernel.Tests/BlockHeaderTests.cs | 2 +- tests/BitcoinKernel.Tests/BlockProcessingTests.cs | 15 ++++++++------- tests/BitcoinKernel.Tests/BlockTests.cs | 2 +- tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs | 3 ++- .../BlockValidationStateTests.cs | 2 +- .../ScriptVerificationTests.cs | 2 +- .../Handlers/MethodDispatcher.cs | 2 +- 25 files changed, 33 insertions(+), 31 deletions(-) rename src/BitcoinKernel/{Abstractions => Primatives}/Block.cs (99%) rename src/BitcoinKernel/{Abstractions => Primatives}/BlockHash.cs (97%) rename src/BitcoinKernel/{Abstractions => Primatives}/BlockHeader.cs (99%) rename src/BitcoinKernel/{Abstractions => Primatives}/BlockIndex.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/BlockSpentOutputs.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/BlockValidationState.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/Coin.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/ScriptPubKey.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/Transaction.cs (99%) rename src/BitcoinKernel/{Abstractions => Primatives}/TransactionSpentOutputs.cs (98%) rename src/BitcoinKernel/{Abstractions => Primatives}/TxOut.cs (98%) diff --git a/examples/BlockProcessing/Program.cs b/examples/BlockProcessing/Program.cs index e9b0b1e..ee15a39 100644 --- a/examples/BlockProcessing/Program.cs +++ b/examples/BlockProcessing/Program.cs @@ -1,6 +1,6 @@ using System.IO; using BitcoinKernel; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Chain; using BitcoinKernel.Interop.Enums; diff --git a/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs b/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs index 695781a..98fbf25 100644 --- a/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs +++ b/src/BitcoinKernel/BlockProcessing/BlockProcessor.cs @@ -1,5 +1,5 @@ using System; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Chain; using BitcoinKernel.Exceptions; diff --git a/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs b/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs index 5b01bad..30a8c58 100644 --- a/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs +++ b/src/BitcoinKernel/BlockProcessing/BlockTreeEntry.cs @@ -1,4 +1,4 @@ -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; diff --git a/src/BitcoinKernel/Chain/Chain.cs b/src/BitcoinKernel/Chain/Chain.cs index 5b9eba7..271c168 100644 --- a/src/BitcoinKernel/Chain/Chain.cs +++ b/src/BitcoinKernel/Chain/Chain.cs @@ -1,6 +1,6 @@ -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; diff --git a/src/BitcoinKernel/Chain/ChainStateManager.cs b/src/BitcoinKernel/Chain/ChainStateManager.cs index 0e56e09..f44e048 100644 --- a/src/BitcoinKernel/Chain/ChainStateManager.cs +++ b/src/BitcoinKernel/Chain/ChainStateManager.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; namespace BitcoinKernel.Chain; diff --git a/src/BitcoinKernel/Abstractions/Block.cs b/src/BitcoinKernel/Primatives/Block.cs similarity index 99% rename from src/BitcoinKernel/Abstractions/Block.cs rename to src/BitcoinKernel/Primatives/Block.cs index 37d22e8..69d3a8d 100644 --- a/src/BitcoinKernel/Abstractions/Block.cs +++ b/src/BitcoinKernel/Primatives/Block.cs @@ -2,7 +2,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents a block in the blockchain. diff --git a/src/BitcoinKernel/Abstractions/BlockHash.cs b/src/BitcoinKernel/Primatives/BlockHash.cs similarity index 97% rename from src/BitcoinKernel/Abstractions/BlockHash.cs rename to src/BitcoinKernel/Primatives/BlockHash.cs index ae41752..b322e54 100644 --- a/src/BitcoinKernel/Abstractions/BlockHash.cs +++ b/src/BitcoinKernel/Primatives/BlockHash.cs @@ -1,7 +1,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents a block hash. /// diff --git a/src/BitcoinKernel/Abstractions/BlockHeader.cs b/src/BitcoinKernel/Primatives/BlockHeader.cs similarity index 99% rename from src/BitcoinKernel/Abstractions/BlockHeader.cs rename to src/BitcoinKernel/Primatives/BlockHeader.cs index 4b0df10..d9acf18 100644 --- a/src/BitcoinKernel/Abstractions/BlockHeader.cs +++ b/src/BitcoinKernel/Primatives/BlockHeader.cs @@ -1,7 +1,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents a block header containing metadata about a block. diff --git a/src/BitcoinKernel/Abstractions/BlockIndex.cs b/src/BitcoinKernel/Primatives/BlockIndex.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/BlockIndex.cs rename to src/BitcoinKernel/Primatives/BlockIndex.cs index 981889e..d12fcd8 100644 --- a/src/BitcoinKernel/Abstractions/BlockIndex.cs +++ b/src/BitcoinKernel/Primatives/BlockIndex.cs @@ -1,6 +1,6 @@ using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents a block index entry in the block tree. diff --git a/src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs rename to src/BitcoinKernel/Primatives/BlockSpentOutputs.cs index 9505f75..69d712e 100644 --- a/src/BitcoinKernel/Abstractions/BlockSpentOutputs.cs +++ b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Abstractions +namespace BitcoinKernel.Primatives { using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel/Abstractions/BlockValidationState.cs b/src/BitcoinKernel/Primatives/BlockValidationState.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/BlockValidationState.cs rename to src/BitcoinKernel/Primatives/BlockValidationState.cs index 412d12b..8c04870 100644 --- a/src/BitcoinKernel/Abstractions/BlockValidationState.cs +++ b/src/BitcoinKernel/Primatives/BlockValidationState.cs @@ -2,7 +2,7 @@ using BitcoinKernel.Interop; using BitcoinKernel.Interop.Enums; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents the validation state of a block. diff --git a/src/BitcoinKernel/Abstractions/Coin.cs b/src/BitcoinKernel/Primatives/Coin.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/Coin.cs rename to src/BitcoinKernel/Primatives/Coin.cs index e79fdf6..e341455 100644 --- a/src/BitcoinKernel/Abstractions/Coin.cs +++ b/src/BitcoinKernel/Primatives/Coin.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Abstractions +namespace BitcoinKernel.Primatives { using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel/Abstractions/ScriptPubKey.cs b/src/BitcoinKernel/Primatives/ScriptPubKey.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/ScriptPubKey.cs rename to src/BitcoinKernel/Primatives/ScriptPubKey.cs index cc90e88..f1bd5ad 100644 --- a/src/BitcoinKernel/Abstractions/ScriptPubKey.cs +++ b/src/BitcoinKernel/Primatives/ScriptPubKey.cs @@ -2,7 +2,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// A single script pubkey containing spending conditions for a transaction output. /// diff --git a/src/BitcoinKernel/Abstractions/Transaction.cs b/src/BitcoinKernel/Primatives/Transaction.cs similarity index 99% rename from src/BitcoinKernel/Abstractions/Transaction.cs rename to src/BitcoinKernel/Primatives/Transaction.cs index 288817d..3bc4247 100644 --- a/src/BitcoinKernel/Abstractions/Transaction.cs +++ b/src/BitcoinKernel/Primatives/Transaction.cs @@ -3,7 +3,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Managed wrapper for Bitcoin transactions with automatic memory management. diff --git a/src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs b/src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs rename to src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs index 190d398..c8836c0 100644 --- a/src/BitcoinKernel/Abstractions/TransactionSpentOutputs.cs +++ b/src/BitcoinKernel/Primatives/TransactionSpentOutputs.cs @@ -1,4 +1,4 @@ -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; using BitcoinKernel.Interop; using System; diff --git a/src/BitcoinKernel/Abstractions/TxOut.cs b/src/BitcoinKernel/Primatives/TxOut.cs similarity index 98% rename from src/BitcoinKernel/Abstractions/TxOut.cs rename to src/BitcoinKernel/Primatives/TxOut.cs index 9a8bd4d..5bfac9d 100644 --- a/src/BitcoinKernel/Abstractions/TxOut.cs +++ b/src/BitcoinKernel/Primatives/TxOut.cs @@ -3,7 +3,7 @@ using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; -namespace BitcoinKernel.Abstractions; +namespace BitcoinKernel.Primatives; /// /// Represents a transaction output (TxOut) in a Bitcoin transaction. diff --git a/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs b/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs index 3cb6f65..75b0839 100644 --- a/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs +++ b/src/BitcoinKernel/ScriptVerification/PrecomputedTransactionData.cs @@ -1,4 +1,4 @@ -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Exceptions; using BitcoinKernel.Interop; diff --git a/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs b/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs index 4b5cefd..fbc6d64 100644 --- a/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs +++ b/src/BitcoinKernel/ScriptVerification/ScriptVerifier.cs @@ -5,7 +5,7 @@ using BitcoinKernel.Interop; using BitcoinKernel.Interop.Enums; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; namespace BitcoinKernel.ScriptVerification; diff --git a/tests/BitcoinKernel.Tests/BlockHeaderTests.cs b/tests/BitcoinKernel.Tests/BlockHeaderTests.cs index c1edb06..9b0563a 100644 --- a/tests/BitcoinKernel.Tests/BlockHeaderTests.cs +++ b/tests/BitcoinKernel.Tests/BlockHeaderTests.cs @@ -1,5 +1,5 @@ using BitcoinKernel; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.BlockProcessing; using BitcoinKernel.Chain; using BitcoinKernel.Exceptions; diff --git a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs index 4881267..80bb31b 100644 --- a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs +++ b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs @@ -1,6 +1,7 @@ using BitcoinKernel.Chain; using BitcoinKernel.Exceptions; using BitcoinKernel.Interop.Enums; +using BitcoinKernel.Primatives; using Xunit; namespace BitcoinKernel.Tests @@ -65,7 +66,7 @@ private void ProcessBlockData(ChainstateManager chainstateManager, List { foreach (var rawBlock in blockData) { - using var block = Abstractions.Block.FromBytes(rawBlock); + using var block = Block.FromBytes(rawBlock); chainstateManager.ProcessBlock(block); } } @@ -96,7 +97,7 @@ public void TestProcessData() // Act & Assert foreach (var rawBlock in blockData) { - using var block = Abstractions.Block.FromBytes(rawBlock); + using var block = Block.FromBytes(rawBlock); var result = chainstateManager.ProcessBlock(block); // Assert the block was processed successfully (is new) @@ -117,7 +118,7 @@ public void TestValidateAny() // Act & Assert chainstateManager.ImportBlocks(); - using var block2 = Abstractions.Block.FromBytes(blockData[1]); + using var block2 = Block.FromBytes(blockData[1]); // The block should be invalid and processing should fail var exception = Assert.Throws(() => @@ -142,7 +143,7 @@ public void TestReindex() foreach (var rawBlock in blockData) { - using var block = Abstractions.Block.FromBytes(rawBlock); + using var block = Block.FromBytes(rawBlock); var result = chainstateManager.ProcessBlock(block); Assert.True(result, "Block should be new and processed successfully"); } @@ -176,7 +177,7 @@ public void TestInvalidBlock() // Not a block var invalidBlockData = Convert.FromHexString("deadbeef"); - Assert.Throws(() => Abstractions.Block.FromBytes(invalidBlockData)); + Assert.Throws(() => Block.FromBytes(invalidBlockData)); // Invalid block var invalidBlockHex = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd" + @@ -186,7 +187,7 @@ public void TestInvalidBlock() "1600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf62" + "1e73a82cbf2342c858eeac00000000"; - using var block = Abstractions.Block.FromBytes(Convert.FromHexString(invalidBlockHex)); + using var block = Block.FromBytes(Convert.FromHexString(invalidBlockHex)); // The block should be invalid and processing should fail var exception = Assert.Throws(() => @@ -477,7 +478,7 @@ public void TestIteratorWithBlockTransactions() 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 block = Block.FromBytes(blockData[1]); using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex); // Zip block transactions (skipping coinbase) with spent outputs diff --git a/tests/BitcoinKernel.Tests/BlockTests.cs b/tests/BitcoinKernel.Tests/BlockTests.cs index 5ed352c..ca73177 100644 --- a/tests/BitcoinKernel.Tests/BlockTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTests.cs @@ -1,4 +1,4 @@ -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using Xunit; namespace BitcoinKernel.Tests diff --git a/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs index 6c8ebce..b9a3e62 100644 --- a/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTreeEntryTests.cs @@ -1,6 +1,7 @@ using BitcoinKernel.BlockProcessing; using BitcoinKernel.Chain; using BitcoinKernel.Interop.Enums; +using BitcoinKernel.Primatives; namespace BitcoinKernel.Tests; @@ -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.Tests/BlockValidationStateTests.cs b/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs index d7ce45c..66c15aa 100644 --- a/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs +++ b/tests/BitcoinKernel.Tests/BlockValidationStateTests.cs @@ -1,4 +1,4 @@ -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Interop.Enums; using Xunit; diff --git a/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs b/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs index 19cafa4..b9c9828 100644 --- a/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs +++ b/tests/BitcoinKernel.Tests/ScriptVerificationTests.cs @@ -1,6 +1,6 @@ using System; using BitcoinKernel.ScriptVerification; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Exceptions; using BitcoinKernel.Chain; using BitcoinKernel.Interop.Enums; diff --git a/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs index 6d170c4..41cce44 100644 --- a/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs +++ b/tools/kernel-bindings-test-handler/Handlers/MethodDispatcher.cs @@ -1,5 +1,5 @@ using BitcoinKernel; -using BitcoinKernel.Abstractions; +using BitcoinKernel.Primatives; using BitcoinKernel.Chain; using BitcoinKernel.Exceptions; using BitcoinKernel.ScriptVerification; From b7076ebdb66d22d6da2cf0e5daea45f8463f8ff9 Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:46:41 +0100 Subject: [PATCH 6/8] refactor: Use consistent file-scoped namespaces --- examples/BasicUsage/Program.cs | 127 +- examples/BlockProcessing/Program.cs | 188 +- src/BitcoinKernel.Interop/Enums/ChainType.cs | 18 +- .../Enums/LogCategory.cs | 118 +- .../Enums/ScriptVerificationFlags.cs | 112 +- .../Enums/ScriptVerifyStatus.cs | 58 +- src/BitcoinKernel.Interop/Enums/Warning.cs | 12 +- src/BitcoinKernel.Interop/NativeMethods.cs | 1780 ++++++++--------- .../Structs/LoggingOptions.cs | 20 +- .../Structs/NotificationInterfaceCallbacks.cs | 26 +- .../Structs/ValidationInterfaceCallbacks.cs | 20 +- .../Primatives/BlockSpentOutputs.cs | 175 +- src/BitcoinKernel/Primatives/Coin.cs | 181 +- .../BlockProcessingTests.cs | 774 ++++--- tests/BitcoinKernel.Tests/BlockTests.cs | 102 +- 15 files changed, 1842 insertions(+), 1869 deletions(-) diff --git a/examples/BasicUsage/Program.cs b/examples/BasicUsage/Program.cs index 69c6b11..d7c21db 100644 --- a/examples/BasicUsage/Program.cs +++ b/examples/BasicUsage/Program.cs @@ -1,64 +1,63 @@ -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(" Chain queries working"); - } - catch (Exception ex) - { - Console.WriteLine($" Error: {ex.Message}"); - } - - Console.WriteLine("\nPress any key to exit..."); - Console.ReadKey(); - } - } -} +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(" 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 ee15a39..e212e40 100644 --- a/examples/BlockProcessing/Program.cs +++ b/examples/BlockProcessing/Program.cs @@ -4,133 +4,131 @@ 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("====================================="); + Console.WriteLine("Bitcoin Kernel Block Processing Example"); + Console.WriteLine("====================================="); - var dataDir = Path.Combine(Path.GetTempPath(), $"bitcoinkernel_{Guid.NewGuid()}"); - var blocksDir = Path.Combine(dataDir, "blocks"); + var dataDir = Path.Combine(Path.GetTempPath(), $"bitcoinkernel_{Guid.NewGuid()}"); + var blocksDir = Path.Combine(dataDir, "blocks"); - try + try + { + using var logging = new LoggingConnection((category, message, level) => { - using var logging = new LoggingConnection((category, message, level) => - { - if (level <= 2) - Console.WriteLine($"[{category}] {message}"); - }); + 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); + 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"); + Console.WriteLine("Created kernel for mainnet"); + Console.WriteLine("Chainstate initialized"); - 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."); - return; - } + 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."); + return; + } - DisplayBlockInfo(sampleBlockData); + DisplayBlockInfo(sampleBlockData); - Console.WriteLine("\nProcessing block..."); - try + Console.WriteLine("\nProcessing block..."); + try + { + using var block = Block.FromBytes(sampleBlockData); + bool isNew = chainstate.ProcessBlock(block); + + if (isNew) { - using var block = Block.FromBytes(sampleBlockData); - bool isNew = chainstate.ProcessBlock(block); - - if (isNew) - { - var activeChain = chainstate.GetActiveChain(); - Console.WriteLine($"Block processed! Chain height: {activeChain.Height}"); - var tip = activeChain.GetTip(); - Console.WriteLine($" - Tip: {BitConverter.ToString(tip.GetBlockHash()).Replace("-", "")}"); - } - else - { - Console.WriteLine("Block processing failed - 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("\nBlock processing example completed!"); } catch (Exception ex) { - Console.WriteLine($"Error: {ex.Message}"); - if (ex.InnerException != null) - Console.WriteLine($"Inner exception: {ex.InnerException.Message}"); + 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) { - byte[] blockData = new byte[80]; + Console.WriteLine($"Error: {ex.Message}"); + if (ex.InnerException != null) + Console.WriteLine($"Inner exception: {ex.InnerException.Message}"); + } + } - // Version: 1 (little endian) - BitConverter.GetBytes(1).CopyTo(blockData, 0); + private static byte[] CreateSampleBlock() + { + byte[] blockData = new byte[80]; - // Previous block hash: all zeros (indices 4-35) - // Merkle root: all zeros (indices 36-67) + // Version: 1 (little endian) + BitConverter.GetBytes(1).CopyTo(blockData, 0); - // Timestamp: current Unix timestamp - uint timestamp = (uint)(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); - BitConverter.GetBytes(timestamp).CopyTo(blockData, 68); + // Previous block hash: all zeros (indices 4-35) + // Merkle root: all zeros (indices 36-67) - // Bits: 0x1d00ffff (Bitcoin mainnet difficulty) - BitConverter.GetBytes(0x1d00ffffu).CopyTo(blockData, 72); + // Timestamp: current Unix timestamp + uint timestamp = (uint)(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); + BitConverter.GetBytes(timestamp).CopyTo(blockData, 68); - // Nonce: 0 (indices 76-79) + // Bits: 0x1d00ffff (Bitcoin mainnet difficulty) + BitConverter.GetBytes(0x1d00ffffu).CopyTo(blockData, 72); - return blockData; - } + // Nonce: 0 (indices 76-79) - private static void DisplayBlockInfo(byte[] blockData) - { - Console.WriteLine("\nBlock Information:"); - Console.WriteLine("-----------------"); + return blockData; + } - try - { - Console.WriteLine($"Block Size: {blockData.Length} bytes"); - Console.WriteLine($"Block Data (first 32 bytes): {BitConverter.ToString(blockData.Take(32).ToArray()).Replace("-", " ")}"); + private static void DisplayBlockInfo(byte[] blockData) + { + Console.WriteLine("\nBlock Information:"); + Console.WriteLine("-----------------"); - uint version = BitConverter.ToUInt32(blockData, 0); - Console.WriteLine($"Version: {version}"); + try + { + Console.WriteLine($"Block Size: {blockData.Length} bytes"); + Console.WriteLine($"Block Data (first 32 bytes): {BitConverter.ToString(blockData.Take(32).ToArray()).Replace("-", " ")}"); - 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 version = BitConverter.ToUInt32(blockData, 0); + Console.WriteLine($"Version: {version}"); - uint bits = BitConverter.ToUInt32(blockData, 72); - Console.WriteLine($"Bits: 0x{bits:X8}"); + 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 nonce = BitConverter.ToUInt32(blockData, 76); - Console.WriteLine($"Nonce: {nonce}"); - } - catch (Exception ex) - { - Console.WriteLine($"Error parsing block info: {ex.Message}"); - } + uint bits = BitConverter.ToUInt32(blockData, 72); + Console.WriteLine($"Bits: 0x{bits:X8}"); + + 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.Interop/Enums/ChainType.cs b/src/BitcoinKernel.Interop/Enums/ChainType.cs index 80e0993..7f1f8f9 100644 --- a/src/BitcoinKernel.Interop/Enums/ChainType.cs +++ b/src/BitcoinKernel.Interop/Enums/ChainType.cs @@ -1,11 +1,9 @@ -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..a62212b 100644 --- a/src/BitcoinKernel.Interop/Enums/Warning.cs +++ b/src/BitcoinKernel.Interop/Enums/Warning.cs @@ -1,8 +1,6 @@ -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 ec9a79d..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. /// - 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 - - /// - /// 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 0dd46ae..902751a 100644 --- a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs +++ b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs @@ -1,14 +1,12 @@ using System.Runtime.InteropServices; -namespace BitcoinKernel.Interop.Structs +namespace BitcoinKernel.Interop.Structs; +[StructLayout(LayoutKind.Sequential)] +internal struct LoggingOptions { - [StructLayout(LayoutKind.Sequential)] - internal 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 b899ac8..6421fc8 100644 --- a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs @@ -1,18 +1,16 @@ 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)] - internal 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 aad75b0..807b755 100644 --- a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs @@ -1,15 +1,13 @@ 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)] - internal 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/Primatives/BlockSpentOutputs.cs b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs index 69d712e..96d4535 100644 --- a/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs +++ b/src/BitcoinKernel/Primatives/BlockSpentOutputs.cs @@ -1,121 +1,120 @@ -namespace BitcoinKernel.Primatives +using System; +using BitcoinKernel.Interop; + +namespace BitcoinKernel.Primatives; + +/// +/// Represents the spent outputs for all transactions in a block. +/// +public class BlockSpentOutputs : IDisposable { - using BitcoinKernel.Interop; - using System; + 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; + } /// - /// Represents the spent outputs for all transactions in a block. + /// Gets the number of transactions with spent outputs in this block. + /// This excludes the coinbase transaction. /// - public class BlockSpentOutputs : IDisposable + public int Count { - private IntPtr _handle; - private bool _disposed; - - internal BlockSpentOutputs(IntPtr handle) + get { - if (handle == IntPtr.Zero) - { - throw new ArgumentException("Invalid block spent outputs handle", nameof(handle)); - } - - _handle = handle; + ThrowIfDisposed(); + return (int)NativeMethods.BlockSpentOutputsCount(_handle); } + } - /// - /// Gets the number of transactions with spent outputs in this block. - /// This excludes the coinbase transaction. - /// - public int Count + /// + /// 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) { - get - { - ThrowIfDisposed(); - return (int)NativeMethods.BlockSpentOutputsCount(_handle); - } + throw new ArgumentOutOfRangeException(nameof(transactionIndex)); } - /// - /// 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(); + var txSpentOutputsPtr = NativeMethods.BlockSpentOutputsGetTransactionSpentOutputsAt( + _handle, (nuint)transactionIndex); - if (transactionIndex < 0 || transactionIndex >= Count) - { - throw new ArgumentOutOfRangeException(nameof(transactionIndex)); - } + if (txSpentOutputsPtr == IntPtr.Zero) + { + throw new InvalidOperationException($"Failed to get transaction spent outputs at index {transactionIndex}"); + } - var txSpentOutputsPtr = NativeMethods.BlockSpentOutputsGetTransactionSpentOutputsAt( - _handle, (nuint)transactionIndex); + // Don't own the handle - it's only valid for the lifetime of BlockSpentOutputs + return new TransactionSpentOutputs(txSpentOutputsPtr, ownsHandle: false); + } - if (txSpentOutputsPtr == IntPtr.Zero) - { - throw new InvalidOperationException($"Failed to get transaction spent outputs at index {transactionIndex}"); - } + /// + /// Enumerates all transaction spent outputs in the block. + /// + /// An enumerable of TransactionSpentOutputs for each transaction (excluding coinbase). + public IEnumerable EnumerateTransactionSpentOutputs() + { + ThrowIfDisposed(); - // Don't own the handle - it's only valid for the lifetime of BlockSpentOutputs - return new TransactionSpentOutputs(txSpentOutputsPtr, ownsHandle: false); + int count = Count; + for (int i = 0; i < count; i++) + { + yield return GetTransactionSpentOutputs(i); } + } - /// - /// Enumerates all transaction spent outputs in the block. - /// - /// An enumerable of TransactionSpentOutputs for each transaction (excluding coinbase). - public IEnumerable EnumerateTransactionSpentOutputs() + internal IntPtr Handle + { + get { ThrowIfDisposed(); - - int count = Count; - for (int i = 0; i < count; i++) - { - yield return GetTransactionSpentOutputs(i); - } + return _handle; } + } - internal IntPtr Handle + private void ThrowIfDisposed() + { + if (_disposed) { - get - { - ThrowIfDisposed(); - return _handle; - } + throw new ObjectDisposedException(nameof(BlockSpentOutputs)); } + } - private void ThrowIfDisposed() + protected virtual void Dispose(bool disposing) + { + if (!_disposed) { - if (_disposed) + if (_handle != IntPtr.Zero) { - throw new ObjectDisposedException(nameof(BlockSpentOutputs)); + NativeMethods.BlockSpentOutputsDestroy(_handle); + _handle = IntPtr.Zero; } - } - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (_handle != IntPtr.Zero) - { - NativeMethods.BlockSpentOutputsDestroy(_handle); - _handle = IntPtr.Zero; - } - - _disposed = true; - } + _disposed = true; } + } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - ~BlockSpentOutputs() - { - Dispose(false); - } + ~BlockSpentOutputs() + { + Dispose(false); } } diff --git a/src/BitcoinKernel/Primatives/Coin.cs b/src/BitcoinKernel/Primatives/Coin.cs index e341455..d556c55 100644 --- a/src/BitcoinKernel/Primatives/Coin.cs +++ b/src/BitcoinKernel/Primatives/Coin.cs @@ -1,124 +1,123 @@ -namespace BitcoinKernel.Primatives +using System; +using BitcoinKernel.Interop; + +namespace BitcoinKernel.Primatives; + +/// +/// Represents a coin (unspent transaction output) with confirmation height information. +/// +public class Coin : IDisposable { - using BitcoinKernel.Interop; - using System; + 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; + } /// - /// Represents a coin (unspent transaction output) with confirmation height information. + /// Gets the block height where the transaction that created this coin was included. /// - public class Coin : IDisposable + public uint ConfirmationHeight { - private IntPtr _handle; - private bool _disposed; - private readonly bool _ownsHandle; - - internal Coin(IntPtr handle, bool ownsHandle = true) + get { - if (handle == IntPtr.Zero) - { - throw new ArgumentException("Invalid coin handle", nameof(handle)); - } - - _handle = handle; - _ownsHandle = ownsHandle; + ThrowIfDisposed(); + return NativeMethods.CoinConfirmationHeight(_handle); } + } - /// - /// Gets the block height where the transaction that created this coin was included. - /// - public uint ConfirmationHeight + /// + /// Gets a value indicating whether this coin is from a coinbase transaction. + /// + public bool IsCoinbase + { + get { - get - { - ThrowIfDisposed(); - return NativeMethods.CoinConfirmationHeight(_handle); - } + ThrowIfDisposed(); + return NativeMethods.CoinIsCoinbase(_handle) != 0; } + } - /// - /// Gets a value indicating whether this coin is from a coinbase transaction. - /// - public bool IsCoinbase + /// + /// 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) { - get - { - ThrowIfDisposed(); - return NativeMethods.CoinIsCoinbase(_handle) != 0; - } + throw new InvalidOperationException("Failed to get coin output"); } - /// - /// 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); + } - // 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"); } - /// - /// Creates a copy of this coin. - /// - public Coin Copy() + return new Coin(copiedHandle, ownsHandle: true); + } + + internal IntPtr Handle + { + get { ThrowIfDisposed(); - var copiedHandle = NativeMethods.CoinCopy(_handle); - if (copiedHandle == IntPtr.Zero) - { - throw new InvalidOperationException("Failed to copy coin"); - } - - return new Coin(copiedHandle, ownsHandle: true); + return _handle; } + } - internal IntPtr Handle + private void ThrowIfDisposed() + { + if (_disposed) { - get - { - ThrowIfDisposed(); - return _handle; - } + throw new ObjectDisposedException(nameof(Coin)); } + } - private void ThrowIfDisposed() + protected virtual void Dispose(bool disposing) + { + if (!_disposed) { - if (_disposed) + if (_ownsHandle && _handle != IntPtr.Zero) { - throw new ObjectDisposedException(nameof(Coin)); + NativeMethods.CoinDestroy(_handle); + _handle = IntPtr.Zero; } - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (_ownsHandle && _handle != IntPtr.Zero) - { - NativeMethods.CoinDestroy(_handle); - _handle = IntPtr.Zero; - } - _disposed = true; - } + _disposed = true; } + } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - ~Coin() - { - Dispose(false); - } + ~Coin() + { + Dispose(false); } } diff --git a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs index 80bb31b..d67b4a1 100644 --- a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs +++ b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs @@ -4,495 +4,493 @@ using BitcoinKernel.Primatives; using Xunit; -namespace BitcoinKernel.Tests +namespace BitcoinKernel.Tests; +public class BlockProcessingTests : IDisposable { - public class BlockProcessingTests : IDisposable + private KernelContext? _context; + private ChainParameters? _chainParams; + private string? _tempDir; + + public void Dispose() { - private KernelContext? _context; - private ChainParameters? _chainParams; - private string? _tempDir; + _chainParams?.Dispose(); + _context?.Dispose(); - public void Dispose() + if (!string.IsNullOrEmpty(_tempDir) && Directory.Exists(_tempDir)) { - _chainParams?.Dispose(); - _context?.Dispose(); - - if (!string.IsNullOrEmpty(_tempDir) && Directory.Exists(_tempDir)) - { - Directory.Delete(_tempDir, true); - } + 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); + 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); + // Create temporary directory + _tempDir = Path.Combine(Path.GetTempPath(), $"test_chainman_regtest_{Guid.NewGuid()}"); + Directory.CreateDirectory(_tempDir); - return (_context, _chainParams, _tempDir); - } + return (_context, _chainParams, _tempDir); + } - private List ReadBlockData() + 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)) { - 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"); + throw new FileNotFoundException($"Block data file not found: {blockDataFile}"); + } - if (!File.Exists(blockDataFile)) + foreach (var line in File.ReadLines(blockDataFile)) + { + if (!string.IsNullOrWhiteSpace(line)) { - throw new FileNotFoundException($"Block data file not found: {blockDataFile}"); + blockData.Add(Convert.FromHexString(line.Trim())); } + } - foreach (var line in File.ReadLines(blockDataFile)) - { - if (!string.IsNullOrWhiteSpace(line)) - { - blockData.Add(Convert.FromHexString(line.Trim())); - } - } + return blockData; + } - return blockData; + private void ProcessBlockData(ChainstateManager chainstateManager, List blockData) + { + foreach (var rawBlock in blockData) + { + using var block = Block.FromBytes(rawBlock); + chainstateManager.ProcessBlock(block); } + } - private void ProcessBlockData(ChainstateManager chainstateManager, List blockData) + 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) { - foreach (var rawBlock in blockData) - { - using var block = Block.FromBytes(rawBlock); - chainstateManager.ProcessBlock(block); - } + 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"); } + } - private (ChainstateManager, List) SetupChainstateManager() - { - var (context, chainParams, dataDir) = TestingSetup(); - var blockData = ReadBlockData(); + [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, Path.Combine(dataDir, "blocks")); - var chainstateManager = new ChainstateManager(context, chainParams, options); + var options = new ChainstateManagerOptions(context, dataDir, blocksDir); + using var chainstateManager = new ChainstateManager(context, chainParams, options); - return (chainstateManager, blockData); - } + // Act & Assert + chainstateManager.ImportBlocks(); + using var block2 = Block.FromBytes(blockData[1]); - [Fact] - public void TestProcessData() - { - // Arrange - var (context, chainParams, dataDir) = TestingSetup(); - var blocksDir = Path.Combine(dataDir, "blocks"); - var blockData = ReadBlockData(); + // 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); - // 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 - Reindex + var reindexOptions = new ChainstateManagerOptions(context, dataDir, blocksDir) + .SetWipeDbs(false, true); + using var chainstateManagerReindex = new ChainstateManager(context, chainParams, reindexOptions); + var result_reindex = chainstateManagerReindex.ImportBlocks(); - // Act & Assert - chainstateManager.ImportBlocks(); - using var block2 = Block.FromBytes(blockData[1]); + Assert.True(result_reindex, "Reindexing should be successful"); - // The block should be invalid and processing should fail - var exception = Assert.Throws(() => - chainstateManager.ProcessBlock(block2)); + // Assert - Verify chainstate is intact after reindex + var activeChain = chainstateManagerReindex.GetActiveChain(); + Assert.Equal(blockData.Count, activeChain.Height); + } - // Verify it's a validation error (non-zero error code) - Assert.Contains("Failed to process block", exception.Message); - } + [Fact] + public void TestInvalidBlock() + { + // Arrange + var (context, chainParams, dataDir) = TestingSetup(); + var blocksDir = Path.Combine(dataDir, "blocks"); - [Fact] - public void TestReindex() + for (int i = 0; i < 10; i++) { - // 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); + 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"); - } - } + // Not a block + var invalidBlockData = Convert.FromHexString("deadbeef"); + Assert.Throws(() => Block.FromBytes(invalidBlockData)); + // Invalid block + var invalidBlockHex = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd" + + "1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299" + + "0101000000010000000000000000000000000000000000000000000000000000000000000000ffff" + + "ffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec1" + + "1600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf62" + + "1e73a82cbf2342c858eeac00000000"; - // 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(); + using var block = Block.FromBytes(Convert.FromHexString(invalidBlockHex)); - Assert.True(result_reindex, "Reindexing should be successful"); + // The block should be invalid and processing should fail + var exception = Assert.Throws(() => + chainstateManager.ProcessBlock(block)); - // Assert - Verify chainstate is intact after reindex - var activeChain = chainstateManagerReindex.GetActiveChain(); - Assert.Equal(blockData.Count, activeChain.Height); + // Verify it's a validation error (non-zero error code) + Assert.Contains("Failed to process block", exception.Message); } + } - [Fact] - public void TestInvalidBlock() - { - // Arrange - var (context, chainParams, dataDir) = TestingSetup(); - var blocksDir = Path.Combine(dataDir, "blocks"); + [Fact] + public void TestScanTransactions() + { + // Arrange - Setup test environment with blocks + var setup = SetupChainstateManager(); + using var chainstateManager = setup.Item1; + var blockData = setup.Item2; - for (int i = 0; i < 10; i++) - { - var options = new ChainstateManagerOptions(context, dataDir, blocksDir); - using var chainstateManager = new ChainstateManager(context, chainParams, options); + // Act - Process all test blocks + ProcessBlockData(chainstateManager, blockData); - // Not a block - var invalidBlockData = Convert.FromHexString("deadbeef"); - Assert.Throws(() => Block.FromBytes(invalidBlockData)); + var activeChain = chainstateManager.GetActiveChain(); - // Invalid block - var invalidBlockHex = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd" + - "1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299" + - "0101000000010000000000000000000000000000000000000000000000000000000000000000ffff" + - "ffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec1" + - "1600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf62" + - "1e73a82cbf2342c858eeac00000000"; + // 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); + } - using var block = Block.FromBytes(Convert.FromHexString(invalidBlockHex)); + // Get the tip and read its spent outputs + var tipBlockIndex = activeChain.GetTip(); + Assert.NotNull(tipBlockIndex); - // The block should be invalid and processing should fail - var exception = Assert.Throws(() => - chainstateManager.ProcessBlock(block)); + using var spentOutputsTip = chainstateManager.ReadSpentOutputs(tipBlockIndex); + Assert.NotNull(spentOutputsTip); - // Verify it's a validation error (non-zero error code) - Assert.Contains("Failed to process block", exception.Message); - } - } + // 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"); - [Fact] - public void TestScanTransactions() + // If we have a previous block, scan its transactions in detail + var previousBlock = tipBlockIndex.GetPrevious(); + if (previousBlock != null) { - // Arrange - Setup test environment with blocks - var setup = SetupChainstateManager(); - using var chainstateManager = setup.Item1; - var blockData = setup.Item2; + using var spentOutputs = chainstateManager.ReadSpentOutputs(previousBlock); + var spentOutputsCount = spentOutputs.Count; - // 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++) + // Scan each transaction's spent outputs + for (int txIndex = 0; txIndex < spentOutputsCount; txIndex++) { - var blockIndex = activeChain.GetBlockByHeight(height); - Assert.NotNull(blockIndex); - Assert.Equal(height, blockIndex.Height); - } + using var txSpentOutputs = spentOutputs.GetTransactionSpentOutputs(txIndex); + var coinsCount = txSpentOutputs.Count; - // Get the tip and read its spent outputs - var tipBlockIndex = activeChain.GetTip(); - Assert.NotNull(tipBlockIndex); + // Verify we can access each coin + for (int coinIndex = 0; coinIndex < coinsCount; coinIndex++) + { + using var coin = txSpentOutputs.GetCoin(coinIndex); - using var spentOutputsTip = chainstateManager.ReadSpentOutputs(tipBlockIndex); - Assert.NotNull(spentOutputsTip); + // Verify coin properties + Assert.True(coin.ConfirmationHeight >= 0, "Confirmation height should be non-negative"); - // 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"); + // We should be able to get the output + using var output = coin.GetOutput(); + Assert.NotNull(output); - // 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; + // 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"); - // 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"); - } + // Verify we can get the amount + var amount = output.Amount; + Assert.True(amount >= 0, "Amount should be non-negative"); } } } + } - [Fact] - public void TestChainOperations() + [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()) { - // 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); + Assert.True(chain.Contains(currentBlockIndex)); + Assert.Equal(count, currentBlockIndex.Height); + 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); + // Verify we iterated through the entire chain + Assert.Equal(tipHeight + 1, count); + } - var activeChain = chainstateManager.GetActiveChain(); - var blockIndexTip = activeChain.GetTip(); - using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip); + [Fact] + public void TestBlockSpentOutputsIterator() + { + // Arrange - Setup test environment with blocks + var setup = SetupChainstateManager(); + using var chainstateManager = setup.Item1; + var blockData = setup.Item2; - // Test count via iterator matches Count property - var countViaIterator = spentOutputs.EnumerateTransactionSpentOutputs().Count(); - Assert.Equal(spentOutputs.Count, countViaIterator); + // Process all test blocks + ProcessBlockData(chainstateManager, blockData); - // Test collecting all transaction spent outputs - var txSpentVec = spentOutputs.EnumerateTransactionSpentOutputs().ToList(); - Assert.Equal(spentOutputs.Count, txSpentVec.Count); + var activeChain = chainstateManager.GetActiveChain(); + var blockIndexTip = activeChain.GetTip(); + using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip); - // 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 count via iterator matches Count property + var countViaIterator = spentOutputs.EnumerateTransactionSpentOutputs().Count(); + Assert.Equal(spentOutputs.Count, countViaIterator); - // Test iterator length tracking - var initialLen = spentOutputs.Count; + // Test collecting all transaction spent outputs + var txSpentVec = spentOutputs.EnumerateTransactionSpentOutputs().ToList(); + Assert.Equal(spentOutputs.Count, txSpentVec.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); - } + // 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++; } - [Fact] - public void TestTransactionSpentOutputsIterator() + // Test iterator length tracking + var initialLen = spentOutputs.Count; + + if (initialLen > 0) { - // Arrange - Setup test environment with blocks - var setup = SetupChainstateManager(); - using var chainstateManager = setup.Item1; - var blockData = setup.Item2; + // After skipping one element, we have initialLen - 1 remaining + var remaining = spentOutputs.EnumerateTransactionSpentOutputs().Skip(1).Count(); + Assert.Equal(initialLen - 1, remaining); + } + } - // Process all test blocks - ProcessBlockData(chainstateManager, blockData); + [Fact] + public void TestTransactionSpentOutputsIterator() + { + // Arrange - Setup test environment with blocks + var setup = SetupChainstateManager(); + using var chainstateManager = setup.Item1; + var blockData = setup.Item2; - var activeChain = chainstateManager.GetActiveChain(); - var blockIndexTip = activeChain.GetTip(); - using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip); + // Process all test blocks + ProcessBlockData(chainstateManager, blockData); - using var txSpent = spentOutputs.GetTransactionSpentOutputs(0); + var activeChain = chainstateManager.GetActiveChain(); + var blockIndexTip = activeChain.GetTip(); + using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndexTip); - // Test count via iterator matches Count property - var countViaIterator = txSpent.EnumerateCoins().Count(); - Assert.Equal(txSpent.Count, countViaIterator); + using var txSpent = spentOutputs.GetTransactionSpentOutputs(0); - // Test collecting all coins - var coins = txSpent.EnumerateCoins().ToList(); - Assert.Equal(txSpent.Count, coins.Count); + // Test count via iterator matches Count property + var countViaIterator = txSpent.EnumerateCoins().Count(); + Assert.Equal(txSpent.Count, countViaIterator); - // 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; + // Test collecting all coins + var coins = txSpent.EnumerateCoins().ToList(); + Assert.Equal(txSpent.Count, coins.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 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 filtering coinbase coins - var coinbaseCoins = txSpent.EnumerateCoins().Where(coin => coin.IsCoinbase).ToList(); + // Test iterator length tracking + var initialLen = txSpent.Count; - foreach (var coin in coinbaseCoins) - { - Assert.True(coin.IsCoinbase); - } + if (initialLen > 0) + { + // After skipping one element, we have initialLen - 1 remaining + var remaining = txSpent.EnumerateCoins().Skip(1).Count(); + Assert.Equal(initialLen - 1, remaining); } - [Fact] - public void TestNestedIteration() + // Test filtering coinbase coins + var coinbaseCoins = txSpent.EnumerateCoins().Where(coin => coin.IsCoinbase).ToList(); + + foreach (var coin in coinbaseCoins) { - // Arrange - Setup test environment with blocks - var setup = SetupChainstateManager(); - using var chainstateManager = setup.Item1; - var blockData = setup.Item2; + Assert.True(coin.IsCoinbase); + } + } - // Process all test blocks - ProcessBlockData(chainstateManager, blockData); + [Fact] + public void TestNestedIteration() + { + // Arrange - Setup test environment with blocks + var setup = SetupChainstateManager(); + using var chainstateManager = setup.Item1; + var blockData = setup.Item2; - var activeChain = chainstateManager.GetActiveChain(); - var blockIndex = activeChain.GetBlockByHeight(1); - Assert.NotNull(blockIndex); + // Process all test blocks + ProcessBlockData(chainstateManager, blockData); - using var spentOutputs = chainstateManager.ReadSpentOutputs(blockIndex); + var activeChain = chainstateManager.GetActiveChain(); + var blockIndex = activeChain.GetBlockByHeight(1); + Assert.NotNull(blockIndex); - // Count total coins by nested iteration - int totalCoins = 0; - foreach (var txSpent in spentOutputs.EnumerateTransactionSpentOutputs()) + 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()) { - foreach (var coin in txSpent.EnumerateCoins()) - { - totalCoins++; - } + 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); + // Calculate expected total using LINQ + int expectedTotal = spentOutputs.EnumerateTransactionSpentOutputs() + .Sum(txSpent => txSpent.Count); - // 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++; - } + Assert.Equal(expectedTotal, totalCoins); + } - // Verify we processed all spent outputs - Assert.Equal(spentOutputs.Count, txIndex); + [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); } -} \ No newline at end of file +} diff --git a/tests/BitcoinKernel.Tests/BlockTests.cs b/tests/BitcoinKernel.Tests/BlockTests.cs index ca73177..a57850c 100644 --- a/tests/BitcoinKernel.Tests/BlockTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTests.cs @@ -1,72 +1,70 @@ using BitcoinKernel.Primatives; using Xunit; -namespace BitcoinKernel.Tests +namespace BitcoinKernel.Tests; +public class BlockTests { - public class BlockTests + private List ReadBlockData() { - 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"); + 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}"); - } + if (!File.Exists(blockDataFile)) + { + throw new FileNotFoundException($"Block data file not found: {blockDataFile}"); + } - foreach (var line in File.ReadLines(blockDataFile)) + foreach (var line in File.ReadLines(blockDataFile)) + { + if (!string.IsNullOrWhiteSpace(line)) { - if (!string.IsNullOrWhiteSpace(line)) - { - blockData.Add(Convert.FromHexString(line.Trim())); - } + blockData.Add(Convert.FromHexString(line.Trim())); } - - return blockData; } - [Fact] - public void TestBlockTransactionsIterator() - { - var blockData = ReadBlockData(); + return blockData; + } - using var block = Block.FromBytes(blockData[5]); + [Fact] + public void TestBlockTransactionsIterator() + { + var blockData = ReadBlockData(); - // Test that iterator count matches transaction count - var txCountViaIterator = block.GetTransactions().Count(); - Assert.Equal(block.TransactionCount, txCountViaIterator); + using var block = Block.FromBytes(blockData[5]); - // Test collecting all transactions - var txs = block.GetTransactions().ToList(); - Assert.Equal(block.TransactionCount, txs.Count); + // Test that iterator count matches transaction count + var txCountViaIterator = block.GetTransactions().Count(); + Assert.Equal(block.TransactionCount, txCountViaIterator); - // 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 collecting all transactions + var txs = block.GetTransactions().ToList(); + Assert.Equal(block.TransactionCount, txs.Count); - // Test iterator length decreases as we consume it - var iter = block.GetTransactions().GetEnumerator(); - var initialLen = block.TransactionCount; + // 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++; + } - // 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 iterator length decreases as we consume it + var iter = block.GetTransactions().GetEnumerator(); + var initialLen = block.TransactionCount; - // Test skipping coinbase transaction - var nonCoinbaseTxs = block.GetTransactions().Skip(1).ToList(); - Assert.Equal(block.TransactionCount - 1, nonCoinbaseTxs.Count); - } + // 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); } } From 3cc348e12a5dba42c6b8e51f05b934ce420b76ec Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 20:47:12 +0100 Subject: [PATCH 7/8] Bumped version and Updated changelog --- CHANGELOG.md | 12 ++++++++++++ README.md | 2 +- src/BitcoinKernel/BitcoinKernel.csproj | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) 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 4fcea9c..637326e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This library uses [libbitcoinkernel](https://github.com/bitcoin/bitcoin/tree/mas | Package | Version | Description | |---------|---------|-------------| -| **BitcoinKernel** | 0.1.2 | Managed wrappers and native bindings | +| **BitcoinKernel** | 0.2.0 | Managed wrappers and native bindings | ```bash dotnet add package BitcoinKernel diff --git a/src/BitcoinKernel/BitcoinKernel.csproj b/src/BitcoinKernel/BitcoinKernel.csproj index 823221c..ee489a7 100644 --- a/src/BitcoinKernel/BitcoinKernel.csproj +++ b/src/BitcoinKernel/BitcoinKernel.csproj @@ -8,7 +8,7 @@ BitcoinKernel - 0.1.2 + 0.2.0 JanB84 .NET bindings and managed wrappers for libbitcoinkernel. Provides direct access to Bitcoin Core consensus and validation logic with automatic memory management. MIT From f6bb439516f19cc62fbe83c7009bdfd2624e63fc Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 3 Mar 2026 21:03:57 +0100 Subject: [PATCH 8/8] formatting fixes --- examples/BlockProcessing/Program.cs | 1 + src/BitcoinKernel.Interop/Enums/ChainType.cs | 1 + src/BitcoinKernel.Interop/Enums/Warning.cs | 1 + src/BitcoinKernel.Interop/Structs/LoggingOptions.cs | 1 + .../Structs/NotificationInterfaceCallbacks.cs | 1 + .../Structs/ValidationInterfaceCallbacks.cs | 1 + tests/BitcoinKernel.Tests/BlockProcessingTests.cs | 1 + tests/BitcoinKernel.Tests/BlockTests.cs | 1 + 8 files changed, 8 insertions(+) diff --git a/examples/BlockProcessing/Program.cs b/examples/BlockProcessing/Program.cs index e212e40..8b48deb 100644 --- a/examples/BlockProcessing/Program.cs +++ b/examples/BlockProcessing/Program.cs @@ -5,6 +5,7 @@ using BitcoinKernel.Interop.Enums; namespace BlockProcessing; + class Program { static void Main(string[] args) diff --git a/src/BitcoinKernel.Interop/Enums/ChainType.cs b/src/BitcoinKernel.Interop/Enums/ChainType.cs index 7f1f8f9..f7e9ea1 100644 --- a/src/BitcoinKernel.Interop/Enums/ChainType.cs +++ b/src/BitcoinKernel.Interop/Enums/ChainType.cs @@ -1,4 +1,5 @@ namespace BitcoinKernel.Interop.Enums; + public enum ChainType : uint { MAINNET = 0, diff --git a/src/BitcoinKernel.Interop/Enums/Warning.cs b/src/BitcoinKernel.Interop/Enums/Warning.cs index a62212b..d59136c 100644 --- a/src/BitcoinKernel.Interop/Enums/Warning.cs +++ b/src/BitcoinKernel.Interop/Enums/Warning.cs @@ -1,4 +1,5 @@ namespace BitcoinKernel.Interop.Enums; + public enum Warning { UnknownNewRulesActivated = 0, diff --git a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs index 902751a..42cc099 100644 --- a/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs +++ b/src/BitcoinKernel.Interop/Structs/LoggingOptions.cs @@ -1,6 +1,7 @@ using System.Runtime.InteropServices; namespace BitcoinKernel.Interop.Structs; + [StructLayout(LayoutKind.Sequential)] internal struct LoggingOptions { diff --git a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs index 6421fc8..583a013 100644 --- a/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/NotificationInterfaceCallbacks.cs @@ -2,6 +2,7 @@ using BitcoinKernel.Interop.Delegates.Notification; namespace BitcoinKernel.Interop.Structs; + [StructLayout(LayoutKind.Sequential)] internal struct NotificationInterfaceCallbacks { diff --git a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs index 807b755..6215fae 100644 --- a/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs +++ b/src/BitcoinKernel.Interop/Structs/ValidationInterfaceCallbacks.cs @@ -2,6 +2,7 @@ using BitcoinKernel.Interop.Delegates.Validation; namespace BitcoinKernel.Interop.Structs; + [StructLayout(LayoutKind.Sequential)] internal struct ValidationInterfaceCallbacks { diff --git a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs index d67b4a1..741267f 100644 --- a/tests/BitcoinKernel.Tests/BlockProcessingTests.cs +++ b/tests/BitcoinKernel.Tests/BlockProcessingTests.cs @@ -5,6 +5,7 @@ using Xunit; namespace BitcoinKernel.Tests; + public class BlockProcessingTests : IDisposable { private KernelContext? _context; diff --git a/tests/BitcoinKernel.Tests/BlockTests.cs b/tests/BitcoinKernel.Tests/BlockTests.cs index a57850c..ce87f8e 100644 --- a/tests/BitcoinKernel.Tests/BlockTests.cs +++ b/tests/BitcoinKernel.Tests/BlockTests.cs @@ -2,6 +2,7 @@ using Xunit; namespace BitcoinKernel.Tests; + public class BlockTests { private List ReadBlockData()