@@ -20,6 +20,7 @@ import (
2020 "github.com/pkg/errors"
2121
2222 "perun.network/go-perun/channel"
23+ "perun.network/go-perun/log"
2324 "perun.network/go-perun/pkg/sync"
2425 "perun.network/go-perun/wire"
2526)
@@ -75,7 +76,7 @@ func (c *Channel) Watch(h AdjudicatorEventHandler) error {
7576
7677 // If local version greater than backend version, register local state.
7778 if e .Version () < c .State ().Version {
78- if err := c .Register (ctx ); err != nil {
79+ if err := c .registerDispute (ctx ); err != nil {
7980 return errors .WithMessage (err , "registering" )
8081 }
8182 }
@@ -90,17 +91,17 @@ func (c *Channel) Watch(h AdjudicatorEventHandler) error {
9091 return errors .WithMessage (err , "subscription closed" )
9192}
9293
93- // Register registers the channel and all its relatives on the adjudicator .
94+ // registerDispute registers a dispute for the channel and all its relatives.
9495//
9596// Returns TxTimedoutError when the program times out waiting for a transaction
9697// to be mined.
9798// Returns ChainNotReachableError if the connection to the blockchain network
9899// fails when sending a transaction to / reading from the blockchain.
99- func (c * Channel ) Register (ctx context.Context ) error {
100+ func (c * Channel ) registerDispute (ctx context.Context ) error {
100101 // If this is not the root, go up one level.
101102 // Once we are at the root, we register the whole channel tree together.
102103 if c .parent != nil {
103- return c .parent .Register (ctx )
104+ return c .parent .registerDispute (ctx )
104105 }
105106
106107 // Lock machines of channel and all subchannels recursively.
@@ -133,13 +134,18 @@ func (c *Channel) Register(ctx context.Context) error {
133134 return nil
134135}
135136
136- // ProgressBy progresses the channel state in the adjudicator backend .
137+ // ForceUpdate enforces a channel update on the adjudicator.
137138//
138139// Returns TxTimedoutError when the program times out waiting for a transaction
139140// to be mined.
140141// Returns ChainNotReachableError if the connection to the blockchain network
141142// fails when sending a transaction to / reading from the blockchain.
142- func (c * Channel ) ProgressBy (ctx context.Context , update func (* channel.State )) error {
143+ func (c * Channel ) ForceUpdate (ctx context.Context , update func (* channel.State )) error {
144+ err := c .ensureRegistered (ctx )
145+ if err != nil {
146+ return err
147+ }
148+
143149 // Lock machine
144150 if ! c .machMtx .TryLockCtx (ctx ) {
145151 return errors .Errorf ("locking machine mutex in time: %v" , ctx .Err ())
@@ -182,6 +188,13 @@ func (c *Channel) ProgressBy(ctx context.Context, update func(*channel.State)) e
182188// Returns ChainNotReachableError if the connection to the blockchain network
183189// fails when sending a transaction to / reading from the blockchain.
184190func (c * Channel ) Settle (ctx context.Context , secondary bool ) (err error ) {
191+ if ! c .State ().IsFinal {
192+ err := c .ensureRegistered (ctx )
193+ if err != nil {
194+ return err
195+ }
196+ }
197+
185198 // Lock machines of channel and all subchannels recursively.
186199 l , err := c .tryLockRecursive (ctx )
187200 defer l .Unlock ()
@@ -396,3 +409,55 @@ func (c *Channel) subChannelStateMap() (states channel.StateMap, err error) {
396409 })
397410 return
398411}
412+
413+ // ensureRegistered ensures that the channel is registered.
414+ func (c * Channel ) ensureRegistered (ctx context.Context ) error {
415+ phase := c .Phase ()
416+ if phase == channel .Registered || phase == channel .Progressed {
417+ return nil
418+ }
419+
420+ registeredEvents := make (chan * channel.RegisteredEvent )
421+
422+ // Start event subscription.
423+ sub , err := c .adjudicator .Subscribe (ctx , c .Params ())
424+ if err != nil {
425+ return errors .WithMessage (err , "subscribing to adjudicator events" )
426+ }
427+ go waitForRegisteredEvent (sub , registeredEvents )
428+
429+ // Register.
430+ err = c .registerDispute (ctx )
431+ if err != nil {
432+ return errors .WithMessage (err , "registering" )
433+ }
434+
435+ select {
436+ case e := <- registeredEvents :
437+ err = e .Timeout ().Wait (ctx )
438+ if err != nil {
439+ return err
440+ }
441+ case <- ctx .Done ():
442+ return ctx .Err ()
443+ }
444+ return nil
445+ }
446+
447+ // waitForRegisteredEvent waits until a RegisteredEvent has been observed.
448+ func waitForRegisteredEvent (sub channel.AdjudicatorSubscription , events chan <- * channel.RegisteredEvent ) {
449+ defer func () {
450+ err := sub .Close ()
451+ if err != nil {
452+ log .Warn ("Subscription closed with error:" , err )
453+ }
454+ }()
455+
456+ // Scan for registered event.
457+ for e := sub .Next (); e != nil ; e = sub .Next () {
458+ if e , ok := e .(* channel.RegisteredEvent ); ok {
459+ events <- e
460+ return
461+ }
462+ }
463+ }
0 commit comments