OP_VAULT draft #26857

pull jamesob wants to merge 9 commits into bitcoin:master from jamesob:2023-01-opvault changing 30 files +2522 −95
  1. jamesob commented at 4:02 pm on January 9, 2023: member

    This is a draft for a consensus change enabling on-chain vaults, as detailed in the BIP: https://github.com/bitcoin/bips/pull/1421

    In short, it introduces two opcodes, OP_VAULT and OP_UNVAULT, that facilitate constructing vaults which

    • allow multiple deposits,
    • allow partial unvaultings and recursive re-vaults,
    • allow batch operations (recoveries and unvaultings) using vaults with compatible parameters,
    • support dynamic withdrawal target specification, and
    • support robust fee management.

    For the last item, the proposal has a hard dependency on package relay and ephemeral anchors.

    The code as-written here lacks specific activation mechanism, and there’s probably some policy/wallet stuff missing, but in substance it is implemented and comes with some interesting functional tests.

  2. jamesob marked this as a draft on Jan 9, 2023
  3. jamesob force-pushed on Jan 9, 2023
  4. DrahtBot commented at 4:46 pm on January 9, 2023: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept NACK 1440000bytes

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #27223 (Update chainparams for 25.x by johnny9)
    • #26749 (refactor: Use move semantics instead of custom swap functions by hebasto)
    • #26201 (Remove Taproot activation height by Sjors)
    • #26177 (refactor / kernel: Move non-gArgs chainparams functionality to kernel by TheCharlatan)
    • #25740 (assumeutxo: background validation completion by jamesob)
    • #24230 (indexes: Stop using node internal types and locking cs_main, improve sync logic by ryanofsky)
    • #15606 (assumeutxo by jamesob)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  5. jamesob force-pushed on Jan 9, 2023
  6. jamesob force-pushed on Jan 9, 2023
  7. jamesob force-pushed on Jan 9, 2023
  8. jamesob force-pushed on Jan 9, 2023
  9. ariard commented at 2:58 am on January 10, 2023: member

    Congrats here – Always cool to see new implemented ideas to extend the Script interpreter flexibility!

    From a primitive viewpoint, I think I’ve few open questions, like if the recovery path should be committed with a signature rather than protected by a simple scriptpubkey preimage. Beyond locking up the inputs/outputs fields for mempool issues, I think there is the accountability upsides of using new private and accountable Schnorr-compatible schemes (e.g TAPS). The current OP_VAULT implementation is using OP_NOP repurposing but this doesn’t seem compatible with Taproot-only extensions (e.g ANYPREVOUT) and maybe a OP_SUCCESS could be used. There is a conceptual wonder, if a CTV and template malleability approach wouldn’t better suit the vault use-case and allow other ones, as such better re-usability of primitives.

    From a procedural viewpoint, recently there has been proposed the bitcoin-inquisition fork of Core as an experimental platform to test, iterate and play with Script interpreter extensions, notably also aiming to support package relay and ephemeral outputs to observe the fee-bumping primitives trade-offs. I believe the idea is to have a stable Core release where one can have a protocol proof-of-concept running with hopefully minimal rebase maintenance cost (yeah we all hate the rebase hell…). Looking forward to review things there!

  10. naumenkogs commented at 10:07 am on January 10, 2023: member

    Great to see this, I hope this functionality comes into Bitcoin one way or another, and this seems like a decent attempt. Your listing of the features makes sense, and I currently don’t think a more optimal way to achieve them.

    By no means blockers, but rather some thoughts I wanted to share on the design:

    1. I’m personally not sure batching withdrawals is that compelling… It’s a nice-to-have, but I’d think about the benefits dropping this feature would provide.
    2. Or, from a different angle, the issue of malicious de-batching should not stop this idea from moving forward, as I’m not convinced this use case would be that widespread. I want to think more about use cases (solo user cold wallet, exchange cold wallet, fund cold wallet) and what their setups would look like.
  11. darosior commented at 11:28 am on January 10, 2023: member

    I plan to comment about the design on the ML, but just a note about @naumenkogs’ comment above.

    On the contrary i think the batching feature is very compelling. The impossibility to batch Unvaults in Revault is a major drawback: it significantly increases the cost of any realistic operation (you need one whole additional transaction per input, and each have likely more than one output). It also potentially increases the cost on the network (you’d likely want some sort of anchor output on each Unvault tx, that you might not spend, so that’s 2*n outputs created with n the number of coins spent): we definitely don’t want to prevent batching. The ability to batch the recovery transactions (what we called Emergency tx in Revault) is also very compelling but i think your comment was only about batched withdrawals.

  12. jamesob force-pushed on Jan 10, 2023
  13. ajtowns added the label Consensus on Jan 11, 2023
  14. jamesob force-pushed on Jan 13, 2023
  15. DrahtBot added the label Needs rebase on Jan 16, 2023
  16. michaelfolkson commented at 6:09 pm on January 16, 2023: contributor

    I second most (if not all) of the comments thus far. Especially this from @ariard.

    From a procedural viewpoint, recently there has been proposed the bitcoin-inquisition fork of Core as an experimental platform to test, iterate and play with Script interpreter extensions, notably also aiming to support package relay and ephemeral outputs to observe the fee-bumping primitives trade-offs

    Thanks also for keeping this in draft for now @jamesob. For it to be moved out of draft I’d like to see a convergence on this being the best proposal to enable this functionality and proofs of concept on bitcoin-inquisition seem like a good step towards that (assuming the bitcoin-inquisition maintainer(s) think this is ready to be merged there).

  17. in src/script/interpreter.cpp:2118 in a8323b9cea outdated
    2135+{
    2136+    if (out.nValue != 0) {
    2137+        return false;
    2138+    }
    2139+    const CScript& spk = out.scriptPubKey;
    2140+    if (!(spk.size() == 1 && spk[0] == OP_2)) {
    


    achow101 commented at 8:46 pm on January 16, 2023:

    In fbf344931a2224dc3ace0011c1a4cb5cd4187f3e “wip: draft implementation”

    OP_2?


    john-moffett commented at 6:52 pm on January 19, 2023:
  18. in src/script/interpreter.cpp:1428 in a8323b9cea outdated
    1467+                    // into a further recursion if OP_VAULT spends are included in the
    1468+                    // trigger witness program; the recursion depth is limited
    1469+                    // solely by script size constraints.
    1470+                    //
    1471+                    // TODO: think more about whether to limit recursive OP_VAULT
    1472+                    // evaluations in trigger witness programs.
    


    achow101 commented at 9:03 pm on January 16, 2023:

    In fbf344931a2224dc3ace0011c1a4cb5cd4187f3e “wip: draft implementation”

    I think it makes sense to disallow recursive OP_VAULTs in the OP_VAULT trigger script (? this was called unvault script in the paper). They necessarily have to have the same recovery spk hash and delay as the top level OP_VAULT, and at the end, would have some witness script which is what we actually care about at this point. So really all that would do is waste resources.


    jamesob commented at 2:11 pm on February 21, 2023:
    Good point. This has been done; see the limit_recursion parameter. Thanks to @john-moffett for outlining a particular test case to ensure that recursion is limited to a single call.
  19. in src/script/interpreter.cpp:2178 in fbf344931a outdated
    1994+bool GenericTransactionSignatureChecker<T>::CheckUnvaultTarget(
    1995+    const uint256& target_outputs_hash) const
    1996+{
    1997+    // We can't use precomputed transaction data here because, since the input lacks a
    1998+    // witness, the precomputation routines don't run. I.e. `txdata.hashOutputs` is blank.
    1999+    return SHA256Uint256(GetOutputsSHA256(*this->txTo)) == target_outputs_hash;
    


    achow101 commented at 9:09 pm on January 16, 2023:

    In fbf344931a2224dc3ace0011c1a4cb5cd4187f3e “wip: draft implementation”

    Note that this is a different serialization from the one described in the paper. The paper says to serialize the scriptPubKey first, then nValue. However GetOutputsSHA256 serializes each output as nValue then scriptPubKey. I’m going to assume this is an error in the paper as I think it is better the way it is implemented rather than described.

  20. in src/script/interpreter.cpp:1434 in a9db7392bf outdated
    1412+                        // Validate the OP_UNVAULT output as a bare script.
    1413+                        if (!CheckUnvaultTriggerOutputsBare(
    1414+                                unvault_output_spk,
    1415+                                recovery_spk_hash, spend_delay, fRequireMinimal)) {
    1416+                            return set_error(serror, SCRIPT_ERR_UNVAULT_MISMATCH);
    1417+                        }
    


    achow101 commented at 9:22 pm on January 16, 2023:

    In a9db7392bf9d4d69d5a7a91db32dda7bd50479d8 “consensus: allow OP_UNVAULT outputs to be behind scripthash”

    Is it useful to allow OP_UNVAULT as a bare script? ISTM it would be simpler to just require that the the unvault script must be one of P2WSH or P2TR. It’s not clear to me that it’s actually useful to allow it as a bare script, especially since that requires further policy changes to allow such transactions to even be relayed.


    jamesob commented at 4:36 pm on January 19, 2023:
    Yeah, this is a good point. I think I’ll remove this.

    jamesob commented at 2:12 pm on February 21, 2023:
    Removed. Vault opcodes now only exist as OP_SUCCESSx overrides in tapscript.
  21. in src/script/interpreter.cpp:2160 in c00dad503d outdated
    2180+
    2181+    bool has_ea{false};
    2182+    bool has_revault{false};
    2183+
    2184+    // Verify that all optional outputs are either an ephemeral anchor or a revault.
    2185+    // Permit the optional outputs to appear in any order.
    


    achow101 commented at 9:31 pm on January 16, 2023:

    In c00dad503d7dfa990afd24c9fde2555482cc247b “consensus: allow one revault output during unvault”

    I don’t see why the OP_UNVAULT output has to be the 0th output if the optional ones can be in any order.


    jamesob commented at 2:13 pm on February 21, 2023:
    Fixed. OP_UNVAULT outputs (and recovery outputs) are now specified explicitly by an index on the witness stack. Thanks for this feedback.
  22. achow101 commented at 9:38 pm on January 16, 2023: member
    Left some comments on the code, although a few may be more appropriate to followup on the mailing list about. Will also send a response to the mailing list.
  23. jamesob force-pushed on Jan 18, 2023
  24. Sjors commented at 1:26 pm on January 19, 2023: member
    Any plans for a vault() descriptor? For Our wallet currently isn’t designed for a two-stage transaction, which is necessary for the unvaulting part, so it’d be interesting to see someone attempting to implement a working vault in our wallet. Not saying you should be the one doing that, and it deserves a separate PR.
  25. john-moffett commented at 9:22 pm on January 22, 2023: contributor

    I think the overall approach is sound for vault-specific functionality.

    I understand the implementation is a draft at this point, so you may already be aware of these issues, but I thought I’d flag them just in case. My apologies if these are premature!

    I believe the recursion here ought to be explicitly limited. As it stands, an attacker could crash a node by crafting a transaction spending from a vault that has, as its recov_spk_script, a P2WSH scriptPubkey with a witnessScript of:

    OP_3 OP_PICK OP_3 OP_PICK OP_3 OP_PICK OP_3 OP_PICK OP_VAULT

    If you supply witnessScript, recovery_params, delay, 0x00*32, witnessScript to the witness stack (in addition to the initial witness stack here), it’ll recurse infinitely and crash. (See diff at the end of this comment for my addition to the test code.)

    A potential attacker could also perform almost any arbitrary computation using a similar method.

    The recursion also doesn’t count any potential additional signature operations toward the sigOps limits from what I can tell. (Maybe this is by design, though?)

    Finally, I don’t think implementing these opcodes as OP_NOPs is workable as a soft fork. The current implementation is actually (I think) a hard fork, given that the stack will not be clean for old nodes and they’ll reject most transactions using these opcodes. Even absent the cleanstack rule for witness scripts, the top element could be false in this case for old nodes yet the script would succeed in this PR, since it pushes a true.

    I think it’s generally unsafe for a reimplemented NOP to push to or pop the stack. My suggestion would be restricting OP_VAULT / OP_UNVAULT to be Tapscript only and using OP_SUCCESSx codes.

    Diff for feature_vaults.py:

     0
     1@@ -21,0 +22 @@ from test_framework.util import assert_equal, assert_raises_rpc_error
     2+from test_framework.script_util import script_to_p2wsh_script
     3@@ -64,0 +66,3 @@ class VaultsTest(BitcoinTestFramework):
     4+            title("testing recursive attack sweep")
     5+            self.single_vault_test(node, wallet, sweep_from_vault=True)
     6+
     7@@ -447 +451,3 @@ DEFAULT_UNVAULT_SECRET = 3
     8-
     9+def get_recursive_witness_script() -> CScript:
    10+    return CScript([script.OP_3, script.OP_PICK, script.OP_3, script.OP_PICK, script.OP_3,
    11+                    script.OP_PICK, script.OP_3, script.OP_PICK, script.OP_VAULT])
    12@@ -465 +471,3 @@ class VaultSpec:
    13-        self.recovery_spk = CScript([script.OP_TRUE])
    14+        recursive_script = get_recursive_witness_script()
    15+        recursive_program = script_to_p2wsh_script(recursive_script)
    16+        self.recovery_spk = recursive_program
    17@@ -672,0 +681,5 @@ def get_sweep_to_recovery_tx(
    18+                get_recursive_witness_script(),
    19+                vault.recovery_params,
    20+                CScript([vault.spend_delay]),
    21+                CScript(b'\x00' * 32),
    22+                get_recursive_witness_script(),
    
  26. jamesob commented at 4:35 pm on January 23, 2023: member

    Any plans for a vault() descriptor?

    That’d be great, though if no one else wants to do that work I’ll have spend some time learning more about descriptors.

    I understand the implementation is a draft at this point, so you may already be aware of these issues, but I thought I’d flag them just in case. My apologies if these are premature! @john-moffett this is all great! I’d planned to move OP_VAULT/OP_UNVAULT to OP_SUCCESSx as of late last week, and was vaguely aware that the recursion probably facilitates Bad Things, but your detailed explanations and test cases (!) are very valuable. Never too early to point out a crash bug! Thank you for your help.

    I’ll remedy these things in the coming days.

  27. jamesob force-pushed on Jan 23, 2023
  28. DrahtBot removed the label Needs rebase on Jan 23, 2023
  29. jamesob force-pushed on Jan 25, 2023
  30. unknown changes_requested
  31. unknown commented at 4:57 pm on January 25, 2023: none

    Concept: Specific covenant proposal instead of generalized covenant that achieves multiple things over years

    Concept NACK

    Overall I agree with covenants being implemented however only supporting one use case doesn’t make sense. I could link to several other discussions including some in which reviewers of this PR were not satisfied with OP_CTV because it seems to be redundant and general covenants approach works better, however below links sums up everything without any drama.

    Note: Its possible to emulate CTV inefficiently if this is implemented.

    Related links:

    https://twitter.com/tierotiero/status/1618133549294718976

    https://twitter.com/tierotiero/status/1618136358001967104


    I appreciate the efforts by PR author to write the paper, mailing list discussion etc. however this has no consensus apart from a few vault enthusiasts in this repository. Author had also requested people to participate in mailing list discussion to share other use cases, I think it has been done already and resulted in being called ‘attack on bitcoin’, ‘personal attacks’ etc. Also its not possible to discuss anything on mailing list related to coinjoin. Maybe we need a mailing list on nostr.

  32. jamesob force-pushed on Jan 26, 2023
  33. jamesob force-pushed on Jan 26, 2023
  34. jamesob force-pushed on Jan 26, 2023
  35. jamesob force-pushed on Jan 27, 2023
  36. jamesob force-pushed on Feb 3, 2023
  37. in src/checkqueue.h:154 in a3ad8ecf96 outdated
    146+                        auto& dc = *check.m_deferred_checks;
    147+                        results.insert(
    148+                            results.end(),
    149+                            std::make_move_iterator(dc.begin()),
    150+                            std::make_move_iterator(dc.end()));
    151+                    }
    


    ajtowns commented at 4:07 am on February 4, 2023:
    0template<typename T1, typename T2>
    1void move_to_end(T1& dest, T2& src)
    2{
    3    dest.insert(
    4        dest.end(), 
    5        std::make_move_iterator(src.begin()),
    6        std::make_move_iterator(src.end()));
    7}
    8
    9move_to_end(results, *check.m_deferred_checks);
    

    ?


    jamesob commented at 3:42 pm on February 16, 2023:
    Good cleanup, done - thanks.
  38. in src/script/interpreter.h:247 in a3ad8ecf96 outdated
    197+//! Data that is accumulated during the script verification of a single input and then
    198+//! used to perform aggregate checks after all inputs have been run through
    199+//! `VerifyScript()`.
    200+//!
    201+//! TODO I realize this is kind of a hacky polymorphic-union thing; if there's a nicer
    202+//! way to do this, please someone let me know.
    


    ajtowns commented at 4:09 am on February 4, 2023:
    std::variant?

    jamesob commented at 5:57 pm on February 17, 2023:
    I looked at using std::variant but the end use in ValidateDeferredChecks winds up being much hairier. I’ve changed the specific checks from std::unique_ptr to std::optional for simplicity’s sake. If we eventually decide that the memory implications of this approach are too heavyweight, we could do something with std::variant - but I think they’re comparable, and given that we’ll never have more than a few thousand deferred checks in flight at any given time, I think it’s probably okay to leave this representation as-is.
  39. in src/checkqueue.h:44 in a3ad8ecf96 outdated
    27@@ -26,9 +28,12 @@ class CCheckQueueControl;
    28   * the master is done adding work, it temporarily joins the worker pool
    29   * as an N'th worker, until all jobs are done.
    30   */
    31-template <typename T>
    32+template <typename T, typename R>
    33 class CCheckQueue
    34 {
    35+public:
    36+    using ChecksReturn = std::pair<bool, std::optional<std::vector<R>>>;
    


    ajtowns commented at 4:35 am on February 4, 2023:
    Could just be a std::optional<std::vector>nullopt is false, empty vector is true, non-empty vector is conditionally true.
  40. in src/script/interpreter.h:208 in a3ad8ecf96 outdated
    203+struct DeferredCheck
    204+{
    205+    //! Set when script execution happens asynchronously so that we can associate
    206+    //! deferred checks with their related transaction when a block's worth of
    207+    //! script executions are performed in batch.
    208+    const CTransaction* m_tx_to;
    


    ajtowns commented at 9:52 am on February 4, 2023:

    I think the way you’re setting this up is that you give CCheckQueue a bunch of work, and it then returns a batch of deferred work back to you, that you then finish off. But if you’re doing a whole block at once, maybe that’s bad, because you’re doing all the deferred checks for all txns in a single thread, rather than in parallel.

    Maybe it would be better to expand CCheckQueue into being more of a map/reduce model – you map the scripts to many processes getting deferred checks in response, then you sort the deferred checks so related ones (from the same tx) all go to the same thread, then reduce/accumulate the results from them so that you’ve got your conclusion.

    Could be really clever and do the reduce work in parallel with mapping, I think; though you’d need some way of maintaining the accumulator state.


    jamesob commented at 5:54 pm on February 17, 2023:

    This is good feedback, and in the general case you’re right. In the specific case of the deferred checks being introduced here, they don’t include any of the computationally expensive stuff that motivates parallelizing checks in the case of CScriptCheck - i.e. we’re not doing any cryptographic ops or signature checking here; OP_VAULT deferred checks consist of summing and comparing integers.

    So I’m not necessarily averse to doing the deferred-check parallelization in this changeset, but (i) I don’t think it’s strictly necessary from a resource standpoint and (ii) I can’t think of a straightforward way to do it without introducing another thread pool devoted to the deferred checks, which is a decent amount of work.

  41. DrahtBot added the label Needs rebase on Feb 6, 2023
  42. jamesob force-pushed on Feb 7, 2023
  43. jamesob force-pushed on Feb 14, 2023
  44. jamesob force-pushed on Feb 15, 2023
  45. jamesob force-pushed on Feb 17, 2023
  46. DrahtBot removed the label Needs rebase on Feb 17, 2023
  47. jamesob force-pushed on Feb 17, 2023
  48. jamesob force-pushed on Feb 17, 2023
  49. jamesob force-pushed on Feb 17, 2023
  50. jamesob force-pushed on Feb 17, 2023
  51. jamesob force-pushed on Feb 17, 2023
  52. jamesob force-pushed on Feb 22, 2023
  53. test: make ECKey more easily constructable b3242e21b4
  54. consensus: deferred check framework
    Implements a framework for accumulated "deferred checks" during vin
    script execution, and then executing the checks after all inputs have
    been validated individually.
    
    This facilitates new forms of validation which involve gathering
    information during vin script execution and then using that information
    to do "aggregate" checks on the transaction as a whole.
    
    For vaults in particular, this allows us to conjoin operations across
    vaults with incompatible parameters into the same transaction, as well
    as include unrelated inputs and outputs, which facilitates more flexible
    fee management.
    
    There are also applications re: batch validation and cross-input
    signature aggregation.
    d68521931b
  55. consensus: add OP_VAULT deployment parameters 85715fba44
  56. consensus: implement OP_VAULT and OP_UNVAULT
    OP_VAULT adds a native way of doing vaults - that is, encumbering coins
    in such a way that they must pass through a delay period before being
    successfully spent, aside from a predetermined path (the recovery
    path) which they can be swept to at any time during the life of the
    vault.
    
    Vaulting
    ========
    
    To create a vault, coins must be encumbered under a scriptPubKey that
    looks like
    
      <recovery-params> <spend-delay> <trigger-sPK-hash> OP_VAULT
    
    Of course, this can be within a P2TR taptree.
    
    <recovery-params>
    -----------------
    
    The `recovery-params` paramater is of the form
    
      <32-byte-hash>[<arbitrary scriptPubKey>]
    
    where the first component is the hash of the recovery path scriptPubKey:
    i.e. the scriptPubKey which the full value of recovered vaults must be
    spent to in order to successfully sweep the coins from a vault.
    
    The optional bytes following the recovery path hash dictate the optional
    recovery authorization. When this is specified, the script given must be
    satisfied when sweeping the vaulted inputs to recovery. Using this
    parameter has benefits and drawbacks. The benefits are
    
      - unrelated inputs and outputs can be attached to a recovery, making
        "exogenous" fee management like ephemeral anchor use unneccessary.
    
      - vaults with incompatible recovery parameters can be recovered in the
        same transaction, which allows fee managed UTXOs to be shared.
    
    however the drawbacks are
    
      - increased risk/complexity around the ability to perform recovery
        sweeps.
    
      - if an attacker obtains the recovery authorization key and all
        information necesary to attempt a recovery (the "location" of the
        vaulted coins) as well as the trigger authorization key, they may
        attempt to both trigger an unvault and pin a recovery. This is
        mitigated by the necessary presence of an ephemeral anchor output
        in every recovery transaction.
    
    In either case, any vault outputs which share <recovery-params> can be
    recovered together in the same transaction.
    
    <spend-delay>
    -------------
    
    This is a relative timelock a la BIP-68 that specifies how many blocks
    (or how much time) must elapse before an OP_UNVAULT output becomes
    spendable to the declared unvault target (more on this below).
    
    Vaults with compatible <recovery-params> and <spend-delay> can be
    unvaulted together.
    
    <trigger-sPK-hash>
    ------------------
    
    This is the hash of the scriptPubKey which needs to be satisfied in
    order to trigger the unvault process.
    
    OP_UNVAULT
    ==========
    
    To trigger the start of the unvault process, vaulted outputs must be
    spent into a transaction which has a corresponding OP_UNVAULT output of
    the form
    
      <recovery-params> <spend-delay> <target-hash> OP_UNVAULT
    
    where the first two parameters are identical to the input vault and the
    last parameter, <target-hash>, is a content hash of the proposed unvault
    destination. It is a hash of each target output's scriptPubKey and
    amount.
    
    Because triggers are always signed with the trigger authorization key,
    these transaction can be always be accompanied by unrelated inputs and
    outputs, e.g. fee management coins or multiple incompatible vaults.
    
    Triggers support a special "revault" output, which allows depositing
    some balance of the vault back into the OP_VAULT scriptPubKey that is
    being withdrawn from.
    
    When spending an OP_VAULT into an OP_UNVAULT trigger output, the witness
    stack must look like
    
      [trigger witness stack ...] <trigger-sPK> <target-hash> <trigger-vout_idx>
    
    The first two parameters are evaluated recursively as script. The
    <trigger-vout-idx> parameter indicates which vout is the related
    OP_UNVAULT, which allows us to handle script upgradeability for future
    witness versions.
    
    Final withdrawal
    ================
    
    Once an OP_UNVAULT output has been confirmed and the related
    <spend-delay> has elapsed, the output can be spent into a transaction
    matching the <target-hash> given in the trigger transaction. This final
    withdrawal transaction will be responsible for providing its own fees in
    whatever manner the withdrawer prefers.
    
    Recovery
    ========
    
    At any point before final withdrawal, OP_VAULT or OP_UNVAULT outputs can
    be swept to the recovery path.
    
    If no optional recovery authorization is used, all inputs to the
    recovery transaction must be from recovery-compatible vault outputs.
    There can only be two outputs: one transferring the full value of the
    vault inputs to the recovery sPK, and one ephemeral anchor output.
    
    If an optional recovery authorization has bene specified, the recovery
    transaction can be more freeform. The only requirements are that the
    full value of any vault inputs are transferred to a compatible recovery
    sPK output, and there must be at least one ephemeral anchor output. But
    unrelated inputs/outputs can "ride along" or provide fees, and otherwise
    recovery-incompatible vaults can be recovered together.
    
    [NOTE TODO: this has yet to be implemented, but is planned]
    
    Other notes
    ===========
    
    Use of OP_VAULT is restricted to witness v1 and up (Taproot).
    
    Credit
    ======
    
    Thanks to Greg Sanders, AJ Towns, and John Moffett for material
    suggestions and review that wound up improving this proposal.
    
    - AJ: make recovery authorization optional, revault trigger outputs
    - Greg: put trigger-hash onto witness stack to avoid bare OP_UNVAULT
    - John Moffett: explicating recursive eval attack and providing a test
      case.
    f24cf26174
  57. test: make TaprootInfo hashable a45b90ec0c
  58. test: add pprint_tx aa4f2a58e3
  59. test: add MiniWallet.get_utxo_as_txin 81dc847508
  60. test: add OP_VAULT functional tests 29798a375a
  61. jamesob force-pushed on Feb 23, 2023
  62. jamesob force-pushed on Feb 23, 2023
  63. jamesob force-pushed on Feb 23, 2023
  64. fixup! deferred checks build fix 8eacc25a06
  65. jamesob force-pushed on Feb 24, 2023
  66. DrahtBot added the label Needs rebase on Mar 8, 2023
  67. DrahtBot commented at 0:30 am on March 8, 2023: contributor

    🐙 This pull request conflicts with the target branch and needs rebase.

  68. jamesob commented at 4:41 pm on March 21, 2023: member
    Closing this until the BIP is finalized and this has been tested on inquisition (https://github.com/bitcoin-inquisition/bitcoin/pull/21).
  69. jamesob closed this on Mar 21, 2023

  70. bitcoin locked this on Mar 20, 2024

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-26 21:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me