-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement local watcher #182
Implement local watcher #182
Conversation
8d2d2a9
to
b36713f
Compare
659c280
to
096646e
Compare
- Previously, the adjudicator interface consisted of four methods. - But, only some of the methods were required in any particular place. - Hence, define an interface for each of the methods and compose the adjudicator interfaces from these smaller interfaces. Signed-off-by: Manoranjith <[email protected]>
- Add an interface "RegisterSubscriber" that combines the Register and Subscribe methods. This will be used by the watcher. Signed-off-by: Manoranjith <[email protected]>
Signed-off-by: Manoranjith <[email protected]>
Signed-off-by: Manoranjith <[email protected]>
Signed-off-by: Manoranjith <[email protected]>
096646e
to
fcb78d0
Compare
- Implementation is same for ledger and non-ledger channels (sub/virtual). - However, since non-ledger channel require an additional parameter (parent), seaprate API interfaces are provided. - Mocks (placed in watcher/internal/mocks) were generated using testify framework. Signed-off-by: Manoranjith <[email protected]>
Signed-off-by: Manoranjith <[email protected]>
- Use a channel based mechanism to retrieve the latest transactions while handling dispute in order to avoid mutex locks. Signed-off-by: Manoranjith <[email protected]>
Signed-off-by: Manoranjith <[email protected]>
- Usage of the API is described in doc comments and all the scenarios are covered in tests. Signed-off-by: Manoranjith <[email protected]>
fcb78d0
to
ba8bbb9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few high level comments. Could you give me and @ggwpez a code intro in our next meeting?
// | ||
// This channel will be closed when client requests the watcher to stop | ||
// watching or when there is an error. After the channel is closed, error | ||
// message can be read using the Err method. | ||
AdjudicatorSub interface { | ||
Next() <-chan channel.AdjudicatorEvent | ||
EventStream() <-chan channel.AdjudicatorEvent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wha happens if EventStream()
is called twice? Should the implementation support multiplexing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated documentation that Repeated calls to the EventStream method returns the same channel instance.
in PR #212.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think multiplexing is not necessary in our use case, because the only consumer of the events is the watch function.
If at a later point in time, we have the need for consuming the events in multiple places, then we could implement multiplexing.
} | ||
|
||
func (w *Watcher) startWatching(ctx context.Context, parent channel.ID, signedState channel.SignedState) ( | ||
watcher.StatesPub, watcher.AdjudicatorSub, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format looks odd. It looks like this is the first line of the function while in fact it is the beginning of the return parameters. If the line gets too long, you can place each parameter on a separate line, like
func (w *Watcher) StartWatchingSubChannel(
ctx context.Context,
parent channel.ID,
signedState channel.SignedState,
) (watcher.StatesPub, watcher.AdjudicatorSub, error) {
I think this is more intuitive to read.
The same comment applies to all functions using that format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have updated in PR #213.
// StartWatchingLedgerChannel starts watching for a ledger channel. | ||
func (w *Watcher) StartWatchingLedgerChannel(ctx context.Context, signedState channel.SignedState) ( | ||
watcher.StatesPub, watcher.AdjudicatorSub, error) { | ||
return w.startWatching(ctx, channel.Zero, signedState) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the usage channel.Zero
. Even though it seems very unlikely that a channel will have ID zero, it would still be better to not make any assumptions about certain ID values.
It would be better to explicitly mark the parent parameter as optional. You could use a pointer for that and check for nil, which is also not super clean but at least it does not require any assumptions about the ID value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thisCh *ch) { | ||
for e := eventsFromChainSub.Next(); e != nil; e = eventsFromChainSub.Next() { | ||
switch e.(type) { | ||
case *channel.RegisteredEvent: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed in #207 , you may need to check also for the Progressed and Concluded events to be sure that you notice channel registration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in #215.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments from the meeting.
Registerer | ||
Withdrawer | ||
Progresser | ||
EventSubscriber |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed. As adjudicator does not make subscriptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EventSubscriber
removed from Adjudicator
, as it not used by the client anymore. (It is used only by the Watcher
and Watcher
uses the RegisterSubscriber
method. See PR #212.
Closed in favor #248 |
Overview
client.New
API.Implementation details
go-perun/watcher
.go-perun/watcher/local
.Data structures
Watcher:
NewWatcher
function.channel.RegistererSubscriber
instance for interacting with the blockchain.registry
that holds a map of all the channels currently registered with the Watcher.ch:
id
of the channel.params
of the channel. Required while registering dispute for the channel. This will be passed when registering the channel with theWatcher
viaStartWatching
function.parent
of this channel. For ledger channels, this is set tochannel.Zero
.subChsAccess
, (relevant only for ledger channel) a mutex used for concurrency safe access of a family of channels. When a dispute registration is required for a channel, we traverse back to the parent and lock this mutex. It is unlocked only after the dispute registration is completed. This also ensures, we lock only the relevant channels and not the entire registry when registering disputes.registeredVersion
: when a dispute is registered for a ledger, sub or virtual channel, this field is updated. This is used to ensure, we do not register the same version more than once.requestLatestTx
andlatestTx
are a set of channels used for retrieving the latest state of this channel without use of mutex locks.registry: Used to store and retrieve channels registered with the watcher. It is protected by a mutex.
StatesPubSub and AdjudicatorPubSub implements the functionalities exactly as described in the proposal.
Methods
NewWatcher
initializes the watcher.Watcher.StartWatchingForLedgerChannel
and Watcher.StartWatchingForNonLedgerChannel` APIs are used to register a channel with the watcher. Though the implementations of both the APIs are same, two APIs are provided becauseAdjudicatorSub.EventStream
can be used by the client for receiving adjudicator events from the watcher.StatesPub.Publish
can be used by the client to send newer transactions to the watcher.Watcher.StopWatching
andWatcher.Shutdown
are yet to implemented.Tests
It was difficult for me to figure out how to add tests using the simulated backend. Particularly, I couldn't figure out how to make the client send events to the watcher, before integrating the watcher API into client.
However, I implemented some tests based on generated mocks , which I used these to guide my development. I have added them in the PR (in separate commits) for time being. After figuring out how to test simulated backed, we could also replace these tests.
Open points
RegisteredEvent
is received for LC1.Resolves #174