-
Notifications
You must be signed in to change notification settings - Fork 956
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
Add Ethereum secp keys to validators #471
Add Ethereum secp keys to validators #471
Conversation
still missing some VP stuff, will make this a draft PR again |
@james-chf feel free to leave a review, if you have time. what's blocking this PR right now are some changes to VPs, which will unify the native and wasm interfaces #318. after that is more or less done, in |
This PR has code from another PR + some new Ethereum-bridge specific logic, this would be easier to review in separate stacked PRs (though not worth splitting out now) I can't test this locally yet as I need to update my way of generating a devchain to work with the new Tendermint v0.38.x, but I'll do that soon. Then I can test this altogether (maybe after it has merged to |
&mut self, | ||
address: &Self::Address, | ||
value: &types::ValidatorEthKey<Self::PublicKey>, | ||
) { |
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 realize the rest of the API is similar to this currently, but it'd be good to return a Result
type rather than .unwrap()
ping, since self.write
can error
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.
yeah this is more of a general issue outside of this PR, idk if @tzemanovic wants to pitch in on 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.
In general, yes agree that it'd be better. We didn't worry about this too much for now in here as this is inside PosBase
and these methods are only used by the protocol to init chain. If we return an error from, it would still crash further up the stack - the API of PoS crate could do some bigger refactors in general, but for now it's not a high priority
fn read_validator_eth_cold_key( | ||
&self, | ||
key: &Self::Address, | ||
) -> Option<types::ValidatorEthKey<Self::PublicKey>> { | ||
let value = | ||
self.ctx.read_pre(&validator_eth_cold_key_key(key)).unwrap(); | ||
value.map(|value| decode(value).unwrap()) | ||
} | ||
|
||
fn read_validator_eth_hot_key( | ||
&self, | ||
key: &Self::Address, | ||
) -> Option<types::ValidatorEthKey<Self::PublicKey>> { | ||
let value = self.ctx.read_pre(&validator_eth_hot_key_key(key)).unwrap(); | ||
value.map(|value| decode(value).unwrap()) | ||
} |
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.
When should we expect read_validator_eth_cold_key
/read_validator_eth_hot_key
to return None
instead of Some(...)
? It feels like this API could directly return a ValidatorEthKey<Self::PublicKey>
(or better, Result<ValidatorEthKey<Self::PublicKey>>
), if it's the case that all validators must have Eth keys going forwards
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.
it can happen if we are a fullnode, for instance
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.
Even for a full node, we are reading the validator's key from blockchain state (self.ctx.read_pre
) when executing this VP, so these two funcs should work the same for full nodes and validators? I guess returning an Option
here follows the pattern of other methods here for the time being
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.
at type level key: &Self::Address
can be any address, so this would be None
if the given address is not a validator address. If we know we're calling it with validator addresses only, we can expect that those are always Some
impl | ||
namada_proof_of_stake::types::TryRefTo< | ||
namada_proof_of_stake::types::EthAddress, | ||
> for common::PublicKey | ||
{ |
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.
How come we have this TryRefTo
trait (impl TryRefTo<T> for U
)? It looks like it's trying to achieve the same thing as impl TryInto<U> for &T
which would be more standard, couldn't we use 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.
me and tomas had a whole coding session where we tried (and successfully!) managed to implement TryFrom
, but the code in the proof_of_stake
crate looked hideous and unmaintainable with it, because of lifetime issues with references. in short, it's not worth using TryInto
.
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.
pretty sure this is the same reason why we have a RefTo
trait lying around
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.
Ah interesting, it'd be nice if we could use TryInto
but I haven't see what the code looks like with using that, if it means lifetimes everywhere
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.
yeah, we had to specify pretty funky bounds on the PoS traits that use an associated types for the public key to get it to work, so this was actually lot cleaner
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.
still, same as the other thing, the way PoS traits are implemented could use a bigger refactor that would alleviate this
@@ -287,16 +289,28 @@ impl Store { | |||
/// | |||
/// Note that this removes the validator data. | |||
pub fn gen_validator_keys( | |||
eth_bridge_keypair: Option<common::SecretKey>, |
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 ultimately needs to be a namada::types::key::secp256k1::SecretKey
, we should refactor at some point to accept namada::types::key::secp256k1::SecretKey
rather than common::SecretKey
. In general, I think we have places where we are using common::{SecretKey, PublicKey}
where we should be constraining to the a more specific type (as not all schemes make sense)? We should only use those enum types where the function can or should accept both imo
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.
yeah agreed. it forces you to return Option
or Return
types, which makes APIs more convoluted to use in the end.
fn get_ethbridge_from_namada_addr( | ||
&self, | ||
validator: &Address, | ||
epoch: Option<Epoch>, | ||
) -> Option<EthAddress> { |
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.
It would be clearer to return a Result
here instead of Option
- it looks like we return None
in the case where read_validator_eth_hot_key
returns None
, so it sort of goes back to that. Would we ever expect this to return None
, or would that indicate an error?
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.
same issue as above, it can return None
if we are a fullnode.
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.
like we discussed in our call, the Shell<...>
should take an extra parameterNodeTag
to distinguish between different node kinds, and only implement methods like prepare_proposal
e.g. if we are a NodeTag = Validator
. this would also obviate the need to error out from methods like get_ethbridge_from_namada_addr
, unless we actually got some storage reading error.
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.
Yeah that sounds like a good approach, have opened #521
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.
lgtm to merge!
8d7b66f
to
c285b74
Compare
pls update wasm |
Finalizes the implementation of the 8th item of issue no. #242
This PR adds Ethereum secp keys to genesis validators, and also finalizes the validation code for valset upd vote extensions.
We integrate changes from #371
Missing in this PR: Proof-of-stake VP changes, centered around verifying Ethereum secp keys in storage. This can be addressed in a future PR.