Skip to content

Commit 74bef56

Browse files
authored
Merge pull request #10 from janb84/Updates_for_kernel-bindings-tests_v0_0_3
Updates for kernel bindings tests v0 0 3
2 parents 9e8e8f0 + f28fdaf commit 74bef56

10 files changed

Lines changed: 951 additions & 307 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
platform: linux_amd64
9797

9898
env:
99-
TEST_VERSION: '0.0.2'
99+
TEST_VERSION: '0.0.3-alpha.4'
100100
TEST_REPO: 'stringintech/kernel-bindings-tests'
101101
TEST_DIR: '.conformance-tests'
102102

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using BitcoinKernel.Core.Abstractions;
2+
using BitcoinKernel.Core.Exceptions;
3+
using BitcoinKernel.Interop;
4+
5+
namespace BitcoinKernel.Core.ScriptVerification;
6+
7+
/// <summary>
8+
/// Holds precomputed transaction data used to accelerate repeated script verification
9+
/// across multiple inputs of the same transaction.
10+
/// Required when <c>btck_ScriptVerificationFlags_TAPROOT</c> is set.
11+
/// </summary>
12+
public sealed class PrecomputedTransactionData : IDisposable
13+
{
14+
private IntPtr _handle;
15+
private bool _disposed;
16+
17+
/// <summary>
18+
/// Creates precomputed transaction data for the given transaction.
19+
/// </summary>
20+
/// <param name="transaction">The transaction being verified.</param>
21+
/// <param name="spentOutputs">
22+
/// The outputs being spent by the transaction inputs. Required when the TAPROOT
23+
/// verification flag is set. Must match the transaction input count if provided.
24+
/// </param>
25+
public PrecomputedTransactionData(Transaction transaction, IReadOnlyList<TxOut>? spentOutputs = null)
26+
{
27+
ArgumentNullException.ThrowIfNull(transaction);
28+
29+
IntPtr[] handles = spentOutputs is { Count: > 0 }
30+
? spentOutputs.Select(o => o.Handle).ToArray()
31+
: Array.Empty<IntPtr>();
32+
33+
_handle = NativeMethods.PrecomputedTransactionDataCreate(
34+
transaction.Handle,
35+
handles,
36+
(nuint)handles.Length);
37+
38+
if (_handle == IntPtr.Zero)
39+
throw new KernelException("Failed to create precomputed transaction data");
40+
}
41+
42+
internal IntPtr Handle
43+
{
44+
get
45+
{
46+
ThrowIfDisposed();
47+
return _handle;
48+
}
49+
}
50+
51+
public void Dispose()
52+
{
53+
if (!_disposed && _handle != IntPtr.Zero)
54+
{
55+
NativeMethods.PrecomputedTransactionDataDestroy(_handle);
56+
_handle = IntPtr.Zero;
57+
_disposed = true;
58+
}
59+
GC.SuppressFinalize(this);
60+
}
61+
62+
~PrecomputedTransactionData() => Dispose();
63+
64+
private void ThrowIfDisposed()
65+
{
66+
if (_disposed)
67+
throw new ObjectDisposedException(nameof(PrecomputedTransactionData));
68+
}
69+
}

src/BitcoinKernel.Core/ScriptVerification/ScriptVerifier.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,55 @@ namespace BitcoinKernel.Core.ScriptVerification;
1515
public static class ScriptVerifier
1616
{
1717

18+
/// <summary>
19+
/// Verifies a script pubkey using externally-managed precomputed transaction data.
20+
/// Use this overload when the <see cref="PrecomputedTransactionData"/> is created
21+
/// separately and reused across multiple inputs of the same transaction.
22+
/// </summary>
23+
/// <param name="scriptPubkey">The output script to verify against.</param>
24+
/// <param name="amount">The amount of the output being spent.</param>
25+
/// <param name="transaction">The transaction containing the input to verify.</param>
26+
/// <param name="precomputedTxData">Optional externally-managed precomputed transaction data. Required for Taproot.</param>
27+
/// <param name="inputIndex">The index of the transaction input to verify.</param>
28+
/// <param name="flags">Script verification flags to use.</param>
29+
/// <returns>True if the script is valid, false if invalid.</returns>
30+
/// <exception cref="ScriptVerificationException">Thrown when verification fails with an error status.</exception>
31+
public static bool VerifyScript(
32+
ScriptPubKey scriptPubkey,
33+
long amount,
34+
Transaction transaction,
35+
PrecomputedTransactionData? precomputedTxData,
36+
uint inputIndex,
37+
ScriptVerificationFlags flags = ScriptVerificationFlags.All)
38+
{
39+
IntPtr precomputedPtr = precomputedTxData?.Handle ?? IntPtr.Zero;
40+
41+
IntPtr statusPtr = Marshal.AllocHGlobal(1);
42+
try
43+
{
44+
int result = NativeMethods.ScriptPubkeyVerify(
45+
scriptPubkey.Handle,
46+
amount,
47+
transaction.Handle,
48+
precomputedPtr,
49+
inputIndex,
50+
(uint)flags,
51+
statusPtr);
52+
53+
byte statusCode = Marshal.ReadByte(statusPtr);
54+
var status = (ScriptVerifyStatus)statusCode;
55+
56+
if (status != ScriptVerifyStatus.OK)
57+
throw new ScriptVerificationException(status, $"Script verification failed: {status}");
58+
59+
return result != 0;
60+
}
61+
finally
62+
{
63+
Marshal.FreeHGlobal(statusPtr);
64+
}
65+
}
66+
1867
/// <summary>
1968
/// Verifies a script pubkey against a transaction input, throwing an exception on error.
2069
/// </summary>

0 commit comments

Comments
 (0)