Refactor states update

This commit is contained in:
Sosthene 2024-11-12 23:22:20 +01:00 committed by Nicolas Cantu
parent 1f154ce4e6
commit eb1ce0bfc9

View File

@ -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<Vec<ProcessState>> {
pub fn remove_all_concurrent_states(&mut self) -> anyhow::Result<Vec<ProcessState>> {
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};