1use bitcoin::blockdata::constants::genesis_block;
4use bitcoin::hashes::{sha256d, Hash};
5use bitcoin::secp256k1::ecdsa::Signature;
6use bitcoin::{BlockHash, Network, PublicKey, Txid};
7use nom::combinator::success;
8use nom::multi::length_count;
9use nom::number::streaming::*;
10use nom::{Parser, ToUsize};
11use rust_decimal::prelude::*;
12use time::OffsetDateTime;
13
14use crate::parse::*;
15use crate::value::*;
16use crate::*;
17
18#[derive(Clone, Copy, Debug)]
19pub struct Sat(Decimal);
20
21const SATS: Decimal = Decimal::from_parts(100000000, 0, 0, false, 0);
22
23impl Sat {
24 pub fn new(sat: u64) -> Sat {
25 Sat(Decimal::from_u64(sat).unwrap())
26 }
27
28 pub fn sat(&self) -> u64 {
29 self.0.to_u64().unwrap()
30 }
31
32 pub fn btc(&self) -> Decimal {
33 self.0 / SATS
34 }
35
36 pub fn as_str(&self) -> String {
37 format!("{} ₿", self.btc())
38 }
39}
40
41pub fn sat(input: Span) -> Parsed<Sat> {
42 with("datatype", "sat", le_u64)(input).map(|(s, n)| (s, Sat::new(n)))
43}
44
45#[derive(Clone, Debug)]
47pub struct ChainHash {
48 pub block_hash: BlockHash,
49 pub network: Option<Network>,
50}
51
52impl ChainHash {
53 pub fn as_string(&self) -> String {
54 match self.network {
55 Some(n) => n.to_string(),
56 None => "unknown".to_string(),
57 }
58 }
59}
60
61impl ToValue for ChainHash {
62 fn to_value(&self) -> Value {
63 Value::Alt(
64 Box::new(Value::Hash(self.block_hash.as_hash())),
65 Box::new(Value::text(self.as_string())),
66 )
67 }
68}
69
70pub fn chain_hash_le(s: Span) -> Parsed<ChainHash> {
72 let (s, mut b) = bytes(32_usize)(s)?;
73
74 b.reverse();
75
76 let block_hash = BlockHash::from_slice(&b).unwrap();
77
78 let network = if block_hash == genesis_block(Network::Bitcoin).block_hash() {
79 Some(Network::Bitcoin)
80 } else if block_hash == genesis_block(Network::Regtest).block_hash() {
81 Some(Network::Regtest)
82 } else if block_hash == genesis_block(Network::Testnet).block_hash() {
83 Some(Network::Testnet)
84 } else if block_hash == genesis_block(Network::Signet).block_hash() {
85 Some(Network::Signet)
86 } else {
87 None
88 };
89
90 Ok((
91 s.with("datatype", "chain_hash"),
92 ChainHash {
93 block_hash,
94 network,
95 },
96 ))
97}
98
99pub fn chain_hash_be(s: Span) -> Parsed<ChainHash> {
101 let (s, b) = bytes(32_usize)(s)?;
102
103 let block_hash = BlockHash::from_slice(&b).unwrap();
104
105 let network = if block_hash == genesis_block(Network::Bitcoin).block_hash() {
106 Some(Network::Bitcoin)
107 } else if block_hash == genesis_block(Network::Regtest).block_hash() {
108 Some(Network::Regtest)
109 } else if block_hash == genesis_block(Network::Testnet).block_hash() {
110 Some(Network::Testnet)
111 } else if block_hash == genesis_block(Network::Signet).block_hash() {
112 Some(Network::Signet)
113 } else {
114 None
115 };
116
117 Ok((
118 s.with("datatype", "chain_hash"),
119 ChainHash {
120 block_hash,
121 network,
122 },
123 ))
124}
125
126pub fn bytes<'a, U: ToUsize + std::fmt::Debug + Copy>(
127 len: U,
128) -> impl Fn(Span<'a>) -> Parsed<'a, Vec<u8>> {
129 move |input: Span<'a>| with("datatype", "bytes", length_count(success(len), u8))(input)
130}
131
132pub fn sha256d(input: Span) -> Parsed<sha256d::Hash> {
133 let (s, x) = bytes(32_usize)(input)?;
134 let x = sha256d::Hash::from_slice(&x).unwrap();
135 Ok((s.with("datatype", "sha256"), x))
136}
137
138pub fn txid(input: Span) -> Parsed<Txid> {
139 let (s, x) = sha256d(input)?;
140 Ok((s.with("datatype", "txid"), Txid::from_hash(x)))
141}
142
143pub fn signature(input: Span) -> Parsed<Signature> {
144 let (s, b) = bytes(64_usize)(input)?;
145 match Signature::from_compact(&b) {
146 Ok(sig) => Ok((s.with("datatype", "signature"), sig)),
147 Err(_) => Err(nom::Err::Failure(nom::error::Error {
148 input: s,
149 code: nom::error::ErrorKind::Fail,
150 })),
151 }
152}
153
154pub fn public_key(input: Span) -> Parsed<PublicKey> {
155 let (s, b) = bytes(33_usize)(input)?;
156 match PublicKey::from_slice(&b) {
157 Ok(pk) => Ok((s.with("datatype", "public_key"), pk)),
158 Err(_) => Err(nom::Err::Failure(nom::error::Error {
159 input: s,
160 code: nom::error::ErrorKind::Fail,
161 })),
162 }
163}
164
165fn varint_impl(input: Span) -> Parsed<u64> {
166 let (s, byte) = le_u8(input)?;
167
168 let s_int = match byte {
169 0xfd => {
170 let (s, a) = le_u16(s)?;
171 (s, a as u64)
172 }
173 0xfe => {
174 let (s, a) = le_u32(s)?;
175 (s, a as u64)
176 }
177 0xff => le_u64(s)?,
178 n => success(n as u64)(s)?,
179 };
180 Ok(s_int)
181}
182
183pub fn uint32(input: Span) -> Parsed<u32> {
184 with("datatype", "uint32", le_u32)(input)
185}
186
187pub fn int32(input: Span) -> Parsed<i32> {
188 with("datatype", "int32", le_i32)(input)
189}
190
191pub fn varint(input: Span) -> Parsed<u64> {
192 with("datatype", "varint", varint_impl)(input)
193}
194
195pub fn timestamp<'a, Parse>(mut parser: Parse) -> impl FnMut(Span<'a>) -> Parsed<OffsetDateTime>
198where
199 Parse: Parser<Span<'a>, u32, nom::error::Error<Span<'a>>>,
200{
201 move |input: Span| {
202 parser.parse(input).map(|(s, ts)| {
203 (
204 s.with("datatype", "timestamp"),
205 OffsetDateTime::from_unix_timestamp(ts.into()).unwrap(),
206 )
207 })
208 }
209}