Skip to content

Bug: panic in DSL macro when using invalid RelLockTime value #403

@AmosOO7

Description

@AmosOO7

Description:
The descriptor! DSL macro in src/descriptor/dsl.rs previously used .expect("valid RelLockTime") when converting an integer into a miniscript::RelLockTime. RelLockTime::from_consensus() is fallible and
returns an error when the provided value does not fit in the 24-bit field (e.g. 0x80000000). The .expect() caused a panic during macro expansion, leading to a crash in calling code instead of a proper error.

This issue is particularly surprising because:

  1. String-based descriptor parsing does not perform this validation and accepts arbitrary u32 values, so users might not realise the macro is more strict.
  2. The panic leaks through into tests and consumers, making it hard to handle programmatically.

Steps to reproduce:

let _ = descriptor!(wsh(older(0x80000000))).unwrap();

Running the above results in a panic with message valid \RelLockTime``.

Expected behaviour:
The macro should return a Err(DescriptorError::RelLockTime(_)) for out-of-range values, allowing callers to handle the failure.

Additional context:

  • RelLockTimeError already implements Display with a helpful message; the underlying bitcoin/miniscript crates provide user-friendly errors.
  • RelLockTime values must be less than 16_777_216 (24 bits). Values with the high bit set are invalid.

Proposed fix outline:

  • Change the older rule in dsl.rs to match on RelLockTime::from_consensus() and propagate errors into
    DescriptorError::RelLockTime instead of unwrapping.
  • Add RelLockTime(miniscript::RelLockTimeError) variant to descriptor::error::Error with Display and From implementations.
  • Add unit tests covering valid, invalid, and edge-case values.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status

In Progress

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions