# Actor Spec: PaymentChannel [Back to Master Tracking Doc](https://hackmd.io/LOZjAsz-THelSD5lWqSVlw) ## Contents [TOC] ## At a Glance The PaymentChannel actor allows two parties to establish an off-chain payment channel. This channel is only one directional from the party that sends the funds to the party that receives the funds. * Both parties may engage in microtransactions off-chain by exchanging signed Vouchers. * Vouchers may be submitted to the PaymentChannel instance by either party. Submitted Vouchers update the on-chain state of the PaymentChannel. * Either party may call `Settle` to begin the PaymentChannel's settling period. * Once the settling period ends, either party may call `Collect` to finalize the PaymentChannel's on-chain state, sending the appropriate amounts to each party and terminating the actor itself. **Actor Type:** - Instanced **Exported Methods:** 1. Constructor 2. UpdateChannelState 3. Settle 4. Collect ## State ```go= type State struct { From addr.Address To addr.Address ToSend abi.TokenAmount SettlingAt abi.ChainEpoch MinSettleHeight abi.ChainEpoch LaneStates []*LaneState } ``` **`From`**: The owner of the channel. Expected to send microtransactions to `To` off-chain. * Notes: * `From` is expected to fund the PaymentChannel with a token amount. * Invariants: * `From` is an ID address * `From` is an Account actor **`To`**: The beneficiary who receives payments off-chain in the form of signed vouchers. * Notes: * `To` is expected to validate that the `CurrentBalance` of the PaymentChannel actor on-chain meets or exceeds the value of the vouchers being signed off-chain. * Invariants: * `To` is an ID address * `To` is an Account actor **`ToSend`**: The token amount successfully redeemed by the highest-nonce voucher submitted to `UpdateChannelState`. Paid to `To` on `Collect`. * Notes: * Any remaining value will be sent to `From`. * Invariants: * `ToSend >= 0` * `ToSend <= rt.CurrentBalance()` **`SettlingAt`**: The epoch after which a call to `Collect` will send `ToSend` to `To`. * Notes: * Initially, `SettlingAt` is set to 0, denoting that the PaymentChannel is not currently settling. * A nonzero value denotes that the PaymentChannel will settle at `SettlingAt`, at which point `Collect` can be called. * Invariants: * `SettlingAt >= 0` **`MinSettleHeight`**: If set, denotes the minimum epoch at which the PaymentChannel can `Settle`. * Notes: * Can only be set via `UpdateChannelState`: both parties must agree to this value. * Invariants: * `MinSettleHeight >= 0` **`LaneStates`**: A collection of "lanes" between the parties. Each lane keeps track of its latest-seen `Nonce` and total `Redeemed` amount. * Invariants: * `len(st.LaneStates) <= LaneLimit` (256) #### LaneState ```go= type LaneState struct { ID uint64 Redeemed big.Int Nonce uint64 } ``` **`ID`**: The lane's ID in `st.LaneStates`. * Notes: * Any valid `uint64` value may serve as an `ID`. * A signed voucher specifies to which lane it applies via the field `sv.Lane` **`Redeemed`**: The token amount successfully redeemed by the highest-nonce voucher associated with this lane. * Notes: * `Redeemed <= rt.CurrentBalance()` * `Redeemed >= 0` **`Nonce`**: The highest-seen nonce attributed to a voucher redeemed for this lane. ## Exported Methods #### 1. Constructor ```go= func (pca *Actor) Constructor(rt vmr.Runtime, params *ConstructorParams) *adt.EmptyValue ``` Initializes actor state with the resolved addresses of `params.From` and `params.To` as the PaymentChannel's parties. **`params.From`** may be provided as address protocols SECP, BLS, or ID. **`params.To`** may be provided as address protocols SECP, BLS, or ID. ##### Failure conditions * `params.From` is not an Account actor * `params.To` is not an Account actor #### 2. UpdateChannelState ```go= func (a Actor) UpdateChannelState(rt vmr.Runtime, params *UpdateChannelStateParams) *adt.EmptyValue ``` Allows either party to update the channel's state by providing a voucher signed by their counterparty. Supports two primary operations: * Lane creation: If the lane specified by `params.Sv.Lane` does not exist, it will be created. * Up to 256 unique lanes may be exist in PaymentChannel before lane creation fails. * Lanes are created one-at-a-time: a maximum of 1 lane will be created per call to `UpdateChannelState` * On creation, the new lane is placed in `st.LaneStates` with the following values: * `ID`: `params.Sv.Lane` * `Redeemed`: `params.Sv.Amount` * `Nonce`: `params.Sv.Nonce` * Lane merges: The redemption of a voucher through `UpdateChannelState` is an implicit "merge" of the voucher's `params.Sv.Amount` into the lane's state. A merge updates the lane's `Redeemed` and `Nonce` fields. * Additional merges may be specified through the optional field `params.Sv.Merges`. For each entry therein, a merge operation will be performed from `merge.Lane` into `params.Sv.Lane`. * Each merged lane's `Redeemed` total is subtracted from `params.Sv.Amount`. The sum of these operations is added to `st.ToSend`. ##### Parameters ```go= type UpdateChannelStateParams struct { Sv SignedVoucher Secret []byte } ``` **`Sv`**: A voucher signed by either `st.From` or `st.To` **`Secret`**: If the SignedVoucher has a SecretPreImage (`len(sv.SecretPreimage) > 0`), the hash of `Secret` must match it. * Requirements: * `len(Secret) <= MaxSecretSize` (256) ###### SignedVoucher ```go= type SignedVoucher struct { ChannelAddr addr.Address TimeLockMin abi.ChainEpoch TimeLockMax abi.ChainEpoch SecretPreimage []byte Extra *ModVerifyParams Lane uint64 Nonce uint64 Amount big.Int MinSettleHeight abi.ChainEpoch Merges []Merge Signature *crypto.Signature } ``` **`ChannelAddr`**: The address of the PaymentChannel actor this SignedVoucher is valid for * Requirements: * `ChannelAddr == rt.Message().Receiver()` **`TimeLockMin`**: Before epoch `TimeLockMin`, this voucher may not be redeemed. * Notes: * OPTIONAL. 0 by default. * Requirements: * `rt.CurrEpoch() < TimeLockMin` **`TimeLockMax`**: After epoch `TimeLockMax`, this voucher may not be redeemed. If `TimeLockMax` is 0, this field is not checked. * Notes: * OPTIONAL. 0 by default. * `TimeLockMin == TimeLockMax` implies a 1-epoch window in which the voucher may be redeemed * Requirements: * `TimeLockMax == 0 || rt.CurrEpoch() >= TimeLockMax` **`SecretPreimage`**: If provided, `params.Secret` must be a valid preimage of `SecretPreimage` * Notes: * OPTIONAL. `nil` by default. **`Extra`**: If provided, `Extra` defines an arbitrary Send that should succeed when provided some additional `Proof` by the Caller. * Notes: * OPTIONAL. `nil` by default. * No value will be sent with this Send. * See `ModVerifyParams` below for details on individual fields. * Requirements: * The Send must succeed (`ExitCode == 0`) **`Lane`**: Specifies which lane the voucher will be redeemed for. * Notes: * If the lane does not exist within `st.LaneStates`, it will be created. * A lane may not be created if there are already 256 lanes in the PaymentChannel. **`Nonce`**: Prevents the redemption of old vouchers. `Nonce` is compared to the highest-seen nonce of the lane specified by `Lane`. The lane's `ls.Nonce` will be set to `Nonce`. * Requirements: * `ls.Nonce < Nonce` **`Amount`**: The token amount this voucher may be redeemed for. The lane's `ls.Redeemed` field will be set to `Amount`. * Notes: * The sum of `Amount`, the lane's current `ls.Redeemed` amount, and any `ls.Redeemed` amounts from other lanes specified in `Merges` will be added to `st.ToSend`. * Requirements: * `Amount >= 0` **`MinSettleHeight`**: If nonzero, may cause `UpdateChannelState` to modify the settling epoch. * Notes: * OPTIONAL. 0 by default. * If the settling epoch has been set (`st.SettlingAt != 0`) AND `MinSettleHeight` specifies a greater epoch, the settling epoch is updated to `MinSettleHeight`. * If `MinSettleHeight` specifies a greater epoch than the one currently recorded in `st.MinSettleHeight`, this state is updated. * Requirements: * `MinSettleHeight >= 0` **`Merges`**: If provided, denotes a collection of other lanes that will be merged into the `Lane` specified by the voucher. * Notes: * OPTIONAL. `nil` by default. * See `Merge` below. **`Signature`**: A signature over `sv.SigningBytes`, signed by the counterparty to the Caller. * Notes: * If Caller is `st.From`, the signature must be from `st.To` * If Caller is `st.To`, the signature must be from `st.From` * Requirements: * `Signature != nil` * Must be a valid signature as determined by `rt.Syscalls().VerifySignature` ###### ModVerifyParams ```go= type ModVerifyParams struct { Actor addr.Address Method abi.MethodNum Params []byte } ``` **`Actor`**: The actor to which a Send will be made, denoting extra verification. **`Method`**: The MethodNum of the actor to invoke. **`Params`**: The data provided as parameters to the method invocation. ###### Merge ```go= type Merge struct { Lane uint64 Nonce uint64 } ``` **`Lane`**: Which lane will be merged into the lane specified by the voucher (`sv.Lane`). * Requirements: * `Lane` must exist in `st.LaneStates` * `Lane != sv.Lane` **`Nonce`**: Compared to the highest-seen nonce of the merging lane. The lane's nonce is updated to this value. * Requirements: * `Nonce` must be greater than the current nonce of the merging lane. ##### Failure conditions * Caller is not `st.From` or `st.To` * `sv.Signature == nil` * `st.SettlingAt != 0 && rt.CurrEpoch >= st.SettlingAt` * `len(params.Secret) > MaxSecretSize` (256) * SignedVoucher unable to be serialized via `SigningBytes` * Signature verification fails (via `rt.Syscalls().VerifySignature`) * SignedVoucher is not valid for this PaymentChannel (`rt.Message().Receiver() != sv.ChannelAddr`) * `rt.CurrEpoch() < sv.TimeLockMin` * `sv.TimeLockMax != 0 && rt.CurrEpoch() > sv.TimeLockMax` * `sv.Amount < 0` * `len(sv.SecretPreimage) != 0` AND hashed `params.Secret` does not match * `sv.Extra != nil` AND external validation fails * `sv.Lane` specifies a lane that does not exist in `st.LaneStates` AND `len(st.LaneStates) >= 256` * `ls.Nonce >= sv.Nonce` * For any provided Merge: * `merge.Lane == sv.Lane` * `merge.Lane` does not exist in `st.LaneStates` * Nonce specified by `merge.Lane` LaneState is greater than or equal to nonce specified by `merge.Nonce` * Updated `st.ToSend` balance would be negative * Updated `st.ToSend` balance would be greater than the current balance of the PaymentChannel #### 3. Settle ```go= func (pca Actor) Settle(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` Sets `st.SettlingAt`, which is the epoch where either party may call `Collect`. This may only be called once. * `st.SettlingAt` is set to the maximum value between `rt.CurrEpoch() + SettleDelay` and `st.MinSettleHeight` Once the channel has settled (`CurrEpoch == st.SettlingAt`), further updates to the channel are prohibited. ##### Failure conditions * Caller is not `st.From` or `st.To` * `Settle` has already been called (`st.SettlingAt != 0`) #### 4. Collect ```go= func (pca Actor) Collect(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` At or after the settling epoch, allows either party to collect the amount redeemed so far. * `st.ToSend` is sent to `st.To` * The PaymentChannel actor is deleted via `rt.DeleteActor`, with `st.From` supplied as the beneficiary of the remaining funds. ##### Failure conditions * Caller is not `st.From` or `st.To` * `st.SettlingAt == 0`, denoting that `Settle` has not been called yet * `rt.CurrEpoch() < st.SettlingAt`, denoting that the settling epoch has not been reached * The Send to `st.To` fails * `rt.DeleteActor(st.From)` fails because `st.From` does not exist ## Open Questions * UpdateChannelState: Does `SigningBytes()` add additional salt, domain separators, or other information to ensure that signed vouchers are unique in respect to both the payment channel AND the specific permutation of provided values? * UpdateChannelState: Does `Syscalls().VerifySignature()` resolve the `signer` to a BLS/SECP address? * UpdateChannelState: Should `SignedVoucher.ChannelAddr` use the PaymentChannel's ACTOR address for re-org protection? * Collect: Could `st.From` cause the first `Send` to fail in any way outside of the actor being underfunded already?