Hi list,
In this post, I'm digging on OP_CHECKCONTRACTVERIFY (OP_BIP 443)
and how it can be leveraged to design UTXO-sharing schemes like
CoinPool, and the limits of the primitive in this regard.
### CoinPool: Main Operations
In this section, I'm reminding the main operations of a coinpool
(for more in-depth reminders, see [0], [1], [2]). Basically, a
coinpool is a multi-party construction designed to improve the
onboarding and transactional scaling of bitcoin users by orders of
magnitude. To work in an efficient way, it requires some consensus
changes, e.g a TAPROOT_LEAF_UPDATE_VERIFY or OP_MERKLE_SUB [3] (the
primitive matters less than the level of expressivity brought by
the primitive).
A coinpool instance is defined by a set of public keys and the
associated balances, which are debited and credited during pool
operation. State is maintained by an on-chain UTXO and a set of
pre-signed transactions encoding the users' balances. Off-chain
transfers between pool accounts require replacing old pre-signed
txn and all the pool participants have to approve.
Once the off-chain pool state has hit the chain, all the users
can recursively and non-interactively withdraw their funds, one
by one.
This recursive update of the state pool is the mechanism on which
to draw attention in the present post, and especially in which measure
it can be (imperfectly) reproduced with OP_CHECKCONTRACTVERIFY.
Let's say you have a pool of four (A,B,C,D) [4]
Funding UTXO script is a multisig of ABCD.
Each update transaction has a Eltoo-encoded nLockime.
In the output of each update transaction, each participant with
a balance has an exit path.
Any withdraw transaction can consume an update tx exit path.
The MERKLESUB (or TLUV) ensure that the withdraw output is the
similar script with 3 modifications:
- the withdrawing participant balance has been subtracted
from the pool balance amount
- the withdrawing participant point has been subtracted
from the curve point constituting the internal point
- the withdrawing participant script has been subtracted
from the tree of scripts
This mechanism allows the participants to withdraw from the update
tx output in any-order, i.e without having to know at setup who is
the first that is going to exit the off-chain construction.
This is ensuring reasonable fault-tolerance of the construction, where
one bad party cannot force a massive on-chain footprint, of which the
cost would be burden by all the pool participants (and the chain txn logs
be unnecessarily inflated).
### A CoinPool built with OP_CCV
The proposed opocode OP_CHECKCONTRACTVERIFY, in my understanding, works
in the following way. When evaluating an OP_CCV, the interpreter is excpecting
5 elements on the stack:
- <mode> : the selected verification mode
- <taptree> : the tweaked taptree
- <pk> : the verified naked key
- <index> : the verified input or output index
- <data> : a buffer of arbitrary data length
By selecting the accurate mode (i.e `CCV_MODE_CHECK_OUTPUT`), one
can ensure that an output is encumbered by an expected taptree and
an expected internal public key. The output amount and its update
can be selected with the combinatory `CCV_MODE_CHECK_OUTPUT_DEDUCT_AMOUNT`.
Going back to CoinPool design, any order recursive mechanism
for the withdrawals can be implemented with CCV in the following way.
At each update tx, the participants builts a withdraw tx for each participant and multi-sign it.
The output in the update has all the branches of the `taptree`.
When a pool participant wishes to withdraw, it gives the `updated_taptree` in the
witness of the withdraw transaction as a CCV argument.
The multi-signature ensures that the pre-image `update_taptree` matches the expected
withdraw output. The multi-signature can also ensure the amount matches the off-chain
balance. However, this approach is limited for one step, as otherwise the pool participant
would have to generate a withdraw tx for each combination. While this workable for
small sized pool, this is a practical exponential limit for a high number of participants
(from previous measures around the 11th or 12th participant).
## Open Design Questions
This is an open design question if CCV can be combined with other opcodes,
where introspection would be done on the <data> argument to deduce from it
what should be the triplet (pubkey, tree, amount) for the withdraw tx output
based on the input state.
From laying out the question, there are 2 obvious observations for the bitcoin
script experts (a) if this hypothetical introspection phase can be rendered
unforgeable by any of the participant to the pool and (b) if a contrario a
templated approach a la MERKLESUB and OP_TLUV is not more efficient witness
space wise.
This short analysis is limited to the usage of OP_CCV for the precise case
of UTXO-sharing like CoinPool, and its design trade-offs might be more fruitful
and is more adapted for other use-cases.
Cheers,
Antoine
OTS hash: 15a8f04022265a0258e51ca54d98285bc9e33df0342f5700cd91e750febbe4de
[0]
https://gnusha.org/pi/bitcoindev/CALZpt+FqAWCAqCLF2HsajL84sOvst_X9_34bb_tvUxLFw=HT...@mail.gmail.com/[1]
https://gnusha.org/pi/bitcoindev/CALZpt+E+eKKtOXd-8A6oThw-...@mail.gmail.com/[2]
https://github.com/ariard/coinpool-gitbook/blob/master/coinpool-v0.1.pdf[3]
https://gnusha.org/pi/bitcoindev/20210909064...@erisian.com.au/[4]
https://gist.github.com/ariard/713ce396281163337c175d9122163e8f