diff --git a/channel/adjudicator.go b/channel/adjudicator.go index b9f9d41..f44fbd3 100644 --- a/channel/adjudicator.go +++ b/channel/adjudicator.go @@ -1,4 +1,4 @@ -// Copyright 2023 PolyCrypt GmbH +// Copyright 2024 PolyCrypt GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,27 +32,31 @@ import ( var ErrChannelAlreadyClosed = errors.New("channel is already closed") +var DefaultChallengeDuration = time.Duration(20) * time.Second + type Adjudicator struct { - log log.Embedding - StellarClient *client.Client - acc *wallet.Account - assetAddr xdr.ScAddress - perunAddr xdr.ScAddress - maxIters int - pollingInterval time.Duration + challengeDuration *time.Duration + log log.Embedding + StellarClient *client.Client + acc *wallet.Account + assetAddr xdr.ScAddress + perunAddr xdr.ScAddress + maxIters int + pollingInterval time.Duration } // NewAdjudicator returns a new Adjudicator. func NewAdjudicator(acc *wallet.Account, stellarClient *client.Client, perunID xdr.ScAddress, assetID xdr.ScAddress) *Adjudicator { return &Adjudicator{ - StellarClient: stellarClient, - acc: acc, - perunAddr: perunID, - assetAddr: assetID, - maxIters: MaxIterationsUntilAbort, - pollingInterval: DefaultPollingInterval, - log: log.MakeEmbedding(log.Default()), + challengeDuration: &DefaultChallengeDuration, + StellarClient: stellarClient, + acc: acc, + perunAddr: perunID, + assetAddr: assetID, + maxIters: MaxIterationsUntilAbort, + pollingInterval: DefaultPollingInterval, + log: log.MakeEmbedding(log.Default()), } } @@ -68,7 +72,7 @@ func (a *Adjudicator) Subscribe(ctx context.Context, cid pchannel.ID) (pchannel. c := a.StellarClient perunAddr := a.GetPerunAddr() assetAddr := a.GetAssetAddr() - return NewAdjudicatorSub(ctx, cid, c, perunAddr, assetAddr) + return NewAdjudicatorSub(ctx, cid, c, perunAddr, assetAddr, a.challengeDuration) } func (a *Adjudicator) Withdraw(ctx context.Context, req pchannel.AdjudicatorReq, smap pchannel.StateMap) error { diff --git a/channel/adjudicator_sub.go b/channel/adjudicator_sub.go index b14bbc2..b1139b8 100644 --- a/channel/adjudicator_sub.go +++ b/channel/adjudicator_sub.go @@ -1,4 +1,4 @@ -// Copyright 2023 PolyCrypt GmbH +// Copyright 2024 PolyCrypt GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,44 +32,37 @@ const ( DefaultSubscriptionPollingInterval = time.Duration(5) * time.Second ) -type AdjEvent interface { - // Sets the necessary event data from the channel information - EventDataFromChannel(cchanState wire.Channel, timestamp uint64) error - ID() pchannel.ID - Timeout() pchannel.Timeout - Version() event.Version - Tstamp() uint64 -} - // AdjudicatorSub implements the AdjudicatorSubscription interface. type AdjEventSub struct { - stellarClient *client.Client - chanControl wire.Control - cid pchannel.ID - perunAddr xdr.ScAddress - assetAddr xdr.ScAddress - events chan AdjEvent - subErrors chan error - err error - cancel context.CancelFunc - closer *pkgsync.Closer - pollInterval time.Duration - log log.Embedding + challengeDuration *time.Duration + stellarClient *client.Client + chanControl wire.Control + cid pchannel.ID + perunAddr xdr.ScAddress + assetAddr xdr.ScAddress + events chan event.PerunEvent + subErrors chan error + err error + cancel context.CancelFunc + closer *pkgsync.Closer + pollInterval time.Duration + log log.Embedding } -func NewAdjudicatorSub(ctx context.Context, cid pchannel.ID, stellarClient *client.Client, perunAddr xdr.ScAddress, assetAddr xdr.ScAddress) (*AdjEventSub, error) { +func NewAdjudicatorSub(ctx context.Context, cid pchannel.ID, stellarClient *client.Client, perunAddr xdr.ScAddress, assetAddr xdr.ScAddress, challengeDuration *time.Duration) (*AdjEventSub, error) { sub := &AdjEventSub{ - stellarClient: stellarClient, - chanControl: wire.Control{}, - cid: cid, - perunAddr: perunAddr, - assetAddr: assetAddr, - events: make(chan AdjEvent, DefaultBufferSize), - subErrors: make(chan error, 1), - pollInterval: DefaultSubscriptionPollingInterval, - closer: new(pkgsync.Closer), - log: log.MakeEmbedding(log.Default()), + challengeDuration: challengeDuration, + stellarClient: stellarClient, + chanControl: wire.Control{}, + cid: cid, + perunAddr: perunAddr, + assetAddr: assetAddr, + events: make(chan event.PerunEvent, DefaultBufferSize), + subErrors: make(chan error, 1), + pollInterval: DefaultSubscriptionPollingInterval, + closer: new(pkgsync.Closer), + log: log.MakeEmbedding(log.Default()), } ctx, sub.cancel = context.WithCancel(ctx) @@ -121,8 +114,8 @@ polling: continue polling } else { - s.log.Log().Debug("Event detected, evaluating events...") - s.log.Log().Debugf("Found event: %v", adjEvent) + s.log.Log().Debug("Contract event detected, evaluating...") + s.log.Log().Debugf("Found contract event: %v", adjEvent) s.events <- adjEvent return } @@ -130,7 +123,7 @@ polling: } } -func DifferencesInControls(controlCurr, controlNext wire.Control) (AdjEvent, error) { +func DifferencesInControls(controlCurr, controlNext wire.Control) (event.PerunEvent, error) { if controlCurr.FundedA != controlNext.FundedA { if controlCurr.FundedA { @@ -187,12 +180,3 @@ func DifferencesInControls(controlCurr, controlNext wire.Control) (AdjEvent, err return nil, nil } - -func IdenticalControls(controlCurr, controlNext wire.Control) bool { - return controlCurr.FundedA == controlNext.FundedA && - controlCurr.FundedB == controlNext.FundedB && - controlCurr.Closed == controlNext.Closed && - controlCurr.WithdrawnA == controlNext.WithdrawnA && - controlCurr.WithdrawnB == controlNext.WithdrawnB && - controlCurr.Disputed == controlNext.Disputed -} diff --git a/channel/subscribe.go b/channel/subscribe.go index 25470ca..04ae043 100644 --- a/channel/subscribe.go +++ b/channel/subscribe.go @@ -1,4 +1,4 @@ -// Copyright 2023 PolyCrypt GmbH +// Copyright 2024 PolyCrypt GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -36,15 +36,13 @@ func (s *AdjEventSub) Next() pchannel.AdjudicatorEvent { return nil } - timestamp := ev.Tstamp() - switch e := ev.(type) { case *event.DisputedEvent: log.Println("DisputedEvent received") dispEvent := pchannel.AdjudicatorEventBase{ VersionV: e.Version(), IDV: e.ID(), - TimeoutV: MakeTimeout(timestamp), + TimeoutV: event.MakeTimeout(*s.challengeDuration), } ddn := &pchannel.RegisteredEvent{AdjudicatorEventBase: dispEvent, State: nil, Sigs: nil} s.closer.Close() @@ -56,7 +54,7 @@ func (s *AdjEventSub) Next() pchannel.AdjudicatorEvent { conclEvent := pchannel.AdjudicatorEventBase{ VersionV: e.Version(), IDV: e.ID(), - TimeoutV: MakeTimeout(timestamp), + TimeoutV: event.MakeTimeout(*s.challengeDuration), } ccn := &pchannel.ConcludedEvent{AdjudicatorEventBase: conclEvent} s.closer.Close() @@ -77,7 +75,7 @@ func (s *AdjEventSub) Close() error { return nil } -func (s *AdjEventSub) getEvents() <-chan AdjEvent { +func (s *AdjEventSub) getEvents() <-chan event.PerunEvent { return s.events } diff --git a/channel/timeout.go b/channel/timeout.go deleted file mode 100644 index 7c35892..0000000 --- a/channel/timeout.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2023 PolyCrypt GmbH -// -// 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 ( - "context" - "perun.network/go-perun/log" - "time" -) - -type ( - // ExpiredTimeout is always expired. - // Implements the Perun Timeout interface. - ExpiredTimeout struct{} - - // Timeout can be used to wait until a specific timepoint is reached by - // the blockchain. Implements the Perun Timeout interface. - Timeout struct { - log.Embedding - - when time.Time - pollInterval time.Duration - } - - // TimePoint as defined by pallet Timestamp. - TimePoint uint64 -) - -// DefaultTimeoutPollInterval default value for the PollInterval of a Timeout. -const DefaultTimeoutPollInterval = 1 * time.Second - -// NewExpiredTimeout returns a new ExpiredTimeout. -func NewExpiredTimeout() *ExpiredTimeout { - return &ExpiredTimeout{} -} - -func (*ExpiredTimeout) IsElapsed(context.Context) bool { - return true -} - -// Wait returns nil. -func (*ExpiredTimeout) Wait(context.Context) error { - return nil -} - -// NewTimeout returns a new Timeout which expires at the given time. -func NewTimeout(when time.Time, pollInterval time.Duration) *Timeout { - return &Timeout{log.MakeEmbedding(log.Default()), when, pollInterval} -} - -// IsElapsed returns whether the timeout is elapsed. -func (t *Timeout) IsElapsed(ctx context.Context) bool { - now := time.Now() - - elapsed := t.when.Before(now) || t.when.Equal(now) - - delta := now.Sub(t.when) - if elapsed { - t.Log().Printf("Timeout elapsed since %v", delta) - } else { - t.Log().Printf("Timeout target in %v", delta) - } - - return elapsed -} - -// Wait waits for the timeout or until the context is cancelled. -func (t *Timeout) Wait(ctx context.Context) error { - for { - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(t.pollInterval): - if t.IsElapsed(ctx) { - return nil - } - } - } -} - -// MakeTimeout creates a new timeout. -func MakeTimeout(challDurSec uint64) *Timeout { - expirationTime := time.Now().Add(MakeTime(challDurSec)) - return NewTimeout(expirationTime, DefaultTimeoutPollInterval) -} - -// MakeTime creates a new time from the argument. -func MakeTime(challDurSec uint64) time.Duration { - return time.Duration(challDurSec) * time.Second -} diff --git a/event/doc.go b/event/doc.go new file mode 100644 index 0000000..c59ff9d --- /dev/null +++ b/event/doc.go @@ -0,0 +1,16 @@ +// Copyright 2024 - 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 event provides the functionality to interpret events emitted from the Perun contract and to transform them into AdjudicatorEvent events. +package event diff --git a/event/event.go b/event/event.go index 35fd537..4b22430 100644 --- a/event/event.go +++ b/event/event.go @@ -1,4 +1,4 @@ -// Copyright 2023 PolyCrypt GmbH +// Copyright 2024 PolyCrypt GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import ( "github.com/stellar/go/xdr" pchannel "perun.network/go-perun/channel" "perun.network/perun-stellar-backend/wire" - "time" ) type Version = uint64 @@ -61,28 +60,24 @@ type controlsState map[string]bool type ( PerunEvent interface { ID() pchannel.ID - Timeout() pchannel.Timeout Version() Version } OpenEvent struct { - Channel wire.Channel - IDV pchannel.ID - VersionV Version - Timestamp uint64 + Channel wire.Channel + IDV pchannel.ID + VersionV Version } FundEvent struct { - Channel wire.Channel - IDV pchannel.ID - VersionV Version - Timestamp uint64 + Channel wire.Channel + IDV pchannel.ID + VersionV Version } CloseEvent struct { - Channel wire.Channel - IDV pchannel.ID - VersionV Version - Timestamp uint64 + Channel wire.Channel + IDV pchannel.ID + VersionV Version } WithdrawnEvent struct { @@ -93,10 +88,9 @@ type ( } DisputedEvent struct { - Channel wire.Channel - IDV pchannel.ID - VersionV Version - Timestamp uint64 + Channel wire.Channel + IDV pchannel.ID + VersionV Version } ) @@ -119,15 +113,6 @@ func (e *OpenEvent) ID() pchannel.ID { func (e *OpenEvent) Version() Version { return e.VersionV } -func (e *OpenEvent) Tstamp() uint64 { - return e.Timestamp -} - -func (e *OpenEvent) Timeout() pchannel.Timeout { - when := time.Now().Add(10 * time.Second) - pollInterval := 1 * time.Second - return NewTimeout(when, pollInterval) -} func (e *WithdrawnEvent) GetChannel() wire.Channel { return e.Channel @@ -139,15 +124,6 @@ func (e *WithdrawnEvent) ID() pchannel.ID { func (e *WithdrawnEvent) Version() Version { return e.VersionV } -func (e WithdrawnEvent) Tstamp() uint64 { - return e.Timestamp -} - -func (e *WithdrawnEvent) Timeout() pchannel.Timeout { - when := time.Now().Add(10 * time.Second) - pollInterval := 1 * time.Second - return NewTimeout(when, pollInterval) -} func (e *CloseEvent) GetChannel() wire.Channel { return e.Channel @@ -159,21 +135,6 @@ func (e *CloseEvent) ID() pchannel.ID { func (e *CloseEvent) Version() Version { return e.VersionV } -func (e *CloseEvent) Tstamp() uint64 { - return e.Timestamp -} - -func (e *CloseEvent) Timeout() pchannel.Timeout { - when := time.Now().Add(10 * time.Second) - pollInterval := 1 * time.Second - return NewTimeout(when, pollInterval) -} - -func (e *FundEvent) Timeout() pchannel.Timeout { - when := time.Now().Add(10 * time.Second) - pollInterval := 1 * time.Second - return NewTimeout(when, pollInterval) -} func (e *FundEvent) ID() pchannel.ID { return e.IDV @@ -181,15 +142,6 @@ func (e *FundEvent) ID() pchannel.ID { func (e *FundEvent) Version() Version { return e.VersionV } -func (e *FundEvent) Tstamp() uint64 { - return e.Timestamp -} - -func (e *DisputedEvent) Timeout() pchannel.Timeout { - when := time.Now().Add(10 * time.Second) - pollInterval := 1 * time.Second - return NewTimeout(when, pollInterval) -} func (e *DisputedEvent) ID() pchannel.ID { return e.IDV @@ -197,9 +149,6 @@ func (e *DisputedEvent) ID() pchannel.ID { func (e *DisputedEvent) Version() Version { return e.VersionV } -func (e *DisputedEvent) Tstamp() uint64 { - return e.Timestamp -} func DecodeEventsPerun(txMeta xdr.TransactionMeta) ([]PerunEvent, error) { evs := make([]PerunEvent, 0) @@ -312,11 +261,6 @@ func GetChannelFromEvents(evData xdr.ScVal) (wire.Channel, error) { return wire.Channel{}, err } - if err != nil { - return wire.Channel{}, err - - } - return chanStellar, nil } @@ -352,51 +296,3 @@ func checkOpen(cState controlsState) error { } return nil } - -func (e *CloseEvent) EventDataFromChannel(chanState wire.Channel, timestamp uint64) error { - - chanID := chanState.State.ChannelID - var cid [32]byte - copy(cid[:], chanID[:]) - - e.IDV = cid - e.Timestamp = timestamp - e.Channel = chanState - return nil -} - -func (e *FundEvent) EventDataFromChannel(chanState wire.Channel, timestamp uint64) error { - - chanID := chanState.State.ChannelID - var cid [32]byte - copy(cid[:], chanID[:]) - - e.IDV = cid - e.Timestamp = timestamp - e.Channel = chanState - return nil -} - -func (e *WithdrawnEvent) EventDataFromChannel(chanState wire.Channel, timestamp uint64) error { - - chanID := chanState.State.ChannelID - var cid [32]byte - copy(cid[:], chanID[:]) - - e.IDV = cid - e.Timestamp = timestamp - e.Channel = chanState - return nil -} - -func (e *DisputedEvent) EventDataFromChannel(chanState wire.Channel, timestamp uint64) error { - - chanID := chanState.State.ChannelID - var cid [32]byte - copy(cid[:], chanID[:]) - - e.IDV = cid - e.Timestamp = timestamp - e.Channel = chanState - return nil -} diff --git a/event/timeout.go b/event/timeout.go index c62e47b..6490ee4 100644 --- a/event/timeout.go +++ b/event/timeout.go @@ -1,4 +1,4 @@ -// Copyright 2023 PolyCrypt GmbH +// Copyright 2024 PolyCrypt GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,88 +15,17 @@ package event import ( - "context" - "perun.network/go-perun/log" + pchannel "perun.network/go-perun/channel" "time" ) -type ( - // ExpiredTimeout is always expired. - // Implements the Perun Timeout interface. - ExpiredTimeout struct{} - - // Timeout can be used to wait until a specific timepoint is reached by - // the blockchain. Implements the Perun Timeout interface. - Timeout struct { - log.Embedding - - when time.Time - pollInterval time.Duration - } - - // TimePoint as defined by pallet Timestamp. - TimePoint uint64 -) - -// DefaultTimeoutPollInterval default value for the PollInterval of a Timeout. -const DefaultTimeoutPollInterval = 1 * time.Second - -// NewExpiredTimeout returns a new ExpiredTimeout. -func NewExpiredTimeout() *ExpiredTimeout { - return &ExpiredTimeout{} -} - -func (*ExpiredTimeout) IsElapsed(context.Context) bool { - return true -} - -// Wait returns nil. -func (*ExpiredTimeout) Wait(context.Context) error { - return nil -} - -// NewTimeout returns a new Timeout which expires at the given time. -func NewTimeout(when time.Time, pollInterval time.Duration) *Timeout { - return &Timeout{log.MakeEmbedding(log.Default()), when, pollInterval} -} - -// IsElapsed returns whether the timeout is elapsed. -func (t *Timeout) IsElapsed(ctx context.Context) bool { - now := time.Now() - - elapsed := t.when.Before(now) || t.when.Equal(now) - - delta := now.Sub(t.when) - if elapsed { - t.Log().Printf("Timeout elapsed since %v", delta) - } else { - t.Log().Printf("Timeout target in %v", delta) - } - - return elapsed -} - -// Wait waits for the timeout or until the context is cancelled. -func (t *Timeout) Wait(ctx context.Context) error { - for { - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(t.pollInterval): - if t.IsElapsed(ctx) { - return nil - } - } - } +// NewTimeTimeout returns a new Timeout which expires at the given time. +func NewTimeTimeout(when time.Time) pchannel.Timeout { + return &pchannel.TimeTimeout{Time: when} } // MakeTimeout creates a new timeout. -func MakeTimeout(challDurSec uint64) *Timeout { - expirationTime := time.Now().Add(MakeTime(challDurSec)) - return NewTimeout(expirationTime, DefaultTimeoutPollInterval) -} - -// MakeTime creates a new time from the argument. -func MakeTime(challDurSec uint64) time.Duration { - return time.Duration(challDurSec) * time.Second +func MakeTimeout(challDur time.Duration) pchannel.Timeout { + expirationTime := time.Now().Add(challDur) + return NewTimeTimeout(expirationTime) }