ソースを参照

script/research/streamlet_rust: Block transactions changed from String to tx::Transaction.

Additional modifications:
  script/research/streamlet_rust: fixed epoch calculation
  Added macros at:
    crypto::{note::EncryptedNote, proof::Proof, MintRevealedValues, SpendRevealedValues},
    tx::{Transaction, TransactionClearInput, TransactionInput, TransactionOutput}
aggstam 4 年 前
コミット
5396dae4bb

+ 1 - 2
script/research/streamlet_rust/Cargo.toml

@@ -5,10 +5,9 @@ edition = "2021"
 
 [dependencies.darkfi]
 path = "../../../"
-features = ["crypto"]
+features = ["crypto", "node"]
 
 [dependencies]
-chrono = "0.4"
 rand = "0.8.5"
 
 [workspace]

+ 43 - 26
script/research/streamlet_rust/src/lib.rs

@@ -2,19 +2,23 @@ pub mod structures;
 
 #[cfg(test)]
 mod tests {
-    use chrono::Utc;
-    use std::{thread, time};
+    use std::{
+        thread,
+        time::{Duration, Instant},
+    };
 
     use super::structures::{block::Block, node::Node};
 
+    use darkfi::{crypto::token_id::generate_id2, util::NetworkName};
+
     #[test]
     fn protocol_execution() {
         // Genesis block is generated.
-        let mut genesis_block = Block::new(String::from("⊥"), 0, vec![String::from("⊥")]);
+        let mut genesis_block = Block::new(String::from("⊥"), 0, vec![]);
         genesis_block.notarized = true;
         genesis_block.finalized = true;
 
-        let genesis_time = Utc::now().timestamp();
+        let genesis_time = Instant::now();
 
         // We create some nodes to participate in the Protocol.
         let mut node0 = Node::new(0, genesis_time, genesis_block.clone());
@@ -27,12 +31,17 @@ mod tests {
         let node2_public_key = node2.public_key;
 
         // We simulate some epochs to test consistency.
-        node0.receive_transaction(String::from("tx0"));
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], String::from("tx0"));
-        node1.receive_transaction(String::from("tx1"));
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], String::from("tx1"));
-        node2.receive_transaction(String::from("tx2"));
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], String::from("tx2"));
+        let token_id = generate_id2("STREAMLET", &NetworkName::Ethereum).unwrap();
+
+        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
+        node0.receive_transaction(tx.clone());
+        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
+        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
+        node1.receive_transaction(tx.clone());
+        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
+        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
+        node2.receive_transaction(tx.clone());
+        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
         // Each node checks if they are the epoch leader. Leader will propose the block.
         let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
@@ -66,14 +75,18 @@ mod tests {
         verify_outputs(&node0, &node1, &node2);
 
         // We use thread sleep to simulate sinchronization period.
-        thread::sleep(time::Duration::from_millis(5000));
-
-        node0.receive_transaction(String::from("tx3"));
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], String::from("tx3"));
-        node1.receive_transaction(String::from("tx4"));
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], String::from("tx4"));
-        node2.receive_transaction(String::from("tx5"));
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], String::from("tx5"));
+        thread::sleep(Duration::new(5, 0));
+
+        // Next round.
+        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
+        node0.receive_transaction(tx.clone());
+        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
+        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
+        node1.receive_transaction(tx.clone());
+        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
+        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
+        node2.receive_transaction(tx.clone());
+        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
         // Each node checks if they are the epoch leader. Leader will propose the block.
         let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
@@ -107,14 +120,18 @@ mod tests {
         verify_outputs(&node0, &node1, &node2);
 
         // We use thread sleep to simulate sinchronization period.
-        thread::sleep(time::Duration::from_millis(5000));
-
-        node0.receive_transaction(String::from("tx6"));
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], String::from("tx6"));
-        node1.receive_transaction(String::from("tx7"));
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], String::from("tx7"));
-        node2.receive_transaction(String::from("tx8"));
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], String::from("tx8"));
+        thread::sleep(Duration::new(5, 0));
+
+        // Next round.
+        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
+        node0.receive_transaction(tx.clone());
+        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
+        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
+        node1.receive_transaction(tx.clone());
+        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
+        let tx = node2.generate_transaction(token_id, 150, &node1_public_key).unwrap();
+        node2.receive_transaction(tx.clone());
+        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
 
         // Each node checks if they are the epoch leader. Leader will propose the block.
         let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {

+ 7 - 5
script/research/streamlet_rust/src/structures/block.rs

@@ -2,6 +2,8 @@ use std::hash::{Hash, Hasher};
 
 use super::vote::Vote;
 
+use darkfi::tx::Transaction;
+
 /// This struct represents a tuple of the form (h, e, txs).
 /// Each blocks parent hash h may be computed simply as a hash of the parent block.
 #[derive(Debug, Clone)]
@@ -9,9 +11,9 @@ pub struct Block {
     /// parent hash
     pub h: String,
     /// epoch number
-    pub e: i64,
+    pub e: u64,
     /// transactions payload
-    pub txs: Vec<String>,
+    pub txs: Vec<Transaction>,
     /// Epoch votes
     pub votes: Vec<Vote>,
     /// block notarization flag
@@ -21,12 +23,12 @@ pub struct Block {
 }
 
 impl Block {
-    pub fn new(h: String, e: i64, txs: Vec<String>) -> Block {
+    pub fn new(h: String, e: u64, txs: Vec<Transaction>) -> Block {
         Block { h, e, txs, votes: Vec::new(), notarized: false, finalized: false }
     }
 
     pub fn signature_encode(&self) -> String {
-        self.h.clone() + &self.e.to_string() + &self.txs.clone().join("")
+        format!("{:?}{:?}{:?}", self.h, self.e, self.txs)
     }
 }
 
@@ -38,6 +40,6 @@ impl PartialEq for Block {
 
 impl Hash for Block {
     fn hash<H: Hasher>(&self, hasher: &mut H) {
-        (&self.h, &self.e, &self.txs).hash(hasher);
+        format!("{:?}{:?}{:?}", self.h, self.e, self.txs).hash(hasher);
     }
 }

+ 54 - 22
script/research/streamlet_rust/src/structures/node.rs

@@ -1,13 +1,23 @@
-use chrono::Utc;
 use std::{
     collections::hash_map::DefaultHasher,
     hash::{Hash, Hasher},
+    time::Instant,
 };
 
 use super::{block::Block, blockchain::Blockchain, vote::Vote};
-use darkfi::crypto::{
-    keypair::{PublicKey, SecretKey},
-    schnorr::{SchnorrPublic, SchnorrSecret},
+use darkfi::{
+    crypto::{
+        keypair::{PublicKey, SecretKey},
+        proof::ProvingKey,
+        schnorr::{SchnorrPublic, SchnorrSecret},
+        types::DrkTokenId,
+    },
+    tx::{
+        Transaction, TransactionBuilder, TransactionBuilderClearInputInfo,
+        TransactionBuilderOutputInfo,
+    },
+    zk::circuit::{mint_contract::MintContract, spend_contract::SpendContract},
+    Result,
 };
 use rand::rngs::OsRng;
 
@@ -18,16 +28,16 @@ use rand::rngs::OsRng;
 #[derive(Debug)]
 pub struct Node {
     pub id: u64,
-    pub genesis_time: i64,
+    pub genesis_time: Instant,
     pub secret_key: SecretKey,
     pub public_key: PublicKey,
     pub canonical_blockchain: Blockchain,
     pub node_blockchains: Vec<Blockchain>,
-    pub unconfirmed_transactions: Vec<String>,
+    pub unconfirmed_transactions: Vec<Transaction>,
 }
 
 impl Node {
-    pub fn new(id: u64, genesis_time: i64, init_block: Block) -> Node {
+    pub fn new(id: u64, genesis_time: Instant, init_block: Block) -> Node {
         // TODO: clock sync
         let secret = SecretKey::random(&mut OsRng);
         Node {
@@ -46,14 +56,39 @@ impl Node {
         &self.canonical_blockchain
     }
 
+    /// Node generates a dummy transaction for provided token.
+    /// Additional validity rules must be defined by the protocol for transactions.
+    pub fn generate_transaction(
+        &self,
+        token_id: DrkTokenId,
+        value: u64,
+        public: &PublicKey,
+    ) -> Result<Transaction> {
+        let builder = TransactionBuilder {
+            clear_inputs: vec![TransactionBuilderClearInputInfo {
+                value,
+                token_id,
+                signature_secret: self.secret_key,
+            }],
+            inputs: vec![],
+            outputs: vec![TransactionBuilderOutputInfo { value, token_id, public: *public }],
+        };
+
+        const K: u32 = 11;
+        let mint_pk = ProvingKey::build(K, &MintContract::default());
+        let spend_pk = ProvingKey::build(K, &SpendContract::default());
+
+        builder.build(&mint_pk, &spend_pk)
+    }
+
     /// Node retreives a transaction and append it to the unconfirmed transactions list.
-    /// Additional validity rules must be defined by the protocol for its blockchain data structure.
-    pub fn receive_transaction(&mut self, transaction: String) {
+    /// Additional validity rules must be defined by the protocol for transactions.
+    pub fn receive_transaction(&mut self, transaction: Transaction) {
         self.unconfirmed_transactions.push(transaction);
     }
 
     /// Node broadcast a transaction to provided nodes list.
-    pub fn broadcast_transaction(&mut self, nodes: Vec<&mut Node>, transaction: String) {
+    pub fn broadcast_transaction(&mut self, nodes: Vec<&mut Node>, transaction: Transaction) {
         for node in nodes {
             node.receive_transaction(transaction.clone())
         }
@@ -61,10 +96,9 @@ impl Node {
 
     /// Node calculates current epoch, based on elapsed time from the genesis block.
     /// Epochs duration is configured using the delta value.
-    pub fn get_current_epoch(&self) -> i64 {
-        let delta = 2;
-        let current_time = Utc::now().timestamp();
-        ((current_time - self.genesis_time) % (2 * delta)) + 1
+    pub fn get_current_epoch(&self) -> u64 {
+        let delta = 5;
+        self.genesis_time.elapsed().as_secs() / (2 * delta)
     }
 
     /// Node finds epochs leader, using a simple hash method.
@@ -149,18 +183,16 @@ impl Node {
     pub fn find_extended_blockchain_index(&self, block: &Block) -> i64 {
         let mut hasher = DefaultHasher::new();
         for (index, blockchain) in self.node_blockchains.iter().enumerate() {
-            blockchain.blocks.last().unwrap().hash(&mut hasher);
-            if block.h == hasher.finish().to_string() &&
-                block.e > blockchain.blocks.last().unwrap().e
-            {
+            let last_block = blockchain.blocks.last().unwrap();
+            last_block.hash(&mut hasher);
+            if block.h == hasher.finish().to_string() && block.e > last_block.e {
                 return index as i64
             }
         }
 
-        self.canonical_blockchain.blocks.last().unwrap().hash(&mut hasher);
-        if block.h != hasher.finish().to_string() ||
-            block.e <= self.canonical_blockchain.blocks.last().unwrap().e
-        {
+        let last_block = self.canonical_blockchain.blocks.last().unwrap();
+        last_block.hash(&mut hasher);
+        if block.h != hasher.finish().to_string() || block.e <= last_block.e {
             panic!("Proposed block doesn't extend any known chains.");
         }
         -1

+ 1 - 1
src/crypto/mint_proof.rs

@@ -21,7 +21,7 @@ use crate::{
     Result,
 };
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct MintRevealedValues {
     pub value_commit: DrkValueCommit,
     pub token_commit: DrkValueCommit,

+ 1 - 1
src/crypto/note.rs

@@ -76,7 +76,7 @@ impl Note {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct EncryptedNote {
     ciphertext: [u8; ENC_CIPHERTEXT_SIZE],
     ephem_public: PublicKey,

+ 1 - 1
src/crypto/proof.rs

@@ -44,7 +44,7 @@ impl ProvingKey {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct Proof(Vec<u8>);
 
 impl AsRef<[u8]> for Proof {

+ 1 - 1
src/crypto/spend_proof.rs

@@ -25,7 +25,7 @@ use crate::{
     Result,
 };
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct SpendRevealedValues {
     pub value_commit: DrkValueCommit,
     pub token_commit: DrkValueCommit,

+ 4 - 3
src/tx/mod.rs

@@ -30,13 +30,14 @@ pub use self::builder::{
     TransactionBuilderOutputInfo,
 };
 
+#[derive(Debug, Clone, PartialEq)]
 pub struct Transaction {
     pub clear_inputs: Vec<TransactionClearInput>,
     pub inputs: Vec<TransactionInput>,
     pub outputs: Vec<TransactionOutput>,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct TransactionClearInput {
     pub value: u64,
     pub token_id: DrkTokenId,
@@ -46,14 +47,14 @@ pub struct TransactionClearInput {
     pub signature: schnorr::Signature,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct TransactionInput {
     pub spend_proof: Proof,
     pub revealed: SpendRevealedValues,
     pub signature: schnorr::Signature,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct TransactionOutput {
     pub mint_proof: Proof,
     pub revealed: MintRevealedValues,