Skip to content

v30.2.10#25

Merged
nervana21 merged 28 commits intomainfrom
v30.2.10
Mar 18, 2026
Merged

v30.2.10#25
nervana21 merged 28 commits intomainfrom
v30.2.10

Conversation

@nervana21
Copy link
Owner

Bump bitcoind client crate to v30.2.10

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.
@nervana21 nervana21 merged commit 323585e into main Mar 18, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant