-
Notifications
You must be signed in to change notification settings - Fork 175
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
Deprecate prepareBeaconProposer, consolidate on registerValidator. #435
Comments
As the author of that blog post about the attack, it's not something I would be worried about and if anything I'd consider it a feature. A validator should not be using a public beacon node to perform its duties as that means it isn't actually validating the chain (it's just trusting the public node provider). Otherwise I haven't thought enough about the proposed change to say if it's a good idea or not - just wanted to clarify that this isn't required to fix an actual security issue. |
Registering validators registers all validators known by the validator client and is a pass-through to relays, whereas prepare proposer is meant to be limited to just those validators that are scheduled to propose within the next epoch and more focused on local block production. There is an argument for using public key rather than index in the registration, although index is used in a number of other places in the API so it isn't a unique requirement for this endpoint. But I think some sort of fast-path notification to the beacon node that the validator client has a validator that is expecting to request a block in the near future is still useful, as it avoids the beacon node having to wade through potentially tens of thousands of registrations to see if one of them is scheduled to propose (although client teams can weigh in here if they think that the overhead isn't relevant).
Note that local payload generation is usually started ahead of the proposing slot, to allow the execution node a chance to build a good payload and provide same when requested with minimal delay. And the underlying code will usually (outside of specific values of the boost factor) talk to both relays and execution node for payloads simultaneously, so I don't think that this point is relevant for what is being discussed. |
Hi Adrian, I have been wondering when we'd run into each other. I reference your blog post often. Evaluating it as a feature, it also fails the sniff test in my opinion. The trust assumption with a public beacon node with prepareBeaconProposer is that not only are the maintainers benevolent but that so is every single other participant- but this can easily be reduced by the maintainers to eliminate the need to trust all the other participants. I helped build such a public beacon node.. Further, most "public beacon nodes" are public by accident- node operators spin up a VPS or baremetal and use docker to manage their clients and ufw to secure the node, but the iptables entries for each bypass one another. A quick search on shodan shows thousands of nodes with unsecured API ports. So, it doesn't accomplish the prevention of public beacon nodes, and it also hurts less-than-professional node operators. Requiring a signature from the validator would at least protect the latter group. Proof of custody, if well implemented, will resolve the public beacon node problem. prepareBeaconProposer is largely irrelevant at this point.
Interesting, if this is the original intent. I have observed every single client send prepareBeaconProposer and registerValidator with the same vector sizes at the same cadence. I have graphs, if needed, to back this up. Since both are called with every attached validator, every epoch (generally), it doesn't make sense to me that they can't serve the same purpose.
It is perhaps unrelated. I only mean that in the past, eligibility to request a blinded block was predicated on a validator's presence in registerValidators, and eligibility to request a block built by the paired execution client was predicated on a validator's presence in prepareBeaconProposer, but that need not be true. Both can be prepared by the beacon node based on registerValidator alone, called unconditionally by the validator client, and the validator client can control which one is signed and published. Ultimately this suggestion serves two purposes:
I'd like to hear from the client teams as to whether they think it accomplishes 2. |
This is correct, the validator client doesn't know the proposers beforehand so it has to send them all and the beacon node will prepare a payload if there is an scheduled proposal.
Although we still need to get the validator status at startup for various other reasons, I think consolidating those two APIs is a strict improvement in terms of security and also avoids overhead of calling two different APIs. The only overhead is that we would have to verify signatures but since this API is not that time sensitive I don't think it's an issue. Just a note that we can't just deprecate prepareBeaconProposers and use the current registerValidator API. This requires to implement a registerValidatorV2 API which consolidates the two APIs (similar to block v3), otherwise pairing two different clients might result in proposers not being prepared at all. Maybe something to enable at Electra fork epoch? |
I spoke out-of-band with @tersec on the nimbus discord to get his perspective, and hopefully this summary is representative:
I'm of a mind to day that proxied beacon nodes bear the responsibility to broadcast prepareBeaconProposer requests to all upstreams, and that the VCs should not be sending prepareBeaconProposer once per slot. On the other hand, I can see why they do- a node operator who is not savvy enough to secure their beacon api port certainly is not savvy enough to handle a complicated proxying setup. |
Thank you for summarizing our discussion here; yes, that's accurate from my perspective. |
Speaking as a Lighthouse dev, I am in favour of combining them. I think it's a good simplification. I suspect that the current per-slot schedule for We could start experimenting prior to a coordinated release (e.g. Electra) by updating BNs to always draw fee recipients from |
This can also be mitigated by holding a tcp connection open (or similar), and sending an adhoc request each time it's reestablished. Nimbus does something along these lines, from what I can tell through observation. |
There is ongoing discussion to pass the target gas limit configured on the vc side as part of The new consolidated api could be called each slot as currently to address #435 (comment) or depending on validator client use different approaches but either way on the beacon node side could limit this to only forward registrations to builder once an epoch (to still follow builder spec). Ideally, we wanna roll this out to out now and migrate to consolidated api post-electra |
If we forget
which should cover all of the eventualities. However, the last situation here isn't something that can be recognized with the existing API. It's possible that the clients will pick up the dropped connection if using long-lived connections, but it's not guaranteed. An alternative would be to require on-disk caching of the validator registrations on the beacon node so that they are not lost on restart, but that seems like dumping a lot of work on the client teams. We could add an endpoint in Or we can send the data more frequently, e.g. every slot, as you say. But that's a significant amount of additional work for a corner case. Perhaps a hybrid approach: if a validator client knows that it has a proposal coming up in the next epoch it sends the registrations each slot, otherwise once per epoch? That may fit best in terms of retaining the statelessness of the API (and the underlying beacon node), but cover the corner case. Thoughts? |
The Lodestar vc already polls
I also think it would be best to not make any assumptions on how the beacon node manages the cache (eg. like persisting it to disk between restarts) and leave it up to the validator client to make sure it's updated before a proposal with whatever strategy fits well with the current design, this is pretty implementation specific, especially when it comes to how the interacts with multiple connected bns. |
I truly believe prepareBeaconProposer is strictly more cumbersome than registerValidator.
Now that builder_boost_factor is present, control over whether to use a builder block or a paired node block is satisfied at the time produceBlockV3 is called, and consolidating prepareBeaconProposer and registerValidator will not leave the BN wondering which block to return to each attached validator client.
The text was updated successfully, but these errors were encountered: