Skip to content

Latest commit

 

History

History
45 lines (32 loc) · 6.07 KB

2022-05-18-#24148.md

File metadata and controls

45 lines (32 loc) · 6.07 KB

This is a 2-part Review Club for PR by Antoine Poinsot which introduces Miniscript support for Output Descriptors. In this first part participants focused on general Miniscript concepts, and some of the changes introduced in #24148.

Questions

Which type of analysis enabled by Miniscript would be helpful for which use case or application? 🔗

  • The policy compiler can sometimes find more optimal Script. In general, since Miniscript is only a subset of Script, some policies tend to be more optimizable "by hand". But then you lose all the guarantees given by Miniscript for just a few witness units.
    • (IIRC) in the anchor output proposal for Lightning, one of the Scripts was found using the Miniscript policy compiler.
    • One of the (hand-crafted) transaction templates used on LN (I believe it's the commitment tx?) was found to be slightly suboptimal thanks to Miniscript analysis
  • The analysis of the maximum witness size is helpful for "second layer" protocols to assign fee bumping reserves, since they can then estimate the worst case size of the transaction (if not signed with exotic sighash types).
  • Composition is really interesting, where multiple parties (e.g. in an advanced kind of multi-sig) can provide complex subexpressions without everyone having to understand the other party's spending conditions.
    • "make sure it can only be spent with me signing" (on all possible paths), e.g CEO always has to sign.

What would be a valid Miniscript for a spending policy that unconditionally locks the UTXO for 21 blocks, and then requires a 2-of-3 multisig from Alice, Bob, or Carol? (Note: the Miniscript homepage and https://min.sc/ have easy-to-use tooling available to construct Miniscripts) 🔗

  • There is a difference between policy and Miniscript.
  • This is policy: and(thresh(2,pk(key_1),pk(key_2),pk(key_3)), after(21))
  • This is Miniscript: wsh(and_v(v:multi(2, key_a, key_b, key_c), older(21)))
  • Miniscript doesn't "compile" to Script (maybe the word works but it can lead to confusion), each Miniscript fragment maps to a specific Script. Rather than just a few simple templates we have now in descriptors (pkh, multi, ...), Miniscript is a project to deal with vaguely generic, composable, script.

What does it mean when a node is “sane” or “valid”? Do they mean the same thing? 🔗

  • A Miniscript expression is essentially a tree (see https://miniscript.fun for a visual). Each fragment in the tree is a node, e.g. and_v, thresh, multi, etc.
  • We call "valid" any correctly-typed Miniscript, meaning the arguments passed to the fragment match what the fragment type expects (in terms of number of args and types). "sane" is more restrictive. For Miniscript to be "sane"/"safe" it needs to be valid, consensus and standardness-compliant (e.g. number of operations and script size), have non-malleable solutions, not mix different timelock units (block/time), and not have duplicate keys (Node::IsSane()).
  • Example: thresh(101,pk(pk_1),pk(pk_2),...pk(pk_101)) is valid as it passes the "type-check" but is affected by resource limitations as it's larger than 3600 bytes which makes it invalid by standardness thus "(in)sane".

What does it mean for an expression to be non-malleably satisfied? After SegWit, why do we still need to worry about malleability? 🔗

  • Malleability is the ability for a third party (not a participant in the script) to modify an existing satisfaction into another valid satisfaction.
  • Segwit didn't remove malleability. It only made it harmless for the purpose of not breaking unbroadcast transactions (see signature malleability). But malleability has other effects, which are far less severe, but still existant. Segwit transactions are no less malleable than other ones.
  • Malleability scenario:
    • What if a transaction spends a Miniscript which contains a sha256() fragment, but not in the branch used to spend. Replacing the hash dissatisfaction by any 32 bytes string will not invalidate the witness (see "Basic satisfactions").
    • Then the first node I'm broadcasting it to can just take my transaction and send a different version (by replacing the 32-byte string) to all nodes on the network.
    • This will increase the bandwidth usage of compact relay for everyone, since the miner will mine a transaction that is not exactly the same as every node has in its mempool, adding roundtrips to BIP152 block propagation.
    • Another scenario: If a witness can be stuffed with additional data, the transaction's feerate will go down, potentially to the point where its ability to propagate and get confirmed is impacted.
  • For a definition of a non-malleable satisfaction see "Malleability".

In Node::CheckTimeLocksMix(), what is the type of "k"_mst? In your own words, what does the << operator do here? 🔗

  • "k"_mst is converted into a Type instance through the user-defined literal operator"" _mst.
  • The << operator is overloaded to check that every type property that the right hand has, the left hand also has. Or to quote the docstring: "Check whether the left hand's properties are superset of the right's (= left is a subtype of right)."