diff options
Diffstat (limited to 'src/remake/api.rs')
| -rw-r--r-- | src/remake/api.rs | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/src/remake/api.rs b/src/remake/api.rs index 3345086..ffd1844 100644 --- a/src/remake/api.rs +++ b/src/remake/api.rs @@ -171,6 +171,9 @@ struct Report { enum StartError { #[error("remake {0} is already open for this epoch")] Open(String), + /// The proposer votes for its own remake, so it must be free to. + #[error("this node can't vote for a new remake: {0}")] + VoteHeld(String), #[error("base head {0} is not in this node's document")] UnknownBase(String), #[error(transparent)] @@ -454,6 +457,9 @@ async fn start_kind<H: Host>( Some(json!({ "remake": open })), ); } + Err(error @ StartError::VoteHeld(_)) => { + return error_response(StatusCode::CONFLICT, error.to_string(), None); + } Err(error @ StartError::UnknownBase(_)) => { return error_response(StatusCode::BAD_REQUEST, error.to_string(), None); } @@ -502,13 +508,25 @@ async fn propose<H: Host>( let record_id = id.clone(); let electorate_host = host.clone(); let me = host.node_id(); + let started = host.remake().started_at() + grace; let record = host .commit_doc(move |doc| -> Result<Record, StartError> { - if let Some((open, _)) = records::load_all(doc).into_iter().find(|(_, record)| { + let all = records::load_all(doc); + if let Some((open, _)) = all.iter().find(|(_, record)| { record.proposal.from_epoch == proposal.from_epoch && record.phase(now, grace).is_open() }) { - return Err(StartError::Open(open)); + return Err(StartError::Open(open.clone())); + } + let register = records::load_register(doc); + match vote::freedom(&me, &proposal.from_epoch, &all, ®ister, started) { + vote::Freedom::Any => {} + vote::Freedom::Only(id) => { + return Err(StartError::VoteHeld(format!( + "it may have voted for remake {id} before its start" + ))); + } + vote::Freedom::Held(reason) => return Err(StartError::VoteHeld(reason)), } // The base is the requested heads, or everything before the proposal (the @@ -538,8 +556,11 @@ async fn propose<H: Host>( proposal.electorate = electorate; records::write_proposal(doc, &record_id, &proposal)?; - let own_vote = Vote { at: now }; - records::write_vote(doc, &record_id, &me, &own_vote)?; + let own_vote = Vote { + remake: record_id.clone(), + at: now, + }; + records::write_vote(doc, &me, &own_vote)?; Ok(Record { proposal, decision: None, |
