Просмотр исходного кода

tx: TransactionBuilder created to generate txs using DarkTree

aggstam 2 лет назад
Родитель
Сommit
bd3a32ee18
2 измененных файлов с 83 добавлено и 14 удалено
  1. 18 14
      src/sdk/src/dark_tree.rs
  2. 65 0
      src/tx/mod.rs

+ 18 - 14
src/sdk/src/dark_tree.rs

@@ -18,7 +18,7 @@
 
 
 use std::{collections::VecDeque, iter::FusedIterator, mem};
 use std::{collections::VecDeque, iter::FusedIterator, mem};
 
 
-use crate::error::{DarkTreeResult, DarkTreeError};
+use crate::error::{DarkTreeError, DarkTreeResult};
 
 
 /// This struct represents the information hold by a
 /// This struct represents the information hold by a
 /// [`DarkTreeLeaf`], namely its data, along with positional
 /// [`DarkTreeLeaf`], namely its data, along with positional
@@ -27,12 +27,12 @@ use crate::error::{DarkTreeResult, DarkTreeError};
 /// connected nodes, and are *not* used as pointers by the
 /// connected nodes, and are *not* used as pointers by the
 /// tree. Creator must ensure they are properly setup.
 /// tree. Creator must ensure they are properly setup.
 #[derive(Clone, Debug, PartialEq)]
 #[derive(Clone, Debug, PartialEq)]
-struct DarkLeaf<T>
+pub struct DarkLeaf<T>
 where
 where
     T: Clone,
     T: Clone,
 {
 {
     /// Data holded by this leaf
     /// Data holded by this leaf
-    data: T,
+    pub data: T,
     /// Index showcasing this leaf's parent tree, when all
     /// Index showcasing this leaf's parent tree, when all
     /// leafs are in order. None indicates that this leaf
     /// leafs are in order. None indicates that this leaf
     /// has no parent.
     /// has no parent.
@@ -47,7 +47,7 @@ where
 /// holding this tree node data, along with its positional
 /// holding this tree node data, along with its positional
 /// index, based on tree's traversal order.
 /// index, based on tree's traversal order.
 #[derive(Clone, Debug, PartialEq)]
 #[derive(Clone, Debug, PartialEq)]
-struct DarkTreeLeaf<T>
+pub struct DarkTreeLeaf<T>
 where
 where
     T: Clone,
     T: Clone,
 {
 {
@@ -89,7 +89,7 @@ impl<T: std::clone::Clone> DarkTreeLeaf<T> {
 /// to always execute .build() after finishing setting up the
 /// to always execute .build() after finishing setting up the
 /// Tree, to properly index it and check its integrity.
 /// Tree, to properly index it and check its integrity.
 #[derive(Debug, PartialEq)]
 #[derive(Debug, PartialEq)]
-struct DarkTree<T: std::clone::Clone> {
+pub struct DarkTree<T: std::clone::Clone> {
     /// This tree's leaf information, along with its data
     /// This tree's leaf information, along with its data
     leaf: DarkTreeLeaf<T>,
     leaf: DarkTreeLeaf<T>,
     /// Vector containing all tree's branches(children tree)
     /// Vector containing all tree's branches(children tree)
@@ -115,7 +115,7 @@ struct DarkTree<T: std::clone::Clone> {
 impl<T: std::clone::Clone> DarkTree<T> {
 impl<T: std::clone::Clone> DarkTree<T> {
     /// Initialize a [`DarkTree`], using provided data to
     /// Initialize a [`DarkTree`], using provided data to
     /// generate its root.
     /// generate its root.
-    fn new(
+    pub fn new(
         data: T,
         data: T,
         children: Vec<DarkTree<T>>,
         children: Vec<DarkTree<T>>,
         min_capacity: Option<usize>,
         min_capacity: Option<usize>,
@@ -140,7 +140,7 @@ impl<T: std::clone::Clone> DarkTree<T> {
     /// after we have appended all child nodes, so we
     /// after we have appended all child nodes, so we
     /// don't have to call .index() and .integrity_check()
     /// don't have to call .index() and .integrity_check()
     /// manually.
     /// manually.
-    fn build(&mut self) -> DarkTreeResult<()> {
+    pub fn build(&mut self) -> DarkTreeResult<()> {
         self.index();
         self.index();
         self.integrity_check()
         self.integrity_check()
     }
     }
@@ -148,7 +148,7 @@ impl<T: std::clone::Clone> DarkTree<T> {
     /// Build the [`DarkTree`] using .build() and
     /// Build the [`DarkTree`] using .build() and
     /// then produce a flattened vector containing
     /// then produce a flattened vector containing
     /// all the leafs in DFS post-order traversal order.
     /// all the leafs in DFS post-order traversal order.
-    fn build_vec(&mut self) -> DarkTreeResult<Vec<DarkLeaf<T>>> {
+    pub fn build_vec(&mut self) -> DarkTreeResult<Vec<DarkLeaf<T>>> {
         self.build()?;
         self.build()?;
         Ok(self.iter().cloned().map(|x| x.info).collect())
         Ok(self.iter().cloned().map(|x| x.info).collect())
     }
     }
@@ -182,7 +182,7 @@ impl<T: std::clone::Clone> DarkTree<T> {
     /// if max capacity has not been exceeded. This call
     /// if max capacity has not been exceeded. This call
     /// doesn't update the indexes, so either .index()
     /// doesn't update the indexes, so either .index()
     /// or .build() must be called after it.
     /// or .build() must be called after it.
-    fn append(&mut self, child: DarkTree<T>) -> DarkTreeResult<()> {
+    pub fn append(&mut self, child: DarkTree<T>) -> DarkTreeResult<()> {
         // Check current max capacity
         // Check current max capacity
         if let Some(max_capacity) = self.max_capacity {
         if let Some(max_capacity) = self.max_capacity {
             if self.len() + 1 > max_capacity {
             if self.len() + 1 > max_capacity {
@@ -303,7 +303,7 @@ impl<T: std::clone::Clone> DarkTree<T> {
 
 
 /// Immutable iterator of a [`DarkTree`], performing DFS post-order
 /// Immutable iterator of a [`DarkTree`], performing DFS post-order
 /// traversal on the Tree leafs.
 /// traversal on the Tree leafs.
-struct DarkTreeIter<'a, T: std::clone::Clone> {
+pub struct DarkTreeIter<'a, T: std::clone::Clone> {
     children: &'a [DarkTree<T>],
     children: &'a [DarkTree<T>],
     parent: Option<Box<DarkTreeIter<'a, T>>>,
     parent: Option<Box<DarkTreeIter<'a, T>>>,
 }
 }
@@ -365,7 +365,7 @@ impl<'a, T: std::clone::Clone> IntoIterator for &'a DarkTree<T> {
 
 
 /// Mutable iterator of a [`DarkTree`], performing DFS post-order
 /// Mutable iterator of a [`DarkTree`], performing DFS post-order
 /// traversal on the Tree leafs.
 /// traversal on the Tree leafs.
-struct DarkTreeIterMut<'a, T: std::clone::Clone> {
+pub struct DarkTreeIterMut<'a, T: std::clone::Clone> {
     children: &'a mut [DarkTree<T>],
     children: &'a mut [DarkTree<T>],
     parent: Option<Box<DarkTreeIterMut<'a, T>>>,
     parent: Option<Box<DarkTreeIterMut<'a, T>>>,
     parent_leaf: Option<&'a mut DarkTreeLeaf<T>>,
     parent_leaf: Option<&'a mut DarkTreeLeaf<T>>,
@@ -429,7 +429,7 @@ impl<'a, T: std::clone::Clone> IntoIterator for &'a mut DarkTree<T> {
 /// Special iterator of a [`DarkTree`], performing DFS post-order
 /// Special iterator of a [`DarkTree`], performing DFS post-order
 /// traversal on the Tree leafs, consuming each leaf. Since this
 /// traversal on the Tree leafs, consuming each leaf. Since this
 /// iterator consumes the tree, it becomes unusable after it's moved.
 /// iterator consumes the tree, it becomes unusable after it's moved.
-struct DarkTreeIntoIter<T: std::clone::Clone> {
+pub struct DarkTreeIntoIter<T: std::clone::Clone> {
     children: VecDeque<DarkTree<T>>,
     children: VecDeque<DarkTree<T>>,
     parent: Option<Box<DarkTreeIntoIter<T>>>,
     parent: Option<Box<DarkTreeIntoIter<T>>>,
 }
 }
@@ -497,7 +497,7 @@ impl<T: std::clone::Clone> IntoIterator for DarkTree<T> {
 
 
 /// Auxiliary function to verify provided [`DarkLeaf`] slice is
 /// Auxiliary function to verify provided [`DarkLeaf`] slice is
 /// properly bounded and its members indexes are valid.
 /// properly bounded and its members indexes are valid.
-fn dark_leaf_vec_integrity_check<T: std::clone::Clone>(
+pub fn dark_leaf_vec_integrity_check<T: std::clone::Clone>(
     leafs: &[DarkLeaf<T>],
     leafs: &[DarkLeaf<T>],
     min_capacity: Option<usize>,
     min_capacity: Option<usize>,
     max_capacity: Option<usize>,
     max_capacity: Option<usize>,
@@ -745,7 +745,11 @@ mod tests {
             DarkTree {
             DarkTree {
                 leaf: DarkTreeLeaf {
                 leaf: DarkTreeLeaf {
                     index: 22,
                     index: 22,
-                    info: DarkLeaf { data: 24, parent_index: None, children_indexes: vec![10, 14, 21] },
+                    info: DarkLeaf {
+                        data: 24,
+                        parent_index: None,
+                        children_indexes: vec![10, 14, 21]
+                    },
                 },
                 },
                 children: vec![
                 children: vec![
                     DarkTree {
                     DarkTree {

+ 65 - 0
src/tx/mod.rs

@@ -23,6 +23,8 @@ use darkfi_sdk::{
         schnorr::{SchnorrPublic, SchnorrSecret, Signature},
         schnorr::{SchnorrPublic, SchnorrSecret, Signature},
         PublicKey, SecretKey,
         PublicKey, SecretKey,
     },
     },
+    dark_tree::{dark_leaf_vec_integrity_check, DarkTree},
+    error::DarkTreeResult,
     pasta::pallas,
     pasta::pallas,
     tx::ContractCall,
     tx::ContractCall,
 };
 };
@@ -168,3 +170,66 @@ use crate::net::Message;
 
 
 #[cfg(feature = "net")]
 #[cfg(feature = "net")]
 crate::impl_p2p_message!(Transaction, "tx");
 crate::impl_p2p_message!(Transaction, "tx");
+
+/// Calls tree bounds definitions
+// TODO: increase min to 2 when fees are implement
+pub const MIN_TX_CALLS: usize = 1;
+// TODO: verify max value
+pub const MAX_TX_CALLS: usize = 20;
+
+/// Auxiliarry structure containing all the information
+/// required to execute a contract call.
+#[derive(Clone)]
+pub struct ContractCallLeaf {
+    /// Call executed
+    pub call: ContractCall,
+    /// Attached ZK proofs
+    pub proofs: Vec<Proof>,
+    /// Attached Schnorr signatures
+    pub signatures: Vec<Signature>,
+}
+
+/// Auxilliary structure to build a full [`Transaction`] using
+/// [`DarkTree`] to order everything.
+pub struct TransactionBuilder {
+    /// Contract calls tree
+    pub calls: DarkTree<ContractCallLeaf>,
+}
+
+// TODO: for now we build the tree manually, but we should
+//       add all the proper functions for easier building.
+impl TransactionBuilder {
+    /// Initialize the builder, using provided data to
+    /// generate its [`DarkTree`] root.
+    pub fn new(data: ContractCallLeaf, children: Vec<DarkTree<ContractCallLeaf>>) -> Self {
+        let calls = DarkTree::new(data, children, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS));
+        Self { calls }
+    }
+
+    /// Append a new call to the tree
+    pub fn append(&mut self, child: DarkTree<ContractCallLeaf>) -> DarkTreeResult<()> {
+        self.calls.append(child)
+    }
+
+    /// Builder builds the calls vector using the [`DarkTree`]
+    /// and generates the corresponding [`Transaction`].
+    pub fn build(&mut self) -> DarkTreeResult<Transaction> {
+        // Build the leafs vector
+        let leafs = self.calls.build_vec()?;
+
+        // Double check integrity
+        dark_leaf_vec_integrity_check(&leafs, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
+
+        // Build the corresponding transaction
+        let mut calls = Vec::with_capacity(leafs.len());
+        let mut proofs = Vec::with_capacity(leafs.len());
+        let mut signatures = Vec::with_capacity(leafs.len());
+        for leaf in leafs {
+            calls.push(leaf.data.call);
+            proofs.push(leaf.data.proofs);
+            signatures.push(leaf.data.signatures);
+        }
+
+        Ok(Transaction { calls, proofs, signatures })
+    }
+}