From 9a1e8fc056663dc3fa813cf9888914f3fd1817ba Mon Sep 17 00:00:00 2001 From: stringintech Date: Sun, 7 Dec 2025 14:58:52 +0330 Subject: [PATCH] Drop response ID field and restructure TestCase type Remove ID field from responses while keeping it required in requests. Response IDs are unnecessary since test cases are executed sequentially against handlers. Restructure TestCase to use explicit Request and Response fields instead of flat structure, making validation against future JSON schemas easier. --- cmd/mock-handler/main.go | 19 +-- docs/handler-spec.md | 10 +- runner/runner.go | 53 +++---- runner/runner_test.go | 68 +++------ runner/types.go | 19 +-- testdata/script_verify_errors.json | 60 ++++---- testdata/script_verify_success.json | 218 +++++++++++++++------------- 7 files changed, 205 insertions(+), 242 deletions(-) diff --git a/cmd/mock-handler/main.go b/cmd/mock-handler/main.go index e64bc7e..98d82ec 100644 --- a/cmd/mock-handler/main.go +++ b/cmd/mock-handler/main.go @@ -53,7 +53,9 @@ func buildTestIndex() (map[string]string, error) { // Parse just enough to get test IDs var suite struct { Tests []struct { - ID string `json:"id"` + Request struct { + ID string `json:"id"` + } `json:"request"` } `json:"tests"` } if err := json.Unmarshal(data, &suite); err != nil { @@ -61,7 +63,7 @@ func buildTestIndex() (map[string]string, error) { } for _, test := range suite.Tests { - index[test.ID] = testFile + index[test.Request.ID] = testFile } } @@ -79,7 +81,6 @@ func handleRequest(line string, testIndex map[string]string) error { filename, ok := testIndex[req.ID] if !ok { resp := runner.Response{ - ID: req.ID, Error: &runner.Error{ Code: &runner.ErrorCode{ Type: "Handler", @@ -94,7 +95,6 @@ func handleRequest(line string, testIndex map[string]string) error { suite, err := runner.LoadTestSuiteFromFS(testdata.FS, filename) if err != nil { resp := runner.Response{ - ID: req.ID, Error: &runner.Error{ Code: &runner.ErrorCode{ Type: "Handler", @@ -108,14 +108,13 @@ func handleRequest(line string, testIndex map[string]string) error { // Find the specific test case var testCase *runner.TestCase for _, test := range suite.Tests { - if test.ID == req.ID { + if test.Request.ID == req.ID { testCase = &test break } } if testCase == nil { resp := runner.Response{ - ID: req.ID, Error: &runner.Error{ Code: &runner.ErrorCode{ Type: "Handler", @@ -127,9 +126,8 @@ func handleRequest(line string, testIndex map[string]string) error { } // Verify method matches - if req.Method != testCase.Method { + if req.Method != testCase.Request.Method { resp := runner.Response{ - ID: req.ID, Error: &runner.Error{ Code: &runner.ErrorCode{ Type: "Handler", @@ -142,9 +140,8 @@ func handleRequest(line string, testIndex map[string]string) error { // Build response based on expected result return writeResponse(runner.Response{ - ID: req.ID, - Result: testCase.Expected.Result, - Error: testCase.Expected.Error, + Result: testCase.ExpectedResponse.Result, + Error: testCase.ExpectedResponse.Error, }) } diff --git a/docs/handler-spec.md b/docs/handler-spec.md index 85fa586..c7b5499 100644 --- a/docs/handler-spec.md +++ b/docs/handler-spec.md @@ -30,7 +30,6 @@ Handlers communicate with the test runner via **stdin/stdout**: ```json { - "id": "unique-request-id", "result": null, "error": { "code": { @@ -42,7 +41,6 @@ Handlers communicate with the test runner via **stdin/stdout**: ``` **Fields:** -- `id` (string, required): Must match the request ID - `result` (any, optional): The return value, or `null` for void/nullptr operations. Must be `null` on error - `error` (object, optional): Error details. Must be `null` on success. An empty object `{}` is used to indicate an error is raised without further details, it is NOT equivalent to `null` - `code` (object, optional): Error code details @@ -55,9 +53,8 @@ Handlers communicate with the test runner via **stdin/stdout**: 1. **Input Processing**: Read JSON requests line-by-line from stdin 2. **Response Order**: Responses must match request order (process sequentially) -3. **ID Matching**: Response `id` must exactly match the request `id` -4. **Error Handling**: Return error responses for invalid requests or failed operations -5. **Exit Behavior**: Exit cleanly when stdin closes +3. **Error Handling**: Return error responses for invalid requests or failed operations +4. **Exit Behavior**: Exit cleanly when stdin closes ## Test Suites and Expected Responses @@ -73,14 +70,12 @@ Test cases where the script verification operation executes successfully and ret **Expected Response Format:** ```json { - "id": "test-id", "result": true } ``` or ```json { - "id": "test-id", "result": false } ``` @@ -95,7 +90,6 @@ Test cases where the verification operation fails to determine validity of the s **Expected Response Format:** ```json { - "id": "test-id", "result": null, "error": { "code": { diff --git a/runner/runner.go b/runner/runner.go index 3c2c441..511389d 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -126,23 +126,17 @@ func (tr *TestRunner) runTest(ctx context.Context, test TestCase) SingleTestResu select { case <-ctx.Done(): return SingleTestResult{ - TestID: test.ID, + TestID: test.Request.ID, Passed: false, Message: fmt.Sprintf("Total execution timeout exceeded (%v)", tr.timeout), } default: } - req := Request{ - ID: test.ID, - Method: test.Method, - Params: test.Params, - } - - err := tr.SendRequest(req) + err := tr.SendRequest(test.Request) if err != nil { return SingleTestResult{ - TestID: test.ID, + TestID: test.Request.ID, Passed: false, Message: fmt.Sprintf("Failed to send request: %v", err), } @@ -151,7 +145,7 @@ func (tr *TestRunner) runTest(ctx context.Context, test TestCase) SingleTestResu resp, err := tr.ReadResponse() if err != nil { return SingleTestResult{ - TestID: test.ID, + TestID: test.Request.ID, Passed: false, Message: fmt.Sprintf("Failed to read response: %v", err), } @@ -159,28 +153,21 @@ func (tr *TestRunner) runTest(ctx context.Context, test TestCase) SingleTestResu if err := validateResponse(test, resp); err != nil { return SingleTestResult{ - TestID: test.ID, + TestID: test.Request.ID, Passed: false, Message: fmt.Sprintf("Invalid response: %s", err.Error()), } } return SingleTestResult{ - TestID: test.ID, + TestID: test.Request.ID, Passed: true, } } // validateResponse validates that a response matches the expected test outcome. -// Returns an error if: -// -// Response ID does not match the request ID -// Response does not match the expected outcome (error or success) +// Returns an error if the response does not match the expected outcome (error or success). func validateResponse(test TestCase, resp *Response) error { - if resp.ID != test.ID { - return fmt.Errorf("response ID mismatch: expected %s, got %s", test.ID, resp.ID) - } - - if test.Expected.Error != nil { + if test.ExpectedResponse.Error != nil { return validateResponseForError(test, resp) } @@ -191,14 +178,14 @@ func validateResponse(test TestCase, resp *Response) error { // It ensures the response contains an error, the result is null or omitted, and if an // error code is expected, it matches the expected type and member. func validateResponseForError(test TestCase, resp *Response) error { - if test.Expected.Error == nil { + if test.ExpectedResponse.Error == nil { panic("validateResponseForError expects non-nil error") } if resp.Error == nil { - if test.Expected.Error.Code != nil { + if test.ExpectedResponse.Error.Code != nil { return fmt.Errorf("expected error %s.%s, but got no error", - test.Expected.Error.Code.Type, test.Expected.Error.Code.Member) + test.ExpectedResponse.Error.Code.Type, test.ExpectedResponse.Error.Code.Member) } return fmt.Errorf("expected error, but got no error") } @@ -207,18 +194,18 @@ func validateResponseForError(test TestCase, resp *Response) error { return fmt.Errorf("expected result to be null or omitted when error is present, got: %s", string(resp.Result)) } - if test.Expected.Error.Code != nil { + if test.ExpectedResponse.Error.Code != nil { if resp.Error.Code == nil { return fmt.Errorf("expected error code %s.%s, but got error with no code", - test.Expected.Error.Code.Type, test.Expected.Error.Code.Member) + test.ExpectedResponse.Error.Code.Type, test.ExpectedResponse.Error.Code.Member) } - if resp.Error.Code.Type != test.Expected.Error.Code.Type { - return fmt.Errorf("expected error type %s, got %s", test.Expected.Error.Code.Type, resp.Error.Code.Type) + if resp.Error.Code.Type != test.ExpectedResponse.Error.Code.Type { + return fmt.Errorf("expected error type %s, got %s", test.ExpectedResponse.Error.Code.Type, resp.Error.Code.Type) } - if resp.Error.Code.Member != test.Expected.Error.Code.Member { - return fmt.Errorf("expected error member %s, got %s", test.Expected.Error.Code.Member, resp.Error.Code.Member) + if resp.Error.Code.Member != test.ExpectedResponse.Error.Code.Member { + return fmt.Errorf("expected error member %s, got %s", test.ExpectedResponse.Error.Code.Member, resp.Error.Code.Member) } } return nil @@ -228,7 +215,7 @@ func validateResponseForError(test TestCase, resp *Response) error { // It ensures the response contains no error, and if a result is expected, it matches the // expected value. func validateResponseForSuccess(test TestCase, resp *Response) error { - if test.Expected.Error != nil { + if test.ExpectedResponse.Error != nil { panic("validateResponseForSuccess expects nil error") } @@ -239,14 +226,14 @@ func validateResponseForSuccess(test TestCase, resp *Response) error { return fmt.Errorf("expected success with no error, but got error") } - if test.Expected.Result.IsNullOrOmitted() { + if test.ExpectedResponse.Result.IsNullOrOmitted() { if !resp.Result.IsNullOrOmitted() { return fmt.Errorf("expected null or omitted result, got: %s", string(resp.Result)) } return nil } - expectedNorm, err := test.Expected.Result.Normalize() + expectedNorm, err := test.ExpectedResponse.Result.Normalize() if err != nil { return fmt.Errorf("failed to normalize expected result: %w", err) } diff --git a/runner/runner_test.go b/runner/runner_test.go index 3bb8929..25aac56 100644 --- a/runner/runner_test.go +++ b/runner/runner_test.go @@ -17,11 +17,10 @@ func TestValidateResponse(t *testing.T) { { name: "success with boolean result", testCaseJSON: `{ - "id": "1", - "expected": {"result": true} + "request": {"id": "1"}, + "expected_response": {"result": true} }`, responseJSON: `{ - "id": "1", "result": true }`, wantErr: false, @@ -29,11 +28,10 @@ func TestValidateResponse(t *testing.T) { { name: "success with null result explicit", testCaseJSON: `{ - "id": "2", - "expected": {} + "request": {"id": "2"}, + "expected_response": {} }`, responseJSON: `{ - "id": "2", "result": null }`, wantErr: false, @@ -41,19 +39,18 @@ func TestValidateResponse(t *testing.T) { { name: "success with null result omitted", testCaseJSON: `{ - "id": "3", - "expected": {} + "request": {"id": "3"}, + "expected_response": {} }`, responseJSON: `{ - "id": "3" }`, wantErr: false, }, { name: "error exact match", testCaseJSON: `{ - "id": "4", - "expected": { + "request": {"id": "4"}, + "expected_response": { "error": { "code": { "type": "type", @@ -63,7 +60,6 @@ func TestValidateResponse(t *testing.T) { } }`, responseJSON: `{ - "id": "4", "result": null, "error": { "code": { @@ -77,8 +73,8 @@ func TestValidateResponse(t *testing.T) { { name: "error type mismatch", testCaseJSON: `{ - "id": "5", - "expected": { + "request": {"id": "5"}, + "expected_response": { "error": { "code": { "type": "type", @@ -88,7 +84,6 @@ func TestValidateResponse(t *testing.T) { } }`, responseJSON: `{ - "id": "5", "error": { "code": { "type": "different_type", @@ -102,8 +97,8 @@ func TestValidateResponse(t *testing.T) { { name: "error member mismatch", testCaseJSON: `{ - "id": "6", - "expected": { + "request": {"id": "6"}, + "expected_response": { "error": { "code": { "type": "type", @@ -113,7 +108,6 @@ func TestValidateResponse(t *testing.T) { } }`, responseJSON: `{ - "id": "6", "error": { "code": { "type": "type", @@ -127,11 +121,10 @@ func TestValidateResponse(t *testing.T) { { name: "expected success got error", testCaseJSON: `{ - "id": "7", - "expected": {"result": true} + "request": {"id": "7"}, + "expected_response": {"result": true} }`, responseJSON: `{ - "id": "7", "result": null, "error": { "code": { @@ -146,8 +139,8 @@ func TestValidateResponse(t *testing.T) { { name: "expected error got success", testCaseJSON: `{ - "id": "8", - "expected": { + "request": {"id": "8"}, + "expected_response": { "error": { "code": { "type": "type", @@ -157,7 +150,6 @@ func TestValidateResponse(t *testing.T) { } }`, responseJSON: `{ - "id": "8", "result": true }`, wantErr: true, @@ -166,34 +158,20 @@ func TestValidateResponse(t *testing.T) { { name: "result value mismatch", testCaseJSON: `{ - "id": "9", - "expected": {"result": true} + "request": {"id": "9"}, + "expected_response": {"result": true} }`, responseJSON: `{ - "id": "9", "result": false }`, wantErr: true, wantErrMsg: "result mismatch", }, - { - name: "response ID mismatch", - testCaseJSON: `{ - "id": "10", - "expected": {"result": true} - }`, - responseJSON: `{ - "id": "99", - "result": true - }`, - wantErr: true, - wantErrMsg: "response ID mismatch", - }, { name: "protocol violation with result not null when error present", testCaseJSON: `{ - "id": "11", - "expected": { + "request": {"id": "11"}, + "expected_response": { "error": { "code": { "type": "type", @@ -203,7 +181,6 @@ func TestValidateResponse(t *testing.T) { } }`, responseJSON: `{ - "id": "11", "result": true, "error": { "code": { @@ -218,13 +195,12 @@ func TestValidateResponse(t *testing.T) { { name: "error generic without code", testCaseJSON: `{ - "id": "12", - "expected": { + "request": {"id": "12"}, + "expected_response": { "error": {} } }`, responseJSON: `{ - "id": "12", "result": null, "error": {} }`, diff --git a/runner/types.go b/runner/types.go index 413c62b..e1c16eb 100644 --- a/runner/types.go +++ b/runner/types.go @@ -6,19 +6,9 @@ import ( // TestCase represents a single test case type TestCase struct { - ID string `json:"id"` - Description string `json:"description,omitempty"` - Method string `json:"method"` - Params json.RawMessage `json:"params"` - Expected TestExpectation `json:"expected"` -} - -// TestExpectation defines what response is expected. -// If expecting success, result contains the expected value (or null for void/nullptr) and error must be null. -// If expecting failure, result must be null and error contains the expected error details. -type TestExpectation struct { - Result Result `json:"result"` // Expected return value (null for void/nullptr/error cases) - Error *Error `json:"error,omitempty"` // Expected error (null for success cases) + Description string `json:"description,omitempty"` + Request Request `json:"request"` + ExpectedResponse Response `json:"expected_response"` } // TestSuite represents a collection of test cases @@ -32,14 +22,13 @@ type TestSuite struct { type Request struct { ID string `json:"id"` Method string `json:"method"` - Params json.RawMessage `json:"params"` + Params json.RawMessage `json:"params,omitempty"` } // Response represents a response from the handler. // If the operation succeeds, result contains the return value (or null for void/nullptr) and error must be null. // If the operation fails, result must be null and error contains error details. type Response struct { - ID string `json:"id"` Result Result `json:"result"` // Return value (null for void/nullptr/error cases) Error *Error `json:"error,omitempty"` // Error details (null for success cases) } diff --git a/testdata/script_verify_errors.json b/testdata/script_verify_errors.json index 0be810f..b276afc 100644 --- a/testdata/script_verify_errors.json +++ b/testdata/script_verify_errors.json @@ -3,23 +3,27 @@ "description": "Test cases where the verification operation fails to determine validity of the script due to bad user input", "tests": [ { - "id": "error_invalid_flags_combination", "description": "VERIFY_WITNESS flag requires P2SH flag to be set as well", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", - "amount": 0, - "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", - "input_index": 0, - "flags": ["btck_ScriptVerificationFlags_WITNESS"], - "spent_outputs": [ - { - "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", - "amount": 100000 - } - ] + "request": { + "id": "error_invalid_flags_combination", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", + "amount": 0, + "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [ + { + "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", + "amount": 100000 + } + ] + } }, - "expected": { + "expected_response": { "error": { "code": { "type": "btck_ScriptVerifyStatus", @@ -29,18 +33,22 @@ } }, { - "id": "error_spent_outputs_required", "description": "Taproot verification requires spent outputs to be provided", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", - "amount": 0, - "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", - "input_index": 0, - "flags": ["btck_ScriptVerificationFlags_TAPROOT"], - "spent_outputs": [] + "request": { + "id": "error_spent_outputs_required", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", + "amount": 0, + "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_TAPROOT" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "error": { "code": { "type": "btck_ScriptVerifyStatus", @@ -50,4 +58,4 @@ } } ] -} \ No newline at end of file +} diff --git a/testdata/script_verify_success.json b/testdata/script_verify_success.json index bbbb08a..7a9a384 100644 --- a/testdata/script_verify_success.json +++ b/testdata/script_verify_success.json @@ -3,142 +3,154 @@ "description": "Test cases where the script verification operation executes successfully and returns a boolean result (true for valid scripts, false for invalid scripts)", "tests": [ { - "id": "valid_p2pkh_legacy", "description": "Valid legacy P2PKH (Pay-to-PubKey-Hash) transaction verification", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", - "amount": 0, - "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "valid_p2pkh_legacy", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", + "amount": 0, + "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": true } }, { - "id": "valid_p2sh_wrapped_segwit", "description": "Valid P2SH-wrapped SegWit transaction verification", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "a91434c06f8c87e355e123bdc6dda4ffabc64b6989ef87", - "amount": 1900000, - "tx_to": "01000000000101d9fd94d0ff0026d307c994d0003180a5f248146efb6371d040c5973f5f66d9df0400000017160014b31b31a6cb654cfab3c50567bcf124f48a0beaecffffffff012cbd1c000000000017a914233b74bf0823fa58bbbd26dfc3bb4ae715547167870247304402206f60569cac136c114a58aedd80f6fa1c51b49093e7af883e605c212bdafcd8d202200e91a55f408a021ad2631bc29a67bd6915b2d7e9ef0265627eabd7f7234455f6012103e7e802f50344303c76d12c089c8724c1b230e3b745693bbe16aad536293d15e300000000", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "valid_p2sh_wrapped_segwit", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "a91434c06f8c87e355e123bdc6dda4ffabc64b6989ef87", + "amount": 1900000, + "tx_to": "01000000000101d9fd94d0ff0026d307c994d0003180a5f248146efb6371d040c5973f5f66d9df0400000017160014b31b31a6cb654cfab3c50567bcf124f48a0beaecffffffff012cbd1c000000000017a914233b74bf0823fa58bbbd26dfc3bb4ae715547167870247304402206f60569cac136c114a58aedd80f6fa1c51b49093e7af883e605c212bdafcd8d202200e91a55f408a021ad2631bc29a67bd6915b2d7e9ef0265627eabd7f7234455f6012103e7e802f50344303c76d12c089c8724c1b230e3b745693bbe16aad536293d15e300000000", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": true } }, { - "id": "valid_native_segwit_p2wpkh", "description": "Valid native SegWit (P2WPKH) transaction verification", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d", - "amount": 18393430, - "tx_to": "010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "valid_native_segwit_p2wpkh", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d", + "amount": 18393430, + "tx_to": "010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": true } }, { - "id": "error_invalid_p2pkh_wrong_signature", "description": "P2PKH script verification fails due to wrong signature (malformed final opcode)", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ff", - "amount": 0, - "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "error_invalid_p2pkh_wrong_signature", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ff", + "amount": 0, + "tx_to": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": false } }, { - "id": "error_invalid_p2sh_segwit_wrong_amount", "description": "P2SH-wrapped SegWit verification fails due to incorrect amount", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "a91434c06f8c87e355e123bdc6dda4ffabc64b6989ef87", - "amount": 900000, - "tx_to": "01000000000101d9fd94d0ff0026d307c994d0003180a5f248146efb6371d040c5973f5f66d9df0400000017160014b31b31a6cb654cfab3c50567bcf124f48a0beaecffffffff012cbd1c000000000017a914233b74bf0823fa58bbbd26dfc3bb4ae715547167870247304402206f60569cac136c114a58aedd80f6fa1c51b49093e7af883e605c212bdafcd8d202200e91a55f408a021ad2631bc29a67bd6915b2d7e9ef0265627eabd7f7234455f6012103e7e802f50344303c76d12c089c8724c1b230e3b745693bbe16aad536293d15e300000000", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "error_invalid_p2sh_segwit_wrong_amount", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "a91434c06f8c87e355e123bdc6dda4ffabc64b6989ef87", + "amount": 900000, + "tx_to": "01000000000101d9fd94d0ff0026d307c994d0003180a5f248146efb6371d040c5973f5f66d9df0400000017160014b31b31a6cb654cfab3c50567bcf124f48a0beaecffffffff012cbd1c000000000017a914233b74bf0823fa58bbbd26dfc3bb4ae715547167870247304402206f60569cac136c114a58aedd80f6fa1c51b49093e7af883e605c212bdafcd8d202200e91a55f408a021ad2631bc29a67bd6915b2d7e9ef0265627eabd7f7234455f6012103e7e802f50344303c76d12c089c8724c1b230e3b745693bbe16aad536293d15e300000000", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": false } }, { - "id": "error_invalid_native_segwit_wrong_script", "description": "Native SegWit verification fails due to malformed witness script hash", - "method": "btck_script_pubkey_verify", - "params": { - "script_pubkey": "0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58f", - "amount": 18393430, - "tx_to": "010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000", - "input_index": 0, - "flags": [ - "btck_ScriptVerificationFlags_P2SH", - "btck_ScriptVerificationFlags_DERSIG", - "btck_ScriptVerificationFlags_NULLDUMMY", - "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", - "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", - "btck_ScriptVerificationFlags_WITNESS" - ], - "spent_outputs": [] + "request": { + "id": "error_invalid_native_segwit_wrong_script", + "method": "btck_script_pubkey_verify", + "params": { + "script_pubkey": "0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58f", + "amount": 18393430, + "tx_to": "010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000", + "input_index": 0, + "flags": [ + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS" + ], + "spent_outputs": [] + } }, - "expected": { + "expected_response": { "result": false } } ] -} \ No newline at end of file +}