# Tr(): rawnode() and rawleaf() support

**URL:** <https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901>\
**Category:** Implementation\
**Tags:** taproot, miniscript\
**Created:** [May 22, 2024, 3:25pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901 "2024-05-22T15:25:38Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Eunovo](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/eunovo/32/375_2.png) [@Eunovo](https://delvingbitcoin.org/u/Eunovo)\
**Post date:** [May 22, 2024, 3:25pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/1 "2024-05-22T15:25:38Z")

</div>

Previous discussions on [Issue 24114](https://github.com/bitcoin/bitcoin/issues/24114) and [Partial Descriptors Gist](https://gist.github.com/sipa/06c5c844df155d4e5044c2c8cac9c05e#partial-descriptors) suggests two new descriptors for `tr()`:

- `rawnode(HEXHASH)` which allows the specification of a branch using the merkle hash
- `rawleaf(HEXSCRIPT,[HEXLEAFVER])` which allows the addition of raw scripts with different leaf versions

Arguments for `rawnode()` include:

- Adding support for Need-to-Know-Branches (N2KB) see [Jeremy’s comment on 21365](https://github.com/bitcoin/bitcoin/pull/21365#issuecomment-793027851)
- Allowing users to specify TR trees with omitted information
- Allowing users to simplify TR trees  
As an example, this descriptor:

```auto
tr(
  5a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5,{
    multi_a(
      2,
      tprv8btqJtFL5n1drr8jP95PBgTitQiCJyxDb27gGhbXM2vacGt3gV2Bfs5PHSBt6LbpPs5fUb4hGhD5TXudLrisjd14qtM8EZ3nVSv31jhLuop/*,
      415f59b2ce1ad8f714fd40b71865937dd911ad4742724cead5db936f73029d1e,1a3569fb509ababa09cf896c0a66619d0a01fd235d26b479a42503670beb9754
    ),
   {
     {
       and_v(
         v:older(4320),
         multi_a(
           2,
           ae3f20aee8d8798ceafb1671bf5607a45794676498e2edfac042958f7407ee1c,
           tpubD8asTJHaE9hJkKAXGnjyb67qTSE8UK98AKiTZDdpmJiySm8pJsqmrMhFTZV9cQyCdisA71G9bjGCZXcjXgFWCfjK5rfxVYmbnA5XikwzEHt/*
         )
       ),
       and_v(
         v:older(4320),
         multi_a(
           2,
           ae3f20aee8d8798ceafb1671bf5607a45794676498e2edfac042958f7407ee1c,
           415f59b2ce1ad8f714fd40b71865937dd911ad4742724cead5db936f73029d1e
         )
       )
    },
    {
      and_v(
        v:older(4320),
        multi_a(
          2,
          ae3f20aee8d8798ceafb1671bf5607a45794676498e2edfac042958f7407ee1c,
          1a3569fb509ababa09cf896c0a66619d0a01fd235d26b479a42503670beb9754
        )
      ),
      and_v(
        v:older(12960),
        pk(ae3f20aee8d8798ceafb1671bf5607a45794676498e2edfac042958f7407ee1c)
      )
    }
  }
})#vz6zss2j

```

has been reduced to:

```auto
tr(
  5a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5,
    {
        multi_a(
          2,
          tprv8btqJtFL5n1drr8jP95PBgTitQiCJyxDb27gGhbXM2vacGt3gV2Bfs5PHSBt6LbpPs5fUb4hGhD5TXudLrisjd14qtM8EZ3nVSv31jhLuop/*,
          415f59b2ce1ad8f714fd40b71865937dd911ad4742724cead5db936f73029d1e,
          1a3569fb509ababa09cf896c0a66619d0a01fd235d26b479a42503670beb9754
        ),
        rawnode(8a62dc0a100c4156cc2a4b7c2a97747ce0dfe90562673fd662678aaae93121fb)
    }
)

```

See [test case verifying this](https://github.com/Eunovo/tr-partial-descriptors-test/blob/2449ccddbe7132fa20c2f607e2a807542f07f875/src/main.py#L17-L59)

While it would seem that `rawleaf` offers no advantage since we have `rawnode`, @sipa makes the argument that since the script and leaf version can be communicated via PSBTs, then descriptors should also be able to pass this information [See Sipa’s comment on 24114](https://github.com/bitcoin/bitcoin/issues/24114#issuecomment-1038441246)

There’s an unanswered question about whether `rawleaf(HEXSCRIPT,[HEXLEAFVER])` should just be `raw()` that takes an optional `HEXLEAFVER` under `tr()` but I prefer `rawleaf` to avoid overloading the `raw()` descriptor.

## Implementation

I have created a PoC here [wip-tr-raw-nodes](https://github.com/Eunovo/bitcoin/tree/wip-tr-raw-nodes), see [diff](https://github.com/bitcoin/bitcoin/compare/master...Eunovo:bitcoin:wip-tr-raw-nodes). I created two new `DescriptorImpl` subclasses, `RawNodeDescriptor` and `RawLeafDescriptor`. Both are only valid under `P2TR` context and can be inferred by `InferDescriptor`.

### Descriptor Inference

- If no taptree is inferred, and the Merkle root is not null, then `tr(internal_key,rawnode(merkle_root))` is returned instead of the previous `rawtr(tr_public_key)`. I am not sure if this should be the case. _What advantage does inferring `tr(internal_key,rawnode(merkle_root))` have over inferring `rawtr(tr_public_key)`?_
- `rawleaf` is inferred after no standard scripts could be inferred under a `P2TR` context.

---

<div class="post-metadata">

**Author:** ![josibake](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/josibake/32/83_2.png) [@josibake](https://delvingbitcoin.org/u/josibake)\
**Post date:** [May 22, 2024, 3:28pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/2 "2024-05-22T15:28:00Z")

</div>

cc @ajtowns @sipa @AntoineP , since this work is based off your prior discussions.

---

<div class="post-metadata">

**Author:** ![sipa](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/sipa/32/1100_2.png) [@sipa](https://delvingbitcoin.org/u/sipa)\
**Post date:** [May 28, 2024, 3:49pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/3 "2024-05-28T15:49:08Z")

</div>

Thank you for working on this!

> [@Eunovo](#):
>
> What advantage does inferring `tr(internal_key,rawnode(merkle_root))` have over inferring `rawtr(tr_public_key)`?

It provides strictly more information: the internal key. Philosophically, I think, the idea of partial descriptors is that any subset of relevant information should be conveyable, so that would be sufficient justification for having it. But practically, imagine a signer that recognizes the internal key, but does not recognize the tweaked output key; having the `internal_key` and `merkle_root` would enable them to locate the correct key.

---

<div class="post-metadata">

**Author:** ![Eunovo](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/eunovo/32/375_2.png) [@Eunovo](https://delvingbitcoin.org/u/Eunovo)\
**Post date:** [May 28, 2024, 5:34pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/4 "2024-05-28T17:34:35Z")

</div>

Makes sense. I didn’t see it that way. Thanks! @sipa

---

<div class="post-metadata">

**Author:** ![Eunovo](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/eunovo/32/375_2.png) [@Eunovo](https://delvingbitcoin.org/u/Eunovo)\
**Post date:** [May 28, 2024, 5:41pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/5 "2024-05-28T17:41:55Z")

</div>

@sipa I wonder if you have any ideas about how N2KBs are supposed to be used. I imagine that other parties of the transaction will fear hidden spend paths.

Would be cool to get @JeremyRubin take as well

---

<div class="post-metadata">

**Author:** ![ajtowns](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/ajtowns/32/417_2.png) [@ajtowns](https://delvingbitcoin.org/u/ajtowns)\
**Post date:** [May 28, 2024, 9:20pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/6 "2024-05-28T21:20:57Z")

</div>

> [@Eunovo](#):
>
> @sipa I wonder if you have any ideas about how N2KBs are supposed to be used. I imagine that other parties of the transaction will fear hidden spend paths.

Could be useful for inheritance/escrow type services: “this isn’t my money, so I don’t care about other spend paths, but in an emergency, the spend path I do know about can be used to help that person recover their money even if they’ve lost all their keys”.

Could be useful for places where you’re using multiple wallets for some funds – maybe your main wallet understands some super clever contracts that you want to put in a tapscript, but your backup (hardware? cold?) wallet doesn’t and can only spend via the key path; in that case all the backup wallet needs to know is the ipk and a rawnode leaf.

---

<div class="post-metadata">

**Author:** ![Eunovo](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/eunovo/32/375_2.png) [@Eunovo](https://delvingbitcoin.org/u/Eunovo)\
**Post date:** [May 29, 2024, 8:00am UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/7 "2024-05-29T08:00:27Z")

</div>

Thanks for the clarification @ajtowns !

---

<div class="post-metadata">

**Author:** ![josibake](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/josibake/32/83_2.png) [@josibake](https://delvingbitcoin.org/u/josibake)\
**Post date:** [May 31, 2024, 2:36pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/8 "2024-05-31T14:36:20Z")

</div>

@Eunovo took a brief look at your implementation, perhaps its worth opening as a PR?

---

<div class="post-metadata">

**Author:** ![Eunovo](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/eunovo/32/375_2.png) [@Eunovo](https://delvingbitcoin.org/u/Eunovo)\
**Post date:** [June 7, 2024, 6:03pm UTC](https://delvingbitcoin.org/t/tr-rawnode-and-rawleaf-support/901/9 "2024-06-07T18:03:33Z")

</div>

Cleaned up the commits and opened [Tr partial descriptors by Eunovo · Pull Request #30243 · bitcoin/bitcoin (github.com)](https://github.com/bitcoin/bitcoin/pull/30243) @josibake @ajtowns
