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 +}