Conversation
This commit enables `serde_json`'s `preserve_order` feature so the pipeline's JSON output has stable, review-friendly key ordering.
This commit threads `UnmappedMethodContext` through codegen call sites so `canonical_from_adapter_method` can include schema category and description when an adapter RPC lacks a normalization mapping. The client and response generators still derive canonical names in the same way, but now have the option to attach richer diagnostics when something is missing. The method wrapper generator also uses the new `protocol_rpc_method_to_rust_name_with_context` helper so any failure to map a method is explained in terms of the original protocol schema.
Use the IR `protocol_type` field when mapping primitive response types to Rust via `BitcoinCoreTypeRegistry`. Primitives must have `protocol_type`. This aligns the response type generator with the adapter domain model so JSON-RPC result types (string, number, amount, etc.) are interpreted consistently. Type meaning stays in the IR.
Treat the `getopenrpcinfo` RPC as a special case in `suggest_canonical_key` so its canonical name becomes `GetOpenRpcInfo` with `RPC` fully capitalized. This keeps the method name consistent with expectations from Bitcoin Core and avoids surprising mixed case in generated identifiers. Adding `openrpc` to `METHOD_WORDS` also teaches the greedy segmenter about this noun so future normalization stays stable as the schema evolves.
Filter protocol IR by version_added/version_removed so only RPCs present in the requested Core version are compiled (Bitcoin Core only).
The response type generator now uses BTreeMap and BTreeSet instead of HashMap and HashSet when collecting nested types and building the type registry. Emission order of generated structs in responses.rs is now stable across runs. Schema edits, such as removing a single field or method, no longer reshuffle unrelated types in the output. Diffs stay localized and reviewable. A regression test ensures that when the set of nested types shrinks, the relative order of the remaining structs is unchanged.
Extends the codegen mapping table so that concatenated or camelCase wire names (e.g. addrbind, scriptPubKey) are converted to idiomatic snake_case Rust identifiers (addr_bind, script_pubkey). The wire format is unchanged because codegen already emits `#[serde(rename = "...")]` when the Rust name differs from the wire key. This allows generated response structs to use readable, consistent field names such as `addr_bind` and `script_pubkey` instead of the raw Core keys, so downstream code is easier to read and matches Rust naming conventions. Covers getpeerinfo, getaddednodeinfo, listunspent, and other RPCs that return these fields. CamelCase names like scriptPubKey and redeemScript are included so that all generated structs use the same snake_case convention (e.g. script_pubkey) wherever those fields appear.
This change gives top-level array RPCs a stable element type name in the Bitcoin Core OpenRPC adapter. The adapter now uses `top_level_array_element_type_name` to assign a concrete `TypeDef.name` for array elements of methods listed in `TOP_LEVEL_ARRAY_METHODS`, such as `getpeerinfo`. Previously these element types were emitted as an anonymous `object`, which made it hard for downstream codegen to recognise and reuse the same logical shape. By naming the element type at the IR layer, downstream generators can emit dedicated structs instead of defaulting to `serde_json::Value`. This ensures that schema changes in `x-bitcoin-results` for array elements can be reflected in strongly typed response models. The behavior remains backward compatible for non-object elements, which still use the existing mapping logic.
Rename all script-pubkey-related identifiers to `script_pubkey` in the Bitcoin Core adapter and in the decoded tx codegen. Category rules now match on the field name `script_pubkey`, and the emitted structs for prevout and tx output use a `script_pubkey` field (still deserialized from JSON "scriptPubKey" via serde). The codegen parameter is renamed from `skip_decoded_script_pub_key` to `skip_decoded_script_pubkey`. This keeps a single naming convention for the script pubkey field in Rust and avoids mixing "script_pub_key" and "script_pubkey" across the codebase. New readers see one consistent name while behaviour and JSON compatibility stay the same.
Teaches `map_ir_type_to_rust` to map IR objects with a single numeric `msg` field into `HashMap<String, u64>` instead of `serde_json::Value`. This allows dynamic per-message byte statistics from `getpeerinfo` to be represented as typed maps in Raw clients whenever the IR encodes them as `OBJ_DYN` with numeric values. This keeps the generator mechanical and schema-driven while still surfacing the stronger type information
This change updates the version-specific response type generator to use named IR element types for top-level array RPCs when they are available. The generator now checks the array element `TypeDef` and, when it is an `Object` with a non-generic `name`, uses that name directly as the Rust element type. Previously, array elements were passed through `map_ir_type_to_rust`, which often collapsed rich object shapes into `serde_json::Value`. By respecting the element type name created by the adapter, the generator can emit dedicated structs such as `GetpeerinfoElement` instead of opaque JSON values. This ensures that changes in `x-bitcoin-results` for array elements become visible as schema changes in the downstream client types. The existing mapping logic remains in place as a fallback when no specific element type name is present in the IR.
Introduce the `ethos-normalization` crate as the shared home for RPC normalization and canonicalization helpers. This moves types such as `UnmappedMethodContext`, `SuggestedMapping`, and `UnmappedMethodsError` and functions like `canonical_from_adapter_method` and `validate_method_mappings` out of `codegen` into a dedicated primitives crate. The compiler pipeline now reads `NORMALIZATION_JSON_DIRS` from this crate, so error messages and suggested mappings are driven from a single source of truth. Existing callers in `codegen` and the pipeline are updated to depend on `ethos-normalization` without changing the observable behavior of generated code. This refactor prepares the rest of the workspace to reuse normalization logic, avoiding a second copy of the JSON wiring and naming rules in adapters or future protocol integrations.
Teach the Bitcoin Core adapter to derive top level array element type names from the same canonical mapping used for response structs. The adapter now calls `bitcoin_canonical_from_adapter_method` from `ethos-normalization`, falling back to `normalization::suggest_canonical_key` when a method has not yet been mapped. This replaces the previous heuristic that capitalized only the first character of the method name before appending `Element`, which produced inconsistent identifiers such as `GetaddednodeinfoElement`. By delegating to the shared normalization crate, element types like `ListUnspentElement` stay aligned with their corresponding response types, reducing surprises for users of the generated API. This change confines behavior to the adapter, building directly on the earlier refactor that centralized the normalization logic.
The codegen was adding `use bitcoin::Transaction` whenever any type name contained "Transaction", so GetBlockTemplateTransaction and similar structs triggered the import even though they do not use the bitcoin crate type. We now set needs_transaction only when the generated field type is BitcoinTransaction or contains bitcoin::Transaction, so downstream generated code no longer has an unused import and builds without warnings.
Rust identifiers must not start with a digit. Schema keys like `10th_percentile_feerate` were being sanitized to invalid Rust names. We now prefix such results with `n` so generated code compiles; callers that need the original JSON key can keep using `#[serde(rename)]`. This keeps codegen correct for RPCs that expose numeric-prefixed fields without changing the external API contract.
IR and OpenRPC type names can contain `/` or `-`, which are invalid in Rust type names. This helper normalizes them to underscores and converts to PascalCase so generated struct names compile and satisfy `non_camel_case_types`. Later commits will use it in the registry and when emitting nested types so names like `GetrawaddrmanBucket/position` become `GetrawaddrmanBucketPosition` in code.
This test builds a decodepsbt-style result (tx, inputs, outputs with named element types) and asserts the generated response uses `DecodepsbtTx`, `Vec<DecodepsbtInput>`, and `Vec<DecodepsbtOutput>`.
The compiler no longer writes a timestamped promotion_map JSON file when type canonicalization detects duplicates. That file was only for debugging and is not part of the build or library contract. Dropping the output_dir parameter from run_compiler_passes simplifies the API and keeps the compiler focused on transforming IR. Call sites in the pipeline and CLI orchestrator are updated to match.
sort_definitions_by_name now orders ProtocolDef so that Type definitions come first (by type name) and RpcMethod definitions second (by method name). This keeps canonical type definitions before any method that references them, which the codegen expects when resolving top-level types from the IR. The sort remains deterministic and consistent across code paths. Made-with: Cursor
The Bitcoin Core versioned generator now collects top-level type definitions from the IR (canonical types like DecodedScriptPubKey) and passes them into VersionSpecificResponseTypeGenerator. The registry is seeded with these types; refs (TypeDef with canonical_name set and no fields) are skipped when walking method results so they are not re-added or overwritten. When top_level_types is not set, the previous first-occurrence-wins behavior remains, with merge_descriptions_into_type_def propagating non-empty descriptions from later occurrences. This allows the adapter to define shared types once and reference them everywhere without the codegen clobbering or duplicating them.
This change introduces a single helper, `canonical_method_pascal`, for deriving the canonical PascalCase method name from an adapter method. Previously, `top_level_array_element_type_name` performed this logic inline, which duplicated the same normalization concerns that other parts of the codebase already handle. By calling `canonical_method_pascal` and then appending the `Element` suffix, the function now delegates all naming decisions to the shared normalization layer. This prepares the codebase for later commits that will reuse the same helper to name nested result types in a consistent, protocol-driven way.
This change threads the RPC method name through `convert_result` and `merge_results_to_object` so that nested result objects can be named in a stable, method-scoped way. The new helper `result_key_pascal_suffix` derives a simple PascalCase suffix from each result key, with small special cases like `inputs` and `outputs`, and combines it with the canonical method prefix from `canonical_method_pascal`. As a result, decoded result shapes such as `decodepsbt` now produce predictable type names like `DecodepsbtTx` and `DecodepsbtInput` instead of anonymous `object` types. This makes the generated IR easier to understand, keeps downstream Rust codegen from falling back to generic `serde_json::Value`, and aligns naming across adapters and the shared normalization crate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bump bitcoind client crate to v30.2.10