diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs index 02ebe93ce25..0f3af171eb9 100644 --- a/crates/sdk/src/error.rs +++ b/crates/sdk/src/error.rs @@ -183,6 +183,15 @@ pub enum TxSubmitError { /// No bonds found #[error("No bonds found")] NoBondFound, + /// No delegations found at epoch + #[error("The account {0} has no active delegations found at epoch {1}")] + NoDelegationsFound(Address, Epoch), + /// Cannot vote in governance + #[error( + "Validator {0} cannot vote in governance because the validator is \ + either jailed or inactive at the current epoch {1}" + )] + CannotVoteInGovernance(Address, Epoch), /// Lower bond amount than the unbond #[error( "The total bonds of the source {0} is lower than the amount to be \ diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index e4320bd9616..28b90e68bd7 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -1961,6 +1961,26 @@ pub async fn build_vote_proposal( let is_validator = rpc::is_validator(context.client(), voter_address).await?; + // Prevent jailed or inactive validators from voting + if is_validator && !tx.force { + let state = rpc::get_validator_state( + context.client(), + voter_address, + Some(current_epoch), + ) + .await?; + if matches!( + state, + Some(ValidatorState::Jailed) | Some(ValidatorState::Inactive) + ) { + return Err(Error::from(TxSubmitError::CannotVoteInGovernance( + voter_address.clone(), + current_epoch, + ))); + } + } + + // Check if the voting period is still valid for the voter if !proposal.can_be_voted(current_epoch, is_validator) { if tx.force { eprintln!("Invalid proposal {} vote period.", proposal_id); @@ -1971,20 +1991,38 @@ pub async fn build_vote_proposal( } } - let delegations = rpc::get_delegations_of_delegator_at( + // Get active valid validators with whom the voter has delegations (bonds) + let delegation_vals = rpc::get_delegation_validators( context.client(), voter_address, proposal.voting_start_epoch, ) - .await? - .keys() - .cloned() - .collect::>(); - - if delegations.is_empty() { - return Err(Error::Other( - "Voter address must have delegations".to_string(), - )); + .await?; + + let mut delegation_validators = Vec::
::new(); + for validator in delegation_vals { + let val_state = rpc::get_validator_state( + context.client(), + &validator, + Some(current_epoch), + ) + .await + .expect("Expected to find the state of the validator"); + if !matches!( + val_state, + Some(ValidatorState::Jailed) | Some(ValidatorState::Inactive) + ) { + continue; + } + delegation_validators.push(validator); + } + + // Check that there are delegations to vote with + if delegation_validators.is_empty() && !tx.force { + return Err(Error::from(TxSubmitError::NoDelegationsFound( + voter_address.clone(), + current_epoch, + ))); } let data = VoteProposalData {