Skip to content

Commit

Permalink
Create app id type (hyperledger-labs#378)
Browse files Browse the repository at this point in the history
* Create app id type

Signed-off-by: Matthias Geihs <[email protected]>

* Lint

Signed-off-by: Matthias Geihs <[email protected]>

* Payment App: Rename Addr to ID

Signed-off-by: Matthias Geihs <[email protected]>

* appID.Key: Remove comment

Signed-off-by: Matthias Geihs <[email protected]>

Signed-off-by: Matthias Geihs <[email protected]>
  • Loading branch information
matthiasgeihs authored Oct 10, 2022
1 parent be6e072 commit c23f66b
Show file tree
Hide file tree
Showing 24 changed files with 193 additions and 67 deletions.
7 changes: 3 additions & 4 deletions apps/payment/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@ import (

"perun.network/go-perun/channel"
"perun.network/go-perun/log"
"perun.network/go-perun/wallet"
)

// App is a payment app.
type App struct {
Addr wallet.Address
ID channel.AppID
}

// Def returns the address of this payment app.
func (a *App) Def() wallet.Address {
return a.Addr
func (a *App) Def() channel.AppID {
return a.ID
}

// NewData returns a new instance of data specific to the payment app,
Expand Down
5 changes: 2 additions & 3 deletions apps/payment/app_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ import (

"perun.network/go-perun/channel"
"perun.network/go-perun/channel/test"
wallettest "perun.network/go-perun/wallet/test"
pkgtest "polycry.pt/poly-go/test"
)

func TestApp_Def(t *testing.T) {
rng := pkgtest.Prng(t)
def := wallettest.NewRandomAddress(rng)
def := test.NewRandomAppID(rng)
app := &App{def}
assert.True(t, def.Equal(app.Def()))
assert.True(t, app.Def().Equal(app.Def()))
}

func TestApp_ValidInit(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions apps/payment/randomizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (

"perun.network/go-perun/channel"
"perun.network/go-perun/channel/test"
wtest "perun.network/go-perun/wallet/test"
)

// Randomizer implements channel.test.AppRandomizer.
Expand All @@ -29,7 +28,7 @@ var _ test.AppRandomizer = (*Randomizer)(nil)

// NewRandomApp always returns a payment app with a different address.
func (*Randomizer) NewRandomApp(rng *rand.Rand) channel.App {
return &App{wtest.NewRandomAddress(rng)}
return &App{test.NewRandomAppID(rng)}
}

// NewRandomData returns NoData because a PaymentApp does not have data.
Expand Down
3 changes: 1 addition & 2 deletions apps/payment/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ package payment

import (
"perun.network/go-perun/channel"
"perun.network/go-perun/wallet"
)

// Resolver is the payment app resolver.
type Resolver struct{}

// Resolve returns a payment app with the given definition.
func (b *Resolver) Resolve(def wallet.Address) (channel.App, error) {
func (b *Resolver) Resolve(def channel.AppID) (channel.App, error) {
return &App{def}, nil
}
4 changes: 2 additions & 2 deletions apps/payment/resolver_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

_ "perun.network/go-perun/backend/sim" // backend init
"perun.network/go-perun/channel"
"perun.network/go-perun/wallet/test"
ctest "perun.network/go-perun/channel/test"
pkgtest "polycry.pt/poly-go/test"
)

Expand All @@ -32,7 +32,7 @@ func TestResolver(t *testing.T) {
rng := pkgtest.Prng(t)
assert, require := assert.New(t), require.New(t)

def := test.NewRandomAddress(rng)
def := ctest.NewRandomAppID(rng)
channel.RegisterAppResolver(def.Equal, &Resolver{})

app, err := channel.Resolve(def)
Expand Down
52 changes: 52 additions & 0 deletions backend/sim/channel/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 channel

import (
"math/rand"

"perun.network/go-perun/backend/sim/wallet"
"perun.network/go-perun/channel"
)

// AppID represents an app identifier.
type AppID struct {
*wallet.Address
}

// Equal returns whether the object is equal to the given object.
func (id AppID) Equal(b channel.AppID) bool {
bTyped, ok := b.(AppID)
if !ok {
return false
}

return id.Address.Equal(bTyped.Address)
}

// Key returns the key representation of this app identifier.
func (id AppID) Key() channel.AppIDKey {
b, err := id.MarshalBinary()
if err != nil {
panic(err)
}
return channel.AppIDKey(b)
}

// NewRandomAppID generates a new random app identifier.
func NewRandomAppID(rng *rand.Rand) AppID {
addr := wallet.NewRandomAddress(rng)
return AppID{addr}
}
1 change: 1 addition & 0 deletions backend/sim/channel/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// 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 channel_test

import (
Expand Down
8 changes: 8 additions & 0 deletions backend/sim/channel/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/pkg/errors"

simwallet "perun.network/go-perun/backend/sim/wallet"
"perun.network/go-perun/channel"
"perun.network/go-perun/log"
"perun.network/go-perun/wallet"
Expand Down Expand Up @@ -79,3 +80,10 @@ func (b *backend) NewAsset() channel.Asset {
addr := Asset{}
return &addr
}

// NewAppID returns an object of type AppID, which can be used for
// unmarshalling an app identifier from its binary representation.
func (b *backend) NewAppID() channel.AppID {
addr := &simwallet.Address{}
return AppID{addr}
}
5 changes: 5 additions & 0 deletions backend/sim/channel/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
package channel

import (
"math/rand"

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

func init() {
channel.SetBackend(new(backend))
test.SetRandomizer(new(randomizer))
test.SetNewRandomAppID(func(r *rand.Rand) channel.AppID {
return NewRandomAppID(r)
})
}
25 changes: 17 additions & 8 deletions channel/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,20 @@ import (

"github.com/pkg/errors"

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

type (
// AppID represents an app identifier.
AppID interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
Equal(AppID) bool

// Key returns the object key which can be used as a map key.
Key() AppIDKey
}

// An App is an abstract interface for an app definition. Either a StateApp or
// ActionApp should be implemented.
App interface {
Expand All @@ -33,7 +42,7 @@ type (
// what valid actions or transitions are.
// Calling this function on a NoApp panics, so ensure that IsNoApp
// returns false.
Def() wallet.Address
Def() AppID

// NewData returns a new instance of data specific to NoApp, intialized
// to its zero value.
Expand Down Expand Up @@ -117,11 +126,11 @@ type (
// AppResolver provides functionality to create an App from an Address.
// The AppResolver needs to be implemented for every state channel application.
AppResolver interface {
// Resolve creates an app from its defining address. It is
// possible that multiple apps are in use, which is why creation happens
// over a central Resolve function. This function is intended to resolve
// app definitions coming in on the wire.
Resolve(wallet.Address) (App, error)
// Resolve creates an app from its defining identifier. It is possible that
// multiple apps are in use, which is why creation happens over a central
// Resolve function. This function is intended to resolve app definitions
// coming in on the wire.
Resolve(AppID) (App, error)
}
)

Expand Down Expand Up @@ -165,7 +174,7 @@ func (d OptAppDec) Decode(r io.Reader) (err error) {
*d.App = NoApp()
return nil
}
appDef := wallet.NewAddress()
appDef := backend.NewAppID()
err = perunio.Decode(r, appDef)
if err != nil {
return errors.WithMessage(err, "decode app address")
Expand Down
27 changes: 16 additions & 11 deletions channel/appregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,38 @@ import (
"sync"

"github.com/pkg/errors"
"perun.network/go-perun/wallet"
)

// appRegistry is the global registry for `AppResolver`s.
var appRegistry = appReg{singles: make(map[wallet.AddrKey]App)}
var appRegistry = appReg{singles: make(map[AppIDKey]App)}

// AppIDKey is the key representation of an app identifier.
type AppIDKey string

type appReg struct {
sync.RWMutex
resolvers []appRegEntry
singles map[wallet.AddrKey]App
singles map[AppIDKey]App
defaultRes AppResolver
}

// AppIDPredicate is a function for filtering app identifiers.
type AppIDPredicate = func(AppID) bool

type appRegEntry struct {
pred wallet.AddressPredicate
pred AppIDPredicate
res AppResolver
}

// Resolve is a global wrapper call to the global `appRegistry`.
// This function is intended to resolve app definitions coming in on the wire.
func Resolve(def wallet.Address) (App, error) {
func Resolve(def AppID) (App, error) {
appRegistry.RLock()
defer appRegistry.RUnlock()
if def == nil {
log.Panic("resolving nil address")
}
if app, ok := appRegistry.singles[wallet.Key(def)]; ok {
if app, ok := appRegistry.singles[def.Key()]; ok {
return app, nil
}
for _, e := range appRegistry.resolvers {
Expand All @@ -59,14 +64,14 @@ func Resolve(def wallet.Address) (App, error) {
return appRegistry.defaultRes.Resolve(def)
}

// RegisterAppResolver appends the given `AddressPredicate` and `AppResolver` to the
// global `appRegistry`.
func RegisterAppResolver(pred wallet.AddressPredicate, appRes AppResolver) {
// RegisterAppResolver appends the given `AppIDPredicate` and `AppResolver` to
// the global `appRegistry`.
func RegisterAppResolver(pred AppIDPredicate, appRes AppResolver) {
appRegistry.Lock()
defer appRegistry.Unlock()

if pred == nil || appRes == nil {
log.Panic("nil AddressPredicate or AppResolver")
log.Panic("nil AppIDPredicate or AppResolver")
}

appRegistry.resolvers = append(appRegistry.resolvers, appRegEntry{pred, appRes})
Expand All @@ -81,7 +86,7 @@ func RegisterApp(app App) {
log.Panic("nil Address or App")
}

appRegistry.singles[wallet.Key(app.Def())] = app
appRegistry.singles[app.Def().Key()] = app
}

// RegisterDefaultApp allows to specify a default `AppResolver` which is used by
Expand Down
Loading

0 comments on commit c23f66b

Please sign in to comment.