From 169d8498567e33b5ccf9ff37788884538914c72d Mon Sep 17 00:00:00 2001
From: Aman Rojjha <aman.rojjha@research.iiit.ac.in>
Date: Wed, 20 Apr 2022 01:13:59 +0530
Subject: [PATCH] Add policy to descriptor target compilation method

---
 src/policy/concrete.rs | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs
index fc79704e3..f2e4853e3 100644
--- a/src/policy/concrete.rs
+++ b/src/policy/concrete.rs
@@ -100,6 +100,21 @@ pub enum PolicyError {
     DuplicatePubKeys,
 }
 
+/// Descriptor context for [`Policy`] compilation into a [`Descriptor`]
+pub enum DescriptorCtx<Pk> {
+    /// [Bare][`Descriptor::Bare`]
+    Bare,
+    /// [Sh][`Descriptor::Sh`]
+    Sh,
+    /// [Wsh][`Descriptor::Wsh`]
+    Wsh,
+    /// Sh-wrapped [Wsh][`Descriptor::Wsh`]
+    ShWsh,
+    /// [Tr][`Descriptor::Tr`] where the Option<Pk> corresponds to the internal_key if no internal
+    /// key can be inferred from the given policy
+    Tr(Option<Pk>),
+}
+
 impl fmt::Display for PolicyError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
@@ -289,6 +304,31 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
         }
     }
 
+    /// Compile the [`Policy`] into desc_ctx [`Descriptor`]
+    ///
+    /// In case of [Tr][`DescriptorCtx::Tr`], `internal_key` is used for the Taproot comilation when
+    /// no public key can be inferred from the given policy
+    #[cfg(feature = "compiler")]
+    pub fn compile_to_descriptor<Ctx: ScriptContext>(
+        &self,
+        desc_ctx: DescriptorCtx<Pk>,
+    ) -> Result<Descriptor<Pk>, Error> {
+        self.is_valid()?;
+        match self.is_safe_nonmalleable() {
+            (false, _) => Err(Error::from(CompilerError::TopLevelNonSafe)),
+            (_, false) => Err(Error::from(
+                CompilerError::ImpossibleNonMalleableCompilation,
+            )),
+            _ => match desc_ctx {
+                DescriptorCtx::Bare => Descriptor::new_bare(compiler::best_compilation(self)?),
+                DescriptorCtx::Sh => Descriptor::new_sh(compiler::best_compilation(self)?),
+                DescriptorCtx::Wsh => Descriptor::new_wsh(compiler::best_compilation(self)?),
+                DescriptorCtx::ShWsh => Descriptor::new_sh_wsh(compiler::best_compilation(self)?),
+                DescriptorCtx::Tr(unspendable_key) => self.compile_tr(unspendable_key),
+            },
+        }
+    }
+
     /// Compile the descriptor into an optimized `Miniscript` representation
     #[cfg(feature = "compiler")]
     pub fn compile<Ctx: ScriptContext>(&self) -> Result<Miniscript<Pk, Ctx>, CompilerError> {