Virtual Channel Tutorial

In this tutorial, we will explain how Go-Perun can be used to create a two-party virtual payment channel. A virtual channel is a channel that is funded off-chain from existing channels. In our scenario, we will have the parties Alice, Bob, and Ingrid. Alice and Bob have an open ledger channel with Ingrid and will then open a virtual channel between each other.

Virtual channel setup


The virtual channel protocol is described in section Protocols. Transactions in a virtual channel work the same as in other types of channels. What is different is the funding and settlement. Funds will be deducted from the open channels with Ingrid, and then provided to the newly created virtual channel between Alice and Bob. Once the channel is created, they can make peer-to-peer payments between each other without involving Ingrid. However, Ingrid is involved in the creation and settlement of the virtual channel.

Source code

As an example we will rely on the virtual channel test of Go-Perun. This test shows how a virtual channel is created and used.

Channel opening

As a pre-requisite, we require that Alice and Bob have an open channel with Ingrid. These channels are created at the beginning of the test setup.

Once Alice and Bob have an open channel with Ingrid, Alice specifies the virtual channel proposal that she will send to Bob.

	// Establish virtual channel between Alice and Bob via Ingrid.
	initAllocVirtual := channel.Allocation{
		Assets:   []channel.Asset{asset},
		Balances: [][]channel.Bal{initBalsVirtual},
	indexMapAlice := []channel.Index{0, 1}
	indexMapBob := []channel.Index{1, 0}
	vcp, err := client.NewVirtualChannelProposal(
		[]wire.Address{alice.Identity.Address(), bob.Identity.Address()},
		[]channel.ID{vct.chAliceIngrid.ID(), vct.chBobIngrid.ID()},
		[][]channel.Index{indexMapAlice, indexMapBob},
	require.NoError(err, "creating virtual channel proposal")

Virtual channel proposals are created using client.NewVirtualChannelProposal and then specifying the identifiers of the channels from which the funds come from.

		[]channel.ID{vct.chAliceIngrid.ID(), vct.chBobIngrid.ID()},

Furthermore, it must be specified how the indices of the participants map from the parent channels to the virtual channel. Here, we specify that Alice has index 0 in the virtual channel and Bob has index 1. Ingrid, on the other hand funds the respective opposite party and therefore takes their index during the funding and settlement phase.

	indexMapAlice := []channel.Index{0, 1}
	indexMapBob := []channel.Index{1, 0}

The channel proposal is sent as usual by using client.ProposeChannel.

	vct.chAliceBob, err = alice.ProposeChannel(ctx, vcp)

Afterwards, a channel object is returned that can be used for off-chain transactions just as any other channel object.

Channel closing

The virtual channel settlement protocol guarantees that either the funds are withdrawn back into the parent ledger channels, in the optimistic case, or, in the dispute case, that the funds are withdrawn on the ledger. Perun handles both cases for you. As a user of the library, you simply need to call ch.Settle as usual.