diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c7d2b1..1264b21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,7 @@ jobs: platform: linux_amd64 env: - TEST_VERSION: '0.0.1' + TEST_VERSION: '0.0.2' TEST_REPO: 'stringintech/kernel-bindings-tests' TEST_DIR: '.conformance-tests' diff --git a/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs b/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs index e55a479..7e0c29f 100644 --- a/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs +++ b/tools/kernel-bindings-test-handler/Handlers/ScriptVerifyHandler.cs @@ -22,7 +22,7 @@ public ScriptVerifyHandler(KernelContext context) /// /// Handles a script verification request. /// - public Response Handle(string requestId, ScriptVerifyParams parameters) + public Response Handle(string requestId, BtckScriptPubkeyVerifyParams parameters) { try { @@ -37,7 +37,7 @@ public Response Handle(string requestId, ScriptVerifyParams parameters) foreach (var output in parameters.SpentOutputs) { var outputScriptPubKey = ScriptPubKey.FromHex(output.ScriptPubKeyHex); - spentOutputs.Add(new TxOut(outputScriptPubKey, output.Amount)); + spentOutputs.Add(new TxOut(outputScriptPubKey, output.Value)); } } @@ -58,7 +58,7 @@ public Response Handle(string requestId, ScriptVerifyParams parameters) return new Response { Id = requestId, - Success = new { } + Result = true }; } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "inputIndex") @@ -66,45 +66,41 @@ public Response Handle(string requestId, ScriptVerifyParams parameters) return new Response { Id = requestId, + Result = null, Error = new ErrorResponse { - Type = "ScriptVerify", - Variant = "TxInputIndex" + Code = new ErrorCode + { + Type = "btck_ScriptVerifyStatus", + Member = "TxInputIndex" + } } }; } catch (ScriptVerificationException ex) { - return new Response + // If status is OK, the script just failed verification (result: false) + // If status is not OK, it's an actual error condition + if (ex.Status == ScriptVerifyStatus.OK) { - Id = requestId, - Error = new ErrorResponse + return new Response { - Type = "ScriptVerify", - Variant = MapScriptVerifyStatus(ex.Status) - } - }; - } - catch (Exception -#if DEBUG - ex -#endif - ) - { - // Log to stderr for debugging (can be disabled in production) -#if DEBUG - Console.Error.WriteLine($"Exception: {ex.GetType().Name}: {ex.Message}"); - Console.Error.WriteLine($"StackTrace: {ex.StackTrace}"); -#endif + Id = requestId, + Result = false + }; + } - // Generic error for unexpected exceptions return new Response { Id = requestId, + Result = null, Error = new ErrorResponse { - Type = "ScriptVerify", - Variant = "Invalid" + Code = new ErrorCode + { + Type = "btck_ScriptVerifyStatus", + Member = MapScriptVerifyStatus(ex.Status) + } } }; } @@ -132,9 +128,18 @@ private ScriptVerificationFlags ParseFlags(object? flags) { return (ScriptVerificationFlags)jsonElement.GetUInt32(); } - else if (jsonElement.ValueKind == System.Text.Json.JsonValueKind.String) + else if (jsonElement.ValueKind == System.Text.Json.JsonValueKind.Array) { - return ParseFlagString(jsonElement.GetString() ?? string.Empty); + // Handle array of string flags - combine them with OR + ScriptVerificationFlags combinedFlags = ScriptVerificationFlags.None; + foreach (var element in jsonElement.EnumerateArray()) + { + if (element.ValueKind == System.Text.Json.JsonValueKind.String) + { + combinedFlags |= ParseFlagString(element.GetString() ?? string.Empty); + } + } + return combinedFlags; } } @@ -152,18 +157,24 @@ private ScriptVerificationFlags ParseFlags(object? flags) /// private ScriptVerificationFlags ParseFlagString(string flagStr) { + // Handle btck_ prefixed format (e.g., "btck_ScriptVerificationFlags_WITNESS") + if (flagStr.StartsWith("btck_ScriptVerificationFlags_", StringComparison.OrdinalIgnoreCase)) + { + flagStr = flagStr.Substring("btck_ScriptVerificationFlags_".Length); + } + return flagStr.ToUpperInvariant() switch { - "VERIFY_NONE" or "NONE" => ScriptVerificationFlags.None, - "VERIFY_P2SH" or "P2SH" => ScriptVerificationFlags.P2SH, - "VERIFY_DERSIG" or "DERSIG" => ScriptVerificationFlags.DerSig, - "VERIFY_NULLDUMMY" or "NULLDUMMY" => ScriptVerificationFlags.NullDummy, - "VERIFY_CHECKLOCKTIMEVERIFY" or "CHECKLOCKTIMEVERIFY" => ScriptVerificationFlags.CheckLockTimeVerify, - "VERIFY_CHECKSEQUENCEVERIFY" or "CHECKSEQUENCEVERIFY" => ScriptVerificationFlags.CheckSequenceVerify, - "VERIFY_WITNESS" or "WITNESS" => ScriptVerificationFlags.Witness, - "VERIFY_TAPROOT" or "TAPROOT" => ScriptVerificationFlags.Taproot, - "VERIFY_ALL" or "ALL" => ScriptVerificationFlags.All, - "VERIFY_ALL_PRE_TAPROOT" or "ALL_PRE_TAPROOT" => ScriptVerificationFlags.AllPreTaproot, + "NONE" => ScriptVerificationFlags.None, + "P2SH" => ScriptVerificationFlags.P2SH, + "DERSIG" => ScriptVerificationFlags.DerSig, + "NULLDUMMY" => ScriptVerificationFlags.NullDummy, + "CHECKLOCKTIMEVERIFY" => ScriptVerificationFlags.CheckLockTimeVerify, + "CHECKSEQUENCEVERIFY" => ScriptVerificationFlags.CheckSequenceVerify, + "WITNESS" => ScriptVerificationFlags.Witness, + "TAPROOT" => ScriptVerificationFlags.Taproot, + "ALL" => ScriptVerificationFlags.All, + "ALL_PRE_TAPROOT" => ScriptVerificationFlags.AllPreTaproot, _ => throw new ArgumentException($"Unknown flag: {flagStr}") }; } @@ -175,12 +186,9 @@ private string MapScriptVerifyStatus(ScriptVerifyStatus status) { return status switch { - ScriptVerifyStatus.ERROR_TX_INPUT_INDEX => "TxInputIndex", - ScriptVerifyStatus.ERROR_INVALID_FLAGS => "InvalidFlags", - ScriptVerifyStatus.ERROR_INVALID_FLAGS_COMBINATION => "InvalidFlagsCombination", - ScriptVerifyStatus.ERROR_SPENT_OUTPUTS_MISMATCH => "SpentOutputsMismatch", - ScriptVerifyStatus.ERROR_SPENT_OUTPUTS_REQUIRED => "SpentOutputsRequired", - _ => "Invalid" + ScriptVerifyStatus.ERROR_INVALID_FLAGS_COMBINATION => "ERROR_INVALID_FLAGS_COMBINATION", + ScriptVerifyStatus.ERROR_SPENT_OUTPUTS_REQUIRED => "ERROR_SPENT_OUTPUTS_REQUIRED", + _ => "ERROR_INVALID" }; } } diff --git a/tools/kernel-bindings-test-handler/Program.cs b/tools/kernel-bindings-test-handler/Program.cs index ccd89e1..8c4d7ae 100644 --- a/tools/kernel-bindings-test-handler/Program.cs +++ b/tools/kernel-bindings-test-handler/Program.cs @@ -46,7 +46,10 @@ static async Task Main(string[] args) Id = "unknown", Error = new ErrorResponse { - Type = "InvalidRequest" + Code = new ErrorCode + { + Type = "InvalidRequest" + } } }; } @@ -62,7 +65,10 @@ static async Task Main(string[] args) Id = "unknown", Error = new ErrorResponse { - Type = "InvalidRequest" + Code = new ErrorCode + { + Type = "InvalidRequest" + } } }; } @@ -91,7 +97,7 @@ private static Response HandleRequest(Request request, ScriptVerifyHandler scrip { switch (request.Method) { - case "script_pubkey.verify": + case "btck_script_pubkey_verify": if (request.Params == null) { return new Response @@ -99,26 +105,32 @@ private static Response HandleRequest(Request request, ScriptVerifyHandler scrip Id = request.Id, Error = new ErrorResponse { - Type = "InvalidParams" + Code = new ErrorCode + { + Type = "InvalidParams" + } } }; } - var scriptVerifyParams = JsonSerializer.Deserialize(request.Params.Value, jsonOptions); + var btckScriptPubkeyVerifyParams = JsonSerializer.Deserialize(request.Params.Value, jsonOptions); - if (scriptVerifyParams == null) + if (btckScriptPubkeyVerifyParams == null) { return new Response { Id = request.Id, Error = new ErrorResponse { - Type = "InvalidParams" + Code = new ErrorCode + { + Type = "InvalidParams" + } } }; } - return scriptVerifyHandler.Handle(request.Id, scriptVerifyParams); + return scriptVerifyHandler.Handle(request.Id, btckScriptPubkeyVerifyParams); default: return new Response @@ -126,7 +138,10 @@ private static Response HandleRequest(Request request, ScriptVerifyHandler scrip Id = request.Id, Error = new ErrorResponse { - Type = "MethodNotFound" + Code = new ErrorCode + { + Type = "MethodNotFound" + } } }; } @@ -138,7 +153,10 @@ private static Response HandleRequest(Request request, ScriptVerifyHandler scrip Id = request.Id, Error = new ErrorResponse { - Type = "InternalError" + Code = new ErrorCode + { + Type = "InternalError" + } } }; } diff --git a/tools/kernel-bindings-test-handler/Protocol/Request.cs b/tools/kernel-bindings-test-handler/Protocol/Request.cs index 0d75185..79f9cd8 100644 --- a/tools/kernel-bindings-test-handler/Protocol/Request.cs +++ b/tools/kernel-bindings-test-handler/Protocol/Request.cs @@ -19,17 +19,17 @@ public class Request } /// -/// Parameters for script_pubkey.verify method. +/// Parameters for btck_script_pubkey_verify method. /// -public class ScriptVerifyParams +public class BtckScriptPubkeyVerifyParams { - [JsonPropertyName("script_pubkey_hex")] + [JsonPropertyName("script_pubkey")] public string ScriptPubKeyHex { get; set; } = string.Empty; [JsonPropertyName("amount")] public long Amount { get; set; } - [JsonPropertyName("tx_hex")] + [JsonPropertyName("tx_to")] public string TxHex { get; set; } = string.Empty; [JsonPropertyName("input_index")] @@ -39,7 +39,7 @@ public class ScriptVerifyParams public List? SpentOutputs { get; set; } [JsonPropertyName("flags")] - public object? Flags { get; set; } // Can be uint or string + public JsonElement? Flags { get; set; } // Can be uint, or array } /// @@ -47,9 +47,9 @@ public class ScriptVerifyParams /// public class SpentOutput { - [JsonPropertyName("script_pubkey_hex")] + [JsonPropertyName("script_pubkey")] public string ScriptPubKeyHex { get; set; } = string.Empty; [JsonPropertyName("amount")] - public long Amount { get; set; } + public long Value { get; set; } } diff --git a/tools/kernel-bindings-test-handler/Protocol/Response.cs b/tools/kernel-bindings-test-handler/Protocol/Response.cs index 1c49f2a..e75f655 100644 --- a/tools/kernel-bindings-test-handler/Protocol/Response.cs +++ b/tools/kernel-bindings-test-handler/Protocol/Response.cs @@ -10,9 +10,9 @@ public class Response [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; - [JsonPropertyName("success")] + [JsonPropertyName("result")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public object? Success { get; set; } + public object? Result { get; set; } [JsonPropertyName("error")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -23,11 +23,19 @@ public class Response /// Represents an error response. /// public class ErrorResponse +{ + [JsonPropertyName("code")] + public ErrorCode Code { get; set; } = new(); +} + +/// +/// Represents an error code with type and member information. +/// +public class ErrorCode { [JsonPropertyName("type")] public string Type { get; set; } = string.Empty; - [JsonPropertyName("variant")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Variant { get; set; } + [JsonPropertyName("member")] + public string Member { get; set; } = string.Empty; }