Superseded by the approach described here - https://gist.github.com/antiochp/d490280fa0b87e0cd84f961b0911119f
Elder (inspired by Eltoo).
Also "Elder Wand".
Taking heavy insiration from the Eltoo Channel design but leveraging the simplicity (and contraints) of Grin/MW transactions.
Unlike Eltoo we do not have the ability to "rebind" transactions based on output scripts (there are no scripts in Grin/MW).
In contrast we can easily build on unconfirmed transactions. We can also aggregate and cut-through intermediate state. Rebinding becomes multi-kernel tx aggregation.
Fees are ignored here for simplicity (and potentially ignored by design).
tl;dr Elder payment channels are simple aggregated cut-through transactions involving multisig outputs and some careful constraints around tx dependencies.
Channel state is represented as a single multisig output.
Outchannel_0
The channel is initially funded by building this multisig output. Alice and Bob build this transaction, sending funds to it as necessary.
Txfund_0 ([InA, InB] -> Outchannel_0, Kernfund_0)
The channel is open once this funding tx is broadcast and confirmed.
Updating the channel state is done via a series of "update" txs spending from the previous multisig output to a new multisig output.
Txupdate_1 (Inchannel_0 -> Outchannel_1, Kernupdate_1)
Multiple updates txs can be combined into a single aggregate tx. The resulting cut-through tx consists of a spend from the initial state to the latest state and kernels for each intermediate state update.
Txupdate_1 (Inchannel_0 -> Outchannel_1, Kernupdate_1)
Txupdate_2 (Inchannel_1 -> Outchannel_2, Kernupdate_2)
Txupdate_3 (Inchannel_2 -> Outchannel_3, Kernupdate_3)
=> Txupdate_1_3 (Inchannel_0 -> Outchannel_3, [Kernupdate_1, Kernupdate_2, Kernupdate_3])
These updates are built but not broadcast. They only need to be broadcast to close the channel non-cooperatively.
Alice and Bob both store the latest channel state and all previous update kernels. They do not need to store all previous update transactions.
Both parties need to mutually agree on state updates. Normally they would build individual transactions to transition from one state to another. Channels may have large numbers of state transitions and funds are adjusted between parties. It would be relatively easy for both parties to build additional "skip list" transactions to keep the number of kernels manageable.
[Needs more thought but additional txs like (Inchannel_0 -> Outchannel_10) allowing sequences of update txs to be skipped.]
The "cooperative close" scenario is straightforward. Both parties can mutually decide to close the channel at any point by simply spending the multisig output, sending funds to both parties as desired.
Txcoop_0 (Inchannel_0 -> [OutA, OutB], Kerncoop_0)
A cooperatively closed Elder channel is indistinguishable from a couple of regular transactions ("fund" and "close"). The outputs are not even identifiable as multisig.
The "non-cooperative close" scenario allows either party to close the current channel state. This is done by mutually building a pair of "close" and "settle" txs for each channel state.
The "close" and "settle" transactions must be mutually negotiated by the parties involved in the channel and should be built prior to the corresponding state "update" tx to avoid funds getting blocked by either party.
These are symmetric transaction (as in Eltoo Channels). Neither Alice nor Bob require endpoint specific transactions.
Txupdate_2 (Inchannel_1 -> Outchannel_2, Kernupdate_2)
Each channel state has a corresponding pair of "close" and "settle" transactions associated with it. The "settle" transaction has a relative lock height against the "close" transaction. This lock height is used to "revoke" a "close" and is described later. The example here uses a relative lock height of 1,440 (24 hours). The "settle" tx can only be accepted 1,440 blocks after the "close" tx has been confirmed. This 24 hour delay can be avoided by cooperatively closing the channel.
Txclose_2 (Inchannel_2 -> Outclose_2, Kernclose_2)
Txsettle_2 (Inclose_2 -> [OutA, OutB], Kernsettle_2,close_2,1440)
Either party can close the channel at the latest state via the appropriate "close" tx. Each channel state has an associated close tx. Only the latest state should be closed. The problem here is any old state can be closed using an old "close" tx. We prevent this by allowing the other party to "revoke" a previous "close" tx.
The "revoke" tx spends a specific "close" output back to the next successive channel state. If either party sees a previous "close" they can immediately "revoke" it and begin the process of a non-cooperative close on the latest state.
Txrevoke_0 (Inclose_0 -> Outchannel_1, Kernrevoke_1)
Each state can potentially be the result of a state "update" or from the "revoke" of a "close" on the previous state.
For example if we are currently at state Outchannel_2 and Alice sees an old state close attempt (Outclose_0) they can broadcast the necessary "revoke" and subsequent channel state update txs to close the most recent state. These can be aggregated and cut-through to produce a single aggregated "revoke and close" tx.
The resulting cut-through tx consists of a spend of the old revoked "close" output to the latest close state along with all intermediate channel state update kernels.
Txrevoke_0 (Inclose_0 -> Outchannel_1, Kernrevoke_1)
Txupdate_2 (Inchannel_1 -> Outchannel_2, Kernupdate_2)
Txclose_2 (Inchannel_2 -> Outclose_2, Kernclose_2)
=> Txrevoke_close (Inclose_0 -> Outclose_2, [Kernrevoke_1, Kernupdate_2, Kernclose_2])
Either party can revoke any close attempt on an old previous state. There is no need to penalize the other party as we can simply close the channel in the non-cooperative case if this occurs.
We take advantage of the delay between "close" and "settle" here to "revoke" as necessary. A "revoke" of an old state can always be broadcast before the revoked "settle" tx.
A "revoked" channel collapses into a non-cooperatively closed channel. There is nothing on-chain to distinguish these two cases. The relative lock height between the "close" and "settle" transactions will be visible on-chain but these will be indistinguishable from any other relative lock height occurence.
Either party can close the latest state from any prior state. To do so they need the latest "close" and "settle" tx pair and the kernels (but not the txs themselves) from all previous state updates.
Txclose_n (Inchannel_n -> Outclose_n, Kernclose_n)
Txsettle_n (Inclose_n -> [OutA, OutB], Kernsettle_n,close_n,1440)
[Kernupdate_1, Kernupdate_2, ..., Kernupdate_n]
To support revocation of any previous close state they also need to store all previous "revoke" kernels.
[Kernrevoke_0, Kernrevoke_1, ..., Kernrevoke_n-1]
Regardless of what either party broadcasts, the other party can construct a single compensating tx that will robustly close the channel at the latest state from the lateast state and the set of previous kernels.
We can reduce the total number of kernels in the aggregate tx (see "skip lists") but we will still likely be limited in terms of how many state updates we can robuystly perform on a given channel. We will likely have to consider some kind of channel "refresh" or "reset" transaction, similar to the initial funding transaction that will allow the parties to mutually refresh or reset the channel over time.
1,000 channel updates will require a relatively large tx (1,000 intermediate kernels) to close it non-cooperatively for exmple. This is still significantly smaller than the full 1,0000 intermediate transactions.
We have ignored fees entirely in the above description. We can always increase the fees of any given tx (smaller than max weight) by aggregating it with a high fee tx. The entire channel construction may be workable by deferring the introduction of fees until the channel is closed.
Any party attempting to close an old state will need to provide the necessary fees.
Any party deciding to non-cooperatively close the channel will need to provide sufficient fees to do so.
If the channel is cooperatively closed the parties can mutually negotiate a suitable fee.
I don't like the chaining of txs and resultant accumulation of kernels, which the skip lists only partially address.
A direct implementation of Poon-Dryja channels [1] would only require only a handful of kernels to be broadcast in total?!
[1] https://lightning.network/lightning-network-paper.pdf