use std::fmt::Debug;
use std::str::FromStr;
use derive_more::derive::{Deref, DerefMut};
use dutils::error::ContextWrapper;
use itertools::Itertools;
use rand::Rng;
use crate::utils::bytes::{concat_arrays, NinBytes};
use crate::utils::sha256::IntoHash256;
use super::hash::Hash256;
#[derive(
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
bytemuck::Pod,
bytemuck::Zeroable,
serde::Serialize,
serde::Deserialize,
Default,
derive_more::Add,
derive_more::Sub,
derive_more::Mul,
derive_more::From,
)]
#[mul(forward)]
#[repr(C)]
#[serde(transparent)]
#[derive(Deref, DerefMut)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct InscriptionNumber(pub u64);
impl num_traits::Bounded for InscriptionNumber {
fn min_value() -> Self {
Self(0)
}
fn max_value() -> Self {
Self::MAX
}
}
impl num_traits::Zero for InscriptionNumber {
fn zero() -> Self {
Self(0)
}
fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl num_traits::One for InscriptionNumber {
fn one() -> Self {
Self(1)
}
}
impl num_traits::SaturatingAdd for InscriptionNumber {
fn saturating_add(&self, v: &Self) -> Self {
Self(self.0.saturating_add(v.0))
}
}
impl Debug for InscriptionNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl InscriptionNumber {
pub const MAX: Self = Self(4_000_000_000);
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable, Hash)]
#[repr(C)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Outpoint {
pub txid: [u8; 32],
pub vout: u32,
}
#[cfg(feature = "schema")]
impl schemars::JsonSchema for Outpoint {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Outpoint".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"type": "string",
"pattern": "^[0-9a-fA-F]{64}$i\\d+$",
"description": "SHA-256 transaction hexadecimal hash"
})
}
}
impl Debug for Outpoint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Outpoint").field(&self.to_string()).finish()
}
}
impl Outpoint {
pub fn randomized() -> Self {
let mut rnd = rand::thread_rng();
Self {
txid: rnd.gen(),
vout: rnd.gen_range(0..100_000),
}
}
}
impl std::str::FromStr for Outpoint {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(['i', ':']).collect();
if parts.len() != 2 {
anyhow::bail!("Wrong len");
}
let txid = hex::decode(parts[0]).anyhow_with("Not hex")?.into_iter().rev().collect_vec();
let txid: [u8; 32] = txid.try_into().map_err(|_| "Not array of 32").anyhow()?;
let vout = parts[1].parse().map_err(|_| "Not u32").anyhow()?;
Ok(Outpoint { txid, vout })
}
}
impl<'de> serde::Deserialize<'de> for Outpoint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = <String>::deserialize(deserializer)?;
let mut iter = v.split(['i', ':']);
let txid = iter.next();
let vout = iter.next();
if iter.next().is_some() {
return Err(serde::de::Error::custom("Many items"));
}
match (txid, vout) {
(Some(txid), Some(vout)) => {
let txid = hex::decode(txid).map_err(serde::de::Error::custom)?.into_iter().rev().collect_vec();
let txid: [u8; 32] = txid.try_into().map_err(|_| serde::de::Error::custom("Can't get txid"))?;
let vout: u32 = vout.parse().map_err(serde::de::Error::custom)?;
Ok(Self { txid, vout })
}
_ => Err(serde::de::Error::custom("Wrong 'Outpoint' format")),
}
}
}
impl serde::Serialize for Outpoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(self)
}
}
impl std::fmt::Display for Outpoint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let txid = hex::encode(self.txid.iter().copied().rev().collect_vec());
let vout = self.vout;
write!(f, "{txid}i{vout}")
}
}
impl<'a> NinBytes<'a> for Outpoint {
type Bytes = [u8; 36];
fn as_bytes(&'a self) -> Self::Bytes {
concat_arrays(self.txid, self.vout.to_be_bytes())
}
fn from_bytes(b: Self::Bytes) -> Self {
let txid: [u8; 32] = b[..32].try_into().unwrap();
let vout = u32::from_be_bytes(b[32..].try_into().unwrap());
Self { txid, vout }
}
}
#[derive(bytemuck::Pod, bytemuck::Zeroable, Clone, Copy, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, derive_more::From, derive_more::Display, Hash, PartialOrd, Ord)]
#[repr(C)]
#[serde(transparent)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema), schemars(transparent))]
pub struct Genesis(pub Outpoint);
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq, Debug, derive_more::From, derive_more::Display, Hash, bytemuck::Pod, bytemuck::Zeroable)]
#[serde(transparent)]
#[repr(C)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct AddressHash(pub Hash256);
#[deprecated(note = "Address was renamed to AddressHash to avoid confusion")]
pub type Address = AddressHash;
impl AddressHash {
pub fn from_original(addr: impl AsRef<str>) -> Self {
Self(addr.as_ref().hash_256())
}
}
#[derive(Clone, PartialEq, Eq, Debug, Copy, PartialOrd, Ord, bytemuck::Zeroable)]
#[repr(C)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Location {
pub genesis: Genesis,
pub offset: u64,
}
#[cfg(feature = "schema")]
impl schemars::JsonSchema for Location {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Location".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"type": "string",
"pattern": "^[0-9a-fA-F]{64}i\\d+$",
"description": "Genesis of inscription and it's offest"
})
}
}
impl std::fmt::Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let outpoint = self.genesis.to_string();
let offest = self.offset;
write!(f, "{outpoint}i{offest}")
}
}
impl<'de> serde::Deserialize<'de> for Location {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = <String>::deserialize(deserializer)?;
let mut iter = v.split(['i', ':']);
let txid = iter.next();
let vout = iter.next();
let offset = iter.next();
if iter.next().is_some() {
return Err(serde::de::Error::custom("Many items"));
}
match (txid, vout, offset) {
(Some(txid), Some(vout), Some(offset)) => {
let offset: u64 = offset.parse().map_err(serde::de::Error::custom)?;
let outpoint = Outpoint::from_str(&format!("{txid}i{vout}")).map_err(serde::de::Error::custom)?;
Ok(Self { genesis: Genesis(outpoint), offset })
}
_ => Err(serde::de::Error::custom("Wrong 'Location' format")),
}
}
}
impl serde::Serialize for Location {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(self)
}
}
#[derive(Debug, Clone, Copy, derive_more::From)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum InscriptionRef {
Genesis(Genesis),
Number(InscriptionNumber),
}
impl<'de> serde::Deserialize<'de> for InscriptionRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = <String>::deserialize(deserializer)?;
if let Ok(x) = v.parse::<u64>() {
return Ok(Self::Number(InscriptionNumber(x)));
}
if let Ok(x) = v.parse::<Outpoint>() {
return Ok(Self::Genesis(Genesis(x)));
}
Err(serde::de::Error::custom("InscriptionRef accepts only genesis or number"))
}
}
impl serde::Serialize for InscriptionRef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s = match self {
InscriptionRef::Genesis(x) => x.to_string(),
InscriptionRef::Number(x) => x.0.to_string(),
};
serializer.collect_str(&s)
}
}