Skip to content

Commit

Permalink
feat(swarm): auto mining (#1174)
Browse files Browse the repository at this point in the history
Description
---
Added auto mining feature to swarm daemon UI. It needs to be started by
hand but afterwards it runs until stopped from UI.



https://github.com/user-attachments/assets/90a00c45-3fef-47c8-a598-7e6ce7415363


Motivation and Context
---
To be able to simulate a real L1 network, we need to have constant
mining on that, so we can see epoch changes and see how the
network/consensus moves forward.

How Has This Been Tested?
---


https://github.com/user-attachments/assets/90a00c45-3fef-47c8-a598-7e6ce7415363

What process can a PR reviewer use to test or verify this change?
---


Breaking Changes
---

- [x] None
- [ ] Requires data directory to be deleted
- [ ] Other - Please specify
  • Loading branch information
ksrichard authored Oct 18, 2024
1 parent 0949763 commit f64bac7
Show file tree
Hide file tree
Showing 4 changed files with 653 additions and 519 deletions.
40 changes: 39 additions & 1 deletion applications/tari_swarm_daemon/src/webserver/context.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::sync::Arc;

use anyhow::bail;
use tari_shutdown::Shutdown;
use tokio::sync::RwLock;

use crate::{config::Config, process_manager::ProcessManagerHandle};

#[derive(Debug, Clone)]
pub struct HandlerContext {
config: Config,
pm_handle: ProcessManagerHandle,
mining_shutdown: Arc<RwLock<Option<Shutdown>>>,
}

impl HandlerContext {
pub fn new(config: Config, pm_handle: ProcessManagerHandle) -> Self {
Self { config, pm_handle }
Self {
config,
pm_handle,
mining_shutdown: Arc::new(RwLock::new(None)),
}
}

pub fn config(&self) -> &Config {
Expand All @@ -21,4 +32,31 @@ impl HandlerContext {
pub fn process_manager(&self) -> &ProcessManagerHandle {
&self.pm_handle
}

pub async fn start_mining(&self, shutdown: Shutdown) -> anyhow::Result<()> {
let lock = self.mining_shutdown.read().await;
if lock.is_none() || lock.as_ref().is_some_and(|curr_shutdown| curr_shutdown.is_triggered()) {
drop(lock);
let mut lock = self.mining_shutdown.write().await;
if lock.is_none() || lock.as_ref().is_some_and(|curr_shutdown| curr_shutdown.is_triggered()) {
*lock = Some(shutdown);
return Ok(());
}
}

bail!("Mining already running!")
}

pub async fn stop_mining(&self) {
let mut lock = self.mining_shutdown.write().await;
if let Some(curr_shutdown) = lock.as_mut() {
curr_shutdown.trigger();
}
*lock = None;
}

pub async fn is_mining(&self) -> bool {
let lock = self.mining_shutdown.read().await;
lock.as_ref().is_some_and(|curr_shutdown| !curr_shutdown.is_triggered())
}
}
72 changes: 72 additions & 0 deletions applications/tari_swarm_daemon/src/webserver/rpc/miners.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::time::Duration;

use log::warn;
use serde::{Deserialize, Serialize};
use tari_shutdown::Shutdown;
use tokio::select;

use crate::webserver::context::HandlerContext;

Expand All @@ -17,3 +22,70 @@ pub async fn mine(context: &HandlerContext, req: MineRequest) -> Result<MineResp
context.process_manager().mine_blocks(req.num_blocks).await?;
Ok(MineResponse {})
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StartMiningRequest {
interval_seconds: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StartMiningResponse {}

pub async fn start_mining(
context: &HandlerContext,
req: StartMiningRequest,
) -> Result<StartMiningResponse, anyhow::Error> {
let shutdown = Shutdown::new();
context.start_mining(shutdown.clone()).await?;

let process_manager = context.process_manager().clone();
tokio::spawn(async move {
let shutdown_signal = shutdown.to_signal();
let interval = tokio::time::interval(Duration::from_secs(req.interval_seconds));
tokio::pin!(shutdown_signal);
tokio::pin!(interval);
loop {
select! {
_ = &mut shutdown_signal => {
break;
}
_ = interval.tick() => {
if let Err(error) = process_manager.mine_blocks(1).await {
warn!("Failed to mine a block: {error:?}");
}
}
}
}
});
Ok(StartMiningResponse {})
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IsMiningRequest {}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IsMiningResponse {
result: bool,
}

pub async fn is_mining(context: &HandlerContext, _req: IsMiningRequest) -> Result<IsMiningResponse, anyhow::Error> {
Ok(IsMiningResponse {
result: context.is_mining().await,
})
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StopMiningRequest {}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StopMiningResponse {
result: bool,
}

pub async fn stop_mining(
context: &HandlerContext,
_req: StopMiningRequest,
) -> Result<StopMiningResponse, anyhow::Error> {
context.stop_mining().await;
Ok(StopMiningResponse { result: true })
}
3 changes: 3 additions & 0 deletions applications/tari_swarm_daemon/src/webserver/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ async fn json_rpc_handler(Extension(context): Extension<Arc<HandlerContext>>, va
"get_stdout" => call_handler(context, value, rpc::logs::list_stdout_files).await,
"get_file" => call_handler(context, value, rpc::logs::get_log_file).await,
"mine" => call_handler(context, value, rpc::miners::mine).await,
"is_mining" => call_handler(context, value, rpc::miners::is_mining).await,
"start_mining" => call_handler(context, value, rpc::miners::start_mining).await,
"stop_mining" => call_handler(context, value, rpc::miners::stop_mining).await,
"add_base_node" | "add_minotari_node" => call_handler(context, value, rpc::minotari_nodes::create).await,
"add_base_wallet" | "add_minotari_wallet" => call_handler(context, value, rpc::minotari_wallets::create).await,
"add_asset_wallet" | "add_wallet_daemon" => call_handler(context, value, rpc::dan_wallets::create).await,
Expand Down
Loading

0 comments on commit f64bac7

Please sign in to comment.