1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use core::str::FromStr;
use regex::Regex;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::io;
use lnpbp::bitcoin::Txid;
use lnpbp::bp;
use lnpbp::hex::FromHex;
use lnpbp::rgb::SealDefinition;
use lnpbp::strict_encoding::{self, StrictDecode, StrictEncode};
use crate::error::ParseError;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize,),
serde(crate = "serde_crate")
)]
#[display(Debug)]
pub struct SealSpec {
pub vout: u32,
pub txid: Option<Txid>,
}
impl SealSpec {
pub fn seal_definition(&self) -> SealDefinition {
use lnpbp::bitcoin::secp256k1::rand::{self, RngCore};
let mut rng = rand::thread_rng();
let entropy = rng.next_u64();
match self.txid {
Some(txid) => {
SealDefinition::TxOutpoint(bp::blind::OutpointReveal {
blinding: entropy,
txid,
vout: self.vout,
})
}
None => SealDefinition::WitnessVout {
vout: self.vout,
blinding: entropy,
},
}
}
}
impl StrictEncode for SealSpec {
type Error = strict_encoding::Error;
fn strict_encode<E: io::Write>(
&self,
mut e: E,
) -> Result<usize, Self::Error> {
Ok(strict_encode_list!(e; self.vout, self.txid))
}
}
impl StrictDecode for SealSpec {
type Error = strict_encoding::Error;
fn strict_decode<D: io::Read>(mut d: D) -> Result<Self, Self::Error> {
Ok(Self {
vout: u32::strict_decode(&mut d)?,
txid: Option::<Txid>::strict_decode(&mut d)?,
})
}
}
impl FromStr for SealSpec {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let re = Regex::new(
r"(?x)
((?P<txid>[a-f\d]{64}) # Txid
:)
(?P<vout>\d+)$ # Vout
",
)
.expect("Regex parse failure");
if let Some(m) = re.captures(&s.to_ascii_lowercase()) {
match (m.name("txid"), m.name("vout")) {
(Some(txid), Some(vout)) => Ok(Self {
vout: vout.as_str().parse()?,
txid: Some(Txid::from_hex(txid.as_str())?),
}),
(None, Some(vout)) => Ok(Self {
vout: vout.as_str().parse()?,
txid: None,
}),
_ => Err(ParseError),
}
} else {
Err(ParseError)
}
}
}