mirror of
https://github.com/mimblewimble/grin.git
synced 2025-03-14 13:01:09 +03:00
add job_id to stratum job and solution rpc messages (#1240)
* add job_id to stratum job and solution rpc messages * remove unnecessary clone
This commit is contained in:
parent
64db4d92f0
commit
c7d78446f3
1 changed files with 125 additions and 92 deletions
|
@ -28,7 +28,7 @@ use chain;
|
||||||
use common::adapters::PoolToChainAdapter;
|
use common::adapters::PoolToChainAdapter;
|
||||||
use common::stats::{StratumStats, WorkerStats};
|
use common::stats::{StratumStats, WorkerStats};
|
||||||
use common::types::{StratumServerConfig, SyncState};
|
use common::types::{StratumServerConfig, SyncState};
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::Block;
|
||||||
use core::{pow, global};
|
use core::{pow, global};
|
||||||
use keychain;
|
use keychain;
|
||||||
use mining::mine_block;
|
use mining::mine_block;
|
||||||
|
@ -75,6 +75,7 @@ struct LoginParams {
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct SubmitParams {
|
struct SubmitParams {
|
||||||
height: u64,
|
height: u64,
|
||||||
|
job_id: u64,
|
||||||
nonce: u64,
|
nonce: u64,
|
||||||
pow: Vec<u64>,
|
pow: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
@ -82,6 +83,7 @@ struct SubmitParams {
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct JobTemplate {
|
pub struct JobTemplate {
|
||||||
height: u64,
|
height: u64,
|
||||||
|
job_id: u64,
|
||||||
difficulty: u64,
|
difficulty: u64,
|
||||||
pre_pow: String,
|
pre_pow: String,
|
||||||
}
|
}
|
||||||
|
@ -230,7 +232,7 @@ pub struct StratumServer {
|
||||||
config: StratumServerConfig,
|
config: StratumServerConfig,
|
||||||
chain: Arc<chain::Chain>,
|
chain: Arc<chain::Chain>,
|
||||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||||
current_block: Block,
|
current_block_versions: Vec<Block>,
|
||||||
current_difficulty: u64,
|
current_difficulty: u64,
|
||||||
minimum_share_difficulty: u64,
|
minimum_share_difficulty: u64,
|
||||||
current_key_id: Option<keychain::Identifier>,
|
current_key_id: Option<keychain::Identifier>,
|
||||||
|
@ -251,7 +253,7 @@ impl StratumServer {
|
||||||
config: config,
|
config: config,
|
||||||
chain: chain_ref,
|
chain: chain_ref,
|
||||||
tx_pool: tx_pool,
|
tx_pool: tx_pool,
|
||||||
current_block: Block::default(),
|
current_block_versions: Vec::new(),
|
||||||
current_difficulty: <u64>::max_value(),
|
current_difficulty: <u64>::max_value(),
|
||||||
current_key_id: None,
|
current_key_id: None,
|
||||||
workers: Arc::new(Mutex::new(Vec::new())),
|
workers: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
@ -260,13 +262,15 @@ impl StratumServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build and return a JobTemplate for mining the current block
|
// Build and return a JobTemplate for mining the current block
|
||||||
fn build_block_template(&self, bh: BlockHeader) -> JobTemplate {
|
fn build_block_template(&self) -> JobTemplate {
|
||||||
|
let bh = self.current_block_versions.last().unwrap().header.clone();
|
||||||
// Serialize the block header into pre and post nonce strings
|
// Serialize the block header into pre and post nonce strings
|
||||||
let mut pre_pow_writer = mine_block::HeaderPrePowWriter::default();
|
let mut pre_pow_writer = mine_block::HeaderPrePowWriter::default();
|
||||||
bh.write_pre_pow(&mut pre_pow_writer).unwrap();
|
bh.write_pre_pow(&mut pre_pow_writer).unwrap();
|
||||||
let pre = pre_pow_writer.as_hex_string(false);
|
let pre = pre_pow_writer.as_hex_string(false);
|
||||||
let job_template = JobTemplate {
|
let job_template = JobTemplate {
|
||||||
height: bh.height,
|
height: bh.height,
|
||||||
|
job_id: (self.current_block_versions.len() - 1) as u64,
|
||||||
difficulty: self.minimum_share_difficulty,
|
difficulty: self.minimum_share_difficulty,
|
||||||
pre_pow: pre,
|
pre_pow: pre,
|
||||||
};
|
};
|
||||||
|
@ -328,8 +332,7 @@ impl StratumServer {
|
||||||
};
|
};
|
||||||
Err(serde_json::to_value(e).unwrap())
|
Err(serde_json::to_value(e).unwrap())
|
||||||
} else {
|
} else {
|
||||||
let b = self.current_block.header.clone();
|
self.handle_getjobtemplate()
|
||||||
self.handle_getjobtemplate(b)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"status" => {
|
"status" => {
|
||||||
|
@ -383,7 +386,7 @@ impl StratumServer {
|
||||||
// Return worker status in json for use by a dashboard or healthcheck.
|
// Return worker status in json for use by a dashboard or healthcheck.
|
||||||
let status = WorkerStatus {
|
let status = WorkerStatus {
|
||||||
id: worker_stats.id.clone(),
|
id: worker_stats.id.clone(),
|
||||||
height: self.current_block.header.height,
|
height: self.current_block_versions.last().unwrap().header.height,
|
||||||
difficulty: worker_stats.pow_difficulty,
|
difficulty: worker_stats.pow_difficulty,
|
||||||
accepted: worker_stats.num_accepted,
|
accepted: worker_stats.num_accepted,
|
||||||
rejected: worker_stats.num_rejected,
|
rejected: worker_stats.num_rejected,
|
||||||
|
@ -394,10 +397,17 @@ impl StratumServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle GETJOBTEMPLATE message
|
// Handle GETJOBTEMPLATE message
|
||||||
fn handle_getjobtemplate(&self, bh: BlockHeader) -> Result<Value, Value> {
|
fn handle_getjobtemplate(&self) -> Result<Value, Value> {
|
||||||
// Build a JobTemplate from a BlockHeader and return JSON
|
// Build a JobTemplate from a BlockHeader and return JSON
|
||||||
let job_template = self.build_block_template(bh);
|
let job_template = self.build_block_template();
|
||||||
let response = serde_json::to_value(&job_template).unwrap();
|
let response = serde_json::to_value(&job_template).unwrap();
|
||||||
|
debug!(
|
||||||
|
LOGGER,
|
||||||
|
"(Server ID: {}) sending block {} with id {} to single worker",
|
||||||
|
self.id,
|
||||||
|
job_template.height,
|
||||||
|
job_template.job_id,
|
||||||
|
);
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,13 +457,41 @@ impl StratumServer {
|
||||||
return Err(serde_json::to_value(e).unwrap());
|
return Err(serde_json::to_value(e).unwrap());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut b: Block;
|
|
||||||
let share_difficulty: u64;
|
let share_difficulty: u64;
|
||||||
let mut share_is_block = false;
|
let mut share_is_block = false;
|
||||||
if params.height == self.current_block.header.height {
|
if params.height != self.current_block_versions.last().unwrap().header.height {
|
||||||
|
// Return error status
|
||||||
|
error!(
|
||||||
|
LOGGER,
|
||||||
|
"(Server ID: {}) Share at height {} submitted too late", self.id, params.height,
|
||||||
|
);
|
||||||
|
worker_stats.num_stale += 1;
|
||||||
|
let e = RpcError {
|
||||||
|
code: -32503,
|
||||||
|
message: "Solution submitted too late".to_string(),
|
||||||
|
};
|
||||||
|
return Err(serde_json::to_value(e).unwrap());
|
||||||
|
}
|
||||||
|
// Find the correct version of the block to match this header
|
||||||
|
let b: Option<&Block> = self.current_block_versions.get(params.job_id as usize);
|
||||||
|
if b.is_none() {
|
||||||
|
// Return error status
|
||||||
|
error!(
|
||||||
|
LOGGER,
|
||||||
|
"(Server ID: {}) Failed to validate solution at height {}: invalid job_id {}",
|
||||||
|
self.id,
|
||||||
|
params.height,
|
||||||
|
params.job_id,
|
||||||
|
);
|
||||||
|
worker_stats.num_rejected += 1;
|
||||||
|
let e = RpcError {
|
||||||
|
code: -32502,
|
||||||
|
message: "Failed to validate solution".to_string(),
|
||||||
|
};
|
||||||
|
return Err(serde_json::to_value(e).unwrap());
|
||||||
|
}
|
||||||
|
let mut b: Block = b.unwrap().clone();
|
||||||
// Reconstruct the block header with this nonce and pow added
|
// Reconstruct the block header with this nonce and pow added
|
||||||
b = self.current_block.clone();
|
|
||||||
b.header.nonce = params.nonce;
|
b.header.nonce = params.nonce;
|
||||||
b.header.pow.nonces = params.pow;
|
b.header.pow.nonces = params.pow;
|
||||||
// Get share difficulty
|
// Get share difficulty
|
||||||
|
@ -477,6 +515,7 @@ impl StratumServer {
|
||||||
}
|
}
|
||||||
// If the difficulty is high enough, submit it (which also validates it)
|
// If the difficulty is high enough, submit it (which also validates it)
|
||||||
if share_difficulty >= self.current_difficulty {
|
if share_difficulty >= self.current_difficulty {
|
||||||
|
// This is a full solution, submit it to the network
|
||||||
let res = self.chain.process_block(b.clone(), chain::Options::MINE);
|
let res = self.chain.process_block(b.clone(), chain::Options::MINE);
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
// Return error status
|
// Return error status
|
||||||
|
@ -493,21 +532,24 @@ impl StratumServer {
|
||||||
message: "Failed to validate solution".to_string(),
|
message: "Failed to validate solution".to_string(),
|
||||||
};
|
};
|
||||||
return Err(serde_json::to_value(e).unwrap());
|
return Err(serde_json::to_value(e).unwrap());
|
||||||
} else {
|
|
||||||
share_is_block = true;
|
|
||||||
}
|
}
|
||||||
// Success case falls through to be logged
|
share_is_block = true;
|
||||||
|
// Log message to make it obvious we found a block
|
||||||
|
warn!(
|
||||||
|
LOGGER,
|
||||||
|
"(Server ID: {}) Solution Found for block {} - Yay!!!", self.id, params.height
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// This is a low-difficulty share, not a full solution
|
|
||||||
// Do some validation but dont submit
|
// Do some validation but dont submit
|
||||||
if !pow::verify_size(&b.header, global::min_sizeshift()) {
|
if !pow::verify_size(&b.header, global::min_sizeshift()) {
|
||||||
// Return error status
|
// Return error status
|
||||||
error!(
|
error!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"(Server ID: {}) Failed to validate share at height {} with nonce {}",
|
"(Server ID: {}) Failed to validate share at height {} with nonce {} using job_id {}",
|
||||||
self.id,
|
self.id,
|
||||||
params.height,
|
params.height,
|
||||||
b.header.nonce
|
b.header.nonce,
|
||||||
|
params.job_id,
|
||||||
);
|
);
|
||||||
worker_stats.num_rejected += 1;
|
worker_stats.num_rejected += 1;
|
||||||
let e = RpcError {
|
let e = RpcError {
|
||||||
|
@ -517,19 +559,6 @@ impl StratumServer {
|
||||||
return Err(serde_json::to_value(e).unwrap());
|
return Err(serde_json::to_value(e).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Return error status
|
|
||||||
error!(
|
|
||||||
LOGGER,
|
|
||||||
"(Server ID: {}) Share at height {} submitted too late", self.id, params.height,
|
|
||||||
);
|
|
||||||
worker_stats.num_stale += 1;
|
|
||||||
let e = RpcError {
|
|
||||||
code: -32503,
|
|
||||||
message: "Solution submitted too late".to_string(),
|
|
||||||
};
|
|
||||||
return Err(serde_json::to_value(e).unwrap());
|
|
||||||
}
|
|
||||||
// Log this as a valid share
|
// Log this as a valid share
|
||||||
let submitted_by = match worker.login.clone() {
|
let submitted_by = match worker.login.clone() {
|
||||||
None => worker.id.to_string(),
|
None => worker.id.to_string(),
|
||||||
|
@ -588,15 +617,8 @@ impl StratumServer {
|
||||||
// Broadcast a jobtemplate RpcRequest to all connected workers - no response
|
// Broadcast a jobtemplate RpcRequest to all connected workers - no response
|
||||||
// expected
|
// expected
|
||||||
fn broadcast_job(&mut self) {
|
fn broadcast_job(&mut self) {
|
||||||
debug!(
|
|
||||||
LOGGER,
|
|
||||||
"(Server ID: {}) sending block {} to stratum clients",
|
|
||||||
self.id,
|
|
||||||
self.current_block.header.height
|
|
||||||
);
|
|
||||||
|
|
||||||
// Package new block into RpcRequest
|
// Package new block into RpcRequest
|
||||||
let job_template = self.build_block_template(self.current_block.header.clone());
|
let job_template = self.build_block_template();
|
||||||
let job_template_json = serde_json::to_string(&job_template).unwrap();
|
let job_template_json = serde_json::to_string(&job_template).unwrap();
|
||||||
// Issue #1159 - use a serde_json Value type to avoid extra quoting
|
// Issue #1159 - use a serde_json Value type to avoid extra quoting
|
||||||
let job_template_value: Value = serde_json::from_str(&job_template_json).unwrap();
|
let job_template_value: Value = serde_json::from_str(&job_template_json).unwrap();
|
||||||
|
@ -607,7 +629,13 @@ impl StratumServer {
|
||||||
params: Some(job_template_value),
|
params: Some(job_template_value),
|
||||||
};
|
};
|
||||||
let job_request_json = serde_json::to_string(&job_request).unwrap();
|
let job_request_json = serde_json::to_string(&job_request).unwrap();
|
||||||
|
debug!(
|
||||||
|
LOGGER,
|
||||||
|
"(Server ID: {}) sending block {} with id {} to stratum clients",
|
||||||
|
self.id,
|
||||||
|
job_template.height,
|
||||||
|
job_template.job_id,
|
||||||
|
);
|
||||||
// Push the new block to all connected clients
|
// Push the new block to all connected clients
|
||||||
// NOTE: We do not give a unique nonce (should we?) so miners need
|
// NOTE: We do not give a unique nonce (should we?) so miners need
|
||||||
// to choose one for themselves
|
// to choose one for themselves
|
||||||
|
@ -651,6 +679,7 @@ impl StratumServer {
|
||||||
let mut current_hash = head.prev_block_h;
|
let mut current_hash = head.prev_block_h;
|
||||||
let mut latest_hash;
|
let mut latest_hash;
|
||||||
let listen_addr = self.config.stratum_server_addr.clone().unwrap();
|
let listen_addr = self.config.stratum_server_addr.clone().unwrap();
|
||||||
|
self.current_block_versions.push(Block::default());
|
||||||
|
|
||||||
// Start a thread to accept new worker connections
|
// Start a thread to accept new worker connections
|
||||||
let mut workers_th = self.workers.clone();
|
let mut workers_th = self.workers.clone();
|
||||||
|
@ -698,7 +727,11 @@ impl StratumServer {
|
||||||
if !self.config.burn_reward {
|
if !self.config.burn_reward {
|
||||||
wallet_listener_url = Some(self.config.wallet_listener_url.clone());
|
wallet_listener_url = Some(self.config.wallet_listener_url.clone());
|
||||||
}
|
}
|
||||||
|
// If this is a new block, clear the current_block version history
|
||||||
|
if current_hash != latest_hash {
|
||||||
|
self.current_block_versions.clear();
|
||||||
|
}
|
||||||
|
// Build the new block (version)
|
||||||
let (new_block, block_fees) = mine_block::get_block(
|
let (new_block, block_fees) = mine_block::get_block(
|
||||||
&self.chain,
|
&self.chain,
|
||||||
&self.tx_pool,
|
&self.tx_pool,
|
||||||
|
@ -706,8 +739,7 @@ impl StratumServer {
|
||||||
MAX_TX.clone(),
|
MAX_TX.clone(),
|
||||||
wallet_listener_url,
|
wallet_listener_url,
|
||||||
);
|
);
|
||||||
self.current_block = new_block;
|
self.current_difficulty = (new_block.header.total_difficulty.clone()
|
||||||
self.current_difficulty = (self.current_block.header.total_difficulty.clone()
|
|
||||||
- head.total_difficulty.clone())
|
- head.total_difficulty.clone())
|
||||||
.to_num();
|
.to_num();
|
||||||
self.current_key_id = block_fees.key_id();
|
self.current_key_id = block_fees.key_id();
|
||||||
|
@ -722,10 +754,11 @@ impl StratumServer {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||||
stratum_stats.block_height = self.current_block.header.height;
|
stratum_stats.block_height = new_block.header.height;
|
||||||
stratum_stats.network_difficulty = self.current_difficulty;
|
stratum_stats.network_difficulty = self.current_difficulty;
|
||||||
}
|
}
|
||||||
|
// Add this new block version to our current block map
|
||||||
|
self.current_block_versions.push(new_block);
|
||||||
// Send this job to all connected workers
|
// Send this job to all connected workers
|
||||||
self.broadcast_job();
|
self.broadcast_job();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue