perun

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2020 License: Apache-2.0 Imports: 11 Imported by: 0

README

Perun Node - Go implementation join the chat

Develop Master
CircleCI CircleCI

Perun is an open source project that aims to increase blockchain transaction throughput by using just a handful of main chain transactions to move an entire peer-to-peer network of activity off the main chain. After an initial setup of a set of basic transaction channels, this network lets any participant transact with any other participant via virtual channels which do not require additional on-chain setup. We do this by implementing the Perun protocol, which has been formally proven to allow for secure off-chain transactions.

Project Status

At the moment the perun-node is neither ready for production nor does it implement the complete perun protocol yet. But with basic features available, the project is at a stage where you can try it out and start to get involved.

This is a complete re-implementation of the previous version (available under the previous name of the project: dst-go) in branch legacy/master. This version builds on top of the go-perun SDK that implements a state channel client based on perun protocol. See Description for more details.

Description

The perun-node is multi-user state channel node that can be used for opening, transacting on and closing state channels. It builds on the state channel client implemented by go-perun and implements the following functionalities:

  1. Payment App: For using perun protocol to establish and use bi-directional payment channels.
  2. Contacts Provider: For the user to define a list of known participants in the off-chain network.
  3. Key management: For managing the cryptographic keys of the user.
  4. User session: For allowing multiple users to use a single node, each with a dedicated key manager and contacts provider.
  5. User API interface: For the user to interact with the perun-node.

The current version provides the following features:

Feature Implementation
Blockchain Backend Ethereum
Key management Ethereum keystore
Contacts Provider YAML file
User API Two Party Payment API
User API Adapter gRPC
Persistence LevelDB

This project currently contains two executable packages located in the cmd directory.

  • perunnode: An app for starting a running instance of perun node. It can also generate configuration artifacts for trying out the node.

  • perunnodecli is an app with interactive CLI interface that serves two purposes:

    • easy way to try out payment channel API.
    • reference implementation for using the generated grpc client stubs for payment channel API.

For detailed information on the features offered by these two applications and steps on how to try them out, see the Trying It Out article.

Getting Started

Install the following pre-requisites.

1. Go (v1.14 or later).
2. ganache-cli (v6.9.1 or later).

Clone the project and sync the dependencies:

git clone https://github.com/hyperledger-labs/perun-node.git
cd perun-node
go mod tidy

Start the ganache-cli node for running integration tests:

# These funded accounts will be used in tests. "-b 1" configures the
# ganache-cli node to mine one block every second. It is required as our
# contracts use blockchain based timeout for settling a state channel on-chain.
ganache-cli -b 1 \
--account="0x1fedd636dbc7e8d41a0622a2040b86fea8842cef9d4aa4c582aad00465b7acff,100000000000000000000" \
--account="0xb0309c60b4622d3071fad3e16c2ce4d0b1e7758316c187754f4dd0cfb44ceb33,100000000000000000000"

Run the linter and tests from the project root directory:

# Lint
golangci-lint run ./...

# Test
go test -tags=integration -count=1 ./...

# Build peurnnode and perunnodecli binaries
make

License

perun-node is open-sourced under the Apache-2.0 license. See the LICENSE file for details.

Documentation

Overview

Package perun defines the different types and backends in this project. Implementation of functionalities of the types and packges will be done in the corresponding packages.

Index

Constants

View Source
const OwnAlias = "self"

OwnAlias is the alias for the entry of the user's own peer details. It will be used when translating addresses in incoming messages / proposals to aliases.

Variables

View Source
var (
	ErrUnknownSessionID  = APIError("No session corresponding to the specified ID")
	ErrUnknownProposalID = APIError("No channel proposal corresponding to the specified ID")
	ErrUnknownChID       = APIError("No channel corresponding to the specified ID")
	ErrUnknownAlias      = APIError("No peer corresponding to the specified ID was found in contacts")
	ErrUnknownUpdateID   = APIError("No response was expected for the given channel update ID")

	ErrUnsupportedCurrency     = APIError("Currency not supported by this node instance")
	ErrUnsupportedContactsType = APIError("Contacts type not supported by this node instance")
	ErrUnsupportedCommType     = APIError("Communication protocol not supported by this node instance")

	ErrInsufficientBal     = APIError("Insufficient balance in sender account")
	ErrInvalidAmount       = APIError("Invalid amount string")
	ErrMissingBalance      = APIError("Missing balance")
	ErrInvalidConfig       = APIError("Invalid configuration detected")
	ErrInvalidOffChainAddr = APIError("Invalid off-chain address string")
	ErrInvalidPayee        = APIError("Invalid payee, no such participant in the channel")

	ErrNoActiveSub      = APIError("No active subscription was found")
	ErrSubAlreadyExists = APIError("A subscription for this context already exists")

	ErrSessionClosed      = APIError("Session is closed")
	ErrChFinalized        = APIError("Channel is finalized")
	ErrChClosed           = APIError("Channel is closed")
	ErrPeerAliasInUse     = APIError("Alias already used by another peer in the contacts")
	ErrPeerExists         = APIError("Peer already available in the contacts provider")
	ErrRespTimeoutExpired = APIError("Response to the notification was sent after the timeout has expired")
	ErrPeerRejected       = APIError("The request was rejected by peer")

	ErrOpenCh         = APIError("Session cannot be closed (without force option) as there are open channels")
	ErrInternalServer = APIError("Internal Server Error")
)

Sentinal Error values that are relevant for the end user of the node.

Functions

func GetAPIError

func GetAPIError(err error) error

GetAPIError returns the APIError contained in err if err is an APIError. If not, it returns ErrInternalServer API error.

Types

type APIError

type APIError string

APIError represents the errors that will be communicated via the user API.

func (APIError) Error

func (e APIError) Error() string

type App

type App struct {
	Def  pchannel.App
	Data pchannel.Data
}

App represents the app definition and the corresponding app data for a channel.

type BalInfo

type BalInfo struct {
	Currency string   // Currency interpreter used to interpret the amounts in the balance.
	Parts    []string // List of aliases of channel participants.
	Bal      []string // Amounts held by each participant in this channel for the given currency.
}

BalInfo represents the Balance information of the channel participants. A valid BalInfo should meet the following conditions (will be validated before using the struct):

  1. Lengths of Parts list and Balance list are equal.
  2. All entries in Parts list are unique.
  3. Parts list has an entry "self", that represents the user of the session.
  4. No amount in Balance must be negative.

type ChAPI added in v0.4.0

type ChAPI interface {
	// Methods for reading the channel information is doesn't change.
	// These APIs don't use mutex lock.
	ID() string
	Currency() string
	Parts() []string
	ChallengeDurSecs() uint64

	// Methods to trasact on, close the channel and read its state.
	// These APIs use a mutex lock.
	SendChUpdate(context.Context, StateUpdater) (ChInfo, error)
	SubChUpdates(ChUpdateNotifier) error
	UnsubChUpdates() error
	RespondChUpdate(context.Context, string, bool) (ChInfo, error)
	GetChInfo() ChInfo
	Close(context.Context) (ChInfo, error)
}

ChAPI represents the APIs that can be accessed in the context of a perun channel. First a channel has to be initialized using the SessionAPI. The channel can then be used send and receive updates.

type ChClient added in v0.4.0

type ChClient interface {
	Registerer
	ProposeChannel(context.Context, pclient.ChannelProposal) (*pclient.Channel, error)
	Handle(pclient.ProposalHandler, pclient.UpdateHandler)
	Channel(pchannel.ID) (*pclient.Channel, error)
	Close() error

	EnablePersistence(ppersistence.PersistRestorer)
	OnNewChannel(handler func(*pclient.Channel))
	Restore(context.Context) error
	RestoreChs(func(*pclient.Channel)) error

	Log() pLog.Logger
}

ChClient allows the user to establish off-chain channels and transact on these channels.

It allows the user to enable persistence, where all data pertaining to the lifecycle of a channel is persisted continuously. When it is enabled, the channel client can be stopped at any point of time and resumed later.

However, the channel client is not responsible if any channel the user was participating in was closed with a wrong state when the channel client was not running. Hence it is highly recommended not to stop the channel client if there are open channels.

type ChCloseNotif

type ChCloseNotif struct {
	ClosedChInfo ChInfo
	Error        string
}

ChCloseNotif represents the parameters sent in a channel close notifications.

type ChCloseNotifier

type ChCloseNotifier func(ChCloseNotif)

ChCloseNotifier is the notifier function that is used for sending channel close notifications.

type ChInfo added in v0.4.0

type ChInfo struct {
	ChID string
	// Represents the amount held by each participant in the channel.
	BalInfo BalInfo
	// App used in the channel.
	App App
	// Current Version Number for the channel. This will be zero when a channel is opened and will be incremented
	// during each update. When registering the state on-chain, if different participants register states with
	// different versions, channel will be settled according to the state with highest version number.
	Version string
}

ChInfo represents the info regarding a channel that will be sent to the user.

type ChProposalNotif

type ChProposalNotif struct {
	ProposalID       string
	OpeningBalInfo   BalInfo
	App              App
	ChallengeDurSecs uint64
	Expiry           int64
}

ChProposalNotif represents the parameters sent in a channel proposal notifications.

type ChProposalNotifier

type ChProposalNotifier func(ChProposalNotif)

ChProposalNotifier is the notifier function that is used for sending channel proposal notifications.

type ChUpdateNotif

type ChUpdateNotif struct {
	// UpdateID denotes the unique ID for this update. It is derived from the channel ID and version number.
	UpdateID       string
	CurrChInfo     ChInfo
	ProposedChInfo ChInfo

	Type ChUpdateType

	// It is with reference to the system clock on the computer running the perun-node.
	// Time (in unix timestamp) before which response to this notification should be sent.
	//
	// It is 0, when no response is expected.
	Expiry int64

	// Error represents any error encountered while processing incoming updates or
	// while a channel is closed by the watcher..
	// When this is non empty, expiry will also be zero and no response is expected
	Error string
}

ChUpdateNotif represents the parameters sent in a channel update notification. The update can be of two types 1. Regular update proposed by the peer to progress the offchain state of the channel. 2. Closing update when a channel is closed, balance is settled on the blockchain and the amount corresponding to this user is withdrawn.

The two types of updates can be differentiated using the status field, which is "open" or "final" for a regular update and "closed" for a closing update.

type ChUpdateNotifier

type ChUpdateNotifier func(ChUpdateNotif)

ChUpdateNotifier is the notifier function that is used for sending channel update notifications.

type ChUpdateType added in v0.4.0

type ChUpdateType uint8

ChUpdateType is the type of channel update. It can have three values: "open", "final" and "closed".

const (
	ChUpdateTypeOpen ChUpdateType = iota
	ChUpdateTypeFinal
	ChUpdateTypeClosed
)

Enumeration of values for ChUpdateType: Open: If accepted, channel will be updated and it will remain in open for off-chain tx. Final: If accepted, channel will be updated and closed (settled on-chain and amount withdrawn). Closed: Channel has been closed (settled on-chain and amount withdrawn).

type ChainBackend

type ChainBackend interface {
	DeployAdjudicator(onChainAddr pwallet.Address) (adjAddr pwallet.Address, _ error)
	DeployAsset(adjAddr, onChainAddr pwallet.Address) (assetAddr pwallet.Address, _ error)
	ValidateContracts(adjAddr, assetAddr pwallet.Address) error
	NewFunder(assetAddr, onChainAddr pwallet.Address) pchannel.Funder
	NewAdjudicator(adjAddr, receiverAddr pwallet.Address) pchannel.Adjudicator
}

ChainBackend wraps the methods required for instantiating and using components for making on-chain transactions and reading on-chain values on a specific blockchain platform. The timeout for on-chain transaction should be implemented by the corresponding backend. It is up to the implementation to make the value user configurable.

It defines methods for deploying contracts; validating deployed contracts and instantiating a funder, adjudicator.

type CommBackend

type CommBackend interface {
	// Returns a listener that can listen for incoming messages at the specified address.
	NewListener(address string) (pnet.Listener, error)

	// Returns a dialer that can dial for new outgoing connections.
	// If timeout is zero, program will use no timeout, but standard OS timeouts may still apply.
	NewDialer() Dialer
}

CommBackend defines the set of methods required for initializing components required for off-chain communication. This can be protocols such as tcp, websockets, MQTT.

type Contacts

type Contacts interface {
	ContactsReader
	Write(alias string, p Peer) error
	Delete(alias string) error
	UpdateStorage() error
}

Contacts represents a cached list of contacts backed by a storage. Read, Write and Delete methods act on the cache. The state of cached list can be written to the storage by using the UpdateStorage method.

type ContactsReader

type ContactsReader interface {
	ReadByAlias(alias string) (p Peer, contains bool)
	ReadByOffChainAddr(offChainAddr pwire.Address) (p Peer, contains bool)
}

ContactsReader represents a read only cached list of contacts.

type Credential

type Credential struct {
	Addr     pwallet.Address
	Wallet   pwallet.Wallet
	Keystore string
	Password string
}

Credential represents the parameters required to access the keys and make signatures for a given address.

type Currency

type Currency interface {
	Parse(string) (*big.Int, error)
	Print(*big.Int) string
}

Currency represents a parser that can convert between string representation of a currency and its equivalent value in base unit represented as a big integer.

type Dialer

type Dialer interface {
	pnet.Dialer
	Registerer
}

Dialer extends net.Dialer with Registerer interface.

type NodeAPI

type NodeAPI interface {
	Time() int64
	GetConfig() NodeConfig
	Help() []string
	OpenSession(configFile string) (string, []ChInfo, error)

	// This function is used internally to get a SessionAPI instance.
	// Should not be exposed via user API.
	GetSession(string) (SessionAPI, error)
}

NodeAPI represents the APIs that can be accessed in the context of a perun node. Multiple sessions can be opened in a single node. Each instance will have a dedicated keystore and contacts provider.

type NodeConfig

type NodeConfig struct {
	// User configurable values.
	LogLevel         string        // LogLevel represents the log level for the node and all derived loggers.
	LogFile          string        // LogFile represents the file to write logs. Empty string represents stdout.
	ChainURL         string        // Address of the default blockchain node used by the perun node.
	Adjudicator      string        // Address of the default Adjudicator contract used by the perun node.
	Asset            string        // Address of the default Asset Holder contract used by the perun node.
	ChainConnTimeout time.Duration // Timeout for connecting to blockchain node.
	OnChainTxTimeout time.Duration // Timeout to wait for confirmation of on-chain tx.
	ResponseTimeout  time.Duration // Timeout to wait for a response from the peer / user.

	// Hard coded values. See cmd/perunnode/run.go.
	CommTypes            []string // Communication protocols supported by the node for off-chain communication.
	ContactTypes         []string // Contacts Provider backends supported by the node.
	CurrencyInterpreters []string // Currencies Interpreters supported by the node.

}

NodeConfig represents the configurable parameters of a perun node.

type Peer

type Peer struct {
	// Name assigned by user for referring to this peer in API requests to the node.
	// It is unique within a session on the node.
	Alias string `yaml:"alias"`

	// Permanent identity used for authenticating the peer in the off-chain network.
	OffChainAddr pwire.Address `yaml:"-"`
	// This field holds the string value of address for easy marshaling / unmarshaling.
	OffChainAddrString string `yaml:"offchain_address"`

	// Address for off-chain communication.
	CommAddr string `yaml:"comm_address"`
	// Type of off-chain communication protocol.
	CommType string `yaml:"comm_type"`
}

Peer represents any participant in the off-chain network that the user wants to transact with.

type Registerer

type Registerer interface {
	Register(offChainAddr pwire.Address, commAddr string)
}

Registerer is used to register the commAddr corresponding to an offChainAddr to the wire.Bus in runtime.

type Session

type Session struct {
	ID   string // ID uniquely identifies a session instance.
	User User

	ChClient ChClient
}

Session provides a context for the user to interact with a node. It manages user data (such as IDs, contacts), and channel client.

Once established, a user can establish and transact on state channels. All the channels within a session will use the same type and version of communication and state channel protocol. If a user desires to use multiple types or versions of any protocol, it should request a separate session for each combination of type and version of those.

type SessionAPI

type SessionAPI interface {
	ID() string
	AddContact(Peer) error
	GetContact(alias string) (Peer, error)
	OpenCh(context.Context, BalInfo, App, uint64) (ChInfo, error)
	GetChsInfo() []ChInfo
	SubChProposals(ChProposalNotifier) error
	UnsubChProposals() error
	RespondChProposal(context.Context, string, bool) (ChInfo, error)
	Close(force bool) ([]ChInfo, error)

	// This function is used internally to get a ChAPI instance.
	// Should not be exposed via user API.
	GetCh(string) (ChAPI, error)
}

SessionAPI represents the APIs that can be accessed in the context of a perun node. First a session has to be instantiated using the NodeAPI. The session can then be used open channels and accept channel proposals.

type StateUpdater

type StateUpdater func(*pchannel.State)

StateUpdater function is the function that will be used for applying state updates.

type User

type User struct {
	Peer

	OnChain  Credential // Account for funding the channel and the on-chain transactions.
	OffChain Credential // Account (corresponding to off-chain address) used for signing authentication messages.

	// List of participant addresses for this user in each open channel.
	// OffChain credential is used for managing all these accounts.
	PartAddrs []pwallet.Address
}

User represents a participant in the off-chain network that uses a session on this node for sending transactions.

type WalletBackend

type WalletBackend interface {
	ParseAddr(string) (pwallet.Address, error)
	NewWallet(keystore string, password string) (pwallet.Wallet, error)
	UnlockAccount(pwallet.Wallet, pwallet.Address) (pwallet.Account, error)
}

WalletBackend wraps the methods for instantiating wallets and accounts that are specific to a blockchain platform.

type WireBus

type WireBus interface {
	pwire.Bus
	Close() error
}

WireBus is an extension of the wire.Bus interface in go-perun to include a "Close" method. pwire.Bus (in go-perun) is a central message bus over which all clients of a channel network communicate. It is used as the transport layer abstraction for the ChClient.

Directories

Path Synopsis
api
grpc
Package grpc implements a grpc payment API server.
Package grpc implements a grpc payment API server.
grpc/pb
Package pb contains proto3 definitions for user API and the corresponding generated code for grpc server and client.
Package pb contains proto3 definitions for user API and the corresponding generated code for grpc server and client.
app
payment
Package payment implements a payment API that can used with the generic session and channel APIs to open, use and close payment channels.
Package payment implements a payment API that can used with the generic session and channel APIs to open, use and close payment channels.
blockchain
ethereum
Package ethereum provides on-chain transaction backend and wallet backend for the ethereum blockchain platform.
Package ethereum provides on-chain transaction backend and wallet backend for the ethereum blockchain platform.
ethereum/ethereumtest
Package ethereumtest provides test helpers for using ethereum backend in test.
Package ethereumtest provides test helpers for using ethereum backend in test.
ethereum/internal
Package internal implements the ethereum related backend functionality.
Package internal implements the ethereum related backend functionality.
Package client provides an abstraction over the channel client used for running the off-chain network implemented by go-perun project.
Package client provides an abstraction over the channel client used for running the off-chain network implemented by go-perun project.
cmd
perunnode command
perunnodecli command
comm
tcp
Package tcp implements the off-chain communication backend to initialize adapters for for tcp communication protocol.
Package tcp implements the off-chain communication backend to initialize adapters for for tcp communication protocol.
contacts
contactstest
Package contactstest provides a helper functions to create contacts file from a list of peers for use in tests.
Package contactstest provides a helper functions to create contacts file from a list of peers for use in tests.
contactsyaml
Package contactsyaml implements contacts provider to access contacts stored in a yaml file.
Package contactsyaml implements contacts provider to access contacts stored in a yaml file.
Package currency implements conversion backends for different currencies used in a channel.
Package currency implements conversion backends for different currencies used in a channel.
internal
Package log implements a simple logger that directly uses the logrus library.
Package log implements a simple logger that directly uses the logrus library.
Package node implements the node API.
Package node implements the node API.
Package session implements a session to which a user can attach his or her credentials.
Package session implements a session to which a user can attach his or her credentials.
sessiontest
Package sessiontest implements test helpers for functionalities defined in session.
Package sessiontest implements test helpers for functionalities defined in session.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL