Skip to content

Commit

Permalink
Use timer job to submit proposals (#4508)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Oct 6, 2023
1 parent 72b40d0 commit 8bc7a47
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions backend/canisters/proposals_bot/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@ use candid::CandidType;
use serde::{Deserialize, Serialize};
use types::icrc1::Account;

#[derive(CandidType, Serialize, Deserialize, Debug)]
#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
pub struct ProposalToSubmit {
pub title: String,
pub summary: String,
pub url: String,
pub action: ProposalToSubmitAction,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
pub enum ProposalToSubmitAction {
Motion,
TransferSnsTreasuryFunds(TransferSnsTreasuryFunds),
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
pub struct TransferSnsTreasuryFunds {
pub treasury: Treasury,
pub amount: u128,
pub to: Account,
pub memo: Option<u64>,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
pub enum Treasury {
ICP,
SNS,
Expand Down
2 changes: 1 addition & 1 deletion backend/canisters/proposals_bot/impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ candid = { workspace = true }
canister_api_macros = { path = "../../../libraries/canister_api_macros" }
canister_logger = { path = "../../../libraries/canister_logger" }
canister_state_macros = { path = "../../../libraries/canister_state_macros" }
canister_timer_jobs = { path = "../../../libraries/canister_timer_jobs" }
canister_tracing_macros = { path = "../../../libraries/canister_tracing_macros" }
community_canister = { path = "../../community/api" }
community_canister_c2c_client = { path = "../../community/c2c_client" }
fire_and_forget_handler = { path = "../../../libraries/fire_and_forget_handler" }
group_canister = { path = "../../group/api" }
group_canister_c2c_client = { path = "../../group/c2c_client" }
group_index_canister = { path = "../../group_index/api" }
Expand Down
8 changes: 5 additions & 3 deletions backend/canisters/proposals_bot/impl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::model::nervous_systems::NervousSystems;
use crate::timer_job_types::TimerJob;
use candid::{CandidType, Principal};
use canister_state_macros::canister_state;
use fire_and_forget_handler::FireAndForgetHandler;
use canister_timer_jobs::TimerJobs;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::cell::RefCell;
Expand All @@ -16,6 +17,7 @@ mod lifecycle;
mod memory;
mod model;
mod queries;
mod timer_job_types;
mod updates;

thread_local! {
Expand Down Expand Up @@ -72,7 +74,7 @@ struct Data {
pub nns_governance_canister_id: CanisterId,
pub finished_proposals_to_process: VecDeque<(CanisterId, ProposalId)>,
#[serde(default)]
pub fire_and_forget_handler: FireAndForgetHandler,
pub timer_jobs: TimerJobs<TimerJob>,
pub test_mode: bool,
}

Expand All @@ -99,7 +101,7 @@ impl Data {
cycles_dispenser_canister_id,
nns_governance_canister_id,
finished_proposals_to_process: VecDeque::new(),
fire_and_forget_handler: FireAndForgetHandler::default(),
timer_jobs: TimerJobs::default(),
test_mode,
}
}
Expand Down
34 changes: 34 additions & 0 deletions backend/canisters/proposals_bot/impl/src/timer_job_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::updates::c2c_submit_proposal::submit_proposal;
use canister_timer_jobs::Job;
use proposals_bot_canister::ProposalToSubmit;
use serde::{Deserialize, Serialize};
use types::{CanisterId, SnsNeuronId, UserId};

#[derive(Serialize, Deserialize, Clone)]
pub enum TimerJob {
SubmitProposal(SubmitProposalJob),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct SubmitProposalJob {
pub governance_canister_id: CanisterId,
pub user_id: UserId,
pub neuron_id: SnsNeuronId,
pub proposal: ProposalToSubmit,
}

impl Job for TimerJob {
fn execute(self) {
match self {
TimerJob::SubmitProposal(job) => job.execute(),
}
}
}

impl Job for SubmitProposalJob {
fn execute(self) {
ic_cdk::spawn(async move {
submit_proposal(self.user_id, self.governance_canister_id, self.neuron_id, self.proposal).await;
});
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use crate::timer_job_types::{SubmitProposalJob, TimerJob};
use crate::{mutate_state, read_state, RuntimeState};
use candid::Principal;
use canister_api_macros::update_msgpack;
use canister_tracing_macros::trace;
use local_user_index_canister_c2c_client::{lookup_user, LookupUserError};
use proposals_bot_canister::c2c_submit_proposal::{Response::*, *};
use proposals_bot_canister::{ProposalToSubmitAction, Treasury};
use proposals_bot_canister::{ProposalToSubmit, ProposalToSubmitAction, Treasury};
use sns_governance_canister::types::manage_neuron::Command;
use sns_governance_canister::types::proposal::Action;
use sns_governance_canister::types::{Motion, Proposal, Subaccount, TransferSnsTreasuryFunds};
use types::{CanisterId, SnsNeuronId};
use sns_governance_canister::types::{manage_neuron_response, Motion, Proposal, Subaccount, TransferSnsTreasuryFunds};
use types::{CanisterId, SnsNeuronId, UserId};
use utils::time::SECOND_IN_MS;

#[update_msgpack]
#[trace]
Expand All @@ -22,35 +24,13 @@ async fn c2c_submit_proposal(args: Args) -> Response {
Err(response) => return response,
};

match lookup_user(caller, local_user_index_canister_id).await {
Ok(_) => {}
let user_id = match lookup_user(caller, local_user_index_canister_id).await {
Ok(u) => u.user_id,
Err(LookupUserError::UserNotFound) => unreachable!(),
Err(LookupUserError::InternalError(error)) => return InternalError(error),
}

let make_proposal_args = sns_governance_canister::manage_neuron::Args {
subaccount: neuron_id.to_vec(),
command: Some(Command::MakeProposal(Proposal {
title: args.proposal.title,
summary: args.proposal.summary,
url: args.proposal.url,
action: Some(convert_proposal_action(args.proposal.action)),
})),
};
if let Err(error) =
sns_governance_canister_c2c_client::manage_neuron(args.governance_canister_id, &make_proposal_args).await
{
mutate_state(|state| {
state.data.fire_and_forget_handler.send(
args.governance_canister_id,
"manage_neuron".to_string(),
candid::encode_one(&make_proposal_args).unwrap(),
)
});
Retrying(format!("{error:?}"))
} else {
Success
}

submit_proposal(user_id, args.governance_canister_id, neuron_id, args.proposal).await
}

struct PrepareResult {
Expand All @@ -75,6 +55,51 @@ fn prepare(args: &Args, state: &RuntimeState) -> Result<PrepareResult, Response>
}
}

pub(crate) async fn submit_proposal(
user_id: UserId,
governance_canister_id: CanisterId,
neuron_id: SnsNeuronId,
proposal: ProposalToSubmit,
) -> Response {
let make_proposal_args = sns_governance_canister::manage_neuron::Args {
subaccount: neuron_id.to_vec(),
command: Some(Command::MakeProposal(Proposal {
title: proposal.title.clone(),
summary: proposal.summary.clone(),
url: proposal.url.clone(),
action: Some(convert_proposal_action(proposal.action.clone())),
})),
};
match sns_governance_canister_c2c_client::manage_neuron(governance_canister_id, &make_proposal_args).await {
Ok(response) => {
if let Some(command) = response.command {
return match command {
manage_neuron_response::Command::MakeProposal(_) => Success,
manage_neuron_response::Command::Error(error) => InternalError(format!("{error:?}")),
_ => unreachable!(),
};
}
InternalError("Response command was empty".to_string())
}
Err(error) => {
mutate_state(|state| {
let now = state.env.now();
state.data.timer_jobs.enqueue_job(
TimerJob::SubmitProposal(SubmitProposalJob {
user_id,
governance_canister_id,
neuron_id,
proposal,
}),
now + (10 * SECOND_IN_MS),
now,
)
});
Retrying(format!("{error:?}"))
}
}
}

fn convert_proposal_action(action: ProposalToSubmitAction) -> Action {
match action {
ProposalToSubmitAction::Motion => Action::Motion(Motion {
Expand Down
14 changes: 7 additions & 7 deletions backend/canisters/proposals_bot/impl/src/updates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod add_governance_canister;
mod appoint_admins;
mod c2c_submit_proposal;
mod import_proposals_group_into_community;
mod remove_governance_canister;
mod stake_neuron_for_submitting_proposals;
mod wallet_receive;
pub mod add_governance_canister;
pub mod appoint_admins;
pub mod c2c_submit_proposal;
pub mod import_proposals_group_into_community;
pub mod remove_governance_canister;
pub mod stake_neuron_for_submitting_proposals;
pub mod wallet_receive;

0 comments on commit 8bc7a47

Please sign in to comment.