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

Fee Recipient API #24

Merged
merged 20 commits into from
Apr 22, 2022
Merged

Fee Recipient API #24

merged 20 commits into from
Apr 22, 2022

Conversation

james-prysm
Copy link
Collaborator

Post Merge ( Bellatrix release) , stakers will be able to set an eth address to their corresponding validator key to receive gas fees when proposing a block. Fee recipient mapping could be standard across all validating public keys or specific per validating key.

Validator clients should provide a standard API to update and view the fee recipient settings so stakers who have a gui only setup ( dappnode/avado ) and stakers who want to update fee recipients at run time can do so.

This PR proposes one possible implementation of this standard API.

related to #23

Comment on lines 46 to 47
/eth/v1/feerecipient:
$ref: './apis/fee_recipient.yaml'
Copy link
Collaborator

Choose a reason for hiding this comment

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

i think the question here will come down to what we actually want to do when consuming the api.

  • if i had 2000 validators or more loaded, do i really want to list all of the fee recipients for all of the validators?
  • when I'm updating a fee recipient, am i likely to want to update all, or a small number (like 1)

for this api, I would be very tempted to start off by offering the ability to get / post to 1 specific validator in the first instance, and see if a get all / list all is likely to be actually required.

for example, if we were to provide /eth/v1/feerecipient/{pubkey} and and a get will fetch the recipient for that pubkey, a POST will update it, then that may be a very useful way to interact, especially for UI's I would expect...

Again - it depends on how it's going to be used. Not having a UI, this seems to make the most sense in the first instance.
If we do go down the route of a larger array of data, then we should at least be using feerecipients plural, because it's not acting on a single. It would likely need to be able to accept a query parameter or a body to get a subset on the GET. I'd be very interested to know why it's needed though.
Potentially we'd also want a DELETE to remove an overridden fee recipient for one (or many). otherwise the POST would need to accept an empty string or something to indicate we're removing that and just want to use the default fee recipient, which seems hacky.

Copy link
Collaborator

Choose a reason for hiding this comment

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

the other thing a specific endpoint gives us is the ability to return 404...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good points let me brew over it for the evening, going to see if others had any thoughts on this too.

Copy link

Choose a reason for hiding this comment

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

a specific get is a good idea and it could also be a post endpoint accepting array of pubkeys, also it should indicate that if the fee_recipient registered against it is a default or overridden.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I would be very tempted to start off by offering the ability to get / post to 1 specific validator in the first instance and see if a get all / list all is likely to be actually required.

thinking back on this I feel like the reverse would be used more often with something like client migration 🤔

If we do go down the route of a larger array of data, then we should at least be using feerecipients plural, because it's not acting on a single. It would likely need to be able to accept a query parameter or a body to get a subset on the GET.

That's probably true. I think this will take longer to implement than the single use one haha so maybe you're right and we should just go with that....

Potentially we'd also want a DELETE to remove an overridden fee recipient for one (or many).
I guess most clients don't persist this 🤔 so it'll get reset on validator restart, they can update it again with whatever they need and also have a default, not sure if it's needed for mvp.

Copy link
Collaborator

Choose a reason for hiding this comment

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

i think most of the time people will have a default fee recipient and be updating smaller numbers (probably 1), or they'll have large numbers and be basically wanting all/most to a default... they're the 2 main use-cases i can see... I think the latter is more likely to use a config based setup than keymanager management.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok i updated based on the individual get/post. hope I'm doing this correctly 😓 . ready for re-review.

Specific Public keys not mapped will continue to use the default address for fee recipient in accordance to the startup of the validator client and beacon node.
Cannot specify default fee recipient address through API.

WARNING: API only works POST MERGE(Bellatrix)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we'd be far better off allowing this to happen as long as the Bellatrix milestone is enabled in config.
People everywhere would otherwise have to script updating their config, or leave it for hours potentially not correct, which I can't see as a great outcome.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think prysm has a fork config flag 🤔 unless you meant something else.
the API doesn't set the default address ( which i think would complain loudly), but those ux problems are definitely a concern.

Copy link

Choose a reason for hiding this comment

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

I think what @rolfyone is saying is the config has bellatrix epoch set to non infinity. But in my opinion there is no need to condition it to anything, a user will obviously use this api on setup which is merged or impending merge.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess the note maybe could be more for future devs doing integration testing? which I guess is a whole different UX problem lol. Do we keep the description as is then?

Copy link
Collaborator

Choose a reason for hiding this comment

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

if its future devs, we don't care.

  • what do we need now for UX to be ideal?
  • are we doing more than we need, or are we doing 'enough'?

Ultimately we're trying to make it possible to provide a 'painless' UX for people, and that's why i think that restricting to after bellatrix epoch may be against that idea.

Comment on lines 57 to 66
pubkeys:
type: array
description: hexadecimal validator public keys.
items:
$ref: "../keymanager-oapi.yaml#/components/schemas/Pubkey"
ethaddresses:
type: array
description: hexadecimal eth addresses that the validator public key should be associated to, the length should match .
items:
$ref: "../keymanager-oapi.yaml#/components/schemas/Ethaddress"
Copy link
Collaborator

Choose a reason for hiding this comment

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

this really is just being unkind to ourselves. we should be creating an object so that we dont have 2 large disassociated arrays.

{
 "pubkey": "0x...",
 "fee_recipient": "0x..."
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

actually, i think this would mean we're just using the fee recipient map defined here as a ref

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

that's fair I was following the model on the other APIs that ended up getting approved. I do think it should be called fee recipient and then have ethaddress as the second property. other thoughts?

Copy link

@g11tech g11tech Apr 14, 2022

Choose a reason for hiding this comment

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

I agree, the array of this object is better, but then one will also need to qualify that last entry wins in case there are repeats for a pubkey. Also should there be a signature field for validating the the fee_recipient request is actually authorized. Might be crucial for multi party single validator setup if thats a thing.

Copy link

Choose a reason for hiding this comment

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

Another point: one special value of fee_recipient could be default deleting any set entry against this validaor which is akin to delete as highlighted by @rolfyone later in the comments

Copy link
Collaborator

Choose a reason for hiding this comment

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

if we do batch, then yes the last one wins. I think an individual call might be cleaner...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I also think an individual call is cleaner though I am still wondering how important it is to implement right now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

please take a look at the updated version

properties:
pubkey:
$ref: './public_key.yaml'
ethaddress:
Copy link
Collaborator

Choose a reason for hiding this comment

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

call this by its function not its type - fee_recipient

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

manage_fee_recipient? 😅

Copy link
Collaborator

Choose a reason for hiding this comment

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

im not sure why not fee_recipient?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think i called the api the same thing 😓 so i was thinking it should be different but I guess they are in different folders

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

updated

description: |
- set: new fee recipient mapping is set.
- updated: existing fee recipient mapping is replaced.
- error: Any other status different to the above: decrypting error, I/O errors, etc.
Copy link

Choose a reason for hiding this comment

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

or validator not registered

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What did you mean by this one? I think you can set the fee recipient mapping even if the validator doesn't exist in the validator/ it's not active.

Copy link

Choose a reason for hiding this comment

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

umm... returning error would be more prudent, or if not error then another enum value stating validator missing or something ? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Still not sure on this. as long as it's valid format shouldn't it just be set? 🤔 even if you don't have the keys currently or if those aren't real keys, the validator itself will check when the keys become active.

Copy link
Collaborator

Choose a reason for hiding this comment

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

we really want to take advantage of HTTP return codes...
200 - updated, 202, updated (no content reuturned)
404 - not found
400 - error

404 is a particularly useful response on the POST to a specific address

so if the fee_recipient is set, and we don't have a body to return (don't think we should need one) then the 'most appropriate' response is really 202 with no body.
If the entity wasn't found to update, then 404, and if we tried to update it but there were errors, then a 400 with a mesage would be ideal, because you can provide feedback in the message about the nature of the failure.

items:
type: object
required: [status]
properties:
Copy link

Choose a reason for hiding this comment

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

can we also return what is now the current update value set against it (irrespective of the status)

Copy link
Collaborator Author

@james-prysm james-prysm Apr 14, 2022

Choose a reason for hiding this comment

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

I guess it would be stated in the message, but how would you like to see it? to be honest I was just following how the previous APIs were implemented haha.

Copy link

Choose a reason for hiding this comment

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

return property as fee_recipient 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added 🤔

Comment on lines 80 to 87
description: |
- set: new fee recipient mapping is set.
- updated: existing fee recipient mapping is replaced.
- error: Any other status different to the above: decrypting error, I/O errors, etc.
enum:
- set
- updated
- error
Copy link
Collaborator

Choose a reason for hiding this comment

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

i think if we're doing this kind of individual interface, then that changes the response too.
202 is literally 'ok'/'updated' and no content body returned
400 with an error message thats useful, something like {data:{"code": 400, "message": "oopsie"}}

we don't need to pass back fee recipient if it's a 202, because we literally passed it in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

should it be 202 accepted or 200 ok? 🤔 i kept it as 200 right now since I wasn't sure but I just updated this

Copy link
Collaborator

Choose a reason for hiding this comment

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

no body would be 202... typically a 200 would expect to have a HTTP BODY associated

List the validator public key to eth address mapping for fee recipient feature on a specific public key.
The validator public key will return with the default fee recipient address if a specific one was not found.

WARNING: API only works POST MERGE(Bellatrix)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Potentially something like The fee_recipient is not used on Phase0 or Altair networks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

updated

Comment on lines 67 to 74
"200":
description: ok or updated
content:
application/json:
schema:
title: SetFeeRecipientResponse
type: string
example: "updated"
Copy link
Collaborator

Choose a reason for hiding this comment

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

so i think we go with 202, description "successfully updated", and no content.
The 200 then wont be used for the POST. I've said this in a couple of comments but highlighting the actual code for review here (sorry if it sounds like I'm nagging, but this is arguably the best actual place to comment for it)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

got it, appreciate the comments. I just updated it, how does it look now?

@james-prysm james-prysm requested a review from rolfyone April 20, 2022 15:31
@james-prysm james-prysm marked this pull request as ready for review April 21, 2022 02:36
@@ -52,8 +56,12 @@ components:
schemas:
Pubkey:
$ref: './types/public_key.yaml'
Ethaddress:
Copy link
Collaborator

Choose a reason for hiding this comment

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

EthAddress - missed capital ~A

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

updated

@rolfyone
Copy link
Collaborator

I was talking to the team and someone pointed out having it more rest like changes the path a bit but makes things more flexible, and more rest-like, so it sounds good...

This may look like /eth/v1/validator/{pubkey}/feerecipient for example... Then building out other fields becomes 'simple'... also becomes possible to build out a /eth/v1/validator/{pubkey} maybe at some point that allows patches...

Overall I think we're close to a model here, but we may be kind to ourselves by going this route and maybe leveraging that model down the line...

@james-prysm
Copy link
Collaborator Author

Overall I think we're close to a model here, but we may be kind to ourselves by going this route and maybe leveraging that model down the line...

Cool I think this is fair and a good idea for down the road, maybe we can migrate to that one once we have some more APIs for the specific validator key !

@james-prysm james-prysm requested a review from rolfyone April 22, 2022 04:05
@@ -41,6 +43,8 @@ paths:
$ref: './apis/local_keystores.yaml'
/eth/v1/remotekeys:
$ref: './apis/remote_keystores.yaml'
/eth/v1/feerecipient/{pubkey}:
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is the bit i think, if we just change this in the current PR to be /eth/v1/validator/{pubkey}/feerecipient I think we leave the change i was talking about easy without making people move from the one we do here...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oh i misunderstood then, ok i'll follow that then and change it to under validator

Copy link
Collaborator

@rolfyone rolfyone left a comment

Choose a reason for hiding this comment

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

LGTM overall, I think changing the path before implementing is probably a good plan, it seems logical...
marking approved because i think we're in a good place overall.

@rolfyone
Copy link
Collaborator

Thanks for your patience James, looks good, happy for you to merge ;)

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.

3 participants