1use core::fmt;
6use std::io;
7
8use bitcoin::block::BlockHashDecoder as GenesisHashDecoder;
10use bitcoin::block::{
11 BlockHashDecoderError as GenesisHashDecoderError, BlockHashEncoder as GenesisHashEncoder,
12};
13use bitcoin::hashes::Hash as _;
14use hashes::encoding::UnexpectedEofError;
15
16use crate::{encode, encoding, AssetId};
17
18const TOTAL_PEGIN_LENGTH: usize = 6;
19
20#[derive(Default, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
22pub struct PeginWitness {
23 inner: Option<PeginData>,
24}
25
26impl PeginWitness {
27 pub const EMPTY: Self = Self { inner: None };
29
30 pub fn new(data: PeginData) -> Self { Self { inner: Some(data) } }
32
33 pub fn data(&self) -> Option<&PeginData> { self.inner.as_ref() }
35
36 pub fn into_data(self) -> Option<PeginData> { self.inner }
38
39 pub fn is_empty(&self) -> bool { self.inner.is_none() }
41
42 pub fn len(&self) -> usize {
44 if self.inner.is_some() {
45 TOTAL_PEGIN_LENGTH
46 } else {
47 0
48 }
49 }
50
51 pub fn encoded_size(&self) -> usize {
53 use encoding::{Encode as _, ExactSizeEncoder as _};
54 match self.inner {
55 Some(ref data) => data.encoder().len(),
56 None => 1,
57 }
58 }
59}
60
61#[derive(Clone, Debug)]
63pub struct PeginWitnessEncoder<'e>(PeginWitnessEncoderInner<'e>);
64
65#[derive(Clone, Debug)]
66#[allow(clippy::large_enum_variant)]
67enum PeginWitnessEncoderInner<'e> {
68 Pegin(PeginDataEncoder<'e>),
69 Empty(encoding::CompactSizeEncoder),
70}
71
72impl encoding::Encoder for PeginWitnessEncoder<'_> {
73 fn current_chunk(&self) -> &[u8] {
74 use PeginWitnessEncoderInner as Inner;
75 match self.0 {
76 Inner::Pegin(ref enc) => enc.current_chunk(),
77 Inner::Empty(ref enc) => enc.current_chunk(),
78 }
79 }
80
81 fn advance(&mut self) -> encoding::EncoderStatus {
82 use PeginWitnessEncoderInner as Inner;
83 match self.0 {
84 Inner::Pegin(ref mut enc) => enc.advance(),
85 Inner::Empty(ref mut enc) => enc.advance(),
86 }
87 }
88}
89
90impl encoding::ExactSizeEncoder for PeginWitnessEncoder<'_> {
91 fn len(&self) -> usize {
92 use PeginWitnessEncoderInner as Inner;
93 match self.0 {
94 Inner::Pegin(ref enc) => enc.len(),
95 Inner::Empty(ref enc) => enc.len(),
96 }
97 }
98}
99
100impl encoding::Encode for PeginWitness {
101 type Encoder<'e> = PeginWitnessEncoder<'e>;
102
103 fn encoder(&self) -> Self::Encoder<'_> {
104 match self.inner {
105 Some(ref data) => PeginWitnessEncoder(PeginWitnessEncoderInner::Pegin(data.encoder())),
106 None => PeginWitnessEncoder(PeginWitnessEncoderInner::Empty(
107 encoding::CompactSizeEncoder::new(0),
108 )),
109 }
110 }
111}
112
113#[derive(Default)]
115pub struct PeginWitnessDecoder(PeginWitnessDecoderInner);
116
117#[derive(Default)]
118#[allow(clippy::large_enum_variant)]
119enum PeginWitnessDecoderInner {
120 #[default]
121 Undetermined,
122 Empty,
123 Pegin(PeginDataDecoder),
124}
125
126impl encoding::Decoder for PeginWitnessDecoder {
127 type Output = PeginWitness;
128 type Error = PeginWitnessDecoderError;
129
130 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<encoding::DecoderStatus, Self::Error> {
131 use PeginWitnessDecoderInner as Inner;
132 loop {
133 match self.0 {
134 Inner::Undetermined => {
135 match bytes.first().copied().map(usize::from) {
136 None => return Ok(encoding::DecoderStatus::NeedsMore),
137 Some(0) => {
138 *bytes = &bytes[1..];
139 self.0 = Inner::Empty;
140 }
141 Some(TOTAL_PEGIN_LENGTH) => {
142 self.0 = Inner::Pegin(PeginDataDecoder::default());
144 }
145 Some(x) => {
146 return Err(PeginWitnessDecoderError {
147 field: "pegin witness",
148 inner: PeginDataDecoderErrorInner::Length(
149 ExactLengthDecoderError::IncorrectLength {
150 expected: TOTAL_PEGIN_LENGTH,
151 got: x,
152 },
153 ),
154 });
155 }
156 }
157 }
158 Inner::Empty => return Ok(encoding::DecoderStatus::Ready),
159 Inner::Pegin(ref mut decoder) => return decoder.push_bytes(bytes),
160 }
161 }
162 }
163
164 fn end(self) -> Result<Self::Output, Self::Error> {
165 use PeginWitnessDecoderInner as Inner;
166 match self.0 {
167 Inner::Undetermined => Err(PeginWitnessDecoderError {
168 field: "pegin witness",
169 inner: PeginDataDecoderErrorInner::InsufficientLength { minimum: 1, got: 0 },
170 }),
171 Inner::Empty => Ok(PeginWitness { inner: None }),
172 Inner::Pegin(decoder) => decoder.end().map(|inner| PeginWitness { inner: Some(inner) }),
173 }
174 }
175
176 fn read_limit(&self) -> usize {
177 use PeginWitnessDecoderInner as Inner;
178 match self.0 {
179 Inner::Undetermined => 1,
180 Inner::Empty => 0,
181 Inner::Pegin(ref decoder) => decoder.read_limit(),
182 }
183 }
184}
185
186impl encoding::Decode for PeginWitness {
187 type Decoder = PeginWitnessDecoder;
188}
189
190#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
192pub struct PeginData {
193 pub value: u64,
195 pub asset_id: AssetId,
197 pub genesis_hash: bitcoin::BlockHash,
199 pub claim_script: bitcoin::ScriptBuf,
201 pub transaction: Vec<u8>,
206 pub merkle_proof: Vec<u8>,
208 pub referenced_block: bitcoin::BlockHash,
211}
212
213impl PeginData {
214 pub fn parse_tx(&self) -> Result<bitcoin::Transaction, bitcoin::consensus::encode::Error> {
216 bitcoin::consensus::encode::deserialize(&self.transaction)
217 }
218
219 pub fn parse_merkle_proof(
221 &self,
222 ) -> Result<bitcoin::MerkleBlock, bitcoin::consensus::encode::Error> {
223 bitcoin::consensus::encode::deserialize(&self.merkle_proof)
224 }
225}
226
227encoding::encoder_newtype_exact! {
228 #[derive(Clone, Debug)]
230 pub struct PeginDataEncoder<'e>(
231 encoding::Encoder3<
232 encoding::CompactSizeEncoder,
234 encoding::Encoder6<
235 encoding::CompactSizeEncoder,
237 encoding::ArrayEncoder<8>,
238 encoding::CompactSizeEncoder,
240 encoding::ArrayRefEncoder<'e, 32>,
241 encoding::CompactSizeEncoder,
243 GenesisHashEncoder<'e>,
244 >,
245 encoding::Encoder3<
246 bitcoin::blockdata::script::ScriptEncoder<'e>,
248 encoding::PrefixedBytesEncoder<'e>,
250 encoding::PrefixedBytesEncoder<'e>,
252
253 >,
254 >
255 );
256}
257
258impl encoding::Encode for PeginData {
259 type Encoder<'e> = PeginDataEncoder<'e>;
260
261 fn encoder(&self) -> Self::Encoder<'_> {
262 PeginDataEncoder::new(encoding::Encoder3::new(
263 encoding::CompactSizeEncoder::new(TOTAL_PEGIN_LENGTH),
264 encoding::Encoder6::new(
265 encoding::CompactSizeEncoder::new(8),
266 encoding::ArrayEncoder::without_length_prefix(self.value.to_le_bytes()),
267 encoding::CompactSizeEncoder::new(32),
268 encoding::ArrayRefEncoder::without_length_prefix(self.asset_id.as_byte_array()),
269 encoding::CompactSizeEncoder::new(32),
270 self.genesis_hash.encoder(),
271 ),
272 encoding::Encoder3::new(
273 self.claim_script.encoder(),
274 encoding::PrefixedBytesEncoder::new(&self.transaction),
275 encoding::PrefixedBytesEncoder::new(&self.merkle_proof),
276 ),
277 ))
278 }
279}
280
281struct ExactLengthDecoder {
282 target: usize,
283 inner: encoding::CompactSizeDecoder,
284}
285
286impl ExactLengthDecoder {
287 fn new(target: usize) -> Self { Self { target, inner: encoding::CompactSizeDecoder::new() } }
288}
289
290#[derive(Clone, PartialEq, Eq, Debug)]
291enum ExactLengthDecoderError {
292 IncorrectLength { expected: usize, got: usize },
293 InvalidCompactSize(encoding::CompactSizeDecoderError),
294}
295
296impl fmt::Display for ExactLengthDecoderError {
297 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298 match *self {
299 Self::IncorrectLength { expected, got } => {
300 write!(f, "expected length {expected} but got {got}")
301 }
302 Self::InvalidCompactSize(_) => f.write_str("failed to decode compact size"),
303 }
304 }
305}
306
307impl std::error::Error for ExactLengthDecoderError {
308 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
309 match *self {
310 Self::IncorrectLength { .. } => None,
311 Self::InvalidCompactSize(ref error) => Some(error),
312 }
313 }
314}
315
316impl encoding::Decoder for ExactLengthDecoder {
317 type Output = usize;
318 type Error = ExactLengthDecoderError;
319
320 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<encoding::DecoderStatus, Self::Error> {
321 self.inner.push_bytes(bytes).map_err(ExactLengthDecoderError::InvalidCompactSize)
322 }
323
324 fn end(self) -> Result<Self::Output, Self::Error> {
325 let expected = self.target;
326 let got = self.inner.end().map_err(ExactLengthDecoderError::InvalidCompactSize)?;
327
328 if got == self.target {
329 Ok(got)
330 } else {
331 Err(ExactLengthDecoderError::IncorrectLength { expected, got })
332 }
333 }
334
335 fn read_limit(&self) -> usize { self.inner.read_limit() }
336}
337
338#[allow(clippy::type_complexity)]
340pub struct PeginDataDecoder {
341 inner: encoding::Decoder3<
342 ExactLengthDecoder,
344 encoding::Decoder6<
345 ExactLengthDecoder,
347 encoding::ArrayDecoder<8>,
348 ExactLengthDecoder,
350 crate::AssetIdDecoder,
351 ExactLengthDecoder,
353 GenesisHashDecoder,
354 >,
355 encoding::Decoder3<
356 bitcoin::blockdata::script::ScriptBufDecoder,
358 encoding::ByteVecDecoder,
360 encoding::ByteVecDecoder,
362 >,
363 >,
364}
365
366impl Default for PeginDataDecoder {
367 fn default() -> Self {
368 Self {
369 inner: encoding::Decoder3::new(
370 ExactLengthDecoder::new(TOTAL_PEGIN_LENGTH),
371 encoding::Decoder6::new(
372 ExactLengthDecoder::new(8),
373 encoding::ArrayDecoder::new(),
374 ExactLengthDecoder::new(32),
375 crate::AssetIdDecoder::default(),
376 ExactLengthDecoder::new(32),
377 GenesisHashDecoder::new(),
378 ),
379 encoding::Decoder3::new(
380 bitcoin::blockdata::script::ScriptBufDecoder::new(),
381 encoding::ByteVecDecoder::new(),
382 encoding::ByteVecDecoder::new(),
383 ),
384 ),
385 }
386 }
387}
388
389#[derive(Clone, PartialEq, Eq, Debug)]
390enum PeginDataDecoderErrorInner {
391 AssetId(crate::AssetIdDecoderError),
392 ClaimScript(bitcoin::blockdata::script::ScriptBufDecoderError),
393 GenesisHash(GenesisHashDecoderError),
394 Length(ExactLengthDecoderError),
395 InsufficientLength { minimum: usize, got: usize },
396 Eof(encoding::UnexpectedEofError),
397 ByteVec(encoding::ByteVecDecoderError),
398}
399
400#[derive(Clone, PartialEq, Eq, Debug)]
402pub struct PeginWitnessDecoderError {
403 field: &'static str,
404 inner: PeginDataDecoderErrorInner,
405}
406
407impl fmt::Display for PeginWitnessDecoderError {
408 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409 if self.field == "pegin witness" {
410 f.write_str("error decoding pegin witness")?;
411 } else {
412 write!(f, "error decoding pegin witness field {}", self.field)?;
413 }
414 if let PeginDataDecoderErrorInner::InsufficientLength { minimum, got } = self.inner {
415 write!(f, ": needed at least {minimum} bytes, got {got}")?;
416 }
417 Ok(())
418 }
419}
420
421impl std::error::Error for PeginWitnessDecoderError {
422 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
423 use PeginDataDecoderErrorInner as Inner;
424 match self.inner {
425 Inner::AssetId(ref e) => Some(e),
426 Inner::ClaimScript(ref e) => Some(e),
427 Inner::GenesisHash(ref e) => Some(e),
428 Inner::Length(ref e) => Some(e),
429 Inner::InsufficientLength { .. } => None,
430 Inner::Eof(ref e) => Some(e),
431 Inner::ByteVec(ref e) => Some(e),
432 }
433 }
434}
435
436impl PeginWitnessDecoderError {
437 #[allow(clippy::type_complexity)]
439 fn from(
440 inner: encoding::Decoder3Error<
441 ExactLengthDecoderError,
442 encoding::Decoder6Error<
443 ExactLengthDecoderError,
444 UnexpectedEofError,
445 ExactLengthDecoderError,
446 crate::AssetIdDecoderError,
447 ExactLengthDecoderError,
448 GenesisHashDecoderError,
449 >,
450 encoding::Decoder3Error<
451 bitcoin::blockdata::script::ScriptBufDecoderError,
452 encoding::ByteVecDecoderError,
453 encoding::ByteVecDecoderError,
454 >,
455 >,
456 ) -> Self {
457 use encoding::{Decoder3Error as Dec3Err, Decoder6Error as Dec6Err};
458
459 match inner {
460 Dec3Err::First(error) =>
461 Self { field: "pegin witness", inner: PeginDataDecoderErrorInner::Length(error) },
462 Dec3Err::Second(Dec6Err::First(error)) =>
463 Self { field: "value", inner: PeginDataDecoderErrorInner::Length(error) },
464 Dec3Err::Second(Dec6Err::Second(error)) =>
465 Self { field: "value", inner: PeginDataDecoderErrorInner::Eof(error) },
466 Dec3Err::Second(Dec6Err::Third(error)) =>
467 Self { field: "asset ID", inner: PeginDataDecoderErrorInner::Length(error) },
468 Dec3Err::Second(Dec6Err::Fourth(error)) =>
469 Self { field: "asset ID", inner: PeginDataDecoderErrorInner::AssetId(error) },
470 Dec3Err::Second(Dec6Err::Fifth(error)) =>
471 Self { field: "genesis hash", inner: PeginDataDecoderErrorInner::Length(error) },
472 Dec3Err::Second(Dec6Err::Sixth(error)) => Self {
473 field: "genesis hash",
474 inner: PeginDataDecoderErrorInner::GenesisHash(error),
475 },
476 Dec3Err::Third(Dec3Err::First(error)) => Self {
477 field: "claim script",
478 inner: PeginDataDecoderErrorInner::ClaimScript(error),
479 },
480 Dec3Err::Third(Dec3Err::Second(error)) =>
481 Self { field: "transaction", inner: PeginDataDecoderErrorInner::ByteVec(error) },
482 Dec3Err::Third(Dec3Err::Third(error)) =>
483 Self { field: "merkle proof", inner: PeginDataDecoderErrorInner::ByteVec(error) },
484 }
485 }
486}
487
488impl encoding::Decoder for PeginDataDecoder {
489 type Output = PeginData;
490 type Error = PeginWitnessDecoderError;
491
492 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<encoding::DecoderStatus, Self::Error> {
493 self.inner.push_bytes(bytes).map_err(PeginWitnessDecoderError::from)
494 }
495
496 fn end(self) -> Result<Self::Output, Self::Error> {
497 use internals::slice::SliceExt;
498
499 let (
500 _,
501 (_, value, _, asset_id, _, genesis_hash),
502 (claim_script, transaction, merkle_proof),
503 ) = self.inner.end().map_err(PeginWitnessDecoderError::from)?;
504
505 let Some((block_header, _)) = SliceExt::split_first_chunk::<80>(merkle_proof.as_slice())
506 else {
507 return Err(PeginWitnessDecoderError {
508 field: "merkle proof",
509 inner: PeginDataDecoderErrorInner::InsufficientLength {
510 minimum: 80,
511 got: merkle_proof.len(),
512 },
513 });
514 };
515 let referenced_block = bitcoin::BlockHash::hash(block_header);
516
517 Ok(PeginData {
518 value: u64::from_le_bytes(value),
519 asset_id,
520 genesis_hash,
521 claim_script,
522 transaction,
523 merkle_proof,
524 referenced_block,
525 })
526 }
527
528 fn read_limit(&self) -> usize { self.inner.read_limit() }
529}
530
531impl encoding::Decode for PeginData {
532 type Decoder = PeginDataDecoder;
533}
534
535impl encode::Encodable for PeginData {
536 fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, encode::Error> {
537 let mut counter = encode::ByteCounter::new(e);
538 crate::encoding::encode_to_writer(self, &mut counter)?;
539 Ok(counter.into_count())
540 }
541}
542
543impl encode::Decodable for PeginWitness {
544 fn consensus_decode<D: io::Read>(d: D) -> Result<Self, encode::Error> {
545 match encoding::decode_from_read_unbuffered(d) {
546 Ok(res) => Ok(res),
547 Err(encoding::ReadError::Io(e)) => Err(encode::Error::Io(e)),
548 Err(encoding::ReadError::Decode(e)) => Err(encode::Error::PeginWitness(e)),
549 }
550 }
551}
552
553impl encode::Encodable for PeginWitness {
554 fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, encode::Error> {
555 match self.inner {
556 Some(ref wit) => wit.consensus_encode(e),
557 None => 0u8.consensus_encode(e),
558 }
559 }
560}