From 4e7dd4e0b4cd8dcb5342d8caaa57db033b7d1fba Mon Sep 17 00:00:00 2001 From: Sosthene Date: Tue, 12 Nov 2024 23:22:20 +0100 Subject: [PATCH] Refactor states update --- src/process.rs | 91 ++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/src/process.rs b/src/process.rs index ac83ac6..a70763f 100644 --- a/src/process.rs +++ b/src/process.rs @@ -174,28 +174,46 @@ impl Process { Ok(last_state.commited_in) } - /// We want to always keep an empty state with only the latest unspent commited_in value at the last position - pub fn insert_state(&mut self, prd_update: &Prd) -> anyhow::Result<()> { - if prd_update.prd_type != PrdType::Update { return Err(anyhow::Error::msg("Only update prd allowed")) } + pub fn update_states_tip(&mut self, new_commitment: OutPoint) -> anyhow::Result<()> { if self.states.is_empty() { return Err(anyhow::Error::msg("Empty Process")); } - let new_encrypted_pcd: Value = serde_json::from_str(&prd_update.payload).unwrap(); - let last_index = self.states.len() - 1; - let last_value = self.states.get(last_index).unwrap(); - if last_value.encrypted_pcd != Value::Null || - last_value.keys != Map::new() || - last_value.pcd_commitment != Value::Null || - last_value.validation_tokens != vec![] - { - return Err(anyhow::Error::msg("Last state is not empty")); + let last_value = self.states.last().unwrap(); + if !last_value.is_empty() { + return Err(anyhow::Error::msg("Last value should be empty")); } - let empty_state = self.states.remove(last_index); - let new_state = ProcessState { - commited_in: empty_state.commited_in, - pcd_commitment: prd_update.pcd_commitments.clone(), - encrypted_pcd: new_encrypted_pcd, - keys: prd_update.keys.clone(), - validation_tokens: vec![] + if last_value.commited_in == new_commitment { + return Err(anyhow::Error::msg("new_commitment is the same than existing tip")); + } + + // Before updating we make sure that we only have one concurrent state + let concurrent_states = self.get_latest_concurrent_states()?; + if concurrent_states.len() != 2 { + return Err(anyhow::Error::msg("We must have exactly one state for the current tip")); + } + + // Replace the existing tip + let new_tip = ProcessState { + commited_in: new_commitment, + ..Default::default() }; + let _ = self.states.pop().unwrap(); + self.states.push(new_tip); + + Ok(()) + } + + /// We want to insert a new state that would be commited by the last UTXO + /// The new state *must* have the same commited_in than the last empty one + /// We want to always keep an empty state with only the latest unspent commited_in value at the last position + pub fn insert_concurrent_state(&mut self, new_state: ProcessState) -> anyhow::Result<()> { + if self.states.is_empty() { return Err(anyhow::Error::msg("Empty Process")); } + let last_value = self.states.last().unwrap(); + if !last_value.is_empty() { + return Err(anyhow::Error::msg("Last value should be empty")); + } + if last_value.commited_in != new_state.commited_in { + return Err(anyhow::Error::msg("A concurrent state must have the same commited in than the tip of the states")); + } + let empty_state = self.states.pop().unwrap(); self.states.push(new_state); // We always keep an empty state at the end self.states.push(empty_state); @@ -281,36 +299,22 @@ impl Process { Ok(states) } - pub fn remove_latest_concurrent_states(&mut self) -> anyhow::Result> { + pub fn remove_all_concurrent_states(&mut self) -> anyhow::Result> { if self.get_number_of_states() == 0 { // This should never happen, but we better get rid of it now return Err(anyhow::Error::msg("process is empty".to_owned())); } - let mut previous_commited_in = OutPoint::null(); - // Iterate backwards, find the reverse position, and adjust to forward position - let reverse_position = self.states.iter().rev().position(|state| { - if previous_commited_in == OutPoint::null() { - previous_commited_in = state.commited_in; - false // Continue iterating - } else if previous_commited_in != state.commited_in { - true // Stop when a different commited_in is found - } else { - false // Continue iterating - } - }); + let empty_state = self.states.pop().unwrap(); + let last_commitment_outpoint = empty_state.commited_in; + let split_index = self.states.iter().position(|state| state.commited_in == last_commitment_outpoint).unwrap(); - let forward_position = reverse_position.map(|pos| self.states.len() - pos - 1); + let removed = self.states.split_off(split_index); - match forward_position { - Some(pos) => Ok(self.states.split_off(pos)), - None => { - // We take everything out - let res = self.states.to_vec(); - self.states = vec![]; - Ok(res) - } - } + // We make sure we always have an empty state at the end + self.states.push(empty_state); + + Ok(removed) } pub fn get_latest_commited_state(&self) -> Option<&ProcessState> { @@ -379,8 +383,7 @@ mod tests { use serde_json::json; use sp_client::{ - bitcoin::{secp256k1::SecretKey, Network}, - spclient::{SpClient, SpWallet, SpendKey}, + bitcoin::{secp256k1::SecretKey, Network}, silentpayments::utils::SilentPaymentAddress, spclient::{SpClient, SpWallet, SpendKey} }; use crate::pcd::{Member, ValidationRule};