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

darkfid2: (very) raw miner task added

aggstam 2 лет назад
Родитель
Сommit
214a4f458d

+ 1 - 1
bin/darkfid2/darkfid_config.toml

@@ -22,7 +22,7 @@ testing_mode = false
 [sync_net]
 # P2P accept addresses the instance listens on for inbound connections
 # You can also use an IPv6 address
-inbound = ["tcp+tls://0.0.0.0:8342"]
+inbound = ["tcp+tls://0.0.0.0:18342"]
 # IPv6 version:
 #inbound = ["tcp+tls://[::]:8342"]
 # Combined:

+ 28 - 3
bin/darkfid2/src/main.rs

@@ -55,7 +55,7 @@ mod rpc_tx;
 
 /// Validator async tasks
 mod task;
-use task::sync::sync_task;
+use task::{miner_task, sync_task};
 
 /// P2P net protocols
 mod proto;
@@ -223,11 +223,11 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
 
     // Consensus protocol
     if args.consensus {
-        info!("Starting consensus P2P network");
+        info!(target: "darkfid", "Starting consensus P2P network");
         let consensus_p2p = consensus_p2p.clone().unwrap();
         consensus_p2p.clone().start().await?;
     } else {
-        info!("Not starting consensus P2P network");
+        info!(target: "darkfid", "Not starting consensus P2P network");
     }
 
     // Sync blockchain
@@ -240,6 +240,28 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
     // Clean node pending transactions
     darkfid.validator.write().await.purge_pending_txs().await?;
 
+    // Consensus protocol
+    let consensus_task = if args.consensus {
+        info!(target: "darkfid", "Starting consensus protocol task");
+        let task = StoppableTask::new();
+        task.clone().start(
+            // Weird hack to prevent lifetimes hell
+            async move { miner_task(&darkfid).await },
+            |res| async {
+                match res {
+                    Ok(()) | Err(Error::MinerTaskStopped) => { /* Do nothing */ }
+                    Err(e) => error!(target: "darkfid", "Failed starting miner task: {}", e),
+                }
+            },
+            Error::MinerTaskStopped,
+            ex.clone(),
+        );
+        Some(task)
+    } else {
+        info!(target: "darkfid", "Not participating in consensus");
+        None
+    };
+
     // Signal handling for graceful termination.
     let (signals_handler, signals_task) = SignalHandler::new(ex)?;
     signals_handler.wait_termination(signals_task).await?;
@@ -254,6 +276,9 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
     if args.consensus {
         info!(target: "darkfid", "Stopping consensus P2P network...");
         consensus_p2p.unwrap().stop().await;
+
+        info!(target: "darkfid", "Stopping consensus task...");
+        consensus_task.unwrap().stop().await;
     }
 
     info!(target: "darkfid", "Flushing sled database...");

+ 98 - 0
bin/darkfid2/src/task/miner.rs

@@ -0,0 +1,98 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use darkfi::{
+    blockchain::BlockInfo,
+    system::sleep,
+    util::time::Timestamp,
+    validator::pow::{mine_block, PoWModule},
+    Result,
+};
+use log::info;
+
+use crate::{proto::BlockInfoMessage, Darkfid};
+
+/// async task used for participating in the PoW consensus protocol
+pub async fn miner_task(node: &Darkfid) -> Result<()> {
+    // TODO: For now we asume we have a single miner that produces block,
+    //       until the PoW consensus and proper validations have been added.
+    //       The miner workflow would be:
+    //          First we wait for next finalization, for optimal conditions.
+    //          After that we ask all our connected peers for their blocks,
+    //          and append them to our consensus state, creating their forks.
+    //          Then we evaluate each fork and find the best one, so we can
+    //          mine its next.
+    //          We start running 2 tasks, one listenning for blocks(proposals)
+    //          from other miners, and one mining the best fork next block.
+    //          These two tasks run in parallel. If we receive a block from
+    //          another miner, we evaluate it and if it produces a higher
+    //          ranking fork that the one we currectly mine, we stop, check
+    //          if we can finalize any fork, and then start mining that fork
+    //          next block. If we manage to mine the block next, we broadcast
+    //          it and then execute the finalization check and start mining
+    //          next best fork block.
+    info!(target: "darkfid::task::miner_task", "Starting miner task...");
+
+    // TODO: Remove this once proper validations are added
+    // We sleep so our miner can grab their pickaxe
+    sleep(10).await;
+
+    // TODO: add miner threads arg
+    // Generate a PoW module
+    let mut module = PoWModule::new(node.validator.read().await.blockchain.clone(), None, Some(90));
+
+    // Miner loop
+    loop {
+        // TODO: consensus should generate next block, along with its difficulty,
+        //       derived from best fork
+        // Retrieve last block
+        let last = node.validator.read().await.blockchain.last_block()?;
+
+        // Mine next block
+        let difficulty = module.next_difficulty();
+        // TODO: BlockInfo::default() should be based on block version
+        // TODO: block version should be derived from cuttoff const, not
+        //       hardcoded BLOCK_VERSION
+        let mut next_block = BlockInfo::default();
+        next_block.header.version = 0;
+        next_block.header.previous = last.hash()?;
+        next_block.header.height = last.header.height + 1;
+        next_block.header.timestamp = Timestamp::current_time();
+        mine_block(module.clone(), &mut next_block);
+
+        // Verify it
+        module.verify_block(&next_block)?;
+
+        // Generate stuff before pushing block to blockchain
+        let timestamp = next_block.header.timestamp.0;
+        let message = BlockInfoMessage::from(&next_block);
+
+        // Append block to blockchain
+        node.validator.write().await.add_blocks(&[next_block]).await?;
+
+        // Broadcast block
+        node.sync_p2p.broadcast(&message).await;
+
+        // Update PoW module
+        module.append(timestamp, &difficulty);
+
+        // TODO: remove this once mining is not blocking
+        // Lazy way to enable stopping this task
+        sleep(10).await;
+    }
+}

+ 3 - 0
bin/darkfid2/src/task/mod.rs

@@ -20,3 +20,6 @@
 
 pub mod sync;
 pub use sync::sync_task;
+
+pub mod miner;
+pub use miner::miner_task;

+ 3 - 0
src/error.rs

@@ -321,6 +321,9 @@ pub enum Error {
     #[error("Proposal task stopped")]
     ProposalTaskStopped,
 
+    #[error("Miner task stopped")]
+    MinerTaskStopped,
+
     // ===============
     // Database errors
     // ===============