Merge rust-bitcoin/rust-bitcoin#752: Make Map trait private

dfd8924398 Remove insert_pair from Map trait (Tobin Harding)
ad75d5181f Make Map trait private to psbt module (Tobin Harding)
53225c0a6e Improve docs in map module (Tobin Harding)
92059c2841 Add full stops to rustdocs (Tobin Harding)
11c046b707 Refactor match arms (Tobin Harding)
e6af569490 Move imports to top of file (Tobin Harding)

Pull request description:

  The `Map` method `insert_pair` is never called for `PartiallySignedTransaction`. Separate the method into its own trait (`Insert`) and delete dead code. The dead code contains the alleged bug in #576.

  - Patch 1: Preparatory cleanup
  - Patch 2: Preparatory refactor
  - Patch 3 and 4: Improve docs in the module that this PR touches
  - Patch 5: Make `Map` trait private to the `psbt` module
  - ~Patch 6: Make `concensus_decode_global` method into a function~
  - Patch ~7~ 6: Pull `insert_pair` method out of `Map` trait into newly create `Insert` trait

  Resolves: https://github.com/rust-bitcoin/rust-bitcoin/issues/576

  (Title of PR is `Make Map trait private` because that is the API break.)

ACKs for top commit:
  dr-orlovsky:
    ACK dfd8924398
  apoelstra:
    ACK dfd8924398

Tree-SHA512: 1a78294bc8a455552d93caf64db697f886345ba979f574abad55820415958fee1c2dd16945f4eafdbe542fa202cb7e08618aa137ec7ee22b3c9dac5df0328157
This commit is contained in:
sanket1729 2022-01-16 08:14:11 +05:30
commit 093f8b612d
No known key found for this signature in database
GPG Key ID: 648FFB183E0870A2
6 changed files with 65 additions and 75 deletions

View File

@ -75,7 +75,7 @@ macro_rules! impl_psbtmap_consensus_decoding {
loop { loop {
match $crate::consensus::Decodable::consensus_decode(&mut d) { match $crate::consensus::Decodable::consensus_decode(&mut d) {
Ok(pair) => $crate::util::psbt::Map::insert_pair(&mut rv, pair)?, Ok(pair) => rv.insert_pair(pair)?,
Err($crate::consensus::encode::Error::Psbt($crate::util::psbt::Error::NoMorePairs)) => return Ok(rv), Err($crate::consensus::encode::Error::Psbt($crate::util::psbt::Error::NoMorePairs)) => return Ok(rv),
Err(e) => return Err(e), Err(e) => return Err(e),
} }

View File

@ -37,27 +37,6 @@ const PSBT_GLOBAL_VERSION: u8 = 0xFB;
const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC; const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC;
impl Map for PartiallySignedTransaction { impl Map for PartiallySignedTransaction {
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
let raw::Pair {
key: raw_key,
value: raw_value,
} = pair;
match raw_key.type_value {
PSBT_GLOBAL_UNSIGNED_TX => return Err(Error::DuplicateKey(raw_key).into()),
PSBT_GLOBAL_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
}
_ => match self.unknown.entry(raw_key) {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);},
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
}
}
Ok(())
}
fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> { fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> {
let mut rv: Vec<raw::Pair> = Default::default(); let mut rv: Vec<raw::Pair> = Default::default();
@ -278,11 +257,15 @@ impl PartiallySignedTransaction {
} }
} }
PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::from_key(pair.key.clone())?) { PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::from_key(pair.key.clone())?) {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(pair.value);}, btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(pair.value);
},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(pair.key).into()), btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(pair.key).into()),
} }
_ => match unknowns.entry(pair.key) { _ => match unknowns.entry(pair.key) {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(pair.value);}, btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(pair.value);
},
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
} }
} }

View File

@ -108,32 +108,32 @@ pub struct Input {
/// other scripts necessary for this input to pass validation. /// other scripts necessary for this input to pass validation.
pub final_script_witness: Option<Witness>, pub final_script_witness: Option<Witness>,
/// TODO: Proof of reserves commitment /// TODO: Proof of reserves commitment
/// RIPEMD160 hash to preimage map /// RIPEMD160 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>, pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
/// SHA256 hash to preimage map /// SHA256 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>, pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
/// HSAH160 hash to preimage map /// HSAH160 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>, pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
/// HAS256 hash to preimage map /// HAS256 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_byte_values"))]
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>, pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
/// Serialized schnorr signature with sighash type for key spend /// Serialized schnorr signature with sighash type for key spend.
pub tap_key_sig: Option<SchnorrSig>, pub tap_key_sig: Option<SchnorrSig>,
/// Map of <xonlypubkey>|<leafhash> with signature /// Map of <xonlypubkey>|<leafhash> with signature.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), SchnorrSig>, pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), SchnorrSig>,
/// Map of Control blocks to Script version pair /// Map of Control blocks to Script version pair.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>, pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
/// Map of tap root x only keys to origin info and leaf hashes contained in it /// Map of tap root x only keys to origin info and leaf hashes contained in it.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>, pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Taproot Internal key /// Taproot Internal key.
pub tap_internal_key : Option<XOnlyPublicKey>, pub tap_internal_key : Option<XOnlyPublicKey>,
/// Taproot Merkle root /// Taproot Merkle root.
pub tap_merkle_root : Option<TapBranchHash>, pub tap_merkle_root : Option<TapBranchHash>,
/// Proprietary key-value pairs for this input. /// Proprietary key-value pairs for this input.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq_byte_values"))]
@ -189,8 +189,8 @@ impl PsbtSigHashType {
} }
} }
impl Map for Input { impl Input {
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
let raw::Pair { let raw::Pair {
key: raw_key, key: raw_key,
value: raw_value, value: raw_value,
@ -284,23 +284,28 @@ impl Map for Input {
self.tap_merkle_root <= <raw_key: _>|< raw_value: TapBranchHash> self.tap_merkle_root <= <raw_key: _>|< raw_value: TapBranchHash>
} }
} }
PSBT_IN_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) { PSBT_IN_PROPRIETARY => {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, let key = raw::ProprietaryKey::from_key(raw_key.clone())?;
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), match self.proprietary.entry(key) {
btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
}
} }
_ => match self.unknown.entry(raw_key) { _ => match self.unknown.entry(raw_key) {
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value); empty_key.insert(raw_value);
} }
btree_map::Entry::Occupied(k) => { btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
return Err(Error::DuplicateKey(k.key().clone()).into())
}
}, },
} }
Ok(()) Ok(())
} }
}
impl Map for Input {
fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> { fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> {
let mut rv: Vec<raw::Pair> = Default::default(); let mut rv: Vec<raw::Pair> = Default::default();

View File

@ -20,18 +20,22 @@ use consensus::encode;
use util::psbt; use util::psbt;
use util::psbt::raw; use util::psbt::raw;
/// A trait that describes a PSBT key-value map. mod global;
pub trait Map { mod input;
/// Attempt to insert a key-value pair. mod output;
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error>;
pub use self::input::{Input, PsbtSigHashType};
pub use self::output::{Output, TapTree};
/// A trait that describes a PSBT key-value map.
pub(super) trait Map {
/// Attempt to get all key-value pairs. /// Attempt to get all key-value pairs.
fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error>; fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error>;
/// Attempt to merge with another key-value map of the same type. /// Attempt to merge with another key-value map of the same type.
fn merge(&mut self, other: Self) -> Result<(), psbt::Error>; fn merge(&mut self, other: Self) -> Result<(), psbt::Error>;
/// Encodes map data with bitcoin consensus encoding /// Encodes map data with bitcoin consensus encoding.
fn consensus_encode_map<S: io::Write>( fn consensus_encode_map<S: io::Write>(
&self, &self,
mut s: S, mut s: S,
@ -47,12 +51,3 @@ pub trait Map {
Ok(len + encode::Encodable::consensus_encode(&0x00_u8, s)?) Ok(len + encode::Encodable::consensus_encode(&0x00_u8, s)?)
} }
} }
// place at end to pick up macros
mod global;
mod input;
mod output;
pub use self::input::{Input, PsbtSigHashType};
pub use self::output::Output;
pub use self::output::TapTree;

View File

@ -58,11 +58,11 @@ pub struct Output {
/// corresponding master key fingerprints and derivation paths. /// corresponding master key fingerprints and derivation paths.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>, pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
/// The internal pubkey /// The internal pubkey.
pub tap_internal_key: Option<XOnlyPublicKey>, pub tap_internal_key: Option<XOnlyPublicKey>,
/// Taproot Output tree /// Taproot Output tree.
pub tap_tree: Option<TapTree>, pub tap_tree: Option<TapTree>,
/// Map of tap root x only keys to origin info and leaf hashes contained in it /// Map of tap root x only keys to origin info and leaf hashes contained in it.
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>, pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Proprietary key-value pairs for this output. /// Proprietary key-value pairs for this output.
@ -79,7 +79,7 @@ pub struct Output {
pub unknown: BTreeMap<raw::Key, Vec<u8>>, pub unknown: BTreeMap<raw::Key, Vec<u8>>,
} }
/// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree) /// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TapTree(pub(crate) TaprootBuilder); pub struct TapTree(pub(crate) TaprootBuilder);
@ -93,7 +93,7 @@ impl PartialEq for TapTree {
impl Eq for TapTree {} impl Eq for TapTree {}
impl TapTree { impl TapTree {
// get the inner node info as the builder is finalized /// Gets the inner node info as the builder is finalized.
fn node_info(&self) -> &NodeInfo { fn node_info(&self) -> &NodeInfo {
// The builder algorithm invariant guarantees that is_complete builder // The builder algorithm invariant guarantees that is_complete builder
// have only 1 element in branch and that is not None. // have only 1 element in branch and that is not None.
@ -102,8 +102,10 @@ impl TapTree {
self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders") self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders")
} }
/// Convert a [`TaprootBuilder`] into a tree if it is complete binary tree. /// Converts a [`TaprootBuilder`] into a tree if it is complete binary tree.
/// Returns the inner as Err if it is not a complete tree ///
/// # Return
/// A `TapTree` iff the `inner` builder is complete, otherwise return the inner as `Err`.
pub fn from_inner(inner: TaprootBuilder) -> Result<Self, TaprootBuilder> { pub fn from_inner(inner: TaprootBuilder) -> Result<Self, TaprootBuilder> {
if inner.is_complete() { if inner.is_complete() {
Ok(TapTree(inner)) Ok(TapTree(inner))
@ -112,15 +114,14 @@ impl TapTree {
} }
} }
/// Convert self into builder [`TaprootBuilder`]. The builder is guaranteed to /// Converts self into builder [`TaprootBuilder`]. The builder is guaranteed to be finalized.
/// be finalized.
pub fn into_inner(self) -> TaprootBuilder { pub fn into_inner(self) -> TaprootBuilder {
self.0 self.0
} }
} }
impl Map for Output { impl Output {
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
let raw::Pair { let raw::Pair {
key: raw_key, key: raw_key,
value: raw_value, value: raw_value,
@ -142,9 +143,14 @@ impl Map for Output {
self.bip32_derivation <= <raw_key: secp256k1::PublicKey>|<raw_value: KeySource> self.bip32_derivation <= <raw_key: secp256k1::PublicKey>|<raw_value: KeySource>
} }
} }
PSBT_OUT_PROPRIETARY => match self.proprietary.entry(raw::ProprietaryKey::from_key(raw_key.clone())?) { PSBT_OUT_PROPRIETARY => {
btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, let key = raw::ProprietaryKey::from_key(raw_key.clone())?;
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), match self.proprietary.entry(key) {
btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()),
}
} }
PSBT_OUT_TAP_INTERNAL_KEY => { PSBT_OUT_TAP_INTERNAL_KEY => {
impl_psbt_insert_pair! { impl_psbt_insert_pair! {
@ -165,15 +171,15 @@ impl Map for Output {
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value); empty_key.insert(raw_value);
} }
btree_map::Entry::Occupied(k) => { btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()),
return Err(Error::DuplicateKey(k.key().clone()).into()) }
}
},
} }
Ok(()) Ok(())
} }
}
impl Map for Output {
fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> { fn get_pairs(&self) -> Result<Vec<raw::Pair>, io::Error> {
let mut rv: Vec<raw::Pair> = Default::default(); let mut rv: Vec<raw::Pair> = Default::default();

View File

@ -39,7 +39,8 @@ mod macros;
pub mod serialize; pub mod serialize;
mod map; mod map;
pub use self::map::{Map, Input, Output, TapTree}; pub use self::map::{Input, Output, TapTree};
use self::map::Map;
use util::bip32::{ExtendedPubKey, KeySource}; use util::bip32::{ExtendedPubKey, KeySource};