elements_miniscript/descriptor/csfs_cov/
satisfy.rs

1// Miniscript
2// Written in 2021 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//     Sanket Kanjalkar <sanket1729@gmail.com>
5//
6// To the extent possible under law, the author(s) have dedicated all
7// copyright and related and neighboring rights to this software to
8// the public domain worldwide. This software is distributed without
9// any warranty.
10//
11// You should have received a copy of the CC0 Public Domain Dedication
12// along with this software.
13// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
14//
15//! Covenant Descriptor Satisfaction
16
17use elements::encode::Encodable;
18use elements::hashes::{sha256d, Hash};
19use elements::sighash::SighashCache;
20use elements::{self, confidential, EcdsaSighashType, OutPoint, Script, Sighash, Transaction};
21
22use super::CovError;
23use crate::{MiniscriptKey, Satisfier, ToPublicKey};
24
25/// A satisfier for Covenant descriptors
26/// that can do transaction introspection
27/// 'tx denotes the lifetime of the transaction
28/// being satisfied and 'ptx denotes the lifetime
29/// of the previous transaction inputs
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct LegacyCovSatisfier<'tx, 'ptx> {
32    // Common fields in Segwit and Taphash
33    /// The transaction being spent
34    tx: &'tx Transaction,
35    /// The script code required for
36    /// The input index being spent
37    idx: u32,
38    /// The sighash type
39    hash_type: EcdsaSighashType,
40
41    // Segwitv0
42    /// The script code required for segwit sighash
43    script_code: Option<&'ptx Script>,
44    /// The value of the output being spent
45    value: Option<confidential::Value>,
46}
47
48impl<'tx, 'ptx> LegacyCovSatisfier<'tx, 'ptx> {
49    /// Create  a new Covsatisfier for v0 spends
50    /// Panics if idx is out of bounds
51    pub fn new_segwitv0(
52        tx: &'tx Transaction,
53        idx: u32,
54        value: confidential::Value,
55        script_code: &'ptx Script,
56        hash_type: EcdsaSighashType,
57    ) -> Self {
58        assert!((idx as usize) < tx.input.len());
59        Self {
60            tx,
61            idx,
62            hash_type,
63            script_code: Some(script_code),
64            value: Some(value),
65        }
66    }
67
68    /// Easy way to get sighash since we already have
69    /// all the required information.
70    /// Note that this does not do any caching, so it
71    /// will be slightly inefficient as compared to
72    /// using sighash
73    pub fn segwit_sighash(&self) -> Result<Sighash, CovError> {
74        let mut cache = SighashCache::new(self.tx);
75        // TODO: error types
76        let script_code = self.script_code.ok_or(CovError::MissingScriptCode)?;
77        let value = self.value.ok_or(CovError::MissingValue)?;
78        Ok(cache.segwitv0_sighash(self.idx as usize, script_code, value, self.hash_type))
79    }
80}
81
82impl<'tx, 'ptx, Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for LegacyCovSatisfier<'tx, 'ptx> {
83    fn lookup_nversion(&self) -> Option<u32> {
84        Some(self.tx.version)
85    }
86
87    fn lookup_hashprevouts(&self) -> Option<sha256d::Hash> {
88        let mut enc = sha256d::Hash::engine();
89        for txin in &self.tx.input {
90            txin.previous_output.consensus_encode(&mut enc).unwrap();
91        }
92        Some(sha256d::Hash::from_engine(enc))
93    }
94
95    fn lookup_hashsequence(&self) -> Option<sha256d::Hash> {
96        let mut enc = sha256d::Hash::engine();
97        for txin in &self.tx.input {
98            txin.sequence.consensus_encode(&mut enc).unwrap();
99        }
100        Some(sha256d::Hash::from_engine(enc))
101    }
102
103    fn lookup_hashissuances(&self) -> Option<sha256d::Hash> {
104        let mut enc = sha256d::Hash::engine();
105        for txin in &self.tx.input {
106            if txin.has_issuance() {
107                txin.asset_issuance.consensus_encode(&mut enc).unwrap();
108            } else {
109                0u8.consensus_encode(&mut enc).unwrap();
110            }
111        }
112        Some(sha256d::Hash::from_engine(enc))
113    }
114
115    fn lookup_outpoint(&self) -> Option<OutPoint> {
116        Some(self.tx.input[self.idx as usize].previous_output)
117    }
118
119    fn lookup_scriptcode(&self) -> Option<&Script> {
120        self.script_code
121    }
122
123    fn lookup_value(&self) -> Option<confidential::Value> {
124        self.value
125    }
126
127    fn lookup_nsequence(&self) -> Option<u32> {
128        Some(self.tx.input[self.idx as usize].sequence.to_consensus_u32())
129    }
130
131    fn lookup_outputs(&self) -> Option<&[elements::TxOut]> {
132        Some(&self.tx.output)
133    }
134
135    fn lookup_nlocktime(&self) -> Option<u32> {
136        Some(self.tx.lock_time.to_consensus_u32())
137    }
138
139    fn lookup_sighashu32(&self) -> Option<u32> {
140        Some(self.hash_type.as_u32())
141    }
142}