-
Notifications
You must be signed in to change notification settings - Fork 34
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
refactor: add StateSync
component
#646
Conversation
/// The [SyncState] trait defines the interface for the state sync process. The sync process is | ||
/// responsible for updating the client's store with the latest state of the network. | ||
/// | ||
/// Methods in this trait shouldn't change the state of the client itself, but rather return the | ||
/// updated state as a result. | ||
#[async_trait(?Send)] | ||
pub trait SyncState { |
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've only looked at this briefly, so could be missing the main idea entirely - but I was thinking of components a bit differently. Specifically, the SyncState
component would be a struct rather than a trait and it would be completely separate from the store. The workflow would look something like this then:
- The user instantiates
SyncState
struct by passing to itrpc_api
and relevant initial data from the store. - Then the user runs the
sync()
function. - This function returns the data that the user would then filter through and insert into the store.
This SyncState
component would then be used in our implementation of the Client
, but users would be able to use it in other contexts too.
I think the main thing here is to define what data we need to provide to the StateSync
component on initialization and what would be returned from the sync()
function.
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 I got a better idea. The user wouldn't create a different implementation, they just would get access to the same output the client will get on a sync. I like this approach better as it seems simpler and wouldn't change the client internals greatly. I'll create a separate branch for ths approach.
It would be completely separate from the store.
This function returns the data that the user would then filter through and insert into the store.
The returned information might be incomplete/not entirely processed, as the sync process involves getting some information from the store. Another option would be to get this needed information beforehand but maybe it would be wasteful.
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 returned information might be incomplete/not entirely processed, as the sync process involves getting some information from the store. Another option would be to get this needed information beforehand but maybe it would be wasteful.
Yeah, I think one of the open questions is whether we can find a good balance here so that we don't have to pre-load too much info from the store, but also get some meaningful processing during the sync process.
replaced by #650 |
Objective
This PR is a proof of concept for the first client component. The idea of components is that they are parts of the client's logic that users can compose and add their own functionality.
These components could be passed to the client's constructor like the store and rpc (this is not implemented in this draft but it wouldn't be hard to do so).
In this initial iteration, a new
StateSync
component is added that implements the oldsync_state_once
function. In terms of additional logic, there isn't much, the old code is moved to this new component and the interface is declared in a trait so that users can create their own.Example
While implementing this I wanted to add an example of a possible alternate
StateSync
component someone could implement. I remembered we have a simpler sync (what we call note sync) inside the import note logic. I created aStateSync
inimport.rs
that only looks for updates of a specific note record. After implementing it though, I don't think this example is adequate tough, as the component isn't used how an external user would use it (passing it to the client as a constructor). It does show how the interface could be used in different ways. (this "example" is contained in the last commit so it can be ignored in the review tab). Before fixing the example so it's used in the intended way I had some thoughts I wanted to discuss.Some thoughts before continuing
Before continuing with the implementation (tidying up the code organization, etc.) I wanted to create this draft PR to further discuss this initial iteration of the component feature. Some comments I had during the process:
Maybe I'm overthinking it and this way of implementing it isn't ideal. I tried different ways, but I thought this one was the simplest.