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 diff --git a/Makefile b/Makefile index 37c99fb..6186a1b 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 specgen 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,20 @@ 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 + +specgen: + @echo "Generating method reference from schemas..." + go run ./cmd/specgen + clean: @echo "Cleaning build artifacts..." rm -rf $(BUILD_DIR) 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. 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/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/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/handler-spec.md b/docs/handler-spec.md index ae488aa..c87306d 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). @@ -167,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) 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/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/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= diff --git a/runner/runner.go b/runner/runner.go index 41afed3..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 @@ -120,8 +124,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 @@ -201,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, @@ -210,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, } } @@ -330,11 +358,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 +386,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/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) +} 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/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 a5c5c86..6f0f042 100644 --- a/testdata/chain.json +++ b/testdata/chain.json @@ -1,10 +1,10 @@ { - "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": [ { - "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 cd684c8..b8bac39 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": [ @@ -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 dada662..c239c8a 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": [ @@ -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 583a8bc..23a7dcf 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": [ @@ -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 0fb9951..997400c 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": [ @@ -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 09ae587..40ee315 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": [ @@ -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 c7eb2fd..eaaf714 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": [ @@ -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 64647a7..d0cc024 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": [ @@ -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 bbb426b..f4de5b2 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": [ @@ -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 b8d193a..4604645 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": [ @@ -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 e1b13ae..03e2068 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": [ @@ -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 932cd4b..5967842 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": [ @@ -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": {} + } + ] +}