Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions api/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::auth::{
use crate::chain::{Chain, SyncState};
use crate::foreign::Foreign;
use crate::foreign_rpc::ForeignRpc;
use crate::owner::Owner;
use crate::owner::{MiningStatsProvider, Owner};
use crate::owner_rpc::OwnerRpc;
use crate::pool;
use crate::pool::{BlockChain, PoolAdapter};
Expand Down Expand Up @@ -63,6 +63,40 @@ pub fn node_apis<B, P>(
api_chan: (mpsc::Sender<()>, mpsc::Receiver<()>),
stop_state: Arc<StopState>,
) -> Result<(), Error>
where
B: BlockChain + 'static,
P: PoolAdapter + 'static,
{
node_apis_with_mining_stats(
addr,
chain,
tx_pool,
peers,
sync_state,
api_secret,
foreign_api_secret,
tls_config,
api_chan,
stop_state,
None,
)
}

/// Same as [`node_apis`] but additionally wires a provider of live stratum
/// mining stats into the Owner API `get_mining_status` method.
pub fn node_apis_with_mining_stats<B, P>(
addr: &str,
chain: Arc<Chain>,
tx_pool: Arc<RwLock<pool::TransactionPool<B, P>>>,
peers: Arc<p2p::Peers>,
sync_state: Arc<SyncState>,
api_secret: Option<String>,
foreign_api_secret: Option<String>,
tls_config: Option<TLSConfig>,
api_chan: (mpsc::Sender<()>, mpsc::Receiver<()>),
stop_state: Arc<StopState>,
mining_stats: Option<MiningStatsProvider>,
Comment thread
wiesche89 marked this conversation as resolved.
) -> Result<(), Error>
where
B: BlockChain + 'static,
P: PoolAdapter + 'static,
Expand All @@ -85,6 +119,7 @@ where
Arc::downgrade(&chain),
Arc::downgrade(&peers),
Arc::downgrade(&sync_state),
mining_stats,
);
router.add_route("/v2/owner", Arc::new(api_handler))?;

Expand Down Expand Up @@ -142,25 +177,33 @@ pub struct OwnerAPIHandlerV2 {
pub chain: Weak<Chain>,
pub peers: Weak<p2p::Peers>,
pub sync_state: Weak<SyncState>,
pub mining_stats: Option<MiningStatsProvider>,
}

impl OwnerAPIHandlerV2 {
/// Create a new owner API handler for GET methods
pub fn new(chain: Weak<Chain>, peers: Weak<p2p::Peers>, sync_state: Weak<SyncState>) -> Self {
pub fn new(
chain: Weak<Chain>,
peers: Weak<p2p::Peers>,
sync_state: Weak<SyncState>,
mining_stats: Option<MiningStatsProvider>,
) -> Self {
OwnerAPIHandlerV2 {
chain,
peers,
sync_state,
mining_stats,
}
}
}

impl crate::router::Handler for OwnerAPIHandlerV2 {
fn post(&self, req: Request<Incoming>) -> ResponseFuture {
let api = Owner::new(
let api = Owner::with_mining_stats(
self.chain.clone(),
self.peers.clone(),
self.sync_state.clone(),
self.mining_stats.clone(),
);

Box::pin(async move {
Expand Down
4 changes: 2 additions & 2 deletions api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ pub use crate::auth::{
};
pub use crate::foreign::Foreign;
pub use crate::foreign_rpc::ForeignRpc;
pub use crate::handlers::node_apis;
pub use crate::owner::Owner;
pub use crate::handlers::{node_apis, node_apis_with_mining_stats};
pub use crate::owner::{MiningStatsProvider, Owner};
pub use crate::owner_rpc::OwnerRpc;
pub use crate::rest::*;
pub use crate::router::*;
Expand Down
84 changes: 82 additions & 2 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ use crate::handlers::server_api::StatusHandler;
use crate::p2p::types::PeerInfoDisplay;
use crate::p2p::{self, PeerData};
use crate::rest::*;
use crate::types::Status;
use crate::types::{MiningStatus, Status};
use std::net::SocketAddr;
use std::sync::Weak;
use std::sync::{Arc, Weak};

/// Callback that returns a snapshot of stratum mining stats for the Owner API.
pub type MiningStatsProvider = Arc<dyn Fn() -> MiningStatus + Send + Sync>;

/// Main interface into all node API functions.
/// Node APIs are split into two separate blocks of functionality
Expand All @@ -37,6 +40,8 @@ pub struct Owner {
pub chain: Weak<Chain>,
pub peers: Weak<p2p::Peers>,
pub sync_state: Weak<SyncState>,
/// Optional provider of live stratum mining stats (set by the server process).
pub mining_stats: Option<MiningStatsProvider>,
}

impl Owner {
Expand All @@ -58,6 +63,22 @@ impl Owner {
chain,
peers,
sync_state,
mining_stats: None,
}
}

/// Create a new Owner API instance with a mining stats provider.
pub fn with_mining_stats(
chain: Weak<Chain>,
peers: Weak<p2p::Peers>,
sync_state: Weak<SyncState>,
mining_stats: Option<MiningStatsProvider>,
) -> Self {
Owner {
chain,
peers,
sync_state,
mining_stats,
}
}

Expand All @@ -78,6 +99,23 @@ impl Owner {
status_handler.get_status()
}

/// Returns current stratum mining statistics, mirroring the TUI mining tab.
///
/// # Returns
/// * Result Containing:
/// * A [`MiningStatus`](types/struct.MiningStatus.html)
/// * or [`Error`](struct.Error.html) if no mining stats provider is configured.
///

pub fn get_mining_status(&self) -> Result<MiningStatus, Error> {
Comment thread
wiesche89 marked this conversation as resolved.
match &self.mining_stats {
Some(provider) => Ok(provider()),
None => Err(Error::Internal(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed now. Could you also update the PR description? It still says a missing provider returns a disabled default.

"no mining stats provider configured".to_string(),
)),
}
}

/// Trigger a validation of the chain state.
///
/// # Arguments
Expand Down Expand Up @@ -201,3 +239,45 @@ impl Owner {
peer_handler.unban_peer(addr)
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::types::{MiningStatus, WorkerInfo};
use std::sync::Arc;

#[test]
fn get_mining_status_without_provider_returns_error() {
let owner = Owner::new(Weak::new(), Weak::new(), Weak::new());
assert!(owner.get_mining_status().is_err());
}

#[test]
fn get_mining_status_with_provider() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we test this once through the generated JSON RPC handler? The current tests only call Owner directly, so the wire response is not covered.

let expected = MiningStatus {
is_enabled: true,
is_running: true,
num_workers: 2,
block_height: 50,
network_difficulty: 10,
edge_bits: 29,
blocks_found: 1,
network_hashrate: 0.5,
minimum_share_difficulty: 1,
worker_stats: vec![WorkerInfo {
id: "w0".into(),
last_seen: 100,
initial_block_height: 40,
pow_difficulty: 1,
num_accepted: 3,
num_rejected: 0,
num_stale: 0,
num_blocks_found: 0,
}],
};
let expected_clone = expected.clone();
let provider: MiningStatsProvider = Arc::new(move || expected_clone.clone());
let owner = Owner::with_mining_stats(Weak::new(), Weak::new(), Weak::new(), Some(provider));
assert_eq!(owner.get_mining_status().unwrap(), expected);
}
}
61 changes: 60 additions & 1 deletion api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::owner::Owner;
use crate::p2p::types::PeerInfoDisplay;
use crate::p2p::PeerData;
use crate::rest::Error;
use crate::types::Status;
use crate::types::{MiningStatus, Status};
use std::net::SocketAddr;

/// Public definition used to generate Node jsonrpc api.
Expand Down Expand Up @@ -73,6 +73,61 @@ pub trait OwnerRpc: Sync + Send {
*/
fn get_status(&self) -> Result<Status, Error>;

/**
Networked version of [Owner::get_mining_status](struct.Owner.html#method.get_mining_status).

Returns the same mining / stratum information shown on the TUI mining tab so
headless operators can query connected workers and share stats.

# Json rpc example

```
# grin_api::doctest_helper_json_rpc_owner_assert_response!(
# r#"
{
"jsonrpc": "2.0",
"method": "get_mining_status",
"params": [],
"id": 1
}
# "#
# ,
# r#"
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"Ok": {
"is_enabled": true,
"is_running": true,
"num_workers": 1,
"block_height": 1000,
"network_difficulty": 42,
"edge_bits": 29,
"blocks_found": 3,
"network_hashrate": 1.5,
"minimum_share_difficulty": 1,
"worker_stats": [
{
"id": "0",
"last_seen": 1609459200,
"initial_block_height": 990,
"pow_difficulty": 1,
"num_accepted": 10,
"num_rejected": 0,
"num_stale": 0,
"num_blocks_found": 1
}
]
}
}
}
# "#
# );
```
*/
fn get_mining_status(&self) -> Result<MiningStatus, Error>;

/**
Networked version of [Owner::validate_chain](struct.Owner.html#method.validate_chain).

Expand Down Expand Up @@ -364,6 +419,10 @@ impl OwnerRpc for Owner {
Owner::get_status(self)
}

fn get_mining_status(&self) -> Result<MiningStatus, Error> {
Owner::get_mining_status(self)
}

fn validate_chain(&self, assume_valid_rangeproofs_kernels: bool) -> Result<(), Error> {
Owner::validate_chain(self, assume_valid_rangeproofs_kernels)
}
Expand Down
Loading
Loading