-
Notifications
You must be signed in to change notification settings - Fork 651
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
refactor: Wrap validator_signer with MutableConfigValue #11372
Conversation
Can you give a bit more context for this change? What is the benefit we get to wrap them in MutableConfigValue? it this prep for another change? thanks. |
Yes, it is prep for another change. Part of #11264. |
Ah ok, makes sense, thanks. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #11372 +/- ##
========================================
Coverage 71.37% 71.38%
========================================
Files 790 790
Lines 160086 160243 +157
Branches 160086 160243 +157
========================================
+ Hits 114256 114384 +128
- Misses 40857 40886 +29
Partials 4973 4973
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
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
@@ -146,7 +148,7 @@ pub struct Client { | |||
/// Network adapter. | |||
pub network_adapter: PeerManagerAdapter, | |||
/// Signer for block producer (if present). | |||
pub validator_signer: Option<Arc<dyn ValidatorSigner>>, | |||
pub validator_signer: MutableConfigValue<Option<Arc<ValidatorSigner>>>, |
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.
@staffik Can you tell me briefly how will that work here? The MutableConfigValue today checks the contents of the config file. The validator key is stored in a different file though, will that work out of the box or do you need to make any extra changes there?
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 we just wrap with MutableConfigValue
and it does not update validator key. In the follow up PR we add a logic that updates the validator key based on appropriate file.
@@ -37,12 +37,12 @@ impl<T: Serialize> Serialize for MutableConfigValue<T> { | |||
} | |||
} | |||
|
|||
impl<T: Copy + PartialEq + Debug> MutableConfigValue<T> { | |||
impl<T: Clone + PartialEq + Debug> MutableConfigValue<T> { |
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.
Would it make sense to make the validator key Copy-able rather than this change?
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 tried but I found it better to relax the Copy
requirement and use Clone
instead. Reasons:
- it would require making Copy-able:
AccountId
- which is considered stable and would require making a new release in separate repo. Perhaps there is a reason why it is non-Copy-able and it would not be possible to make it Copy-able anyway.PublicKey
,SecretKey
,ED25519PublicKey
,ED25519SecretKey
- and possibly more
Copy
is for better perfomance but here we just reload simple structs rarely.- If we want to add non-Copy-able field in the future we would have to do this change anyway.
core/crypto/src/signer.rs
Outdated
/// Generic signer trait, that can sign with some subset of supported curves. | ||
pub trait Signer: Sync + Send { | ||
fn public_key(&self) -> PublicKey; | ||
fn sign(&self, data: &[u8]) -> Signature; | ||
#[derive(Debug, PartialEq)] | ||
pub enum Signer { |
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.
Can you update the comment please? It's no longer a trait.
core/crypto/src/signer.rs
Outdated
Empty(EmptySigner), | ||
InMemory(InMemorySigner), |
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.
Can you add short comments about those signers?
let signer: Signer = | ||
InMemorySigner::from_random("test".parse().unwrap(), KeyType::ED25519).into(); |
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.
Instead of into() would it make sense to have the constructors of InMemorySigner and EmptySigner return Signer? If access to the inner enum value is needed you can expose that via new methods. Same for Signer and ValidatorSigner.
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 thought about it but account_id
field does not exist in EmptySigner
.
We could return empty string or unimplemented
for EmptySigner
but this code path should never be called anyway.
I have no strong opinion, looks like doing what you said would simplify this PR, I will try it out, thanks!
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 spent a while trying to get rid of into()
, but it was not straightforward. There are some places that use members like secret_key
. I would rather do it as a follow up PR.
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.
Will do it as a separate issue: #11531
#[derive(Clone, Debug, PartialEq)] | ||
pub enum ValidatorSigner { | ||
Empty(EmptyValidatorSigner), | ||
InMemory(InMemoryValidatorSigner), | ||
} | ||
|
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 add comments for the struct and the values.
@staffik Looking at the last commits it seems like those only address nits and add comment. Please let me know if you need a fresh review and of what exactly, otherwise my old approval still stands. |
Issue: #11264 This is follow-up to #11372. The actual changes (+test) for #11264 will be done in a third, final PR: #11536. ### Summary This PR should mostly be no-op. It focuses on propagating `MutableConfigValue` for `validator_signer` everywhere. All instances of mutable `validator_signer` are synchronized. In case validator_id only is needed, we propagate `validator_signer` anyway as it contains the current validator info. ### Extra changes - Remove signer as a field and pass to methods instead: `Doomslug`, `InfoHelper`, `ChunkValidator`. - Make some public methods internal where they do not need to be public. - Split `process_ready_orphan_witnesses_and_clean_old` into two functions. - Removed `block_production_started` from `ClientActorInner`. - Add `FrozenValidatorConfig` to make it possible to return a snapshot of `ValidatorConfig`. --------- Co-authored-by: Your Name <you@example.com>
Issue: #11264 This PR build on: * #11372 * #11400 and contains actual changes and test for validator key hot swap. ### Summary - Extend `UpdateableConfig` with validator key. - Update client's mutable validator key when we detect it changed in the updateable config. - Advertise our new validator key through `advertise_tier1_proxies()`. - Add integration test for the new behaviour: - We start with 2 validating nodes (`node0`, `node1`) and 1 non-validating node (`node2`). It is important that the non-validating node tracks all shards, because we do not know which shard it will track when we switch validator keys. - We copy validator key from `node0` to `node2`. - We stop `node0`, then we trigger validator key reload for `node2`. - Now `node2` is a validator, but it figures out as `node0` because it copied validator key from `node0`. - We wait for a couple of epochs and we require that both remaining nodes progress the chain. Both nodes should be synchronised after a few epochs. Test with: ``` cargo build -pneard --features test_features,rosetta_rpc && cargo build -pgenesis-populate -prestaked -pnear-test-contracts && python3 pytest/tests/sanity/validator_switch_key_quick.py ``` #### Extra changes: - Use `MutableValidatorSigner` alias instead of `MutableConfigValue<Option<Arc<ValidatorSigner>>>` - Return `ConfigUpdaterResult` from config updater. - Remove (de)serialization derives for `UpdateableConfigs`. - --------- Co-authored-by: Your Name <you@example.com>
Part of: #11264 This PR should be no-op: - convert `Signer` and `ValidatorSigner` traits into an enum - wrap `ValidatorSigner` with `MutableConfigValue` `MutableConfigValue` requires to implement `PartialEq` and `Clone` traits. These traits are not object safe, thus cannot be derived for `ValidatorSigner` trait. We need to convert `ValidatorSigner` trait into an enum, similarly `Signer` trait. That's also the solution recommended by Rust: rust-lang/rust#80194 Unfortunately, this change requires a change in enormous number of places, because the existing code mostly used `InMemory(Validator)Signer` directly instead of `dyn (Validator)Signer`. To minimize changes, I added traits like `From<InMemoryValidatorSigner> for ValidatorSigner` so that it suffices to add `.into()` in most cases.
Issue: #11264 This is follow-up to #11372. The actual changes (+test) for #11264 will be done in a third, final PR: #11536. This PR should mostly be no-op. It focuses on propagating `MutableConfigValue` for `validator_signer` everywhere. All instances of mutable `validator_signer` are synchronized. In case validator_id only is needed, we propagate `validator_signer` anyway as it contains the current validator info. - Remove signer as a field and pass to methods instead: `Doomslug`, `InfoHelper`, `ChunkValidator`. - Make some public methods internal where they do not need to be public. - Split `process_ready_orphan_witnesses_and_clean_old` into two functions. - Removed `block_production_started` from `ClientActorInner`. - Add `FrozenValidatorConfig` to make it possible to return a snapshot of `ValidatorConfig`. --------- Co-authored-by: Your Name <you@example.com>
Issue: #11264 This PR build on: * #11372 * #11400 and contains actual changes and test for validator key hot swap. ### Summary - Extend `UpdateableConfig` with validator key. - Update client's mutable validator key when we detect it changed in the updateable config. - Advertise our new validator key through `advertise_tier1_proxies()`. - Add integration test for the new behaviour: - We start with 2 validating nodes (`node0`, `node1`) and 1 non-validating node (`node2`). It is important that the non-validating node tracks all shards, because we do not know which shard it will track when we switch validator keys. - We copy validator key from `node0` to `node2`. - We stop `node0`, then we trigger validator key reload for `node2`. - Now `node2` is a validator, but it figures out as `node0` because it copied validator key from `node0`. - We wait for a couple of epochs and we require that both remaining nodes progress the chain. Both nodes should be synchronised after a few epochs. Test with: ``` cargo build -pneard --features test_features,rosetta_rpc && cargo build -pgenesis-populate -prestaked -pnear-test-contracts && python3 pytest/tests/sanity/validator_switch_key_quick.py ``` #### Extra changes: - Use `MutableValidatorSigner` alias instead of `MutableConfigValue<Option<Arc<ValidatorSigner>>>` - Return `ConfigUpdaterResult` from config updater. - Remove (de)serialization derives for `UpdateableConfigs`. - --------- Co-authored-by: Your Name <you@example.com>
Part of: #11264
This PR should be no-op:
Signer
andValidatorSigner
traits into an enumValidatorSigner
withMutableConfigValue
MutableConfigValue
requires to implementPartialEq
andClone
traits. These traits are not object safe, thus cannot be derived forValidatorSigner
trait. We need to convertValidatorSigner
trait into an enum, similarlySigner
trait.That's also the solution recommended by Rust: rust-lang/rust#80194
Unfortunately, this change requires a change in enormous number of places, because the existing code mostly used
InMemory(Validator)Signer
directly instead ofdyn (Validator)Signer
.To minimize changes, I added traits like
From<InMemoryValidatorSigner> for ValidatorSigner
so that it suffices to add.into()
in most cases.