bitcoin 0.32

This commit is contained in:
Luke Parker
2024-05-21 05:27:01 -04:00
parent fb7d12ee6e
commit a0a7d63dad
14 changed files with 224 additions and 168 deletions

View File

@@ -36,7 +36,7 @@ async-lock = "3"
simple-request = { path = "../../common/request", version = "0.1", optional = true }
bitcoin = { version = "0.31", optional = true }
bitcoin = { version = "0.32", optional = true }
ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true }
monero-serai = { path = "../../coins/monero", version = "0.1.4-alpha", optional = true }

View File

@@ -6,8 +6,8 @@ use bitcoin::{
hashes::{Hash as HashTrait, hash160::Hash},
PubkeyHash, ScriptHash,
network::Network,
WitnessVersion, WitnessProgram,
address::{Error, Payload, NetworkChecked, Address as BAddressGeneric},
WitnessVersion, WitnessProgram, ScriptBuf,
address::{AddressType, NetworkChecked, Address as BAddressGeneric},
};
type BAddress = BAddressGeneric<NetworkChecked>;
@@ -17,21 +17,22 @@ pub struct Address(BAddress);
impl PartialEq for Address {
fn eq(&self, other: &Self) -> bool {
// Since Serai defines the Bitcoin-address specification as a variant of the payload alone,
// define equivalency as the payload alone
self.0.payload() == other.0.payload()
// Since Serai defines the Bitcoin-address specification as a variant of the script alone,
// define equivalency as the script alone
self.0.script_pubkey() == other.0.script_pubkey()
}
}
impl FromStr for Address {
type Err = Error;
fn from_str(str: &str) -> Result<Address, Error> {
type Err = ();
fn from_str(str: &str) -> Result<Address, ()> {
Address::new(
BAddressGeneric::from_str(str)
.map_err(|_| Error::UnrecognizedScript)?
.require_network(Network::Bitcoin)?,
.map_err(|_| ())?
.require_network(Network::Bitcoin)
.map_err(|_| ())?,
)
.ok_or(Error::UnrecognizedScript)
.ok_or(())
}
}
@@ -54,55 +55,65 @@ enum EncodedAddress {
impl TryFrom<Vec<u8>> for Address {
type Error = ();
fn try_from(data: Vec<u8>) -> Result<Address, ()> {
Ok(Address(BAddress::new(
Network::Bitcoin,
match EncodedAddress::decode(&mut data.as_ref()).map_err(|_| ())? {
EncodedAddress::P2PKH(hash) => {
Payload::PubkeyHash(PubkeyHash::from_raw_hash(Hash::from_byte_array(hash)))
}
EncodedAddress::P2SH(hash) => {
Payload::ScriptHash(ScriptHash::from_raw_hash(Hash::from_byte_array(hash)))
}
EncodedAddress::P2WPKH(hash) => {
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V0, hash).unwrap())
}
EncodedAddress::P2WSH(hash) => {
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V0, hash).unwrap())
}
EncodedAddress::P2TR(key) => {
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V1, key).unwrap())
}
},
)))
Ok(Address(match EncodedAddress::decode(&mut data.as_ref()).map_err(|_| ())? {
EncodedAddress::P2PKH(hash) => {
BAddress::p2pkh(PubkeyHash::from_raw_hash(Hash::from_byte_array(hash)), Network::Bitcoin)
}
EncodedAddress::P2SH(hash) => {
let script_hash = ScriptHash::from_raw_hash(Hash::from_byte_array(hash));
let res =
BAddress::from_script(&ScriptBuf::new_p2sh(&script_hash), Network::Bitcoin).unwrap();
debug_assert_eq!(res.script_hash(), Some(script_hash));
res
}
EncodedAddress::P2WPKH(hash) => BAddress::from_witness_program(
WitnessProgram::new(WitnessVersion::V0, &hash).unwrap(),
Network::Bitcoin,
),
EncodedAddress::P2WSH(hash) => BAddress::from_witness_program(
WitnessProgram::new(WitnessVersion::V0, &hash).unwrap(),
Network::Bitcoin,
),
EncodedAddress::P2TR(key) => BAddress::from_witness_program(
WitnessProgram::new(WitnessVersion::V1, &key).unwrap(),
Network::Bitcoin,
),
}))
}
}
fn try_to_vec(addr: &Address) -> Result<Vec<u8>, ()> {
let witness_program = |addr: &Address| {
let script = addr.0.script_pubkey();
let program_push = script.as_script().instructions().last().ok_or(())?.map_err(|_| ())?;
let program = program_push.push_bytes().ok_or(())?.as_bytes();
Ok::<_, ()>(program.to_vec())
};
Ok(
(match addr.0.payload() {
Payload::PubkeyHash(hash) => EncodedAddress::P2PKH(*hash.as_raw_hash().as_byte_array()),
Payload::ScriptHash(hash) => EncodedAddress::P2SH(*hash.as_raw_hash().as_byte_array()),
Payload::WitnessProgram(program) => match program.version() {
WitnessVersion::V0 => {
let program = program.program();
if program.len() == 20 {
let mut buf = [0; 20];
buf.copy_from_slice(program.as_ref());
EncodedAddress::P2WPKH(buf)
} else if program.len() == 32 {
let mut buf = [0; 32];
buf.copy_from_slice(program.as_ref());
EncodedAddress::P2WSH(buf)
} else {
Err(())?
}
}
WitnessVersion::V1 => {
let program_ref: &[u8] = program.program().as_ref();
EncodedAddress::P2TR(program_ref.try_into().map_err(|_| ())?)
}
_ => Err(())?,
},
(match addr.0.address_type() {
Some(AddressType::P2pkh) => {
EncodedAddress::P2PKH(*addr.0.pubkey_hash().unwrap().as_raw_hash().as_byte_array())
}
Some(AddressType::P2sh) => {
EncodedAddress::P2SH(*addr.0.script_hash().unwrap().as_raw_hash().as_byte_array())
}
Some(AddressType::P2wpkh) => {
let program = witness_program(addr)?;
let mut buf = [0; 20];
buf.copy_from_slice(program.as_ref());
EncodedAddress::P2WPKH(buf)
}
Some(AddressType::P2wsh) => {
let program = witness_program(addr)?;
let mut buf = [0; 32];
buf.copy_from_slice(program.as_ref());
EncodedAddress::P2WSH(buf)
}
Some(AddressType::P2tr) => {
let program = witness_program(addr)?;
let program_ref: &[u8] = program.as_ref();
EncodedAddress::P2TR(program_ref.try_into().map_err(|_| ())?)
}
_ => Err(())?,
})
.encode(),