changed 5 years ago
Published Linked with GitHub

Actor Spec: PaymentChannel

Back to Master Tracking Doc

Contents

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

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

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

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

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
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
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
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
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

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

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?
Select a repo