mod error;
pub mod manager;
use crate::context::manager::ContextManagerError;
use crate::error::InternalError;
use crate::protocol::receipt::{Event, StateChange, TransactionReceipt};
use std::mem;
use uuid::Uuid;
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct ContextId([u8; 16]);
impl ContextId {
fn new_random() -> ContextId {
ContextId(*Uuid::new_v4().as_bytes())
}
}
impl From<[u8; 16]> for ContextId {
fn from(bytes: [u8; 16]) -> Self {
ContextId(bytes)
}
}
impl Default for ContextId {
fn default() -> Self {
ContextId(*Uuid::nil().as_bytes())
}
}
impl std::fmt::Debug for ContextId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_tuple("ContextId")
.field(&Uuid::from_bytes(self.0).to_simple_ref())
.finish()
}
}
impl std::fmt::Display for ContextId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str(&Uuid::from_bytes(self.0).to_simple_ref().to_string())
}
}
pub trait ContextLifecycle: Send {
fn create_context(&mut self, dependent_contexts: &[ContextId], state_id: &str) -> ContextId;
fn drop_context(&mut self, context_id: ContextId) -> Result<(), InternalError>;
fn get_transaction_receipt(
&self,
context_id: &ContextId,
transaction_id: &str,
) -> Result<TransactionReceipt, ContextManagerError>;
fn clone_box(&self) -> Box<dyn ContextLifecycle>;
}
impl Clone for Box<dyn ContextLifecycle> {
fn clone(&self) -> Box<dyn ContextLifecycle> {
self.clone_box()
}
}
#[derive(Debug, Clone, Default)]
pub struct Context {
base_contexts: Vec<ContextId>,
state_changes: Vec<StateChange>,
id: ContextId,
data: Vec<Vec<u8>>,
events: Vec<Event>,
state_id: String,
}
impl Context {
pub fn new(state_id: &str, base_contexts: Vec<ContextId>) -> Self {
Context {
base_contexts,
state_changes: Vec::new(),
id: ContextId::new_random(),
data: Vec::new(),
events: Vec::new(),
state_id: state_id.to_string(),
}
}
pub fn base_contexts(&self) -> &[ContextId] {
&self.base_contexts
}
pub fn events(&self) -> &Vec<Event> {
&self.events
}
pub fn state_changes(&self) -> &Vec<StateChange> {
&self.state_changes
}
pub fn id(&self) -> &ContextId {
&self.id
}
pub fn data(&self) -> &Vec<Vec<u8>> {
&self.data
}
pub fn state_id(&self) -> &String {
&self.state_id
}
pub fn add_event(&mut self, event: Event) {
if !self.events().contains(&event) {
self.events.push(event);
}
}
pub fn add_data(&mut self, data: Vec<u8>) {
if !self.data().contains(&data) {
self.data.push(data);
}
}
pub fn get_state(&self, key: &str) -> Option<&[u8]> {
if let Some(StateChange::Set { value: v, .. }) = self
.state_changes
.iter()
.rev()
.find(|state_change| state_change.has_key(key))
{
return Some(v);
}
None
}
pub fn set_state(&mut self, key: String, value: Vec<u8>) {
let new_state_change = StateChange::Set { key, value };
self.state_changes.push(new_state_change);
}
pub fn delete_state(&mut self, key: &str) -> Option<Vec<u8>> {
let found_state_change = self
.state_changes
.iter_mut()
.rev()
.find(|state_change| state_change.has_key(key));
if let Some(StateChange::Set { .. }) = found_state_change {
let mut new_state_change: StateChange = StateChange::Delete {
key: key.to_string(),
};
mem::swap(found_state_change.unwrap(), &mut new_state_change);
if let StateChange::Set { value: v, .. } = new_state_change {
return Some(v);
}
} else if found_state_change.is_none() {
self.state_changes.push(StateChange::Delete {
key: key.to_string(),
});
}
None
}
pub fn contains(&self, key: &str) -> bool {
for state_change in self.state_changes().iter().rev() {
match state_change {
StateChange::Set { key: k, .. } => {
if k == key {
return true;
}
}
StateChange::Delete { key: k } => {
if k == key {
return false;
}
}
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::receipt::StateChange;
static KEY1: &str = "111111111111111111111111111111111111111111111111111111111111111111";
static KEY2: &str = "222222222222222222222222222222222222222222222222222222222222222222";
static KEY3: &str = "333333333333333333333333333333333333333333333333333333333333333333";
static BYTES1: [u8; 4] = [0x01, 0x02, 0x03, 0x04];
static BYTES2: [u8; 4] = [0x05, 0x06, 0x07, 0x08];
static BYTES3: [u8; 4] = [0x09, 0x0a, 0x0b, 0x0c];
#[test]
fn get_state() {
let first_key = &KEY1.to_string();
let first_value = &BYTES1.to_vec();
let base_contexts = Vec::new();
let mut context = Context::new(&KEY3, base_contexts);
context.set_state(first_key.to_string(), first_value.to_vec());
assert!(context.contains(&first_key));
let state_value = context.get_state(&first_key);
assert_eq!(state_value, Some(first_value.as_slice()));
}
#[test]
fn test_compare_state_change() {
let first_set: StateChange = StateChange::Set {
key: KEY1.to_string(),
value: BYTES1.to_vec(),
};
let second_set: StateChange = StateChange::Set {
key: KEY2.to_string(),
value: BYTES2.to_vec(),
};
let delete_first: StateChange = StateChange::Delete {
key: KEY1.to_string(),
};
let delete_second: StateChange = StateChange::Delete {
key: KEY2.to_string(),
};
let first_set_key = KEY1.to_string();
assert_eq!(first_set.has_key(&first_set_key), true);
assert_eq!(second_set.has_key(&first_set_key), false);
assert_eq!(delete_first.has_key(&first_set_key), true);
assert_eq!(delete_second.has_key(&first_set_key), false);
}
#[test]
fn test_contains() {
let base_contexts = Vec::new();
let mut context = Context::new(&KEY3, base_contexts);
context.set_state(KEY1.to_string(), BYTES1.to_vec());
assert!(context.contains(&KEY1));
context.set_state(KEY1.to_string(), BYTES2.to_vec());
assert!(context.contains(&KEY1));
context.set_state(KEY2.to_string(), BYTES3.to_vec());
let deleted_value = context.delete_state(&KEY1);
assert_eq!(deleted_value, Some(BYTES2.to_vec()));
assert!(context.contains(&KEY2));
assert!(!context.contains(&KEY1));
}
#[test]
fn verify_state_changes() {
let mut context = Context::new(&KEY3, Vec::new());
context.set_state(KEY1.to_string(), BYTES1.to_vec());
context.set_state(KEY1.to_string(), BYTES2.to_vec());
context.set_state(KEY2.to_string(), BYTES3.to_vec());
assert_eq!(context.state_changes().len(), 3);
let deleted_value = context.delete_state(&KEY1);
assert_ne!(deleted_value, Some(BYTES3.to_vec()));
assert_eq!(context.state_changes().len(), 3);
let first_key_set = context
.state_changes()
.iter()
.cloned()
.find(|change| change.has_key(&KEY1));
if let Some(StateChange::Set { key: k, value: v }) = first_key_set {
assert_eq!(k, KEY1.to_string());
assert_ne!(Some(v), deleted_value);
}
if let StateChange::Set { key: k, value: v } = &context.state_changes()[1] {
assert_eq!(k, KEY1);
assert_eq!(Some(v.clone()), deleted_value);
}
}
}