From ccb99bd5b00a1876de00d9d75530ff340a9b4c1d Mon Sep 17 00:00:00 2001 From: stringintech Date: Tue, 12 May 2026 15:01:23 +0330 Subject: [PATCH 1/7] Rename "name" to "title" in suites Also change values to better titles and adapt runner to use both title and filename --- cmd/runner/main.go | 4 ++-- runner/runner.go | 21 ++++++++++----------- runner/types.go | 3 ++- testdata/chain.json | 2 +- testdata/script_verify_cltv.json | 2 +- testdata/script_verify_csv.json | 2 +- testdata/script_verify_errors.json | 2 +- testdata/script_verify_p2pkh.json | 2 +- testdata/script_verify_p2sh_multisig.json | 2 +- testdata/script_verify_p2sh_p2wpkh.json | 2 +- testdata/script_verify_p2sh_p2wsh.json | 2 +- testdata/script_verify_p2tr_keypath.json | 2 +- testdata/script_verify_p2tr_scriptpath.json | 2 +- testdata/script_verify_p2wpkh.json | 2 +- testdata/script_verify_p2wsh.json | 2 +- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cmd/runner/main.go b/cmd/runner/main.go index f804c8c..bef31e2 100644 --- a/cmd/runner/main.go +++ b/cmd/runner/main.go @@ -68,7 +68,7 @@ func main() { totalTests := 0 for _, testFile := range testFiles { - fmt.Printf("\n=== Running test suite: %s ===\n", testFile) + fmt.Printf("\n=== Running test suite ===\n") // Load test suite from embedded FS suite, err := runner.LoadTestSuiteFromFS(testdata.FS, testFile) @@ -106,7 +106,7 @@ func main() { } func printResults(suite *runner.TestSuite, result runner.TestResult) { - fmt.Printf("\nTest Suite: %s\n", result.SuiteName) + fmt.Printf("\nTest Suite: %s (%s)\n", result.SuiteTitle, result.SuiteFileName) if suite.Description != "" { fmt.Printf("Description: %s\n", suite.Description) } diff --git a/runner/runner.go b/runner/runner.go index 41afed3..12baef4 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -120,8 +120,9 @@ func (tr *TestRunner) RunTestSuite(ctx context.Context, suite TestSuite, verbosi depTracker := NewDependencyTracker() result := TestResult{ - SuiteName: suite.Name, - TotalTests: len(suite.Tests), + SuiteTitle: suite.Title, + SuiteFileName: suite.FileName, + TotalTests: len(suite.Tests), } skipTests := false @@ -330,11 +331,12 @@ func validateResponseForSuccess(test *TestCase, resp *Response) error { // TestResult contains results from running a test suite type TestResult struct { - SuiteName string - TotalTests int - PassedTests int - FailedTests int - TestResults []SingleTestResult + SuiteTitle string + SuiteFileName string + TotalTests int + PassedTests int + FailedTests int + TestResults []SingleTestResult } // SingleTestResult contains the result of a single test @@ -357,10 +359,7 @@ func LoadTestSuiteFromFS(fsys embed.FS, filePath string) (*TestSuite, error) { return nil, fmt.Errorf("failed to parse JSON: %w", err) } - // Set suite name from filename if not specified - if suite.Name == "" { - suite.Name = filepath.Base(filePath) - } + suite.FileName = filepath.Base(filePath) return &suite, nil } diff --git a/runner/types.go b/runner/types.go index b2a0f81..9df3dd5 100644 --- a/runner/types.go +++ b/runner/types.go @@ -13,9 +13,10 @@ type TestCase struct { // TestSuite represents a collection of test cases type TestSuite struct { - Name string `json:"name"` + Title string `json:"title"` Description string `json:"description,omitempty"` Tests []TestCase `json:"tests"` + FileName string `json:"-"` // Stateful indicates that tests in this suite depend on each other and must // execute sequentially. If any test fails in a stateful suite, all subsequent diff --git a/testdata/chain.json b/testdata/chain.json index a5c5c86..48955d2 100644 --- a/testdata/chain.json +++ b/testdata/chain.json @@ -1,5 +1,5 @@ { - "name": "Chain", + "title": "Chain Operations", "description": "Sets up blocks, checks chain state, and verifies that the chain tip changes as expected after a reorg scenario", "stateful": true, "tests": [ diff --git a/testdata/script_verify_cltv.json b/testdata/script_verify_cltv.json index cd684c8..47db604 100644 --- a/testdata/script_verify_cltv.json +++ b/testdata/script_verify_cltv.json @@ -1,5 +1,5 @@ { - "name": "script_verify_cltv", + "title": "Script Verification - CLTV", "description": "Verifies a P2SH output with OP_CHECKLOCKTIMEVERIFY locked to block 100. Transaction with locktime=100 passes with P2SH + CHECKLOCKTIMEVERIFY and all pre-taproot flags; transaction with locktime=50 fails when CHECKLOCKTIMEVERIFY is enforced but passes with P2SH only.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_csv.json b/testdata/script_verify_csv.json index dada662..a131a49 100644 --- a/testdata/script_verify_csv.json +++ b/testdata/script_verify_csv.json @@ -1,5 +1,5 @@ { - "name": "script_verify_csv", + "title": "Script Verification - CSV", "description": "Verifies a P2SH output with OP_CHECKSEQUENCEVERIFY locked to sequence 10. Transaction with sequence=10 passes with P2SH + CHECKSEQUENCEVERIFY and all pre-taproot flags; transaction with sequence=5 fails when CHECKSEQUENCEVERIFY is enforced but passes with P2SH only.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_errors.json b/testdata/script_verify_errors.json index 583a8bc..762c4fa 100644 --- a/testdata/script_verify_errors.json +++ b/testdata/script_verify_errors.json @@ -1,5 +1,5 @@ { - "name": "Failed Script Verification Cases", + "title": "Script Verification Error Cases", "description": "Test cases where the verification operation fails to determine validity of the script due to bad user input", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2pkh.json b/testdata/script_verify_p2pkh.json index 0fb9951..b242011 100644 --- a/testdata/script_verify_p2pkh.json +++ b/testdata/script_verify_p2pkh.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2pkh", + "title": "Script Verification - P2PKH", "description": "Verifies a mainnet P2PKH output against three transaction variants: valid sig (passes with no flags and all pre-taproot flags), corrupted sig (always fails), non-DER sig (passes without DERSIG, fails with it). Mainnet tx aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2sh_multisig.json b/testdata/script_verify_p2sh_multisig.json index 09ae587..9cf3f94 100644 --- a/testdata/script_verify_p2sh_multisig.json +++ b/testdata/script_verify_p2sh_multisig.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2sh_multisig", + "title": "Script Verification - P2SH Multisig", "description": "Verifies a mainnet P2SH 2-of-3 multisig output against three variants: valid sigs (passes with P2SH and all pre-taproot flags), corrupted sig (fails with P2SH, passes without it), non-null dummy element (passes with P2SH only, fails when NULLDUMMY is also set). Mainnet tx 3cd7f78499632d6f672d8a9412ae756b29c41342954c97846e0d153c7753a37e.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2sh_p2wpkh.json b/testdata/script_verify_p2sh_p2wpkh.json index c7eb2fd..7e1fe51 100644 --- a/testdata/script_verify_p2sh_p2wpkh.json +++ b/testdata/script_verify_p2sh_p2wpkh.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2sh_p2wpkh", + "title": "Script Verification - P2SH-P2WPKH", "description": "Verifies a mainnet P2SH-P2WPKH output against two variants: valid witness sig (passes with P2SH + WITNESS and all pre-taproot flags), corrupted witness sig (fails with WITNESS enforced, passes with P2SH only). Mainnet tx 07dea5918a500d7476b1d116d80507a66bc2167681b2e6ca7dd99dbc6d95c31d.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2sh_p2wsh.json b/testdata/script_verify_p2sh_p2wsh.json index 64647a7..0a827b2 100644 --- a/testdata/script_verify_p2sh_p2wsh.json +++ b/testdata/script_verify_p2sh_p2wsh.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2sh_p2wsh", + "title": "Script Verification - P2SH-P2WSH", "description": "Verifies a mainnet P2SH-P2WSH (2-of-3 multisig) output against two variants: valid witness sigs (passes with P2SH + WITNESS and all pre-taproot flags), corrupted witness sig (fails with WITNESS enforced, passes with P2SH only). Mainnet tx 017be55761bf5a3920c73778810a6be4c3315dc6efa4f31b590bc3bc1da9d75f.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2tr_keypath.json b/testdata/script_verify_p2tr_keypath.json index bbb426b..f2333c1 100644 --- a/testdata/script_verify_p2tr_keypath.json +++ b/testdata/script_verify_p2tr_keypath.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2tr_keypath", + "title": "Script Verification - P2TR Key-Path", "description": "Verifies a mainnet P2TR key-path spend. Requires one spent output for precomputed transaction data. Valid Schnorr sig passes with P2SH + WITNESS + TAPROOT and all flags; corrupted Schnorr sig fails when TAPROOT is enforced, passes with P2SH + WITNESS only. Mainnet tx 33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2tr_scriptpath.json b/testdata/script_verify_p2tr_scriptpath.json index b8d193a..8c0e3fd 100644 --- a/testdata/script_verify_p2tr_scriptpath.json +++ b/testdata/script_verify_p2tr_scriptpath.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2tr_scriptpath", + "title": "Script Verification - P2TR Script-Path", "description": "Verifies a mainnet P2TR script-path spend at input index 1 of a two-input transaction. Requires two spent outputs for precomputed transaction data. Valid script-path witness passes with P2SH + WITNESS + TAPROOT and all flags; corrupted sig fails when TAPROOT is enforced, passes with P2SH + WITNESS only. Mainnet tx 1ba232a8bf936cf24155292c9a4330298278f572bacc78455eb68e3552197c30.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2wpkh.json b/testdata/script_verify_p2wpkh.json index e1b13ae..6f3f94d 100644 --- a/testdata/script_verify_p2wpkh.json +++ b/testdata/script_verify_p2wpkh.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2wpkh", + "title": "Script Verification - P2WPKH", "description": "Verifies a mainnet native P2WPKH output with two amount values: correct amount (5003 sat) passes with P2SH + WITNESS and all pre-taproot flags; wrong amount (5002 sat) fails the witness commitment check when WITNESS is enforced, passes with P2SH only. Mainnet tx 00000000102d4e899ec7cc3656d91ab83aa8e95807dabb90fbe16a1a9e70b6ab.", "stateful": true, "tests": [ diff --git a/testdata/script_verify_p2wsh.json b/testdata/script_verify_p2wsh.json index 932cd4b..8163ec5 100644 --- a/testdata/script_verify_p2wsh.json +++ b/testdata/script_verify_p2wsh.json @@ -1,5 +1,5 @@ { - "name": "script_verify_p2wsh", + "title": "Script Verification - P2WSH", "description": "Verifies a mainnet native P2WSH output at input index 1 of a two-input transaction. Valid HTLC-style witness script passes with P2SH + WITNESS and all pre-taproot flags; corrupted witness sig fails with WITNESS enforced, passes with P2SH only. Mainnet tx 12fc05be6778b06e77191e8fb18fee632b2d92efa0b6830e1cf63e28723a8b8f.", "stateful": true, "tests": [ From 2d2e0e33667da20f03e705f0027e1af06ddb33ae Mon Sep 17 00:00:00 2001 From: stringintech Date: Tue, 12 May 2026 16:00:25 +0330 Subject: [PATCH 2/7] Add coverage for operations on primitive types New suites added for operations on block, block hash, block header, script pubkey, transaction, transaction input, transaction output and txid. Chain suite refactored to return ref for `btck_block_tree_entry_get_block_hash` test cases and call `btck_block_hash_to_bytes` for asserting its value. Existing suites refactored to call destroy as soon as objects (refs) no longer needed and use `"expected_response": {}` where both `result` and `error` are expected to be null. --- docs/handler-spec.md | 44 +++ testdata/block.json | 352 ++++++++++++++++++++ testdata/block_hash.json | 165 +++++++++ testdata/block_header.json | 283 ++++++++++++++++ testdata/chain.json | 212 +++++++++--- testdata/script_pubkey.json | 141 ++++++++ testdata/script_verify_cltv.json | 20 +- testdata/script_verify_csv.json | 20 +- testdata/script_verify_errors.json | 12 +- testdata/script_verify_p2pkh.json | 28 +- testdata/script_verify_p2sh_multisig.json | 28 +- testdata/script_verify_p2sh_p2wpkh.json | 20 +- testdata/script_verify_p2sh_p2wsh.json | 20 +- testdata/script_verify_p2tr_keypath.json | 24 +- testdata/script_verify_p2tr_scriptpath.json | 132 ++++---- testdata/script_verify_p2wpkh.json | 12 +- testdata/script_verify_p2wsh.json | 20 +- testdata/transaction.json | 310 +++++++++++++++++ testdata/transaction_input.json | 252 ++++++++++++++ testdata/transaction_output.json | 162 +++++++++ testdata/txid.json | 201 +++++++++++ 21 files changed, 2180 insertions(+), 278 deletions(-) create mode 100644 testdata/block.json create mode 100644 testdata/block_hash.json create mode 100644 testdata/block_header.json create mode 100644 testdata/script_pubkey.json create mode 100644 testdata/transaction.json create mode 100644 testdata/transaction_input.json create mode 100644 testdata/transaction_output.json create mode 100644 testdata/txid.json diff --git a/docs/handler-spec.md b/docs/handler-spec.md index ae488aa..db848cd 100644 --- a/docs/handler-spec.md +++ b/docs/handler-spec.md @@ -101,6 +101,50 @@ Many operations return objects (contexts, blocks, chains, etc.) that must persis The conformance tests are organized into suites, each testing a specific aspect of the Bitcoin Kernel bindings. Test files are located in [`../testdata/`](../testdata/). +### Operations on Primitive Types + +Test suites covering primitive kernel objects, their serialization, and related value objects. + +#### Txid Operations +**File:** [`txid.json`](../testdata/txid.json) + +Creates txid objects from parsed transactions, verifies byte serialization and equality, and checks copy and destroy behavior. + +#### Block Hash Operations +**File:** [`block_hash.json`](../testdata/block_hash.json) + +Creates block hash objects from raw 32-byte values, verifies byte serialization and equality, and checks copy and destroy behavior. + +#### Script Pubkey Operations +**File:** [`script_pubkey.json`](../testdata/script_pubkey.json) + +Creates script pubkey objects from raw script bytes, verifies round-trip serialization including empty scripts, and checks copy and destroy behavior. + +#### Transaction Operations +**File:** [`transaction.json`](../testdata/transaction.json) + +Parses raw transactions, rejects malformed inputs, verifies txid and serialization getters, checks input and output counts plus indexed accessors, and exercises copy and destroy behavior. + +#### Transaction Input Operations +**File:** [`transaction_input.json`](../testdata/transaction_input.json) + +Extracts transaction input objects from a parsed transaction, reads each input's outpoint index and txid, and checks copy and destroy behavior for both input and outpoint objects. + +#### Transaction Output Operations +**File:** [`transaction_output.json`](../testdata/transaction_output.json) + +Builds transaction output objects from a script pubkey and amount, verifies amount and script getter behavior, and checks copy and destroy behavior. + +#### Block Header Operations +**File:** [`block_header.json`](../testdata/block_header.json) + +Parses raw block headers, rejects short inputs, verifies header hash generation, field getters, and serialization semantics around trailing bytes, and exercises copy and destroy behavior. + +#### Block Operations +**File:** [`block.json`](../testdata/block.json) + +Parses full blocks, rejects malformed inputs, verifies block hash and byte serialization, checks header and transaction accessors, and exercises copy and destroy behavior using the mainnet genesis block. + ### Script Verification Success Cases Test cases where the script verification operation executes successfully and returns a boolean result (true for valid scripts, false for invalid scripts). diff --git a/testdata/block.json b/testdata/block.json new file mode 100644 index 0000000..912a22c --- /dev/null +++ b/testdata/block.json @@ -0,0 +1,352 @@ +{ + "title": "Block Operations", + "description": "Covers block parsing, invalid-input rejection, hash and serialization getters, header access, transaction access by index, copy equality, and object cleanup using the mainnet genesis block", + "stateful": true, + "tests": [ + { + "description": "Rejects empty raw block bytes", + "request": { + "id": "block#1", + "method": "btck_block_create", + "params": { + "raw_block": "" + }, + "ref": "$empty_block" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Rejects incomplete genesis block bytes containing only the header", + "request": { + "id": "block#2", + "method": "btck_block_create", + "params": { + "raw_block": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c" + }, + "ref": "$invalid_block" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Creates a block from the full mainnet genesis block bytes", + "request": { + "id": "block#3", + "method": "btck_block_create", + "params": { + "raw_block": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + }, + "ref": "$block" + }, + "expected_response": { + "result": { + "ref": "$block" + } + } + }, + { + "description": "Gets the block hash", + "request": { + "id": "block#4", + "method": "btck_block_get_hash", + "params": { + "block": { + "ref": "$block" + } + }, + "ref": "$block_hash" + }, + "expected_response": { + "result": { + "ref": "$block_hash" + } + } + }, + { + "description": "Verifies the serialized block hash", + "request": { + "id": "block#5", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$block_hash" + } + } + }, + "expected_response": { + "result": "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + } + }, + { + "description": "Verifies block has one transaction", + "request": { + "id": "block#6", + "method": "btck_block_count_transactions", + "params": { + "block": { + "ref": "$block" + } + } + }, + "expected_response": { + "result": 1 + } + }, + { + "description": "Verifies block serialization round-trips to the original bytes", + "request": { + "id": "block#7", + "method": "btck_block_to_bytes", + "params": { + "block": { + "ref": "$block" + } + } + }, + "expected_response": { + "result": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + } + }, + { + "description": "Copies the block", + "request": { + "id": "block#8", + "method": "btck_block_copy", + "params": { + "block": { + "ref": "$block" + } + }, + "ref": "$block_copy" + }, + "expected_response": { + "result": { + "ref": "$block_copy" + } + } + }, + { + "description": "Gets the hash of the copied block", + "request": { + "id": "block#9", + "method": "btck_block_get_hash", + "params": { + "block": { + "ref": "$block_copy" + } + }, + "ref": "$block_copy_hash" + }, + "expected_response": { + "result": { + "ref": "$block_copy_hash" + } + } + }, + { + "description": "Destroys the copied block", + "request": { + "id": "block#10", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$block_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the hash of the copied block equals the original block hash", + "request": { + "id": "block#11", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$block_hash" + }, + "hash2": { + "ref": "$block_copy_hash" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the hash returned for the copied block", + "request": { + "id": "block#12", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$block_copy_hash" + } + } + }, + "expected_response": {} + }, + { + "description": "Extracts the block header", + "request": { + "id": "block#13", + "method": "btck_block_get_header", + "params": { + "block": { + "ref": "$block" + } + }, + "ref": "$header" + }, + "expected_response": { + "result": { + "ref": "$header" + } + } + }, + { + "description": "Gets the header hash", + "request": { + "id": "block#14", + "method": "btck_block_header_get_hash", + "params": { + "header": { + "ref": "$header" + } + }, + "ref": "$header_hash" + }, + "expected_response": { + "result": { + "ref": "$header_hash" + } + } + }, + { + "description": "Destroys the header after deriving its hash", + "request": { + "id": "block#15", + "method": "btck_block_header_destroy", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the header hash equals the block hash", + "request": { + "id": "block#16", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$header_hash" + }, + "hash2": { + "ref": "$block_hash" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the original block hash", + "request": { + "id": "block#17", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$block_hash" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the hash returned for the header", + "request": { + "id": "block#18", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$header_hash" + } + } + }, + "expected_response": {} + }, + { + "description": "Gets the first transaction from the block by index", + "request": { + "id": "block#19", + "method": "btck_block_get_transaction_at", + "params": { + "block": { + "ref": "$block" + }, + "transaction_index": 0 + }, + "ref": "$tx" + }, + "expected_response": { + "result": { + "ref": "$tx" + } + } + }, + { + "description": "Gets the txid from the transaction returned by index", + "request": { + "id": "block#20", + "method": "btck_transaction_get_txid", + "params": { + "transaction": { + "ref": "$tx" + } + }, + "ref": "$txid" + }, + "expected_response": { + "result": { + "ref": "$txid" + } + } + }, + { + "description": "Verifies the serialized txid", + "request": { + "id": "block#21", + "method": "btck_txid_to_bytes", + "params": { + "txid": { + "ref": "$txid" + } + } + }, + "expected_response": { + "result": "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a" + } + }, + { + "description": "Destroys the original block", + "request": { + "id": "block#22", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$block" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/block_hash.json b/testdata/block_hash.json new file mode 100644 index 0000000..d84af09 --- /dev/null +++ b/testdata/block_hash.json @@ -0,0 +1,165 @@ +{ + "title": "Block Hash Operations", + "description": "Covers block hash object creation from valid and invalid bytes, byte serialization, equality checks, copying, and cleanup", + "stateful": true, + "tests": [ + { + "description": "Creates a block hash from 32 raw bytes", + "request": { + "id": "block_hash#1", + "method": "btck_block_hash_create", + "params": { + "block_hash": "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + }, + "ref": "$hash1" + }, + "expected_response": { + "result": { + "ref": "$hash1" + } + } + }, + { + "description": "Verifies block hash serialization round-trips to the original bytes", + "request": { + "id": "block_hash#2", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$hash1" + } + } + }, + "expected_response": { + "result": "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + } + }, + { + "description": "Verifies a block hash equals itself", + "request": { + "id": "block_hash#3", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$hash1" + }, + "hash2": { + "ref": "$hash1" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Creates a block hash from all-zero bytes", + "request": { + "id": "block_hash#4", + "method": "btck_block_hash_create", + "params": { + "block_hash": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "ref": "$hash2" + }, + "expected_response": { + "result": { + "ref": "$hash2" + } + } + }, + { + "description": "Verifies different block hashes are not equal", + "request": { + "id": "block_hash#5", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$hash1" + }, + "hash2": { + "ref": "$hash2" + } + } + }, + "expected_response": { + "result": false + } + }, + { + "description": "Destroys the all-zero block hash", + "request": { + "id": "block_hash#6", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$hash2" + } + } + }, + "expected_response": {} + }, + { + "description": "Copies the first block hash", + "request": { + "id": "block_hash#7", + "method": "btck_block_hash_copy", + "params": { + "block_hash": { + "ref": "$hash1" + } + }, + "ref": "$hash1_copy" + }, + "expected_response": { + "result": { + "ref": "$hash1_copy" + } + } + }, + { + "description": "Verifies the copied block hash equals the original", + "request": { + "id": "block_hash#8", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$hash1_copy" + }, + "hash2": { + "ref": "$hash1" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the copied block hash", + "request": { + "id": "block_hash#9", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$hash1_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the original block hash", + "request": { + "id": "block_hash#10", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$hash1" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/block_header.json b/testdata/block_header.json new file mode 100644 index 0000000..7110d97 --- /dev/null +++ b/testdata/block_header.json @@ -0,0 +1,283 @@ +{ + "title": "Block Header Operations", + "description": "Covers block header parsing, invalid-input rejection, hash comparison and serialization, field getters, copy equality, and object cleanup using the mainnet genesis block header", + "stateful": true, + "tests": [ + { + "description": "Rejects empty raw block header bytes", + "request": { + "id": "block_header#1", + "method": "btck_block_header_create", + "params": { + "raw_block_header": "" + }, + "ref": "$empty_header" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Rejects raw header bytes shorter than the required 80-byte block header", + "request": { + "id": "block_header#2", + "method": "btck_block_header_create", + "params": { + "raw_block_header": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b" + }, + "ref": "$short_header" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Creates a header from the exact 80-byte mainnet genesis block header", + "request": { + "id": "block_header#3", + "method": "btck_block_header_create", + "params": { + "raw_block_header": "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c" + }, + "ref": "$header" + }, + "expected_response": { + "result": { + "ref": "$header" + } + } + }, + { + "description": "Gets the hash for the exact genesis block header", + "request": { + "id": "block_header#4", + "method": "btck_block_header_get_hash", + "params": { + "header": { + "ref": "$header" + } + }, + "ref": "$header_hash" + }, + "expected_response": { + "result": { + "ref": "$header_hash" + } + } + }, + { + "description": "Verifies the serialized exact header hash matches the mainnet genesis block hash", + "request": { + "id": "block_header#5", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$header_hash" + } + } + }, + "expected_response": { + "result": "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + } + }, + { + "description": "Gets the previous block hash from the genesis block header", + "request": { + "id": "block_header#6", + "method": "btck_block_header_get_prev_hash", + "params": { + "header": { + "ref": "$header" + } + }, + "ref": "$prev_hash" + }, + "expected_response": { + "result": { + "ref": "$prev_hash" + } + } + }, + { + "description": "Verifies the genesis previous block hash is all zero bytes", + "request": { + "id": "block_header#7", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$prev_hash" + } + } + }, + "expected_response": { + "result": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "description": "Verifies the genesis block header version", + "request": { + "id": "block_header#8", + "method": "btck_block_header_get_version", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": { + "result": 1 + } + }, + { + "description": "Verifies the genesis block header timestamp", + "request": { + "id": "block_header#9", + "method": "btck_block_header_get_timestamp", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": { + "result": 1231006505 + } + }, + { + "description": "Verifies the genesis block header proof-of-work bits", + "request": { + "id": "block_header#10", + "method": "btck_block_header_get_bits", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": { + "result": 486604799 + } + }, + { + "description": "Verifies the genesis block header nonce", + "request": { + "id": "block_header#11", + "method": "btck_block_header_get_nonce", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": { + "result": 2083236893 + } + }, + { + "description": "Copies the parsed genesis block header", + "request": { + "id": "block_header#12", + "method": "btck_block_header_copy", + "params": { + "header": { + "ref": "$header" + } + }, + "ref": "$header_copy" + }, + "expected_response": { + "result": { + "ref": "$header_copy" + } + } + }, + { + "description": "Destroys the original header after the copy has been created", + "request": { + "id": "block_header#13", + "method": "btck_block_header_destroy", + "params": { + "header": { + "ref": "$header" + } + } + }, + "expected_response": {} + }, + { + "description": "Gets the hash from the copied header after the original header is destroyed", + "request": { + "id": "block_header#14", + "method": "btck_block_header_get_hash", + "params": { + "header": { + "ref": "$header_copy" + } + }, + "ref": "$header_copy_hash" + }, + "expected_response": { + "result": { + "ref": "$header_copy_hash" + } + } + }, + { + "description": "Destroys the copied header after deriving its hash", + "request": { + "id": "block_header#15", + "method": "btck_block_header_destroy", + "params": { + "header": { + "ref": "$header_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the copied header hash equals the original header hash", + "request": { + "id": "block_header#16", + "method": "btck_block_hash_equals", + "params": { + "hash1": { + "ref": "$header_hash" + }, + "hash2": { + "ref": "$header_copy_hash" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the original header hash after comparison", + "request": { + "id": "block_header#17", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$header_hash" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the hash returned for the copied header", + "request": { + "id": "block_header#18", + "method": "btck_block_hash_destroy", + "params": { + "block_hash": { + "ref": "$header_copy_hash" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/chain.json b/testdata/chain.json index 48955d2..6f0f042 100644 --- a/testdata/chain.json +++ b/testdata/chain.json @@ -4,7 +4,7 @@ "stateful": true, "tests": [ { - "description": "Create context with regtest chain parameters", + "description": "Creates a context with regtest chain parameters", "request": { "id": "chain#1", "method": "btck_context_create", @@ -22,7 +22,7 @@ } }, { - "description": "Create chainstate manager from context", + "description": "Creates a chainstate manager from the context", "request": { "id": "chain#2", "method": "btck_chainstate_manager_create", @@ -40,7 +40,7 @@ } }, { - "description": "Destroy context as it's no longer needed", + "description": "Destroys the context after creating the chainstate manager", "request": { "id": "chain#3", "method": "btck_context_destroy", @@ -50,12 +50,10 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { - "description": "Get active chain reference from chainstate manager", + "description": "Gets the active chain reference from the chainstate manager", "request": { "id": "chain#4", "method": "btck_chainstate_manager_get_active_chain", @@ -73,7 +71,7 @@ } }, { - "description": "Assert chain height is 0 (genesis block only)", + "description": "Verifies the active chain starts at height 0", "request": { "id": "chain#5", "method": "btck_chain_get_height", @@ -88,7 +86,7 @@ } }, { - "description": "Create block 1 from raw hex data", + "description": "Creates block 1 from raw bytes", "request": { "id": "chain#6", "method": "btck_block_create", @@ -104,7 +102,7 @@ } }, { - "description": "Process block 1, extending chain to height 1", + "description": "Processes block 1 to extend the chain to height 1", "request": { "id": "chain#7", "method": "btck_chainstate_manager_process_block", @@ -124,9 +122,22 @@ } }, { - "description": "Create block 2 from raw hex data", + "description": "Destroys block 1 after processing", "request": { "id": "chain#8", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$block_1" + } + } + }, + "expected_response": {} + }, + { + "description": "Creates block 2 from raw bytes", + "request": { + "id": "chain#9", "method": "btck_block_create", "params": { "raw_block": "000000205e2f859d70e29641f32371f3bf17a282466ad851f9e51b44a70738abeace314a9cf876c62dbbe036af4ea4a7363cd4ca1c14c8572095cba3b76a87daa1303ed8dce5494dffff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025200feffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000001000000" @@ -140,9 +151,9 @@ } }, { - "description": "Process block 2, extending chain to height 2", + "description": "Processes block 2 to extend the chain to height 2", "request": { - "id": "chain#9", + "id": "chain#10", "method": "btck_chainstate_manager_process_block", "params": { "chainstate_manager": { @@ -160,9 +171,22 @@ } }, { - "description": "Create block 3 from raw hex data", + "description": "Destroys block 2 after processing", "request": { - "id": "chain#10", + "id": "chain#11", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$block_2" + } + } + }, + "expected_response": {} + }, + { + "description": "Creates block 3 from raw bytes", + "request": { + "id": "chain#12", "method": "btck_block_create", "params": { "raw_block": "0000002077622c1ae937c9fec6be84d01521cb31b0e6f88ec48150965323dba6a1e36e19354352df0f2a5d635ca7d3a52064f9c95f070d2c13c0a6c087acba03dfeeae66dde5494dffff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025300feffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000002000000" @@ -176,9 +200,9 @@ } }, { - "description": "Process block 3, extending chain to height 3", + "description": "Processes block 3 to extend the chain to height 3", "request": { - "id": "chain#11", + "id": "chain#13", "method": "btck_chainstate_manager_process_block", "params": { "chainstate_manager": { @@ -196,9 +220,22 @@ } }, { - "description": "Assert chain height is 3 after processing blocks", + "description": "Destroys block 3 after processing", "request": { - "id": "chain#12", + "id": "chain#14", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$block_3" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the active chain height is 3 after processing blocks", + "request": { + "id": "chain#15", "method": "btck_chain_get_height", "params": { "chain": { @@ -211,9 +248,9 @@ } }, { - "description": "Get block tree entry at height 3 to use after reorg", + "description": "Gets the height-3 block tree entry before the reorg", "request": { - "id": "chain#13", + "id": "chain#16", "method": "btck_chain_get_by_height", "params": { "chain": { @@ -230,24 +267,42 @@ } }, { - "description": "Assert tip block hash matches expected value", + "description": "Gets the current tip block hash", "request": { - "id": "chain#14", + "id": "chain#17", "method": "btck_block_tree_entry_get_block_hash", "params": { "block_tree_entry": { "ref": "$tip_entry" } + }, + "ref": "$tip_hash" + }, + "expected_response": { + "result": { + "ref": "$tip_hash" + } + } + }, + { + "description": "Verifies the current tip block hash bytes", + "request": { + "id": "chain#18", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$tip_hash" + } } }, "expected_response": { - "result": "1a81e97231fb262ccf464f937553a1deff996ac6901b062d0b35afe025ee2886" + "result": "8628ee25e0af350b2d061b90c66a99ffdea15375934f46cf2c26fb3172e9811a" } }, { - "description": "Create reorg block 1 (competing block at height 2)", + "description": "Creates the first competing block at height 2", "request": { - "id": "chain#15", + "id": "chain#19", "method": "btck_block_create", "params": { "raw_block": "000000205e2f859d70e29641f32371f3bf17a282466ad851f9e51b44a70738abeace314a9cf876c62dbbe036af4ea4a7363cd4ca1c14c8572095cba3b76a87daa1303ed8dee5494dffff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025200feffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000001000000" @@ -261,9 +316,9 @@ } }, { - "description": "Process reorg block 1", + "description": "Processes the first competing block", "request": { - "id": "chain#16", + "id": "chain#20", "method": "btck_chainstate_manager_process_block", "params": { "chainstate_manager": { @@ -281,9 +336,22 @@ } }, { - "description": "Create reorg block 2 (competing block at height 3)", + "description": "Destroys the first competing block after processing", "request": { - "id": "chain#17", + "id": "chain#21", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$reorg_block_1" + } + } + }, + "expected_response": {} + }, + { + "description": "Creates the second competing block at height 3", + "request": { + "id": "chain#22", "method": "btck_block_create", "params": { "raw_block": "000000202c6c418b1f714cbe22c9c2906a5c1a3f5c0df22d32989b71f579b2289a0ccd4c354352df0f2a5d635ca7d3a52064f9c95f070d2c13c0a6c087acba03dfeeae66dfe5494dffff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025300feffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000002000000" @@ -297,9 +365,9 @@ } }, { - "description": "Process reorg block 2", + "description": "Processes the second competing block", "request": { - "id": "chain#18", + "id": "chain#23", "method": "btck_chainstate_manager_process_block", "params": { "chainstate_manager": { @@ -317,9 +385,22 @@ } }, { - "description": "Create reorg block 3 (extending chain to height 4, triggering reorg)", + "description": "Destroys the second competing block after processing", "request": { - "id": "chain#19", + "id": "chain#24", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$reorg_block_2" + } + } + }, + "expected_response": {} + }, + { + "description": "Creates the third competing block that extends the branch to height 4", + "request": { + "id": "chain#25", "method": "btck_block_create", "params": { "raw_block": "00000020732f2f7a1035b802d670218031da2b11d0fe7297ddaeb4a428fc51bf588770417bd00ba57498a2dfcf4e3f0d7ef7f279b254fc422133f300a49aed3c8ed7717fe0e5494dffff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025400feffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000003000000" @@ -333,9 +414,9 @@ } }, { - "description": "Process reorg block 3, triggering chain reorganization", + "description": "Processes the third competing block to trigger a reorg", "request": { - "id": "chain#20", + "id": "chain#26", "method": "btck_chainstate_manager_process_block", "params": { "chainstate_manager": { @@ -353,9 +434,22 @@ } }, { - "description": "Assert chain height is 4 after processing reorg block 3", + "description": "Destroys the third competing block after processing", "request": { - "id": "chain#21", + "id": "chain#27", + "method": "btck_block_destroy", + "params": { + "block": { + "ref": "$reorg_block_3" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the active chain height is 4 after the reorg", + "request": { + "id": "chain#28", "method": "btck_chain_get_height", "params": { "chain": { @@ -368,9 +462,9 @@ } }, { - "description": "Verify that the old tip is no longer in the active chain after reorg", + "description": "Verifies the old height-3 tip is no longer active after the reorg", "request": { - "id": "chain#22", + "id": "chain#29", "method": "btck_chain_contains", "params": { "chain": { @@ -386,9 +480,9 @@ } }, { - "description": "Get block tree entry at height 4 (new tip after reorg)", + "description": "Gets the height-4 block tree entry after the reorg", "request": { - "id": "chain#23", + "id": "chain#30", "method": "btck_chain_get_by_height", "params": { "chain": { @@ -405,24 +499,42 @@ } }, { - "description": "Assert new tip block hash matches expected value after reorg", + "description": "Gets the new tip block hash after the reorg", "request": { - "id": "chain#24", + "id": "chain#31", "method": "btck_block_tree_entry_get_block_hash", "params": { "block_tree_entry": { "ref": "$new_tip_entry" } + }, + "ref": "$new_tip_hash" + }, + "expected_response": { + "result": { + "ref": "$new_tip_hash" + } + } + }, + { + "description": "Verifies the new tip block hash bytes after the reorg", + "request": { + "id": "chain#32", + "method": "btck_block_hash_to_bytes", + "params": { + "block_hash": { + "ref": "$new_tip_hash" + } } }, "expected_response": { - "result": "18618dcf64dddb10ea15d7850bc4c7965c9a72b613da8530b83057672f29bbfa" + "result": "fabb292f675730b83085da13b6729a5c96c7c40b85d715ea10dbdd64cf8d6118" } }, { - "description": "Destroy chainstate manager", + "description": "Destroys the chainstate manager", "request": { - "id": "chain#25", + "id": "chain#33", "method": "btck_chainstate_manager_destroy", "params": { "chainstate_manager": { @@ -430,9 +542,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] -} \ No newline at end of file +} diff --git a/testdata/script_pubkey.json b/testdata/script_pubkey.json new file mode 100644 index 0000000..be16b64 --- /dev/null +++ b/testdata/script_pubkey.json @@ -0,0 +1,141 @@ +{ + "title": "Script Pubkey Operations", + "description": "Covers script pubkey object creation from raw bytes, byte serialization, copying, and cleanup", + "stateful": true, + "tests": [ + { + "description": "Creates a script pubkey from raw bytes", + "request": { + "id": "script_pubkey#1", + "method": "btck_script_pubkey_create", + "params": { + "script_pubkey": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + }, + "ref": "$spk" + }, + "expected_response": { + "result": { + "ref": "$spk" + } + } + }, + { + "description": "Verifies script pubkey serialization round-trips to the original bytes", + "request": { + "id": "script_pubkey#2", + "method": "btck_script_pubkey_to_bytes", + "params": { + "script_pubkey": { + "ref": "$spk" + } + } + }, + "expected_response": { + "result": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + } + }, + { + "description": "Copies the script pubkey", + "request": { + "id": "script_pubkey#3", + "method": "btck_script_pubkey_copy", + "params": { + "script_pubkey": { + "ref": "$spk" + } + }, + "ref": "$spk_copy" + }, + "expected_response": { + "result": { + "ref": "$spk_copy" + } + } + }, + { + "description": "Destroys the original script pubkey", + "request": { + "id": "script_pubkey#4", + "method": "btck_script_pubkey_destroy", + "params": { + "script_pubkey": { + "ref": "$spk" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the copied script pubkey serializes to the original bytes", + "request": { + "id": "script_pubkey#5", + "method": "btck_script_pubkey_to_bytes", + "params": { + "script_pubkey": { + "ref": "$spk_copy" + } + } + }, + "expected_response": { + "result": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + } + }, + { + "description": "Destroys the copied script pubkey", + "request": { + "id": "script_pubkey#6", + "method": "btck_script_pubkey_destroy", + "params": { + "script_pubkey": { + "ref": "$spk_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Creates an empty script pubkey from raw bytes", + "request": { + "id": "script_pubkey#7", + "method": "btck_script_pubkey_create", + "params": { + "script_pubkey": "" + }, + "ref": "$empty_spk" + }, + "expected_response": { + "result": { + "ref": "$empty_spk" + } + } + }, + { + "description": "Verifies empty script pubkey serialization returns empty bytes", + "request": { + "id": "script_pubkey#8", + "method": "btck_script_pubkey_to_bytes", + "params": { + "script_pubkey": { + "ref": "$empty_spk" + } + } + }, + "expected_response": { + "result": "" + } + }, + { + "description": "Destroys the empty script pubkey", + "request": { + "id": "script_pubkey#9", + "method": "btck_script_pubkey_destroy", + "params": { + "script_pubkey": { + "ref": "$empty_spk" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/script_verify_cltv.json b/testdata/script_verify_cltv.json index 47db604..b8bac39 100644 --- a/testdata/script_verify_cltv.json +++ b/testdata/script_verify_cltv.json @@ -122,9 +122,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid locktime CLTV transaction", @@ -137,9 +135,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create CLTV transaction with locktime=50 (does not satisfy CLTV condition)", @@ -239,9 +235,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy invalid locktime CLTV transaction", @@ -254,9 +248,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy CLTV P2SH script pubkey", @@ -269,9 +261,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_csv.json b/testdata/script_verify_csv.json index a131a49..c239c8a 100644 --- a/testdata/script_verify_csv.json +++ b/testdata/script_verify_csv.json @@ -122,9 +122,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid sequence CSV transaction", @@ -137,9 +135,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create CSV transaction with input sequence=5 (does not satisfy CSV condition)", @@ -239,9 +235,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy invalid sequence CSV transaction", @@ -254,9 +248,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy CSV P2SH script pubkey", @@ -269,9 +261,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_errors.json b/testdata/script_verify_errors.json index 762c4fa..23a7dcf 100644 --- a/testdata/script_verify_errors.json +++ b/testdata/script_verify_errors.json @@ -126,9 +126,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy transaction", @@ -141,9 +139,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy script pubkey", @@ -156,9 +152,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2pkh.json b/testdata/script_verify_p2pkh.json index b242011..997400c 100644 --- a/testdata/script_verify_p2pkh.json +++ b/testdata/script_verify_p2pkh.json @@ -121,9 +121,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2PKH transaction", @@ -136,9 +134,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2PKH transaction with corrupted signature (one byte flipped)", @@ -211,9 +207,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2PKH transaction", @@ -226,9 +220,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2PKH transaction with non-DER signature (length byte 0x46 instead of 0x45)", @@ -327,9 +319,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy non-DER sig P2PKH transaction", @@ -342,9 +332,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy P2PKH script pubkey", @@ -357,9 +345,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2sh_multisig.json b/testdata/script_verify_p2sh_multisig.json index 9cf3f94..40ee315 100644 --- a/testdata/script_verify_p2sh_multisig.json +++ b/testdata/script_verify_p2sh_multisig.json @@ -121,9 +121,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2SH multisig transaction", @@ -136,9 +134,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2SH multisig transaction with corrupted signature (length byte 0x31 instead of 0x30)", @@ -237,9 +233,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2SH multisig transaction", @@ -252,9 +246,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2SH multisig transaction with non-null dummy stack element (OP_1 instead of OP_0)", @@ -354,9 +346,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy non-null dummy P2SH multisig transaction", @@ -369,9 +359,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy P2SH multisig script pubkey", @@ -384,9 +372,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2sh_p2wpkh.json b/testdata/script_verify_p2sh_p2wpkh.json index 7e1fe51..eaaf714 100644 --- a/testdata/script_verify_p2sh_p2wpkh.json +++ b/testdata/script_verify_p2sh_p2wpkh.json @@ -122,9 +122,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2SH-P2WPKH transaction", @@ -137,9 +135,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2SH-P2WPKH transaction with corrupted signature (one byte flipped in witness)", @@ -239,9 +235,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2SH-P2WPKH transaction", @@ -254,9 +248,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy P2SH-P2WPKH script pubkey", @@ -269,9 +261,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2sh_p2wsh.json b/testdata/script_verify_p2sh_p2wsh.json index 0a827b2..d0cc024 100644 --- a/testdata/script_verify_p2sh_p2wsh.json +++ b/testdata/script_verify_p2sh_p2wsh.json @@ -122,9 +122,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2SH-P2WSH transaction", @@ -137,9 +135,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2SH-P2WSH transaction with corrupted signature (one byte flipped in witness)", @@ -239,9 +235,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2SH-P2WSH transaction", @@ -254,9 +248,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy P2SH-P2WSH script pubkey", @@ -269,9 +261,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2tr_keypath.json b/testdata/script_verify_p2tr_keypath.json index f2333c1..f4de5b2 100644 --- a/testdata/script_verify_p2tr_keypath.json +++ b/testdata/script_verify_p2tr_keypath.json @@ -148,9 +148,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2TR key-path transaction", @@ -163,9 +161,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2TR key-path transaction with corrupted Schnorr signature (one byte flipped)", @@ -272,9 +268,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2TR key-path transaction", @@ -287,9 +281,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy spent output", @@ -302,9 +294,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy P2TR script pubkey", @@ -317,9 +307,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2tr_scriptpath.json b/testdata/script_verify_p2tr_scriptpath.json index 8c0e3fd..4604645 100644 --- a/testdata/script_verify_p2tr_scriptpath.json +++ b/testdata/script_verify_p2tr_scriptpath.json @@ -20,44 +20,57 @@ } }, { - "description": "Create script pubkey for spent output at index 1 (the P2TR output being verified)", + "description": "Create spent output at index 0 (amount=1757828)", "request": { "id": "script_verify_p2tr_scriptpath#2", - "method": "btck_script_pubkey_create", + "method": "btck_transaction_output_create", "params": { - "script_pubkey": "5120e687f4f55e3de5264cf4c4f43b53edb5c26e4adae3a3098ce918a663582785bd" + "script_pubkey": { + "ref": "$spk_0" + }, + "amount": 1757828 }, - "ref": "$spk_1" + "ref": "$spent_output_0" }, "expected_response": { "result": { - "ref": "$spk_1" + "ref": "$spent_output_0" } } }, { - "description": "Create spent output at index 0 (amount=1757828)", + "description": "Destroy script pubkey for spent output at index 0 after output creation", "request": { "id": "script_verify_p2tr_scriptpath#3", - "method": "btck_transaction_output_create", + "method": "btck_script_pubkey_destroy", "params": { "script_pubkey": { "ref": "$spk_0" - }, - "amount": 1757828 + } + } + }, + "expected_response": {} + }, + { + "description": "Create script pubkey for spent output at index 1 (the P2TR output being verified)", + "request": { + "id": "script_verify_p2tr_scriptpath#4", + "method": "btck_script_pubkey_create", + "params": { + "script_pubkey": "5120e687f4f55e3de5264cf4c4f43b53edb5c26e4adae3a3098ce918a663582785bd" }, - "ref": "$spent_output_0" + "ref": "$spk_1" }, "expected_response": { "result": { - "ref": "$spent_output_0" + "ref": "$spk_1" } } }, { "description": "Create spent output at index 1 (the P2TR output being spent, amount=503185)", "request": { - "id": "script_verify_p2tr_scriptpath#4", + "id": "script_verify_p2tr_scriptpath#5", "method": "btck_transaction_output_create", "params": { "script_pubkey": { @@ -76,7 +89,7 @@ { "description": "Create valid P2TR script-path transaction", "request": { - "id": "script_verify_p2tr_scriptpath#5", + "id": "script_verify_p2tr_scriptpath#6", "method": "btck_transaction_create", "params": { "raw_transaction": "02000000000102761402258bf42275f52db288dbbc8fdfe30b35dea86c5425a57feef1a4008b0b0100000000ffffffff3847ba0ccc4e1b63ed2f3b4a677bd247940f4d5669cc91d9a4eb096e7615badc0000000000ffffffff0291ad070000000000225120059715a12766bbbee8529b53dce51fe708e9895f50c6babec988c7917ff5958464d11a0000000000225120bee1246f13735551e5e5c2b5631014501a6c77f8ee2d16d33dc109096f22b2a40140ac4e4af854be645890275c8144869343752d5ceee9b361cfab3de0726c10a449cc7491a295417f7c457961fdde59bde483330364b42fddddeef65cd1d97150fc0440b78c0a5065343d451a93dcb499edd3d8994697932322be5e27fa218f5a99be8484a8ef802c3054dee442baced3c170b8afe18ec9758c860876fe4f06a5e3ccb240984299fc968b71d999354af2e991e089908adec84e1b1f04da8149aa0ffce28311b363dfd2dfc456de77746919c263e95a14952080f433ddb87b13b884812bda4420b5095be39b9f2f96a77235854af7635dd09d0324569e9b3d587fe5fb7c44720cad202b74c2011af089c849383ee527c72325de52df6a788428b68d49e9174053aabaac41c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0675a94484b3d55d76af4a2275d327a47c1ec5c7d2232596a09fc883d40bb237e00000000" @@ -92,7 +105,7 @@ { "description": "Create precomputed transaction data for valid P2TR script-path (with both spent outputs for taproot)", "request": { - "id": "script_verify_p2tr_scriptpath#6", + "id": "script_verify_p2tr_scriptpath#7", "method": "btck_precomputed_transaction_data_create", "params": { "tx_to": { @@ -118,7 +131,7 @@ { "description": "Verify valid P2TR script-path at input index 1 with btck_ScriptVerificationFlags_P2SH + btck_ScriptVerificationFlags_WITNESS + btck_ScriptVerificationFlags_TAPROOT - passes", "request": { - "id": "script_verify_p2tr_scriptpath#7", + "id": "script_verify_p2tr_scriptpath#8", "method": "btck_script_pubkey_verify", "params": { "script_pubkey": { @@ -146,7 +159,7 @@ { "description": "Verify valid P2TR script-path at input index 1 with all flags - passes", "request": { - "id": "script_verify_p2tr_scriptpath#8", + "id": "script_verify_p2tr_scriptpath#9", "method": "btck_script_pubkey_verify", "params": { "script_pubkey": { @@ -178,7 +191,7 @@ { "description": "Destroy precomputed transaction data for valid P2TR script-path", "request": { - "id": "script_verify_p2tr_scriptpath#9", + "id": "script_verify_p2tr_scriptpath#10", "method": "btck_precomputed_transaction_data_destroy", "params": { "precomputed_txdata": { @@ -186,14 +199,12 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2TR script-path transaction", "request": { - "id": "script_verify_p2tr_scriptpath#10", + "id": "script_verify_p2tr_scriptpath#11", "method": "btck_transaction_destroy", "params": { "transaction": { @@ -201,14 +212,12 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2TR script-path transaction with corrupted signature (one byte flipped in script-path witness)", "request": { - "id": "script_verify_p2tr_scriptpath#11", + "id": "script_verify_p2tr_scriptpath#12", "method": "btck_transaction_create", "params": { "raw_transaction": "02000000000102761402258bf42275f52db288dbbc8fdfe30b35dea86c5425a57feef1a4008b0b0100000000ffffffff3847ba0ccc4e1b63ed2f3b4a677bd247940f4d5669cc91d9a4eb096e7615badc0000000000ffffffff0291ad070000000000225120059715a12766bbbee8529b53dce51fe708e9895f50c6babec988c7917ff5958464d11a0000000000225120bee1246f13735551e5e5c2b5631014501a6c77f8ee2d16d33dc109096f22b2a40140ac4e4af854be645890275c8144869343752d5ceee9b361cfab3de0726c10a449cc7491a295417f7c457961fdde59bde483330364b42fddddeef65cd1d97150fc0440b78c0a5065343d451a93dcb499edd3d8994697932322be5e27fa218f5a99be8484a8ef802c3054dee442baced3c170b8afe18ec9758c860876fe4f06a5e3ccb240984299fc968b71d999354af2e991e089908adec84e1b1f04da8149aa0ffce28211b363dfd2dfc456de77746919c263e95a14952080f433ddb87b13b884812bda4420b5095be39b9f2f96a77235854af7635dd09d0324569e9b3d587fe5fb7c44720cad202b74c2011af089c849383ee527c72325de52df6a788428b68d49e9174053aabaac41c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0675a94484b3d55d76af4a2275d327a47c1ec5c7d2232596a09fc883d40bb237e00000000" @@ -224,7 +233,7 @@ { "description": "Create precomputed transaction data for corrupted sig P2TR script-path (with both spent outputs)", "request": { - "id": "script_verify_p2tr_scriptpath#12", + "id": "script_verify_p2tr_scriptpath#13", "method": "btck_precomputed_transaction_data_create", "params": { "tx_to": { @@ -250,7 +259,7 @@ { "description": "Verify P2TR script-path with corrupted signature at input index 1 and btck_ScriptVerificationFlags_P2SH + btck_ScriptVerificationFlags_WITNESS + btck_ScriptVerificationFlags_TAPROOT - fails", "request": { - "id": "script_verify_p2tr_scriptpath#13", + "id": "script_verify_p2tr_scriptpath#14", "method": "btck_script_pubkey_verify", "params": { "script_pubkey": { @@ -278,7 +287,7 @@ { "description": "Verify P2TR script-path with corrupted signature at input index 1 and btck_ScriptVerificationFlags_P2SH + btck_ScriptVerificationFlags_WITNESS only - passes (taproot not enforced)", "request": { - "id": "script_verify_p2tr_scriptpath#14", + "id": "script_verify_p2tr_scriptpath#15", "method": "btck_script_pubkey_verify", "params": { "script_pubkey": { @@ -302,10 +311,23 @@ "result": true } }, + { + "description": "Destroy script pubkey for spent output at index 1 after final script verification", + "request": { + "id": "script_verify_p2tr_scriptpath#16", + "method": "btck_script_pubkey_destroy", + "params": { + "script_pubkey": { + "ref": "$spk_1" + } + } + }, + "expected_response": {} + }, { "description": "Destroy precomputed transaction data for corrupted sig P2TR script-path", "request": { - "id": "script_verify_p2tr_scriptpath#15", + "id": "script_verify_p2tr_scriptpath#17", "method": "btck_precomputed_transaction_data_destroy", "params": { "precomputed_txdata": { @@ -313,14 +335,12 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2TR script-path transaction", "request": { - "id": "script_verify_p2tr_scriptpath#16", + "id": "script_verify_p2tr_scriptpath#18", "method": "btck_transaction_destroy", "params": { "transaction": { @@ -328,14 +348,12 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy spent output at index 0", "request": { - "id": "script_verify_p2tr_scriptpath#17", + "id": "script_verify_p2tr_scriptpath#19", "method": "btck_transaction_output_destroy", "params": { "transaction_output": { @@ -343,14 +361,12 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy spent output at index 1", "request": { - "id": "script_verify_p2tr_scriptpath#18", + "id": "script_verify_p2tr_scriptpath#20", "method": "btck_transaction_output_destroy", "params": { "transaction_output": { @@ -358,39 +374,7 @@ } } }, - "expected_response": { - "result": null - } - }, - { - "description": "Destroy script pubkey for spent output at index 0", - "request": { - "id": "script_verify_p2tr_scriptpath#19", - "method": "btck_script_pubkey_destroy", - "params": { - "script_pubkey": { - "ref": "$spk_0" - } - } - }, - "expected_response": { - "result": null - } - }, - { - "description": "Destroy script pubkey for spent output at index 1", - "request": { - "id": "script_verify_p2tr_scriptpath#20", - "method": "btck_script_pubkey_destroy", - "params": { - "script_pubkey": { - "ref": "$spk_1" - } - } - }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2wpkh.json b/testdata/script_verify_p2wpkh.json index 6f3f94d..03e2068 100644 --- a/testdata/script_verify_p2wpkh.json +++ b/testdata/script_verify_p2wpkh.json @@ -175,9 +175,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy native P2WPKH transaction", @@ -190,9 +188,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy native P2WPKH script pubkey", @@ -205,9 +201,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/script_verify_p2wsh.json b/testdata/script_verify_p2wsh.json index 8163ec5..5967842 100644 --- a/testdata/script_verify_p2wsh.json +++ b/testdata/script_verify_p2wsh.json @@ -122,9 +122,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy valid P2WSH transaction", @@ -137,9 +135,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Create P2WSH transaction with corrupted signature (one byte flipped in second witness)", @@ -239,9 +235,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy corrupted sig P2WSH transaction", @@ -254,9 +248,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} }, { "description": "Destroy native P2WSH script pubkey", @@ -269,9 +261,7 @@ } } }, - "expected_response": { - "result": null - } + "expected_response": {} } ] } diff --git a/testdata/transaction.json b/testdata/transaction.json new file mode 100644 index 0000000..fce18ca --- /dev/null +++ b/testdata/transaction.json @@ -0,0 +1,310 @@ +{ + "title": "Transaction Operations", + "description": "Covers transaction parsing, invalid-input rejection, txid and serialization getters, input and output access by index, copying, and object cleanup", + "stateful": true, + "tests": [ + { + "description": "Rejects empty raw transaction bytes", + "request": { + "id": "transaction#1", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "" + }, + "ref": "$empty_tx" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Rejects incomplete transaction bytes", + "request": { + "id": "transaction#2", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "0100000001000000000000000000000000000000000000000000000000000000000000000000ffffffff" + }, + "ref": "$invalid_tx" + }, + "expected_response": { + "error": {} + } + }, + { + "description": "Creates a transaction from raw bytes", + "request": { + "id": "transaction#3", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + }, + "ref": "$tx" + }, + "expected_response": { + "result": { + "ref": "$tx" + } + } + }, + { + "description": "Gets the txid", + "request": { + "id": "transaction#4", + "method": "btck_transaction_get_txid", + "params": { + "transaction": { + "ref": "$tx" + } + }, + "ref": "$tx_txid" + }, + "expected_response": { + "result": { + "ref": "$tx_txid" + } + } + }, + { + "description": "Verifies the serialized txid", + "request": { + "id": "transaction#5", + "method": "btck_txid_to_bytes", + "params": { + "txid": { + "ref": "$tx_txid" + } + } + }, + "expected_response": { + "result": "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a" + } + }, + { + "description": "Verifies the transaction input count", + "request": { + "id": "transaction#6", + "method": "btck_transaction_count_inputs", + "params": { + "transaction": { + "ref": "$tx" + } + } + }, + "expected_response": { + "result": 1 + } + }, + { + "description": "Verifies the transaction output count", + "request": { + "id": "transaction#7", + "method": "btck_transaction_count_outputs", + "params": { + "transaction": { + "ref": "$tx" + } + } + }, + "expected_response": { + "result": 1 + } + }, + { + "description": "Gets the first transaction input by index", + "request": { + "id": "transaction#8", + "method": "btck_transaction_get_input_at", + "params": { + "transaction": { + "ref": "$tx" + }, + "input_index": 0 + }, + "ref": "$in0" + }, + "expected_response": { + "result": { + "ref": "$in0" + } + } + }, + { + "description": "Gets the out point from the indexed input", + "request": { + "id": "transaction#9", + "method": "btck_transaction_input_get_out_point", + "params": { + "transaction_input": { + "ref": "$in0" + } + }, + "ref": "$outpoint0" + }, + "expected_response": { + "result": { + "ref": "$outpoint0" + } + } + }, + { + "description": "Verifies the out point index from the indexed input", + "request": { + "id": "transaction#10", + "method": "btck_transaction_out_point_get_index", + "params": { + "transaction_out_point": { + "ref": "$outpoint0" + } + } + }, + "expected_response": { + "result": 4294967295 + } + }, + { + "description": "Verifies transaction serialization round-trips to the original bytes", + "request": { + "id": "transaction#11", + "method": "btck_transaction_to_bytes", + "params": { + "transaction": { + "ref": "$tx" + } + } + }, + "expected_response": { + "result": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + } + }, + { + "description": "Gets the first transaction output by index", + "request": { + "id": "transaction#12", + "method": "btck_transaction_get_output_at", + "params": { + "transaction": { + "ref": "$tx" + }, + "output_index": 0 + }, + "ref": "$out0" + }, + "expected_response": { + "result": { + "ref": "$out0" + } + } + }, + { + "description": "Verifies the amount from the indexed output", + "request": { + "id": "transaction#13", + "method": "btck_transaction_output_get_amount", + "params": { + "transaction_output": { + "ref": "$out0" + } + } + }, + "expected_response": { + "result": 5000000000 + } + }, + { + "description": "Copies the transaction", + "request": { + "id": "transaction#14", + "method": "btck_transaction_copy", + "params": { + "transaction": { + "ref": "$tx" + } + }, + "ref": "$tx_copy" + }, + "expected_response": { + "result": { + "ref": "$tx_copy" + } + } + }, + { + "description": "Verifies copied transaction serialization matches the original bytes", + "request": { + "id": "transaction#15", + "method": "btck_transaction_to_bytes", + "params": { + "transaction": { + "ref": "$tx_copy" + } + } + }, + "expected_response": { + "result": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + } + }, + { + "description": "Gets the txid of the copied transaction", + "request": { + "id": "transaction#16", + "method": "btck_transaction_get_txid", + "params": { + "transaction": { + "ref": "$tx_copy" + } + }, + "ref": "$tx_copy_txid" + }, + "expected_response": { + "result": { + "ref": "$tx_copy_txid" + } + } + }, + { + "description": "Verifies the txid of the copied transaction equals the original txid", + "request": { + "id": "transaction#17", + "method": "btck_txid_equals", + "params": { + "txid1": { + "ref": "$tx_txid" + }, + "txid2": { + "ref": "$tx_copy_txid" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the original transaction after comparing txids", + "request": { + "id": "transaction#18", + "method": "btck_transaction_destroy", + "params": { + "transaction": { + "ref": "$tx" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the copied transaction", + "request": { + "id": "transaction#19", + "method": "btck_transaction_destroy", + "params": { + "transaction": { + "ref": "$tx_copy" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/transaction_input.json b/testdata/transaction_input.json new file mode 100644 index 0000000..1198d49 --- /dev/null +++ b/testdata/transaction_input.json @@ -0,0 +1,252 @@ +{ + "title": "Transaction Input Operations", + "description": "Covers transaction input object access by index, out point getters, input copying, out point copying, and cleanup", + "stateful": true, + "tests": [ + { + "description": "Creates a transaction from raw bytes", + "request": { + "id": "transaction_input#1", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700" + }, + "ref": "$tx" + }, + "expected_response": { + "result": { + "ref": "$tx" + } + } + }, + { + "description": "Gets the first transaction input by index", + "request": { + "id": "transaction_input#2", + "method": "btck_transaction_get_input_at", + "params": { + "transaction": { + "ref": "$tx" + }, + "input_index": 0 + }, + "ref": "$in0" + }, + "expected_response": { + "result": { + "ref": "$in0" + } + } + }, + { + "description": "Gets the out point from the indexed input", + "request": { + "id": "transaction_input#3", + "method": "btck_transaction_input_get_out_point", + "params": { + "transaction_input": { + "ref": "$in0" + } + }, + "ref": "$op0" + }, + "expected_response": { + "result": { + "ref": "$op0" + } + } + }, + { + "description": "Verifies the out point index", + "request": { + "id": "transaction_input#4", + "method": "btck_transaction_out_point_get_index", + "params": { + "transaction_out_point": { + "ref": "$op0" + } + } + }, + "expected_response": { + "result": 0 + } + }, + { + "description": "Gets the txid from the out point", + "request": { + "id": "transaction_input#5", + "method": "btck_transaction_out_point_get_txid", + "params": { + "transaction_out_point": { + "ref": "$op0" + } + }, + "ref": "$op0_txid" + }, + "expected_response": { + "result": { + "ref": "$op0_txid" + } + } + }, + { + "description": "Verifies the serialized txid from the out point", + "request": { + "id": "transaction_input#6", + "method": "btck_txid_to_bytes", + "params": { + "txid": { + "ref": "$op0_txid" + } + } + }, + "expected_response": { + "result": "3f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95" + } + }, + { + "description": "Copies the transaction input", + "request": { + "id": "transaction_input#7", + "method": "btck_transaction_input_copy", + "params": { + "transaction_input": { + "ref": "$in0" + } + }, + "ref": "$in0_copy" + }, + "expected_response": { + "result": { + "ref": "$in0_copy" + } + } + }, + { + "description": "Gets the out point from the copied input", + "request": { + "id": "transaction_input#8", + "method": "btck_transaction_input_get_out_point", + "params": { + "transaction_input": { + "ref": "$in0_copy" + } + }, + "ref": "$op0_copy" + }, + "expected_response": { + "result": { + "ref": "$op0_copy" + } + } + }, + { + "description": "Verifies the copied input out point has the same index", + "request": { + "id": "transaction_input#9", + "method": "btck_transaction_out_point_get_index", + "params": { + "transaction_out_point": { + "ref": "$op0_copy" + } + } + }, + "expected_response": { + "result": 0 + } + }, + { + "description": "Destroys the copied transaction input", + "request": { + "id": "transaction_input#10", + "method": "btck_transaction_input_destroy", + "params": { + "transaction_input": { + "ref": "$in0_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Copies the original input out point", + "request": { + "id": "transaction_input#11", + "method": "btck_transaction_out_point_copy", + "params": { + "transaction_out_point": { + "ref": "$op0" + } + }, + "ref": "$op0_dup" + }, + "expected_response": { + "result": { + "ref": "$op0_dup" + } + } + }, + { + "description": "Gets the txid from the copied out point", + "request": { + "id": "transaction_input#12", + "method": "btck_transaction_out_point_get_txid", + "params": { + "transaction_out_point": { + "ref": "$op0_dup" + } + }, + "ref": "$op0_dup_txid" + }, + "expected_response": { + "result": { + "ref": "$op0_dup_txid" + } + } + }, + { + "description": "Verifies the txid from the copied out point equals the original txid", + "request": { + "id": "transaction_input#13", + "method": "btck_txid_equals", + "params": { + "txid1": { + "ref": "$op0_txid" + }, + "txid2": { + "ref": "$op0_dup_txid" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the copied out point after comparing txids", + "request": { + "id": "transaction_input#14", + "method": "btck_transaction_out_point_destroy", + "params": { + "transaction_out_point": { + "ref": "$op0_dup" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the transaction after comparing out point txids", + "request": { + "id": "transaction_input#15", + "method": "btck_transaction_destroy", + "params": { + "transaction": { + "ref": "$tx" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/transaction_output.json b/testdata/transaction_output.json new file mode 100644 index 0000000..ba72cce --- /dev/null +++ b/testdata/transaction_output.json @@ -0,0 +1,162 @@ +{ + "title": "Transaction Output Operations", + "description": "Covers transaction output object creation from a script pubkey and amount, amount and script getters, copying, and cleanup", + "stateful": true, + "tests": [ + { + "description": "Creates a script pubkey from raw bytes", + "request": { + "id": "transaction_output#1", + "method": "btck_script_pubkey_create", + "params": { + "script_pubkey": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + }, + "ref": "$spk" + }, + "expected_response": { + "result": { + "ref": "$spk" + } + } + }, + { + "description": "Creates a transaction output from the script pubkey and amount", + "request": { + "id": "transaction_output#2", + "method": "btck_transaction_output_create", + "params": { + "script_pubkey": { + "ref": "$spk" + }, + "amount": 5000000000 + }, + "ref": "$txout" + }, + "expected_response": { + "result": { + "ref": "$txout" + } + } + }, + { + "description": "Destroys the original script pubkey after output creation", + "request": { + "id": "transaction_output#3", + "method": "btck_script_pubkey_destroy", + "params": { + "script_pubkey": { + "ref": "$spk" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the transaction output amount", + "request": { + "id": "transaction_output#4", + "method": "btck_transaction_output_get_amount", + "params": { + "transaction_output": { + "ref": "$txout" + } + } + }, + "expected_response": { + "result": 5000000000 + } + }, + { + "description": "Gets the script pubkey from the transaction output", + "request": { + "id": "transaction_output#5", + "method": "btck_transaction_output_get_script_pubkey", + "params": { + "transaction_output": { + "ref": "$txout" + } + }, + "ref": "$txout_spk" + }, + "expected_response": { + "result": { + "ref": "$txout_spk" + } + } + }, + { + "description": "Verifies the output script pubkey serializes to the original bytes", + "request": { + "id": "transaction_output#6", + "method": "btck_script_pubkey_to_bytes", + "params": { + "script_pubkey": { + "ref": "$txout_spk" + } + } + }, + "expected_response": { + "result": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + } + }, + { + "description": "Copies the transaction output", + "request": { + "id": "transaction_output#7", + "method": "btck_transaction_output_copy", + "params": { + "transaction_output": { + "ref": "$txout" + } + }, + "ref": "$txout_copy" + }, + "expected_response": { + "result": { + "ref": "$txout_copy" + } + } + }, + { + "description": "Destroys the original transaction output after copying", + "request": { + "id": "transaction_output#8", + "method": "btck_transaction_output_destroy", + "params": { + "transaction_output": { + "ref": "$txout" + } + } + }, + "expected_response": {} + }, + { + "description": "Verifies the copied transaction output has the same amount", + "request": { + "id": "transaction_output#9", + "method": "btck_transaction_output_get_amount", + "params": { + "transaction_output": { + "ref": "$txout_copy" + } + } + }, + "expected_response": { + "result": 5000000000 + } + }, + { + "description": "Destroys the copied transaction output", + "request": { + "id": "transaction_output#10", + "method": "btck_transaction_output_destroy", + "params": { + "transaction_output": { + "ref": "$txout_copy" + } + } + }, + "expected_response": {} + } + ] +} diff --git a/testdata/txid.json b/testdata/txid.json new file mode 100644 index 0000000..3c4a19d --- /dev/null +++ b/testdata/txid.json @@ -0,0 +1,201 @@ +{ + "title": "Txid Operations", + "description": "Covers txid objects returned from transactions, byte serialization, equality checks, copying, and cleanup", + "stateful": true, + "tests": [ + { + "description": "Creates the first transaction from raw bytes", + "request": { + "id": "txid#1", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" + }, + "ref": "$tx1" + }, + "expected_response": { + "result": { + "ref": "$tx1" + } + } + }, + { + "description": "Gets the txid from the first transaction", + "request": { + "id": "txid#2", + "method": "btck_transaction_get_txid", + "params": { + "transaction": { + "ref": "$tx1" + } + }, + "ref": "$txid1" + }, + "expected_response": { + "result": { + "ref": "$txid1" + } + } + }, + { + "description": "Verifies txid serialization round-trips to the original bytes", + "request": { + "id": "txid#3", + "method": "btck_txid_to_bytes", + "params": { + "txid": { + "ref": "$txid1" + } + } + }, + "expected_response": { + "result": "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a" + } + }, + { + "description": "Verifies a txid equals itself", + "request": { + "id": "txid#4", + "method": "btck_txid_equals", + "params": { + "txid1": { + "ref": "$txid1" + }, + "txid2": { + "ref": "$txid1" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Creates a second transaction for txid comparison", + "request": { + "id": "txid#5", + "method": "btck_transaction_create", + "params": { + "raw_transaction": "02000000000102761402258bf42275f52db288dbbc8fdfe30b35dea86c5425a57feef1a4008b0b0100000000ffffffff3847ba0ccc4e1b63ed2f3b4a677bd247940f4d5669cc91d9a4eb096e7615badc0000000000ffffffff0291ad070000000000225120059715a12766bbbee8529b53dce51fe708e9895f50c6babec988c7917ff5958464d11a0000000000225120bee1246f13735551e5e5c2b5631014501a6c77f8ee2d16d33dc109096f22b2a40140ac4e4af854be645890275c8144869343752d5ceee9b361cfab3de0726c10a449cc7491a295417f7c457961fdde59bde483330364b42fddddeef65cd1d97150fc0440b78c0a5065343d451a93dcb499edd3d8994697932322be5e27fa218f5a99be8484a8ef802c3054dee442baced3c170b8afe18ec9758c860876fe4f06a5e3ccb240984299fc968b71d999354af2e991e089908adec84e1b1f04da8149aa0ffce28311b363dfd2dfc456de77746919c263e95a14952080f433ddb87b13b884812bda4420b5095be39b9f2f96a77235854af7635dd09d0324569e9b3d587fe5fb7c44720cad202b74c2011af089c849383ee527c72325de52df6a788428b68d49e9174053aabaac41c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0675a94484b3d55d76af4a2275d327a47c1ec5c7d2232596a09fc883d40bb237e00000000" + }, + "ref": "$tx2" + }, + "expected_response": { + "result": { + "ref": "$tx2" + } + } + }, + { + "description": "Gets the txid from the second transaction", + "request": { + "id": "txid#6", + "method": "btck_transaction_get_txid", + "params": { + "transaction": { + "ref": "$tx2" + } + }, + "ref": "$txid2" + }, + "expected_response": { + "result": { + "ref": "$txid2" + } + } + }, + { + "description": "Verifies different txids are not equal", + "request": { + "id": "txid#7", + "method": "btck_txid_equals", + "params": { + "txid1": { + "ref": "$txid1" + }, + "txid2": { + "ref": "$txid2" + } + } + }, + "expected_response": { + "result": false + } + }, + { + "description": "Destroys the second transaction", + "request": { + "id": "txid#8", + "method": "btck_transaction_destroy", + "params": { + "transaction": { + "ref": "$tx2" + } + } + }, + "expected_response": {} + }, + { + "description": "Copies the first txid", + "request": { + "id": "txid#9", + "method": "btck_txid_copy", + "params": { + "txid": { + "ref": "$txid1" + } + }, + "ref": "$txid1_copy" + }, + "expected_response": { + "result": { + "ref": "$txid1_copy" + } + } + }, + { + "description": "Verifies the copied txid equals the original", + "request": { + "id": "txid#10", + "method": "btck_txid_equals", + "params": { + "txid1": { + "ref": "$txid1_copy" + }, + "txid2": { + "ref": "$txid1" + } + } + }, + "expected_response": { + "result": true + } + }, + { + "description": "Destroys the copied txid", + "request": { + "id": "txid#11", + "method": "btck_txid_destroy", + "params": { + "txid": { + "ref": "$txid1_copy" + } + } + }, + "expected_response": {} + }, + { + "description": "Destroys the first transaction", + "request": { + "id": "txid#12", + "method": "btck_transaction_destroy", + "params": { + "transaction": { + "ref": "$tx1" + } + } + }, + "expected_response": {} + } + ] +} From 66fbcdbb22166cecd1728cc11aaaac4f62fe006b Mon Sep 17 00:00:00 2001 From: stringintech Date: Tue, 12 May 2026 16:20:17 +0330 Subject: [PATCH 3/7] Introduce JSON schema files to validate test suites against Adds suite-schema.json which is used to validate each test suite in testdata dir against. Adds a separate schema file per method which is referenced by the root schema file suite-schema.json. Response schema files are also introduced separately (and referenced by their parent method schema file). This allows the runner to later only embed the response schemas for handler response validation. A validator command line tool is written in cmd/suite-validate which performs the testdata suites validation against the root schema and depends on a third party library (github.com/santhosh-tekuri/jsonschema/v6). Co-authored-by: janb84 --- Makefile | 10 +- cmd/suite-validate/main.go | 92 ++++++++ docs/schemas/btck_block_copy.json | 53 +++++ docs/schemas/btck_block_copy.response.json | 5 + .../btck_block_count_transactions.json | 52 +++++ ...tck_block_count_transactions.response.json | 5 + docs/schemas/btck_block_create.json | 53 +++++ docs/schemas/btck_block_create.response.json | 12 + docs/schemas/btck_block_destroy.json | 52 +++++ docs/schemas/btck_block_destroy.response.json | 4 + docs/schemas/btck_block_get_hash.json | 52 +++++ .../schemas/btck_block_get_hash.response.json | 5 + docs/schemas/btck_block_get_header.json | 52 +++++ .../btck_block_get_header.response.json | 5 + .../btck_block_get_transaction_at.json | 61 +++++ ...tck_block_get_transaction_at.response.json | 5 + docs/schemas/btck_block_hash_copy.json | 52 +++++ .../btck_block_hash_copy.response.json | 5 + docs/schemas/btck_block_hash_create.json | 52 +++++ .../btck_block_hash_create.response.json | 5 + docs/schemas/btck_block_hash_destroy.json | 52 +++++ .../btck_block_hash_destroy.response.json | 4 + docs/schemas/btck_block_hash_equals.json | 61 +++++ .../btck_block_hash_equals.response.json | 5 + docs/schemas/btck_block_hash_to_bytes.json | 52 +++++ .../btck_block_hash_to_bytes.response.json | 5 + docs/schemas/btck_block_header_copy.json | 52 +++++ .../btck_block_header_copy.response.json | 5 + docs/schemas/btck_block_header_create.json | 52 +++++ .../btck_block_header_create.response.json | 13 ++ docs/schemas/btck_block_header_destroy.json | 52 +++++ .../btck_block_header_destroy.response.json | 4 + docs/schemas/btck_block_header_get_bits.json | 52 +++++ .../btck_block_header_get_bits.response.json | 5 + docs/schemas/btck_block_header_get_hash.json | 52 +++++ .../btck_block_header_get_hash.response.json | 5 + docs/schemas/btck_block_header_get_nonce.json | 52 +++++ .../btck_block_header_get_nonce.response.json | 5 + .../btck_block_header_get_prev_hash.json | 52 +++++ ...k_block_header_get_prev_hash.response.json | 5 + .../btck_block_header_get_timestamp.json | 52 +++++ ...k_block_header_get_timestamp.response.json | 5 + .../btck_block_header_get_version.json | 52 +++++ ...tck_block_header_get_version.response.json | 5 + docs/schemas/btck_block_to_bytes.json | 52 +++++ .../schemas/btck_block_to_bytes.response.json | 5 + .../btck_block_tree_entry_get_block_hash.json | 52 +++++ ...ck_tree_entry_get_block_hash.response.json | 5 + docs/schemas/btck_chain_contains.json | 58 +++++ .../schemas/btck_chain_contains.response.json | 5 + docs/schemas/btck_chain_get_by_height.json | 63 +++++ .../btck_chain_get_by_height.response.json | 13 ++ docs/schemas/btck_chain_get_height.json | 49 ++++ .../btck_chain_get_height.response.json | 5 + .../btck_chainstate_manager_create.json | 53 +++++ ...ck_chainstate_manager_create.response.json | 12 + .../btck_chainstate_manager_destroy.json | 49 ++++ ...k_chainstate_manager_destroy.response.json | 4 + ...k_chainstate_manager_get_active_chain.json | 53 +++++ ...ate_manager_get_active_chain.response.json | 5 + ...btck_chainstate_manager_process_block.json | 58 +++++ ...nstate_manager_process_block.response.json | 33 +++ docs/schemas/btck_context_create.json | 68 ++++++ .../schemas/btck_context_create.response.json | 12 + docs/schemas/btck_context_destroy.json | 49 ++++ .../btck_context_destroy.response.json | 4 + ...k_precomputed_transaction_data_create.json | 64 +++++ ...uted_transaction_data_create.response.json | 12 + ..._precomputed_transaction_data_destroy.json | 49 ++++ ...ted_transaction_data_destroy.response.json | 4 + docs/schemas/btck_script_pubkey_copy.json | 52 +++++ .../btck_script_pubkey_copy.response.json | 5 + docs/schemas/btck_script_pubkey_create.json | 53 +++++ .../btck_script_pubkey_create.response.json | 5 + docs/schemas/btck_script_pubkey_destroy.json | 49 ++++ .../btck_script_pubkey_destroy.response.json | 4 + docs/schemas/btck_script_pubkey_to_bytes.json | 52 +++++ .../btck_script_pubkey_to_bytes.response.json | 5 + docs/schemas/btck_script_pubkey_verify.json | 96 ++++++++ .../btck_script_pubkey_verify.response.json | 47 ++++ docs/schemas/btck_transaction_copy.json | 52 +++++ .../btck_transaction_copy.response.json | 5 + .../btck_transaction_count_inputs.json | 52 +++++ ...tck_transaction_count_inputs.response.json | 5 + .../btck_transaction_count_outputs.json | 52 +++++ ...ck_transaction_count_outputs.response.json | 5 + docs/schemas/btck_transaction_create.json | 53 +++++ .../btck_transaction_create.response.json | 12 + docs/schemas/btck_transaction_destroy.json | 49 ++++ .../btck_transaction_destroy.response.json | 4 + .../btck_transaction_get_input_at.json | 61 +++++ ...tck_transaction_get_input_at.response.json | 5 + .../btck_transaction_get_output_at.json | 61 +++++ ...ck_transaction_get_output_at.response.json | 5 + docs/schemas/btck_transaction_get_txid.json | 52 +++++ .../btck_transaction_get_txid.response.json | 5 + docs/schemas/btck_transaction_input_copy.json | 52 +++++ .../btck_transaction_input_copy.response.json | 5 + .../btck_transaction_input_destroy.json | 52 +++++ ...ck_transaction_input_destroy.response.json | 4 + .../btck_transaction_input_get_out_point.json | 52 +++++ ...nsaction_input_get_out_point.response.json | 5 + .../btck_transaction_out_point_copy.json | 52 +++++ ...k_transaction_out_point_copy.response.json | 5 + .../btck_transaction_out_point_destroy.json | 52 +++++ ...ransaction_out_point_destroy.response.json | 4 + .../btck_transaction_out_point_get_index.json | 52 +++++ ...nsaction_out_point_get_index.response.json | 5 + .../btck_transaction_out_point_get_txid.json | 52 +++++ ...ansaction_out_point_get_txid.response.json | 5 + .../schemas/btck_transaction_output_copy.json | 52 +++++ ...btck_transaction_output_copy.response.json | 5 + .../btck_transaction_output_create.json | 63 +++++ ...ck_transaction_output_create.response.json | 5 + .../btck_transaction_output_destroy.json | 49 ++++ ...k_transaction_output_destroy.response.json | 4 + .../btck_transaction_output_get_amount.json | 52 +++++ ...ransaction_output_get_amount.response.json | 5 + ..._transaction_output_get_script_pubkey.json | 52 +++++ ...ion_output_get_script_pubkey.response.json | 5 + docs/schemas/btck_transaction_to_bytes.json | 52 +++++ .../btck_transaction_to_bytes.response.json | 5 + docs/schemas/btck_txid_copy.json | 52 +++++ docs/schemas/btck_txid_copy.response.json | 5 + docs/schemas/btck_txid_destroy.json | 52 +++++ docs/schemas/btck_txid_destroy.response.json | 4 + docs/schemas/btck_txid_equals.json | 61 +++++ docs/schemas/btck_txid_equals.response.json | 5 + docs/schemas/btck_txid_to_bytes.json | 52 +++++ docs/schemas/btck_txid_to_bytes.response.json | 5 + docs/schemas/shared.json | 99 ++++++++ docs/schemas/suite-schema.json | 221 ++++++++++++++++++ go.mod | 7 +- go.sum | 6 + 134 files changed, 4324 insertions(+), 4 deletions(-) create mode 100644 cmd/suite-validate/main.go create mode 100644 docs/schemas/btck_block_copy.json create mode 100644 docs/schemas/btck_block_copy.response.json create mode 100644 docs/schemas/btck_block_count_transactions.json create mode 100644 docs/schemas/btck_block_count_transactions.response.json create mode 100644 docs/schemas/btck_block_create.json create mode 100644 docs/schemas/btck_block_create.response.json create mode 100644 docs/schemas/btck_block_destroy.json create mode 100644 docs/schemas/btck_block_destroy.response.json create mode 100644 docs/schemas/btck_block_get_hash.json create mode 100644 docs/schemas/btck_block_get_hash.response.json create mode 100644 docs/schemas/btck_block_get_header.json create mode 100644 docs/schemas/btck_block_get_header.response.json create mode 100644 docs/schemas/btck_block_get_transaction_at.json create mode 100644 docs/schemas/btck_block_get_transaction_at.response.json create mode 100644 docs/schemas/btck_block_hash_copy.json create mode 100644 docs/schemas/btck_block_hash_copy.response.json create mode 100644 docs/schemas/btck_block_hash_create.json create mode 100644 docs/schemas/btck_block_hash_create.response.json create mode 100644 docs/schemas/btck_block_hash_destroy.json create mode 100644 docs/schemas/btck_block_hash_destroy.response.json create mode 100644 docs/schemas/btck_block_hash_equals.json create mode 100644 docs/schemas/btck_block_hash_equals.response.json create mode 100644 docs/schemas/btck_block_hash_to_bytes.json create mode 100644 docs/schemas/btck_block_hash_to_bytes.response.json create mode 100644 docs/schemas/btck_block_header_copy.json create mode 100644 docs/schemas/btck_block_header_copy.response.json create mode 100644 docs/schemas/btck_block_header_create.json create mode 100644 docs/schemas/btck_block_header_create.response.json create mode 100644 docs/schemas/btck_block_header_destroy.json create mode 100644 docs/schemas/btck_block_header_destroy.response.json create mode 100644 docs/schemas/btck_block_header_get_bits.json create mode 100644 docs/schemas/btck_block_header_get_bits.response.json create mode 100644 docs/schemas/btck_block_header_get_hash.json create mode 100644 docs/schemas/btck_block_header_get_hash.response.json create mode 100644 docs/schemas/btck_block_header_get_nonce.json create mode 100644 docs/schemas/btck_block_header_get_nonce.response.json create mode 100644 docs/schemas/btck_block_header_get_prev_hash.json create mode 100644 docs/schemas/btck_block_header_get_prev_hash.response.json create mode 100644 docs/schemas/btck_block_header_get_timestamp.json create mode 100644 docs/schemas/btck_block_header_get_timestamp.response.json create mode 100644 docs/schemas/btck_block_header_get_version.json create mode 100644 docs/schemas/btck_block_header_get_version.response.json create mode 100644 docs/schemas/btck_block_to_bytes.json create mode 100644 docs/schemas/btck_block_to_bytes.response.json create mode 100644 docs/schemas/btck_block_tree_entry_get_block_hash.json create mode 100644 docs/schemas/btck_block_tree_entry_get_block_hash.response.json create mode 100644 docs/schemas/btck_chain_contains.json create mode 100644 docs/schemas/btck_chain_contains.response.json create mode 100644 docs/schemas/btck_chain_get_by_height.json create mode 100644 docs/schemas/btck_chain_get_by_height.response.json create mode 100644 docs/schemas/btck_chain_get_height.json create mode 100644 docs/schemas/btck_chain_get_height.response.json create mode 100644 docs/schemas/btck_chainstate_manager_create.json create mode 100644 docs/schemas/btck_chainstate_manager_create.response.json create mode 100644 docs/schemas/btck_chainstate_manager_destroy.json create mode 100644 docs/schemas/btck_chainstate_manager_destroy.response.json create mode 100644 docs/schemas/btck_chainstate_manager_get_active_chain.json create mode 100644 docs/schemas/btck_chainstate_manager_get_active_chain.response.json create mode 100644 docs/schemas/btck_chainstate_manager_process_block.json create mode 100644 docs/schemas/btck_chainstate_manager_process_block.response.json create mode 100644 docs/schemas/btck_context_create.json create mode 100644 docs/schemas/btck_context_create.response.json create mode 100644 docs/schemas/btck_context_destroy.json create mode 100644 docs/schemas/btck_context_destroy.response.json create mode 100644 docs/schemas/btck_precomputed_transaction_data_create.json create mode 100644 docs/schemas/btck_precomputed_transaction_data_create.response.json create mode 100644 docs/schemas/btck_precomputed_transaction_data_destroy.json create mode 100644 docs/schemas/btck_precomputed_transaction_data_destroy.response.json create mode 100644 docs/schemas/btck_script_pubkey_copy.json create mode 100644 docs/schemas/btck_script_pubkey_copy.response.json create mode 100644 docs/schemas/btck_script_pubkey_create.json create mode 100644 docs/schemas/btck_script_pubkey_create.response.json create mode 100644 docs/schemas/btck_script_pubkey_destroy.json create mode 100644 docs/schemas/btck_script_pubkey_destroy.response.json create mode 100644 docs/schemas/btck_script_pubkey_to_bytes.json create mode 100644 docs/schemas/btck_script_pubkey_to_bytes.response.json create mode 100644 docs/schemas/btck_script_pubkey_verify.json create mode 100644 docs/schemas/btck_script_pubkey_verify.response.json create mode 100644 docs/schemas/btck_transaction_copy.json create mode 100644 docs/schemas/btck_transaction_copy.response.json create mode 100644 docs/schemas/btck_transaction_count_inputs.json create mode 100644 docs/schemas/btck_transaction_count_inputs.response.json create mode 100644 docs/schemas/btck_transaction_count_outputs.json create mode 100644 docs/schemas/btck_transaction_count_outputs.response.json create mode 100644 docs/schemas/btck_transaction_create.json create mode 100644 docs/schemas/btck_transaction_create.response.json create mode 100644 docs/schemas/btck_transaction_destroy.json create mode 100644 docs/schemas/btck_transaction_destroy.response.json create mode 100644 docs/schemas/btck_transaction_get_input_at.json create mode 100644 docs/schemas/btck_transaction_get_input_at.response.json create mode 100644 docs/schemas/btck_transaction_get_output_at.json create mode 100644 docs/schemas/btck_transaction_get_output_at.response.json create mode 100644 docs/schemas/btck_transaction_get_txid.json create mode 100644 docs/schemas/btck_transaction_get_txid.response.json create mode 100644 docs/schemas/btck_transaction_input_copy.json create mode 100644 docs/schemas/btck_transaction_input_copy.response.json create mode 100644 docs/schemas/btck_transaction_input_destroy.json create mode 100644 docs/schemas/btck_transaction_input_destroy.response.json create mode 100644 docs/schemas/btck_transaction_input_get_out_point.json create mode 100644 docs/schemas/btck_transaction_input_get_out_point.response.json create mode 100644 docs/schemas/btck_transaction_out_point_copy.json create mode 100644 docs/schemas/btck_transaction_out_point_copy.response.json create mode 100644 docs/schemas/btck_transaction_out_point_destroy.json create mode 100644 docs/schemas/btck_transaction_out_point_destroy.response.json create mode 100644 docs/schemas/btck_transaction_out_point_get_index.json create mode 100644 docs/schemas/btck_transaction_out_point_get_index.response.json create mode 100644 docs/schemas/btck_transaction_out_point_get_txid.json create mode 100644 docs/schemas/btck_transaction_out_point_get_txid.response.json create mode 100644 docs/schemas/btck_transaction_output_copy.json create mode 100644 docs/schemas/btck_transaction_output_copy.response.json create mode 100644 docs/schemas/btck_transaction_output_create.json create mode 100644 docs/schemas/btck_transaction_output_create.response.json create mode 100644 docs/schemas/btck_transaction_output_destroy.json create mode 100644 docs/schemas/btck_transaction_output_destroy.response.json create mode 100644 docs/schemas/btck_transaction_output_get_amount.json create mode 100644 docs/schemas/btck_transaction_output_get_amount.response.json create mode 100644 docs/schemas/btck_transaction_output_get_script_pubkey.json create mode 100644 docs/schemas/btck_transaction_output_get_script_pubkey.response.json create mode 100644 docs/schemas/btck_transaction_to_bytes.json create mode 100644 docs/schemas/btck_transaction_to_bytes.response.json create mode 100644 docs/schemas/btck_txid_copy.json create mode 100644 docs/schemas/btck_txid_copy.response.json create mode 100644 docs/schemas/btck_txid_destroy.json create mode 100644 docs/schemas/btck_txid_destroy.response.json create mode 100644 docs/schemas/btck_txid_equals.json create mode 100644 docs/schemas/btck_txid_equals.response.json create mode 100644 docs/schemas/btck_txid_to_bytes.json create mode 100644 docs/schemas/btck_txid_to_bytes.response.json create mode 100644 docs/schemas/shared.json create mode 100644 docs/schemas/suite-schema.json diff --git a/Makefile b/Makefile index 37c99fb..689d9cd 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -.PHONY: all build test clean runner mock-handler +.PHONY: all build test clean runner mock-handler suite-validate BUILD_DIR := build RUNNER_BIN := $(BUILD_DIR)/runner MOCK_HANDLER_BIN := $(BUILD_DIR)/mock-handler -all: build test +all: build test suite-validate build: runner mock-handler @@ -18,12 +18,16 @@ mock-handler: @mkdir -p $(BUILD_DIR) go build -o $(MOCK_HANDLER_BIN) ./cmd/mock-handler -test: +test: build @echo "Running runner unit tests..." go test -v ./runner/... @echo "Running conformance tests with mock handler..." $(RUNNER_BIN) --handler $(MOCK_HANDLER_BIN) -vv +suite-validate: + @echo "Validating testdata against the suite schema..." + go run ./cmd/suite-validate + clean: @echo "Cleaning build artifacts..." rm -rf $(BUILD_DIR) diff --git a/cmd/suite-validate/main.go b/cmd/suite-validate/main.go new file mode 100644 index 0000000..0f8fcb9 --- /dev/null +++ b/cmd/suite-validate/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/santhosh-tekuri/jsonschema/v6" +) + +func main() { + if err := validateSuiteDir("docs/schemas/suite-schema.json", "testdata"); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// validateSuiteDir validates every JSON test suite in testdataDir against the +// suite schema in schemaPath. +func validateSuiteDir(schemaPath, testdataDir string) error { + paths, err := filepath.Glob(filepath.Join(testdataDir, "*.json")) + if err != nil { + return err + } + if len(paths) == 0 { + return fmt.Errorf("%s: no JSON suite files found", testdataDir) + } + return validateSuiteFiles(schemaPath, paths) +} + +// validateSuiteFiles validates JSON test suites against the suite schema. +func validateSuiteFiles(schemaPath string, suitePaths []string) error { + if len(suitePaths) == 0 { + return errors.New("no JSON suite files provided") + } + + abs, err := filepath.Abs(schemaPath) + if err != nil { + return err + } + c := jsonschema.NewCompiler() + schema, err := c.Compile(abs) + if err != nil { + return err + } + + var validationErrs suiteValidationErrors + for _, path := range suitePaths { + if err := validateSuiteFile(schema, path); err != nil { + validationErrs = append(validationErrs, suiteValidationError{ + Path: path, + Err: err, + }) + } + } + if len(validationErrs) > 0 { + return validationErrs + } + return nil +} + +func validateSuiteFile(schema *jsonschema.Schema, path string) error { + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + doc, err := jsonschema.UnmarshalJSON(f) + if err != nil { + return err + } + return schema.Validate(doc) +} + +type suiteValidationError struct { + Path string + Err error +} + +type suiteValidationErrors []suiteValidationError + +func (e suiteValidationErrors) Error() string { + var b strings.Builder + fmt.Fprintf(&b, "%d suite validation error(s):", len(e)) + for _, suiteErr := range e { + fmt.Fprintf(&b, "\n%s: %v", suiteErr.Path, suiteErr.Err) + } + return b.String() +} diff --git a/docs/schemas/btck_block_copy.json b/docs/schemas/btck_block_copy.json new file mode 100644 index 0000000..115bb7c --- /dev/null +++ b/docs/schemas/btck_block_copy.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "block" + ], + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_copy.response.json b/docs/schemas/btck_block_copy.response.json new file mode 100644 index 0000000..f1034b7 --- /dev/null +++ b/docs/schemas/btck_block_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied block (e.g., `{\"ref\": \"$block_copy\"}`)" +} diff --git a/docs/schemas/btck_block_count_transactions.json b/docs/schemas/btck_block_count_transactions.json new file mode 100644 index 0000000..af6eda9 --- /dev/null +++ b/docs/schemas/btck_block_count_transactions.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the number of transactions in a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_count_transactions" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + }, + "required": [ + "block" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_count_transactions.response.json" + } + } +} diff --git a/docs/schemas/btck_block_count_transactions.response.json b/docs/schemas/btck_block_count_transactions.response.json new file mode 100644 index 0000000..2af8fe4 --- /dev/null +++ b/docs/schemas/btck_block_count_transactions.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The transaction count" +} diff --git a/docs/schemas/btck_block_create.json b/docs/schemas/btck_block_create.json new file mode 100644 index 0000000..e7a7713 --- /dev/null +++ b/docs/schemas/btck_block_create.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a block object from raw block data", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "raw_block" + ], + "properties": { + "raw_block": { + "$ref": "./shared.json#/$defs/HexString", + "description": "Hex-encoded raw block data" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_create.response.json" + } + } +} diff --git a/docs/schemas/btck_block_create.response.json b/docs/schemas/btck_block_create.response.json new file mode 100644 index 0000000..ce5af0f --- /dev/null +++ b/docs/schemas/btck_block_create.response.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created block (e.g., `{\"ref\": \"$block\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_block_destroy.json b/docs/schemas/btck_block_destroy.json new file mode 100644 index 0000000..dbeb3a9 --- /dev/null +++ b/docs/schemas/btck_block_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference to destroy" + } + }, + "required": [ + "block" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_destroy.response.json b/docs/schemas/btck_block_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_block_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_block_get_hash.json b/docs/schemas/btck_block_get_hash.json new file mode 100644 index 0000000..407960f --- /dev/null +++ b/docs/schemas/btck_block_get_hash.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the hash of a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_get_hash" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + }, + "required": [ + "block" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_get_hash.response.json" + } + } +} diff --git a/docs/schemas/btck_block_get_hash.response.json b/docs/schemas/btck_block_get_hash.response.json new file mode 100644 index 0000000..84fb5fe --- /dev/null +++ b/docs/schemas/btck_block_get_hash.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned block hash (e.g., `{\"ref\": \"$block_hash\"}`)" +} diff --git a/docs/schemas/btck_block_get_header.json b/docs/schemas/btck_block_get_header.json new file mode 100644 index 0000000..faf70e0 --- /dev/null +++ b/docs/schemas/btck_block_get_header.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the block header from a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_get_header" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + }, + "required": [ + "block" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_get_header.response.json" + } + } +} diff --git a/docs/schemas/btck_block_get_header.response.json b/docs/schemas/btck_block_get_header.response.json new file mode 100644 index 0000000..5002bae --- /dev/null +++ b/docs/schemas/btck_block_get_header.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned block header (e.g., `{\"ref\": \"$header\"}`). The returned block header reference depends on the lifetime of the parent block and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_block_get_transaction_at.json b/docs/schemas/btck_block_get_transaction_at.json new file mode 100644 index 0000000..d2dc426 --- /dev/null +++ b/docs/schemas/btck_block_get_transaction_at.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Retrieves the transaction at the given index from a block", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_get_transaction_at" + }, + "params": { + "type": "object", + "x-doc-order": [ + "block", + "transaction_index" + ], + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + }, + "transaction_index": { + "type": "integer", + "description": "Zero-based transaction index" + } + }, + "required": [ + "block", + "transaction_index" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_get_transaction_at.response.json" + } + } +} diff --git a/docs/schemas/btck_block_get_transaction_at.response.json b/docs/schemas/btck_block_get_transaction_at.response.json new file mode 100644 index 0000000..bb66451 --- /dev/null +++ b/docs/schemas/btck_block_get_transaction_at.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned transaction (e.g., `{\"ref\": \"$transaction\"}`). The returned transaction reference depends on the lifetime of the parent block and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_block_hash_copy.json b/docs/schemas/btck_block_hash_copy.json new file mode 100644 index 0000000..d3ae5f1 --- /dev/null +++ b/docs/schemas/btck_block_hash_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a block hash", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_hash_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block_hash": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block hash reference" + } + }, + "required": [ + "block_hash" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_hash_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_hash_copy.response.json b/docs/schemas/btck_block_hash_copy.response.json new file mode 100644 index 0000000..78fc527 --- /dev/null +++ b/docs/schemas/btck_block_hash_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied block hash (e.g., `{\"ref\": \"$block_hash_copy\"}`)" +} diff --git a/docs/schemas/btck_block_hash_create.json b/docs/schemas/btck_block_hash_create.json new file mode 100644 index 0000000..bfe1d6f --- /dev/null +++ b/docs/schemas/btck_block_hash_create.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a block hash object from raw 32-byte block hash data", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_hash_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block_hash": { + "$ref": "./shared.json#/$defs/HexString", + "description": "Hex-encoded raw 32-byte block hash data" + } + }, + "required": [ + "block_hash" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_hash_create.response.json" + } + } +} diff --git a/docs/schemas/btck_block_hash_create.response.json b/docs/schemas/btck_block_hash_create.response.json new file mode 100644 index 0000000..2abb63e --- /dev/null +++ b/docs/schemas/btck_block_hash_create.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created block hash (e.g., `{\"ref\": \"$block_hash\"}`)" +} diff --git a/docs/schemas/btck_block_hash_destroy.json b/docs/schemas/btck_block_hash_destroy.json new file mode 100644 index 0000000..f0e00d8 --- /dev/null +++ b/docs/schemas/btck_block_hash_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a block hash", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_hash_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block_hash": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block hash reference to destroy" + } + }, + "required": [ + "block_hash" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_hash_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_hash_destroy.response.json b/docs/schemas/btck_block_hash_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_block_hash_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_block_hash_equals.json b/docs/schemas/btck_block_hash_equals.json new file mode 100644 index 0000000..f84ee7d --- /dev/null +++ b/docs/schemas/btck_block_hash_equals.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Checks if two block hashes are equal", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_hash_equals" + }, + "params": { + "type": "object", + "x-doc-order": [ + "hash1", + "hash2" + ], + "additionalProperties": false, + "properties": { + "hash1": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "First block hash reference" + }, + "hash2": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Second block hash reference" + } + }, + "required": [ + "hash1", + "hash2" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_hash_equals.response.json" + } + } +} diff --git a/docs/schemas/btck_block_hash_equals.response.json b/docs/schemas/btck_block_hash_equals.response.json new file mode 100644 index 0000000..b2f8710 --- /dev/null +++ b/docs/schemas/btck_block_hash_equals.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/BooleanResponse", + "description": "`true` if the hashes are equal" +} diff --git a/docs/schemas/btck_block_hash_to_bytes.json b/docs/schemas/btck_block_hash_to_bytes.json new file mode 100644 index 0000000..a9a9948 --- /dev/null +++ b/docs/schemas/btck_block_hash_to_bytes.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the raw 32-byte block hash as a hex string", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_hash_to_bytes" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block_hash": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block hash reference" + } + }, + "required": [ + "block_hash" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_hash_to_bytes.response.json" + } + } +} diff --git a/docs/schemas/btck_block_hash_to_bytes.response.json b/docs/schemas/btck_block_hash_to_bytes.response.json new file mode 100644 index 0000000..b1e271b --- /dev/null +++ b/docs/schemas/btck_block_hash_to_bytes.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/Hex64StringResponse", + "description": "Hex-encoded raw 32-byte block hash data" +} diff --git a/docs/schemas/btck_block_header_copy.json b/docs/schemas/btck_block_header_copy.json new file mode 100644 index 0000000..3cf966c --- /dev/null +++ b/docs/schemas/btck_block_header_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_copy.response.json b/docs/schemas/btck_block_header_copy.response.json new file mode 100644 index 0000000..3587556 --- /dev/null +++ b/docs/schemas/btck_block_header_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied block header (e.g., `{\"ref\": \"$header_copy\"}`)" +} diff --git a/docs/schemas/btck_block_header_create.json b/docs/schemas/btck_block_header_create.json new file mode 100644 index 0000000..7473c53 --- /dev/null +++ b/docs/schemas/btck_block_header_create.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a block header object from raw serialized header data", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "raw_block_header": { + "type": "string", + "description": "Hex-encoded raw block header data. At least 80 bytes are required; if additional bytes are provided, only the first 80 bytes are used to create the header." + } + }, + "required": [ + "raw_block_header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_create.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_create.response.json b/docs/schemas/btck_block_header_create.response.json new file mode 100644 index 0000000..cf0606c --- /dev/null +++ b/docs/schemas/btck_block_header_create.response.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created block header (e.g., `{\"ref\": \"$header\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse", + "description": "`{}` if fewer than 80 bytes are provided for the serialized block header" + } + ] +} diff --git a/docs/schemas/btck_block_header_destroy.json b/docs/schemas/btck_block_header_destroy.json new file mode 100644 index 0000000..9d5512d --- /dev/null +++ b/docs/schemas/btck_block_header_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference to destroy" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_destroy.response.json b/docs/schemas/btck_block_header_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_block_header_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_block_header_get_bits.json b/docs/schemas/btck_block_header_get_bits.json new file mode 100644 index 0000000..50c6acd --- /dev/null +++ b/docs/schemas/btck_block_header_get_bits.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the nBits difficulty target of a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_bits" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_bits.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_bits.response.json b/docs/schemas/btck_block_header_get_bits.response.json new file mode 100644 index 0000000..8f40d00 --- /dev/null +++ b/docs/schemas/btck_block_header_get_bits.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The nBits value" +} diff --git a/docs/schemas/btck_block_header_get_hash.json b/docs/schemas/btck_block_header_get_hash.json new file mode 100644 index 0000000..02967e7 --- /dev/null +++ b/docs/schemas/btck_block_header_get_hash.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the hash of a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_hash" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_hash.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_hash.response.json b/docs/schemas/btck_block_header_get_hash.response.json new file mode 100644 index 0000000..84fb5fe --- /dev/null +++ b/docs/schemas/btck_block_header_get_hash.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned block hash (e.g., `{\"ref\": \"$block_hash\"}`)" +} diff --git a/docs/schemas/btck_block_header_get_nonce.json b/docs/schemas/btck_block_header_get_nonce.json new file mode 100644 index 0000000..83caca0 --- /dev/null +++ b/docs/schemas/btck_block_header_get_nonce.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the nonce of a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_nonce" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_nonce.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_nonce.response.json b/docs/schemas/btck_block_header_get_nonce.response.json new file mode 100644 index 0000000..2d0697e --- /dev/null +++ b/docs/schemas/btck_block_header_get_nonce.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The nonce value" +} diff --git a/docs/schemas/btck_block_header_get_prev_hash.json b/docs/schemas/btck_block_header_get_prev_hash.json new file mode 100644 index 0000000..9e111c6 --- /dev/null +++ b/docs/schemas/btck_block_header_get_prev_hash.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the previous block hash from a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_prev_hash" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_prev_hash.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_prev_hash.response.json b/docs/schemas/btck_block_header_get_prev_hash.response.json new file mode 100644 index 0000000..4dabeb7 --- /dev/null +++ b/docs/schemas/btck_block_header_get_prev_hash.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned previous block hash (e.g., `{\"ref\": \"$prev_hash\"}`). The returned block hash reference depends on the lifetime of the parent block header and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_block_header_get_timestamp.json b/docs/schemas/btck_block_header_get_timestamp.json new file mode 100644 index 0000000..bc1c57b --- /dev/null +++ b/docs/schemas/btck_block_header_get_timestamp.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the timestamp of a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_timestamp" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_timestamp.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_timestamp.response.json b/docs/schemas/btck_block_header_get_timestamp.response.json new file mode 100644 index 0000000..f03ae7f --- /dev/null +++ b/docs/schemas/btck_block_header_get_timestamp.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The block timestamp as a Unix timestamp" +} diff --git a/docs/schemas/btck_block_header_get_version.json b/docs/schemas/btck_block_header_get_version.json new file mode 100644 index 0000000..ba87daf --- /dev/null +++ b/docs/schemas/btck_block_header_get_version.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the version field of a block header", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_header_get_version" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "header": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block header reference" + } + }, + "required": [ + "header" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_header_get_version.response.json" + } + } +} diff --git a/docs/schemas/btck_block_header_get_version.response.json b/docs/schemas/btck_block_header_get_version.response.json new file mode 100644 index 0000000..9061496 --- /dev/null +++ b/docs/schemas/btck_block_header_get_version.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The block version" +} diff --git a/docs/schemas/btck_block_to_bytes.json b/docs/schemas/btck_block_to_bytes.json new file mode 100644 index 0000000..20719ea --- /dev/null +++ b/docs/schemas/btck_block_to_bytes.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the consensus-serialized block as a hex string", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_to_bytes" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + }, + "required": [ + "block" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_to_bytes.response.json" + } + } +} diff --git a/docs/schemas/btck_block_to_bytes.response.json b/docs/schemas/btck_block_to_bytes.response.json new file mode 100644 index 0000000..9da1c9e --- /dev/null +++ b/docs/schemas/btck_block_to_bytes.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/HexStringResponse", + "description": "Hex-encoded consensus serialization of the block" +} diff --git a/docs/schemas/btck_block_tree_entry_get_block_hash.json b/docs/schemas/btck_block_tree_entry_get_block_hash.json new file mode 100644 index 0000000..6378fdd --- /dev/null +++ b/docs/schemas/btck_block_tree_entry_get_block_hash.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the block hash from a block tree entry", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_block_tree_entry_get_block_hash" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "block_tree_entry" + ], + "properties": { + "block_tree_entry": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block tree entry reference from `btck_chain_get_by_height`" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_block_tree_entry_get_block_hash.response.json" + } + } +} diff --git a/docs/schemas/btck_block_tree_entry_get_block_hash.response.json b/docs/schemas/btck_block_tree_entry_get_block_hash.response.json new file mode 100644 index 0000000..70cfefe --- /dev/null +++ b/docs/schemas/btck_block_tree_entry_get_block_hash.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned block hash (e.g., `{\"ref\": \"$block_hash\"}`). The returned block hash reference is a view that depends on the lifetime of the parent block tree entry and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_chain_contains.json b/docs/schemas/btck_chain_contains.json new file mode 100644 index 0000000..4c5c861 --- /dev/null +++ b/docs/schemas/btck_chain_contains.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Checks whether a block tree entry is part of the active chain", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chain_contains" + }, + "params": { + "type": "object", + "x-doc-order": [ + "chain", + "block_tree_entry" + ], + "additionalProperties": false, + "required": [ + "chain", + "block_tree_entry" + ], + "properties": { + "chain": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chain reference" + }, + "block_tree_entry": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block tree entry reference to check" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_chain_contains.response.json" + } + } +} diff --git a/docs/schemas/btck_chain_contains.response.json b/docs/schemas/btck_chain_contains.response.json new file mode 100644 index 0000000..4c03b60 --- /dev/null +++ b/docs/schemas/btck_chain_contains.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/BooleanResponse", + "description": "true if block is in the active chain, false otherwise" +} diff --git a/docs/schemas/btck_chain_get_by_height.json b/docs/schemas/btck_chain_get_by_height.json new file mode 100644 index 0000000..97aa9de --- /dev/null +++ b/docs/schemas/btck_chain_get_by_height.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Retrieves a block tree entry at a specific height in the chain", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chain_get_by_height" + }, + "params": { + "type": "object", + "x-doc-order": [ + "chain", + "block_height" + ], + "additionalProperties": false, + "required": [ + "chain", + "block_height" + ], + "properties": { + "chain": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chain reference" + }, + "block_height": { + "type": "integer", + "minimum": 0, + "description": "Height to query" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_chain_get_by_height.response.json" + } + } +} diff --git a/docs/schemas/btck_chain_get_by_height.response.json b/docs/schemas/btck_chain_get_by_height.response.json new file mode 100644 index 0000000..92f2842 --- /dev/null +++ b/docs/schemas/btck_chain_get_by_height.response.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned block tree entry (e.g., `{\"ref\": \"$block_tree_entry\"}`). The returned block tree entry reference depends on the lifetime of the parent chain reference and does not require an explicit destroy call." + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse", + "description": "`{}` if the requested height is out of bounds" + } + ] +} diff --git a/docs/schemas/btck_chain_get_height.json b/docs/schemas/btck_chain_get_height.json new file mode 100644 index 0000000..5c1da90 --- /dev/null +++ b/docs/schemas/btck_chain_get_height.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the current height of the active chain", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chain_get_height" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "chain" + ], + "properties": { + "chain": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chain reference from `btck_chainstate_manager_get_active_chain`" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_chain_get_height.response.json" + } + } +} diff --git a/docs/schemas/btck_chain_get_height.response.json b/docs/schemas/btck_chain_get_height.response.json new file mode 100644 index 0000000..08fa455 --- /dev/null +++ b/docs/schemas/btck_chain_get_height.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The chain height (0 = genesis)" +} diff --git a/docs/schemas/btck_chainstate_manager_create.json b/docs/schemas/btck_chainstate_manager_create.json new file mode 100644 index 0000000..820ce85 --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_create.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a chainstate manager from a context", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chainstate_manager_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "context" + ], + "properties": { + "context": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Context reference from `btck_context_create`" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_chainstate_manager_create.response.json" + } + } +} diff --git a/docs/schemas/btck_chainstate_manager_create.response.json b/docs/schemas/btck_chainstate_manager_create.response.json new file mode 100644 index 0000000..f653cc9 --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_create.response.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created chainstate manager (e.g., `{\"ref\": \"$chainstate_manager\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_chainstate_manager_destroy.json b/docs/schemas/btck_chainstate_manager_destroy.json new file mode 100644 index 0000000..901f41a --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a chainstate manager and frees associated resources", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chainstate_manager_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "chainstate_manager" + ], + "properties": { + "chainstate_manager": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chainstate manager reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_chainstate_manager_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_chainstate_manager_destroy.response.json b/docs/schemas/btck_chainstate_manager_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_chainstate_manager_get_active_chain.json b/docs/schemas/btck_chainstate_manager_get_active_chain.json new file mode 100644 index 0000000..a57c76d --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_get_active_chain.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Retrieves the currently active chain from the chainstate manager", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chainstate_manager_get_active_chain" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "chainstate_manager" + ], + "properties": { + "chainstate_manager": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chainstate manager reference" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_chainstate_manager_get_active_chain.response.json" + } + } +} diff --git a/docs/schemas/btck_chainstate_manager_get_active_chain.response.json b/docs/schemas/btck_chainstate_manager_get_active_chain.response.json new file mode 100644 index 0000000..e76078d --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_get_active_chain.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned active chain (e.g., `{\"ref\": \"$chain\"}`). The returned chain reference depends on the lifetime of the parent chainstate manager and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_chainstate_manager_process_block.json b/docs/schemas/btck_chainstate_manager_process_block.json new file mode 100644 index 0000000..0104122 --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_process_block.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Processes a block through validation checks, disk storage, and UTXO set validation; successful processing does not indicate block validity", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_chainstate_manager_process_block" + }, + "params": { + "type": "object", + "x-doc-order": [ + "chainstate_manager", + "block" + ], + "additionalProperties": false, + "required": [ + "chainstate_manager", + "block" + ], + "properties": { + "chainstate_manager": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Chainstate manager reference" + }, + "block": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Block reference from `btck_block_create`" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_chainstate_manager_process_block.response.json" + } + } +} diff --git a/docs/schemas/btck_chainstate_manager_process_block.response.json b/docs/schemas/btck_chainstate_manager_process_block.response.json new file mode 100644 index 0000000..3d79fa0 --- /dev/null +++ b/docs/schemas/btck_chainstate_manager_process_block.response.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "result" + ], + "properties": { + "result": { + "type": "object", + "additionalProperties": false, + "required": [ + "new_block" + ], + "properties": { + "new_block": { + "type": "boolean" + } + } + }, + "error": { + "type": "null" + } + }, + "description": "Object containing:\n- `new_block` (boolean): `true` if this block was not processed before, `false` otherwise" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_context_create.json b/docs/schemas/btck_context_create.json new file mode 100644 index 0000000..a31541f --- /dev/null +++ b/docs/schemas/btck_context_create.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a context with specified chain parameters", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_context_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "chain_parameters" + ], + "properties": { + "chain_parameters": { + "type": "object", + "additionalProperties": false, + "required": [ + "chain_type" + ], + "properties": { + "chain_type": { + "enum": [ + "btck_ChainType_MAINNET", + "btck_ChainType_TESTNET", + "btck_ChainType_TESTNET_4", + "btck_ChainType_SIGNET", + "btck_ChainType_REGTEST" + ], + "description": "Chain type" + } + } + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_context_create.response.json" + } + } +} diff --git a/docs/schemas/btck_context_create.response.json b/docs/schemas/btck_context_create.response.json new file mode 100644 index 0000000..6847e9d --- /dev/null +++ b/docs/schemas/btck_context_create.response.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created context (e.g., `{\"ref\": \"$context\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_context_destroy.json b/docs/schemas/btck_context_destroy.json new file mode 100644 index 0000000..0125894 --- /dev/null +++ b/docs/schemas/btck_context_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a context and frees associated resources", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_context_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "context" + ], + "properties": { + "context": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Context reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_context_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_context_destroy.response.json b/docs/schemas/btck_context_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_context_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_precomputed_transaction_data_create.json b/docs/schemas/btck_precomputed_transaction_data_create.json new file mode 100644 index 0000000..0f203dc --- /dev/null +++ b/docs/schemas/btck_precomputed_transaction_data_create.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates precomputed transaction data for script verification. Precomputed data is reusable when verifying multiple inputs of the same transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_precomputed_transaction_data_create" + }, + "params": { + "type": "object", + "x-doc-order": [ + "tx_to", + "spent_outputs" + ], + "additionalProperties": false, + "required": [ + "tx_to" + ], + "properties": { + "tx_to": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Reference to a Transaction from `btck_transaction_create`" + }, + "spent_outputs": { + "type": "array", + "items": { + "$ref": "./shared.json#/$defs/RefObject" + }, + "description": "Array of references to TransactionOutput objects from `btck_transaction_output_create`. Required when `btck_ScriptVerificationFlags_TAPROOT` is set" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_precomputed_transaction_data_create.response.json" + } + } +} diff --git a/docs/schemas/btck_precomputed_transaction_data_create.response.json b/docs/schemas/btck_precomputed_transaction_data_create.response.json new file mode 100644 index 0000000..8583a15 --- /dev/null +++ b/docs/schemas/btck_precomputed_transaction_data_create.response.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created precomputed transaction data (e.g., `{\"ref\": \"$precomputed_txdata\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_precomputed_transaction_data_destroy.json b/docs/schemas/btck_precomputed_transaction_data_destroy.json new file mode 100644 index 0000000..338cdc7 --- /dev/null +++ b/docs/schemas/btck_precomputed_transaction_data_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys precomputed transaction data and frees associated resources", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_precomputed_transaction_data_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "precomputed_txdata" + ], + "properties": { + "precomputed_txdata": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Precomputed transaction data reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_precomputed_transaction_data_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_precomputed_transaction_data_destroy.response.json b/docs/schemas/btck_precomputed_transaction_data_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_precomputed_transaction_data_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_script_pubkey_copy.json b/docs/schemas/btck_script_pubkey_copy.json new file mode 100644 index 0000000..453156c --- /dev/null +++ b/docs/schemas/btck_script_pubkey_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a script pubkey", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_script_pubkey_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Script pubkey reference" + } + }, + "required": [ + "script_pubkey" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_script_pubkey_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_script_pubkey_copy.response.json b/docs/schemas/btck_script_pubkey_copy.response.json new file mode 100644 index 0000000..76e41a1 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied script pubkey (e.g., `{\"ref\": \"$script_pubkey_copy\"}`)" +} diff --git a/docs/schemas/btck_script_pubkey_create.json b/docs/schemas/btck_script_pubkey_create.json new file mode 100644 index 0000000..3764782 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_create.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a script pubkey object from hex-encoded data", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_script_pubkey_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "script_pubkey" + ], + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/HexString", + "description": "Hex-encoded script pubkey data" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_script_pubkey_create.response.json" + } + } +} diff --git a/docs/schemas/btck_script_pubkey_create.response.json b/docs/schemas/btck_script_pubkey_create.response.json new file mode 100644 index 0000000..62ad967 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_create.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created script pubkey (e.g., `{\"ref\": \"$script_pubkey\"}`)" +} diff --git a/docs/schemas/btck_script_pubkey_destroy.json b/docs/schemas/btck_script_pubkey_destroy.json new file mode 100644 index 0000000..fe0b23a --- /dev/null +++ b/docs/schemas/btck_script_pubkey_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a script pubkey and frees associated resources", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_script_pubkey_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "script_pubkey" + ], + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Script pubkey reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_script_pubkey_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_script_pubkey_destroy.response.json b/docs/schemas/btck_script_pubkey_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_script_pubkey_to_bytes.json b/docs/schemas/btck_script_pubkey_to_bytes.json new file mode 100644 index 0000000..3624b19 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_to_bytes.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Serializes a script pubkey to raw bytes encoded as hex", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_script_pubkey_to_bytes" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Script pubkey reference" + } + }, + "required": [ + "script_pubkey" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_script_pubkey_to_bytes.response.json" + } + } +} diff --git a/docs/schemas/btck_script_pubkey_to_bytes.response.json b/docs/schemas/btck_script_pubkey_to_bytes.response.json new file mode 100644 index 0000000..5346777 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_to_bytes.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/HexStringResponse", + "description": "Hex-encoded serialized script pubkey bytes" +} diff --git a/docs/schemas/btck_script_pubkey_verify.json b/docs/schemas/btck_script_pubkey_verify.json new file mode 100644 index 0000000..5e2e0f3 --- /dev/null +++ b/docs/schemas/btck_script_pubkey_verify.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Verifies a script pubkey against spending conditions", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_script_pubkey_verify" + }, + "params": { + "type": "object", + "x-doc-order": [ + "script_pubkey", + "amount", + "tx_to", + "precomputed_txdata", + "input_index", + "flags" + ], + "additionalProperties": false, + "required": [ + "script_pubkey", + "amount", + "tx_to", + "input_index", + "flags" + ], + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Reference to a ScriptPubkey from `btck_script_pubkey_create`" + }, + "amount": { + "type": "number", + "minimum": 0, + "description": "Amount of the script pubkey's associated output. May be zero if the witness flag is not set" + }, + "tx_to": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Reference to a Transaction from `btck_transaction_create`" + }, + "precomputed_txdata": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Reference to PrecomputedTransactionData from `btck_precomputed_transaction_data_create`. Required when the taproot flag is set" + }, + "input_index": { + "type": "number", + "minimum": 0, + "description": "Index of the input in tx_to spending the script_pubkey" + }, + "flags": { + "type": "array", + "minItems": 1, + "items": { + "enum": [ + "btck_ScriptVerificationFlags_NONE", + "btck_ScriptVerificationFlags_P2SH", + "btck_ScriptVerificationFlags_DERSIG", + "btck_ScriptVerificationFlags_NULLDUMMY", + "btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY", + "btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY", + "btck_ScriptVerificationFlags_WITNESS", + "btck_ScriptVerificationFlags_TAPROOT" + ] + }, + "description": "Script verification flags controlling validation constraints" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_script_pubkey_verify.response.json" + } + } +} diff --git a/docs/schemas/btck_script_pubkey_verify.response.json b/docs/schemas/btck_script_pubkey_verify.response.json new file mode 100644 index 0000000..ddd48eb --- /dev/null +++ b/docs/schemas/btck_script_pubkey_verify.response.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/BooleanResponse", + "description": "true if script is valid, false if invalid" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "result": { + "type": "null" + }, + "error": { + "type": "object", + "additionalProperties": false, + "required": [ + "code" + ], + "properties": { + "code": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "member" + ], + "properties": { + "type": { + "const": "btck_ScriptVerifyStatus" + }, + "member": { + "enum": [ + "ERROR_INVALID_FLAGS_COMBINATION", + "ERROR_SPENT_OUTPUTS_REQUIRED" + ] + } + } + } + } + } + }, + "description": "On error, returns `{\"code\": {\"type\": \"btck_ScriptVerifyStatus\", \"member\": ...}}` where `member` can be one of:\n- `ERROR_INVALID_FLAGS_COMBINATION` - Invalid or inconsistent verification flags were provided. This occurs when the supplied `script_verify_flags` combination violates internal consistency rules.\n- `ERROR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required but were not provided (e.g., for Taproot verification)." + } + ] +} diff --git a/docs/schemas/btck_transaction_copy.json b/docs/schemas/btck_transaction_copy.json new file mode 100644 index 0000000..99c870a --- /dev/null +++ b/docs/schemas/btck_transaction_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + } + }, + "required": [ + "transaction" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_copy.response.json b/docs/schemas/btck_transaction_copy.response.json new file mode 100644 index 0000000..f86b3c8 --- /dev/null +++ b/docs/schemas/btck_transaction_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied transaction (e.g., `{\"ref\": \"$transaction_copy\"}`)" +} diff --git a/docs/schemas/btck_transaction_count_inputs.json b/docs/schemas/btck_transaction_count_inputs.json new file mode 100644 index 0000000..916d658 --- /dev/null +++ b/docs/schemas/btck_transaction_count_inputs.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the number of inputs in a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_count_inputs" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + } + }, + "required": [ + "transaction" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_count_inputs.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_count_inputs.response.json b/docs/schemas/btck_transaction_count_inputs.response.json new file mode 100644 index 0000000..ac93973 --- /dev/null +++ b/docs/schemas/btck_transaction_count_inputs.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The input count" +} diff --git a/docs/schemas/btck_transaction_count_outputs.json b/docs/schemas/btck_transaction_count_outputs.json new file mode 100644 index 0000000..6e4e514 --- /dev/null +++ b/docs/schemas/btck_transaction_count_outputs.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the number of outputs in a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_count_outputs" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + } + }, + "required": [ + "transaction" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_count_outputs.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_count_outputs.response.json b/docs/schemas/btck_transaction_count_outputs.response.json new file mode 100644 index 0000000..e76692c --- /dev/null +++ b/docs/schemas/btck_transaction_count_outputs.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The output count" +} diff --git a/docs/schemas/btck_transaction_create.json b/docs/schemas/btck_transaction_create.json new file mode 100644 index 0000000..bbe992b --- /dev/null +++ b/docs/schemas/btck_transaction_create.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a transaction object from raw hex-encoded transaction data", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_create" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "raw_transaction" + ], + "properties": { + "raw_transaction": { + "$ref": "./shared.json#/$defs/HexString", + "description": "Hex-encoded raw transaction data" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_create.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_create.response.json b/docs/schemas/btck_transaction_create.response.json new file mode 100644 index 0000000..dc88c77 --- /dev/null +++ b/docs/schemas/btck_transaction_create.response.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created transaction (e.g., `{\"ref\": \"$transaction\"}`)" + }, + { + "$ref": "./shared.json#/$defs/GenericErrorResponse" + } + ] +} diff --git a/docs/schemas/btck_transaction_destroy.json b/docs/schemas/btck_transaction_destroy.json new file mode 100644 index 0000000..2c60738 --- /dev/null +++ b/docs/schemas/btck_transaction_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "transaction" + ], + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_destroy.response.json b/docs/schemas/btck_transaction_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_transaction_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_transaction_get_input_at.json b/docs/schemas/btck_transaction_get_input_at.json new file mode 100644 index 0000000..d060618 --- /dev/null +++ b/docs/schemas/btck_transaction_get_input_at.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Retrieves the input at the given index from a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_get_input_at" + }, + "params": { + "type": "object", + "x-doc-order": [ + "transaction", + "input_index" + ], + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + }, + "input_index": { + "type": "integer", + "description": "Zero-based input index" + } + }, + "required": [ + "transaction", + "input_index" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_get_input_at.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_get_input_at.response.json b/docs/schemas/btck_transaction_get_input_at.response.json new file mode 100644 index 0000000..e9a75cf --- /dev/null +++ b/docs/schemas/btck_transaction_get_input_at.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned transaction input (e.g., `{\"ref\": \"$transaction_input\"}`). The returned transaction input reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_get_output_at.json b/docs/schemas/btck_transaction_get_output_at.json new file mode 100644 index 0000000..13be675 --- /dev/null +++ b/docs/schemas/btck_transaction_get_output_at.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Retrieves the output at the given index from a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_get_output_at" + }, + "params": { + "type": "object", + "x-doc-order": [ + "transaction", + "output_index" + ], + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + }, + "output_index": { + "type": "integer", + "description": "Zero-based output index" + } + }, + "required": [ + "transaction", + "output_index" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_get_output_at.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_get_output_at.response.json b/docs/schemas/btck_transaction_get_output_at.response.json new file mode 100644 index 0000000..f1a64a8 --- /dev/null +++ b/docs/schemas/btck_transaction_get_output_at.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned transaction output (e.g., `{\"ref\": \"$transaction_output\"}`). The returned transaction output reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_get_txid.json b/docs/schemas/btck_transaction_get_txid.json new file mode 100644 index 0000000..aeda607 --- /dev/null +++ b/docs/schemas/btck_transaction_get_txid.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the txid of a transaction", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_get_txid" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference or transaction view reference" + } + }, + "required": [ + "transaction" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_get_txid.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_get_txid.response.json b/docs/schemas/btck_transaction_get_txid.response.json new file mode 100644 index 0000000..eeda5fd --- /dev/null +++ b/docs/schemas/btck_transaction_get_txid.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned txid (e.g., `{\"ref\": \"$txid\"}`). The returned txid reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_input_copy.json b/docs/schemas/btck_transaction_input_copy.json new file mode 100644 index 0000000..baa6713 --- /dev/null +++ b/docs/schemas/btck_transaction_input_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a transaction input", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_input_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_input": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction input reference" + } + }, + "required": [ + "transaction_input" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_input_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_input_copy.response.json b/docs/schemas/btck_transaction_input_copy.response.json new file mode 100644 index 0000000..a715fc6 --- /dev/null +++ b/docs/schemas/btck_transaction_input_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied transaction input (e.g., `{\"ref\": \"$transaction_input_copy\"}`)" +} diff --git a/docs/schemas/btck_transaction_input_destroy.json b/docs/schemas/btck_transaction_input_destroy.json new file mode 100644 index 0000000..21e2b19 --- /dev/null +++ b/docs/schemas/btck_transaction_input_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a transaction input", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_input_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_input": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "TransactionInput reference to destroy" + } + }, + "required": [ + "transaction_input" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_input_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_input_destroy.response.json b/docs/schemas/btck_transaction_input_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_transaction_input_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_transaction_input_get_out_point.json b/docs/schemas/btck_transaction_input_get_out_point.json new file mode 100644 index 0000000..760e8ae --- /dev/null +++ b/docs/schemas/btck_transaction_input_get_out_point.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the out point from a transaction input", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_input_get_out_point" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_input": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction input reference" + } + }, + "required": [ + "transaction_input" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_input_get_out_point.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_input_get_out_point.response.json b/docs/schemas/btck_transaction_input_get_out_point.response.json new file mode 100644 index 0000000..12677a0 --- /dev/null +++ b/docs/schemas/btck_transaction_input_get_out_point.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned transaction out point (e.g., `{\"ref\": \"$transaction_out_point\"}`). The returned transaction out point reference is a view that depends on the lifetime of the parent transaction input and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_out_point_copy.json b/docs/schemas/btck_transaction_out_point_copy.json new file mode 100644 index 0000000..54f76b0 --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a transaction out point", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_out_point_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_out_point": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction out point reference" + } + }, + "required": [ + "transaction_out_point" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_out_point_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_out_point_copy.response.json b/docs/schemas/btck_transaction_out_point_copy.response.json new file mode 100644 index 0000000..6ad27cf --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied transaction out point (e.g., `{\"ref\": \"$transaction_out_point_copy\"}`)" +} diff --git a/docs/schemas/btck_transaction_out_point_destroy.json b/docs/schemas/btck_transaction_out_point_destroy.json new file mode 100644 index 0000000..cf40552 --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a transaction out point", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_out_point_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_out_point": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction out point reference to destroy" + } + }, + "required": [ + "transaction_out_point" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_out_point_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_out_point_destroy.response.json b/docs/schemas/btck_transaction_out_point_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_transaction_out_point_get_index.json b/docs/schemas/btck_transaction_out_point_get_index.json new file mode 100644 index 0000000..a8fadbd --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_get_index.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the output index from a transaction out point", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_out_point_get_index" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_out_point": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction out point reference" + } + }, + "required": [ + "transaction_out_point" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_out_point_get_index.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_out_point_get_index.response.json b/docs/schemas/btck_transaction_out_point_get_index.response.json new file mode 100644 index 0000000..3772556 --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_get_index.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The output index" +} diff --git a/docs/schemas/btck_transaction_out_point_get_txid.json b/docs/schemas/btck_transaction_out_point_get_txid.json new file mode 100644 index 0000000..1a5199f --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_get_txid.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the txid from a transaction out point", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_out_point_get_txid" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_out_point": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction out point reference" + } + }, + "required": [ + "transaction_out_point" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_out_point_get_txid.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_out_point_get_txid.response.json b/docs/schemas/btck_transaction_out_point_get_txid.response.json new file mode 100644 index 0000000..c09dcbc --- /dev/null +++ b/docs/schemas/btck_transaction_out_point_get_txid.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned txid (e.g., `{\"ref\": \"$txid\"}`). The returned txid reference is a view that depends on the lifetime of the parent transaction out point and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_output_copy.json b/docs/schemas/btck_transaction_output_copy.json new file mode 100644 index 0000000..c87af15 --- /dev/null +++ b/docs/schemas/btck_transaction_output_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a transaction output", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_output_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_output": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction output reference" + } + }, + "required": [ + "transaction_output" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_output_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_output_copy.response.json b/docs/schemas/btck_transaction_output_copy.response.json new file mode 100644 index 0000000..3963d3a --- /dev/null +++ b/docs/schemas/btck_transaction_output_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied transaction output (e.g., `{\"ref\": \"$transaction_output_copy\"}`)" +} diff --git a/docs/schemas/btck_transaction_output_create.json b/docs/schemas/btck_transaction_output_create.json new file mode 100644 index 0000000..9cb2228 --- /dev/null +++ b/docs/schemas/btck_transaction_output_create.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Creates a transaction output from a script pubkey reference and amount", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params", + "ref" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_output_create" + }, + "params": { + "type": "object", + "x-doc-order": [ + "script_pubkey", + "amount" + ], + "additionalProperties": false, + "required": [ + "script_pubkey", + "amount" + ], + "properties": { + "script_pubkey": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Reference to a ScriptPubkey from `btck_script_pubkey_create`" + }, + "amount": { + "type": "number", + "minimum": 0, + "description": "Amount in satoshis" + } + } + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_output_create.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_output_create.response.json b/docs/schemas/btck_transaction_output_create.response.json new file mode 100644 index 0000000..a3acf55 --- /dev/null +++ b/docs/schemas/btck_transaction_output_create.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the created transaction output (e.g., `{\"ref\": \"$transaction_output\"}`)" +} diff --git a/docs/schemas/btck_transaction_output_destroy.json b/docs/schemas/btck_transaction_output_destroy.json new file mode 100644 index 0000000..e57f8cd --- /dev/null +++ b/docs/schemas/btck_transaction_output_destroy.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a transaction output", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_output_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "required": [ + "transaction_output" + ], + "properties": { + "transaction_output": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction output reference to destroy" + } + } + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_output_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_output_destroy.response.json b/docs/schemas/btck_transaction_output_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_transaction_output_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_transaction_output_get_amount.json b/docs/schemas/btck_transaction_output_get_amount.json new file mode 100644 index 0000000..ac47a71 --- /dev/null +++ b/docs/schemas/btck_transaction_output_get_amount.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the amount in satoshis from a transaction output", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_output_get_amount" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_output": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction output reference" + } + }, + "required": [ + "transaction_output" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_output_get_amount.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_output_get_amount.response.json b/docs/schemas/btck_transaction_output_get_amount.response.json new file mode 100644 index 0000000..2411190 --- /dev/null +++ b/docs/schemas/btck_transaction_output_get_amount.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/IntegerResponse", + "description": "The amount in satoshis" +} diff --git a/docs/schemas/btck_transaction_output_get_script_pubkey.json b/docs/schemas/btck_transaction_output_get_script_pubkey.json new file mode 100644 index 0000000..43eabf8 --- /dev/null +++ b/docs/schemas/btck_transaction_output_get_script_pubkey.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Gets the script pubkey of a transaction output", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_output_get_script_pubkey" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction_output": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction output reference" + } + }, + "required": [ + "transaction_output" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_output_get_script_pubkey.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_output_get_script_pubkey.response.json b/docs/schemas/btck_transaction_output_get_script_pubkey.response.json new file mode 100644 index 0000000..9e49a44 --- /dev/null +++ b/docs/schemas/btck_transaction_output_get_script_pubkey.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the returned script pubkey (e.g., `{\"ref\": \"$script_pubkey\"}`). The returned script pubkey reference is a view that depends on the lifetime of the parent transaction output and does not require an explicit destroy call." +} diff --git a/docs/schemas/btck_transaction_to_bytes.json b/docs/schemas/btck_transaction_to_bytes.json new file mode 100644 index 0000000..fdab9ac --- /dev/null +++ b/docs/schemas/btck_transaction_to_bytes.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the consensus-serialized transaction as a hex string", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_transaction_to_bytes" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "transaction": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Transaction reference" + } + }, + "required": [ + "transaction" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_transaction_to_bytes.response.json" + } + } +} diff --git a/docs/schemas/btck_transaction_to_bytes.response.json b/docs/schemas/btck_transaction_to_bytes.response.json new file mode 100644 index 0000000..19f2abd --- /dev/null +++ b/docs/schemas/btck_transaction_to_bytes.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/HexStringResponse", + "description": "Hex-encoded consensus serialization of the transaction" +} diff --git a/docs/schemas/btck_txid_copy.json b/docs/schemas/btck_txid_copy.json new file mode 100644 index 0000000..0dc7d44 --- /dev/null +++ b/docs/schemas/btck_txid_copy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Copies a txid", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_txid_copy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "txid": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Txid reference" + } + }, + "required": [ + "txid" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_txid_copy.response.json" + } + } +} diff --git a/docs/schemas/btck_txid_copy.response.json b/docs/schemas/btck_txid_copy.response.json new file mode 100644 index 0000000..83ed1ef --- /dev/null +++ b/docs/schemas/btck_txid_copy.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/RefResponse", + "description": "Contains the copied txid (e.g., `{\"ref\": \"$txid_copy\"}`)" +} diff --git a/docs/schemas/btck_txid_destroy.json b/docs/schemas/btck_txid_destroy.json new file mode 100644 index 0000000..20fd17b --- /dev/null +++ b/docs/schemas/btck_txid_destroy.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Destroys a txid", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_txid_destroy" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "txid": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Txid reference to destroy" + } + }, + "required": [ + "txid" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_txid_destroy.response.json" + } + } +} diff --git a/docs/schemas/btck_txid_destroy.response.json b/docs/schemas/btck_txid_destroy.response.json new file mode 100644 index 0000000..bcff212 --- /dev/null +++ b/docs/schemas/btck_txid_destroy.response.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/NullResponse" +} diff --git a/docs/schemas/btck_txid_equals.json b/docs/schemas/btck_txid_equals.json new file mode 100644 index 0000000..974aa8c --- /dev/null +++ b/docs/schemas/btck_txid_equals.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Checks if two txids are equal", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_txid_equals" + }, + "params": { + "type": "object", + "x-doc-order": [ + "txid1", + "txid2" + ], + "additionalProperties": false, + "properties": { + "txid1": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "First txid reference" + }, + "txid2": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Second txid reference" + } + }, + "required": [ + "txid1", + "txid2" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_txid_equals.response.json" + } + } +} diff --git a/docs/schemas/btck_txid_equals.response.json b/docs/schemas/btck_txid_equals.response.json new file mode 100644 index 0000000..1889edf --- /dev/null +++ b/docs/schemas/btck_txid_equals.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/BooleanResponse", + "description": "`true` if the txids are equal" +} diff --git a/docs/schemas/btck_txid_to_bytes.json b/docs/schemas/btck_txid_to_bytes.json new file mode 100644 index 0000000..f67ebd2 --- /dev/null +++ b/docs/schemas/btck_txid_to_bytes.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Returns the txid as raw bytes encoded as hex", + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "request", + "expected_response" + ], + "properties": { + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "method", + "params" + ], + "properties": { + "id": { + "$ref": "./shared.json#/$defs/TestCaseID" + }, + "method": { + "const": "btck_txid_to_bytes" + }, + "params": { + "type": "object", + "additionalProperties": false, + "properties": { + "txid": { + "$ref": "./shared.json#/$defs/RefObject", + "description": "Txid reference" + } + }, + "required": [ + "txid" + ] + }, + "ref": { + "$ref": "./shared.json#/$defs/RefString" + } + } + }, + "expected_response": { + "$ref": "./btck_txid_to_bytes.response.json" + } + } +} diff --git a/docs/schemas/btck_txid_to_bytes.response.json b/docs/schemas/btck_txid_to_bytes.response.json new file mode 100644 index 0000000..1148d8e --- /dev/null +++ b/docs/schemas/btck_txid_to_bytes.response.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "./shared.json#/$defs/Hex64StringResponse", + "description": "Hex-encoded raw 32-byte txid" +} diff --git a/docs/schemas/shared.json b/docs/schemas/shared.json new file mode 100644 index 0000000..383e088 --- /dev/null +++ b/docs/schemas/shared.json @@ -0,0 +1,99 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "NonEmptyText": { + "type": "string", + "pattern": ".*\\S.*" + }, + "TestCaseID": { + "type": "string", + "pattern": "^[A-Za-z0-9_]+#[0-9]+$" + }, + "RefString": { + "type": "string", + "pattern": "^\\$[A-Za-z0-9_]+$" + }, + "RefObject": { + "type": "object", + "additionalProperties": false, + "required": ["ref"], + "properties": { + "ref": { "$ref": "#/$defs/RefString" } + } + }, + "RefResponse": { + "type": "object", + "additionalProperties": false, + "required": ["result"], + "properties": { + "result": { "$ref": "#/$defs/RefObject" }, + "error": { "type": "null" } + } + }, + "BooleanResponse": { + "type": "object", + "additionalProperties": false, + "required": ["result"], + "properties": { + "result": { "type": "boolean" }, + "error": { "type": "null" } + } + }, + "NullResponse": { + "type": "object", + "additionalProperties": false, + "properties": { + "result": { "type": "null" }, + "error": { "type": "null" } + } + }, + "IntegerResponse": { + "type": "object", + "additionalProperties": false, + "required": ["result"], + "properties": { + "result": { "type": "integer" }, + "error": { "type": "null" } + } + }, + "Hex64String": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "Hex64StringResponse": { + "type": "object", + "additionalProperties": false, + "required": ["result"], + "properties": { + "result": { "$ref": "#/$defs/Hex64String" }, + "error": { "type": "null" } + } + }, + "HexString": { + "type": "string", + "pattern": "^[0-9a-f]*$" + }, + "HexStringResponse": { + "type": "object", + "additionalProperties": false, + "required": ["result"], + "properties": { + "result": { "$ref": "#/$defs/HexString" }, + "error": { "type": "null" } + } + }, + "GenericErrorResponse": { + "type": "object", + "additionalProperties": false, + "properties": { + "result": { + "type": "null" + }, + "error": { + "type": "object", + "additionalProperties": false + } + } + } + } +} diff --git a/docs/schemas/suite-schema.json b/docs/schemas/suite-schema.json new file mode 100644 index 0000000..ab02e58 --- /dev/null +++ b/docs/schemas/suite-schema.json @@ -0,0 +1,221 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "additionalProperties": false, + "required": [ + "title", + "description", + "tests" + ], + "properties": { + "title": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "description": { + "$ref": "./shared.json#/$defs/NonEmptyText" + }, + "stateful": { + "type": "boolean" + }, + "tests": { + "type": "array", + "minItems": 1, + "items": { + "oneOf": [ + { + "$ref": "./btck_block_copy.json" + }, + { + "$ref": "./btck_block_count_transactions.json" + }, + { + "$ref": "./btck_block_create.json" + }, + { + "$ref": "./btck_block_destroy.json" + }, + { + "$ref": "./btck_block_get_hash.json" + }, + { + "$ref": "./btck_block_get_header.json" + }, + { + "$ref": "./btck_block_get_transaction_at.json" + }, + { + "$ref": "./btck_block_hash_copy.json" + }, + { + "$ref": "./btck_block_hash_create.json" + }, + { + "$ref": "./btck_block_hash_destroy.json" + }, + { + "$ref": "./btck_block_hash_equals.json" + }, + { + "$ref": "./btck_block_hash_to_bytes.json" + }, + { + "$ref": "./btck_block_header_copy.json" + }, + { + "$ref": "./btck_block_header_create.json" + }, + { + "$ref": "./btck_block_header_destroy.json" + }, + { + "$ref": "./btck_block_header_get_bits.json" + }, + { + "$ref": "./btck_block_header_get_hash.json" + }, + { + "$ref": "./btck_block_header_get_nonce.json" + }, + { + "$ref": "./btck_block_header_get_prev_hash.json" + }, + { + "$ref": "./btck_block_header_get_timestamp.json" + }, + { + "$ref": "./btck_block_header_get_version.json" + }, + { + "$ref": "./btck_block_to_bytes.json" + }, + { + "$ref": "./btck_block_tree_entry_get_block_hash.json" + }, + { + "$ref": "./btck_chain_contains.json" + }, + { + "$ref": "./btck_chain_get_by_height.json" + }, + { + "$ref": "./btck_chain_get_height.json" + }, + { + "$ref": "./btck_chainstate_manager_create.json" + }, + { + "$ref": "./btck_chainstate_manager_destroy.json" + }, + { + "$ref": "./btck_chainstate_manager_get_active_chain.json" + }, + { + "$ref": "./btck_chainstate_manager_process_block.json" + }, + { + "$ref": "./btck_context_create.json" + }, + { + "$ref": "./btck_context_destroy.json" + }, + { + "$ref": "./btck_precomputed_transaction_data_create.json" + }, + { + "$ref": "./btck_precomputed_transaction_data_destroy.json" + }, + { + "$ref": "./btck_script_pubkey_copy.json" + }, + { + "$ref": "./btck_script_pubkey_create.json" + }, + { + "$ref": "./btck_script_pubkey_destroy.json" + }, + { + "$ref": "./btck_script_pubkey_to_bytes.json" + }, + { + "$ref": "./btck_script_pubkey_verify.json" + }, + { + "$ref": "./btck_transaction_copy.json" + }, + { + "$ref": "./btck_transaction_count_inputs.json" + }, + { + "$ref": "./btck_transaction_count_outputs.json" + }, + { + "$ref": "./btck_transaction_create.json" + }, + { + "$ref": "./btck_transaction_destroy.json" + }, + { + "$ref": "./btck_transaction_get_input_at.json" + }, + { + "$ref": "./btck_transaction_get_output_at.json" + }, + { + "$ref": "./btck_transaction_get_txid.json" + }, + { + "$ref": "./btck_transaction_input_copy.json" + }, + { + "$ref": "./btck_transaction_input_destroy.json" + }, + { + "$ref": "./btck_transaction_input_get_out_point.json" + }, + { + "$ref": "./btck_transaction_out_point_copy.json" + }, + { + "$ref": "./btck_transaction_out_point_destroy.json" + }, + { + "$ref": "./btck_transaction_out_point_get_index.json" + }, + { + "$ref": "./btck_transaction_out_point_get_txid.json" + }, + { + "$ref": "./btck_transaction_output_copy.json" + }, + { + "$ref": "./btck_transaction_output_create.json" + }, + { + "$ref": "./btck_transaction_output_destroy.json" + }, + { + "$ref": "./btck_transaction_output_get_amount.json" + }, + { + "$ref": "./btck_transaction_output_get_script_pubkey.json" + }, + { + "$ref": "./btck_transaction_to_bytes.json" + }, + { + "$ref": "./btck_txid_copy.json" + }, + { + "$ref": "./btck_txid_destroy.json" + }, + { + "$ref": "./btck_txid_equals.json" + }, + { + "$ref": "./btck_txid_to_bytes.json" + } + ] + } + } + } +} diff --git a/go.mod b/go.mod index 2ee73a4..9dcc169 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,9 @@ module github.com/stringintech/kernel-bindings-tests go 1.23 -require github.com/spf13/pflag v1.0.10 +require ( + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 + github.com/spf13/pflag v1.0.10 +) + +require golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 8ec1276..19d8db2 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,8 @@ +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= From 870190e370da8aaa309541f4a4a46ff6fcc31955 Mon Sep 17 00:00:00 2001 From: stringintech Date: Wed, 13 May 2026 00:06:32 +0330 Subject: [PATCH 4/7] Validate handler response against JSON schema Now the runner binary embeds the response schema files and uses the corresponding method response schema for a more strict validation of an incoming response from handler. --- docs/schemas/embed.go | 8 +++++ runner/runner.go | 59 +++++++++++++++++++++++++++---------- runner/schema.go | 68 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 docs/schemas/embed.go create mode 100644 runner/schema.go diff --git a/docs/schemas/embed.go b/docs/schemas/embed.go new file mode 100644 index 0000000..146b573 --- /dev/null +++ b/docs/schemas/embed.go @@ -0,0 +1,8 @@ +package schemas + +import "embed" + +// FS contains only the shared and per-method response schemas needed by the runner. +// +//go:embed shared.json *.response.json +var FS embed.FS diff --git a/runner/runner.go b/runner/runner.go index 12baef4..d121ad9 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -12,6 +12,8 @@ import ( "slices" "strings" "time" + + "github.com/santhosh-tekuri/jsonschema/v6" ) // VerbosityLevel represents different levels of test output verbosity @@ -28,9 +30,10 @@ const ( // TestRunner executes test suites against a handler binary type TestRunner struct { - handler *Handler - handlerConfig *HandlerConfig - timeout time.Duration + handler *Handler + handlerConfig *HandlerConfig + timeout time.Duration + responseSchemas map[string]*jsonschema.Schema } // NewTestRunner creates a new test runner for executing test suites against a handler binary. @@ -55,13 +58,19 @@ func NewTestRunner(handlerPath string, handlerTimeout time.Duration, timeout tim timeout = 30 * time.Second } + responseSchemas, err := loadEmbeddedResponseSchemas() + if err != nil { + return nil, fmt.Errorf("failed to load response schemas: %w", err) + } + return &TestRunner{ handler: handler, handlerConfig: &HandlerConfig{ Path: handlerPath, Timeout: handlerTimeout, }, - timeout: timeout, + timeout: timeout, + responseSchemas: responseSchemas, }, nil } @@ -87,20 +96,15 @@ func (tr *TestRunner) SendRequest(req Request) error { return nil } -// ReadResponse reads and unmarshals a response from the handler -func (tr *TestRunner) ReadResponse() (*Response, error) { +// ReadResponseLine reads a raw JSON response line from the handler. +func (tr *TestRunner) ReadResponseLine() ([]byte, error) { line, err := tr.handler.ReadLine() if err != nil { slog.Warn("Failed to read response, cleaning up handler (will spawn new one for remaining tests)", "error", err) tr.CloseHandler() return nil, err } - - var resp Response - if err := json.Unmarshal(line, &resp); err != nil { - return nil, err - } - return &resp, nil + return line, nil } // CloseHandler closes the handler and sets it to nil @@ -202,7 +206,7 @@ func (tr *TestRunner) runTest(ctx context.Context, test *TestCase) SingleTestRes } } - resp, err := tr.ReadResponse() + line, err := tr.ReadResponseLine() if err != nil { return SingleTestResult{ TestID: test.Request.ID, @@ -211,19 +215,42 @@ func (tr *TestRunner) runTest(ctx context.Context, test *TestCase) SingleTestRes } } - if err := validateResponse(test, resp); err != nil { + schema := tr.responseSchemas[test.Request.Method] + if schema == nil { + panic(fmt.Sprintf("missing response schema for method %q", test.Request.Method)) + } + + if err := validateJSONAgainstSchema(schema, line); err != nil { + return SingleTestResult{ + TestID: test.Request.ID, + Passed: false, + Message: fmt.Sprintf("Invalid response: schema validation failed for method %s: %v", test.Request.Method, err), + } + } + + var resp Response + err = json.Unmarshal(line, &resp) + if err != nil { + return SingleTestResult{ + TestID: test.Request.ID, + Passed: false, + Message: fmt.Sprintf("Invalid response JSON: %v", err), + } + } + + if err := validateResponse(test, &resp); err != nil { return SingleTestResult{ TestID: test.Request.ID, Passed: false, Message: fmt.Sprintf("Invalid response: %s", err.Error()), - ReceivedResponse: resp, + ReceivedResponse: &resp, } } return SingleTestResult{ TestID: test.Request.ID, Passed: true, - ReceivedResponse: resp, + ReceivedResponse: &resp, } } diff --git a/runner/schema.go b/runner/schema.go new file mode 100644 index 0000000..5c33cde --- /dev/null +++ b/runner/schema.go @@ -0,0 +1,68 @@ +package runner + +import ( + "bytes" + "fmt" + "io/fs" + "path/filepath" + "strings" + + "github.com/santhosh-tekuri/jsonschema/v6" + "github.com/stringintech/kernel-bindings-tests/docs/schemas" +) + +func loadEmbeddedResponseSchemas() (map[string]*jsonschema.Schema, error) { + compiler := jsonschema.NewCompiler() + + sharedData, err := fs.ReadFile(schemas.FS, "shared.json") + if err != nil { + return nil, fmt.Errorf("failed to read shared schema: %w", err) + } + sharedDoc, err := jsonschema.UnmarshalJSON(bytes.NewReader(sharedData)) + if err != nil { + return nil, fmt.Errorf("failed to parse shared schema: %w", err) + } + if err := compiler.AddResource("shared.json", sharedDoc); err != nil { + return nil, fmt.Errorf("failed to register shared schema: %w", err) + } + + methodPaths, err := fs.Glob(schemas.FS, "*.response.json") + if err != nil { + return nil, fmt.Errorf("failed to list embedded response schemas: %w", err) + } + + responseSchemaByMethod := make(map[string]*jsonschema.Schema, len(methodPaths)) + + for _, path := range methodPaths { + data, err := fs.ReadFile(schemas.FS, path) + if err != nil { + return nil, fmt.Errorf("failed to read %s: %w", path, err) + } + + doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("failed to parse %s: %w", path, err) + } + + if err := compiler.AddResource(path, doc); err != nil { + return nil, fmt.Errorf("failed to register %s: %w", path, err) + } + + schema, err := compiler.Compile(path) + if err != nil { + return nil, fmt.Errorf("failed to compile %s: %w", path, err) + } + + responseSchemaByMethod[strings.TrimSuffix(filepath.Base(path), ".response.json")] = schema + } + + return responseSchemaByMethod, nil +} + +func validateJSONAgainstSchema(schema *jsonschema.Schema, data []byte) error { + doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(data)) + if err != nil { + return err + } + return schema.Validate(doc) +} From b4433428ca0dbcc4f6956e1677fc324f7481cac2 Mon Sep 17 00:00:00 2001 From: stringintech Date: Wed, 13 May 2026 16:34:16 +0330 Subject: [PATCH 5/7] Add method spec generator Adds a generator in cmd/specgen that deterministically generates a markdown file documenting methods based on method schema files. Now handle-spec points to the generated document using the generator. --- Makefile | 6 +- cmd/specgen/main.go | 13 + cmd/specgen/schema.go | 123 ++++++ cmd/specgen/specgen.go | 635 ++++++++++++++++++++++++++++++ docs/handler-spec.md | 298 +------------- docs/methods-spec.md | 867 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1644 insertions(+), 298 deletions(-) create mode 100644 cmd/specgen/main.go create mode 100644 cmd/specgen/schema.go create mode 100644 cmd/specgen/specgen.go create mode 100644 docs/methods-spec.md diff --git a/Makefile b/Makefile index 689d9cd..6186a1b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build test clean runner mock-handler suite-validate +.PHONY: all build test clean runner mock-handler suite-validate specgen BUILD_DIR := build RUNNER_BIN := $(BUILD_DIR)/runner @@ -28,6 +28,10 @@ suite-validate: @echo "Validating testdata against the suite schema..." go run ./cmd/suite-validate +specgen: + @echo "Generating method reference from schemas..." + go run ./cmd/specgen + clean: @echo "Cleaning build artifacts..." rm -rf $(BUILD_DIR) diff --git a/cmd/specgen/main.go b/cmd/specgen/main.go new file mode 100644 index 0000000..d427a31 --- /dev/null +++ b/cmd/specgen/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + if err := GenerateMethodReference("docs/schemas", "docs/methods-spec.md"); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/specgen/schema.go b/cmd/specgen/schema.go new file mode 100644 index 0000000..3fc0749 --- /dev/null +++ b/cmd/specgen/schema.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/santhosh-tekuri/jsonschema/v6" +) + +const ( + docOrderKeyword = "x-doc-order" + docOrderVocabURL = "urn:kernel-bindings-tests:specgen:doc-order" +) + +var docOrderVocabulary = mustDocOrderVocabulary() + +type docOrderExt struct { + Order []string +} + +func (e *docOrderExt) Validate(*jsonschema.ValidatorContext, any) {} + +func compileSchema(path string) (*jsonschema.Schema, error) { + abs, err := filepath.Abs(path) + if err != nil { + return nil, err + } + + c := jsonschema.NewCompiler() + c.AssertVocabs() + // Preserve x-doc-order so generated parameter docs follow the schema's + // reader-facing order instead of the map iteration order. + c.RegisterVocabulary(docOrderVocabulary) + return c.Compile(abs) +} + +// docOrder reads the custom x-doc-order extension attached during compilation. +// The schema library keeps object properties in a map, so this preserves the +// reader-facing order declared in the source schema. +func docOrder(schema *jsonschema.Schema) []string { + schema = resolveSchema(schema) + if schema == nil { + return nil + } + for _, ext := range schema.Extensions { + docExt, ok := ext.(*docOrderExt) + if ok { + return docExt.Order + } + } + return nil +} + +// resolveSchema unwraps compiled $ref wrappers to the concrete target schema. +// The jsonschema library resolves references during compilation; this helper +// just follows Schema.Ref pointers so callers can inspect the target fields. +func resolveSchema(schema *jsonschema.Schema) *jsonschema.Schema { + for schema != nil { + if schema.Ref == nil { + return schema + } + schema = schema.Ref + } + return nil +} + +// mustDocOrderVocabulary registers a tiny custom vocabulary just for x-doc-order. +// The compiled extension is later read back by docOrder during markdown rendering. +func mustDocOrderVocabulary() *jsonschema.Vocabulary { + meta, err := jsonschema.UnmarshalJSON(strings.NewReader(`{ + "properties": { + "x-doc-order": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + } + } + }`)) + if err != nil { + panic(err) + } + + c := jsonschema.NewCompiler() + if err := c.AddResource(docOrderVocabURL, meta); err != nil { + panic(err) + } + schema, err := c.Compile(docOrderVocabURL) + if err != nil { + panic(err) + } + + return &jsonschema.Vocabulary{ + URL: docOrderVocabURL, + Schema: schema, + // Compile stores x-doc-order on the compiled schema for later doc rendering. + Compile: compileDocOrder, + } +} + +// compileDocOrder validates the raw extension payload and stores it on the +// compiled schema as a strongly typed helper value. +func compileDocOrder(_ *jsonschema.CompilerContext, obj map[string]any) (jsonschema.SchemaExt, error) { + raw, ok := obj[docOrderKeyword] + if !ok { + return nil, nil + } + + values, ok := raw.([]any) + if !ok { + return nil, fmt.Errorf("%s must be an array of strings", docOrderKeyword) + } + + order := make([]string, 0, len(values)) + for _, value := range values { + name, ok := value.(string) + if !ok { + return nil, fmt.Errorf("%s entries must be strings", docOrderKeyword) + } + order = append(order, name) + } + return &docOrderExt{Order: order}, nil +} diff --git a/cmd/specgen/specgen.go b/cmd/specgen/specgen.go new file mode 100644 index 0000000..7c9caa0 --- /dev/null +++ b/cmd/specgen/specgen.go @@ -0,0 +1,635 @@ +package main + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/santhosh-tekuri/jsonschema/v6" +) + +type methodDoc struct { + Name string + Summary string + Params []paramDoc + Result string + Error string +} + +type paramDoc struct { + Name string + Type string + Required bool + Description string + Children []paramDoc + EnumValues []string +} + +const ( + kindRefObject = "ref-object" + kindGenericErrorResponse = "generic-error-response" + kindRefResponse = "ref-response" + kindNullResponse = "null-response" + kindBooleanResponse = "boolean-response" + kindIntegerResponse = "integer-response" + kindHexStringResponse = "hex-string-response" + kindHex64StringResponse = "hex64-string-response" +) + +// GenerateMethodReference builds method reference markdown from method schemas in schemaDir. +func GenerateMethodReference(schemaDir, outPath string) error { + refs, err := methodSchemaPaths(schemaDir) + if err != nil { + return err + } + + methods, err := loadMethodDocs(refs) + if err != nil { + return err + } + + sort.Slice(methods, func(i, j int) bool { + return methods[i].Name < methods[j].Name + }) + + return os.WriteFile(outPath, []byte(renderMethods(methods)), 0o644) +} + +func methodSchemaPaths(schemaDir string) ([]string, error) { + entries, err := os.ReadDir(schemaDir) + if err != nil { + return nil, err + } + + paths := make([]string, 0, len(entries)) + for _, entry := range entries { + if entry.IsDir() { + continue + } + + name := entry.Name() + if !strings.HasSuffix(name, ".json") { + continue + } + if name == "suite-schema.json" || name == "shared.json" || strings.HasSuffix(name, ".response.json") { + continue + } + + paths = append(paths, filepath.Join(schemaDir, name)) + } + + return paths, nil +} + +func loadMethodDocs(refs []string) ([]methodDoc, error) { + methods := make([]methodDoc, 0, len(refs)) + for _, ref := range refs { + doc, err := loadMethodDoc(ref) + if err != nil { + return nil, err + } + methods = append(methods, doc) + } + return methods, nil +} + +// Method extraction: parse one method schema into documentation fields. +func loadMethodDoc(schemaPath string) (methodDoc, error) { + schema, err := compileSchema(schemaPath) + if err != nil { + return methodDoc{}, err + } + + methodName, err := stringConst(schemaAt(schema, "request", "method")) + if err != nil { + return methodDoc{}, fmt.Errorf("%s: missing request.method.const: %w", schemaPath, err) + } + + params, err := loadParams(schema, schemaPath) + if err != nil { + return methodDoc{}, err + } + + responseSchema := schemaAt(schema, "expected_response") + if responseSchema == nil { + return methodDoc{}, fmt.Errorf("%s: missing expected_response schema", schemaPath) + } + + result, errText := loadResponseDocs(responseSchema) + + return methodDoc{ + Name: methodName, + Summary: markdownSentence(schema.Description), + Params: params, + Result: result, + Error: errText, + }, nil +} + +func loadParams(schema *jsonschema.Schema, schemaPath string) ([]paramDoc, error) { + paramsSchema := schemaAt(schema, "request", "params") + if paramsSchema == nil { + return nil, fmt.Errorf("%s: missing request.params schema", schemaPath) + } + return renderProperties(paramsSchema) +} + +// loadResponseDocs turns the expected response schema into one markdown line for +// the success case and one for the error case. Schemas often model this as a +// oneOf between a normal response object and an error envelope. +func loadResponseDocs(response *jsonschema.Schema) (string, string) { + result := fallbackResultText(response) + errText := "`null` (cannot return error)" + + if branches := oneOfSchemas(response); len(branches) > 0 { + for _, branch := range branches { + if isErrorResponseSchema(branch) { + if desc := schemaDescription(branch); desc != "" { + errText = desc + } else { + errText = fallbackErrorText(branch) + } + continue + } + if desc := schemaDescription(branch); desc != "" { + result = desc + } else if txt := fallbackResultText(branch); txt != "" { + result = txt + } + } + return result, errText + } + + if isErrorResponseSchema(response) { + result = "`null`" + if desc := schemaDescription(response); desc != "" { + errText = desc + } else { + errText = fallbackErrorText(response) + } + return result, errText + } + + if desc := schemaDescription(response); desc != "" { + result = desc + } + + return result, errText +} + +// Markdown rendering helpers. +func renderMethods(methods []methodDoc) string { + parts := make([]string, 0, len(methods)+1) + parts = append(parts, + "", + "## Method Reference\n\nMethods are sorted alphabetically. Each method documents its parameters, return values, and possible errors.", + ) + + methodParts := make([]string, 0, len(methods)) + for _, method := range methods { + methodParts = append(methodParts, renderMethod(method)) + } + if len(methodParts) > 0 { + parts = append(parts, strings.Join(methodParts, "\n\n---\n\n")) + } + + return strings.Join(parts, "\n\n") + "\n" +} + +func renderMethod(method methodDoc) string { + var b strings.Builder + fmt.Fprintf(&b, "#### `%s`\n\n", method.Name) + if method.Summary != "" { + b.WriteString(method.Summary) + b.WriteString("\n\n") + } + writeParams(&b, method.Params) + fmt.Fprintf(&b, "**%s:** %s\n\n", "Result", method.Result) + fmt.Fprintf(&b, "**%s:** %s", "Error", method.Error) + return b.String() +} + +// writeParams emits a nested markdown bullet list. Child params appear under +// object params, and enum values become a second nesting level. +func writeParams(b *strings.Builder, params []paramDoc) { + b.WriteString("**Parameters:**\n") + if len(params) == 0 { + b.WriteString("- None\n\n") + return + } + for _, p := range params { + writeParam(b, p, 0) + } + b.WriteString("\n") +} + +func writeParam(b *strings.Builder, p paramDoc, depth int) { + indent := strings.Repeat(" ", depth) + req := "optional" + if p.Required { + req = "required" + } + line := fmt.Sprintf("%s- `%s` (%s, %s)", indent, p.Name, p.Type, req) + if p.Description != "" { + line += ": " + p.Description + } + if len(p.EnumValues) > 0 { + line += enumLeadIn(p.Description) + } + b.WriteString(line) + b.WriteString("\n") + for _, child := range p.Children { + writeParam(b, child, depth+1) + } + if len(p.EnumValues) > 0 { + for _, v := range p.EnumValues { + fmt.Fprintf(b, "%s - `%s`\n", strings.Repeat(" ", depth+1), v) + } + } +} + +// Parameter rendering and schema-to-doc formatting. +func renderProperties(schema *jsonschema.Schema) ([]paramDoc, error) { + if schema == nil || len(schema.Properties) == 0 { + return nil, nil + } + + required := requiredSet(schema) + names, err := orderedPropertyNames(schema) + if err != nil { + return nil, err + } + out := make([]paramDoc, 0, len(names)) + for _, name := range names { + param, err := renderParam(name, schema.Properties[name], required[name]) + if err != nil { + return nil, err + } + out = append(out, param) + } + + return out, nil +} + +func requiredSet(schema *jsonschema.Schema) map[string]bool { + required := make(map[string]bool, len(schema.Required)) + for _, name := range schema.Required { + required[name] = true + } + return required +} + +// orderedPropertyNames enforces x-doc-order for multi-field objects so the +// generated docs stay stable and match the schema author's intended reading order. +func orderedPropertyNames(schema *jsonschema.Schema) ([]string, error) { + if len(schema.Properties) == 1 { + for name := range schema.Properties { + return []string{name}, nil + } + } + + seen := make(map[string]bool, len(schema.Properties)) + order := docOrder(schema) + if len(order) == 0 { + return nil, fmt.Errorf("%s: missing x-doc-order for object with multiple properties", schemaLocation(schema)) + } + + names := make([]string, 0, len(schema.Properties)) + for _, name := range order { + if _, ok := schema.Properties[name]; ok { + names = append(names, name) + seen[name] = true + continue + } + return nil, fmt.Errorf("%s: x-doc-order references unknown property %q", schemaLocation(schema), name) + } + + for name := range schema.Properties { + if !seen[name] { + return nil, fmt.Errorf("%s: property %q missing from x-doc-order", schemaLocation(schema), name) + } + } + return names, nil +} + +// renderParam reduces one schema node to the doc shape needed by markdown output. +// It keeps the property wrapper description, then inspects the resolved schema to +// infer type, nested fields, and enum details. +func renderParam(name string, schema *jsonschema.Schema, required bool) (paramDoc, error) { + resolved := resolveSchema(schema) + if resolved == nil { + return paramDoc{Name: name, Type: "value", Required: required}, nil + } + + out := paramDoc{ + Name: name, + Type: describeSchema(resolved), + Required: required, + Description: schema.Description, + } + + if isRefObjectSchema(schema) { + out.Type = "reference" + return out, nil + } + if applyArrayDetails(&out, resolved) { + return out, nil + } + if enumVals := enumValues(resolved); len(enumVals) > 0 { + out.EnumValues = enumVals + } + if len(resolved.Properties) > 0 { + children, err := renderProperties(resolved) + if err != nil { + return paramDoc{}, err + } + out.Children = children + } + + return out, nil +} + +// applyArrayDetails special-cases array item shapes that read more clearly than +// a plain "array" in the generated reference. +func applyArrayDetails(out *paramDoc, schema *jsonschema.Schema) bool { + if schema == nil || schema.Items2020 == nil { + return false + } + item := schema.Items2020 + if item == nil { + return false + } + if isRefObjectSchema(item) { + out.Type = "array of references" + return true + } + if enumVals := enumValues(item); len(enumVals) > 0 { + out.Type = "array of strings" + out.EnumValues = enumVals + return true + } + return false +} + +// describeSchema maps the compiled schema shape to the short type labels shown +// next to each parameter in markdown. +func describeSchema(schema *jsonschema.Schema) string { + if schema == nil { + return "value" + } + if isRefObjectSchema(schema) { + return "reference" + } + if schema.Types != nil { + types := schema.Types.ToStrings() + if len(types) == 1 { + return types[0] + } + if len(types) > 1 { + return strings.Join(types, " | ") + } + } + if item := schema.Items2020; item != nil { + if isRefObjectSchema(item) { + return "array of references" + } + if enumValues(item) != nil { + return "array of strings" + } + return "array" + } + if len(schema.Properties) > 0 { + return "object" + } + if schema.Enum != nil { + return inferValueType(schema.Enum.Values) + } + if schema.Const != nil { + return inferValueType([]any{*schema.Const}) + } + return "value" +} + +func enumValues(schema *jsonschema.Schema) []string { + if schema == nil || schema.Enum == nil { + return nil + } + out := make([]string, 0, len(schema.Enum.Values)) + for _, value := range schema.Enum.Values { + if s, ok := value.(string); ok { + out = append(out, s) + } + } + return out +} + +func enumLeadIn(desc string) string { + desc = strings.TrimSpace(desc) + if desc == "" { + return ": Allowed values:" + } + switch desc[len(desc)-1] { + case '.', ':', ';': + return " Allowed values:" + default: + return ". Allowed values:" + } +} + +func inferValueType(values []any) string { + if len(values) == 0 { + return "value" + } + switch values[0].(type) { + case string: + return "string" + case bool: + return "boolean" + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + return "integer" + case float32, float64: + return "number" + case map[string]any: + return "object" + case []any: + return "array" + default: + return "value" + } +} + +func oneOfSchemas(schema *jsonschema.Schema) []*jsonschema.Schema { + schema = resolveSchema(schema) + if schema == nil { + return nil + } + return schema.OneOf +} + +// Placeholder text used when schema descriptions are absent. +func fallbackResultText(schema *jsonschema.Schema) string { + if schemaKind(schema) == kindNullResponse { + return "`null` (void operation)" + } + return missingSchemaDescription("result", schema) +} + +func responseTypeLabel(schema *jsonschema.Schema) string { + switch schemaKind(schema) { + case kindRefResponse: + return "Reference" + case kindNullResponse: + return "Null" + case kindBooleanResponse: + return "Boolean" + case kindIntegerResponse: + return "Integer" + case kindHexStringResponse, kindHex64StringResponse: + return "String" + default: + return "" + } +} + +func fallbackErrorText(schema *jsonschema.Schema) string { + if schemaKind(schema) == kindGenericErrorResponse { + return "`{}` when operation fails" + } + return missingSchemaDescription("error", schema) +} + +func missingSchemaDescription(kind string, schema *jsonschema.Schema) string { + loc := schemaLocation(schema) + if loc == "" { + return fmt.Sprintf("TODO: add %s schema description", kind) + } + return fmt.Sprintf("TODO: add %s schema description (%s)", kind, loc) +} + +func isRefObjectSchema(schema *jsonschema.Schema) bool { + return schemaKind(schema) == kindRefObject +} + +// isErrorResponseSchema treats any response with a non-null `error` field as an error envelope. +func isErrorResponseSchema(schema *jsonschema.Schema) bool { + if schemaKind(schema) == kindGenericErrorResponse { + return true + } + resolved := resolveSchema(schema) + if resolved == nil { + return false + } + errorSchema := resolveSchema(resolved.Properties["error"]) + if errorSchema == nil { + return false + } + // Treat any non-null error schema as an error response, including untyped `{}`. + if errorSchema.Types == nil { + return true + } + types := errorSchema.Types.ToStrings() + return !(len(types) == 1 && types[0] == "null") +} + +func schemaDescription(schema *jsonschema.Schema) string { + original := schema + for schema != nil { + if schema.Description != "" { + desc := strings.TrimSpace(schema.Description) + if desc == "" { + return "" + } + if label := responseTypeLabel(original); label != "" { + return label + " - " + desc + } + return desc + } + schema = schema.Ref + } + return "" +} + +func schemaLocation(schema *jsonschema.Schema) string { + resolved := resolveSchema(schema) + if resolved == nil || resolved.Location == "" { + return "" + } + return resolved.Location +} + +// Match known response/reference kinds from shared schema definition paths. +func schemaKind(schema *jsonschema.Schema) string { + if schema == nil { + return "" + } + // Classify known response/reference shapes based on resolved $defs location. + resolved := resolveSchema(schema) + if resolved == nil { + return "" + } + loc := resolved.Location + switch { + case strings.Contains(loc, "#/$defs/RefObject"): + return kindRefObject + case strings.Contains(loc, "#/$defs/GenericErrorResponse"): + return kindGenericErrorResponse + case strings.Contains(loc, "#/$defs/RefResponse"): + return kindRefResponse + case strings.Contains(loc, "#/$defs/NullResponse"): + return kindNullResponse + case strings.Contains(loc, "#/$defs/BooleanResponse"): + return kindBooleanResponse + case strings.Contains(loc, "#/$defs/IntegerResponse"): + return kindIntegerResponse + case strings.Contains(loc, "#/$defs/HexStringResponse"): + return kindHexStringResponse + case strings.Contains(loc, "#/$defs/Hex64StringResponse"): + return kindHex64StringResponse + default: + return "" + } +} + +// schemaAt walks a simple property path without resolving refs. It is used for +// fixed top-level locations like request.method and expected_response. +func schemaAt(schema *jsonschema.Schema, parts ...string) *jsonschema.Schema { + cur := schema + for _, part := range parts { + if cur == nil { + return nil + } + next, ok := cur.Properties[part] + if !ok { + return nil + } + cur = next + } + return cur +} + +func stringConst(schema *jsonschema.Schema) (string, error) { + if schema == nil || schema.Const == nil { + return "", errors.New("const missing") + } + s, ok := (*schema.Const).(string) + if !ok { + return "", errors.New("const is not a string") + } + return s, nil +} + +func markdownSentence(s string) string { + s = strings.TrimSpace(s) + if s == "" { + return "" + } + switch s[len(s)-1] { + case '.', '!', '?', ')': + return s + default: + return s + "." + } +} diff --git a/docs/handler-spec.md b/docs/handler-spec.md index db848cd..c87306d 100644 --- a/docs/handler-spec.md +++ b/docs/handler-spec.md @@ -211,300 +211,4 @@ Sets up blocks, checks chain state, and verifies that the chain tip changes as e ## Method Reference -Methods are grouped by functional area. Each method documents its parameters, return values, and possible errors. - -### Context Management - -#### `btck_context_create` - -Creates a context with specified chain parameters. - -**Parameters:** -- `chain_parameters` (object, required): - - `chain_type` (string, required): Chain type ("btck_ChainType_MAINNET", "btck_ChainType_TESTNET", "btck_ChainType_TESTNET_4", "btck_ChainType_SIGNET", "btck_ChainType_REGTEST") - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$context"}`) - -**Error:** `{}` when operation fails (C API returned null) - ---- - -#### `btck_context_destroy` - -Destroys a context and frees associated resources. - -**Parameters:** -- `context` (reference, required): Context reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) - ---- - -### Chainstate Manager Operations - -#### `btck_chainstate_manager_create` - -Creates a chainstate manager from a context. - -**Parameters:** -- `context` (reference, required): Context reference from `btck_context_create` - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$chainstate_manager"}`) - -**Error:** `{}` when operation fails (C API returned null) - ---- - -#### `btck_chainstate_manager_get_active_chain` - -Retrieves the currently active chain from the chainstate manager. - -**Parameters:** -- `chainstate_manager` (reference, required): Chainstate manager reference - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$chain"}`) - -**Error:** `null` (cannot return error) - ---- - -#### `btck_chainstate_manager_process_block` - -Processes a block through validation checks, disk storage, and UTXO set validation; successful processing does not indicate block validity. - -**Parameters:** -- `chainstate_manager` (reference, required): Chainstate manager reference -- `block` (reference, required): Block reference from `btck_block_create` - -**Result:** Object containing: -- `new_block` (boolean): `true` if this block was not processed before, `false` otherwise - -**Error:** `{}` when processing fails - ---- - -#### `btck_chainstate_manager_destroy` - -Destroys a chainstate manager and frees associated resources. - -**Parameters:** -- `chainstate_manager` (reference, required): Chainstate manager reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) - ---- - -### Chain Operations - -#### `btck_chain_get_height` - -Gets the current height of the active chain. - -**Parameters:** -- `chain` (reference, required): Chain reference from `btck_chainstate_manager_get_active_chain` - -**Result:** Integer - The chain height (0 = genesis) - -**Error:** `null` (cannot return error) - ---- - -#### `btck_chain_get_by_height` - -Retrieves a block tree entry at a specific height in the chain. - -**Parameters:** -- `chain` (reference, required): Chain reference -- `block_height` (integer, required): Height to query - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$block_tree_entry"}`) - -**Error:** `{}` when height is out of bounds (C API returned null) - ---- - -#### `btck_chain_contains` - -Checks whether a block tree entry is part of the active chain. - -**Parameters:** -- `chain` (reference, required): Chain reference -- `block_tree_entry` (reference, required): Block tree entry reference to check - -**Result:** Boolean - true if block is in the active chain, false otherwise - -**Error:** `null` (cannot return error) - ---- - -### Block Operations - -#### `btck_block_create` - -Creates a block object from raw block data. - -**Parameters:** -- `raw_block` (string, required): Hex-encoded raw block data - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$block"}`) - -**Error:** `{}` when operation fails (C API returned null) - ---- - -#### `btck_block_tree_entry_get_block_hash` - -Gets the block hash from a block tree entry. - -**Parameters:** -- `block_tree_entry` (reference, required): Block tree entry reference from `btck_chain_get_by_height` - -**Result:** String - The block hash (hex-encoded, 64 characters) - -**Error:** `null` (cannot return error) - ---- - -### Script Pubkey Operations - -#### `btck_script_pubkey_create` - -Creates a script pubkey object from hex-encoded data. - -**Parameters:** -- `script_pubkey` (string, required): Hex-encoded script pubkey data - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$script_pubkey"}`) - -**Error:** `{}` when operation fails (C API returned null) - ---- - -#### `btck_script_pubkey_destroy` - -Destroys a script pubkey and frees associated resources. - -**Parameters:** -- `script_pubkey` (reference, required): Script pubkey reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) - ---- - -#### `btck_script_pubkey_verify` - -Verifies a script pubkey against spending conditions. - -**Parameters:** -- `script_pubkey` (reference, required): Reference to a ScriptPubkey from `btck_script_pubkey_create` -- `amount` (number, required): Amount of the script pubkey's associated output. May be zero if the witness flag is not set -- `tx_to` (reference, required): Reference to a Transaction from `btck_transaction_create` -- `precomputed_txdata` (reference, optional): Reference to PrecomputedTransactionData from `btck_precomputed_transaction_data_create`. Required when the taproot flag is set -- `input_index` (number, required): Index of the input in tx_to spending the script_pubkey -- `flags` (array of strings, required): Script verification flags controlling validation constraints. Valid flags include: - - `btck_ScriptVerificationFlags_NONE` - - `btck_ScriptVerificationFlags_P2SH` - - `btck_ScriptVerificationFlags_DERSIG` - - `btck_ScriptVerificationFlags_NULLDUMMY` - - `btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY` - - `btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY` - - `btck_ScriptVerificationFlags_WITNESS` - - `btck_ScriptVerificationFlags_TAPROOT` - -**Result:** Boolean - true if script is valid, false if invalid - -**Error:** On error, returns error code with type `btck_ScriptVerifyStatus` and member can be one of: -- `ERROR_INVALID_FLAGS_COMBINATION` - Invalid or inconsistent verification flags were provided. This occurs when the supplied `script_verify_flags` combination violates internal consistency rules. -- `ERROR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required but were not provided (e.g., for Taproot verification). - ---- - -### Transaction Operations - -#### `btck_transaction_create` - -Creates a transaction object from raw hex-encoded transaction data. - -**Parameters:** -- `raw_transaction` (string, required): Hex-encoded raw transaction data - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$transaction"}`) - -**Error:** `{}` when operation fails (C API returned null, e.g., invalid transaction bytes) - ---- - -#### `btck_transaction_destroy` - -Destroys a transaction and frees associated resources. - -**Parameters:** -- `transaction` (reference, required): Transaction reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) - ---- - -### Transaction Output Operations - -#### `btck_transaction_output_create` - -Creates a transaction output from a script pubkey reference and amount. - -**Parameters:** -- `script_pubkey` (reference, required): Reference to a ScriptPubkey from `btck_script_pubkey_create` -- `amount` (number, required): Amount in satoshis - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$transaction_output"}`) - -**Error:** `null` (cannot return error) - ---- - -#### `btck_transaction_output_destroy` - -Destroys a transaction output and frees associated resources. - -**Parameters:** -- `transaction_output` (reference, required): Transaction output reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) - ---- - -### Precomputed Transaction Data Operations - -#### `btck_precomputed_transaction_data_create` - -Creates precomputed transaction data for script verification. Precomputed data is reusable when verifying multiple inputs of the same transaction. - -**Parameters:** -- `tx_to` (reference, required): Reference to a Transaction from `btck_transaction_create` -- `spent_outputs` (array of references, optional): Array of references to TransactionOutput objects from `btck_transaction_output_create`. Required when `btck_ScriptVerificationFlags_TAPROOT` is set - -**Result:** Reference type - Object containing the reference name from the request `ref` field (e.g., `{"ref": "$precomputed_txdata"}`) - -**Error:** `{}` when operation fails (C API returned null) - ---- - -#### `btck_precomputed_transaction_data_destroy` - -Destroys precomputed transaction data and frees associated resources. - -**Parameters:** -- `precomputed_txdata` (reference, required): Precomputed transaction data reference to destroy - -**Result:** `null` (void operation) - -**Error:** `null` (cannot return error) +Handler method definitions are maintained in the auto-generated [methods-spec.md](./methods-spec.md). diff --git a/docs/methods-spec.md b/docs/methods-spec.md new file mode 100644 index 0000000..dc7c2c6 --- /dev/null +++ b/docs/methods-spec.md @@ -0,0 +1,867 @@ + + +## Method Reference + +Methods are sorted alphabetically. Each method documents its parameters, return values, and possible errors. + +#### `btck_block_copy` + +Copies a block. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** Reference - Contains the copied block (e.g., `{"ref": "$block_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_count_transactions` + +Returns the number of transactions in a block. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** Integer - The transaction count + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_create` + +Creates a block object from raw block data. + +**Parameters:** +- `raw_block` (string, required): Hex-encoded raw block data + +**Result:** Reference - Contains the created block (e.g., `{"ref": "$block"}`) + +**Error:** `{}` when operation fails + +--- + +#### `btck_block_destroy` + +Destroys a block. + +**Parameters:** +- `block` (reference, required): Block reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_get_hash` + +Gets the hash of a block. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** Reference - Contains the returned block hash (e.g., `{"ref": "$block_hash"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_get_header` + +Gets the block header from a block. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** Reference - Contains the returned block header (e.g., `{"ref": "$header"}`). The returned block header reference depends on the lifetime of the parent block and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_get_transaction_at` + +Retrieves the transaction at the given index from a block. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` +- `transaction_index` (integer, required): Zero-based transaction index + +**Result:** Reference - Contains the returned transaction (e.g., `{"ref": "$transaction"}`). The returned transaction reference depends on the lifetime of the parent block and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_hash_copy` + +Copies a block hash. + +**Parameters:** +- `block_hash` (reference, required): Block hash reference + +**Result:** Reference - Contains the copied block hash (e.g., `{"ref": "$block_hash_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_hash_create` + +Creates a block hash object from raw 32-byte block hash data. + +**Parameters:** +- `block_hash` (string, required): Hex-encoded raw 32-byte block hash data + +**Result:** Reference - Contains the created block hash (e.g., `{"ref": "$block_hash"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_hash_destroy` + +Destroys a block hash. + +**Parameters:** +- `block_hash` (reference, required): Block hash reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_hash_equals` + +Checks if two block hashes are equal. + +**Parameters:** +- `hash1` (reference, required): First block hash reference +- `hash2` (reference, required): Second block hash reference + +**Result:** Boolean - `true` if the hashes are equal + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_hash_to_bytes` + +Returns the raw 32-byte block hash as a hex string. + +**Parameters:** +- `block_hash` (reference, required): Block hash reference + +**Result:** String - Hex-encoded raw 32-byte block hash data + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_copy` + +Copies a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Reference - Contains the copied block header (e.g., `{"ref": "$header_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_create` + +Creates a block header object from raw serialized header data. + +**Parameters:** +- `raw_block_header` (string, required): Hex-encoded raw block header data. At least 80 bytes are required; if additional bytes are provided, only the first 80 bytes are used to create the header. + +**Result:** Reference - Contains the created block header (e.g., `{"ref": "$header"}`) + +**Error:** `{}` if fewer than 80 bytes are provided for the serialized block header + +--- + +#### `btck_block_header_destroy` + +Destroys a block header. + +**Parameters:** +- `header` (reference, required): Block header reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_bits` + +Gets the nBits difficulty target of a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Integer - The nBits value + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_hash` + +Gets the hash of a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Reference - Contains the returned block hash (e.g., `{"ref": "$block_hash"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_nonce` + +Gets the nonce of a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Integer - The nonce value + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_prev_hash` + +Gets the previous block hash from a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Reference - Contains the returned previous block hash (e.g., `{"ref": "$prev_hash"}`). The returned block hash reference depends on the lifetime of the parent block header and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_timestamp` + +Gets the timestamp of a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Integer - The block timestamp as a Unix timestamp + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_header_get_version` + +Gets the version field of a block header. + +**Parameters:** +- `header` (reference, required): Block header reference + +**Result:** Integer - The block version + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_to_bytes` + +Returns the consensus-serialized block as a hex string. + +**Parameters:** +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** String - Hex-encoded consensus serialization of the block + +**Error:** `null` (cannot return error) + +--- + +#### `btck_block_tree_entry_get_block_hash` + +Gets the block hash from a block tree entry. + +**Parameters:** +- `block_tree_entry` (reference, required): Block tree entry reference from `btck_chain_get_by_height` + +**Result:** Reference - Contains the returned block hash (e.g., `{"ref": "$block_hash"}`). The returned block hash reference is a view that depends on the lifetime of the parent block tree entry and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_chain_contains` + +Checks whether a block tree entry is part of the active chain. + +**Parameters:** +- `chain` (reference, required): Chain reference +- `block_tree_entry` (reference, required): Block tree entry reference to check + +**Result:** Boolean - true if block is in the active chain, false otherwise + +**Error:** `null` (cannot return error) + +--- + +#### `btck_chain_get_by_height` + +Retrieves a block tree entry at a specific height in the chain. + +**Parameters:** +- `chain` (reference, required): Chain reference +- `block_height` (integer, required): Height to query + +**Result:** Reference - Contains the returned block tree entry (e.g., `{"ref": "$block_tree_entry"}`). The returned block tree entry reference depends on the lifetime of the parent chain reference and does not require an explicit destroy call. + +**Error:** `{}` if the requested height is out of bounds + +--- + +#### `btck_chain_get_height` + +Gets the current height of the active chain. + +**Parameters:** +- `chain` (reference, required): Chain reference from `btck_chainstate_manager_get_active_chain` + +**Result:** Integer - The chain height (0 = genesis) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_chainstate_manager_create` + +Creates a chainstate manager from a context. + +**Parameters:** +- `context` (reference, required): Context reference from `btck_context_create` + +**Result:** Reference - Contains the created chainstate manager (e.g., `{"ref": "$chainstate_manager"}`) + +**Error:** `{}` when operation fails + +--- + +#### `btck_chainstate_manager_destroy` + +Destroys a chainstate manager and frees associated resources. + +**Parameters:** +- `chainstate_manager` (reference, required): Chainstate manager reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_chainstate_manager_get_active_chain` + +Retrieves the currently active chain from the chainstate manager. + +**Parameters:** +- `chainstate_manager` (reference, required): Chainstate manager reference + +**Result:** Reference - Contains the returned active chain (e.g., `{"ref": "$chain"}`). The returned chain reference depends on the lifetime of the parent chainstate manager and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_chainstate_manager_process_block` + +Processes a block through validation checks, disk storage, and UTXO set validation; successful processing does not indicate block validity. + +**Parameters:** +- `chainstate_manager` (reference, required): Chainstate manager reference +- `block` (reference, required): Block reference from `btck_block_create` + +**Result:** Object containing: +- `new_block` (boolean): `true` if this block was not processed before, `false` otherwise + +**Error:** `{}` when operation fails + +--- + +#### `btck_context_create` + +Creates a context with specified chain parameters. + +**Parameters:** +- `chain_parameters` (object, required) + - `chain_type` (string, required): Chain type. Allowed values: + - `btck_ChainType_MAINNET` + - `btck_ChainType_TESTNET` + - `btck_ChainType_TESTNET_4` + - `btck_ChainType_SIGNET` + - `btck_ChainType_REGTEST` + +**Result:** Reference - Contains the created context (e.g., `{"ref": "$context"}`) + +**Error:** `{}` when operation fails + +--- + +#### `btck_context_destroy` + +Destroys a context and frees associated resources. + +**Parameters:** +- `context` (reference, required): Context reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_precomputed_transaction_data_create` + +Creates precomputed transaction data for script verification. Precomputed data is reusable when verifying multiple inputs of the same transaction. + +**Parameters:** +- `tx_to` (reference, required): Reference to a Transaction from `btck_transaction_create` +- `spent_outputs` (array of references, optional): Array of references to TransactionOutput objects from `btck_transaction_output_create`. Required when `btck_ScriptVerificationFlags_TAPROOT` is set + +**Result:** Reference - Contains the created precomputed transaction data (e.g., `{"ref": "$precomputed_txdata"}`) + +**Error:** `{}` when operation fails + +--- + +#### `btck_precomputed_transaction_data_destroy` + +Destroys precomputed transaction data and frees associated resources. + +**Parameters:** +- `precomputed_txdata` (reference, required): Precomputed transaction data reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_script_pubkey_copy` + +Copies a script pubkey. + +**Parameters:** +- `script_pubkey` (reference, required): Script pubkey reference + +**Result:** Reference - Contains the copied script pubkey (e.g., `{"ref": "$script_pubkey_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_script_pubkey_create` + +Creates a script pubkey object from hex-encoded data. + +**Parameters:** +- `script_pubkey` (string, required): Hex-encoded script pubkey data + +**Result:** Reference - Contains the created script pubkey (e.g., `{"ref": "$script_pubkey"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_script_pubkey_destroy` + +Destroys a script pubkey and frees associated resources. + +**Parameters:** +- `script_pubkey` (reference, required): Script pubkey reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_script_pubkey_to_bytes` + +Serializes a script pubkey to raw bytes encoded as hex. + +**Parameters:** +- `script_pubkey` (reference, required): Script pubkey reference + +**Result:** String - Hex-encoded serialized script pubkey bytes + +**Error:** `null` (cannot return error) + +--- + +#### `btck_script_pubkey_verify` + +Verifies a script pubkey against spending conditions. + +**Parameters:** +- `script_pubkey` (reference, required): Reference to a ScriptPubkey from `btck_script_pubkey_create` +- `amount` (number, required): Amount of the script pubkey's associated output. May be zero if the witness flag is not set +- `tx_to` (reference, required): Reference to a Transaction from `btck_transaction_create` +- `precomputed_txdata` (reference, optional): Reference to PrecomputedTransactionData from `btck_precomputed_transaction_data_create`. Required when the taproot flag is set +- `input_index` (number, required): Index of the input in tx_to spending the script_pubkey +- `flags` (array of strings, required): Script verification flags controlling validation constraints. Allowed values: + - `btck_ScriptVerificationFlags_NONE` + - `btck_ScriptVerificationFlags_P2SH` + - `btck_ScriptVerificationFlags_DERSIG` + - `btck_ScriptVerificationFlags_NULLDUMMY` + - `btck_ScriptVerificationFlags_CHECKLOCKTIMEVERIFY` + - `btck_ScriptVerificationFlags_CHECKSEQUENCEVERIFY` + - `btck_ScriptVerificationFlags_WITNESS` + - `btck_ScriptVerificationFlags_TAPROOT` + +**Result:** Boolean - true if script is valid, false if invalid + +**Error:** On error, returns `{"code": {"type": "btck_ScriptVerifyStatus", "member": ...}}` where `member` can be one of: +- `ERROR_INVALID_FLAGS_COMBINATION` - Invalid or inconsistent verification flags were provided. This occurs when the supplied `script_verify_flags` combination violates internal consistency rules. +- `ERROR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required but were not provided (e.g., for Taproot verification). + +--- + +#### `btck_transaction_copy` + +Copies a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference + +**Result:** Reference - Contains the copied transaction (e.g., `{"ref": "$transaction_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_count_inputs` + +Returns the number of inputs in a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference + +**Result:** Integer - The input count + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_count_outputs` + +Returns the number of outputs in a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference + +**Result:** Integer - The output count + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_create` + +Creates a transaction object from raw hex-encoded transaction data. + +**Parameters:** +- `raw_transaction` (string, required): Hex-encoded raw transaction data + +**Result:** Reference - Contains the created transaction (e.g., `{"ref": "$transaction"}`) + +**Error:** `{}` when operation fails + +--- + +#### `btck_transaction_destroy` + +Destroys a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_get_input_at` + +Retrieves the input at the given index from a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference +- `input_index` (integer, required): Zero-based input index + +**Result:** Reference - Contains the returned transaction input (e.g., `{"ref": "$transaction_input"}`). The returned transaction input reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_get_output_at` + +Retrieves the output at the given index from a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference +- `output_index` (integer, required): Zero-based output index + +**Result:** Reference - Contains the returned transaction output (e.g., `{"ref": "$transaction_output"}`). The returned transaction output reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_get_txid` + +Gets the txid of a transaction. + +**Parameters:** +- `transaction` (reference, required): Transaction reference or transaction view reference + +**Result:** Reference - Contains the returned txid (e.g., `{"ref": "$txid"}`). The returned txid reference is a view that depends on the lifetime of the parent transaction and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_input_copy` + +Copies a transaction input. + +**Parameters:** +- `transaction_input` (reference, required): Transaction input reference + +**Result:** Reference - Contains the copied transaction input (e.g., `{"ref": "$transaction_input_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_input_destroy` + +Destroys a transaction input. + +**Parameters:** +- `transaction_input` (reference, required): TransactionInput reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_input_get_out_point` + +Gets the out point from a transaction input. + +**Parameters:** +- `transaction_input` (reference, required): Transaction input reference + +**Result:** Reference - Contains the returned transaction out point (e.g., `{"ref": "$transaction_out_point"}`). The returned transaction out point reference is a view that depends on the lifetime of the parent transaction input and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_out_point_copy` + +Copies a transaction out point. + +**Parameters:** +- `transaction_out_point` (reference, required): Transaction out point reference + +**Result:** Reference - Contains the copied transaction out point (e.g., `{"ref": "$transaction_out_point_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_out_point_destroy` + +Destroys a transaction out point. + +**Parameters:** +- `transaction_out_point` (reference, required): Transaction out point reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_out_point_get_index` + +Gets the output index from a transaction out point. + +**Parameters:** +- `transaction_out_point` (reference, required): Transaction out point reference + +**Result:** Integer - The output index + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_out_point_get_txid` + +Gets the txid from a transaction out point. + +**Parameters:** +- `transaction_out_point` (reference, required): Transaction out point reference + +**Result:** Reference - Contains the returned txid (e.g., `{"ref": "$txid"}`). The returned txid reference is a view that depends on the lifetime of the parent transaction out point and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_output_copy` + +Copies a transaction output. + +**Parameters:** +- `transaction_output` (reference, required): Transaction output reference + +**Result:** Reference - Contains the copied transaction output (e.g., `{"ref": "$transaction_output_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_output_create` + +Creates a transaction output from a script pubkey reference and amount. + +**Parameters:** +- `script_pubkey` (reference, required): Reference to a ScriptPubkey from `btck_script_pubkey_create` +- `amount` (number, required): Amount in satoshis + +**Result:** Reference - Contains the created transaction output (e.g., `{"ref": "$transaction_output"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_output_destroy` + +Destroys a transaction output. + +**Parameters:** +- `transaction_output` (reference, required): Transaction output reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_output_get_amount` + +Gets the amount in satoshis from a transaction output. + +**Parameters:** +- `transaction_output` (reference, required): Transaction output reference + +**Result:** Integer - The amount in satoshis + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_output_get_script_pubkey` + +Gets the script pubkey of a transaction output. + +**Parameters:** +- `transaction_output` (reference, required): Transaction output reference + +**Result:** Reference - Contains the returned script pubkey (e.g., `{"ref": "$script_pubkey"}`). The returned script pubkey reference is a view that depends on the lifetime of the parent transaction output and does not require an explicit destroy call. + +**Error:** `null` (cannot return error) + +--- + +#### `btck_transaction_to_bytes` + +Returns the consensus-serialized transaction as a hex string. + +**Parameters:** +- `transaction` (reference, required): Transaction reference + +**Result:** String - Hex-encoded consensus serialization of the transaction + +**Error:** `null` (cannot return error) + +--- + +#### `btck_txid_copy` + +Copies a txid. + +**Parameters:** +- `txid` (reference, required): Txid reference + +**Result:** Reference - Contains the copied txid (e.g., `{"ref": "$txid_copy"}`) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_txid_destroy` + +Destroys a txid. + +**Parameters:** +- `txid` (reference, required): Txid reference to destroy + +**Result:** `null` (void operation) + +**Error:** `null` (cannot return error) + +--- + +#### `btck_txid_equals` + +Checks if two txids are equal. + +**Parameters:** +- `txid1` (reference, required): First txid reference +- `txid2` (reference, required): Second txid reference + +**Result:** Boolean - `true` if the txids are equal + +**Error:** `null` (cannot return error) + +--- + +#### `btck_txid_to_bytes` + +Returns the txid as raw bytes encoded as hex. + +**Parameters:** +- `txid` (reference, required): Txid reference + +**Result:** String - Hex-encoded raw 32-byte txid + +**Error:** `null` (cannot return error) From 9c1b9e0c658b4288c903dfffc7d543d507661556 Mon Sep 17 00:00:00 2001 From: stringintech Date: Wed, 13 May 2026 18:59:54 +0330 Subject: [PATCH 6/7] Update CI to validate suites and generated methods spec --- .github/workflows/test.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c0ea44..3d6a7db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,3 +22,14 @@ jobs: - name: Run tests run: make test + + - name: Validate test suites + run: make suite-validate + + - name: Check generated methods spec doc is up-to-date + run: | + make specgen + if ! git diff --exit-code -- docs/methods-spec.md; then + echo "Generated methods spec doc is out of date. Run 'make specgen' and commit the updated docs/methods-spec.md." + exit 1 + fi From fdffbb9c560a3acd8b29c89effdc5cbfd1e9aa18 Mon Sep 17 00:00:00 2001 From: stringintech Date: Thu, 14 May 2026 00:27:05 +0330 Subject: [PATCH 7/7] Update README for runner releases and schema tooling --- README.md | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 590137f..691c79a 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,11 @@ The framework ensures that all language bindings (Go, Python, Rust, etc.) behave ``` **This repository contains:** -1. [**Handler Specification**](./docs/handler-spec.md): Defines the protocol, message formats, and test suites that handlers must implement -2. [**Test Runner**](./cmd/runner/main.go): Spawns handler binary, sends test requests via stdin, validates responses from stdout -3. [**Test Cases**](./testdata): JSON files defining requests and expected responses -4. [**Mock Handler**](./cmd/mock-handler/main.go): Validates the runner by echoing expected responses from test cases +1. [**Specification**](./docs/handler-spec.md): Defines the handler protocol and links to the generated [**Method Reference**](./docs/methods-spec.md) for method parameters, results, and errors +2. [**Test Suites**](./testdata): JSON files defining requests and expected responses +3. [**Test Runner**](./cmd/runner/main.go): Runs suites against a handler by sending test requests via stdin, validating responses from stdout, and checking them against the expected results +4. [**Schemas**](./docs/schemas): Define the suite format and per-method request/response shapes, with tools in [`cmd/suite-validate`](./cmd/suite-validate) and [`cmd/specgen`](./cmd/specgen) for validation and documentation generation +5. [**Mock Handler**](./cmd/mock-handler/main.go): Validates the runner by echoing expected responses from test cases ** **Handler binaries** are not hosted in this repository. They must be implemented separately following the [**Handler Specification**](./docs/handler-spec.md) and should: - Implement the JSON protocol for communication with the test runner @@ -44,7 +45,11 @@ The framework ensures that all language bindings (Go, Python, Rust, etc.) behave ### Testing Your Binding (Custom Handler) -Test your handler implementation using the test runner: +Test your handler implementation using the test runner. + +You can download a prebuilt runner binary from the latest GitHub release. Tagged releases are published automatically by GoReleaser and include archives for supported platforms. + +If you prefer to build the runner from source: ```bash # Build the test runner @@ -54,11 +59,15 @@ make runner ./build/runner --handler # Configure timeouts (optional) +# Max wait per test case (default: 10s) +# Total execution limit (default: 30s) ./build/runner --handler \ - --handler-timeout 30s \ # Max wait per test case (default: 10s) - --timeout 2m # Total execution limit (default: 30s) + --handler-timeout 30s \ + --timeout 2m ``` +The runner validates each handler response against the method's JSON schema before comparing it with the expected test outcome. + #### Timeout Flags - **`--handler-timeout`** (default: 10s): Maximum time to wait for handler response to each test case. Prevents hangs on unresponsive handlers. @@ -85,7 +94,7 @@ The request chains printed by verbose mode can be directly piped to the handler # # Response: # ──────────────────────────────────────── -# {"result":"$chain_ref"} +# {"result":{"ref":"$chain_ref"}} # Copy the request chain and pipe it to your handler for debugging: echo '{"id":"chain#1","method":"btck_context_create","params":{"chain_parameters":{"chain_type":"btck_ChainType_REGTEST"}},"ref":"$context_ref"} @@ -103,4 +112,17 @@ make build # Run runner unit tests and integration tests with mock handler make test + +# Validate all suite JSON files against the suite schema +make suite-validate +``` + +### Updating Generated Documentation + +When schema definitions change, regenerate the method reference: + +```bash +make specgen ``` + +Do not edit [`docs/methods-spec.md`](./docs/methods-spec.md) manually. It is generated from the schema definitions in [`docs/schemas/`](./docs/schemas), so schema changes should be followed by `make specgen`, and CI checks that the generated spec is up to date.