1use crate::{
2 BitcoinAddress, BitcoinAmount, BitcoinFormat, BitcoinNetwork, BitcoinPublicKey, WitnessProgram,
3 BASE32_DECODE_TABLE,
4};
5use anychain_core::{
6 crypto::checksum as double_sha2, Transaction, TransactionError, TransactionId,
7};
8use anychain_core::{
9 hex,
10 no_std::{io::Read, *},
11 PublicKey,
12};
13use libsecp256k1::Signature;
14
15use base58::FromBase58;
16use bech32::{u5, FromBase32};
17use core::{fmt, str::FromStr};
18use serde::Serialize;
19pub use sha2::{Digest, Sha256};
20
21pub fn variable_length_integer(value: u64) -> Result<Vec<u8>, TransactionError> {
24 match value {
25 0..=252 => Ok(vec![value as u8]),
27 253..=65535 => Ok([vec![0xfd], (value as u16).to_le_bytes().to_vec()].concat()),
29 65536..=4294967295 => Ok([vec![0xfe], (value as u32).to_le_bytes().to_vec()].concat()),
31 _ => Ok([vec![0xff], value.to_le_bytes().to_vec()].concat()),
33 }
34}
35
36pub fn read_variable_length_integer<R: Read>(mut reader: R) -> Result<usize, TransactionError> {
39 let mut flag = [0u8; 1];
40 let _ = reader.read(&mut flag)?;
41
42 match flag[0] {
43 0..=252 => Ok(flag[0] as usize),
44 0xfd => {
45 let mut size = [0u8; 2];
46 let _ = reader.read(&mut size)?;
47 match u16::from_le_bytes(size) {
48 s if s < 253 => Err(TransactionError::InvalidVariableSizeInteger(s as usize)),
49 s => Ok(s as usize),
50 }
51 }
52 0xfe => {
53 let mut size = [0u8; 4];
54 let _ = reader.read(&mut size)?;
55 match u32::from_le_bytes(size) {
56 s if s < 65536 => Err(TransactionError::InvalidVariableSizeInteger(s as usize)),
57 s => Ok(s as usize),
58 }
59 }
60 _ => {
61 let mut size = [0u8; 8];
62 let _ = reader.read(&mut size)?;
63 match u64::from_le_bytes(size) {
64 s if s < 4294967296 => {
65 Err(TransactionError::InvalidVariableSizeInteger(s as usize))
66 }
67 s => Ok(s as usize),
68 }
69 }
70 }
71}
72
73pub struct BitcoinVector;
74
75impl BitcoinVector {
76 pub fn read<R: Read, E, F>(mut reader: R, func: F) -> Result<Vec<E>, TransactionError>
78 where
79 F: Fn(&mut R) -> Result<E, TransactionError>,
80 {
81 let count = read_variable_length_integer(&mut reader)?;
82 (0..count).map(|_| func(&mut reader)).collect()
83 }
84
85 pub fn read_witness<R: Read, E, F>(
87 mut reader: R,
88 func: F,
89 ) -> Result<(usize, Result<Vec<E>, TransactionError>), TransactionError>
90 where
91 F: Fn(&mut R) -> Result<E, TransactionError>,
92 {
93 let count = read_variable_length_integer(&mut reader)?;
94 Ok((count, Self::read(reader, func)))
95 }
96}
97
98pub fn create_script_pub_key<N: BitcoinNetwork>(
100 address: &BitcoinAddress<N>,
101) -> Result<Vec<u8>, TransactionError> {
102 match address.format() {
103 BitcoinFormat::P2PKH => {
104 let bytes = &address.to_string().from_base58()?;
105
106 let pub_key_hash = bytes[1..(bytes.len() - 4)].to_vec();
108
109 let mut script = vec![];
110 script.push(Opcode::OP_DUP as u8);
111 script.push(Opcode::OP_HASH160 as u8);
112 script.extend(variable_length_integer(pub_key_hash.len() as u64)?);
113 script.extend(pub_key_hash);
114 script.push(Opcode::OP_EQUALVERIFY as u8);
115 script.push(Opcode::OP_CHECKSIG as u8);
116 Ok(script)
117 }
118 BitcoinFormat::P2SH_P2WPKH => {
119 let script_bytes = &address.to_string().from_base58()?;
120 let script_hash = script_bytes[1..(script_bytes.len() - 4)].to_vec();
121
122 let mut script = vec![];
123 script.push(Opcode::OP_HASH160 as u8);
124 script.extend(variable_length_integer(script_hash.len() as u64)?);
125 script.extend(script_hash);
126 script.push(Opcode::OP_EQUAL as u8);
127 Ok(script)
128 }
129 BitcoinFormat::P2WSH => {
130 let (_, data, _) = bech32::decode(&address.to_string())?;
131 let (v, script) = data.split_at(1);
132 let script = Vec::from_base32(script)?;
133 let mut script_bytes = vec![v[0].to_u8(), script.len() as u8];
134 script_bytes.extend(script);
135 Ok(script_bytes)
136 }
137 BitcoinFormat::Bech32 => {
138 let (_, data, _) = bech32::decode(&address.to_string())?;
139 let (v, program) = data.split_at(1);
140 let program = Vec::from_base32(program)?;
141 let mut program_bytes = vec![v[0].to_u8(), program.len() as u8];
142 program_bytes.extend(program);
143 Ok(WitnessProgram::new(&program_bytes)?.to_scriptpubkey())
144 }
145 BitcoinFormat::CashAddr => {
146 let address = address.to_string();
147 let prefix = N::to_address_prefix(BitcoinFormat::CashAddr)?.prefix();
148
149 let start = if address.starts_with(&prefix) {
150 prefix.len() + 1
151 } else {
152 0
153 };
154
155 let bytes_u8 = address.as_bytes()[start..address.len() - 8].to_vec();
157
158 let bytes_u5: Vec<u5> = bytes_u8
159 .iter()
160 .map(|byte| u5::try_from_u8(BASE32_DECODE_TABLE[*byte as usize] as u8).unwrap())
161 .collect();
162 let payload = Vec::<u8>::from_base32(&bytes_u5)?;
163 let hash = payload[1..].to_vec();
165
166 let mut script = vec![];
167 script.push(Opcode::OP_DUP as u8);
168 script.push(Opcode::OP_HASH160 as u8);
169 script.extend(variable_length_integer(hash.len() as u64)?);
170 script.extend(hash);
171 script.push(Opcode::OP_EQUALVERIFY as u8);
172 script.push(Opcode::OP_CHECKSIG as u8);
173
174 Ok(script)
175 }
176 }
177}
178
179pub fn create_script_op_return(property_id: u32, amount: i64) -> Result<Vec<u8>, TransactionError> {
183 let mut script = vec![];
184
185 let msg_type: u16 = 0;
186 let msg_version: u16 = 0;
187
188 script.push(Opcode::OP_RETURN as u8);
189 script.push(Opcode::OP_PUSHBYTES_20 as u8);
190 script.push(b'o');
191 script.push(b'm');
192 script.push(b'n');
193 script.push(b'i');
194 script.append(&mut msg_version.to_be_bytes().to_vec());
195 script.append(&mut msg_type.to_be_bytes().to_vec());
196 script.append(&mut property_id.to_be_bytes().to_vec());
197 script.append(&mut amount.to_be_bytes().to_vec());
198
199 Ok(script)
200}
201
202#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
205#[allow(non_camel_case_types)]
206pub enum SignatureHash {
207 SIGHASH_ALL = 0x01,
209
210 SIGHASH_NONE = 0x02,
213
214 SIGHASH_SINGLE = 0x03,
217
218 SIGHASH_ALL_SIGHASH_FORKID = 0x41,
219 SIGHASH_NONE_SIGHASH_FORKID = 0x42,
220 SIGHASH_SINGLE_SIGHASH_FORKID = 0x43,
221
222 SIGHASH_ALL_SIGHASH_ANYONECANPAY = 0x81,
226
227 SIGHASH_NONE_SIGHASH_ANYONECANPAY = 0x82,
231
232 SIGHASH_SINGLE_SIGHASH_ANYONECANPAY = 0x83,
235
236 SIGHASH_ALL_SIGHASH_FORKID_SIGHASH_ANYONECANPAY = 0xc1,
237 SIGHASH_NONE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY = 0xc2,
238 SIGHASH_SINGLE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY = 0xc3,
239}
240
241impl fmt::Display for SignatureHash {
242 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243 match self {
244 SignatureHash::SIGHASH_ALL => write!(f, "SIGHASH_ALL"),
245 SignatureHash::SIGHASH_NONE => write!(f, "SIGHASH_NONE"),
246 SignatureHash::SIGHASH_SINGLE => write!(f, "SIGHASH_SINGLE"),
247 SignatureHash::SIGHASH_ALL_SIGHASH_FORKID => {
248 write!(f, "SIGHASH_ALL | SIGHASH_FORKID")
249 }
250 SignatureHash::SIGHASH_NONE_SIGHASH_FORKID => {
251 write!(f, "SIGHASH_NONE | SIGHASH_FORKID")
252 }
253 SignatureHash::SIGHASH_SINGLE_SIGHASH_FORKID => {
254 write!(f, "SIGHASH_SINGLE | SIGHASH_FORKID")
255 }
256 SignatureHash::SIGHASH_ALL_SIGHASH_ANYONECANPAY => {
257 write!(f, "SIGHASH_ALL | SIGHASH_ANYONECANPAY")
258 }
259 SignatureHash::SIGHASH_NONE_SIGHASH_ANYONECANPAY => {
260 write!(f, "SIGHASH_NONE | SIGHASH_ANYONECANPAY")
261 }
262 SignatureHash::SIGHASH_SINGLE_SIGHASH_ANYONECANPAY => {
263 write!(f, "SIGHASH_SINGLE | SIGHASH_ANYONECANPAY")
264 }
265 SignatureHash::SIGHASH_ALL_SIGHASH_FORKID_SIGHASH_ANYONECANPAY => {
266 write!(f, "SIGHASH_ALL | SIGHASH_FORKID | SIGHASH_ANYONECANPAY")
267 }
268 SignatureHash::SIGHASH_NONE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY => {
269 write!(f, "SIGHASH_NONE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY")
270 }
271 SignatureHash::SIGHASH_SINGLE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY => {
272 write!(f, "SIGHASH_SINGLE | SIGHASH_FORKID | SIGHASH_ANYONECANPAY")
273 }
274 }
275 }
276}
277
278impl SignatureHash {
279 pub fn from_byte(byte: &u8) -> Self {
280 match byte {
281 0x02 => SignatureHash::SIGHASH_NONE,
282 0x03 => SignatureHash::SIGHASH_SINGLE,
283 0x41 => SignatureHash::SIGHASH_ALL_SIGHASH_FORKID,
284 0x42 => SignatureHash::SIGHASH_NONE_SIGHASH_FORKID,
285 0x43 => SignatureHash::SIGHASH_SINGLE_SIGHASH_FORKID,
286 0x81 => SignatureHash::SIGHASH_ALL_SIGHASH_ANYONECANPAY,
287 0x82 => SignatureHash::SIGHASH_NONE_SIGHASH_ANYONECANPAY,
288 0x83 => SignatureHash::SIGHASH_SINGLE_SIGHASH_ANYONECANPAY,
289 0xc1 => SignatureHash::SIGHASH_ALL_SIGHASH_FORKID_SIGHASH_ANYONECANPAY,
290 0xc2 => SignatureHash::SIGHASH_NONE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY,
291 0xc3 => SignatureHash::SIGHASH_SINGLE_SIGHASH_FORKID_SIGHASH_ANYONECANPAY,
292 _ => SignatureHash::SIGHASH_ALL,
293 }
294 }
295}
296
297#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
299#[allow(non_camel_case_types)]
300pub enum Opcode {
301 OP_DUP = 0x76,
302 OP_HASH160 = 0xa9,
303 OP_CHECKSIG = 0xac,
304 OP_EQUAL = 0x87,
305 OP_EQUALVERIFY = 0x88,
306 OP_RETURN = 0x6a,
307 OP_PUSHBYTES_20 = 0x14,
308}
309
310impl fmt::Display for Opcode {
311 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312 match self {
313 Opcode::OP_DUP => write!(f, "OP_DUP"),
314 Opcode::OP_HASH160 => write!(f, "OP_HASH160"),
315 Opcode::OP_CHECKSIG => write!(f, "OP_CHECKSIG"),
316 Opcode::OP_EQUAL => write!(f, "OP_EQUAL"),
317 Opcode::OP_EQUALVERIFY => write!(f, "OP_EQUALVERIFY"),
318 Opcode::OP_RETURN => write!(f, "OP_RETURN"),
319 Opcode::OP_PUSHBYTES_20 => write!(f, "OP_PUSHBYTES_20"),
320 }
321 }
322}
323
324#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct Outpoint {
327 pub reverse_transaction_id: Vec<u8>,
329 pub index: u32,
331}
332
333impl Outpoint {
334 pub fn new(reverse_transaction_id: Vec<u8>, index: u32) -> Self {
336 Self {
337 reverse_transaction_id,
338 index,
339 }
340 }
341}
342
343#[derive(Debug, Clone, PartialEq, Eq)]
345pub struct BitcoinTransactionInput<N: BitcoinNetwork> {
346 pub outpoint: Outpoint,
348 pub balance: Option<BitcoinAmount>,
350 pub address: Option<BitcoinAddress<N>>,
352 pub format: Option<BitcoinFormat>,
354 pub script_pub_key: Option<Vec<u8>>,
356 pub redeem_script: Option<Vec<u8>>,
358 pub script_sig: Vec<u8>,
360 pub sequence: Vec<u8>,
363 pub sighash_code: SignatureHash,
365 pub witnesses: Vec<Vec<u8>>,
367 pub is_signed: bool,
369 pub additional_witness: Option<(Vec<u8>, bool)>,
371 pub witness_script_data: Option<Vec<u8>>,
373}
374
375impl<N: BitcoinNetwork> BitcoinTransactionInput<N> {
376 const DEFAULT_SEQUENCE: [u8; 4] = [0xf2, 0xff, 0xff, 0xff];
377
378 pub fn new(
380 transaction_id: Vec<u8>,
381 index: u32,
382 public_key: Option<BitcoinPublicKey<N>>,
383 format: Option<BitcoinFormat>,
384 address: Option<BitcoinAddress<N>>,
385 balance: Option<BitcoinAmount>,
386 sighash: SignatureHash,
387 ) -> Result<Self, TransactionError> {
388 if transaction_id.len() != 32 {
389 return Err(TransactionError::InvalidTransactionId(transaction_id.len()));
390 }
391
392 let mut reverse_transaction_id = transaction_id;
395 reverse_transaction_id.reverse();
396
397 let format = match format {
398 Some(f) => Some(f),
399 None => Some(BitcoinFormat::P2PKH),
400 };
401
402 let (address, script_pub_key, redeem_script) = match public_key {
403 Some(pk) => {
404 let addr = pk.to_address(&format.clone().unwrap())?;
405 if let Some(v) = address {
406 if v != addr {
407 return Err(TransactionError::Message(format!(
408 "Provided address {} does not match the provided public key {}",
409 addr, pk,
410 )));
411 }
412 }
413 let script_pub_key = create_script_pub_key(&addr)?;
414 let redeem_script = match format {
415 Some(BitcoinFormat::P2SH_P2WPKH) => {
416 Some(BitcoinAddress::<N>::create_redeem_script(&pk).to_vec())
417 }
418 _ => None,
419 };
420 (Some(addr), Some(script_pub_key), redeem_script)
421 }
422 None => match address {
423 Some(addr) => {
424 let script_pub_key = create_script_pub_key(&addr)?;
425 (Some(addr), Some(script_pub_key), None)
426 }
427 None => (None, None, None),
428 },
429 };
430
431 Ok(Self {
432 outpoint: Outpoint::new(reverse_transaction_id, index),
433 balance,
434 address,
435 format,
436 script_pub_key,
437 redeem_script,
438 script_sig: vec![],
439 sequence: BitcoinTransactionInput::<N>::DEFAULT_SEQUENCE.to_vec(),
440 sighash_code: sighash,
441 witnesses: vec![],
442 is_signed: false,
443 additional_witness: None,
444 witness_script_data: None,
445 })
446 }
447
448 pub fn set_public_key(
449 &mut self,
450 public_key: BitcoinPublicKey<N>,
451 format: BitcoinFormat,
452 ) -> Result<(), TransactionError> {
453 let address = public_key.to_address(&format)?;
454 self.format = Some(format.clone());
455 self.script_pub_key = Some(create_script_pub_key(&address)?);
456 self.address = Some(address);
457 self.redeem_script = match format {
458 BitcoinFormat::P2SH_P2WPKH => {
459 Some(BitcoinAddress::<N>::create_redeem_script(&public_key).to_vec())
460 }
461 _ => None,
462 };
463 Ok(())
464 }
465
466 pub fn set_redeem_script(&mut self, redeem_script: Vec<u8>) -> Result<(), TransactionError> {
467 self.redeem_script = Some(redeem_script);
468 Ok(())
469 }
470
471 pub fn set_format(&mut self, format: BitcoinFormat) -> Result<(), TransactionError> {
472 self.format = Some(format);
473 Ok(())
474 }
475
476 pub fn set_balance(&mut self, balance: i64) -> Result<(), TransactionError> {
477 self.balance = Some(BitcoinAmount(balance));
478 Ok(())
479 }
480
481 pub fn set_sequence(&mut self, sequence: u32) -> Result<(), TransactionError> {
482 self.sequence = u32::to_le_bytes(sequence).to_vec();
483 Ok(())
484 }
485
486 pub fn set_sighash(&mut self, sighash: SignatureHash) -> Result<(), TransactionError> {
487 self.sighash_code = sighash;
488 Ok(())
489 }
490
491 pub fn get_address(&self) -> Option<BitcoinAddress<N>> {
492 self.address.clone()
493 }
494
495 pub fn get_format(&self) -> Option<BitcoinFormat> {
496 self.format.clone()
497 }
498
499 pub fn get_balance(&self) -> Option<BitcoinAmount> {
500 self.balance
501 }
502
503 pub fn get_sequence(&self) -> u32 {
504 let sequence: [u8; 4] = self.sequence.clone().try_into().unwrap();
505 u32::from_le_bytes(sequence)
506 }
507
508 pub fn get_sighash(&self) -> SignatureHash {
509 self.sighash_code
510 }
511
512 pub fn read<R: Read>(mut reader: &mut R) -> Result<Self, TransactionError> {
514 let mut transaction_hash = [0u8; 32];
515 let mut vin = [0u8; 4];
516 let mut sequence = [0u8; 4];
517
518 let _ = reader.read(&mut transaction_hash)?;
519 let _ = reader.read(&mut vin)?;
520
521 let outpoint = Outpoint::new(transaction_hash.to_vec(), u32::from_le_bytes(vin));
522
523 let script_sig: Vec<u8> = BitcoinVector::read(&mut reader, |s| {
524 let mut byte = [0u8; 1];
525 let _ = s.read(&mut byte)?;
526 Ok(byte[0])
527 })?;
528
529 let _ = reader.read(&mut sequence)?;
530
531 let script_sig_len = read_variable_length_integer(&script_sig[..])?;
532
533 let sighash_code = SignatureHash::from_byte(&match script_sig_len {
534 0 => 0x01,
535 length => script_sig[length],
536 });
537
538 Ok(Self {
539 outpoint,
540 balance: None,
541 address: None,
542 format: None,
543 script_pub_key: None,
544 redeem_script: None,
545 script_sig: script_sig.to_vec(),
546 sequence: sequence.to_vec(),
547 sighash_code,
548 witnesses: vec![],
549 is_signed: !script_sig.is_empty(),
550 additional_witness: None,
551 witness_script_data: None,
552 })
553 }
554
555 pub fn serialize(&self, raw: bool) -> Result<Vec<u8>, TransactionError> {
557 let mut input = vec![];
558 input.extend(&self.outpoint.reverse_transaction_id);
559 input.extend(&self.outpoint.index.to_le_bytes());
560 match raw {
561 true => input.extend(vec![0x00]),
562 false => match self.script_sig.len() {
563 0 => match &self.address {
564 Some(address) => match address.format() {
565 BitcoinFormat::P2PKH => {
566 let script_pub_key = match &self.script_pub_key {
567 Some(script) => script,
568 None => {
569 return Err(TransactionError::MissingOutpointScriptPublicKey)
570 }
571 };
572 input.extend(variable_length_integer(script_pub_key.len() as u64)?);
573 input.extend(script_pub_key);
574 }
575 _ => input.extend(vec![0x00]),
576 },
577 None => input.extend(vec![0x00]),
578 },
579 _ => {
580 input.extend(variable_length_integer(self.script_sig.len() as u64)?);
581 input.extend(&self.script_sig);
582 }
583 },
584 };
585
586 input.extend(&self.sequence);
587
588 Ok(input)
589 }
590
591 pub fn sign(
593 &mut self,
594 signature: Vec<u8>,
595 public_key: Vec<u8>,
596 ) -> Result<(), TransactionError> {
597 let mut signature = Signature::parse_standard_slice(&signature)
598 .map_err(|error| TransactionError::Crate("libsecp256k1", format!("{:?}", error)))?
599 .serialize_der()
600 .as_ref()
601 .to_vec();
602 signature.push(self.sighash_code as u8);
603
604 let signature = [variable_length_integer(signature.len() as u64)?, signature].concat();
605 let public_key = [
606 variable_length_integer(public_key.len() as u64)?,
607 public_key,
608 ]
609 .concat();
610
611 match self.get_format().unwrap() {
612 BitcoinFormat::P2PKH | BitcoinFormat::CashAddr => {
613 self.script_sig = [signature, public_key].concat()
614 }
615 BitcoinFormat::P2SH_P2WPKH => {
616 let input_script = match &self.redeem_script {
617 Some(script) => script.clone(),
618 None => {
619 return Err(TransactionError::Message(
620 "Missing redeem script".to_string(),
621 ))
622 }
623 };
624 self.script_sig = [
625 variable_length_integer(input_script.len() as u64)?,
626 input_script,
627 ]
628 .concat();
629 self.witnesses.append(&mut vec![signature, public_key]);
630 }
631 BitcoinFormat::Bech32 => self.witnesses.append(&mut vec![signature, public_key]),
632 BitcoinFormat::P2WSH => {
633 return Err(TransactionError::Message(
634 "P2WSH signing not supported".to_string(),
635 ))
636 }
637 }
638
639 self.is_signed = true;
640
641 Ok(())
642 }
643}
644
645#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
647pub struct BitcoinTransactionOutput {
648 pub amount: BitcoinAmount,
650 pub script_pub_key: Vec<u8>,
652}
653
654impl BitcoinTransactionOutput {
655 pub fn new<N: BitcoinNetwork>(
657 address: BitcoinAddress<N>,
658 amount: BitcoinAmount,
659 ) -> Result<Self, TransactionError> {
660 Ok(Self {
661 amount,
662 script_pub_key: create_script_pub_key::<N>(&address)?,
663 })
664 }
665
666 pub fn omni_data_output(
669 property_id: u32,
670 amount: BitcoinAmount,
671 ) -> Result<Self, TransactionError> {
672 let data_output = BitcoinTransactionOutput {
673 amount: BitcoinAmount(0),
674 script_pub_key: create_script_op_return(property_id, amount.0)?,
675 };
676
677 Ok(data_output)
678 }
679
680 pub fn read<R: Read>(mut reader: &mut R) -> Result<Self, TransactionError> {
682 let mut amount = [0u8; 8];
683 let _ = reader.read(&mut amount)?;
684
685 let script_pub_key: Vec<u8> = BitcoinVector::read(&mut reader, |s| {
686 let mut byte = [0u8; 1];
687 let _ = s.read(&mut byte)?;
688 Ok(byte[0])
689 })?;
690
691 Ok(Self {
692 amount: BitcoinAmount::from_satoshi(u64::from_le_bytes(amount) as i64)?,
693 script_pub_key,
694 })
695 }
696
697 pub fn serialize(&self) -> Result<Vec<u8>, TransactionError> {
699 let mut output = vec![];
700 output.extend(&self.amount.0.to_le_bytes());
701 output.extend(variable_length_integer(self.script_pub_key.len() as u64)?);
702 output.extend(&self.script_pub_key);
703 Ok(output)
704 }
705}
706
707#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
710pub struct BitcoinTransactionId {
711 pub txid: Vec<u8>,
712 pub wtxid: Vec<u8>,
713}
714
715impl TransactionId for BitcoinTransactionId {}
716
717impl fmt::Display for BitcoinTransactionId {
718 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
719 write!(f, "{}", &hex::encode(&self.txid))
720 }
721}
722
723#[derive(Debug, Clone, PartialEq, Eq)]
725pub struct BitcoinTransactionParameters<N: BitcoinNetwork> {
726 pub version: u32,
728 pub inputs: Vec<BitcoinTransactionInput<N>>,
730 pub outputs: Vec<BitcoinTransactionOutput>,
732 pub lock_time: u32,
734 pub segwit_flag: bool,
736}
737
738impl<N: BitcoinNetwork> BitcoinTransactionParameters<N> {
739 pub fn new(
741 inputs: Vec<BitcoinTransactionInput<N>>,
742 outputs: Vec<BitcoinTransactionOutput>,
743 ) -> Result<Self, TransactionError> {
744 Ok(Self {
745 version: 2,
746 inputs,
747 outputs,
748 lock_time: 0,
749 segwit_flag: false,
750 })
751 }
752
753 pub fn read<R: Read>(mut reader: R) -> Result<Self, TransactionError> {
755 let mut version = [0u8; 4];
756 let _ = reader.read(&mut version)?;
757
758 let mut inputs = BitcoinVector::read(&mut reader, BitcoinTransactionInput::<N>::read)?;
759
760 let segwit_flag = match inputs.is_empty() {
761 true => {
762 let mut flag = [0u8; 1];
763 let _ = reader.read(&mut flag)?;
764 match flag[0] {
765 1 => {
766 inputs =
767 BitcoinVector::read(&mut reader, BitcoinTransactionInput::<N>::read)?;
768 true
769 }
770 _ => return Err(TransactionError::InvalidSegwitFlag(flag[0] as usize)),
771 }
772 }
773 false => false,
774 };
775
776 let outputs = BitcoinVector::read(&mut reader, BitcoinTransactionOutput::read)?;
777
778 let params = BitcoinTransactionParameters::<N> {
800 version: u32::from_le_bytes(version),
801 inputs,
802 outputs,
803 lock_time: 0,
804 segwit_flag,
805 };
806
807 Ok(params)
808 }
809}
810
811#[derive(Debug, Clone, PartialEq, Eq)]
813pub struct BitcoinTransaction<N: BitcoinNetwork> {
814 pub parameters: BitcoinTransactionParameters<N>,
816}
817
818impl<N: BitcoinNetwork> fmt::Display for BitcoinTransaction<N> {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 write!(f, "{}", hex::encode(self.to_bytes().unwrap()))
821 }
822}
823
824impl<N: BitcoinNetwork> Transaction for BitcoinTransaction<N> {
825 type Address = BitcoinAddress<N>;
826 type Format = BitcoinFormat;
827 type PublicKey = BitcoinPublicKey<N>;
828 type TransactionId = BitcoinTransactionId;
829 type TransactionParameters = BitcoinTransactionParameters<N>;
830
831 fn new(parameters: &Self::TransactionParameters) -> Result<Self, TransactionError> {
833 Ok(Self {
834 parameters: parameters.clone(),
835 })
836 }
837
838 fn from_bytes(transaction: &[u8]) -> Result<Self, TransactionError> {
841 Ok(Self {
842 parameters: Self::TransactionParameters::read(transaction)?,
843 })
844 }
845
846 fn to_bytes(&self) -> Result<Vec<u8>, TransactionError> {
848 let mut transaction = self.parameters.version.to_le_bytes().to_vec();
849
850 if self.parameters.segwit_flag {
851 transaction.extend(vec![0x00, 0x01]);
852 }
853
854 transaction.extend(variable_length_integer(self.parameters.inputs.len() as u64)?);
855 let mut has_witness = false;
856 for input in &self.parameters.inputs {
857 if !has_witness {
858 has_witness = !input.witnesses.is_empty();
859 }
860 transaction.extend(input.serialize(!input.is_signed)?);
861 }
862
863 transaction.extend(variable_length_integer(
864 self.parameters.outputs.len() as u64
865 )?);
866 for output in &self.parameters.outputs {
867 transaction.extend(output.serialize()?);
868 }
869
870 if has_witness {
871 for input in &self.parameters.inputs {
872 match input.witnesses.len() {
873 0 => transaction.extend(vec![0x00]),
874 _ => {
875 transaction.extend(variable_length_integer(input.witnesses.len() as u64)?);
876 for witness in &input.witnesses {
877 transaction.extend(witness);
878 }
879 }
880 };
881 }
882 }
883
884 transaction.extend(&self.parameters.lock_time.to_le_bytes());
885
886 Ok(transaction)
887 }
888
889 fn to_transaction_id(&self) -> Result<Self::TransactionId, TransactionError> {
891 let mut txid = double_sha2(&self.to_transaction_bytes_without_witness()?).to_vec();
892 let mut wtxid = double_sha2(&self.to_bytes()?).to_vec();
893
894 txid.reverse();
895 wtxid.reverse();
896
897 Ok(Self::TransactionId { txid, wtxid })
898 }
899
900 fn sign(&mut self, _signature: Vec<u8>, _recid: u8) -> Result<Vec<u8>, TransactionError> {
901 panic!(
902 "trait method sign() deprecated for bitcoin, use custom methods for signature\
903 insertion in its own impl block instead."
904 );
905 }
906}
907
908impl<N: BitcoinNetwork> BitcoinTransaction<N> {
909 pub fn p2pkh_hash_preimage(
911 &self,
912 vin: usize,
913 sighash: SignatureHash,
914 ) -> Result<Vec<u8>, TransactionError> {
915 let mut preimage = self.parameters.version.to_le_bytes().to_vec();
916 preimage.extend(variable_length_integer(self.parameters.inputs.len() as u64)?);
917 for (index, input) in self.parameters.inputs.iter().enumerate() {
918 preimage.extend(input.serialize(index != vin)?);
919 }
920 preimage.extend(variable_length_integer(
921 self.parameters.outputs.len() as u64
922 )?);
923 for output in &self.parameters.outputs {
924 preimage.extend(output.serialize()?);
925 }
926 preimage.extend(&self.parameters.lock_time.to_le_bytes());
927 preimage.extend(&(sighash as u32).to_le_bytes());
928 Ok(preimage)
929 }
930
931 pub fn segwit_hash_preimage(
934 &self,
935 vin: usize,
936 sighash: SignatureHash,
937 ) -> Result<Vec<u8>, TransactionError> {
938 let mut prev_outputs = vec![];
939 let mut prev_sequences = vec![];
940 let mut outputs = vec![];
941
942 for input in &self.parameters.inputs {
943 prev_outputs.extend(&input.outpoint.reverse_transaction_id);
944 prev_outputs.extend(&input.outpoint.index.to_le_bytes());
945 prev_sequences.extend(&input.sequence);
946 }
947
948 for output in &self.parameters.outputs {
949 outputs.extend(&output.serialize()?);
950 }
951
952 let input = &self.parameters.inputs[vin];
953 let format = match &input.address {
954 Some(address) => address.format(),
955 None => return Err(TransactionError::MissingOutpointAddress),
956 };
957
958 let script = match format {
959 BitcoinFormat::Bech32 => match &input.script_pub_key {
960 Some(script) => script[1..].to_vec(),
961 None => return Err(TransactionError::MissingOutpointScriptPublicKey),
962 },
963 BitcoinFormat::CashAddr => match &input.script_pub_key {
964 Some(script) => script.to_vec(),
965 None => return Err(TransactionError::MissingOutpointScriptPublicKey),
966 },
967 BitcoinFormat::P2WSH => match &input.redeem_script {
968 Some(redeem_script) => redeem_script.to_vec(),
969 None => return Err(TransactionError::InvalidInputs("P2WSH".into())),
970 },
971 BitcoinFormat::P2SH_P2WPKH => match &input.redeem_script {
972 Some(redeem_script) => redeem_script[1..].to_vec(),
973 None => return Err(TransactionError::InvalidInputs("P2SH_P2WPKH".into())),
974 },
975 _ => return Err(TransactionError::UnsupportedPreimage("P2PKH".into())),
976 };
977
978 let mut script_code = vec![];
979 if format == BitcoinFormat::P2WSH || format == BitcoinFormat::CashAddr {
980 script_code.extend(script);
981 } else {
982 script_code.push(Opcode::OP_DUP as u8);
983 script_code.push(Opcode::OP_HASH160 as u8);
984 script_code.extend(script);
985 script_code.push(Opcode::OP_EQUALVERIFY as u8);
986 script_code.push(Opcode::OP_CHECKSIG as u8);
987 }
988 let script_code = [
989 variable_length_integer(script_code.len() as u64)?,
990 script_code,
991 ]
992 .concat();
993 let hash_prev_outputs = double_sha2(&prev_outputs);
994 let hash_sequence = double_sha2(&prev_sequences);
995 let hash_outputs = double_sha2(&outputs);
996 let balance = match &input.balance {
997 Some(balance) => balance.0.to_le_bytes(),
998 None => return Err(TransactionError::MissingOutpointAmount),
999 };
1000
1001 let mut preimage = vec![];
1002 preimage.extend(&self.parameters.version.to_le_bytes());
1003 preimage.extend(hash_prev_outputs);
1004 preimage.extend(hash_sequence);
1005 preimage.extend(&input.outpoint.reverse_transaction_id);
1006 preimage.extend(&input.outpoint.index.to_le_bytes());
1007 preimage.extend(&script_code);
1008 preimage.extend(&balance);
1009 preimage.extend(&input.sequence);
1010 preimage.extend(hash_outputs);
1011 preimage.extend(&self.parameters.lock_time.to_le_bytes());
1012 preimage.extend(&(sighash as u32).to_le_bytes());
1013
1014 Ok(preimage)
1015 }
1016
1017 pub fn to_transaction_bytes_without_witness(&self) -> Result<Vec<u8>, TransactionError> {
1019 let mut transaction = self.parameters.version.to_le_bytes().to_vec();
1020
1021 transaction.extend(variable_length_integer(self.parameters.inputs.len() as u64)?);
1022 for input in &self.parameters.inputs {
1023 transaction.extend(input.serialize(false)?);
1024 }
1025
1026 transaction.extend(variable_length_integer(
1027 self.parameters.outputs.len() as u64
1028 )?);
1029 for output in &self.parameters.outputs {
1030 transaction.extend(output.serialize()?);
1031 }
1032
1033 transaction.extend(&self.parameters.lock_time.to_le_bytes());
1034
1035 Ok(transaction)
1036 }
1037
1038 pub fn input(
1039 &mut self,
1040 index: u32,
1041 ) -> Result<&mut BitcoinTransactionInput<N>, TransactionError> {
1042 if index as usize >= self.parameters.inputs.len() {
1043 return Err(TransactionError::Message(format!(
1044 "you are referring to input {}, which is out of bound",
1045 index
1046 )));
1047 }
1048 Ok(&mut self.parameters.inputs[index as usize])
1049 }
1050
1051 pub fn digest(&mut self, index: u32) -> Result<Vec<u8>, TransactionError> {
1052 let input = self.input(index)?;
1053 let sighash = input.sighash_code;
1054 match input.get_address() {
1055 Some(addr) => {
1056 let preimage = match addr.format() {
1057 BitcoinFormat::P2PKH => self.p2pkh_hash_preimage(index as usize, sighash)?,
1058 _ => self.segwit_hash_preimage(index as usize, sighash)?,
1059 };
1060 Ok(double_sha2(&preimage).to_vec())
1061 }
1062 None => Err(TransactionError::MissingOutpointAddress),
1063 }
1064 }
1065
1066 pub fn set_segwit(&mut self) -> Result<(), TransactionError> {
1067 for input in self.parameters.inputs.clone() {
1068 if self.parameters.segwit_flag {
1069 break;
1070 }
1071 if input.is_signed {
1072 match input.get_format() {
1073 Some(BitcoinFormat::P2SH_P2WPKH) | Some(BitcoinFormat::Bech32) => {
1074 self.parameters.segwit_flag = true
1075 }
1076 _ => {}
1077 }
1078 }
1079 }
1080
1081 Ok(())
1082 }
1083}
1084
1085impl<N: BitcoinNetwork> FromStr for BitcoinTransaction<N> {
1086 type Err = TransactionError;
1087
1088 fn from_str(transaction: &str) -> Result<Self, Self::Err> {
1089 Self::from_bytes(&hex::decode(transaction)?)
1090 }
1091}