-
Notifications
You must be signed in to change notification settings - Fork 13
Add era summary endpoint #147
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
Conversation
message ReadEraSummaryRequest { | ||
} |
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 don't know what you want as a convention when the request is empty. Should it be an empty object (like here), or just omit this entirely?
@@ -135,7 +147,8 @@ service QueryService { | |||
rpc ReadUtxos(ReadUtxosRequest) returns (ReadUtxosResponse); // Read specific UTxOs by reference. | |||
rpc SearchUtxos(SearchUtxosRequest) returns (SearchUtxosResponse); // Search for UTxO based on a pattern. | |||
rpc ReadData(ReadDataRequest) returns (ReadDataResponse); // Read specific datum by hash | |||
rpc ReadTx(GetTxRequest) returns (GetTxResponse); // Get Txs by by chain-specific criteria. | |||
rpc ReadTx(ReadTxRequest) returns (ReadTxResponse); // Get Txs by chain-specific criteria. |
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 noticed ReadTx
was wrong causing a compiler error (it used the wrong name for the request & response types - there is no type called GetTxRequest
)
// a lot of tools expect a string name (ex: "shelley") to look up era info | ||
EraBoundary start = 1; // start of this era | ||
EraBoundary end = 2; // end of this era (if the era has a well-defined ending) | ||
// TODO: do we want a summary of parameter changed? |
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 left this out since I don't think this is required to unblock the core value proposition of this feature (and it's maybe harder to implement for nodes). Notably, if we add the era name
identifier I mention above, we can get the parameters directly from the node/file
I'm open to thoughts on how the structure of including parameter changes here would work though if anybody has a preference. Some things I noticed:
- It doesn't seem BlockFrost gives you all the parameters, just the relevant ones (do we want to do something similar? It's a bit arbitrary)
- Now with dReps, parameters can change through onchain votes, and so are no longer constrained to epoch boundaries
If nobody has any thoughts on this, we can just leave it out for now. My feeling is that we'll probably end up with another set of endpoints to
- Get the genesis file for an era by name
- Get a list of all parameter updates (which can include those triggered by eras and those triggered by onchain actions)
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 since added a ReadEraConfig
endpoint which partially alleviates the issue (it doesn't handle parameters that change through governance, but it's a start and still useful)
uint64 time = 1; // ms timestamp | ||
uint64 slot = 2; // absolute slot number of the first block of this era | ||
uint64 epoch = 3; // first epoch for this era | ||
optional bytes hash = 4; // block hash of the first block of this era (if the era has started) |
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.
This is maybe the main controversial part of this PR
Having a hash
here helps, because it means you can use it to construct a ChainPoint
. If you only get a slot
and nothing else, you can't do anything with it in utxorpc
However, I'm not sure if nodes keep track of this information, or how easy it is to support this. The hard part mostly comes with dealing with eras that haven't started/ended yet (see #144 (comment))
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.
We don't track this in Dingo, but we could. Is that tracked in the Haskell node? It might not work in cardano-node-api's implementation, but that happens sometimes and we consider it acceptable if the Haskell node doesn't give a way.
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 other alternative is that we could change the endpoints that accept a ChainPoint
to instead allow simply passing in a slot number (with no hash required)
It depends if the hash
field in ChainPoint
is used for performance reasons, or if it's just used to avoid rollbacks (i.e. ensure the slot number really is the hash you expect)
But if we can get away with just using slot
only, not only is the API easier to work with, it also solves the issue here (since we would no longer need the hash)
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 created an issue to track the alternative solution to this where only slots are required for ChainPoint
: #148
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 also added a new ReadChainId
endpoint to this PR so we can get the genesis hash for Byron. Of course, getting the hash for other eras (notably Shelley) would be nice, but getting the Byron genesis hash already unblocks multiple cases
63ce556
to
67ca37c
Compare
gen/docs/docs.md
Outdated
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 doc file looks like it was out of date. It contains my changes, but other changes up until now too
// TODO: do we want any kind of "era name" identifier? | ||
// a lot of tools expect a string name (ex: "shelley") to look up era info |
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.
(edit: I ended up adding the name as a field)
My feeling is we should probably add this, but open to thoughts.
The rationale is that the EraSummary
endpoint does not actually tell you the protocol parameters for this era. Rather, you have to query a node (or read from a disk) the right genesis file to get the full data. However, these fields & endpoints use a string name (ex: shelley
) as the identifier, so having a string here would help fetch this info
The alternative, if there is no name, is that clients would have to hardcode it (ex: the first "summary" is for "shelley"), but this is boilerplate and also error-prone (you have to remember to update this mapping every hardfork)
Notably, this is used in cooperation with the new ReadEraConfig
endpoint
} | ||
|
||
message EraConfig { | ||
google.protobuf.Struct config = 1; |
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.
Here I used the Struct
type since one of the recommended ways to deal with JSON (which Cardano genesis files use). However, the generated code for this is pretty verbose (it's not just a JSON object)
The other alternative is to just make the type be string
(then people can use it with a JSON parser of their choice). I'm open to either option
// Response containing the summary of eras | ||
message ReadChainIdResponse { | ||
bytes genesis = 1; // genesis hash for the chain | ||
string caip2 = 2; // the caip-2 ID for this network |
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.
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 wonder if we should add a "name" field
Tentatively, I think not because nodes like Cardano don't expose a "name" field so it would probably end up being annoying to deal with
rpc ReadEraSummary(ReadEraSummaryRequest) returns (ReadEraSummaryResponse); // Get summary of all eras | ||
rpc ReadEraConfig(ReadEraConfigRequest) returns (ReadEraConfigResponse); // Get configuration for an era | ||
rpc ReadChainId(ReadChainIdRequest) returns (ReadChainIdResponse); // Get the chain ID for this network |
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.
@SebastienGllmt do we need to split this three concerns into different methods?
I feel that many of these calls would probably go together in most scenarios and having them separated would make the interface too chatty.
Maybe having something like a single ReadChain
method and rely on a nested structure that we can filter using field_masks.
Something like:
- chain
- genesis
- caip2
- eras[]
- name
- start
- end
- config
What are your thoughts?
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'm totally fine with that as well
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.
@scarmuega how do you want to do the field mask for config
given it's nested in the eras
array?
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.
Let me know if #151 is what you were thinking of
Closes #144
EDIT: likely deprecated, and this PR is instead replaced by #151