Skip to content

Commit

Permalink
update payment-channel-dot
Browse files Browse the repository at this point in the history
Signed-off-by: Minh Huy Tran <huy@perun.network>
  • Loading branch information
NhoxxKienn committed Apr 18, 2024
1 parent f9e43d3 commit ba555aa
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 491 deletions.
18 changes: 15 additions & 3 deletions payment-channel-dot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@ This demo connects to our [Pallet] that runs on a [Polkadot Node] by using our [

## Example Walkthrough

In a first terminal, start a development [Polkadot Node]:
In another terminal, clone and start a local [Polkadot Node]:

**WARNING**: only working with a newer version of Polkadot Node from branch `update_substrate`

To build the Polkadot Node, you need [Rust Developer Environment].

```sh
docker run --rm -it -p 9944:9944 ghcr.io/perun-network/polkadot-test-node
git clone git@github.com:perun-network/perun-polkadot-node.git

cd perun-polkadot-node/node

cargo run --release -- --dev --tmp
```

Wait around 10 seconds for the Node to start-up.

In a second terminal, run the demo
```sh
cd payment-channel-dot/
Expand All @@ -18,4 +29,5 @@ go run .
<!-- Links -->
[Pallet]: https://github.com/perun-network/perun-polkadot-pallet/
[Polkadot Node]: https://github.com/perun-network/perun-polkadot-node
[Polkadot Backend]: https://github.com/perun-network/perun-polkadot-backend
[Polkadot Backend]: https://github.com/perun-network/perun-polkadot-backend
[Rust Developer Environment]: https://github.com/perun-network/perun-polkadot-node/blob/update_substrate/node/doc/rust-setup.md
60 changes: 60 additions & 0 deletions payment-channel-dot/client/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2022 - See NOTICE file for copyright holders.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package client

import (
wallet "github.com/perun-network/perun-polkadot-backend/wallet/sr25519"

"perun.network/go-perun/wire"
)

// Address is a wrapper for wallet.Address.
type Address struct {
*wallet.Address
}

// NewAddress returns a new address.
func NewAddress() *Address {
return &Address{}
}

// Equal returns whether the two addresses are equal.
func (a Address) Equal(b wire.Address) bool {
bTyped, ok := b.(*Address)
if !ok {
panic("wrong type")
}
return a.Address.Equal(bTyped.Address)
}

// Cmp compares the byte representation of two addresses. For `a.Cmp(b)`
// returns -1 if a < b, 0 if a == b, 1 if a > b.
func (a Address) Cmp(b wire.Address) int {
bTyped, ok := b.(*Address)
if !ok {
panic("wrong type")
}
return a.Address.Cmp(bTyped.Address)
}

// MarshalBinay returns the binary representation of the address.
func (a Address) MarshalBinay() ([]byte, error) {
return a.Address.MarshalBinary()
}

// UnmarshalBinary decodes the binary representation of the address.
func (a *Address) UnmarshalBinary(data []byte) error {
return a.Address.UnmarshalBinary(data)
}
10 changes: 4 additions & 6 deletions payment-channel-dot/client/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,31 @@ func newPaymentChannel(ch *client.Channel, currency channel.Asset) *PaymentChann
func (c PaymentChannel) SendPayment(amount float64) {
// Transfer the given amount from us to peer.
// Use UpdateBy to update the channel state.
err := c.ch.UpdateBy(context.TODO(), func(state *channel.State) error { // We use context.TODO to keep the code simple.
err := c.ch.Update(context.TODO(), func(state *channel.State) { // We use context.TODO to keep the code simple.
plancks := DotToPlanck(big.NewFloat(amount))
actor := c.ch.Idx()
peer := 1 - actor
state.Allocation.TransferBalance(actor, peer, c.currency, plancks)
return nil
})
if err != nil {
panic(err) // We panic on error to keep the code simple.
}
}

// Settle settles the payment channel and withdraws the funds.
func (c PaymentChannel) Settle() {
func (c PaymentChannel) Settle(secondary bool) {
// Finalize the channel to enable fast settlement.
if !c.ch.State().IsFinal {
err := c.ch.UpdateBy(context.TODO(), func(state *channel.State) error {
err := c.ch.Update(context.TODO(), func(state *channel.State) {
state.IsFinal = true
return nil
})
if err != nil {
panic(err)
}
}

// Settle concludes the channel and withdraws the funds.
err := c.ch.Settle(context.TODO(), false)
err := c.ch.Settle(context.TODO(), secondary)
if err != nil {
panic(err)
}
Expand Down
26 changes: 15 additions & 11 deletions payment-channel-dot/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ package client
import (
"context"
"fmt"
"github.com/centrifuge/go-substrate-rpc-client/v3/types"
"math/big"

"github.com/centrifuge/go-substrate-rpc-client/v4/types"
dotchannel "github.com/perun-network/perun-polkadot-backend/channel"
"github.com/perun-network/perun-polkadot-backend/channel/pallet"
dot "github.com/perun-network/perun-polkadot-backend/pkg/substrate"
dotwallet "github.com/perun-network/perun-polkadot-backend/wallet/sr25519"
"math/big"
"perun.network/go-perun/channel"
"perun.network/go-perun/client"
"perun.network/go-perun/wallet"
Expand All @@ -35,8 +36,9 @@ import (

// PaymentClient is a payment channel client.
type PaymentClient struct {
perunClient *client.Client // The core Perun client.
account wallet.Address // The account we use for on-chain and off-chain transactions.
perunClient *client.Client // The core Perun client.
account wallet.Account // The account we use for on-chain and off-chain transactions.
waddress wire.Address
currency channel.Asset // The currency we expect to get paid in.
channels chan *PaymentChannel // Accepted payment channels.
}
Expand All @@ -47,11 +49,11 @@ func SetupPaymentClient(
w *dotwallet.Wallet, // w is the wallet used to resolve addresses to accounts for channels.
acc wallet.Account, // acc is the account to be used for signing transactions.
nodeURL string, // nodeURL is the URL of the blockchain node.
networkId dot.NetworkID, // networkId is the identifier of the blockchain.
networkID dot.NetworkID, // networkId is the identifier of the blockchain.
queryDepth types.BlockNumber, // queryDepth is the number of blocks being evaluated when looking for events.
) (*PaymentClient, error) {
// Connect to backend.
api, err := dot.NewAPI(nodeURL, networkId)
api, err := dot.NewAPI(nodeURL, networkID)
if err != nil {
panic(err)
}
Expand All @@ -68,7 +70,8 @@ func SetupPaymentClient(
}

// Setup Perun client.
waddr := dotwallet.AsAddr(acc.Address())
waddr := &Address{Address: dotwallet.AsAddr(acc.Address())}

perunClient, err := client.New(waddr, bus, funder, adj, w, watcher)
if err != nil {
return nil, errors.WithMessage(err, "creating client")
Expand All @@ -77,8 +80,9 @@ func SetupPaymentClient(
// Create client and start request handler.
c := &PaymentClient{
perunClient: perunClient,
account: waddr,
currency: &dotchannel.Asset,
account: acc,
waddress: waddr,
currency: dotchannel.Asset,
channels: make(chan *PaymentChannel, 1),
}

Expand All @@ -91,7 +95,7 @@ func (c *PaymentClient) OpenChannel(peer wire.Address, amount float64) *PaymentC
// We define the channel participants. The proposer has always index 0. Here
// we use the on-chain addresses as off-chain addresses, but we could also
// use different ones.
participants := []wire.Address{c.account, peer}
participants := []wire.Address{c.WireAddress(), peer}

// We create an initial allocation which defines the starting balances.
initBal := DotToPlanck(big.NewFloat(amount))
Expand All @@ -105,7 +109,7 @@ func (c *PaymentClient) OpenChannel(peer wire.Address, amount float64) *PaymentC
challengeDuration := uint64(10) // On-chain challenge duration in seconds.
proposal, err := client.NewLedgerChannelProposal(
challengeDuration,
c.account,
c.account.Address(),
initAlloc,
participants,
)
Expand Down
15 changes: 8 additions & 7 deletions payment-channel-dot/client/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@ import (
"context"
"fmt"
"log"

"perun.network/go-perun/channel"
"perun.network/go-perun/client"
)

// HandleProposal is the callback for incoming channel proposals.
func (c *PaymentClient) HandleProposal(p client.ChannelProposal, r *client.ProposalResponder) {
lcp, err := func() (*client.LedgerChannelProposal, error) {
lcp, err := func() (*client.LedgerChannelProposalMsg, error) {
// Ensure that we got a ledger channel proposal.
lcp, ok := p.(*client.LedgerChannelProposal)
lcp, ok := p.(*client.LedgerChannelProposalMsg)
if !ok {
return nil, fmt.Errorf("Invalid proposal type: %T\n", p)
return nil, fmt.Errorf("invalid proposal type: %T", p)
}

// Check that we have the correct number of participants.
Expand All @@ -38,8 +39,8 @@ func (c *PaymentClient) HandleProposal(p client.ChannelProposal, r *client.Propo

// Check that the channel has the expected assets and funding balances.
const assetIdx, clientIdx, peerIdx = 0, 0, 1
if err := channel.AssetsAssertEqual(lcp.InitBals.Assets, []channel.Asset{c.currency}); err != nil {
return nil, fmt.Errorf("Invalid assets: %v\n", err)
if err := channel.AssertAssetsEqual(lcp.InitBals.Assets, []channel.Asset{c.currency}); err != nil {
return nil, fmt.Errorf("invalid assets: %v", err)
} else if lcp.FundingAgreement[assetIdx][clientIdx].Cmp(lcp.FundingAgreement[assetIdx][peerIdx]) != 0 {
return nil, fmt.Errorf("Invalid funding balance")
}
Expand All @@ -51,7 +52,7 @@ func (c *PaymentClient) HandleProposal(p client.ChannelProposal, r *client.Propo

// Create a channel accept message and send it.
accept := lcp.Accept(
c.account, // The account we use in the channel.
c.account.Address(), // The account we use in the channel.
client.WithRandomNonce(), // Our share of the channel nonce.
)
ch, err := r.Accept(context.TODO(), accept)
Expand All @@ -71,7 +72,7 @@ func (c *PaymentClient) HandleProposal(p client.ChannelProposal, r *client.Propo
func (c *PaymentClient) HandleUpdate(cur *channel.State, next client.ChannelUpdate, r *client.UpdateResponder) {
// We accept every update that increases our balance.
err := func() error {
err := channel.AssetsAssertEqual(cur.Assets, next.State.Assets)
err := channel.AssertAssetsEqual(cur.Assets, next.State.Assets)
if err != nil {
return fmt.Errorf("Invalid assets: %v", err)
}
Expand Down
7 changes: 4 additions & 3 deletions payment-channel-dot/client/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@
package client

import (
dot "github.com/perun-network/perun-polkadot-backend/pkg/substrate"
"math/big"

dot "github.com/perun-network/perun-polkadot-backend/pkg/substrate"
"perun.network/go-perun/wallet"
"perun.network/go-perun/wire"
)

// WalletAddress returns the wallet address of the client.
func (c *PaymentClient) WalletAddress() wallet.Address {
return c.account
return c.account.Address()
}

// WireAddress returns the wire address of the client.
func (c *PaymentClient) WireAddress() wire.Address {
return c.account
return c.waddress
}

// DotToPlanck converts a given amount in Dot to Planck.
Expand Down
39 changes: 22 additions & 17 deletions payment-channel-dot/go.mod
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
module perun.network/perun-examples/payment-channel

go 1.20
go 1.21

toolchain go1.21.4

require (
github.com/centrifuge/go-substrate-rpc-client/v3 v3.0.2
github.com/perun-network/perun-polkadot-backend v0.0.0-20211122151932-1cf5c72ae46f
github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.1
github.com/perun-network/perun-polkadot-backend v0.2.1-0.20240411100708-029d9632b748
github.com/pkg/errors v0.9.1
perun.network/go-perun v0.8.0
perun.network/go-perun v0.10.6
)

require (
github.com/ChainSafe/go-schnorrkel v0.0.0-20210318173838-ccb5cd955283 // indirect
github.com/ChainSafe/go-schnorrkel v1.1.0 // indirect
github.com/btcsuite/btcd v0.21.0-beta // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/decred/base58 v1.0.3 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/base58 v1.0.4 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.10.12 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum/go-ethereum v1.10.20 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect
github.com/pierrec/xxHash v0.1.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/cors v1.8.0 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/stretchr/testify v1.7.2 // indirect
github.com/vedhavyas/go-subkey v1.0.2 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
github.com/vedhavyas/go-subkey/v2 v2.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/sys v0.6.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 // indirect
)
Loading

0 comments on commit ba555aa

Please sign in to comment.