Refactor states update

This commit is contained in:
Sosthene 2024-11-12 23:22:20 +01:00
parent c2fde13e95
commit 4e7dd4e0b4

View File

@ -174,28 +174,46 @@ impl Process {
Ok(last_state.commited_in) 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 update_states_tip(&mut self, new_commitment: OutPoint) -> anyhow::Result<()> {
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")) }
if self.states.is_empty() { return Err(anyhow::Error::msg("Empty Process")); } 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_value = self.states.last().unwrap();
let last_index = self.states.len() - 1; if !last_value.is_empty() {
let last_value = self.states.get(last_index).unwrap(); return Err(anyhow::Error::msg("Last value should be empty"));
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 empty_state = self.states.remove(last_index); if last_value.commited_in == new_commitment {
let new_state = ProcessState { return Err(anyhow::Error::msg("new_commitment is the same than existing tip"));
commited_in: empty_state.commited_in, }
pcd_commitment: prd_update.pcd_commitments.clone(),
encrypted_pcd: new_encrypted_pcd, // Before updating we make sure that we only have one concurrent state
keys: prd_update.keys.clone(), let concurrent_states = self.get_latest_concurrent_states()?;
validation_tokens: vec![] 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); self.states.push(new_state);
// We always keep an empty state at the end // We always keep an empty state at the end
self.states.push(empty_state); self.states.push(empty_state);
@ -281,36 +299,22 @@ impl Process {
Ok(states) Ok(states)
} }
pub fn remove_latest_concurrent_states(&mut self) -> anyhow::Result<Vec<ProcessState>> { pub fn remove_all_concurrent_states(&mut self) -> anyhow::Result<Vec<ProcessState>> {
if self.get_number_of_states() == 0 { if self.get_number_of_states() == 0 {
// This should never happen, but we better get rid of it now // This should never happen, but we better get rid of it now
return Err(anyhow::Error::msg("process is empty".to_owned())); return Err(anyhow::Error::msg("process is empty".to_owned()));
} }
let mut previous_commited_in = OutPoint::null(); let empty_state = self.states.pop().unwrap();
// Iterate backwards, find the reverse position, and adjust to forward position let last_commitment_outpoint = empty_state.commited_in;
let reverse_position = self.states.iter().rev().position(|state| { let split_index = self.states.iter().position(|state| state.commited_in == last_commitment_outpoint).unwrap();
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 forward_position = reverse_position.map(|pos| self.states.len() - pos - 1); let removed = self.states.split_off(split_index);
match forward_position { // We make sure we always have an empty state at the end
Some(pos) => Ok(self.states.split_off(pos)), self.states.push(empty_state);
None => {
// We take everything out Ok(removed)
let res = self.states.to_vec();
self.states = vec![];
Ok(res)
}
}
} }
pub fn get_latest_commited_state(&self) -> Option<&ProcessState> { pub fn get_latest_commited_state(&self) -> Option<&ProcessState> {
@ -379,8 +383,7 @@ mod tests {
use serde_json::json; use serde_json::json;
use sp_client::{ use sp_client::{
bitcoin::{secp256k1::SecretKey, Network}, bitcoin::{secp256k1::SecretKey, Network}, silentpayments::utils::SilentPaymentAddress, spclient::{SpClient, SpWallet, SpendKey}
spclient::{SpClient, SpWallet, SpendKey},
}; };
use crate::pcd::{Member, ValidationRule}; use crate::pcd::{Member, ValidationRule};