Repository: LNP-BP/client_side_validation (language: rust)

Issue:
Remove PSBT BIP-174 encoding since it is not deterministic
Downstream crates should start using modern PSBT implementation from `psbt`(https://crates.io/crate/psbt) crate, supporting also strict encoding and both v0 and v2 PSBT versions (requires use of `string_encoding` flag in that crate).


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index ed34d214..afbea960 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -879,7 +879,7 @@ dependencies = [
 
 [[package]]
 name = "strict_encoding"
-version = "1.8.0-rc.7"
+version = "1.8.0-rc.9"
 dependencies = [
  "amplify",
  "bitcoin",
diff --git a/strict_encoding/Cargo.toml b/strict_encoding/Cargo.toml
index 036b7166..f86942ae 100644
--- a/strict_encoding/Cargo.toml
+++ b/strict_encoding/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "strict_encoding"
-version = "1.8.0-rc.7"
+version = "1.8.0-rc.9"
 license = "Apache-2.0"
 authors = ["Dr. Maxim Orlovsky <orlovsky@pandoracore.com>"]
 description = "Strict encoding: deterministic binary serialization for networking & client-side validation"
diff --git a/strict_encoding/src/bitcoin.rs b/strict_encoding/src/bitcoin.rs
index 9765c176..24782c81 100644
--- a/strict_encoding/src/bitcoin.rs
+++ b/strict_encoding/src/bitcoin.rs
@@ -15,19 +15,20 @@
 use std::io;
 use std::io::{Read, Write};
 
+use bitcoin::psbt::{self, PsbtSigHashType, TapTree};
 use bitcoin::secp256k1::{ecdsa, schnorr, Secp256k1};
 use bitcoin::util::address::{self, Address, WitnessVersion};
 use bitcoin::util::bip32;
-use bitcoin::util::psbt::PartiallySignedTransaction;
 use bitcoin::util::taproot::{
     ControlBlock, FutureLeafVersion, LeafVersion, TapBranchHash, TapLeafHash,
-    TapSighashHash, TapTweakHash, TaprootMerkleBranch,
+    TapSighashHash, TapTweakHash, TaprootBuilder, TaprootMerkleBranch,
 };
 use bitcoin::{
     schnorr as bip340, secp256k1, Amount, BlockHash, EcdsaSig,
     EcdsaSigHashType, KeyPair, OutPoint, PubkeyHash, SchnorrSig,
     SchnorrSigHashType, Script, ScriptHash, SigHash, Transaction, TxIn, TxOut,
-    Txid, WPubkeyHash, WScriptHash, Wtxid, XOnlyPublicKey, XpubIdentifier,
+    Txid, WPubkeyHash, WScriptHash, Witness, Wtxid, XOnlyPublicKey,
+    XpubIdentifier,
 };
 use bitcoin_hashes::sha256;
 
@@ -292,6 +293,20 @@ impl StrictDecode for schnorr::Signature {
     }
 }
 
+impl StrictEncode for PsbtSigHashType {
+    #[inline]
+    fn strict_encode<E: Write>(&self, e: E) -> Result<usize, Error> {
+        self.to_u32().strict_encode(e)
+    }
+}
+
+impl StrictDecode for PsbtSigHashType {
+    #[inline]
+    fn strict_decode<D: Read>(d: D) -> Result<Self, Error> {
+        u32::strict_decode(d).map(PsbtSigHashType::from_u32)
+    }
+}
+
 impl StrictEncode for EcdsaSigHashType {
     #[inline]
     fn strict_encode<E: Write>(&self, e: E) -> Result<usize, Error> {
@@ -417,6 +432,9 @@ impl StrictDecode for bitcoin::PublicKey {
 impl Strategy for OutPoint {
     type Strategy = strategies::BitcoinConsensus;
 }
+impl Strategy for Witness {
+    type Strategy = strategies::BitcoinConsensus;
+}
 impl Strategy for TxOut {
     type Strategy = strategies::BitcoinConsensus;
 }
@@ -426,9 +444,6 @@ impl Strategy for TxIn {
 impl Strategy for Transaction {
     type Strategy = strategies::BitcoinConsensus;
 }
-impl Strategy for PartiallySignedTransaction {
-    type Strategy = strategies::BitcoinConsensus;
-}
 
 impl StrictEncode for address::Payload {
     fn strict_encode<E: io::Write>(&self, mut e: E) -> Result<usize, Error> {
@@ -657,6 +672,66 @@ impl StrictDecode for bip32::ExtendedPrivKey {
     }
 }
 
+impl StrictEncode for psbt::raw::Key {
+    fn strict_encode<E: Write>(&self, mut e: E) -> Result<usize, Error> {
+        Ok(strict_encode_list!(e; self.type_value, self.key))
+    }
+}
+
+impl StrictDecode for psbt::raw::Key {
+    fn strict_decode<D: Read>(mut d: D) -> Result<Self, Error> {
+        Ok(strict_decode_self!(d; type_value, key; crate))
+    }
+}
+
+impl StrictEncode for psbt::raw::Pair {
+    fn strict_encode<E: Write>(&self, mut e: E) -> Result<usize, Error> {
+        Ok(strict_encode_list!(e; self.key, self.value))
+    }
+}
+
+impl StrictDecode for psbt::raw::Pair {
+    fn strict_decode<D: Read>(mut d: D) -> Result<Self, Error> {
+        Ok(strict_decode_self!(d; key, value; crate))
+    }
+}
+
+impl StrictEncode for psbt::raw::ProprietaryKey {
+    fn strict_encode<E: Write>(&self, mut e: E) -> Result<usize, Error> {
+        Ok(strict_encode_list!(e; self.prefix, self.subtype, self.key))
+    }
+}
+
+impl StrictDecode for psbt::raw::ProprietaryKey {
+    fn strict_decode<D: Read>(mut d: D) -> Result<Self, Error> {
+        Ok(strict_decode_self!(d; prefix, subtype, key; crate))
+    }
+}
+
+impl StrictEncode for TapTree {
+    fn strict_encode<E: Write>(&self, e: E) -> Result<usize, Error> {
+        impl StrictEncode for &Script {
+            fn strict_encode<E: Write>(&self, e: E) -> Result<usize, Error> {
+                Script::strict_encode(self, e)
+            }
+        }
+        self.iter().collect::<Vec<_>>().strict_encode(e)
+    }
+}
+
+impl StrictDecode for TapTree {
+    fn strict_decode<D: Read>(d: D) -> Result<Self, Error> {
+        let builder = Vec::<(u8, Script)>::strict_decode(d)?
+            .into_iter()
+            .try_fold(TaprootBuilder::new(), |builder, (depth, script)| {
+                builder.add_leaf(depth as usize, script)
+            })
+            .map_err(|err| Error::DataIntegrityError(err.to_string()))?;
+        TapTree::from_inner(builder)
+            .map_err(|_| Error::DataIntegrityError(s!("incomplete tree")))
+    }
+}
+
 #[cfg(test)]
 pub(crate) mod test {
     use std::str::FromStr;
@@ -1221,34 +1296,6 @@ pub(crate) mod test {
         test_encoding_roundtrip(&txout_legacy, &txout_legacy_bytes).unwrap();
     }
 
-    #[test]
-    fn test_psbt() {
-        let psbt_bytes = Vec::from_hex(
-            "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566\
-            cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a91\
-            4d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a914\
-            3545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda50101000\
-            00000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f\
-            9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985fffff\
-            fff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b4\
-            0100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff020\
-            0c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac\
-            72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587024\
-            7304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a\
-            5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02\
-            db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e\
-            7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0\
-            c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20\
-            167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4\
-            ea169393380734464f84f2ab300000000000000"
-        ).unwrap();
-
-        let psbt: PartiallySignedTransaction =
-            consensus::deserialize(&psbt_bytes).unwrap();
-
-        test_encoding_roundtrip(&psbt, &psbt_bytes).unwrap();
-    }
-
     #[test]
     fn test_encoding_extendedpubkey() {
         static EXT_PUBKEY1: [u8; 78] = [


Test patch: