Skip to content

Commit

Permalink
Integrate go-perun doc
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasgeihs committed Mar 1, 2021
1 parent cc46438 commit 5127ec3
Show file tree
Hide file tree
Showing 28 changed files with 1,619 additions and 0 deletions.
5 changes: 5 additions & 0 deletions source/conf.py
Expand Up @@ -175,3 +175,8 @@
'build_url': os.getenv('CIRCLE_BUILD_URL', ''),
'commit': os.getenv('GIT_COMMIT', '')[:7]
}

# Fix for linking to Github anchor link
linkcheck_ignore = [
'https://github.com/trufflesuite/ganache-cli#'
]
49 changes: 49 additions & 0 deletions source/go-perun/index.rst
@@ -0,0 +1,49 @@
Go-Perun
========

`go-perun <https://github.com/hyperledger-labs/go-perun>`_ is a Go implementation of the Perun state channel protocols.

Developer Tutorial
------------------

The :ref:`developer-tutorial` shows how go-perun is used to build a simple scalable payment application on top of the Ethereum blockchain.

.. toctree::
:maxdepth: 2

tutorial/index

Feedback
--------

Feel free to send your feedback to `info@perun.network <mailto:info@perun.network>`_.

Additional Resources
--------------------

* `Perun Network Website <https://perun.network>`_
* `Perun CLI Demo <https://github.com/perun-network/perun-eth-demo>`_
* `Perun Node <https://github.com/hyperledger-labs/perun-node>`_

Security Disclaimer
-------------------

go-perun is still alpha software.
It should not be used in production.
The purpose of the `current release <https://github.com/hyperledger-labs/go-perun/releases>`_ is to give potential users a general impression and invite feedback.
The authors take no responsibility for any loss of digital assets or other damage caused by the use of this software.
**Do not use this software with real funds**.

Project Funding
---------------

This project is currently being developed by a group of dedicated hackers at the Chair of Applied Cryptography at Technische Universität Darmstadt, Germany.
We thank the German Federal Ministry of Education and Research (BMBF) for their funding through the StartUpSecure grants program as well as the German Science Foundation (DFG), the Foundation for Polish Science (FNP) and the Ethereum Foundation for their support in the research that preceded this implementation.

Copyright
---------

Copyright 2021 - PolyCrypt GmbH, Germany.
Use of the source code is governed by the Apache 2.0 license that can be found in the `LICENSE file <https://github.com/hyperledger-labs/go-perun/blob/dev/LICENSE>`_.

Contact us at `info@perun.network <mailto:info@perun.network>`_.
74 changes: 74 additions & 0 deletions source/go-perun/tutorial/channels/closing.rst
@@ -0,0 +1,74 @@
Closing
=======

Closing a channel can be done in two ways, either cooperative or non-cooperative. This example focuses on the cooperative way. As you would expect from closing an off-chain
channel, the on-chain balances will be updated accordingly. But before that can happen
there are some other steps that we will go through first.

.. _the-watcher:

The Watcher
^^^^^^^^^^^

*go-perun* reacts automatically to on-chain events of a channel as long as its `watcher` routine is running. You should start the watcher in the `NewChannel` handler in a new
go-routine since `channel.Watch`_ blocks.

.. _finalizing:

Finalizing
^^^^^^^^^^

The state of a channel in *go-perun* has a public boolean `IsFinal`_ flag.
Final states can directly be closed on-chain without raising a dispute.
This allows for a faster collaborative closing process.
As soon as a channel has a final state, we call it *finalized* since it can not
be updated anymore. Have a look again at :ref:`updating` on how to do it.

Registering
^^^^^^^^^^^

Registering a channel means pushing its latest state onto the `Adjudicator`.
A registered channel state is openly visible on the blockchain. This should only be done
when a channel should be closed or disputed.

.. note::

Registering non-finalized channels will raise a dispute.

Settlement
^^^^^^^^^^

Settlement is the last step in the lifetime of a channel. It consists of two steps:
*conclude* and *withdraw*. *go-perun* takes care of both when `channel.Settle`_ is called.

*conclude* waits for any on-chain disputes to be resolved and then calls the `Adjudicator`
to close the channel. After this is done, the channel can be *withdrawn*. This is done only
once by one of the channel participants.

The last step is for each participant to *withdraw* their funds from the `AssetHolder`.
The balance that can be withdrawn is the same as the final balance of the channel.
Ethereum transaction fees still apply.

.. warning::

Trying to settle a channel that was not registered before is not advised and
can result in a dispute.

Keep in mind that we already *finalized* the channel in the update that we sent.
We therefore just need to *register* and *settle* which looks like this:

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 130-147

The other participant would then have its `AdjudicatorEvent` handler called with a
`ConcludedEvent`_ and should then also execute `closeChannel`.

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 149-155

.. _IsFinal: https://pkg.go.dev/perun.network/go-perun/channel#State
.. _channel.Settle: https://pkg.go.dev/perun.network/go-perun/client#Channel.Settle
.. _channel.Watch: https://pkg.go.dev/perun.network/go-perun/client#Channel.Watch
.. _ConcludedEvent: https://pkg.go.dev/perun.network/go-perun/channel#ConcludedEvent
23 changes: 23 additions & 0 deletions source/go-perun/tutorial/channels/disputes.rst
@@ -0,0 +1,23 @@
.. _disputes :

Disputes
========

A *dispute* occurs when the channel participants cannot agree on the current state.
Say for example *Bob* is sure that he has 5 *ETH* but *Alice* insists that he has only 4 *ETH*.

Disputes are resolved on-chain.
The Perun protocols guarantee that the most recent state agreed to by all channel participants can be redeemed.
Disputes are handled by the `Adjudicator` contract which determines the valid state by comparing the version numbers of the provided channel states.

A dispute is raised as soon as one participant registers a non-final state in the
`Adjudicator`. The other participant then has `challengeDuration`-seconds time to react by submitting a newer state to prove that he is honest and knows a newer valid state.
If the other participant cannot do this, he loses the dispute and the first state is
accepted as final. The disputed channel is then *settled* and therefore closed.

.. note::

The `challengeDuration` is part of the `channel proposal`_ and is agreed upon by
both participants.

.. _channel proposal: https://pkg.go.dev/perun.network/go-perun/client#NewLedgerChannelProposal
14 changes: 14 additions & 0 deletions source/go-perun/tutorial/channels/index.rst
@@ -0,0 +1,14 @@
Channels
========

With all the components explained, we can now look at channels.
The following pages will explain how to open, update and close a channel.
Disputes will only be outlined as they are not focused on in this tutorial.

.. toctree::
:maxdepth: 1

opening
updating
closing
disputes
51 changes: 51 additions & 0 deletions source/go-perun/tutorial/channels/opening.rst
@@ -0,0 +1,51 @@
Opening
=======

Opening a state channel works by defining the initial asset allocation, setting the
channel parameters, creating a proposal and sending that proposal to all participants.
The channel is open after all participants accept the proposal and finish the on-chain funding.

It looks like this:

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 38-68

The `ProposeChannel` call blocks until *Alice* either accepted or rejected the channel
and funded it.

.. warning::

The channel that is returned by `ProposeChannel` should only be used to retrieve
its *id*.

HandleProposal
^^^^^^^^^^^^^^

An example Proposal handler looks like this:

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 70-89

You can add additional check logic here but in our simple use case we always accept
incoming proposals. After the channel is open, both participants will have their `NewChannel` callback called.

.. warning:: The `Channel` that `ProposalResponder.Accept`_ returns should only be used to retrieve its *ID*.

NewChannel
^^^^^^^^^^

*go-perun* expects this handler to finish quickly. Use *go* routines if you want to do
time-intensive tasks. You should also start the :ref:`watcher <the-watcher>` as shown below:

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 91-100

.. note::

Starting the watcher is not mandatory but strongly advised. *go-perun* can otherwise
not react to malicious behavior of other participants.

.. _ProposalResponder.Accept: https://pkg.go.dev/perun.network/go-perun/client#ProposalResponder.Accept
40 changes: 40 additions & 0 deletions source/go-perun/tutorial/channels/updating.rst
@@ -0,0 +1,40 @@
.. _updating:

Updating
========

We now give the `node` an `updateChannel` function to update the channel by sending Ether from
*Bob* to *Alice*.

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 102-115
:emphasize-lines: 8,9

In the highlighted lines you can see that we use index `0` for the `Balances` slice.
This means that we access the funds of the first asset. Since there is only one asset,
this is the only entry. We also :ref:`finalize <finalizing>` the channel, which will be important later and implies that it can not be updated again.

.. note::

*go-perun* checks that an update preserves the sum of each asset.

HandleUpdate
^^^^^^^^^^^^

The update that was initiated with the `updateChannel` function above would then arrive
at the `HandleUpdate` function of the other participant. In `HandleUpdate` you can decide on whether you want to accept the incoming update or not.
This example function accepts all updates:

.. literalinclude:: ../go-perun-test/node.go
:language: go
:lines: 117-124

An update can also be rejected with a reason. This starts the :ref:`dispute process <disputes>`.

.. code-block:: go
responder.Reject(ctx, "do not like")
.. _UpdateBy: https://pkg.go.dev/perun.network/go-perun/client#Channel.UpdateBy
.. _Update: https://pkg.go.dev/perun.network/go-perun/client#Channel.Update
52 changes: 52 additions & 0 deletions source/go-perun/tutorial/getting-started.rst
@@ -0,0 +1,52 @@
.. _Getting Started:

Getting Started
===============

First we setup some dependencies: Golang and ganache-cli. But no worries, we will walk you through it 😌

Tutorial Source Code
--------------------

To make it easier to follow the tutorial, you may already clone the source code repository:

.. code-block:: bash
cd $GOPATH/src
git clone https://github.com/perun-network/perun-tutorial.git
cd perun-tutorial/go-perun-test
# Initialize Golang
go mod tidy
Running the code is the :ref:`last part <run-the-app>`, but feel free to try it out first.

Golang
------

The tutorial source code will be written in *Golang*.
The official *Golang* installation guide can be found `here <https://golang.org/doc/install>`_.
Restart your shell and check the installation by running::

go version

Ganache CLI
-----------

For the purpose of this tutorial we will use `ganache-cli <https://github.com/trufflesuite/ganache-cli>`_ for providing us with a local Ethereum blockchain for testing our application locally.
Install ganache-cli by following `the instructions on the web page <https://github.com/trufflesuite/ganache-cli#installation>`_.
You can check if ganache-cli is installed by running::

ganache-cli --version

When we run our local blockchain, we usually configure accounts that we want to prefund.
We will do this by specifying a mnemonic.
A mnemonic is a sequence of randomly chosen words from which account secret keys can be derived.
For the purpose of this tutorial we will use the following mnemonic::

"pistol kiwi shrug future ozone ostrich match remove crucial oblige cream critic"

.. warning::
Always keep your *mnemonic* private. Do not use the example *mnemonic*
with real funds.


42 changes: 42 additions & 0 deletions source/go-perun/tutorial/go-perun-test/channel.go
@@ -0,0 +1,42 @@
// Copyright (c) 2021, PolyCrypt GmbH, Germany. All rights reserved.
// This file is part of perun-tutorial. Use of this source code is
// governed by the Apache 2.0 license that can be found in the LICENSE file.

package main

import (
"fmt"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"

ethchannel "perun.network/go-perun/backend/ethereum/channel"
ethwallet "perun.network/go-perun/backend/ethereum/wallet"
"perun.network/go-perun/channel"
"perun.network/go-perun/wallet"
"perun.network/go-perun/wire/net"
"perun.network/go-perun/wire/net/simple"
)

func setupFunder(contractBackend ethchannel.ContractBackend, account accounts.Account, assetHolder common.Address) channel.Funder {
ethDepositor := new(ethchannel.ETHDepositor)
accounts := map[ethchannel.Asset]accounts.Account{ethwallet.Address(assetHolder): account}
depositors := map[ethchannel.Asset]ethchannel.Depositor{ethwallet.Address(assetHolder): ethDepositor}
return ethchannel.NewFunder(contractBackend, accounts, depositors)
}

func setupNetwork(role Role, account wallet.Account) (listener net.Listener, bus *net.Bus, err error) {
dialer := simple.NewTCPDialer(10 * time.Second)
dialer.Register(cfg.addrs[1-role], cfg.hosts[1-role])

listener, err = simple.NewTCPListener(cfg.hosts[role])
fmt.Printf("Setting up listener for %s\n", cfg.hosts[role])
if err != nil {
err = fmt.Errorf("creating listener: %w", err)
return
}

bus = net.NewBus(account, dialer)
return
}

0 comments on commit 5127ec3

Please sign in to comment.