Skip to content

Commit 97bab62

Browse files
authored
Merge pull request #4 from nickfarrow/tr_descriptor
2 parents c81d9ab + 855aa84 commit 97bab62

File tree

2 files changed

+70
-52
lines changed

2 files changed

+70
-52
lines changed

src/descriptor/mod.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ mod tests {
692692
use bitcoin::blockdata::opcodes::all::{OP_CLTV, OP_CSV};
693693
use bitcoin::blockdata::script::Instruction;
694694
use bitcoin::blockdata::{opcodes, script};
695-
use bitcoin::hashes::hex::FromHex;
695+
use bitcoin::hashes::hex::{FromHex, ToHex};
696696
use bitcoin::hashes::{hash160, sha256};
697697
use bitcoin::util::bip32;
698698
use bitcoin::{self, secp256k1, EcdsaSigHashType, PublicKey};
@@ -1192,6 +1192,18 @@ mod tests {
11921192
)
11931193
}
11941194

1195+
#[test]
1196+
fn tr_script_pubkey() {
1197+
let key = Descriptor::<bitcoin::PublicKey>::from_str(
1198+
"tr(02e20e746af365e86647826397ba1c0e0d5cb685752976fe2f326ab76bdc4d6ee9)",
1199+
)
1200+
.unwrap();
1201+
assert_eq!(
1202+
key.script_pubkey().to_hex(),
1203+
"51209c19294f03757da3dc235a5960631e3c55751632f5889b06b7a053bdc0bcfbcb"
1204+
)
1205+
}
1206+
11951207
#[test]
11961208
fn roundtrip_tests() {
11971209
let descriptor = Descriptor::<bitcoin::PublicKey>::from_str("multi");

src/descriptor/tr.rs

+57-51
Original file line numberDiff line numberDiff line change
@@ -212,57 +212,63 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
212212
{
213213
// If the value is already cache, read it
214214
// read only panics if the lock is poisoned (meaning other thread having a lock panicked)
215-
if let Some(spend_info) = &*self.spend_info.read().expect("Lock poisoned") {
216-
return Arc::clone(spend_info);
217-
} else {
218-
// Get a new secp context
219-
// This would be cheap operation after static context support from upstream
220-
let secp = secp256k1::Secp256k1::verification_only();
221-
// Key spend path with no merkle root
222-
let data = if self.tree.is_none() {
223-
TaprootSpendInfo::new_key_spend(&secp, self.internal_key.to_x_only_pubkey(), None)
224-
} else {
225-
let mut builder = TaprootBuilder::new();
226-
for (depth, ms) in self.iter_scripts() {
227-
let script = ms.encode();
228-
builder = builder
229-
.add_leaf(depth, script)
230-
.expect("Computing spend data on a valid Tree should always succeed");
231-
}
232-
// Assert builder cannot error here because we have a well formed descriptor
233-
match builder.finalize(&secp, self.internal_key.to_x_only_pubkey()) {
234-
Ok(data) => data,
235-
Err(e) => match e {
236-
TaprootBuilderError::InvalidMerkleTreeDepth(_) => {
237-
unreachable!("Depth checked in struct construction")
238-
}
239-
TaprootBuilderError::NodeNotInDfsOrder => {
240-
unreachable!("Insertion is called in DFS order")
241-
}
242-
TaprootBuilderError::OverCompleteTree => {
243-
unreachable!("Taptree is a well formed tree")
244-
}
245-
TaprootBuilderError::InvalidInternalKey(_) => {
246-
unreachable!("Internal key checked for validity")
247-
}
248-
TaprootBuilderError::IncompleteTree => {
249-
unreachable!("Taptree is a well formed tree")
250-
}
251-
TaprootBuilderError::EmptyTree => {
252-
unreachable!("Taptree is a well formed tree with atleast 1 element")
253-
}
254-
},
255-
}
256-
};
257-
*self.spend_info.write().expect("Lock poisoned") = Some(Arc::new(data));
258-
// Fetch the cached value
259-
Arc::clone(
260-
self.spend_info
261-
.read()
262-
.expect("Lock poisoned")
263-
.as_ref() // deref from RwLockReadGuard to Option<TaprootSpendInfo>
264-
.expect("Value cached above, option must be some"),
265-
)
215+
let spend_info = self
216+
.spend_info
217+
.read()
218+
.expect("Lock poisoned")
219+
.as_ref()
220+
.map(Arc::clone);
221+
222+
match spend_info {
223+
Some(spend_info) => spend_info,
224+
None => {
225+
// Get a new secp context
226+
// This would be cheap operation after static context support from upstream
227+
let secp = secp256k1::Secp256k1::verification_only();
228+
// Key spend path with no merkle root
229+
let data = if self.tree.is_none() {
230+
TaprootSpendInfo::new_key_spend(
231+
&secp,
232+
self.internal_key.to_x_only_pubkey(),
233+
None,
234+
)
235+
} else {
236+
let mut builder = TaprootBuilder::new();
237+
for (depth, ms) in self.iter_scripts() {
238+
let script = ms.encode();
239+
builder = builder
240+
.add_leaf(depth, script)
241+
.expect("Computing spend data on a valid Tree should always succeed");
242+
}
243+
// Assert builder cannot error here because we have a well formed descriptor
244+
match builder.finalize(&secp, self.internal_key.to_x_only_pubkey()) {
245+
Ok(data) => data,
246+
Err(e) => match e {
247+
TaprootBuilderError::InvalidMerkleTreeDepth(_) => {
248+
unreachable!("Depth checked in struct construction")
249+
}
250+
TaprootBuilderError::NodeNotInDfsOrder => {
251+
unreachable!("Insertion is called in DFS order")
252+
}
253+
TaprootBuilderError::OverCompleteTree => {
254+
unreachable!("Taptree is a well formed tree")
255+
}
256+
TaprootBuilderError::InvalidInternalKey(_) => {
257+
unreachable!("Internal key checked for validity")
258+
}
259+
TaprootBuilderError::IncompleteTree => {
260+
unreachable!("Taptree is a well formed tree")
261+
}
262+
TaprootBuilderError::EmptyTree => {
263+
unreachable!("Taptree is a well formed tree with atleast 1 element")
264+
}
265+
},
266+
}
267+
};
268+
let spend_info = Arc::new(data);
269+
*self.spend_info.write().expect("Lock poisoned") = Some(Arc::clone(&spend_info));
270+
spend_info
271+
}
266272
}
267273
}
268274
}

0 commit comments

Comments
 (0)