Refactor states update
This commit is contained in:
parent
c2fde13e95
commit
4e7dd4e0b4
@ -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};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user