use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Family {
Stock,
Blake2b,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Pow {
Sha256d,
Blake2b,
Scrypt,
Verthash,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Fork {
pub height: u32,
pub hash: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Parent {
pub alias: &'static str,
pub network: Option<&'static str>,
pub label: &'static str,
pub family: Family,
pub pow: Pow,
pub mainnet: bool,
pub genesis: Option<&'static str>,
pub fork: Option<Fork>,
pub reserved: bool,
}
pub const PARENTS: [Parent; 6] = [
Parent {
alias: "btc",
network: Some("btc:mainnet"),
label: "Bitcoin mainnet",
family: Family::Stock,
pow: Pow::Sha256d,
mainnet: true,
genesis: Some("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
fork: None,
reserved: false,
},
Parent {
alias: "tbtc4",
network: Some("btc:testnet4"),
label: "Bitcoin testnet4",
family: Family::Stock,
pow: Pow::Sha256d,
mainnet: false,
genesis: Some("00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043"),
fork: None,
reserved: false,
},
Parent {
alias: "xbt",
network: Some("btc:mainnet-blake2b"),
label: "BLAKE2b mainnet (Knots)",
family: Family::Blake2b,
pow: Pow::Blake2b,
mainnet: true,
genesis: Some("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
fork: Some(Fork {
height: 961_640,
hash: "0000000000000050c1e5f69672f459293be14f46e5a494e7a8c8541396f18eeb",
}),
reserved: false,
},
Parent {
alias: "txbt4",
network: Some("btc:testnet4-blake2b"),
label: "BLAKE2b testnet4 (Knots)",
family: Family::Blake2b,
pow: Pow::Blake2b,
mainnet: false,
genesis: Some("00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043"),
fork: Some(Fork {
height: 150_308,
hash: "000000000000b9d1b7e1bb0e77215ee92c6ef7ec8f4473e23908380649e779b6",
}),
reserved: false,
},
Parent {
alias: "ltc",
network: None,
label: "Litecoin mainnet",
family: Family::Stock,
pow: Pow::Scrypt,
mainnet: true,
genesis: None,
fork: None,
reserved: true,
},
Parent {
alias: "vtc",
network: None,
label: "Vertcoin mainnet",
family: Family::Stock,
pow: Pow::Verthash,
mainnet: true,
genesis: None,
fork: None,
reserved: true,
},
];
pub fn parent_alias(id: &str) -> Option<&'static str> {
PARENTS
.iter()
.find(|p| p.alias == id || p.network == Some(id))
.map(|p| p.alias)
}
pub fn resolve_parent(id: &str) -> Result<&'static Parent> {
let alias = parent_alias(id).ok_or_else(|| Error::UnknownParent(id.to_string()))?;
let p = PARENTS
.iter()
.find(|p| p.alias == alias)
.expect("alias came from the table");
if p.reserved {
return Err(Error::ReservedParent {
alias: p.alias,
label: p.label,
});
}
Ok(p)
}
pub fn is_blake2b(id: &str) -> Result<bool> {
Ok(resolve_parent(id)?.family == Family::Blake2b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn table() {
assert_eq!(
resolve_parent("txbt4").unwrap().network,
Some("btc:testnet4-blake2b")
);
assert_eq!(
resolve_parent("btc:testnet4-blake2b").unwrap().alias,
"txbt4"
);
assert_eq!(
resolve_parent("xbt").unwrap().network,
Some("btc:mainnet-blake2b")
);
assert_eq!(resolve_parent("btc:mainnet-blake2b").unwrap().alias, "xbt");
let by = |a: &str| PARENTS.iter().find(|p| p.alias == a).unwrap();
assert_eq!(by("xbt").genesis, by("btc").genesis);
assert_eq!(by("txbt4").genesis, by("tbtc4").genesis);
assert_eq!(by("txbt4").fork.unwrap().height, 150_308);
assert_eq!(by("xbt").fork.unwrap().height, 961_640);
assert!(is_blake2b("txbt4").unwrap() && is_blake2b("xbt").unwrap());
assert!(!is_blake2b("btc").unwrap() && !is_blake2b("tbtc4").unwrap());
assert_eq!(parent_alias("xbt4"), None);
assert!(matches!(
resolve_parent("ltc"),
Err(Error::ReservedParent { alias: "ltc", .. })
));
let e = resolve_parent("doge").unwrap_err().to_string();
assert!(e.contains("unknown parent \"doge\"") && e.contains("txbt4"));
assert!(resolve_parent("xbt").unwrap().mainnet && resolve_parent("btc").unwrap().mainnet);
assert!(
!resolve_parent("txbt4").unwrap().mainnet
&& !resolve_parent("btc:testnet4-blake2b").unwrap().mainnet
);
for name in ["__proto__", "constructor", "toString", ""] {
assert_eq!(parent_alias(name), None);
}
}
}