Skip to content
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

beacon/light/request: general request framework (WIP) #28656

Closed
wants to merge 1 commit into from

Conversation

zsfelfoldi
Copy link
Contributor

This PR implements a general-purpose framework for sync mechanisms requesting data from multiple servers. It is intended to be used primarily by the beacon chain light client but might be used for other purposes too as it does nothing specific to the beacon chain. It implements timeouts, very simple rate limits and server selection, basically abstracting away the multiple server logic from the actual sync processes.


type RequestServer interface {
Subscribe(eventCallback func(event Event))
CanSendRequest(request interface{}) (bool, float32)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Go 1.18, you can use any instead of interface{}

type RequestServer interface {
Subscribe(eventCallback func(event Event))
CanSendRequest(request interface{}) (bool, float32)
SendRequest(request interface{}) (reqId interface{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would be possible to define a concrete type for request IDs here? Why keep it so abstract?

@holiman
Copy link
Contributor

holiman commented Dec 12, 2023

This PR implements a general-purpose framework for sync mechanisms requesting data from multiple servers.

I don't understand this. The server for a light client is, at the moment, an http endpoint. Why not just

  • have an api-interface BeaconServer.
  • implement that in an http client httpBeaconServer
  • implement that in a multiplexer roundRobinBeaconServer which dispatches requests to a list of alternatives (possibly with some tracking about which are unavailable).

And done. What do we need a general purpose request framework for, when all we do is query a known api?

@zsfelfoldi
Copy link
Contributor Author

What do we need a general purpose request framework for, when all we do is query a known api?

I think this PR will make more sense in the context of the subsequent one :) Sure, the resend/timeout logic could be implemented as a multiplexer for the API, but I think the sync logic will be much cleaner with this event driven approach. See #26874 (comment)
blsync already has multiple sync processes that sometimes needs to trigger each other. For the full featured light client we are going to need even more sync mechanisms that collect partial beacon state data from beacon APIs, regardless of how we distribute that data later. Instead of many concurrent processes calling blocking API functions, I think it is just more manageable to have a single scheduler that sends requests and delivers replies to non-blocking Process functions.

@holiman
Copy link
Contributor

holiman commented Dec 12, 2023

Instead of many concurrent processes calling blocking API functions, I think it is just more manageable to have a single scheduler

In general, it's nicer API to use a blocking api, instead of having to work with callbacks. I mean, we (actually @karalabe) did rewrite large parts of the p2p request-handling on snap/eth just to "feel" like it was a blocking API, to hide the facts that internally it was just actually an async event handling.

func (s *Scheduler) syncLoop() {
for {
s.lock.Lock()
s.processModules()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the processModules is holding s.lock. If any of these generic modules try to interact with the scheduler, e..g registering a new server, this will deadlock, no?

@zsfelfoldi
Copy link
Contributor Author

In general, it's nicer API to use a blocking api, instead of having to work with callbacks.

I'll think about it. Maybe I am trying to do too much abstraction at an early stage again :) A separate goroutine for each sync process certainly doesn't hurt anyone and I am also starting to like the API multiplexer idea. The logic in this PR is fairly easy to restructure. Also, it can be done independently from the other parts so we can finish a single server version of blsync first and then add the multi-server feature.

@zsfelfoldi
Copy link
Contributor Author

Closed in favor of #28906

@zsfelfoldi zsfelfoldi closed this Feb 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants