-
-
Notifications
You must be signed in to change notification settings - Fork 290
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
feat: add endpoint for Altair block reward #6178
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## unstable #6178 +/- ##
============================================
+ Coverage 60.15% 61.69% +1.53%
============================================
Files 407 554 +147
Lines 46511 58090 +11579
Branches 1550 1832 +282
============================================
+ Hits 27980 35840 +7860
- Misses 18499 22213 +3714
- Partials 32 37 +5 |
Co-authored-by: Nico Flaig <nflaig@protonmail.com>
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.
Looks pretty good! Just few remarks / questions regarding the units we use for the ssz type
I tested this on my goerli node (slot 7466188)
> curl -s http://localhost:9596/eth/v1/beacon/rewards/blocks/7466188 | jq
{
"data": {
"proposer_index": "2232",
"total": "25570228",
"attestations": "24656876",
"sync_aggregate": "913352",
"proposer_slashings": "0",
"attester_slashings": "0"
},
"execution_optimistic": false
}
I haven't confirmed that the data is correct but 0,0255 ETH consensus reward sounds about right. We might wanna cross check our rewards APIs against other clients (Teku / Lighthouse) at some point.
Not sure if @tuyennhv wants to give this another review, all previous comments have been addressed
@@ -991,4 +992,11 @@ export class BeaconChain implements IBeaconChain { | |||
} | |||
} | |||
} | |||
|
|||
async getBlockRewards(block: allForks.FullOrBlindedBeaconBlock): Promise<BlockRewards> { | |||
const preState = (await this.regen.getPreState(block, {dontTransferCache: true}, RegenCaller.restApi)).clone(); |
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.
A little sketchy that this can trigger a regen.
Is this the only non-debug endpoint that can do that?
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.
A little sketchy that this can trigger a regen.
What's your concern in particular? I don't think getPreState
modifies anything under the hood. To get the preState of a block I don't see a way without calling regen. At some point regen.getState()
must be called.
Is this the only non-debug endpoint that can do that?
This is the only one that I know of cc. @tuyennhv
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.
Is this the only non-debug endpoint that can do that?
It looks like this is the only one, can be confirmed by searching for allowRegen
which is only set to true for debug state apis
What's your concern in particular?
The main concern is probably that you can use this API to easily DoS our public nodes as regen is quite expensive.
What about adding rewards APIs as their own namespace and disabling them by default?
e.g. we also have light client APIs on their own namespace even though those are part of /beacon as per spec
lightclient: () => lightclient.getRoutes(config, api.lightclient), |
we could then simply not enable rewards APIs by default here
api: ["beacon", "config", "events", "node", "validator", "lightclient"], |
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.
What about adding rewards APIs as their own namespace and disabling them by default?
I read the documentation of other CL clients and looks like everyone has rewards endpoint enabled by default. Don’t know if the users expect this endpoint would be enabled on the public nodes.
Alternatively, we can limit the queried block to any block from last finalized checkpoint to head similar to what Teku behaves under prune
mode: https://docs.teku.consensys.io/how-to/use-rewards-api#limitations . This way we only need to check stateCache
and checkpointStateCache
without triggering a regen request
The main concern is probably that you can use this API to easily DoS our public nodes as regen is quite expensive.
My wishful thinking is to have two priority tiers for RegenRequest
. One being essential and one being non-essential. Any debug and reward endpoint that triggers regen should have a low priority such that when JobItemQueue
size reaches a certain threshold, it rejects new RegenRequest
that has low priority.
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.
Alternatively, we can limit the queried block from last finalized checkpoint to head
This is already the case now, it isn't fetching historical states, but this can still trigger block / epoch transitions if the requested state isn't already in a cache. In practice, in healthy network conditions, we have all states between finalized and head in cache. But it can become a problem in periods of non-finality.
We could add and use a regen.getPreStateSync
that acts like regen.getStateSync
in that it only checks cached state values and returns undefined if the state isn't cached. IMO this is a good compromise, since it allows us to serve the data in most cases, but doesn't open us up to any DoS issues.
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 an aside, It may be worth thinking deeper about our strategy around serving more expensive queries.
Should we support expensive queries? Behind a feature flag or flags? If so, what does that look like?
Behind extra namespaces for each additional feature-set in the APIs?
What does the architecture of generating expensive data look like? Queue that deprioritizes non-urgent work? Separate worker that handles expensive queries? Other?
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.
yes this is really a concern because with PersistentCheckpointStateCache
, using getPreState
means it will reload checkpoint state if needed
We could add and use a regen.getPreStateSync that acts like regen.getStateSync in that it only checks cached state values and returns undefined if the state isn't cached. IMO this is a good compromise, since it allows us to serve the data in most cases, but doesn't open us up to any DoS issues.
in this specific scenario, if we can get a cached pre state, we can also get post state and get the cached reward from post state, so it's no use to have getPreStateSync()
I think we only want to support getting cached reward in post state for lodestar (it means it'll work for 64-96 blocks for now). If demand arises from any specific use case, we can enhance later
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.
in this specific scenario, if we can get a cached pre state, we can also get post state and get the cached reward from post state, so it's no use to have getPreStateSync()
For the purpose of this endpoint, I echo with @wemeetagain 's idea to only serve blocks which its corresponding postState is cached.
So we should just drop the preState parameter in computeBlockRewards(block, preState, postState)
, and also all the reward calculation in blockRewards.ts
and solely rely on cached values
Update: Looks like we still need the preState to calculate proposer and attester slashing rewards instead of simply checking the cache because RewardCache
combines both into a single slashing
value. Will still need getPreStateSync()
for this PR
so it's no use to have
getPreStateSync()
The other two rewards endpoint (attestation and sync committee) both require preState
so we will need to have getPreStateSync()
implemented at some point. We can avoid getPreStateSync()
for this endpoint because we have block rewards cached in BeaconStateCache.proposerRewards: RewardCache
but that's not the case for the other endpoints.
@@ -71,6 +71,40 @@ export class QueuedStateRegenerator implements IStateRegenerator { | |||
return this.stateCache.get(stateRoot); | |||
} | |||
|
|||
getPreStateSync(block: allForks.BeaconBlock): CachedBeaconStateAllForks | null { |
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.
Please take a closer look at getPreStateSync()
and its usage. Pretty much moved the majority of getPreState()
to this function.
Looks to me checkpointStateCache.getLatest()
wouldn't trigger a reload in the absence of state.
@tuyennhv @wemeetagain @nflaig
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.
yes looks good to me
fix: clone states to compute block rewards
@wemeetagain Would love a second pass from you being merging this |
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.
my main concern about this endpoint triggering regen has been resolved
gave another review, LGTM
🎉 This PR is included in v1.17.0 🎉 |
* Add config route definitions * Add debug route definitions * Add events route description * Add lightclient route definitions * Flatten function params * Type safety for optional params in write / parse req * Method args are optional if only optional props * Fix genesisValidatorsRoot type issue * Revert requiring all params in write / parse req * Update http client errors * Add lodestar route definitions * Add node route definitions * Add proof route definitions * Add builder route definitions * Add validator route definitions * Application method response can be void * Generic options can be passed to application methods * Default endpoint request type has body property * Improve types of transform methods * Export server types from index (to be removed) * Update config api impl * Update lightclient api impl * Update events api impl * Update lodestar api impl * Update proof api impl * Update node api impl * Update debug api impl * Update state api impl * Update pool api impl * Update blocks api impl * Partially update validator api impl * Update beacon routes export * Align submitPoolBlsToExecutionChange method args * Filters are always a object * Update errors messages * Add beacon client methods * Add missing routeId label to stream time metric * Fix json casing in codecs * Apply remaining changes from #6227 * Produce block apis only have version meta * Add block values meta to all produce block apis * Apply changes from #6337 * Handle unsafe version in WithMeta and WithVersion * Restore server api error * Update fastify route types * Update server routes / handlers * Remove unnecessary type cast * Restore per route clients * Fix beacon route types * Remove option to patch fetch from http client * Update eventstream client, remove fetch override Fallback does not work like this, see #6180 for proper solution * Use StringType for validator status until #6059 * Remove empty fetch.ts file * Add a few todos * Update builder client and server routes * Update beacon exports * Update api index exports * Update builder index imports * Improve type safety of schema definitions * Add headers to fastify schema * Fix schema definition type * Add missing schemas to route definitions * Fix response codec type * Remove response codec type casts * Fix casing in json only codec * Reuse EmptyResponseCodec * Update base rest api server * Update keymanager routes, client and server * Reuse data types in keymanager impl * Do not await setting headers, not a promise * Improve type safety of empty codecs * Only require to implement supported req methods * Handle requests that only support one format * Handle responses that only support one format * Add json / ssz only req codecs * Update only support errors * Fix assertion * Set correct accept header if only supports one format * Fix eslint / prettier issues * More formatting fixes * Fix fallback request retries in case of http errors * Formatting of res.error * Add add retry functionality to http client (from #6387) * Update rewards routes and server (#6178 and #6260) * Allow to omit body in ssz req if not defined * Always set metadata headers in response * Cache wire format in api response * Only call raw body for json meta * Update api package tests (wip) * Test json and ssz format in generic server tests * Add a bunch of todos * Fix a few broken route definitions * Fix partial config test * Another todo note * Stringify body of json requests * Override default response json method * Validate external consensus version headers in request * Add error handling todo * Skip body schema validation for ssz request bodies * Clean up generic server tests * Pass node, proof, events generic tests * Use enum for media types * Fix a bunch of route definitions * Add justified to blockid type * Properly handle booleans, remove block values codec * Create Uint8Array test data without allocating Buffer * Let fastify handle Buffer conversion * Convert Buffer to Uint8Array in content type parser * Fix build issues * Fix fork type in builder routes * Add some notes * Properly parse request headers * Fix incorrect type assumptions in transform * Generic server tests are passing (except lightclient) * Correctly handle APIs with empty responses * Update getHeader return type to reflect no bid responses * Do not append '?' to URL if query string is empty * Let server handler set status code for parsing errors * Remove unused import * Rename function, request specific * Completely drop ssz support from getSpec * Spec tests are passing against latest releases * Drop unused fastify route config * Drop ssz request from builder routes, not yet supported * Remove import * Apply change from #6695 * Update execution optimistic meta * Apply changes from #6645 * Add workaround to fix epoch committees type issue * Add todo to fix inefficient state conversion * Convert committee to normal array * Apply changes from #6655 * Align args of validators endpoints * Convert indices to str in rewards apis * Update api spec version of README badges * Revert table formatting changes * Make this accessible for class-basd API implementations * Throw err if metadata is accessed for failed response * Add assertOk to api response * Tweak api error message * Update operationIds match spec value * Add missing version to blob sidecars metadata * Test headers and ssz bodies against spec * Minor reordering of code in spec parsing * submitBlindedBlock throws err if fork is not execution * responseOk might be undefined * Remove statusOk from route definition * Remove stale comment * Less build errors in beacon-node * getBlobSidecars return version from server impl * Update validator produce block impl * More expressive pool method args * Application methods might be undefined in mock implementations * Adress open TODOs in server handler * Api response methods are synchronous now * Fix all remaining build issues * Use more performant from/toHex in server api impls * Clean up some TODOs * Fix ApiError type * Errors related to parsing return a 400 status code * Simplify method binding * Forward api context to application methods * There is no easy way to make generic opts typesafe * Better separation of server / client code * Fix comment about missing builder bid * Remove todo, not worth the change / extra indentation * Rename route definitions functions * Return 400 if data passed to keymanager is invalid * Properly handle response metadata headers * Fix lint issues * Add header jsdoc * Move metadata related code into separate file * Remove ssz from POST requests without body * Only set content-type header if body exists * Fix headers extra * POST requests without body are handled similar to GET requests * Fix http client options tests * Improve validation and type safety of JSON metadata * Add type guard for request without body * Differentiate based on body instead of GET vs POST * More renaming * Simplify RequestCode type * Review routes, improve validation * Remaining local diff * Fix accept header handling if only support one wire format * Update 406 error to more closely match spec example * Enforce version header via custom check instead of schema * Use ssz as default request wire format * Log failure to receive head event to verbose * Do not set default value for context * Update getClient return type to better align with method name * Consistent pattern to get route definitions * Dedupe api client type for builder and keymanager * Fix fallback logic if server returns http error * Update head event error logging * Retry 415 errors with JSON and cache SSZ not supported * Use fetch spy to assert call times * Update comment * Update getLightClientUpdatesByRange endpoint meta * Do not forward ssz bytes of blinded block to publishBlock * Fix lightclient e2e tests * Version header in publishBlock api is optional * Reduce type duplication * Add option to override request init in route definition * Add JsonOnlyResp codec * Validate boolean str value from headers * Document default wire formats * Simplify merging of inits in http client * Remove type hacks from fetchBeaconHealth * Reduce call stack in http client * Add .ssz() equivalent method for json to api response * More http client tests * Ensure topics query is provided to eventstream api * Validate request content type in handler Fastify does not cover all edge cases * Review routes, fix param docs, no empty comments * Fix typo * Add note about builder spec not supporting ssz * Consistently move keymanager jsdoc to routes * Sanitize user provided init values before merging * Remove unused ssz only codec * Allow passing wire formats as string literals * chore: review proof routes (#6843) Review proof routes * chore: review lightclient routes (#6842) Review lightclient routes * chore: review node routes (#6844) Review node routes * feat: add cli flags to configure http wire format (#6840) * Review PR, mostly cosmetic changes * Fix event stream error handling --------- Co-authored-by: Cayman <caymannava@gmail.com>
Description
Introduce a beacon API endpoint to return block reward info according to the spec. This is one of the three reward endpoints mentioned in #5694
Note that the endpoint currently only supports Altair block or later. Attempts to query for phase0 block will return error.
TODO
Will open follow-up PRs for:
finalized
property to the reward response mentioning in Addfinalized
property to HTTP API responses #5693 which is currently blockedSteps to test or reproduce