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

84
Cargo.lock generated
View File

@@ -862,6 +862,16 @@ dependencies = [
"tiny-keccak", "tiny-keccak",
] ]
[[package]]
name = "base58ck"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
dependencies = [
"bitcoin-internals",
"bitcoin_hashes",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.1" version = "0.13.1"
@@ -888,9 +898,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]] [[package]]
name = "bech32" name = "bech32"
version = "0.10.0-beta" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
[[package]] [[package]]
name = "beef" name = "beef"
@@ -947,14 +957,16 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "bitcoin" name = "bitcoin"
version = "0.31.2" version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae" checksum = "7170e7750a20974246f17ece04311b4205a6155f1db564c5b224af817663c3ea"
dependencies = [ dependencies = [
"base58ck",
"bech32", "bech32",
"bitcoin-internals", "bitcoin-internals",
"bitcoin-io",
"bitcoin-units",
"bitcoin_hashes", "bitcoin_hashes",
"core2 0.3.3",
"hex-conservative", "hex-conservative",
"hex_lit", "hex_lit",
"secp256k1", "secp256k1",
@@ -963,13 +975,19 @@ dependencies = [
[[package]] [[package]]
name = "bitcoin-internals" name = "bitcoin-internals"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bitcoin-io"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56"
[[package]] [[package]]
name = "bitcoin-serai" name = "bitcoin-serai"
version = "0.3.0" version = "0.3.0"
@@ -991,13 +1009,22 @@ dependencies = [
] ]
[[package]] [[package]]
name = "bitcoin_hashes" name = "bitcoin-units"
version = "0.13.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" checksum = "cb54da0b28892f3c52203a7191534033e051b6f4b52bc15480681b57b7e036f5"
dependencies = [ dependencies = [
"bitcoin-internals", "bitcoin-internals",
"core2 0.3.3", "serde",
]
[[package]]
name = "bitcoin_hashes"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
dependencies = [
"bitcoin-io",
"hex-conservative", "hex-conservative",
"serde", "serde",
] ]
@@ -1400,7 +1427,7 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd94671561e36e4e7de75f753f577edafb0e7c05d6e4547229fdf7938fbcd2c3" checksum = "fd94671561e36e4e7de75f753f577edafb0e7c05d6e4547229fdf7938fbcd2c3"
dependencies = [ dependencies = [
"core2 0.4.0", "core2",
"multibase", "multibase",
"multihash 0.18.1", "multihash 0.18.1",
"serde", "serde",
@@ -1584,15 +1611,6 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "core2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "core2" name = "core2"
version = "0.4.0" version = "0.4.0"
@@ -3128,11 +3146,11 @@ dependencies = [
[[package]] [[package]]
name = "hex-conservative" name = "hex-conservative"
version = "0.1.1" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986"
dependencies = [ dependencies = [
"core2 0.3.3", "arrayvec",
] ]
[[package]] [[package]]
@@ -3288,7 +3306,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite 0.2.14", "pin-project-lite 0.2.14",
"socket2 0.4.10", "socket2 0.5.6",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@@ -4758,7 +4776,7 @@ dependencies = [
"blake2b_simd", "blake2b_simd",
"blake2s_simd", "blake2s_simd",
"blake3", "blake3",
"core2 0.4.0", "core2",
"digest 0.10.7", "digest 0.10.7",
"multihash-derive 0.8.0", "multihash-derive 0.8.0",
"sha2", "sha2",
@@ -4772,7 +4790,7 @@ version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492"
dependencies = [ dependencies = [
"core2 0.4.0", "core2",
"unsigned-varint", "unsigned-varint",
] ]
@@ -4785,7 +4803,7 @@ dependencies = [
"blake2b_simd", "blake2b_simd",
"blake2s_simd", "blake2s_simd",
"blake3", "blake3",
"core2 0.4.0", "core2",
"digest 0.10.7", "digest 0.10.7",
"multihash-derive 0.9.0", "multihash-derive 0.9.0",
"ripemd", "ripemd",
@@ -4815,7 +4833,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e" checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e"
dependencies = [ dependencies = [
"core2 0.4.0", "core2",
"multihash 0.19.1", "multihash 0.19.1",
"multihash-derive-impl", "multihash-derive-impl",
] ]
@@ -7548,9 +7566,9 @@ dependencies = [
[[package]] [[package]]
name = "secp256k1" name = "secp256k1"
version = "0.28.2" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3"
dependencies = [ dependencies = [
"bitcoin_hashes", "bitcoin_hashes",
"rand", "rand",
@@ -7560,9 +7578,9 @@ dependencies = [
[[package]] [[package]]
name = "secp256k1-sys" name = "secp256k1-sys"
version = "0.9.2" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b"
dependencies = [ dependencies = [
"cc", "cc",
] ]

View File

@@ -23,7 +23,7 @@ thiserror = { version = "1", default-features = false, optional = true }
zeroize = { version = "^1.5", default-features = false } zeroize = { version = "^1.5", default-features = false }
rand_core = { version = "0.6", default-features = false } rand_core = { version = "0.6", default-features = false }
bitcoin = { version = "0.31", default-features = false, features = ["no-std"] } bitcoin = { version = "0.32", default-features = false }
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] } k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] }
@@ -36,7 +36,7 @@ serde_json = { version = "1", default-features = false, optional = true }
simple-request = { path = "../../common/request", version = "0.1", default-features = false, features = ["tls", "basic-auth"], optional = true } simple-request = { path = "../../common/request", version = "0.1", default-features = false, features = ["tls", "basic-auth"], optional = true }
[dev-dependencies] [dev-dependencies]
secp256k1 = { version = "0.28", default-features = false, features = ["std"] } secp256k1 = { version = "0.29", default-features = false, features = ["std"] }
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] } frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] }

View File

@@ -195,13 +195,13 @@ impl Rpc {
// If this was already successfully published, consider this having succeeded // If this was already successfully published, consider this having succeeded
if let RpcError::RequestError(Error { code, .. }) = e { if let RpcError::RequestError(Error { code, .. }) = e {
if code == RPC_VERIFY_ALREADY_IN_CHAIN { if code == RPC_VERIFY_ALREADY_IN_CHAIN {
return Ok(tx.txid()); return Ok(tx.compute_txid());
} }
} }
Err(e)? Err(e)?
} }
}; };
if txid != tx.txid() { if txid != tx.compute_txid() {
Err(RpcError::InvalidResponse("returned TX ID inequals calculated TX ID"))?; Err(RpcError::InvalidResponse("returned TX ID inequals calculated TX ID"))?;
} }
Ok(txid) Ok(txid)
@@ -215,7 +215,7 @@ impl Rpc {
let tx: Transaction = encode::deserialize(&bytes) let tx: Transaction = encode::deserialize(&bytes)
.map_err(|_| RpcError::InvalidResponse("node sent an improperly serialized transaction"))?; .map_err(|_| RpcError::InvalidResponse("node sent an improperly serialized transaction"))?;
let mut tx_hash = *tx.txid().as_raw_hash().as_byte_array(); let mut tx_hash = *tx.compute_txid().as_raw_hash().as_byte_array();
tx_hash.reverse(); tx_hash.reverse();
if hash != &tx_hash { if hash != &tx_hash {
Err(RpcError::InvalidResponse("node replied with a different transaction"))?; Err(RpcError::InvalidResponse("node replied with a different transaction"))?;

View File

@@ -39,7 +39,7 @@ fn test_algorithm() {
.verify_schnorr( .verify_schnorr(
&Signature::from_slice(&sig) &Signature::from_slice(&sig)
.expect("couldn't convert produced signature to secp256k1::Signature"), .expect("couldn't convert produced signature to secp256k1::Signature"),
&Message::from(Hash::hash(MESSAGE)), &Message::from_digest_slice(Hash::hash(MESSAGE).as_ref()).unwrap(),
&x_only(&keys[&Participant::new(1).unwrap()].group_key()), &x_only(&keys[&Participant::new(1).unwrap()].group_key()),
) )
.unwrap() .unwrap()

View File

@@ -4,7 +4,7 @@ use std_shims::{
io::{self, Write}, io::{self, Write},
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std_shims::io::Read; use std::io::{Read, BufReader};
use k256::{ use k256::{
elliptic_curve::sec1::{Tag, ToEncodedPoint}, elliptic_curve::sec1::{Tag, ToEncodedPoint},
@@ -18,8 +18,8 @@ use frost::{
}; };
use bitcoin::{ use bitcoin::{
consensus::encode::serialize, key::TweakedPublicKey, address::Payload, OutPoint, ScriptBuf, consensus::encode::serialize, key::TweakedPublicKey, OutPoint, ScriptBuf, TxOut, Transaction,
TxOut, Transaction, Block, Block,
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
use bitcoin::consensus::encode::Decodable; use bitcoin::consensus::encode::Decodable;
@@ -46,12 +46,12 @@ pub fn tweak_keys(keys: &ThresholdKeys<Secp256k1>) -> ThresholdKeys<Secp256k1> {
/// Return the Taproot address payload for a public key. /// Return the Taproot address payload for a public key.
/// ///
/// If the key is odd, this will return None. /// If the key is odd, this will return None.
pub fn address_payload(key: ProjectivePoint) -> Option<Payload> { pub fn p2tr_script_buf(key: ProjectivePoint) -> Option<ScriptBuf> {
if key.to_encoded_point(true).tag() != Tag::CompressedEvenY { if key.to_encoded_point(true).tag() != Tag::CompressedEvenY {
return None; return None;
} }
Some(Payload::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked(x_only(&key)))) Some(ScriptBuf::new_p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked(x_only(&key))))
} }
/// A spendable output. /// A spendable output.
@@ -89,11 +89,17 @@ impl ReceivedOutput {
/// Read a ReceivedOutput from a generic satisfying Read. /// Read a ReceivedOutput from a generic satisfying Read.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> { pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> {
Ok(ReceivedOutput { let offset = Secp256k1::read_F(r)?;
offset: Secp256k1::read_F(r)?, let output;
output: TxOut::consensus_decode(r).map_err(|_| io::Error::other("invalid TxOut"))?, let outpoint;
outpoint: OutPoint::consensus_decode(r).map_err(|_| io::Error::other("invalid OutPoint"))?, {
}) let mut buf_r = BufReader::new(r);
output =
TxOut::consensus_decode(&mut buf_r).map_err(|_| io::Error::other("invalid TxOut"))?;
outpoint =
OutPoint::consensus_decode(&mut buf_r).map_err(|_| io::Error::other("invalid OutPoint"))?;
}
Ok(ReceivedOutput { offset, output, outpoint })
} }
/// Write a ReceivedOutput to a generic satisfying Write. /// Write a ReceivedOutput to a generic satisfying Write.
@@ -124,7 +130,7 @@ impl Scanner {
/// Returns None if this key can't be scanned for. /// Returns None if this key can't be scanned for.
pub fn new(key: ProjectivePoint) -> Option<Scanner> { pub fn new(key: ProjectivePoint) -> Option<Scanner> {
let mut scripts = HashMap::new(); let mut scripts = HashMap::new();
scripts.insert(address_payload(key)?.script_pubkey(), Scalar::ZERO); scripts.insert(p2tr_script_buf(key)?, Scalar::ZERO);
Some(Scanner { key, scripts }) Some(Scanner { key, scripts })
} }
@@ -141,9 +147,8 @@ impl Scanner {
// chance of being even // chance of being even
// That means this should terminate within a very small amount of iterations // That means this should terminate within a very small amount of iterations
loop { loop {
match address_payload(self.key + (ProjectivePoint::GENERATOR * offset)) { match p2tr_script_buf(self.key + (ProjectivePoint::GENERATOR * offset)) {
Some(address) => { Some(script) => {
let script = address.script_pubkey();
if self.scripts.contains_key(&script) { if self.scripts.contains_key(&script) {
None?; None?;
} }
@@ -166,7 +171,7 @@ impl Scanner {
res.push(ReceivedOutput { res.push(ReceivedOutput {
offset: *offset, offset: *offset,
output: output.clone(), output: output.clone(),
outpoint: OutPoint::new(tx.txid(), vout), outpoint: OutPoint::new(tx.compute_txid(), vout),
}); });
} }
} }

View File

@@ -23,7 +23,7 @@ use bitcoin::{
use crate::{ use crate::{
crypto::Schnorr, crypto::Schnorr,
wallet::{ReceivedOutput, address_payload}, wallet::{ReceivedOutput, p2tr_script_buf},
}; };
#[rustfmt::skip] #[rustfmt::skip]
@@ -248,7 +248,7 @@ impl SignableTransaction {
/// Returns the TX ID of the transaction this will create. /// Returns the TX ID of the transaction this will create.
pub fn txid(&self) -> [u8; 32] { pub fn txid(&self) -> [u8; 32] {
let mut res = self.tx.txid().to_byte_array(); let mut res = self.tx.compute_txid().to_byte_array();
res.reverse(); res.reverse();
res res
} }
@@ -288,7 +288,7 @@ impl SignableTransaction {
transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes()); transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes());
let offset = keys.clone().offset(self.offsets[i]); let offset = keys.clone().offset(self.offsets[i]);
if address_payload(offset.group_key())?.script_pubkey() != self.prevouts[i].script_pubkey { if p2tr_script_buf(offset.group_key())? != self.prevouts[i].script_pubkey {
None?; None?;
} }

View File

@@ -22,11 +22,10 @@ use bitcoin_serai::{
hashes::Hash as HashTrait, hashes::Hash as HashTrait,
blockdata::opcodes::all::OP_RETURN, blockdata::opcodes::all::OP_RETURN,
script::{PushBytesBuf, Instruction, Instructions, Script}, script::{PushBytesBuf, Instruction, Instructions, Script},
address::NetworkChecked,
OutPoint, Amount, TxOut, Transaction, Network, Address, OutPoint, Amount, TxOut, Transaction, Network, Address,
}, },
wallet::{ wallet::{
tweak_keys, address_payload, ReceivedOutput, Scanner, TransactionError, SignableTransaction, tweak_keys, p2tr_script_buf, ReceivedOutput, Scanner, TransactionError, SignableTransaction,
}, },
rpc::Rpc, rpc::Rpc,
}; };
@@ -48,7 +47,7 @@ async fn send_and_get_output(rpc: &Rpc, scanner: &Scanner, key: ProjectivePoint)
"generatetoaddress", "generatetoaddress",
serde_json::json!([ serde_json::json!([
1, 1,
Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap()) Address::from_script(&p2tr_script_buf(key).unwrap(), Network::Regtest).unwrap()
]), ]),
) )
.await .await
@@ -69,7 +68,7 @@ async fn send_and_get_output(rpc: &Rpc, scanner: &Scanner, key: ProjectivePoint)
assert_eq!(outputs, scanner.scan_transaction(&block.txdata[0])); assert_eq!(outputs, scanner.scan_transaction(&block.txdata[0]));
assert_eq!(outputs.len(), 1); assert_eq!(outputs.len(), 1);
assert_eq!(outputs[0].outpoint(), &OutPoint::new(block.txdata[0].txid(), 0)); assert_eq!(outputs[0].outpoint(), &OutPoint::new(block.txdata[0].compute_txid(), 0));
assert_eq!(outputs[0].value(), block.txdata[0].output[0].value.to_sat()); assert_eq!(outputs[0].value(), block.txdata[0].output[0].value.to_sat());
assert_eq!( assert_eq!(
@@ -193,7 +192,7 @@ async_sequential! {
assert_eq!(output.offset(), Scalar::ZERO); assert_eq!(output.offset(), Scalar::ZERO);
let inputs = vec![output]; let inputs = vec![output];
let addr = || Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap()); let addr = || Address::from_script(&p2tr_script_buf(key).unwrap(), Network::Regtest).unwrap();
let payments = vec![(addr(), 1000)]; let payments = vec![(addr(), 1000)];
assert!(SignableTransaction::new(inputs.clone(), &payments, None, None, FEE).is_ok()); assert!(SignableTransaction::new(inputs.clone(), &payments, None, None, FEE).is_ok());
@@ -261,14 +260,14 @@ async_sequential! {
// Declare payments, change, fee // Declare payments, change, fee
let payments = [ let payments = [
(Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap()), 1005), (Address::from_script(&p2tr_script_buf(key).unwrap(), Network::Regtest).unwrap(), 1005),
(Address::<NetworkChecked>::new(Network::Regtest, address_payload(offset_key).unwrap()), 1007) (Address::from_script(&p2tr_script_buf(offset_key).unwrap(), Network::Regtest).unwrap(), 1007)
]; ];
let change_offset = scanner.register_offset(Scalar::random(&mut OsRng)).unwrap(); let change_offset = scanner.register_offset(Scalar::random(&mut OsRng)).unwrap();
let change_key = key + (ProjectivePoint::GENERATOR * change_offset); let change_key = key + (ProjectivePoint::GENERATOR * change_offset);
let change_addr = let change_addr =
Address::<NetworkChecked>::new(Network::Regtest, address_payload(change_key).unwrap()); Address::from_script(&p2tr_script_buf(change_key).unwrap(), Network::Regtest).unwrap();
// Create and sign the TX // Create and sign the TX
let tx = SignableTransaction::new( let tx = SignableTransaction::new(
@@ -287,7 +286,7 @@ async_sequential! {
// Ensure we can scan it // Ensure we can scan it
let outputs = scanner.scan_transaction(&tx); let outputs = scanner.scan_transaction(&tx);
for (o, output) in outputs.iter().enumerate() { for (o, output) in outputs.iter().enumerate() {
assert_eq!(output.outpoint(), &OutPoint::new(tx.txid(), u32::try_from(o).unwrap())); assert_eq!(output.outpoint(), &OutPoint::new(tx.compute_txid(), u32::try_from(o).unwrap()));
assert_eq!(&ReceivedOutput::read::<&[u8]>(&mut output.serialize().as_ref()).unwrap(), output); assert_eq!(&ReceivedOutput::read::<&[u8]>(&mut output.serialize().as_ref()).unwrap(), output);
} }
@@ -320,7 +319,7 @@ async_sequential! {
// This also tests send_raw_transaction and get_transaction, which the RPC test can't // This also tests send_raw_transaction and get_transaction, which the RPC test can't
// effectively test // effectively test
rpc.send_raw_transaction(&tx).await.unwrap(); rpc.send_raw_transaction(&tx).await.unwrap();
let mut hash = *tx.txid().as_raw_hash().as_byte_array(); let mut hash = *tx.compute_txid().as_raw_hash().as_byte_array();
hash.reverse(); hash.reverse();
assert_eq!(tx, rpc.get_transaction(&hash).await.unwrap()); assert_eq!(tx, rpc.get_transaction(&hash).await.unwrap());
assert_eq!(expected_id, hash); assert_eq!(expected_id, hash);
@@ -344,7 +343,7 @@ async_sequential! {
&SignableTransaction::new( &SignableTransaction::new(
vec![output], vec![output],
&[], &[],
Some(&Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap())), Some(&Address::from_script(&p2tr_script_buf(key).unwrap(), Network::Regtest).unwrap()),
Some(data.clone()), Some(data.clone()),
FEE FEE
).unwrap() ).unwrap()

View File

@@ -45,7 +45,7 @@ frost-schnorrkel = { path = "../crypto/schnorrkel", default-features = false }
k256 = { version = "^0.13.1", default-features = false, features = ["std"], optional = true } k256 = { version = "^0.13.1", default-features = false, features = ["std"], optional = true }
# Bitcoin # Bitcoin
secp256k1 = { version = "0.28", default-features = false, features = ["std", "global-context", "rand-std"], optional = true } secp256k1 = { version = "0.29", default-features = false, features = ["std", "global-context", "rand-std"], optional = true }
bitcoin-serai = { path = "../coins/bitcoin", default-features = false, features = ["std"], optional = true } bitcoin-serai = { path = "../coins/bitcoin", default-features = false, features = ["std"], optional = true }
# Ethereum # Ethereum

View File

@@ -20,12 +20,12 @@ use bitcoin_serai::{
key::{Parity, XOnlyPublicKey}, key::{Parity, XOnlyPublicKey},
consensus::{Encodable, Decodable}, consensus::{Encodable, Decodable},
script::Instruction, script::Instruction,
address::{NetworkChecked, Address as BAddress}, address::Address as BAddress,
Transaction, Block, Network as BNetwork, ScriptBuf, Transaction, Block, Network as BNetwork, ScriptBuf,
opcodes::all::{OP_SHA256, OP_EQUALVERIFY}, opcodes::all::{OP_SHA256, OP_EQUALVERIFY},
}, },
wallet::{ wallet::{
tweak_keys, address_payload, ReceivedOutput, Scanner, TransactionError, tweak_keys, p2tr_script_buf, ReceivedOutput, Scanner, TransactionError,
SignableTransaction as BSignableTransaction, TransactionMachine, SignableTransaction as BSignableTransaction, TransactionMachine,
}, },
rpc::{RpcError, Rpc}, rpc::{RpcError, Rpc},
@@ -175,7 +175,7 @@ pub struct Fee(u64);
impl TransactionTrait<Bitcoin> for Transaction { impl TransactionTrait<Bitcoin> for Transaction {
type Id = [u8; 32]; type Id = [u8; 32];
fn id(&self) -> Self::Id { fn id(&self) -> Self::Id {
let mut hash = *self.txid().as_raw_hash().as_byte_array(); let mut hash = *self.compute_txid().as_raw_hash().as_byte_array();
hash.reverse(); hash.reverse();
hash hash
} }
@@ -243,7 +243,8 @@ impl EventualityTrait for Eventuality {
buf buf
} }
fn read_completion<R: io::Read>(reader: &mut R) -> io::Result<Transaction> { fn read_completion<R: io::Read>(reader: &mut R) -> io::Result<Transaction> {
Transaction::consensus_decode(reader).map_err(|e| io::Error::other(format!("{e}"))) Transaction::consensus_decode(&mut io::BufReader::new(reader))
.map_err(|e| io::Error::other(format!("{e}")))
} }
} }
@@ -535,11 +536,11 @@ impl Bitcoin {
private_key: &PrivateKey, private_key: &PrivateKey,
) -> ScriptBuf { ) -> ScriptBuf {
let public_key = PublicKey::from_private_key(SECP256K1, private_key); let public_key = PublicKey::from_private_key(SECP256K1, private_key);
let main_addr = BAddress::p2pkh(&public_key, BNetwork::Regtest); let main_addr = BAddress::p2pkh(public_key, BNetwork::Regtest);
let mut der = SECP256K1 let mut der = SECP256K1
.sign_ecdsa_low_r( .sign_ecdsa_low_r(
&Message::from( &Message::from_digest_slice(
SighashCache::new(tx) SighashCache::new(tx)
.legacy_signature_hash( .legacy_signature_hash(
input_index, input_index,
@@ -547,8 +548,10 @@ impl Bitcoin {
EcdsaSighashType::All.to_u32(), EcdsaSighashType::All.to_u32(),
) )
.unwrap() .unwrap()
.to_raw_hash(), .to_raw_hash()
), .as_ref(),
)
.unwrap(),
&private_key.inner, &private_key.inner,
) )
.serialize_der() .serialize_der()
@@ -577,8 +580,14 @@ const MAX_INPUTS: usize = 520;
const MAX_OUTPUTS: usize = 520; const MAX_OUTPUTS: usize = 520;
fn address_from_key(key: ProjectivePoint) -> Address { fn address_from_key(key: ProjectivePoint) -> Address {
Address::new(BAddress::<NetworkChecked>::new(BNetwork::Bitcoin, address_payload(key).unwrap())) Address::new(
.unwrap() BAddress::from_script(
&p2tr_script_buf(key).expect("creating address from key which isn't properly tweaked"),
BNetwork::Bitcoin,
)
.expect("couldn't go from p2tr script buf to address"),
)
.expect("couldn't create Serai-representable address for bitcoin address")
} }
#[async_trait] #[async_trait]
@@ -858,7 +867,7 @@ impl Network for Bitcoin {
Err(RpcError::ConnectionError) => Err(NetworkError::ConnectionError)?, Err(RpcError::ConnectionError) => Err(NetworkError::ConnectionError)?,
// TODO: Distinguish already in pool vs double spend (other signing attempt succeeded) vs // TODO: Distinguish already in pool vs double spend (other signing attempt succeeded) vs
// invalid transaction // invalid transaction
Err(e) => panic!("failed to publish TX {}: {e}", tx.txid()), Err(e) => panic!("failed to publish TX {}: {e}", tx.compute_txid()),
} }
Ok(()) Ok(())
} }
@@ -909,7 +918,7 @@ impl Network for Bitcoin {
let secret_key = SecretKey::new(&mut rand_core::OsRng); let secret_key = SecretKey::new(&mut rand_core::OsRng);
let private_key = PrivateKey::new(secret_key, BNetwork::Regtest); let private_key = PrivateKey::new(secret_key, BNetwork::Regtest);
let public_key = PublicKey::from_private_key(SECP256K1, &private_key); let public_key = PublicKey::from_private_key(SECP256K1, &private_key);
let main_addr = BAddress::p2pkh(&public_key, BNetwork::Regtest); let main_addr = BAddress::p2pkh(public_key, BNetwork::Regtest);
let new_block = self.get_latest_block_number().await.unwrap() + 1; let new_block = self.get_latest_block_number().await.unwrap() + 1;
self self
@@ -923,7 +932,7 @@ impl Network for Bitcoin {
version: Version(2), version: Version(2),
lock_time: LockTime::ZERO, lock_time: LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { txid: tx.txid(), vout: 0 }, previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
script_sig: Script::new().into(), script_sig: Script::new().into(),
sequence: Sequence(u32::MAX), sequence: Sequence(u32::MAX),
witness: Witness::default(), witness: Witness::default(),

View File

@@ -70,7 +70,7 @@ mod bitcoin {
// btc key pair to send from // btc key pair to send from
let private_key = PrivateKey::new(SecretKey::new(&mut rand_core::OsRng), BNetwork::Regtest); let private_key = PrivateKey::new(SecretKey::new(&mut rand_core::OsRng), BNetwork::Regtest);
let public_key = PublicKey::from_private_key(SECP256K1, &private_key); let public_key = PublicKey::from_private_key(SECP256K1, &private_key);
let main_addr = BAddress::p2pkh(&public_key, BNetwork::Regtest); let main_addr = BAddress::p2pkh(public_key, BNetwork::Regtest);
// get unlocked coins // get unlocked coins
let new_block = btc.get_latest_block_number().await.unwrap() + 1; let new_block = btc.get_latest_block_number().await.unwrap() + 1;
@@ -107,7 +107,7 @@ mod bitcoin {
version: Version(2), version: Version(2),
lock_time: LockTime::ZERO, lock_time: LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { txid: tx.txid(), vout: 0 }, previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
script_sig: Script::new().into(), script_sig: Script::new().into(),
sequence: Sequence(u32::MAX), sequence: Sequence(u32::MAX),
witness: Witness::default(), witness: Witness::default(),
@@ -128,7 +128,7 @@ mod bitcoin {
version: Version(2), version: Version(2),
lock_time: LockTime::ZERO, lock_time: LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { txid: tx.txid(), vout: 0 }, previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
script_sig: Script::new().into(), script_sig: Script::new().into(),
sequence: Sequence(u32::MAX), sequence: Sequence(u32::MAX),
witness: Witness::new(), witness: Witness::new(),
@@ -143,12 +143,14 @@ mod bitcoin {
// This is the standard script with an extra argument of the InInstruction // This is the standard script with an extra argument of the InInstruction
let mut sig = SECP256K1 let mut sig = SECP256K1
.sign_ecdsa_low_r( .sign_ecdsa_low_r(
&Message::from( &Message::from_digest_slice(
SighashCache::new(&tx) SighashCache::new(&tx)
.p2wsh_signature_hash(0, &script, initial_output_value, EcdsaSighashType::All) .p2wsh_signature_hash(0, &script, initial_output_value, EcdsaSighashType::All)
.unwrap() .unwrap()
.to_raw_hash(), .to_raw_hash()
), .as_ref(),
)
.unwrap(),
&private_key.inner, &private_key.inner,
) )
.serialize_der() .serialize_der()

View File

@@ -36,7 +36,7 @@ async-lock = "3"
simple-request = { path = "../../common/request", version = "0.1", optional = true } 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 } ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true }
monero-serai = { path = "../../coins/monero", version = "0.1.4-alpha", 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}, hashes::{Hash as HashTrait, hash160::Hash},
PubkeyHash, ScriptHash, PubkeyHash, ScriptHash,
network::Network, network::Network,
WitnessVersion, WitnessProgram, WitnessVersion, WitnessProgram, ScriptBuf,
address::{Error, Payload, NetworkChecked, Address as BAddressGeneric}, address::{AddressType, NetworkChecked, Address as BAddressGeneric},
}; };
type BAddress = BAddressGeneric<NetworkChecked>; type BAddress = BAddressGeneric<NetworkChecked>;
@@ -17,21 +17,22 @@ pub struct Address(BAddress);
impl PartialEq for Address { impl PartialEq for Address {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// Since Serai defines the Bitcoin-address specification as a variant of the payload alone, // Since Serai defines the Bitcoin-address specification as a variant of the script alone,
// define equivalency as the payload alone // define equivalency as the script alone
self.0.payload() == other.0.payload() self.0.script_pubkey() == other.0.script_pubkey()
} }
} }
impl FromStr for Address { impl FromStr for Address {
type Err = Error; type Err = ();
fn from_str(str: &str) -> Result<Address, Error> { fn from_str(str: &str) -> Result<Address, ()> {
Address::new( Address::new(
BAddressGeneric::from_str(str) BAddressGeneric::from_str(str)
.map_err(|_| Error::UnrecognizedScript)? .map_err(|_| ())?
.require_network(Network::Bitcoin)?, .require_network(Network::Bitcoin)
.map_err(|_| ())?,
) )
.ok_or(Error::UnrecognizedScript) .ok_or(())
} }
} }
@@ -54,55 +55,65 @@ enum EncodedAddress {
impl TryFrom<Vec<u8>> for Address { impl TryFrom<Vec<u8>> for Address {
type Error = (); type Error = ();
fn try_from(data: Vec<u8>) -> Result<Address, ()> { fn try_from(data: Vec<u8>) -> Result<Address, ()> {
Ok(Address(BAddress::new( Ok(Address(match EncodedAddress::decode(&mut data.as_ref()).map_err(|_| ())? {
Network::Bitcoin, EncodedAddress::P2PKH(hash) => {
match EncodedAddress::decode(&mut data.as_ref()).map_err(|_| ())? { BAddress::p2pkh(PubkeyHash::from_raw_hash(Hash::from_byte_array(hash)), Network::Bitcoin)
EncodedAddress::P2PKH(hash) => { }
Payload::PubkeyHash(PubkeyHash::from_raw_hash(Hash::from_byte_array(hash))) EncodedAddress::P2SH(hash) => {
} let script_hash = ScriptHash::from_raw_hash(Hash::from_byte_array(hash));
EncodedAddress::P2SH(hash) => { let res =
Payload::ScriptHash(ScriptHash::from_raw_hash(Hash::from_byte_array(hash))) BAddress::from_script(&ScriptBuf::new_p2sh(&script_hash), Network::Bitcoin).unwrap();
} debug_assert_eq!(res.script_hash(), Some(script_hash));
EncodedAddress::P2WPKH(hash) => { res
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V0, hash).unwrap()) }
} EncodedAddress::P2WPKH(hash) => BAddress::from_witness_program(
EncodedAddress::P2WSH(hash) => { WitnessProgram::new(WitnessVersion::V0, &hash).unwrap(),
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V0, hash).unwrap()) Network::Bitcoin,
} ),
EncodedAddress::P2TR(key) => { EncodedAddress::P2WSH(hash) => BAddress::from_witness_program(
Payload::WitnessProgram(WitnessProgram::new(WitnessVersion::V1, key).unwrap()) 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>, ()> { 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( Ok(
(match addr.0.payload() { (match addr.0.address_type() {
Payload::PubkeyHash(hash) => EncodedAddress::P2PKH(*hash.as_raw_hash().as_byte_array()), Some(AddressType::P2pkh) => {
Payload::ScriptHash(hash) => EncodedAddress::P2SH(*hash.as_raw_hash().as_byte_array()), EncodedAddress::P2PKH(*addr.0.pubkey_hash().unwrap().as_raw_hash().as_byte_array())
Payload::WitnessProgram(program) => match program.version() { }
WitnessVersion::V0 => { Some(AddressType::P2sh) => {
let program = program.program(); EncodedAddress::P2SH(*addr.0.script_hash().unwrap().as_raw_hash().as_byte_array())
if program.len() == 20 { }
let mut buf = [0; 20]; Some(AddressType::P2wpkh) => {
buf.copy_from_slice(program.as_ref()); let program = witness_program(addr)?;
EncodedAddress::P2WPKH(buf) let mut buf = [0; 20];
} else if program.len() == 32 { buf.copy_from_slice(program.as_ref());
let mut buf = [0; 32]; EncodedAddress::P2WPKH(buf)
buf.copy_from_slice(program.as_ref()); }
EncodedAddress::P2WSH(buf) Some(AddressType::P2wsh) => {
} else { let program = witness_program(addr)?;
Err(())? let mut buf = [0; 32];
} buf.copy_from_slice(program.as_ref());
} EncodedAddress::P2WSH(buf)
WitnessVersion::V1 => { }
let program_ref: &[u8] = program.program().as_ref(); Some(AddressType::P2tr) => {
EncodedAddress::P2TR(program_ref.try_into().map_err(|_| ())?) let program = witness_program(addr)?;
} let program_ref: &[u8] = program.as_ref();
_ => Err(())?, EncodedAddress::P2TR(program_ref.try_into().map_err(|_| ())?)
}, }
_ => Err(())?, _ => Err(())?,
}) })
.encode(), .encode(),

View File

@@ -57,7 +57,7 @@ async fn mint_and_burn_test() {
}; };
let addr = Address::p2pkh( let addr = Address::p2pkh(
&PublicKey::from_private_key( PublicKey::from_private_key(
SECP256K1, SECP256K1,
&PrivateKey::new(SecretKey::from_slice(&[0x01; 32]).unwrap(), Network::Bitcoin), &PrivateKey::new(SecretKey::from_slice(&[0x01; 32]).unwrap(), Network::Bitcoin),
), ),
@@ -266,14 +266,13 @@ async fn mint_and_burn_test() {
script::{PushBytesBuf, Script, ScriptBuf, Builder}, script::{PushBytesBuf, Script, ScriptBuf, Builder},
absolute::LockTime, absolute::LockTime,
transaction::{Version, Transaction}, transaction::{Version, Transaction},
address::Payload, Sequence, Witness, OutPoint, TxIn, Amount, TxOut, Network, Address,
Sequence, Witness, OutPoint, TxIn, Amount, TxOut, Network,
}; };
let private_key = let private_key =
PrivateKey::new(SecretKey::from_slice(&[0x01; 32]).unwrap(), Network::Bitcoin); PrivateKey::new(SecretKey::from_slice(&[0x01; 32]).unwrap(), Network::Bitcoin);
let public_key = PublicKey::from_private_key(SECP256K1, &private_key); let public_key = PublicKey::from_private_key(SECP256K1, &private_key);
let addr = Payload::p2pkh(&public_key); let addr = Address::p2pkh(public_key, Network::Bitcoin);
// Use the first block's coinbase // Use the first block's coinbase
let rpc = handles[0].bitcoin(&ops).await; let rpc = handles[0].bitcoin(&ops).await;
@@ -284,7 +283,7 @@ async fn mint_and_burn_test() {
version: Version(2), version: Version(2),
lock_time: LockTime::ZERO, lock_time: LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { txid: tx.txid(), vout: 0 }, previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
script_sig: Script::new().into(), script_sig: Script::new().into(),
sequence: Sequence(u32::MAX), sequence: Sequence(u32::MAX),
witness: Witness::default(), witness: Witness::default(),
@@ -292,17 +291,23 @@ async fn mint_and_burn_test() {
output: vec![ output: vec![
TxOut { TxOut {
value: Amount::from_sat(1_100_000_00), value: Amount::from_sat(1_100_000_00),
script_pubkey: Payload::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked( script_pubkey: Address::p2tr_tweaked(
XOnlyPublicKey::from_slice(&bitcoin_key_pair.1[1 ..]).unwrap(), TweakedPublicKey::dangerous_assume_tweaked(
)) XOnlyPublicKey::from_slice(&bitcoin_key_pair.1[1 ..]).unwrap(),
),
Network::Bitcoin,
)
.script_pubkey(), .script_pubkey(),
}, },
TxOut { TxOut {
// change = amount spent - fee // change = amount spent - fee
value: Amount::from_sat(tx.output[0].value.to_sat() - 1_100_000_00 - 1_000_00), value: Amount::from_sat(tx.output[0].value.to_sat() - 1_100_000_00 - 1_000_00),
script_pubkey: Payload::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked( script_pubkey: Address::p2tr_tweaked(
XOnlyPublicKey::from_slice(&public_key.inner.serialize()[1 ..]).unwrap(), TweakedPublicKey::dangerous_assume_tweaked(
)) XOnlyPublicKey::from_slice(&public_key.inner.serialize()[1 ..]).unwrap(),
),
Network::Bitcoin,
)
.script_pubkey(), .script_pubkey(),
}, },
TxOut { TxOut {
@@ -316,12 +321,14 @@ async fn mint_and_burn_test() {
let mut der = SECP256K1 let mut der = SECP256K1
.sign_ecdsa_low_r( .sign_ecdsa_low_r(
&Message::from( &Message::from_digest_slice(
SighashCache::new(&tx) SighashCache::new(&tx)
.legacy_signature_hash(0, &addr.script_pubkey(), EcdsaSighashType::All.to_u32()) .legacy_signature_hash(0, &addr.script_pubkey(), EcdsaSighashType::All.to_u32())
.unwrap() .unwrap()
.to_raw_hash(), .to_raw_hash()
), .as_ref(),
)
.unwrap(),
&private_key.inner, &private_key.inner,
) )
.serialize_der() .serialize_der()
@@ -449,9 +456,9 @@ async fn mint_and_burn_test() {
let bitcoin_addr = { let bitcoin_addr = {
use bitcoin_serai::bitcoin::{network::Network, key::PublicKey, address::Address}; use bitcoin_serai::bitcoin::{network::Network, key::PublicKey, address::Address};
// Uses Network::Bitcoin since it doesn't actually matter, Serai strips it out // Uses Network::Bitcoin since it doesn't actually matter, Serai strips it out
// TODO: Move Serai to Payload from Address // TODO: Move Serai to ScriptBuf from Address
Address::p2pkh( Address::p2pkh(
&loop { loop {
let mut bytes = [0; 33]; let mut bytes = [0; 33];
OsRng.fill_bytes(&mut bytes); OsRng.fill_bytes(&mut bytes);
bytes[0] %= 4; bytes[0] %= 4;

View File

@@ -126,7 +126,7 @@ impl Wallet {
let secret_key = SecretKey::new(&mut rand_core::OsRng); let secret_key = SecretKey::new(&mut rand_core::OsRng);
let private_key = PrivateKey::new(secret_key, Network::Regtest); let private_key = PrivateKey::new(secret_key, Network::Regtest);
let public_key = PublicKey::from_private_key(SECP256K1, &private_key); let public_key = PublicKey::from_private_key(SECP256K1, &private_key);
let main_addr = Address::p2pkh(&public_key, Network::Regtest); let main_addr = Address::p2pkh(public_key, Network::Regtest);
let rpc = Rpc::new(rpc_url).await.expect("couldn't connect to the Bitcoin RPC"); let rpc = Rpc::new(rpc_url).await.expect("couldn't connect to the Bitcoin RPC");
@@ -258,10 +258,10 @@ impl Wallet {
consensus::Encodable, consensus::Encodable,
sighash::{EcdsaSighashType, SighashCache}, sighash::{EcdsaSighashType, SighashCache},
script::{PushBytesBuf, Script, ScriptBuf, Builder}, script::{PushBytesBuf, Script, ScriptBuf, Builder},
address::Payload,
OutPoint, Sequence, Witness, TxIn, Amount, TxOut, OutPoint, Sequence, Witness, TxIn, Amount, TxOut,
absolute::LockTime, absolute::LockTime,
transaction::{Version, Transaction}, transaction::{Version, Transaction},
Network, Address,
}; };
const AMOUNT: u64 = 100000000; const AMOUNT: u64 = 100000000;
@@ -269,7 +269,7 @@ impl Wallet {
version: Version(2), version: Version(2),
lock_time: LockTime::ZERO, lock_time: LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { txid: input_tx.txid(), vout: 0 }, previous_output: OutPoint { txid: input_tx.compute_txid(), vout: 0 },
script_sig: Script::new().into(), script_sig: Script::new().into(),
sequence: Sequence(u32::MAX), sequence: Sequence(u32::MAX),
witness: Witness::default(), witness: Witness::default(),
@@ -281,9 +281,12 @@ impl Wallet {
}, },
TxOut { TxOut {
value: Amount::from_sat(AMOUNT), value: Amount::from_sat(AMOUNT),
script_pubkey: Payload::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked( script_pubkey: Address::p2tr_tweaked(
XOnlyPublicKey::from_slice(&to[1 ..]).unwrap(), TweakedPublicKey::dangerous_assume_tweaked(
)) XOnlyPublicKey::from_slice(&to[1 ..]).unwrap(),
),
Network::Bitcoin,
)
.script_pubkey(), .script_pubkey(),
}, },
], ],
@@ -303,7 +306,7 @@ impl Wallet {
let mut der = SECP256K1 let mut der = SECP256K1
.sign_ecdsa_low_r( .sign_ecdsa_low_r(
&Message::from( &Message::from_digest_slice(
SighashCache::new(&tx) SighashCache::new(&tx)
.legacy_signature_hash( .legacy_signature_hash(
0, 0,
@@ -311,8 +314,10 @@ impl Wallet {
EcdsaSighashType::All.to_u32(), EcdsaSighashType::All.to_u32(),
) )
.unwrap() .unwrap()
.to_raw_hash(), .to_raw_hash()
), .as_ref(),
)
.unwrap(),
&private_key.inner, &private_key.inner,
) )
.serialize_der() .serialize_der()