Skip to content
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

Not finished voting can be cancelled after set time #194

Merged
merged 2 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion dao/src/bid_escrow/bid_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
extern crate alloc;

use crate::bid_escrow::bid::{Bid, BidStatus, CancelBidRequest, SubmitBidRequest};
#[allow(unused_imports)]
use crate::bid_escrow::events::CSPRTransfer;
use crate::bid_escrow::events::{
BidCancelled, BidSubmitted, CSPRTransfer, JobCreated, JobOfferCreated, TransferReason,
BidCancelled, BidSubmitted, JobCreated, JobOfferCreated, TransferReason,
};
use crate::bid_escrow::job::{Job, PickBidRequest};
use crate::bid_escrow::job_offer::{CancelJobOfferRequest, JobOffer, PostJobOfferRequest};
Expand Down
25 changes: 25 additions & 0 deletions dao/src/bid_escrow/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,29 @@ impl BidEscrowContract {
affected_votings,
}
}

/// Cancels a voting that has not been finished in defined time
///
/// # Errors
/// * [crate::utils::Error::VotingDoesNotExist]
/// * [crate::utils::Error::VotingWithGivenTypeNotInProgress]
/// * [crate::utils::Error::FinishingCompletedVotingNotAllowed]
/// * [crate::utils::Error::VotingNotStarted]
/// * [crate::utils::Error::VotingAlreadyFinished]
/// * [crate::utils::Error::VotingAlreadyCancelled]
pub fn cancel_finished_voting(&mut self, voting_id: VotingId) {
// cancel voting
self.voting_engine.cancel_finished_voting(voting_id);

// return cspr
let mut job = self.job_storage.get_job_by_voting_id(voting_id);
self.job_engine.return_job_poster_payment_and_dos_fee(&job);
if job.external_worker_cspr_stake() > 0.into() {
self.job_engine.return_external_worker_cspr_stake(&job);
}

// cancel and save job
job.cancel();
self.job_storage.store_job(job);
}
}
5 changes: 3 additions & 2 deletions dao/src/bid_escrow/job_engine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Job Engine module.
use crate::bid_escrow::bid::{Bid, ReclaimBidRequest};
#[allow(unused_imports)]
use crate::bid_escrow::events::{
BidEscrowVotingCreated, CSPRTransfer, JobCancelled, JobDone, JobRejected, JobSubmitted,
TransferReason,
Expand Down Expand Up @@ -416,7 +417,7 @@ impl JobEngine {
.burn(job.worker(), amount_to_burn);
}

fn return_job_poster_payment_and_dos_fee(&mut self, job: &Job) {
pub fn return_job_poster_payment_and_dos_fee(&mut self, job: &Job) {
let job_offer = self
.bid_storage
.get_job_offer_or_revert(&job.job_offer_id());
Expand All @@ -427,7 +428,7 @@ impl JobEngine {
);
}

fn return_external_worker_cspr_stake(&mut self, job: &Job) {
pub fn return_external_worker_cspr_stake(&mut self, job: &Job) {
withdraw(
&job.worker(),
job.external_worker_cspr_stake(),
Expand Down
4 changes: 4 additions & 0 deletions dao/src/configuration/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ impl ConfigurationBuilder {
formal_quorum_ratio: get_variable(FORMAL_QUORUM_RATIO, variables),
bid_escrow_payment_ratio: get_variable(BID_ESCROW_PAYMENT_RATIO, variables),
voting_ids_address: get_variable(VOTING_IDS_ADDRESS, variables),
cancel_finished_voting_timeout: get_variable(
CANCEL_FINISHED_VOTING_TIMEOUT,
variables,
),
},
VotingConfiguration {
is_bid_escrow: false,
Expand Down
1 change: 1 addition & 0 deletions dao/src/configuration/dao_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ pub struct DaoConfiguration {
pub voting_start_after_job_worker_submission: BlockTime,
pub bid_escrow_payment_ratio: Balance,
pub voting_ids_address: Address,
pub cancel_finished_voting_timeout: BlockTime,
}
4 changes: 4 additions & 0 deletions dao/src/configuration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ impl Configuration {
Err(Error::FiatRateNotSet)
}
}

pub fn cancel_finished_voting_timeout(&self) -> BlockTime {
self.dao_configuration.cancel_finished_voting_timeout
}
}

pub fn get_variable<T: OdraType>(key: &str, variables: &BTreeMap<String, Bytes>) -> T {
Expand Down
1 change: 1 addition & 0 deletions dao/src/modules/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ impl Default for RepositoryDefaults {
259200000u64,
);
items.push(consts::BID_ESCROW_PAYMENT_RATIO, Balance::from(100));
items.push(consts::CANCEL_FINISHED_VOTING_TIMEOUT, 2592000000u64);
kubaplas marked this conversation as resolved.
Show resolved Hide resolved
items
}
}
Expand Down
12 changes: 12 additions & 0 deletions dao/src/onboarding/voting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ impl Onboarding {
);
}

pub fn return_cspr(&mut self, voting_id: VotingId) {
let request = self
.requests
.get(&voting_id)
.unwrap_or_revert_with(Error::OnboardingRequestNotFound);
withdraw(
&request.creator(),
request.cspr_deposit(),
TransferReason::OnboardingStakeReturn,
);
}

fn on_informal_voting_finished(&mut self, _voting_id: VotingId) {}

fn on_formal_voting_in_favor(&mut self, voting_id: VotingId, request: &Request) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::configuration::Configuration;
use crate::rules::validation::VotingValidation;
use crate::utils::Error;
use crate::voting::voting_engine::voting_state_machine::{VotingState, VotingStateMachine};
use macros::Rule;
use odra::types::BlockTime;

/// Verifies if the voting can be cancelled. May return [Error::FinishingCompletedVotingNotAllowed].
#[derive(Rule)]
pub struct FinishedVotingCanBeCancelled {
block_time: BlockTime,
}

impl VotingValidation for FinishedVotingCanBeCancelled {
fn validate(
&self,
voting_state_machine: &VotingStateMachine,
configuration: &Configuration,
) -> Result<(), Error> {
// shorthand for checking if block_time > voting_end_time + cancel_finished_voting_timeout
if voting_state_machine.state_in_time(
kubaplas marked this conversation as resolved.
Show resolved Hide resolved
self.block_time - configuration.cancel_finished_voting_timeout(),
configuration,
) == VotingState::Finished
{
return Ok(());
}

Err(Error::VotingCannotBeCancelledYet)
}
}
2 changes: 2 additions & 0 deletions dao/src/rules/validation/voting/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Groups voting related validations.
mod after_formal_voting;
mod can_create_voting;
mod finished_voting_can_be_cancelled;
mod vote_in_time;
mod voting_not_completed;

pub use after_formal_voting::AfterFormalVoting;
pub use can_create_voting::CanCreateVoting;
pub use finished_voting_can_be_cancelled::FinishedVotingCanBeCancelled;
pub use vote_in_time::VoteInTime;
pub use voting_not_completed::VotingNotCompleted;
2 changes: 2 additions & 0 deletions dao/src/utils/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ pub const VOTING_START_AFTER_JOB_WORKER_SUBMISSION: &str = "VotingStartAfterJobS
pub const DEFAULT_REPUTATION_SLASH: &str = "DefaultReputationSlash";
/// An address of a contract that generates a next voting id.
pub const VOTING_IDS_ADDRESS: &str = "VotingIdsAddress";
/// Amount of time after formal voting end, when it can be cancelled
pub const CANCEL_FINISHED_VOTING_TIMEOUT: &str = "CancelFinishedVotingTimeout";

/// Contract keys.
pub const CONTRACT_MAIN_PURSE: &str = "__contract_main_purse";
1 change: 1 addition & 0 deletions dao/src/utils/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ execution_error! {
FormalVotingNotCompleted => 2110,
InformalVotingNotStarted => 2111,
ConfigurationNotFound => 2112,
VotingCannotBeCancelledYet => 2113,
VaOnboardedAlready => 2201,
OnboardingAlreadyInProgress => 2202,
NotOnboarded => 2203,
Expand Down
1 change: 1 addition & 0 deletions dao/src/utils/variable_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ impl VariableType {
| FORMAL_VOTING_TIME
| TIME_BETWEEN_INFORMAL_AND_FORMAL_VOTING
| VA_BID_ACCEPTANCE_TIMEOUT
| CANCEL_FINISHED_VOTING_TIMEOUT
| VOTING_START_AFTER_JOB_WORKER_SUBMISSION => VariableType::BlockTime,
FIAT_CONVERSION_RATE_ADDRESS | BID_ESCROW_WALLET_ADDRESS | VOTING_IDS_ADDRESS => {
VariableType::Address
Expand Down
8 changes: 8 additions & 0 deletions dao/src/voting/voting_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ impl VotingEngine {
summary
}

/// Cancels finished voting if CancelFinishedVotingTimeout has passed.
pub fn cancel_finished_voting(&mut self, voting_id: VotingId) {
let voting = self.get_voting_or_revert(voting_id);
let configuration = self.get_configuration_or_revert(voting_id);
voting.guard_cancel_finished_voting(get_block_time(), &configuration);
self.cancel_voting(voting);
}

/// Marks voting finished but do nothing with the staked reputation.
///
/// # Errors
Expand Down
16 changes: 15 additions & 1 deletion dao/src/voting/voting_engine/voting_state_machine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Voting State Machine.
use crate::configuration::Configuration;
use crate::rules::validation::voting::{AfterFormalVoting, VoteInTime, VotingNotCompleted};
use crate::rules::validation::voting::{
AfterFormalVoting, FinishedVotingCanBeCancelled, VoteInTime, VotingNotCompleted,
};
use crate::rules::RulesBuilder;
use crate::voting::ballot::Choice;
use crate::voting::types::VotingId;
Expand Down Expand Up @@ -359,6 +361,18 @@ impl VotingStateMachine {
.build()
.validate(self, configuration);
}

pub fn guard_cancel_finished_voting(
&self,
block_time: BlockTime,
configuration: &Configuration,
) {
RulesBuilder::new()
.add_voting_validation(VotingNotCompleted::create())
.add_voting_validation(FinishedVotingCanBeCancelled::create(block_time))
.build()
.validate(self, configuration);
}
}

/// Voting statistics.
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl AdminContract {
) -> Option<Ballot>;
pub fn get_voter(&self, voting_id: VotingId, voting_type: VotingType, at: u32) -> Option<Address>;
pub fn finish_voting(&mut self, voting_id: VotingId, voting_type: VotingType) -> VotingSummary;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/kyc_voter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl KycVoterContract {
address: Address,
) -> Option<Ballot>;
pub fn get_voter(&self, voting_id: VotingId, voting_type: VotingType, at: u32) -> Option<Address>;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
17 changes: 17 additions & 0 deletions dao/src/voting_contracts/onboarding_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,23 @@ impl OnboardingRequestContract {
self.access_control.ensure_whitelisted();
self.voting.slash_voter(voter)
}

/// Cancels a voting that has not been finished in defined time
///
/// # Errors
/// * [crate::utils::Error::VotingDoesNotExist]
/// * [crate::utils::Error::VotingWithGivenTypeNotInProgress]
/// * [crate::utils::Error::FinishingCompletedVotingNotAllowed]
/// * [crate::utils::Error::VotingNotStarted]
/// * [crate::utils::Error::VotingAlreadyFinished]
/// * [crate::utils::Error::VotingAlreadyCancelled]
pub fn cancel_finished_voting(&mut self, voting_id: VotingId) {
// return cspr
self.onboarding.return_cspr(voting_id);

// cancel voting
self.voting.cancel_finished_voting(voting_id);
}
}

/// Event emitted when onboarding voting has been created.
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/repo_voter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl RepoVoterContract {
) -> Option<Ballot>;
pub fn get_voter(&self, voting_id: VotingId, voting_type: VotingType, at: u32) -> Option<Address>;
pub fn finish_voting(&mut self, voting_id: VotingId, voting_type: VotingType) -> VotingSummary;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/reputation_voter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl ReputationVoterContract {
) -> Option<Ballot>;
pub fn get_voter(&self, voting_id: VotingId, voting_type: VotingType, at: u32) -> Option<Address>;
pub fn finish_voting(&mut self, voting_id: VotingId, voting_type: VotingType) -> VotingSummary;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/simple_voter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl SimpleVoterContract {
address: Address,
) -> Option<Ballot>;
pub fn get_voter(&self, voting_id: VotingId, voting_type: VotingType, at: u32) -> Option<Address>;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
1 change: 1 addition & 0 deletions dao/src/voting_contracts/slashing_voter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl SlashingVoterContract {
voting_type: VotingType,
voter: Address,
) -> Option<Ballot>;
pub fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

to self.access_control {
Expand Down
13 changes: 13 additions & 0 deletions dao/tests/common/contracts/voting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub trait Voter {
voting_type: DaoVotingType,
address: Address,
) -> Option<DaoBallot>;
fn cancel_finished_voting(&mut self, voting_id: VotingId);
}

#[allow(dead_code)]
Expand Down Expand Up @@ -163,6 +164,18 @@ impl DaoWorld {
VoterRef::at(&contract).finish_voting(voting_id, voting_type);
}

pub fn cancel_finished_voting(
&mut self,
contract: &Account,
account: &Account,
voting_id: u32,
) {
let account = self.get_address(account);
let contract = self.get_address(contract);
test_env::set_caller(account);
VoterRef::at(&contract).cancel_finished_voting(voting_id);
}

pub fn voting_exists(
&self,
contract: &Account,
Expand Down
Loading
Loading