@connext/vector-protocol
v0.2.5-beta.21
Published
Protocol is where the core Vector framework is defined. Protocol takes in params via method calls, uses them to make updates to its replicated state with a channel peer, and stores resulting commmitments in store.
Downloads
436
Keywords
Readme
Vector Protocol
Protocol is where the core Vector framework is defined. Protocol takes in params via method calls, uses them to make updates to its replicated state with a channel peer, and stores resulting commmitments in store.
Contents:
Developing and Running Tests
In ~/vector
(root), run:
make protocol
to build the protocolmake test-protocol
to run the module tests
Core Principles
Vector aims to be an extremely simple state channel protocol. Both parties follow a single flow to make updates:
- Leader Election -- this is done using a distributed lock implementation. Peers queue updates on the lock and execute them serially.
- Update Generation -- a proposed update is generated and signed by the sender in-memory
- Synchronization -- the sender's update is dispatched over the wire. Receiver validates the update, merges the update with their channel, stores the channel, and then acks. Sender receives the ack and stores.
We use the following design principles:
Vector uses leader election -> consensus to manage updates to both peers' replicated stores. To keep things simple (at the cost of some additional messaging overhead), we have chosen not to use a CRDT + turn taking pattern like those seen in StateChannels.
All updates in a channel fall into one of four types of operations:
All updates are single-round-trip and associated with a monotonically incrementing nonce.
The protocol does not make assumptions about message delivery to the counterparty. Each update additionally contains information about the
n-1
(previous) update. This means that if, for whatever reason, the counterparty failed to properly synchronize the last update, it is possible for them "recover" and do so within the single round trip of the next update. In other words, the protocol will always recover if a peer's state gets out of sync.All generated updates are matched to corresponding validators, that ensure that the peer's updates were generated and signed correctly.
The protocol is not where the RPC interface lives, which instead exists at the engine layer. This is done to allow extra-protocol functions (i.e. saving withdrawal commitments) to be executed via a channel provider, as well as allowing the RPC interface to be more usecase driven (i.e. including a
chan_withdraw
method)The protocol allows for generic transfer logic governed by the onchain
TransferDefinitions
included in theTransferRegistry
. The protocol is unaware of the transfer specifics, and relies on the onchain logic to provide the correct state and resolver encodings, validate the created state, and correctly resolve the balances.
Sync Protocol
At the core of Vector lies sync
. Unlike other state channel systems, there is only a single protocol -- sync
is used both when a sender wants to propose a new update to the replicated state, and also when peer state has diverged. Because updates are monotonic (nonce += 1), there are only a very limited number of cases within which party states possibly diverge.
For this reason, sync
takes a higher degree of control over message delivery than other state channel protocols do. Outbound messages are retried on a timer if they fail, inbound ones are idempotent. Higher-nonced inbound messages are checked against the ChannelState
latest nonce and dropped if they are duplicates, or saved to store if they aren't.
The protocol can be visualized as follows:
Update Types
All channel updates fall into one of 4 types. Each update type is responsible for generating and storing one double-signed commitment.
Note that there is no specific update for withdraw
. Instead, withdrawals can be constructed in an easy and generalizeable way using create
and resolve
(see here).
Setup
The setup update is responsible for creating a channel commitment at nonce 1 and establishing several channel constants:
channelAddress
: the CREATE2 address at which a proxy to theChannelMastercopy.sol
contract will be deployedalice
/bob
: the channel participants, which is a high-fidelity vs. low-fidelity participant in the channel. The assignment of these roles plays a critical role in channel deposits.timeout
: the time (in seconds) channel participants get in each of the dispute phases
The setup
update allows both participants to safely dispute a channel and reclaim funds from the multisig even if initial onchain deposits were never reconciled into the channel balance. For example, imagine a channel setup
commitment is generated and Alice deposits into the channel then generates a single-signed commitment that Bob never countersigns. Using the double-signed setup
commitment, Alice can safely dispute and defund the channel.
Deposit
An offchain deposit
update is designed to reconcile deposits that have been successfully mined onchain (either by calling the depositA
function for alice
, or simply sending funds to the multisig for bob
) with the offchain balance.
To do this safely, the following must occur:
- The update initiator's balance must be incremented by the deposit amount (calculating new balances for each party using onchain data as described in the Depositing and Withdrawing writeup). Note that this is per-assetId, so a new assetId would be added to the
assetId
array. - The
processedDepositsA
andprocessedDepositsB
must be updated to reflect that all onchain deposits have been reconciled offchain. - The channel nonce must be incremented.
- A new
ChannelCommitment
must be generated and signed by both parties. - Set this update to
state.latestUpdate
.
Create
A create update is designed to add a new active conditional transfer into the channel state.
The create update must do the following:
- Decrement the channel state
balance
on one (or both) sides by the amount that will be locked in the transfer (indexed by assetId). - Increment channel nonce.
- Validate the proposed initial
TransferState
by calling thecreate
function on the associated transfer definition. This function returns aboolean
value indicating the validity of the created state - Generate a new merkle tree including the hash the
TransferState
and update themerkleRoot
in the channel state. - Generate a duoblesigned
ChannelCommitment
. - Set this update to
state.latestUpdate
.
Resolve
A resolve update should occur when both parties want to remove a conditional transfer from the active transfers, and reintroduce its balances back to the main channel balance.
The resolve update must do the following:
- Reintroduce the appropriate balance into the channel. This balance is calculated by calling the
resolve
function on the transfer definition (which will also ensure the transfer is able to be resolved). - Increment channel nonce.
- Generate a new merkle tree by removing the hash of the
TransferState
from the active transfers, and update themerkleRoot
in the channel state. - Generate a double signed
ChannelCommitment
- Set this update to
state.latestUpdate