Skip to content

compile doesn't validate keys and returns unusable descriptors #344

Description

@vadim-anfv

Description

compile doesn't check that keys in the policy are actual keys. It succeeds and returns a descriptor that fails only later, when someone tries to use it:

$ bdk-cli compile "pk(ABC)"
{
  "descriptor": "wsh(pk(ABC))#8gmtcnaw"
}

$ bitcoin-cli deriveaddresses "wsh(pk(ABC))#8gmtcnaw"
error code: -5
error message:
pk(): key 'ABC' is not valid

The policy is parsed as Concrete<String>, and a String key accepts anything.

Came up before in #225 and in the #317 review.

Proposed fix

Parse as Concrete<DescriptorPublicKey> by default. Keys are validated at parse time, so placeholders are rejected while real keys and xpubs keep working. Hashes are typed too, so sha256(H) is rejected the same way.

Keep the current behavior behind a flag, e.g. --allow-placeholders, since pk(A) style policies are handy to see what a policy compiles to, and in tests where only the policy shape matters, not the keys. This breaks existing calls with placeholders, docs and tests would need the flag or real keys.

# placeholder key is rejected
$ bdk-cli compile "pk(ABC)"
Error: Generic error: Invalid policy: unexpected «Key too short (<66 char), doesn't match any format»

# placeholder hash is rejected
$ bdk-cli compile "and(pk(02e5b88fdb71c696e1a473f309a47535b7190e21a22bd25e7fc8bd055db3bba12f),sha256(H))"
Error: Generic error: Invalid policy: unexpected «failed to parse hex»

# real keys and xpubs compile
$ bdk-cli compile "or(pk(02e5b88fdb71c696e1a473f309a47535b7190e21a22bd25e7fc8bd055db3bba12f),pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/0/*))"
{
  "descriptor": "wsh(or_b(pk(02e5b88fdb71c696e1a473f309a47535b7190e21a22bd25e7fc8bd055db3bba12f),s:pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/0/*)))#t459ja6u"
}

# placeholders still work with the flag
$ bdk-cli compile "pk(ABC)" --allow-placeholders
{
  "descriptor": "wsh(pk(ABC))#8gmtcnaw"
}

See

Activity

  1. Olorunshogo commented on Oct 9, 2026

    @Olorunshogo

    I would like to work on this. Planning to change the policy parse type from Concrete<String> to Concrete<DescriptorPublicKey> in CompileCommand::execute, which validates keys and hashes at parse time instead of silently accepting placeholders. I'll add an --allow-placeholders flag to keep the old permissive behavior opt-in (needed for policy-shape-only testing), fix the tr branch's internal-key construction to match the new key type, and update the existing compile tests/docs accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    • Status
      In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions