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
use bitcoin::blockdata::script::Script;
use bitcoin::network::constants::Network; use bitcoin::util::{address, bip32, psbt};
use bitcoin_bech32::{u5, WitnessProgram};
use bitcoin_hashes::{hash160, sha256d, Hash};
use secp256k1;
use error::{Error, Result};
fn bech_network(network: Network) -> bitcoin_bech32::constants::Network {
match network {
Network::Bitcoin => bitcoin_bech32::constants::Network::Bitcoin,
Network::Testnet => bitcoin_bech32::constants::Network::Testnet,
Network::Regtest => bitcoin_bech32::constants::Network::Regtest,
}
}
pub fn address_from_script(script: &Script, network: Network) -> Option<address::Address> {
Some(address::Address {
payload: if script.is_p2sh() {
address::Payload::ScriptHash(hash160::Hash::from_slice(&script[2..22]).unwrap())
} else if script.is_p2pkh() {
address::Payload::PubkeyHash(hash160::Hash::from_slice(&script[3..23]).unwrap())
} else if script.is_v0_p2wsh() {
match WitnessProgram::new(
u5::try_from_u8(0).expect("0<32"),
script.as_bytes()[2..34].to_vec(),
bech_network(network),
) {
Ok(prog) => address::Payload::WitnessProgram(prog),
Err(_) => return None,
}
} else if script.is_v0_p2wpkh() {
match WitnessProgram::new(
u5::try_from_u8(0).expect("0<32"),
script.as_bytes()[2..22].to_vec(),
bech_network(network),
) {
Ok(prog) => address::Payload::WitnessProgram(prog),
Err(_) => return None,
}
} else {
return None;
},
network,
})
}
pub fn psbt_find_input(
psbt: &psbt::PartiallySignedTransaction,
txid: sha256d::Hash,
) -> Result<&psbt::Input> {
let inputs = &psbt.global.unsigned_tx.input;
let opt = inputs.iter().enumerate().find(|i| i.1.previous_output.txid == txid);
let idx = opt.ok_or(Error::TxRequestUnknownTxid(txid))?.0;
psbt.inputs.get(idx).ok_or(Error::TxRequestInvalidIndex(idx))
}
pub fn from_rev_bytes(rev_bytes: &[u8]) -> Option<sha256d::Hash> {
let mut bytes = rev_bytes.to_vec();
bytes.reverse();
sha256d::Hash::from_slice(&bytes).ok()
}
pub fn to_rev_bytes(hash: &sha256d::Hash) -> [u8; 32] {
let mut bytes = (*hash).into_inner();
bytes.reverse();
bytes
}
pub fn parse_recoverable_signature(
sig: &[u8],
) -> std::result::Result<secp256k1::RecoverableSignature, secp256k1::Error> {
if sig.len() != 65 {
return Err(secp256k1::Error::InvalidSignature);
}
let rec_id = secp256k1::RecoveryId::from_i32(if sig[0] >= 31 {
(sig[0] - 31) as i32
} else {
(sig[0] - 27) as i32
})?;
secp256k1::RecoverableSignature::from_compact(&sig[1..], rec_id)
}
pub fn coin_name(network: Network) -> Result<String> {
match network {
Network::Bitcoin => Ok("Bitcoin".to_owned()),
Network::Testnet => Ok("Testnet".to_owned()),
_ => Err(Error::UnsupportedNetwork),
}
}
pub fn convert_path(path: &bip32::DerivationPath) -> Vec<u32> {
path.into_iter().map(|i| u32::from(*i)).collect()
}