Re: [bitcoin-dev] BIP proposal: Timelocked address fidelity bond for BIP39 seeds

2022-05-17 Thread Eric Voskuil via bitcoin-dev
Good evening ZmnSCPxj,

Sorry for the long delay...

> Good morning e,
> 
> > Good evening ZmnSCPxj,
> >
> > For the sake of simplicity, I'll use the terms lender (Landlord), borrower
> > (Lessor), interest (X), principal (Y), period (N) and maturity (height 
> > after N).
> >
> > The lender in your scenario "provides use" of the principal, and is paid
> > interest in exchange. This is of course the nature of lending, as a period
> > without one's capital incurs an opportunity cost that must be offset (by
> > interest).
> >
> > The borrower's "use" of the principal is what is being overlooked. To
> > generate income from capital one must produce something and sell it.
> > Production requires both capital and time. Borrowing the principle for the
> > period allows the borrower to produce goods, sell them, and return the
> > "profit" as interest to the lender. Use implies that the borrower is 
> > spending
> > the principle - trading it with others. Eventually any number of others end 
> > up
> > holding the principle. At maturity, the coin is returned to the lender (by
> > covenant). At that point, all people the borrower traded with are bag 
> > holders.
> > Knowledge of this scam results in an imputed net present zero value for the
> > borrowed principal.
> 
> But in this scheme, the principal is not being used as money, but as a 
> billboard
> for an advertisement.
>
> Thus, the bitcoins are not being used as money due to the use of the fidelity
> bond to back a "you can totally trust me I am not a bot!!" assertion.
> This is not the same as your scenario --- the funds are never transferred,
> instead, a different use of the locked funds is invented.
> 
> As a better analogy: I am borrowing a piece of gold, smelting it down to make
> a nice shiny advertisement "I am totally not a bot!!", then at the end of the
> lease period, re-smelting it back and returning to you the same gold piece
> (with the exact same atoms constituting it), plus an interest from my 
> business,
> which gained customers because of the shiny gold advertisement claiming "I
> am totally not a bot!!".
> 
> That you use the same piece of gold for money does not preclude me using
> the gold for something else of economic value, like making a nice shiny
> advertisement, so I think your analysis fails there.
> Otherwise, your analysis is on point, but analyses something else entirely.

Ok, so you are suggesting the renting of someone else's proof of "burn" 
(opportunity cost) to prove your necessary expense - the financial equivalent 
of your own burn. Reading through the thread, it looks like you are suggesting 
this as a way the cost of the burn might be diluted across multiple uses, based 
on the obscuration of the identity. And therefore identity (or at least global 
uniqueness) enters the equation. Sounds like a reasonable concern to me.

It appears that the term "fidelity bond" is generally accepted, though I find 
this an unnecessarily misleading analogy. A bond is a loan (capital at risk), 
and a fidelity bond is also capital at risk (to provide assurance of some 
behavior). Proof of burn/work, such as Hash Cash (and Bitcoin), is merely 
demonstration of a prior expense. But in those cases, the expense is provably 
associated. As you have pointed out, if the burn is not associated with the 
specific use, it can be reused, diluting the demonstrated expense to an 
unprovable degree.

I can see how you come to refer to selling the PoB as "lending" it, because the 
covenant on the underlying coin is time constrained. But nothing is actually 
lent here. The "advertisement" created by the covenant (and its presumed 
exclusivity) is sold. This is also entirely consistent with the idea that a 
loan implies capital at risk. While this is nothing more than a terminology 
nit, the use of "fidelity bond" and the subsequent description of "renting" 
(the fidelity bond) both led me down another path (Tamas' proposal for risk 
free lending under covenant, which we discussed here years ago).

In any case, I tend to agree with your other posts on the subject. For the burn 
to be provably non-dilutable it must be a cost provably associated to the 
scenario which relies upon the cost. This provides the global uniqueness 
constraint (under cryptographic assumptions of difficulty).

Best,
e

> Regards,
> ZmnSCPxj


___
bitcoin-dev mailing list
bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev


Re: [bitcoin-dev] Package Relay Proposal

2022-05-17 Thread Anthony Towns via bitcoin-dev
On Tue, May 17, 2022 at 12:01:04PM -0400, Gloria Zhao via bitcoin-dev wrote:
> New Messages
> Three new protocol messages are added for use in any version of
> package relay. Additionally, each version of package relay must define
> its own inv type and "pckginfo" message version, referred to in this
> document as "MSG_PCKG" and "pckginfo" respectively. See
> BIP-v1-packages for a concrete example.

The "PCKG" abbreviation threw me for a loop; isn't the usual
abbreviation "PKG" ?

> =sendpackages=
> |version || uint32_t || 4 || Denotes a package version supported by the
> node.
> |max_count || uint32_t || 4 ||Specifies the maximum number of transactions
> per package this node is
> willing to accept.
> |max_weight || uint32_t || 4 ||Specifies the maximum total weight per
> package this node is willing
> to accept.

Does it make sense for these to be configurable, rather than implied
by the version? 

I presume the idea is to cope with people specifying different values for
-limitancestorcount or -limitancestorsize, but if people are regularly
relaying packages around, it seems like it becomes hard to have those
values really be configurable while being compatible with that?

I guess I'm asking: would it be better to either just not do sendpackages
at all if you're limiting ancestors in the mempool incompatibly; or
alternatively, would it be better to do the package relay, then reject
the particular package if it turns out too big, and log that you've
dropped it so that the node operator has some way of realising "whoops,
I'm not relaying packages properly because of how I configured my node"?

> 5. If 'fRelay==false' in a peer's version message, the node must not
>send "sendpackages" to them. If a "sendpackages" message is
> received by a peer after sending `fRelay==false` in their version
> message, the sender should be disconnected.

Seems better to just say "if you set fRelay=false in your version
message, you must not send sendpackages"? You already won't do packages
with the peer if they don't also announce sendpackages.

> 7. If both peers send "wtxidrelay" and "sendpackages" with the same
>version, the peers should announce, request, and send package
> information to each other.

Maybe: "You must not send sendpackages unless you also send wtxidrelay" ?


As I understand it, the two cases for the protocol flow are "I received
an orphan, and I'd like its ancestors please" which seems simple enough,
and "here's a child you may be interested in, even though you possibly
weren't interested in the parents of that child". I think the logic for
the latter is:

 * if tx C's fee rate is less than the peer's feefilter, skip it
   (will maybe treat it as a parent in some package later though)
 * if tx C's ancestor fee rate is less than the peer's feefilter, skip
   it?
 * look at the lowest ancestor fee rate for any of C's in-mempool
   parents
 * if that is higher than the peer's fee filter, send a normal INV
 * if it's lower than the peer's fee filter, send a PCKG INV

Are "getpckgtxns" / "pcktxns" really limited to packages, or are they
just a general way to request a batch of transactions? Particularly in
the case of requesting the parents of an orphan tx you already have,
it seems hard for the node receiving getpckgtxns to validate that the
txs are related in some way; but also it doesn't seem very necessary?

Maybe call those messages "getbatchtxns" and "batchtxns" and allow them to
be used more generally, potentially in ways unrelated to packages/cpfp?
The "only be sent if both peers agreed to do package relay" rule could
simply be dropped, I think.

> 4. The reciever uses the package information to decide how to request
>the transactions. For example, if the receiver already has some of
> the transactions in their mempool, they only request the missing ones.
> They could also decide not to request the package at all based on the
> fee information provided.

Shouldn't the sender only be sending package announcements when they know
the recipient will be interested in the package, based on their feefilter?

> =pckginfo1=
> {|
> |  Field Name  ||  Type  ||  Size  ||   Purpose
> |-
> |blockhash || uint256 || 32 || The chain tip at which this package is
> defined.
> |-
> |pckg_fee||CAmount||4|| The sum total fees paid by all transactions in the
> package.

CAmount in consensus/amount.h is a int64_t so shouldn't this be 8
bytes? If you limit a package to 101kvB, an int32_t is enough to cover
any package with a fee rate of about 212 BTC/block or lower, though.

> |pckg_weight||int64_t||8|| The sum total weight of all transactions in the
> package.

The maximum block weight is 4M, and the default -limitancestorsize
presumably implies a max package weight of 404k; seems odd to provide
a uint64_t rather than an int32_t here, which easily allows either of
those values?

> 2. ''Only 1 child with unconfirmed parents.'' The package must consist
>of one transaction and its 

Re: [bitcoin-dev] Package Relay Proposal

2022-05-17 Thread Gloria Zhao via bitcoin-dev
Hi Greg,

Thanks for reading!

>> A child-with-unconfirmed-parents package sent between nodes must abide by
the rules below, otherwise the package is malformed and the sender should
be disconnected.

>> However, if the child has confirmed parents, they must not be in the
package.

> If my naive understanding is correct, this means things like otherwise
common situations such as a new block will result in disconnects, say when
> the sender doesn't hear about a new block which makes the relay package
superfluous/irrelevant. Similar would be disconnection
> when confirmed gets turned into unconfirmed, but those situations are
extremely uncommon. The other rules are entirely under the control
> of the sender, which leads me to wonder if it's appropriate.

This is why the "pckginfo1" message includes the blockhash at which the
package was defined.
Also please see Clarifications - "Q: What if a new block arrives in between
messages?'' section in the v1-packages portion. It covers both cases, i.e.
a transaction going from unconfirmed->confirmed and confirmed->unconfirmed
in a reorg.

In case anybody is wondering "why don't we just allow confirmed parents?":
Since we validate based on the UTXO set, when we see a recently-confirmed
transaction, it just looks like it spends nonexistent inputs. In these
cases, we don't really know if the input was recently spent in a block or
just never existed, unless we plan on looking up transactions in past
blocks. We do some guesswork when we deal with new blocks in normal
transaction relay (e.g. we requested the tx before a block arrived):
https://github.com/bitcoin/bitcoin/blob/d5d40d59f8d12cf53c5ad1ce9710f3f108cec386/src/validation.cpp#L780-L784
I believe it's cleaner to just explicitly say which blockhash you're on to
avoid confusion.

Thanks,
Gloria

On Tue, May 17, 2022 at 1:56 PM Greg Sanders  wrote:

> Hi Gloria,
>
> Thanks for working on this important proposal!
>
> Still a lot to digest, but I just had on area of comment/question:
>
> > A child-with-unconfirmed-parents package sent between nodes must abide by
> the rules below, otherwise the package is malformed and the sender should
> be disconnected.
>
> > However, if the child has confirmed parents, they must not be in the
> package.
>
> If my naive understanding is correct, this means things like otherwise
> common situations such as a new block will result in disconnects, say when
> the sender doesn't hear about a new block which makes the relay package
> superfluous/irrelevant. Similar would be disconnection
> when confirmed gets turned into unconfirmed, but those situations are
> extremely uncommon. The other rules are entirely under the control
> of the sender, which leads me to wonder if it's appropriate.
>
> Cheers,
> Greg
>
> On Tue, May 17, 2022 at 12:09 PM Gloria Zhao via bitcoin-dev <
> bitcoin-dev@lists.linuxfoundation.org> wrote:
>
>> Hi everybody,
>>
>> I’m writing to propose a set of p2p protocol changes to enable package
>> relay, soliciting feedback on the design and approach. Here is a link
>> to the most up-to-date proposal:
>>
>> https://github.com/bitcoin/bips/pull/1324
>>
>> If you have concept or approach feedback, *please respond on the
>> mailing list* to allow everybody to view and participate in the
>> discussion. If you find a typo or inaccurate wording, please feel free
>> to leave suggestions on the PR.
>>
>> I’m also working on an implementation for Bitcoin Core.
>>
>>
>> The rest of this post will include the same contents as the proposal,
>> with a bit of reordering and additional context. If you are not 100%
>> up-to-date on package relay and find the proposal hard to follow, I
>> hope you find this format more informative and persuasive.
>>
>>
>> ==Background and Motivation==
>>
>> Users may create and broadcast transactions that depend upon, i.e.
>> spend outputs of, unconfirmed transactions. A “package” is the
>> widely-used term for a group of transactions representable by a
>> connected Directed Acyclic Graph (where a directed edge exists between
>> a transaction that spends the output of another transaction).
>>
>> Incentive-compatible mempool and miner policies help create a fair,
>> fee-based market for block space. While miners maximize transaction
>> fees in order to earn higher block rewards, non-mining users
>> participating in transaction relay reap many benefits from employing
>> policies that result in a mempool with the same contents, including
>> faster compact block relay and more accurate fee estimation.
>> Additionally, users may take advantage of mempool and miner policy to
>> bump the priority of their transactions by attaching high-fee
>> descendants (Child Pays for Parent or CPFP).  Only considering
>> transactions one at a time for submission to the mempool creates a
>> limitation in the node's ability to determine which transactions have
>> the highest feerates, since it cannot take into account descendants
>> until all the transactions are in the mempool. 

Re: [bitcoin-dev] Package Relay Proposal

2022-05-17 Thread Greg Sanders via bitcoin-dev
Hi Gloria,

Thanks for working on this important proposal!

Still a lot to digest, but I just had on area of comment/question:

> A child-with-unconfirmed-parents package sent between nodes must abide by
the rules below, otherwise the package is malformed and the sender should
be disconnected.

> However, if the child has confirmed parents, they must not be in the
package.

If my naive understanding is correct, this means things like otherwise
common situations such as a new block will result in disconnects, say when
the sender doesn't hear about a new block which makes the relay package
superfluous/irrelevant. Similar would be disconnection
when confirmed gets turned into unconfirmed, but those situations are
extremely uncommon. The other rules are entirely under the control
of the sender, which leads me to wonder if it's appropriate.

Cheers,
Greg

On Tue, May 17, 2022 at 12:09 PM Gloria Zhao via bitcoin-dev <
bitcoin-dev@lists.linuxfoundation.org> wrote:

> Hi everybody,
>
> I’m writing to propose a set of p2p protocol changes to enable package
> relay, soliciting feedback on the design and approach. Here is a link
> to the most up-to-date proposal:
>
> https://github.com/bitcoin/bips/pull/1324
>
> If you have concept or approach feedback, *please respond on the
> mailing list* to allow everybody to view and participate in the
> discussion. If you find a typo or inaccurate wording, please feel free
> to leave suggestions on the PR.
>
> I’m also working on an implementation for Bitcoin Core.
>
>
> The rest of this post will include the same contents as the proposal,
> with a bit of reordering and additional context. If you are not 100%
> up-to-date on package relay and find the proposal hard to follow, I
> hope you find this format more informative and persuasive.
>
>
> ==Background and Motivation==
>
> Users may create and broadcast transactions that depend upon, i.e.
> spend outputs of, unconfirmed transactions. A “package” is the
> widely-used term for a group of transactions representable by a
> connected Directed Acyclic Graph (where a directed edge exists between
> a transaction that spends the output of another transaction).
>
> Incentive-compatible mempool and miner policies help create a fair,
> fee-based market for block space. While miners maximize transaction
> fees in order to earn higher block rewards, non-mining users
> participating in transaction relay reap many benefits from employing
> policies that result in a mempool with the same contents, including
> faster compact block relay and more accurate fee estimation.
> Additionally, users may take advantage of mempool and miner policy to
> bump the priority of their transactions by attaching high-fee
> descendants (Child Pays for Parent or CPFP).  Only considering
> transactions one at a time for submission to the mempool creates a
> limitation in the node's ability to determine which transactions have
> the highest feerates, since it cannot take into account descendants
> until all the transactions are in the mempool. Similarly, it cannot
> use a transaction's descendants when considering which of two
> conflicting transactions to keep (Replace by Fee or RBF).
>
> When a user's transaction does not meet a mempool's minimum feerate
> and they cannot create a replacement transaction directly, their
> transaction will simply be rejected by this mempool. They also cannot
> attach a descendant to pay for replacing a conflicting transaction.
> This limitation harms users' ability to fee-bump their transactions.
> Further, it presents a security issue in contracting protocols which
> rely on **presigned**, time-sensitive transactions to prevent cheating
> (HTLC-Timeout in LN Penalty [1] [2] [3], Unvault Cancel in Revault
> [4], Refund Transaction in Discreet Log Contracts [5], Updates in
> eltoo [6]). In other words, a key security assumption of many
> contracting protocols is that all parties can propagate and confirm
> transactions in a timely manner.
>
> In the past few years, increasing attention [0][1][2][3][6] has been
> brought to **pinning attacks**, a type of censorship in which the
> attacker uses mempool policy restrictions to prevent a transaction
> from being relayed or getting mined.  TLDR: revocation transactions
> must meet a certain confirmation target to be effective, but their
> feerates are negotiated well ahead of broadcast time. If the
> forecasted feerate was too low and no fee-bumping options are
> available, attackers can steal money from their counterparties. I walk
> through a concrete example for stealing Lightning HTLC outputs at
> ~23:58 in this talk [7][8].  Note that most attacks are only possible
> when the market for blockspace at broadcast time  demands much higher
> feerates than originally anticipated at signing time. Always
> overestimating fees may sidestep this issue temporarily (while mempool
> traffic is low and predictable), but this solution is not foolproof
> and wastes users' money. The feerate 

[bitcoin-dev] Package Relay Proposal

2022-05-17 Thread Gloria Zhao via bitcoin-dev
Hi everybody,

I’m writing to propose a set of p2p protocol changes to enable package
relay, soliciting feedback on the design and approach. Here is a link
to the most up-to-date proposal:

https://github.com/bitcoin/bips/pull/1324

If you have concept or approach feedback, *please respond on the
mailing list* to allow everybody to view and participate in the
discussion. If you find a typo or inaccurate wording, please feel free
to leave suggestions on the PR.

I’m also working on an implementation for Bitcoin Core.


The rest of this post will include the same contents as the proposal,
with a bit of reordering and additional context. If you are not 100%
up-to-date on package relay and find the proposal hard to follow, I
hope you find this format more informative and persuasive.


==Background and Motivation==

Users may create and broadcast transactions that depend upon, i.e.
spend outputs of, unconfirmed transactions. A “package” is the
widely-used term for a group of transactions representable by a
connected Directed Acyclic Graph (where a directed edge exists between
a transaction that spends the output of another transaction).

Incentive-compatible mempool and miner policies help create a fair,
fee-based market for block space. While miners maximize transaction
fees in order to earn higher block rewards, non-mining users
participating in transaction relay reap many benefits from employing
policies that result in a mempool with the same contents, including
faster compact block relay and more accurate fee estimation.
Additionally, users may take advantage of mempool and miner policy to
bump the priority of their transactions by attaching high-fee
descendants (Child Pays for Parent or CPFP).  Only considering
transactions one at a time for submission to the mempool creates a
limitation in the node's ability to determine which transactions have
the highest feerates, since it cannot take into account descendants
until all the transactions are in the mempool. Similarly, it cannot
use a transaction's descendants when considering which of two
conflicting transactions to keep (Replace by Fee or RBF).

When a user's transaction does not meet a mempool's minimum feerate
and they cannot create a replacement transaction directly, their
transaction will simply be rejected by this mempool. They also cannot
attach a descendant to pay for replacing a conflicting transaction.
This limitation harms users' ability to fee-bump their transactions.
Further, it presents a security issue in contracting protocols which
rely on **presigned**, time-sensitive transactions to prevent cheating
(HTLC-Timeout in LN Penalty [1] [2] [3], Unvault Cancel in Revault
[4], Refund Transaction in Discreet Log Contracts [5], Updates in
eltoo [6]). In other words, a key security assumption of many
contracting protocols is that all parties can propagate and confirm
transactions in a timely manner.

In the past few years, increasing attention [0][1][2][3][6] has been
brought to **pinning attacks**, a type of censorship in which the
attacker uses mempool policy restrictions to prevent a transaction
from being relayed or getting mined.  TLDR: revocation transactions
must meet a certain confirmation target to be effective, but their
feerates are negotiated well ahead of broadcast time. If the
forecasted feerate was too low and no fee-bumping options are
available, attackers can steal money from their counterparties. I walk
through a concrete example for stealing Lightning HTLC outputs at
~23:58 in this talk [7][8].  Note that most attacks are only possible
when the market for blockspace at broadcast time  demands much higher
feerates than originally anticipated at signing time. Always
overestimating fees may sidestep this issue temporarily (while mempool
traffic is low and predictable), but this solution is not foolproof
and wastes users' money. The feerate market can change due to sudden
spikes in traffic (e.g. huge 12sat/vB dump a few days ago [9]) or
sustained, high volume of Bitcoin payments (e.g.  April 2021 and
December 2017).

The best solution is to enable nodes to consider packages of
transactions as a unit, e.g. one or more low-fee parent transactions
with a high-fee child, instead of separately. A package-aware mempool
policy can help determine if it would actually be economically
rational to accept a transaction to the mempool if it doesn't meet fee
requirements individually. Network-wide adoption of these policies
would create a more purely-feerate-based market for block space and
allow contracting protocols to adjust fees (and therefore mining
priority) at broadcast time.  Some support for packages has existed in
Bitcoin Core for years. Since v0.13, Bitcoin Core has used ancestor
packages instead of individual transactions to evaluate the incentive
compatibility of transactions in the mempool [10] and select them for
inclusion in blocks [11].

Package Relay, the concept of {announcing, requesting, downloading}
packages between nodes 

Re: [bitcoin-dev] Wallet policies for descriptor wallets

2022-05-17 Thread Salvatore Ingala via bitcoin-dev
Hi all,

TL;DR: It is easy to convert from wallet policy to descriptors and back;
imho aliases are better left out of descriptors in real world usage; some
more examples given.

I received some very useful feedback on the wallet policy proposal (in this
list and outside); that also led me to realize that my initial post lacked
some clarity and more practical examples.

This post wants to:
- clarify that extracting descriptors from the wallet policy is trivial;
- argue that figuring out the wallet policy (template and list of keys
information) from the descriptor is reasonably easy − automatable for sane
descriptors currently in use, and much more general ones as well;
- give an idea of what the information shown on a hardware wallet screen
would look like (emphasizing compactness);
- explain my point of view on "descriptors with aliases".

This gist demoes conversions from wallet policies to descriptors, and back:
https://gist.github.com/bigspider/10df51401be3aa6120217c03c2836ffa

Note that I would expect/hope software wallets to prefer working directly
with wallet policies − but it might help to have automated tools for the
conversion, for interoperability with tools that do not adopt wallet
policies.

(All the following examples use the `/**` notation as a shortcut for
`/<0,1>/*`; this notation might be dropped without consequences on the rest
of the proposal.)

All the keys in the example I'm proposing are followed by /**. It is
unclear to me if hardware wallets should allow *registration* of wallet
policies with static keys (that is, without any range operator), as that
would incentivize key reuse. The specs still support it as there might be
other use cases.

The policy for miniscript examples not using taproot was generated with the
online compiler: https://bitcoin.sipa.be/miniscript. Many examples are also
borrowed from there.
(To the best of my knowledge, there is no publicly released compiler for
miniscript on taproot, yet)

Note on aliases: it has been pointed out that many miniscript
implementations internally use aliases to refer to the keys. In my opinion,
aliases:
- should be external to the descriptor language, as they bear no
significance for the actual script(s) that the descriptor can produce
- fail to distinguish which part of the KEY expression is part of the
"wallet description", and which part is not

By clearly separating the key information in the vector (typically, an xpub
with key origin information) from the key placeholder expression (which
typically will have the `/**` or `/<0,1>/*` derivation step), wallet
policies semantically represent keys in a way that should be convenient to
both software wallets and hardware signers.

Associating recognizable names to the xpubs (and registering them on the
device) is a good idea for future developments and can greatly improve the
UX, both during wallet setup, or in recognizing outputs for repeated
payments; it should be easy to build this feature on top of wallet policies.

== Examples ==

All the examples show:
- Miniscript policy: semantic spending rules, and optimization hints (can
be compiled to miniscript automatically)
- Miniscript: the actual miniscript descriptor, compiles 1-to-1 to Bitcoin
Script
- Wallet template: the "wallet descriptor template"
- Vector of keys: the list of key information (with key origin information)

Together, the wallet template and the vector of keys are the complet
"wallet policy".

=== Example 1: Either of two keys (equally likely) ===

Miniscript policy: or(pk(key_0),pk(key_1))
Miniscript:
 
wsh(or_b([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<0;1>/*),s:pk([12345678/44'/0'/0']xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;1>/*)))

Descriptor template:   wsh(or_b(pk(@0/**),s:pk(@1/**)))
Vector of keys: [

"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",

"[12345678/44'/0'/0']xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"
]

In all the following examples, I will replace the xpubs with aliases in the
miniscript for brevity, and omit the corresponding vector of keys in the
wallet policy.

Of course, in comparing the "information density" (especially for UX
purposes), it is important to take the full descriptor into account.
It is always to be assumed that the keys are xpubs, complete with key
origin information if internal (that is, controlled by the software or
hardware signer that the wallet policy is being with).

=== Example 2: Either of two keys, but one is more likely ===

Miniscript policy: or(99@pk(key_likely),pk(key_unlikely))
Miniscript:   wsh(or_d(pk(key_likely),pkh(key_unlikely)))

Descriptor template: wsh(or_d(pk(@0/**),pkh(@1/**)))
Vector of keys: 

=== Example 3: A