Stellar work Antoine and Gleb! Really excited to see designs come out on
payment pools.

I've also been designing some payment pools (I have some not ready code I
can share with you guys off list), and I wanted to share what I learned
here in case it's useful.

In my design of payment pools, I don't think the following requirement: "A
CoinPool must satisfy the following *non-interactive any-order withdrawal*
property: at any point in time and any possible sequence of previous
CoinPool events, a participant should be able to move their funds from the
CoinPool to any address the participant wants without cooperation with
other CoinPool members." is desirable in O(1) space. I think it's much
better to set the requirement to O(log(n)), and this isn't just because of
wanting to use CTV, although it does help.

Let me describe a quick CTV based payment pool:

Build a payment pool for N users as N/2 channels between participants
created in a payment tree with a radix of R, where every node has a
multisig path for being used as a multi-party channel and the CTV branch
has a preset timeout. E.g., with radix 2:

                                     /                                   \
\                                                    /                 \
Channel(a,b)    Channel(c,d)                          Channel(e,f)

All of these channels can be constructed and set up non-interatively using
CTV, and updated interactively. By default payments can happen with minimal
coordination of parties by standard lightning channel updates at the leaf
nodes, and channels can be rebalanced at higher layers with more

Now let's compare the first-person exit non cooperative scenario across

Wait time: Log(N). At each branch, you must wait for a timeout, and you
have to go through log N to make sure there are no updated states. You can
trade off wait time/fees by picking different radixes.
TXN Size: Log(N) 1000 people with radix 4 --> 5 wait periods. 5*4 txn size.
Radix 20 --> 2 wait periods. 2*20 txn size.

Wait Time: O(1)
TXN Size: Depending on accumulator: O(1), O(log N), O(N) bits. Let's be
favorable to Accumulators and assumer O(1), but keep in mind constant may
be somewhat large/operations might be expensive in validation for updates.

This *seems* like a clear win for Accumulators. But not so fast. Let's look
at the case where *everyone* exits non cooperatively from a payment pool.
What is the total work and time?

CTV Pool:
Wait time: Log(N)
Txn Size: O(N) (no worse than 2x factor overhead with radix 2, higher
radixes dramatically less overhead)

Accumulator Pool:
Wait time: O(N)
Txn Size: O(N) (bear in mind *maybe* O(N^2) or O(N log N) if we use an
sub-optimal accumulator, or validation work may be expensive depending on
the new primitive)

So in this context, CTV Pool has a clear benefit. The last recipient can
always clear in Log(N) time whereas in the accumulator pool, the last
recipient has to wait much much longer. There's no asymptotic difference in
Tx Size, but I suspect that CTV is at least as good or cheaper since it's
just one tx hash and doesn't depend on implementation.

Another property that is nice about the CTV pool style is the bisecting
property. Every time you have to do an uncooperative withdrawal, you split
the group into R groups. If your group is not cooperating because one
person is permanently offline, then Accumulator pools *guarantee* you need
to go through a full on-chain redemption. Not so with a CTV-style pool, as
if you have a single failure among [1,2,3,4,5,6,7,8,9,10] channels (let's
say channel 8 fails), then with a radix 4 setup your next steps are:
[1,2,3,4] [5,6,7,X] [9,10]
[1,2,3,4] 5 6 7 X [9,10]

So you only need to do Log(N) chain work to exit the bad actor, but then it
amortizes! A future failure (let's say of 5) only causes 5 to have to close
their channel, and does not affect anyone else.

With an accumulator based pool, if you re-pool after one failure, a second
failure causes another O(N) work. So then total work in that case is
O(N^2). You can improve the design by making the evict in any order option
such that you can *kick out* a member in any order, that helps solve some
of this nastiness (rather than them opting to leave). But I'm unclear how
to make this safe w.r.t. updated states. You could also allow, perhaps, any
number of operators to simultaneously leave in a tx. Also not sure how to
do that.

With CTV Pools, you can make a payment if just your immediate conterparty
is online in your channel. Opportunistically, if people above you are
online, you can make channel updates higher up in the tree which have
better timeout properties. You can also create new channels, binding
yourself to different parties if there is a planned exit.

With Accumulator pools, you need all parties online to make payments.

Cooperation Case:
CTV Pools and Accumulator pools, in a cooperative case, both just act like
a N of N multisig.

Because Accumulator pools always require N signers, it's possible to build
a better privacy model where N parties are essentially managing a chaumian
ecash like server for updates, giving good privacy of who initiated
payments. You *could* do this with CTV pools as well, but I expect users to
prefer making updates at the 2 party channel layer for low latency, and to
get privacy benefits out of the routability of the channels and ability to
connect to the broader lightning network.

Technical Complexity:
Both protocols require new features in Bitcoin. CTV is relatively simple, I
would posit that accumulators + sighashnoinput are relatively not simple.

The actual protocol design for CTV pools is pretty simple and can be
compatible with LN, I already have a rudimentary implementation of the
required transactions (but not servers).


In both designs, the payment pool can be created non-interactively. This is
*super* important as it means third parties (e.g., an exchange) can
withdraw users funds *into* a payment pool.

Thanks for reading!


@JeremyRubin <>
bitcoin-dev mailing list

Reply via email to