diff --git a/Cargo.toml b/Cargo.toml index 1c4c597..f4077ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ overflow-checks = true # Panic in the case of an overflow. [workspace] members = [ - "data-structures", "maths", "test-engine" ] diff --git a/README.md b/README.md index 5da774b..bfb4eef 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,13 @@ This library aims at providing open source tools for Scrypto developers. At the moment, these include: -- [Better testing engine](test-engine/README.md) -- [Data structures](data-structures/README.md) +- [Test Engine](test-engine/README.md) - [Maths library](maths/README.md) (Needs an overhaul) ## Contribute: To contribute please follow the [contribution guide](CONTRIBUTING.md). The following features are open for contribution. -### Data structures - -- [ ] Add more features to `BigVec` -- [ ] Implement more data structures - ### Test Engine - [ ] Implement a better way to deal with Buckets/Proofs return. diff --git a/data-structures/Cargo.toml b/data-structures/Cargo.toml deleted file mode 100644 index eacbc04..0000000 --- a/data-structures/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "data-structures" -version = "0.1.0" -license = "MIT" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "v1.2.0" } - -[dev-dependencies] -test-engine = { path = "../test-engine" } \ No newline at end of file diff --git a/data-structures/README.md b/data-structures/README.md deleted file mode 100644 index ce573d3..0000000 --- a/data-structures/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Data structures -Simple package implementing data structures with no size limits for Scrypto blueprints to use. - diff --git a/data-structures/src/big_vec.rs b/data-structures/src/big_vec.rs deleted file mode 100644 index 93e66f2..0000000 --- a/data-structures/src/big_vec.rs +++ /dev/null @@ -1,635 +0,0 @@ -//! # BigVec -//! -//! is a data structure that represents a vector capable of dynamically growing without the overhead reallocating memory -//! each time the vector resizes and without memory size limit. -//! It internally manages a collection of smaller vectors, enabling efficient insertion and deletion operations. - -use scrypto::prelude::*; -use std::cmp::min; -use std::mem::size_of; -use std::ops::{Deref, DerefMut}; -use std::vec::IntoIter; - -pub trait BigVecElement: - ScryptoEncode + ScryptoDecode + ScryptoDescribe + Categorize -{ -} -impl> - BigVecElement for T -{ -} - -#[derive(ScryptoSbor)] -#[sbor(categorize_types = "V")] -pub struct BigVec { - pub start_index: usize, - pub capacity_per_vec: usize, - pub vec_structure: Vec, - pub vec_data: KeyValueStore>, -} - -impl BigVec { - /// Constructs a new, empty `BigVec`. - pub fn new() -> Self { - Self { - start_index: 0, - capacity_per_vec: 1_000_000 / size_of::(), - vec_structure: Vec::new(), - vec_data: KeyValueStore::new(), - } - } - - /// Creates a new empty `BigVec` with a specified initial capacity for each internal vector. - /// - /// This function initializes a new `BigVec` with the specified `elements_per_vec` as the initial capacity for each - /// internal vector. This can be useful for optimizing memory usage when the approximate number of elements per - /// vector is known in advance. - /// - /// # Arguments - /// - /// * `capacity_per_vec` - The amount of elements to store in each internal vector. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// // Create a new BigVec with an initial capacity of 100 elements per vector - /// let big_vec: BigVec = BigVec::with_capacity_per_vec(100); - /// ``` - pub fn with_capacity_per_vec(capacity_per_vec: usize) -> Self { - Self { - start_index: 0, - capacity_per_vec, - vec_structure: Vec::new(), - vec_data: KeyValueStore::new(), - } - } - - /// Appends an element to the end of the `BigVec`. - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// big_vec.push(42); - /// assert_eq!(big_vec.len(), 1); - /// ``` - pub fn push(&mut self, element: V) { - if self.vec_structure.is_empty() { - self.vec_structure.push(1); - self.vec_data.insert(self.start_index, vec![element]); - } else { - let vec_length = self.vec_structure.len(); - if self.vec_structure[vec_length - 1] == self.capacity_per_vec { - self.vec_structure.push(1); - self.vec_data - .insert(vec_length + self.start_index, vec![element]); - } else { - self.vec_structure[vec_length - 1] += 1; - let mut data = self - .vec_data - .get_mut(&(vec_length + self.start_index - 1)) - .unwrap(); - data.push(element); - } - } - } - - /// Removes the last element from the `BigVec` and returns it, or `None` if it is empty. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// big_vec.push(42); - /// assert_eq!(big_vec.pop(), Some(42)); - /// assert_eq!(big_vec.pop(), None); - /// ``` - pub fn pop(&mut self) -> Option { - if self.vec_structure.is_empty() { - None - } else { - let vec_length = self.vec_structure.len(); - self.vec_structure[vec_length - 1] -= 1; - if self.vec_structure[vec_length - 1] == 0 { - let mut data = self.vec_data.remove(&(vec_length - 1)).unwrap(); - self.vec_structure.pop(); - data.pop() - } else { - let mut data = self.vec_data.get_mut(&(vec_length - 1)).unwrap(); - data.pop() - } - } - } - - /// Retrieves an immutable reference to an item in the `BigVec`. - /// - /// This method takes a reference to an index and returns an `Option` containing a - /// reference to the item at the specified index, if it exists. If the index is out - /// of bounds,, it returns `None`. - /// - /// # Arguments - /// - /// * `index` - A reference to the index of the item to retrieve. - /// - /// # Returns - /// - /// An `Option` containing a reference to the item at the specified index, if it exists. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// big_vec.push(10); - /// - /// assert_eq!(big_vec.get(&0).as_deref(), Some(&10)); - /// assert_eq!(big_vec.get(&1).as_deref(), None); - /// ``` - pub fn get(&self, index: &usize) -> Option> { - self.get_correct_indexes(index) - .map(|indexes| BigVecItemRef::new(self.vec_data.get(&indexes.0).unwrap(), indexes.1)) - } - - /// Retrieves a mutable reference to an item in the `BigVec`. - /// - /// This method takes a reference to an index and returns an `Option` containing a - /// mutable reference to the item at the specified index, if it exists. If the index - /// is out of bounds, it returns `None`. - /// - /// # Arguments - /// - /// * `index` - A reference to the index of the item to retrieve. - /// - /// # Returns - /// - /// An `Option` containing a mutable reference to the item at the specified index, if it exists. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// big_vec.push(10); - /// - /// if let Some(mut item) = big_vec.get_mut(&0) { - /// *item = 20; - /// } - /// - /// assert_eq!(big_vec.get(&0).as_deref(), Some(&20)); - /// ``` - pub fn get_mut(&mut self, index: &usize) -> Option> { - match self.get_correct_indexes(index) { - None => None, - Some(indexes) => Some(BigVecItemRefMut::new( - self.vec_data.get_mut(&indexes.0).unwrap(), - indexes.1, - )), - } - } - - /// Inserts an element at a specified index in the `BigVec`. - /// - /// # Safety - /// - /// This method is marked as unsafe because it allows inserting elements into the `BigVec` at a - /// specific index, which could potentially lead to exceed the fee limit during a transaction. - /// The caller is responsible for ensuring that inserting elements using this method does - /// not result exceeding fee limits. - /// - /// # Panics - /// - /// Panics if the index is out of bounds. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// big_vec.push(1); - /// big_vec.push(3); - /// unsafe { big_vec.insert(1, 2); } - /// assert_eq!(big_vec.pop(), Some(3)); - /// assert_eq!(big_vec.pop(), Some(2)); - /// assert_eq!(big_vec.pop(), Some(1)); - /// ``` - pub unsafe fn insert(&mut self, index: usize, element: V) { - let mut data_index = index / self.capacity_per_vec; - let vec_index = index % self.capacity_per_vec; - - if data_index > self.vec_structure.len() - || (data_index == self.vec_structure.len() && vec_index > 0) - || (data_index + 1 == self.vec_structure.len() - && vec_index >= *self.vec_structure.last().unwrap()) - { - panic!("Trying to insert to index {index} which is out of bounds!") - } - - data_index += self.start_index; - - // If we are trying to insert at last position, push item - if self.vec_structure.get(data_index).is_none() { - self.vec_structure.push(1); - self.vec_data.insert(data_index, vec![element]); - return; - } - - // Otherwise, insert the item - let mut data = self - .vec_data - .get_mut(&data_index) - .expect("Something is wrong with this BigVec"); - - data.insert(vec_index, element); - - if data.len() <= self.capacity_per_vec { - *self.vec_structure.get_mut(data_index).unwrap() += 1; - return; - } - - let mut to_push = data.pop().unwrap(); - let mut index_to_push = data_index + 1; - std::mem::drop(data); - - // Restructure everything if needed - loop { - match self.vec_structure.get(index_to_push) { - None => { - self.vec_structure.push(1); - self.vec_data.insert(index_to_push, vec![to_push]); - return; - } - Some(amount) => { - let mut new_data = self - .vec_data - .get_mut(&index_to_push) - .expect("Something is wrong with this BigVec"); - - new_data.insert(0, to_push); - - if *amount < self.capacity_per_vec { - *self.vec_structure.get_mut(index_to_push).unwrap() += 1; - return; - } else { - to_push = new_data.pop().unwrap(); - index_to_push += 1; - } - } - } - } - } - - /// Removes and returns the first vector of elements from a `BigVec`. - /// - /// This method removes and returns the first vector of elements from the `BigVec`. - /// If the `BigVec` is empty, it returns `None`. - /// - /// # Returns - /// - /// An `Option` containing the first vector of elements from the `BigVec`, if it exists. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::with_capacity_per_vec(2); - /// big_vec.push(1); - /// big_vec.push(2); - /// big_vec.push(3); - /// - /// assert_eq!(big_vec.pop_first_vec(), Some(vec![1,2])); - /// assert_eq!(big_vec.pop_first_vec(), Some(vec![3])); - /// assert_eq!(big_vec.pop_first_vec(), None) - /// ``` - pub fn pop_first_vec(&mut self) -> Option> { - match self.vec_structure.first() { - None => None, - Some(_) => { - self.vec_structure.remove(0); - let ret = self.vec_data.remove(&self.start_index); - self.start_index += 1; - ret - } - } - } - - /// Pushes elements from a vector into a BigVec, organizing them into sub-vectors based on the configured capacity. - /// If the last sub-vector in the BigVec has space remaining, the elements are appended to it. - /// If not, a new sub-vector is created and the elements are divided accordingly. - /// - /// # Arguments - /// - /// * `elements` - A vector containing elements of type `V` to be pushed into the BigVec. - /// - /// # Example - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec = BigVec::::new(); - /// let elements = vec![1, 2, 3, 4, 5]; - /// big_vec.push_vec(elements); - /// ``` - pub fn push_vec(&mut self, mut elements: Vec) { - let start_index = self.vec_structure.len(); - match self.vec_structure.last() { - None => {} - Some(vec_size) => { - let elems_to_push = self.capacity_per_vec - *vec_size; - let last_index = self.vec_structure.len() - 1; - if elems_to_push > elements.len() { - self.vec_structure[last_index] += elements.len(); - self.vec_data - .get_mut(&(start_index - 1)) - .unwrap() - .append(&mut elements); - return; - } else { - self.vec_structure[last_index] = self.capacity_per_vec; - self.vec_data - .get_mut(&(start_index - 1)) - .unwrap() - .append(&mut elements.drain(..elems_to_push).collect()); - } - } - } - - self.push_vec_raw(elements); - } - - /// Pushes elements from a vector into a BigVec, organizing them into sub-vectors based on the configured capacity. - /// It does it without trying to fill the current last vector. - /// - /// # Arguments - /// - /// * `elements`: A vector of elements to be pushed into the internal data structure. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec = BigVec::::new(); - /// let elements = vec![1, 2, 3, 4, 5, 6]; - /// big_vec.push_vec_raw(elements); - /// ``` - pub fn push_vec_raw(&mut self, mut elements: Vec) { - let mut start_index = self.vec_structure.len(); - - while !elements.is_empty() { - let to_drain = min(elements.len(), self.capacity_per_vec); - let new_elems: Vec = elements.drain(..to_drain).collect(); - self.vec_structure.push(new_elems.len()); - self.vec_data.insert(start_index, new_elems); - start_index += 1; - } - } - - /// Lazily appends the contents of another BigVec to this BigVec. - /// The sub-vectors and their sizes from the other BigVec are appended to the end of the current BigVec. - /// - /// # Arguments - /// - /// * `other` - Another BigVec whose contents are to be appended to this BigVec. - /// - /// # Example - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec1 = BigVec::::new(); - /// let mut big_vec2 = BigVec::::new(); - /// big_vec1.append(big_vec2); - /// ``` - pub fn append(&mut self, mut other: Self) { - if other.capacity_per_vec == self.capacity_per_vec { - let mut index_to_push = self.vec_structure.len(); - self.vec_structure.append(&mut other.vec_structure); - for i in 0..other.vec_structure.len() { - let vec_data = other.vec_data.remove(&i).unwrap(); - self.vec_data.insert(index_to_push, vec_data); - index_to_push += 1; - } - } else { - panic!("Cannot append from a BigVec with a different structure") - } - } - - /// Returns the number of elements in the `BigVec`. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// big_vec.push(1); - /// big_vec.push(2); - /// assert_eq!(big_vec.len(), 2); - /// ``` - pub fn len(&self) -> usize { - self.vec_structure.iter().sum() - } - - /// Returns `true` if the `BigVec` is empty, otherwise `false`. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// assert!(big_vec.is_empty()); - /// big_vec.push(1); - /// assert!(!big_vec.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - self.vec_structure.is_empty() - } - - /// Returns the number of vectors internally managed by the `BigVec`. - /// - /// # Examples - /// - /// ```no_run - /// use data_structures::big_vec::BigVec; - /// - /// let mut big_vec: BigVec = BigVec::new(); - /// - /// assert_eq!(big_vec.vec_nb(), 0); - /// big_vec.push(1); - /// assert_eq!(big_vec.vec_nb(), 1); - /// ``` - pub fn vec_nb(&self) -> usize { - self.vec_structure.len() - } - - /// Returns the internal structure of the `BigVec`. - pub fn structure(&self) -> &Vec { - &self.vec_structure - } - - /// Returns the capacity per vec of the `BigVec`. - pub fn capacity_per_vec(&self) -> usize { - self.capacity_per_vec - } - - fn get_correct_indexes(&self, index: &usize) -> Option<(usize, usize)> { - let data_index = *index / self.capacity_per_vec; - let vec_index = *index % self.capacity_per_vec; - - // If we exceeded the size return None - if data_index >= self.vec_structure.len() - || (data_index + 1 == self.vec_structure.len() - && vec_index >= *self.vec_structure.last().unwrap()) - { - None - } else { - Some((data_index + self.start_index, vec_index)) - } - } -} - -impl< - V: ScryptoEncode - + ScryptoDecode - + ScryptoDescribe - + Categorize - + Clone, - > BigVec -{ - /// Returns all the value in the underlying representation. - /// Should only be used for tests. - pub fn internal_representation(&self) -> Vec> { - let mut ret = vec![]; - for i in 0..self.vec_structure.len() { - ret.push(self.vec_data.get(&i).unwrap().clone()); - } - ret - } -} - -impl Default for BigVec { - fn default() -> Self { - Self::new() - } -} - -impl From> for BigVec { - fn from(vec: Vec) -> Self { - let mut big_vec = BigVec::new(); - big_vec.push_vec(vec); - big_vec - } -} - -pub struct BigVecItemRef<'a, V: BigVecElement> { - sub_vec: KeyValueEntryRef<'a, Vec>, - item_index: usize, -} - -impl<'a, V: BigVecElement> BigVecItemRef<'a, V> { - pub fn new(sub_vec: KeyValueEntryRef<'a, Vec>, item_index: usize) -> Self { - Self { - sub_vec, - item_index, - } - } -} - -impl<'a, V: BigVecElement> Deref for BigVecItemRef<'a, V> { - type Target = V; - - fn deref(&self) -> &Self::Target { - self.sub_vec.get(self.item_index).unwrap() - } -} - -pub struct BigVecItemRefMut<'a, V: BigVecElement> { - sub_vec: KeyValueEntryRefMut<'a, Vec>, - item_index: usize, -} -impl<'a, V: BigVecElement> BigVecItemRefMut<'a, V> { - pub fn new(sub_vec: KeyValueEntryRefMut<'a, Vec>, item_index: usize) -> Self { - Self { - sub_vec, - item_index, - } - } -} - -impl<'a, V: BigVecElement> Deref for BigVecItemRefMut<'a, V> { - type Target = V; - - fn deref(&self) -> &Self::Target { - self.sub_vec.get(self.item_index).unwrap() - } -} - -impl<'a, V: BigVecElement> DerefMut for BigVecItemRefMut<'a, V> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.sub_vec.get_mut(self.item_index).unwrap() - } -} - -pub struct BigVecIntoIterator<'a, V: BigVecElement + Clone> { - pub number_of_vec: usize, - pub current_vec: usize, - pub current_vec_iterator: IntoIter, - pub vec_data: &'a KeyValueStore>, -} -impl<'a, V: BigVecElement + Clone> IntoIterator for &'a BigVec { - type Item = V; - type IntoIter = BigVecIntoIterator<'a, V>; - - fn into_iter(self) -> Self::IntoIter { - let current_vec = match self.vec_data.get(&0) { - None => Vec::new(), - Some(vec) => vec.clone(), - }; - Self::IntoIter { - number_of_vec: self.vec_structure.len(), - current_vec: 0, - current_vec_iterator: current_vec.into_iter(), - vec_data: &self.vec_data, - } - } -} - -impl<'a, V: BigVecElement + Clone> Iterator for BigVecIntoIterator<'a, V> { - type Item = V; - - fn next(&mut self) -> Option { - match self.current_vec_iterator.next() { - Some(item) => Some(item), - None => { - if self.current_vec + 1 >= self.number_of_vec { - None - } else { - self.current_vec += 1; - self.current_vec_iterator = match self.vec_data.get(&self.current_vec) { - None => { - panic!("The iterator is wrongly formed! Could not find element at index {}", self.current_vec); - } - Some(vec) => as Clone>::clone(&vec).into_iter(), - }; - - self.current_vec_iterator.next() - } - } - } - } -} diff --git a/data-structures/src/lib.rs b/data-structures/src/lib.rs deleted file mode 100644 index 9cf7b02..0000000 --- a/data-structures/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod big_vec; -pub mod macros; diff --git a/data-structures/src/macros.rs b/data-structures/src/macros.rs deleted file mode 100644 index 62163c7..0000000 --- a/data-structures/src/macros.rs +++ /dev/null @@ -1,26 +0,0 @@ -/// A macro for convenient creation of `BigVec` instances. -/// -/// This macro provides a convenient way to create instances of `BigVec`. -/// -/// # Examples -/// -/// Creating an empty `BigVec`: -/// -/// ```no_code -/// let empty_vec = big_vec!(); -/// ``` -/// -/// Creating a `BigVec` with elements: -/// -/// ```no_code -/// let vec_with_elements = big_vec![1, 2, 3, 4, 5]; -/// ``` -#[macro_export] -macro_rules! big_vec { - () => { - $crate::big_vec::BigVec::new(); - }; - ($($x:expr),* $(,)?) => { - $crate::big_vec::BigVec::from(vec![$($x),*]) - }; -} diff --git a/data-structures/tests/big_vec/mod.rs b/data-structures/tests/big_vec/mod.rs deleted file mode 100644 index f28d4ed..0000000 --- a/data-structures/tests/big_vec/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod unit_tests; diff --git a/data-structures/tests/big_vec/package/Cargo.toml b/data-structures/tests/big_vec/package/Cargo.toml deleted file mode 100644 index af9961b..0000000 --- a/data-structures/tests/big_vec/package/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "big-vec" -version = "0.1.0" -edition = "2021" - -[dependencies] -sbor = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "v1.2.0" } -scrypto = { git = "https://github.com/radixdlt/radixdlt-scrypto", tag = "v1.2.0" } -data-structures = { path = "../../../../data-structures" } - -[profile.release] -opt-level = 'z' # Optimize for size. -lto = true # Enable Link Time Optimization. -codegen-units = 1 # Reduce number of codegen units to increase optimizations. -panic = 'abort' # Abort on panic. -strip = true # Strip the symbols. -overflow-checks = true # Panic in the case of an overflow. - -[lib] -crate-type = ["cdylib", "lib"] - -[workspace] diff --git a/data-structures/tests/big_vec/package/src/lib.rs b/data-structures/tests/big_vec/package/src/lib.rs deleted file mode 100644 index ad84edc..0000000 --- a/data-structures/tests/big_vec/package/src/lib.rs +++ /dev/null @@ -1,148 +0,0 @@ -use data_structures::big_vec; -use data_structures::big_vec::BigVec; -use scrypto::prelude::*; -use std::ops::Deref; - -#[blueprint] -mod big_vec_blueprint { - - struct BigVecBlueprint { - vec: BigVec, - } - - impl BigVecBlueprint { - /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// - /// /// - /// Interface to the `BigVec` data structures for methods that can actually be called /// - /// /// - /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// - - pub fn new() -> Global { - Self { vec: BigVec::new() } - .instantiate() - .prepare_to_globalize(OwnerRole::None) - .globalize() - } - - pub fn with_capacity_per_vec(capacity_per_vec: usize) -> Global { - Self { - vec: BigVec::with_capacity_per_vec(capacity_per_vec), - } - .instantiate() - .prepare_to_globalize(OwnerRole::None) - .globalize() - } - - pub fn default() -> Global { - Self { - vec: BigVec::default(), - } - .instantiate() - .prepare_to_globalize(OwnerRole::None) - .globalize() - } - - pub fn from(vec: Vec) -> Global { - Self { - vec: BigVec::from(vec), - } - .instantiate() - .prepare_to_globalize(OwnerRole::None) - .globalize() - } - - pub fn push(&mut self, element: u32) { - self.vec.push(element); - } - - pub fn pop(&mut self) -> Option { - self.vec.pop() - } - - pub fn get(&self, index: usize) -> Option { - match self.vec.get(&index) { - None => None, - Some(value) => Some(value.deref().clone()), - } - } - - pub fn insert(&mut self, index: usize, element: u32) { - unsafe { - self.vec.insert(index, element); - } - } - - pub fn pop_first_vec(&mut self) -> Option> { - self.vec.pop_first_vec() - } - - pub fn push_vec(&mut self, elements: Vec) { - self.vec.push_vec(elements); - } - - pub fn push_vec_raw(&mut self, elements: Vec) { - self.vec.push_vec_raw(elements); - } - - pub fn len(&self) -> usize { - self.vec.len() - } - - pub fn is_empty(&self) -> bool { - self.vec.is_empty() - } - - pub fn vec_nb(&self) -> usize { - self.vec.vec_nb() - } - - pub fn structure(&self) -> Vec { - self.vec.structure().clone() - } - - pub fn capacity_per_vec(&self) -> usize { - self.vec.capacity_per_vec() - } - - pub fn internal_representation(&self) -> Vec> { - self.vec.internal_representation() - } - - /// /// /// /// /// /// /// /// /// /// /// /// - /// /// - /// Specific methods for testing purposes /// - /// /// - /// /// /// /// /// /// /// /// /// /// //// /// - - pub fn with_macros() -> Global { - Self { - vec: big_vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - } - .instantiate() - .prepare_to_globalize(OwnerRole::None) - .globalize() - } - - pub fn append(&mut self, address: ComponentAddress) { - let other_big_vec: Global = address.into(); - let big_vec = other_big_vec.call("to_big_vec", &None::); - self.vec.append(big_vec); - } - - pub fn change_value_at(&mut self, index: usize, value: u32) { - *self.vec.get_mut(&index).unwrap() = value; - } - - pub fn full_vec(&self) -> Vec { - let mut ret = vec![]; - for elem in &self.vec { - ret.push(elem); - } - ret - } - - pub fn to_big_vec(&self, _fake: Option) -> BigVec { - BigVec::from(self.vec.into_iter().collect::>()) - } - } -} diff --git a/data-structures/tests/big_vec/unit_tests.rs b/data-structures/tests/big_vec/unit_tests.rs deleted file mode 100644 index d1b0ff7..0000000 --- a/data-structures/tests/big_vec/unit_tests.rs +++ /dev/null @@ -1,373 +0,0 @@ -use test_engine::prelude::*; - -global_package!(BIG_VEC_PACKAGE, "tests/big_vec/package"); - -fn instantiate() -> TestEngine { - let mut test_engine = TestEngine::with_package("big vec package", &BIG_VEC_PACKAGE); - test_engine.new_component( - "big vec comp", - "BigVecBlueprint", - "with_capacity_per_vec", - env_args!(3usize), - ); - test_engine -} - -fn instantiate_with_items() -> TestEngine { - let mut test_engine = instantiate(); - for i in 0..7 { - test_engine.call_method("push", env_args!(i as u32)); - } - test_engine -} - -fn get_vec(test_engine: &mut TestEngine) -> Vec { - test_engine - .call_method("full_vec", env_args!()) - .get_return() -} - -#[test] -fn test_new_big_vec() { - let mut test_engine = TestEngine::with_package("big vec package", &BIG_VEC_PACKAGE); - test_engine.new_component("big vec comp", "BigVecBlueprint", "new", env_args!()); - - let is_empty: bool = test_engine - .call_method("is_empty", env_args!()) - .get_return(); - - let capacity_per_vec: usize = test_engine - .call_method("capacity_per_vec", env_args!()) - .get_return(); - - assert_eq!(is_empty, true); - assert_eq!(capacity_per_vec, 250000); -} - -#[test] -fn test_new_with_capacity_vec() { - let mut test_engine = instantiate(); - - let is_empty: bool = test_engine - .call_method("is_empty", env_args!()) - .get_return(); - - let capacity_per_vec: usize = test_engine - .call_method("capacity_per_vec", env_args!()) - .get_return(); - - assert_eq!(is_empty, true); - assert_eq!(capacity_per_vec, 3); -} - -#[test] -fn test_new_default() { - let mut test_engine = TestEngine::with_package("big vec package", &BIG_VEC_PACKAGE); - test_engine.new_component("big vec comp", "BigVecBlueprint", "default", env_args!()); - - let is_empty: bool = test_engine - .call_method("is_empty", env_args!()) - .get_return(); - - let capacity_per_vec: usize = test_engine - .call_method("capacity_per_vec", env_args!()) - .get_return(); - - assert_eq!(is_empty, true); - assert_eq!(capacity_per_vec, 250000); -} - -#[test] -fn test_from() { - let mut test_engine = TestEngine::with_package("big vec package", &BIG_VEC_PACKAGE); - let expected_items: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; - test_engine.new_component( - "big vec comp", - "BigVecBlueprint", - "from", - env_args!(expected_items.clone()), - ); - - let is_empty: bool = test_engine - .call_method("is_empty", env_args!()) - .get_return(); - - let capacity_per_vec: usize = test_engine - .call_method("capacity_per_vec", env_args!()) - .get_return(); - - let items: Vec = test_engine - .call_method("full_vec", env_args!()) - .get_return(); - - assert_eq!(is_empty, false); - assert_eq!(capacity_per_vec, 250000); - assert_eq!(items, expected_items); -} - -#[test] -fn test_push_items() { - let mut test_engine = instantiate(); - - let mut expected_items: Vec = vec![]; - for i in 0..7 { - expected_items.push(i); - test_engine.call_method("push", env_args!(i)); - - let len: usize = test_engine.call_method("len", env_args!()).get_return(); - - let vec_structure: Vec = test_engine - .call_method("structure", env_args!()) - .get_return(); - - let items: Vec = test_engine - .call_method("full_vec", env_args!()) - .get_return(); - - assert_eq!(len, (i + 1) as usize); - assert_eq!(vec_structure.len(), (i / 3 + 1) as usize); - assert_eq!(items, expected_items); - } -} - -#[test] -fn test_pop_items() { - let mut test_engine = instantiate_with_items(); - - let mut expected_items: Vec = vec![0, 1, 2, 3, 4, 5, 6]; - - for i in 0..7 { - let expect_popped = expected_items.pop(); - let popped: Option = test_engine.call_method("pop", env_args!()).get_return(); - - let len: usize = test_engine.call_method("len", env_args!()).get_return(); - - let vec_structure: Vec = test_engine - .call_method("structure", env_args!()) - .get_return(); - - let items: Vec = test_engine - .call_method("full_vec", env_args!()) - .get_return(); - - assert_eq!(popped, expect_popped); - assert_eq!(len, (6 - i) as usize); - assert_eq!(vec_structure.len(), (2 - i / 3) as usize); - assert_eq!(items, expected_items); - } - - let is_empty: bool = test_engine - .call_method("is_empty", env_args!()) - .get_return(); - - assert_eq!(is_empty, true); -} - -#[test] -fn test_get() { - let mut test_engine = instantiate_with_items(); - - for i in 0..7 { - println!("{}", i); - let ret: Option = test_engine - .call_method("get", env_args!(i as usize)) - .assert_is_success() - .get_return(); - assert_eq!(ret, Some(i as u32)) - } - let ret: Option = test_engine - .call_method("get", env_args!(7 as usize)) - .assert_is_success() - .get_return(); - assert_eq!(ret, None); -} - -#[test] -fn test_get_mut() { - let mut test_engine = instantiate_with_items(); - test_engine - .call_method("change_value_at", env_args!(0 as usize, 35 as u32)) - .assert_is_success(); - - let new_value: Option = test_engine - .call_method("get", env_args!(0 as usize)) - .assert_is_success() - .get_return(); - - assert_eq!(new_value, Some(35)); -} - -#[test] -fn test_insert() { - let mut test_engine = instantiate_with_items(); - - let mut expected_items: Vec = vec![0, 1, 2, 3, 4, 5, 6]; - let mut items: Vec; - - test_engine - .call_method("insert", env_args!(5 as usize, 10 as u32)) - .assert_is_success(); - expected_items.insert(5, 10); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); - - test_engine - .call_method("insert", env_args!(15 as usize, 10 as u32)) - .assert_failed_with("Trying to insert to index 15 which is out of bounds!"); - - test_engine - .call_method("insert", env_args!(0 as usize, 10 as u32)) - .assert_is_success(); - expected_items.insert(0, 10); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); - - test_engine - .call_method("insert", env_args!(expected_items.len(), 23 as u32)) - .assert_is_success(); - expected_items.insert(expected_items.len(), 23); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); - - test_engine - .new_component("ok", "BigVecBlueprint", "new", env_args!()) - .assert_is_success(); - test_engine.set_current_component("ok"); - test_engine.call_method("insert", env_args!(0 as usize, 1 as u32)); - - items = get_vec(&mut test_engine); - - assert_eq!(items, vec![1]) -} - -#[test] -fn test_pop_first_vec() { - let mut test_engine = instantiate_with_items(); - - let mut popped: Option> = test_engine - .call_method("pop_first_vec", env_args!()) - .assert_is_success() - .get_return(); - - let mut new_first: Option = test_engine - .call_method("get", env_args!(0 as usize)) - .assert_is_success() - .get_return(); - - let mut new_second: Option = test_engine - .call_method("get", env_args!(1 as usize)) - .assert_is_success() - .get_return(); - - let new_third: Option = test_engine - .call_method("get", env_args!(2 as usize)) - .assert_is_success() - .get_return(); - - let new_fifth: Option = test_engine - .call_method("get", env_args!(5 as usize)) - .assert_is_success() - .get_return(); - - assert_eq!(popped, Some(vec![0, 1, 2])); - assert_eq!(new_first, Some(3)); - assert_eq!(new_second, Some(4)); - assert_eq!(new_third, Some(5)); - assert_eq!(new_fifth, None); - - popped = test_engine - .call_method("pop_first_vec", env_args!()) - .assert_is_success() - .get_return(); - - new_first = test_engine - .call_method("get", env_args!(0 as usize)) - .assert_is_success() - .get_return(); - - new_second = test_engine - .call_method("get", env_args!(1 as usize)) - .assert_is_success() - .get_return(); - - assert_eq!(popped, Some(vec![3, 4, 5])); - assert_eq!(new_first, Some(6)); - assert_eq!(new_second, None); - - test_engine - .call_method("push", env_args!(7 as u32)) - .assert_is_success(); - - popped = test_engine - .call_method("pop_first_vec", env_args!()) - .assert_is_success() - .get_return(); - - new_first = test_engine - .call_method("get", env_args!(0 as usize)) - .assert_is_success() - .get_return(); - - assert_eq!(popped, Some(vec![6, 7])); - assert_eq!(new_first, None); - - popped = test_engine - .call_method("pop_first_vec", env_args!()) - .assert_is_success() - .get_return(); - - assert_eq!(popped, None); -} - -#[test] -fn test_push_vec() { - let mut test_engine = instantiate_with_items(); - - let mut expected_items: Vec = vec![0, 1, 2, 3, 4, 5, 6]; - let mut items: Vec; - - let mut new_items = vec![7, 8, 9]; - test_engine - .call_method("push_vec", env_args!(new_items.clone())) - .assert_is_success(); - expected_items.append(&mut new_items); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); - - new_items = vec![10]; - test_engine - .call_method("push_vec", env_args!(new_items.clone())) - .assert_is_success(); - expected_items.append(&mut new_items); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); - - new_items = vec![11, 12, 13, 14]; - test_engine - .call_method("push_vec", env_args!(new_items.clone())) - .assert_is_success(); - expected_items.append(&mut new_items); - items = get_vec(&mut test_engine); - assert_eq!(items, expected_items); -} - -#[test] -fn test_push_vec_raw() { - let mut test_engine = instantiate_with_items(); - - let mut expected_items: Vec = vec![0, 1, 2, 3, 4, 5, 6]; - let mut expected_structure: Vec = vec![3, 3, 1]; - - let mut new_items = vec![7, 8]; - test_engine - .call_method("push_vec_raw", env_args!(new_items.clone())) - .assert_is_success(); - expected_items.append(&mut new_items); - expected_structure.push(2); - let items = get_vec(&mut test_engine); - let structure: Vec = test_engine - .call_method("structure", env_args!()) - .get_return(); - assert_eq!(items, expected_items); - assert_eq!(structure, expected_structure) -} diff --git a/data-structures/tests/main.rs b/data-structures/tests/main.rs deleted file mode 100644 index 4b35395..0000000 --- a/data-structures/tests/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod big_vec; diff --git a/maths/Cargo.toml b/maths/Cargo.toml index faf5a34..f5d561a 100644 --- a/maths/Cargo.toml +++ b/maths/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "decimal-maths" -version = "0.0.1" +version = "0.2.1" license = "MIT" edition = "2021" diff --git a/test-engine/Cargo.toml b/test-engine/Cargo.toml index c9af4ed..6877aaa 100644 --- a/test-engine/Cargo.toml +++ b/test-engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-engine" -version = "0.2.0" +version = "0.2.1" license = "MIT" edition = "2021" diff --git a/test-engine/README.md b/test-engine/README.md index 40edd04..a50e28d 100644 --- a/test-engine/README.md +++ b/test-engine/README.md @@ -8,14 +8,14 @@ To use the library, add the following dev dependency to the `Cargo.toml` file ``` [dev-dependencies] -test-engine = { git = "https://github.com/BeakerTools/scrypto-toolkit", branch = "main"} +test-engine = test-engine = { git = "https://github.com/BeakerTools/scrypto-toolkit", tag = "v0.2.1"} ``` # Main Features - [Basics](tutorials/1.Basics.md) - [Packages and blueprints](tutorials/2.Packages_and_Blueprints.md) -- [Calling methods](tutorials/3.MethodsCalls.md) +- [Calling methods](tutorials/3.Methods_Calls) # Examples diff --git a/test-engine/src/call_builder.rs b/test-engine/src/call_builder.rs index cef8fae..b9dbbcf 100644 --- a/test-engine/src/call_builder.rs +++ b/test-engine/src/call_builder.rs @@ -23,6 +23,8 @@ pub struct CallBuilder<'a> { output_manifest: Option<(String, String)>, admin_badge: Vec<(ResourceAddress, Option>)>, with_trace: bool, + with_tx_fee: bool, + log_title: Option<&'a str>, deposit_destination: ComponentAddress, manifest_data: Option, } @@ -42,9 +44,27 @@ impl<'a> CallBuilder<'a> { admin_badge: vec![], with_trace: false, manifest_data: None, + with_tx_fee: false, + log_title: None, } } + pub fn with_test_engine(&mut self, f: F) -> R + where + F: FnOnce(&mut TestEngine) -> R, + { + f(&mut self.test_engine) + } + + pub fn with_manifest_builder(mut self, f: F) -> Self + where + F: FnOnce(ManifestBuilder) -> ManifestBuilder, + { + self.manifest_builder = f(self.manifest_builder); + + self + } + /// Creates a call builder for a method call of the current component and skip the transaction execution. /// /// # Arguments @@ -61,7 +81,7 @@ impl<'a> CallBuilder<'a> { /// * `entity_name`: reference name or address of the entity to call the method on. /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - pub fn call_from_component( + pub fn call_from( self, entity_name: G, method_name: &str, @@ -101,11 +121,27 @@ impl<'a> CallBuilder<'a> { true, ); + if let Some(title) = self.log_title { + Self::output_log_title(title); + } + Self::output_logs(&receipt); + if self.with_tx_fee { + Self::output_tx_fee(&receipt); + } + receipt } + pub fn execute_and_expect_success(self) -> CommitResult { + self.execute().expect_commit_success().clone() + } + + pub fn execute_and_expect_failure(self) -> CommitResult { + self.execute().expect_commit_failure().clone() + } + /// Deposits the batch to the given account. /// /// # Arguments @@ -142,21 +178,21 @@ impl<'a> CallBuilder<'a> { pub fn transfer< E: ReferenceName, R: ReferenceName + Clone + 'static, - D: TryInto + Clone + 'static, + // D: TryInto + Clone + 'static, >( self, recipient: E, resource: R, - amount: D, + amount: Decimal, ) -> Self - where - >::Error: std::fmt::Debug, +// where + // >::Error: std::fmt::Debug, { - self.call_from_component( + self.call_from( recipient, "try_deposit_or_abort", vec![ - Box::new(Fungible::Bucket(resource.clone(), amount)), + Box::new(Fungible::FromAccount(resource.clone(), amount)), Box::new(None::), ], ) @@ -174,11 +210,11 @@ impl<'a> CallBuilder<'a> { resource: R, ids: Vec, ) -> Self { - self.call_from_component( + self.call_from( recipient, "try_deposit_or_abort", vec![ - Box::new(NonFungible::Bucket( + Box::new(NonFungible::FromAccount( resource, ids.into_iter().map(|id| id.to_id()).collect(), )), @@ -240,6 +276,20 @@ impl<'a> CallBuilder<'a> { self } + /// Displays tx fee or not. + /// + /// # Arguments + /// * `trace`: + pub fn with_log_tx_fee(mut self) -> Self { + self.with_tx_fee = true; + self + } + + pub fn with_log_title(mut self, title: &'a str) -> Self { + self.log_title = Some(title); + self + } + pub(crate) fn call_method_internal( mut self, component: impl ResolvableGlobalAddress, @@ -294,8 +344,16 @@ impl<'a> CallBuilder<'a> { false, ); + if let Some(title) = self.log_title { + Self::output_log_title(title); + } + Self::output_logs(&receipt); + if self.with_tx_fee { + Self::output_tx_fee(&receipt); + } + receipt } @@ -418,6 +476,14 @@ impl<'a> CallBuilder<'a> { } } } + + fn output_log_title(title: &str) { + println!("\nTX: {title}"); + } + + fn output_tx_fee(receipt: &TransactionReceipt) { + println!("Transaction fees:{:?}", receipt.fee_summary.total_cost()); + } } impl SimpleMethodCaller for CallBuilder<'_> { diff --git a/test-engine/src/engine_interface.rs b/test-engine/src/engine_interface.rs index febaf37..d56836c 100644 --- a/test-engine/src/engine_interface.rs +++ b/test-engine/src/engine_interface.rs @@ -23,6 +23,23 @@ impl EngineInterface { } } + pub fn new_with_custom_genesis(genesis: CustomGenesis) -> Self { + let test_runner_builder = LedgerSimulatorBuilder::new() + .with_custom_genesis(genesis) + .without_kernel_trace() + .build(); + Self { + simulator: test_runner_builder, + } + } + + pub fn with_simulator(&mut self, action: F) -> R + where + F: FnOnce(&mut DefaultLedgerSimulator) -> R, + { + action(&mut self.simulator) + } + pub fn publish_package>(&mut self, package_dir: P) -> TransactionReceipt { self.simulator.try_publish_package(package_dir.as_ref()) } @@ -91,9 +108,10 @@ impl EngineInterface { &mut self, account: ComponentAddress, initial_amount: Decimal, + divisibility: u8, ) -> ResourceAddress { self.simulator - .create_fungible_resource(initial_amount, 18, account) + .create_fungible_resource(initial_amount, divisibility, account) } pub fn set_epoch(&mut self, epoch: Epoch) { diff --git a/test-engine/src/environment.rs b/test-engine/src/environment.rs index 4ec8e1d..aa15d1f 100644 --- a/test-engine/src/environment.rs +++ b/test-engine/src/environment.rs @@ -76,20 +76,16 @@ impl EnvironmentEncode for Environment { } } -pub enum Fungible + Clone> -where - >::Error: std::fmt::Debug, -{ - Bucket(R, D), - BucketFromWorkTop(R, D), - Proof(R, D), - ProofFromAuthZone(R, D), +// Fungible + +pub enum Fungible { + FromAccount(R, Decimal), + FromWorkTop(R, Decimal), + AllFromAccount(R), + AllFromWorktop(R), } -impl + Clone> ToEncode for Fungible -where - >::Error: std::fmt::Debug, -{ +impl ToEncode for Fungible { fn to_encode<'a>( &self, test_engine: &mut TestEngine, @@ -100,7 +96,7 @@ where Box>>, ) { match self { - Fungible::Bucket(resource, amount) => { + Fungible::FromAccount(resource, amount) => { let resource_address = resource.address(test_engine); let amount = amount.clone().try_into().unwrap(); @@ -116,7 +112,7 @@ where }); (manifest_builder, Box::new(bucket.new_bucket.unwrap())) } - Fungible::BucketFromWorkTop(resource, amount) => { + Fungible::FromWorkTop(resource, amount) => { let resource_address = resource.address(test_engine); let amount = amount.clone().try_into().unwrap(); @@ -127,43 +123,64 @@ where }); (manifest_builder, Box::new(bucket.new_bucket.unwrap())) } - Fungible::Proof(resource, amount) => { + Fungible::AllFromAccount(resource) => { + let amount_owned = test_engine.current_balance(resource.clone()); let resource_address = resource.address(test_engine); - let amount = amount.clone().try_into().unwrap(); let manifest_builder = manifest_builder.call_method( caller, - "create_proof_of_amount", - manifest_args!(resource_address, amount), + "withdraw", + manifest_args!(resource_address, amount_owned), ); - let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( - InstructionV1::CreateProofFromAuthZoneOfAmount { - amount, + let (manifest_builder, bucket) = + manifest_builder.add_instruction_advanced(InstructionV1::TakeFromWorktop { resource_address, - }, - ); - (manifest_builder, Box::new(proof.new_proof.unwrap())) + amount: amount_owned, + }); + (manifest_builder, Box::new(bucket.new_bucket.unwrap())) } - Fungible::ProofFromAuthZone(resource, amount) => { + Fungible::AllFromWorktop(resource) => { let resource_address = resource.address(test_engine); - let amount = amount.clone().try_into().unwrap(); - let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( - InstructionV1::CreateProofFromAuthZoneOfAmount { - amount, + let (manifest_builder, bucket) = + manifest_builder.add_instruction_advanced(InstructionV1::TakeAllFromWorktop { resource_address, - }, - ); - (manifest_builder, Box::new(proof.new_proof.unwrap())) - } + }); + (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + } // Fungible::ProofFromAccount(resource, amount) => { + // let resource_address = resource.address(test_engine); + // let amount = amount.clone().try_into().unwrap(); + + // let manifest_builder = manifest_builder.call_method( + // caller, + // "create_proof_of_amount", + // manifest_args!(resource_address, amount), + // ); + // let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + // InstructionV1::CreateProofFromAuthZoneOfAmount { + // amount, + // resource_address, + // }, + // ); + // (manifest_builder, Box::new(proof.new_proof.unwrap())) + // } + // Fungible::ProofFromAuthZone(resource, amount) => { + // let resource_address = resource.address(test_engine); + // let amount = amount.clone().try_into().unwrap(); + + // let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + // InstructionV1::CreateProofFromAuthZoneOfAmount { + // amount, + // resource_address, + // }, + // ); + // (manifest_builder, Box::new(proof.new_proof.unwrap())) + // } } } } -impl + Clone> EnvironmentEncode for Fungible -where - >::Error: std::fmt::Debug, -{ +impl EnvironmentEncode for Fungible { fn encode( &self, test_engine: &mut TestEngine, @@ -177,12 +194,75 @@ where } } -pub enum FungibleAll { - FromAccount(R), - FromWorktop(R), +// pub enum AllFungible { +// FromAccount(R), +// FromWorktop(R), +// } + +// impl ToEncode for AllFungible { +// fn to_encode<'a>( +// &self, +// test_engine: &mut TestEngine, +// manifest_builder: ManifestBuilder, +// caller: ComponentAddress, +// ) -> ( +// ManifestBuilder, +// Box>>, +// ) { +// match self { +// AllFungible::FromAccount(resource) => { +// let amount_owned = test_engine.current_balance(resource.clone()); +// let resource_address = resource.address(test_engine); + +// let manifest_builder = manifest_builder.call_method( +// caller, +// "withdraw", +// manifest_args!(resource_address, amount_owned), +// ); +// let (manifest_builder, bucket) = +// manifest_builder.add_instruction_advanced(InstructionV1::TakeFromWorktop { +// resource_address, +// amount: amount_owned, +// }); +// (manifest_builder, Box::new(bucket.new_bucket.unwrap())) +// } +// AllFungible::FromWorktop(resource) => { +// let resource_address = resource.address(test_engine); + +// let (manifest_builder, bucket) = +// manifest_builder.add_instruction_advanced(InstructionV1::TakeAllFromWorktop { +// resource_address, +// }); +// (manifest_builder, Box::new(bucket.new_bucket.unwrap())) +// } +// } +// } +// } + +// impl EnvironmentEncode for AllFungible { +// fn encode( +// &self, +// test_engine: &mut TestEngine, +// manifest_builder: ManifestBuilder, +// encoder: &mut ManifestEncoder, +// caller: ComponentAddress, +// ) -> ManifestBuilder { +// let (manifest_builder, encoded) = self.to_encode(test_engine, manifest_builder, caller); +// encoder.encode(encoded.as_ref()).expect("Could not encode"); +// manifest_builder +// } +// } + +// Non Fungible + +pub enum NonFungible { + FromAccount(R, Vec), + FromWorktop(R, Vec), + AllFromAccount(R), + AllFromWorktop(R), } -impl ToEncode for FungibleAll { +impl ToEncode for NonFungible { fn to_encode<'a>( &self, test_engine: &mut TestEngine, @@ -193,23 +273,51 @@ impl ToEncode for FungibleAll { Box>>, ) { match self { - FungibleAll::FromAccount(resource) => { - let amount_owned = test_engine.current_balance(resource.clone()); + NonFungible::FromAccount(resource, ids) => { let resource_address = resource.address(test_engine); let manifest_builder = manifest_builder.call_method( caller, - "withdraw", - manifest_args!(resource_address, amount_owned), + "withdraw_non_fungibles", + manifest_args!(resource_address, ids.clone()), ); - let (manifest_builder, bucket) = - manifest_builder.add_instruction_advanced(InstructionV1::TakeFromWorktop { + let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( + InstructionV1::TakeNonFungiblesFromWorktop { resource_address, - amount: amount_owned, - }); + ids: ids.clone(), + }, + ); + (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + } + NonFungible::FromWorktop(resource, ids) => { + let resource_address = resource.address(test_engine); + let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( + InstructionV1::TakeNonFungiblesFromWorktop { + resource_address, + ids: ids.clone(), + }, + ); + (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + } + + NonFungible::AllFromAccount(resource) => { + let ids_owned = test_engine.current_ids_balance(resource.clone()); + let resource_address = resource.address(test_engine); + + let manifest_builder = manifest_builder.call_method( + caller, + "withdraw_non_fungibles", + manifest_args!(resource_address, ids_owned.clone()), + ); + let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( + InstructionV1::TakeNonFungiblesFromWorktop { + resource_address, + ids: ids_owned, + }, + ); (manifest_builder, Box::new(bucket.new_bucket.unwrap())) } - FungibleAll::FromWorktop(resource) => { + NonFungible::AllFromWorktop(resource) => { let resource_address = resource.address(test_engine); let (manifest_builder, bucket) = @@ -217,12 +325,36 @@ impl ToEncode for FungibleAll { resource_address, }); (manifest_builder, Box::new(bucket.new_bucket.unwrap())) - } + } // NonFungible::NonProofFromAccount(resource, ids) => { + // let resource_address = resource.address(test_engine); + // let manifest_builder = manifest_builder.call_method( + // caller, + // "create_proof_of_non_fungibles", + // manifest_args!(resource_address, ids.clone()), + // ); + // let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + // InstructionV1::CreateProofFromAuthZoneOfNonFungibles { + // resource_address, + // ids: ids.clone(), + // }, + // ); + // (manifest_builder, Box::new(proof.new_proof.unwrap())) + // } + // NonFungible::NonProofFromAuthZone(resource, ids) => { + // let resource_address = resource.address(test_engine); + // let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + // InstructionV1::CreateProofFromAuthZoneOfNonFungibles { + // resource_address, + // ids: ids.clone(), + // }, + // ); + // (manifest_builder, Box::new(proof.new_proof.unwrap())) + // } } } } -impl EnvironmentEncode for FungibleAll { +impl EnvironmentEncode for NonFungible { fn encode( &self, test_engine: &mut TestEngine, @@ -236,14 +368,62 @@ impl EnvironmentEncode for FungibleAll { } } -pub enum NonFungible { - Bucket(R, Vec), - BucketFromWorktop(R, Vec), - Proof(R, Vec), - ProofFromAuthZone(R, Vec), +// pub enum NonFungibleAll { +// AllFromAccount(R), +// AllFromWorktop(R), +// } + +// impl ToEncode for NonFungibleAll { +// fn to_encode<'a>( +// &self, +// test_engine: &mut TestEngine, +// manifest_builder: ManifestBuilder, +// caller: ComponentAddress, +// ) -> ( +// ManifestBuilder, +// Box>>, +// ) { +// match self { +// NonFungibleAll::AllFromAccount(resource) => { +// let ids_owned = test_engine.current_ids_balance(resource.clone()); +// let resource_address = resource.address(test_engine); + +// let manifest_builder = manifest_builder.call_method( +// caller, +// "withdraw_non_fungibles", +// manifest_args!(resource_address, ids_owned.clone()), +// ); +// let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( +// InstructionV1::TakeNonFungiblesFromWorktop { +// resource_address, +// ids: ids_owned, +// }, +// ); +// (manifest_builder, Box::new(bucket.new_bucket.unwrap())) +// } +// NonFungibleAll::AllFromWorktop(resource) => { +// let resource_address = resource.address(test_engine); + +// let (manifest_builder, bucket) = +// manifest_builder.add_instruction_advanced(InstructionV1::TakeAllFromWorktop { +// resource_address, +// }); +// (manifest_builder, Box::new(bucket.new_bucket.unwrap())) +// } +// } +// } +// } + +// Proofs + +pub enum ProofOf { + FungibleFromAccount(R, Decimal), + FungibleFromAuthZone(R, Decimal), + NonFungibleFromAccount(R, Vec), + NonFungibleFromAuthZone(R, Vec), } -impl ToEncode for NonFungible { +impl ToEncode for ProofOf { fn to_encode<'a>( &self, test_engine: &mut TestEngine, @@ -254,33 +434,36 @@ impl ToEncode for NonFungible { Box>>, ) { match self { - NonFungible::Bucket(resource, ids) => { + ProofOf::FungibleFromAccount(resource, amount) => { let resource_address = resource.address(test_engine); + let amount = amount.clone().try_into().unwrap(); let manifest_builder = manifest_builder.call_method( caller, - "withdraw_non_fungibles", - manifest_args!(resource_address, ids.clone()), + "create_proof_of_amount", + manifest_args!(resource_address, amount), ); - let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( - InstructionV1::TakeNonFungiblesFromWorktop { + let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + InstructionV1::CreateProofFromAuthZoneOfAmount { + amount, resource_address, - ids: ids.clone(), }, ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, Box::new(proof.new_proof.unwrap())) } - NonFungible::BucketFromWorktop(resource, ids) => { + ProofOf::FungibleFromAuthZone(resource, amount) => { let resource_address = resource.address(test_engine); - let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( - InstructionV1::TakeNonFungiblesFromWorktop { + let amount = amount.clone().try_into().unwrap(); + + let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + InstructionV1::CreateProofFromAuthZoneOfAmount { + amount, resource_address, - ids: ids.clone(), }, ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, Box::new(proof.new_proof.unwrap())) } - NonFungible::Proof(resource, ids) => { + ProofOf::NonFungibleFromAccount(resource, ids) => { let resource_address = resource.address(test_engine); let manifest_builder = manifest_builder.call_method( caller, @@ -295,7 +478,7 @@ impl ToEncode for NonFungible { ); (manifest_builder, Box::new(proof.new_proof.unwrap())) } - NonFungible::ProofFromAuthZone(resource, ids) => { + ProofOf::NonFungibleFromAuthZone(resource, ids) => { let resource_address = resource.address(test_engine); let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( InstructionV1::CreateProofFromAuthZoneOfNonFungibles { @@ -309,7 +492,7 @@ impl ToEncode for NonFungible { } } -impl EnvironmentEncode for NonFungible { +impl EnvironmentEncode for ProofOf { fn encode( &self, test_engine: &mut TestEngine, @@ -323,51 +506,7 @@ impl EnvironmentEncode for NonFungible { } } -pub enum NonFungibleAll { - FromAccount(R), - FromWorktop(R), -} - -impl ToEncode for NonFungibleAll { - fn to_encode<'a>( - &self, - test_engine: &mut TestEngine, - manifest_builder: ManifestBuilder, - caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ) { - match self { - NonFungibleAll::FromAccount(resource) => { - let ids_owned = test_engine.current_ids_balance(resource.clone()); - let resource_address = resource.address(test_engine); - - let manifest_builder = manifest_builder.call_method( - caller, - "withdraw_non_fungibles", - manifest_args!(resource_address, ids_owned.clone()), - ); - let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( - InstructionV1::TakeNonFungiblesFromWorktop { - resource_address, - ids: ids_owned, - }, - ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) - } - NonFungibleAll::FromWorktop(resource) => { - let resource_address = resource.address(test_engine); - - let (manifest_builder, bucket) = - manifest_builder.add_instruction_advanced(InstructionV1::TakeAllFromWorktop { - resource_address, - }); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) - } - } - } -} +// Env Vec pub struct EnvVec { elements: Vec>, diff --git a/test-engine/src/macros.rs b/test-engine/src/macros.rs index dd0406b..30b396b 100644 --- a/test-engine/src/macros.rs +++ b/test-engine/src/macros.rs @@ -21,14 +21,14 @@ macro_rules! env_vec { vec![] ); - ($( $x:expr ),*) => {{ - use test_engine::prelude::*; + ($( $x:expr ),*) => {{ + use test_engine::prelude::*; - let mut temp_vec: Vec> = vec![]; - $( - temp_vec.push(Box::new($x)); - )* - EnvVec::from_vec(temp_vec) + let mut temp_vec: Vec> = vec![]; + $( + temp_vec.push(Box::new($x)); + )* + EnvVec::from_vec(temp_vec) }}; } diff --git a/test-engine/src/method_call.rs b/test-engine/src/method_call.rs index c7c7b1b..bdd7334 100644 --- a/test-engine/src/method_call.rs +++ b/test-engine/src/method_call.rs @@ -44,16 +44,25 @@ pub trait SimpleMethodCaller { pub trait ComplexMethodCaller { /// Returns a new call builder. - fn build_call(&mut self) -> CallBuilder; + fn call_builder(&mut self) -> CallBuilder; /// Returns a call builder with an initial method call. /// /// # Arguments /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - fn call_method_builder( + fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder; + + /// Returns a call builder with an initial method call with a given admin badge. + /// + /// # Arguments + /// * `method_name`: name of the method. + /// * `admin_badge`: reference name or address of the resource to use as an admin badge. + /// * `args`: environment arguments to call the method. + fn call_with_badge( &mut self, method_name: &str, + admin_badge: R, args: Vec>, ) -> CallBuilder; @@ -63,10 +72,16 @@ pub trait ComplexMethodCaller { /// * `global_address`: reference or address of the entity to call. /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - fn call_method_builder_from( + fn call_from( &mut self, global_address: G, method_name: &str, args: Vec>, ) -> CallBuilder; + + fn with_manifest_builder(&mut self, f: F) -> CallBuilder + where + F: FnOnce(ManifestBuilder) -> ManifestBuilder; + + fn withdraw(&mut self, resource: R, amount: Decimal) -> CallBuilder; } diff --git a/test-engine/src/test_engine.rs b/test-engine/src/test_engine.rs index 70b8e68..8311a54 100644 --- a/test-engine/src/test_engine.rs +++ b/test-engine/src/test_engine.rs @@ -24,9 +24,8 @@ pub struct TestEngine { impl TestEngine { /// Returns a new TestEngine. - pub fn new() -> Self { - let mut engine_interface = EngineInterface::new(); + fn _new(mut engine_interface: EngineInterface) -> Self { let default_account = Account::new(&mut engine_interface); let mut accounts = HashMap::new(); accounts.insert("default".format(), default_account); @@ -50,6 +49,22 @@ impl TestEngine { } } + pub fn new() -> Self { + Self::_new(EngineInterface::new()) + } + + pub fn new_with_custom_genesis(genesis: CustomGenesis) -> Self { + Self::_new(EngineInterface::new_with_custom_genesis(genesis)) + } + + pub fn with_simulator(&mut self, action: F) -> R + where + F: FnOnce(&mut DefaultLedgerSimulator) -> R, + { + self.engine_interface + .with_simulator(|simulator| action(simulator)) + } + /// Returns a new TestEngine with an initial global package. /// /// # Arguments @@ -180,6 +195,19 @@ impl TestEngine { ) } + /// Registers a component with a reference name. + /// + /// # Arguments + /// * `name`: name that will be used to reference the component. + /// * `component_address`: address of the component. + pub fn register_component( + &mut self, + name: N, + component_address: ComponentAddress, + ) { + self.components.insert(name.format(), component_address); + } + /// Calls faucet with the current account. pub fn call_faucet(&mut self) { CallBuilder::new(self) @@ -188,6 +216,23 @@ impl TestEngine { .execute(); } + /// Calls faucet with the current account. + pub fn call_faucet_and(&mut self) -> CallBuilder { + CallBuilder::new(self) + .call_method_internal(FAUCET, "free", vec![]) + .lock_fee("faucet", dec!(10)) + } + + /// Calls faucet with the current account. + pub fn call_faucet_time_n(&mut self, n: u32) { + for _ in 0..n { + CallBuilder::new(self) + .call_method_internal(FAUCET, "free", vec![]) + .lock_fee("faucet", dec!(10)) + .execute(); + } + } + /// Transfers some fungible resources form the current account to the given recipient. /// /// # Arguments @@ -197,15 +242,15 @@ impl TestEngine { pub fn transfer< E: ReferenceName, R: ReferenceName + Clone + 'static, - D: TryInto + Clone + 'static, + // D: TryInto + Clone + 'static, >( &mut self, recipient: E, resource: R, - amount: D, + amount: Decimal, ) -> TransactionReceipt - where - >::Error: std::fmt::Debug, +// where + // >::Error: std::fmt::Debug, { CallBuilder::new(self) .transfer(recipient, resource, amount) @@ -238,6 +283,7 @@ impl TestEngine { &mut self, token_name: N, initial_distribution: D, + divisibility: u8, ) where >::Error: std::fmt::Debug, { @@ -247,9 +293,11 @@ impl TestEngine { } None => { let account = *self.current_account().address(); - let token_address = self - .engine_interface - .new_fungible(account, initial_distribution.try_into().unwrap()); + let token_address = self.engine_interface.new_fungible( + account, + initial_distribution.try_into().unwrap(), + divisibility, + ); self.resources.insert(token_name.format(), token_address); } } @@ -429,7 +477,7 @@ impl TestEngine { vec![Box::new(id.to_id()), Box::new(field_name.to_string())]; args.append(&mut data); CallBuilder::new(self) - .call_from_component(resource, "update_non_fungible_data", args) + .call_from(resource, "update_non_fungible_data", args) .with_badge(badge) .execute() } @@ -748,8 +796,7 @@ impl<'a> SimpleMethodCaller for &'a mut TestEngine { method_name: &str, args: Vec>, ) -> TransactionReceipt { - self.call_method_builder_from(global_address, method_name, args) - .execute() + self.call_from(global_address, method_name, args).execute() } fn call_method_with_badge( @@ -758,27 +805,33 @@ impl<'a> SimpleMethodCaller for &'a mut TestEngine { admin_badge: R, args: Vec>, ) -> TransactionReceipt { - self.call_method_builder(method_name, args) + self.call(method_name, args) .with_badge(admin_badge) .execute() } } impl ComplexMethodCaller for TestEngine { - fn build_call(&mut self) -> CallBuilder { + fn call_builder(&mut self) -> CallBuilder { CallBuilder::new(self) } - fn call_method_builder( + fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder { + let component = *self.current_component(); + self.call_from(component, method_name, args) + } + fn call_with_badge( &mut self, method_name: &str, + admin_badge: R, args: Vec>, ) -> CallBuilder { let component = *self.current_component(); - self.call_method_builder_from(component, method_name, args) + self.call_from(component, method_name, args) + .with_badge(admin_badge) } - fn call_method_builder_from( + fn call_from( &mut self, global_address: G, method_name: &str, @@ -787,4 +840,16 @@ impl ComplexMethodCaller for TestEngine { let address = global_address.address(self); CallBuilder::new(self).call_method_internal(address, method_name, args) } + + fn with_manifest_builder(&mut self, f: F) -> CallBuilder + where + F: FnOnce(ManifestBuilder) -> ManifestBuilder, + { + self.call_builder().with_manifest_builder(f) + } + + fn withdraw(&mut self, resource: R, amount: Decimal) -> CallBuilder { + let resource_address = resource.address(self); + self.call_builder().withdraw(resource_address, amount) + } } diff --git a/test-engine/tests/general/mod.rs b/test-engine/tests/general/mod.rs index 74f7c15..bdbff2c 100644 --- a/test-engine/tests/general/mod.rs +++ b/test-engine/tests/general/mod.rs @@ -24,7 +24,7 @@ fn test_pre_allocated_token() { fn test_transfer() { let mut test_engine = TestEngine::new(); - test_engine.new_token("Test token", 1000); + test_engine.new_token("Test token", 1000, 18); test_engine.new_account("Recipient"); assert_eq!(test_engine.balance_of("Recipient", "Test token"), dec!(0)); diff --git a/test-engine/tests/gumball_machine/unit_tests.rs b/test-engine/tests/gumball_machine/unit_tests.rs index 851ae59..9d20dd6 100644 --- a/test-engine/tests/gumball_machine/unit_tests.rs +++ b/test-engine/tests/gumball_machine/unit_tests.rs @@ -17,8 +17,10 @@ mod gumball_machine_tests { #[test] fn test_buy_gumball_success() { let mut test_engine = instantiate_gumball(); - let receipt = - test_engine.call_method("buy_gumball", env_args!(Fungible::Bucket("XRD", 10))); + let receipt = test_engine.call_method( + "buy_gumball", + env_args!(Fungible::FromAccount("XRD", dec!(10))), + ); receipt.assert_is_success(); let amount_owned = test_engine.current_balance("GUM"); assert_eq!(amount_owned, Decimal::one()) @@ -28,7 +30,10 @@ mod gumball_machine_tests { fn test_buy_gumball_fail() { let mut test_engine = instantiate_gumball(); test_engine - .call_method("buy_gumball", env_args!(Fungible::Bucket("XRD", 1))) + .call_method( + "buy_gumball", + env_args!(Fungible::FromAccount("XRD", dec!(1))), + ) .assert_failed_with(""); let amount_owned = test_engine.current_balance("GUM"); assert_eq!(amount_owned, Decimal::zero()) diff --git a/test-engine/tests/nft_marketplace/unit_tests.rs b/test-engine/tests/nft_marketplace/unit_tests.rs index 16a8e7e..48b145d 100644 --- a/test-engine/tests/nft_marketplace/unit_tests.rs +++ b/test-engine/tests/nft_marketplace/unit_tests.rs @@ -28,7 +28,7 @@ mod nft_marketplace_tests { "DutchAuction", "instantiate_dutch_auction", env_args![ - env_vec![NonFungible::Bucket("cars nft", vec![car_id.unwrap()])], + env_vec![NonFungible::FromAccount("cars nft", vec![car_id.unwrap()])], Environment::Resource("xrd"), dec!(10), dec!(5), @@ -57,7 +57,7 @@ mod nft_marketplace_tests { new_buyer(&mut test_engine, "buyer"); let amount_owned_before = test_engine.current_balance("xrd"); test_engine - .call_method("buy", env_args![Fungible::Bucket("xrd", 10)]) + .call_method("buy", env_args![Fungible::FromAccount("xrd", dec!(10))]) .assert_is_success(); let amount_owned_after = test_engine.current_balance("radix"); assert_eq!(amount_owned_before - amount_owned_after, dec!(10)); @@ -71,7 +71,7 @@ mod nft_marketplace_tests { test_engine.jump_epochs(5); let amount_owned_before = test_engine.current_balance("xrd"); test_engine - .call_method_builder("buy", env_args![Fungible::Bucket("xrd", 10)]) + .call("buy", env_args![Fungible::FromAccount("xrd", dec!(10))]) .output("tests/nft_marketplace/package/manifests/", "buy") .execute(); let amount_owned_after = test_engine.current_balance("radix"); @@ -85,7 +85,7 @@ mod nft_marketplace_tests { new_buyer(&mut test_engine, "buyer"); test_engine.jump_epochs(3); test_engine.call_method("buy", env_args![ - Fungible::Bucket("xrd", 5) + Fungible::FromAccount("xrd", dec!(5)) ]).assert_failed_with("[Buy]: Invalid quantity was provided. This sale can only go through when 8.5 tokens are provided."); } diff --git a/test-engine/tests/radiswap/unit_tests.rs b/test-engine/tests/radiswap/unit_tests.rs index 04c586d..e61fbcc 100644 --- a/test-engine/tests/radiswap/unit_tests.rs +++ b/test-engine/tests/radiswap/unit_tests.rs @@ -5,8 +5,8 @@ mod radiswap_tests { fn initialize() -> TestEngine { let mut test_engine = TestEngine::with_package("radiswap package", &RADISWAP_PACKAGE); - test_engine.new_token("usd", dec!(100000)); - test_engine.new_token("btc", dec!(100)); + test_engine.new_token("usd", dec!(100000), 18); + test_engine.new_token("btc", dec!(100), 18); test_engine.new_component( "radiswap", "Radiswap", @@ -26,8 +26,8 @@ mod radiswap_tests { test_engine.call_method( "add_liquidity", env_args!( - Fungible::Bucket("usd", dec!(1000)), - Fungible::Bucket("btc", dec!(1)) + Fungible::FromAccount("usd", dec!(1000)), + Fungible::FromAccount("btc", dec!(1)) ), ); let usd_amount = test_engine.current_balance("usd"); @@ -42,11 +42,11 @@ mod radiswap_tests { test_engine.call_method( "add_liquidity", env_args!( - Fungible::Bucket("usd", dec!(1000)), - Fungible::Bucket("btc", dec!(1)) + Fungible::FromAccount("usd", dec!(1000)), + Fungible::FromAccount("btc", dec!(1)) ), ); - test_engine.call_method("swap", env_args!(Fungible::Bucket("usd", dec!(1000)))); + test_engine.call_method("swap", env_args!(Fungible::FromAccount("usd", dec!(1000)))); let usd_amount = test_engine.current_balance("usd"); let btc_amount = test_engine.current_balance("btc"); assert_eq!(usd_amount, dec!(98000)); diff --git a/test-engine/tutorials/3.MethodsCalls.md b/test-engine/tutorials/3.Methods_Calls.md similarity index 100% rename from test-engine/tutorials/3.MethodsCalls.md rename to test-engine/tutorials/3.Methods_Calls.md