use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::Path;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use serde_with::NoneAsEmptyString;
#[derive(Serialize, Deserialize, Debug)]
struct PoolsJsonFile {
coinbase_tags: HashMap<String, Pool>,
payout_addresses: HashMap<String, Pool>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct Pool {
name: String,
#[serde_as(as = "NoneAsEmptyString")]
link: Option<String>,
}
fn option_string_as_code(option: Option<String>) -> String {
match option {
None => return "None".to_string(),
Some(v) => return format!("Some(\"{}\".to_string())", v).to_string(),
}
}
fn generate_if_for_coinbase_tag(coinbase_tag: String, pool: Pool, first: bool) -> String {
return format!(
"{}if coinbase_utf8.contains(\"{}\") {{
return Some(Pool{{
name: \"{}\".to_string(),
link: {},
identification_method: IdentificationMethod::Tag
}});
}}",
if !first { " else " } else { "" },
coinbase_tag.to_ascii_lowercase(),
pool.name,
option_string_as_code(pool.link)
);
}
fn generate_matches_for_output_addresses(address: String, pool: Pool) -> String {
return format!(
"\"{}\" => {{
return Some(Pool{{
name: \"{}\".to_string(),
link: {},
identification_method: IdentificationMethod::Address
}})
}},\n\t",
address,
pool.name,
option_string_as_code(pool.link)
);
}
fn main() {
let pools_json = fs::read_to_string("./known-mining-pools/pools.json").unwrap();
let pools: PoolsJsonFile = serde_json::from_str(&pools_json).unwrap();
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("matching.rs");
let mut coinbase_tag_matching_ifs = String::default();
for (i, (coinbase_tag, pool)) in pools.coinbase_tags.into_iter().enumerate() {
coinbase_tag_matching_ifs.push_str(&generate_if_for_coinbase_tag(
coinbase_tag,
pool,
i == 0,
));
}
let mut coinbase_output_address_matching_matches = String::default();
for (address, pool) in pools.payout_addresses.into_iter() {
coinbase_output_address_matching_matches
.push_str(&generate_matches_for_output_addresses(address, pool));
}
fs::write(
&dest_path,
format!(
"
// DON'T CHANGE THIS FILE MANUALLY. IT WILL BE OVERWRITTEN.
// This is an automatically generated file.
// Change it's generation in build.rs.
/// Tries to match known mining pool coinbase tags to the given coinbase.
/// Matching is case insensitive. Returning `Some(Pool)` if a pool with
/// this tag is known. Otherwise `None` is returned.
/// The code of this function is auto-generated.
pub fn coinbase_tag_matching(coinbase_utf8: String) -> Option<Pool>{{
let coinbase_utf8 = coinbase_utf8.to_ascii_lowercase();
{}
return None;
}}
/// Tries to match known mining pool addresses to the given address.
/// Returning `Some(Pool)` if a pool with this address is known.
/// Otherwise `None` is returned.
/// The code of this function is auto-generated.
pub fn coinbase_address_matching(address: String) -> Option<Pool> {{
match address.as_str() {{
{}
_ => return None,
}}
}}
",
coinbase_tag_matching_ifs, coinbase_output_address_matching_matches
),
)
.unwrap();
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=known-mining-pools/pools.json");
}