simplicity/jet/elements/
environment.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use crate::merkle::cmr::Cmr;
4use elements::confidential;
5use elements::taproot::ControlBlock;
6use simplicity_sys::c_jets::c_env::elements as c_elements;
7use std::ops::Deref;
8
9use super::c_env;
10
11/// An Elements UTXO
12// This is not a complete TxOut as it does not contain the nonce that
13// is sent to the recipient.
14#[derive(Debug, Clone, Eq, PartialEq)]
15pub struct ElementsUtxo {
16    /// The 'scriptpubkey' (hash of Simplicity program)
17    pub script_pubkey: elements::Script,
18    /// The explicit or confidential asset
19    pub asset: confidential::Asset,
20    /// The explict or confidential value
21    pub value: confidential::Value,
22}
23
24impl From<elements::TxOut> for ElementsUtxo {
25    fn from(txout: elements::TxOut) -> Self {
26        ElementsUtxo {
27            script_pubkey: txout.script_pubkey,
28            asset: txout.asset,
29            value: txout.value,
30        }
31    }
32}
33
34/// Environment for Elements Simplicity
35///
36/// # Note
37/// The order of `utxos` must be same as of the order of inputs in the
38/// transaction.
39#[derive(Debug)]
40pub struct ElementsEnv<T: Deref<Target = elements::Transaction>> {
41    /// The CTxEnv struct
42    c_tx_env: c_elements::CTxEnv,
43    /// The elements transaction
44    tx: T,
45    /// the current index of the input
46    ix: u32,
47    /// Control block used to spend this leaf script
48    control_block: ControlBlock,
49    /// Optional Annex.
50    annex: Option<Vec<u8>>,
51    /// Genesis block hash
52    genesis_hash: elements::BlockHash,
53}
54
55impl<T> ElementsEnv<T>
56where
57    T: Deref<Target = elements::Transaction>,
58{
59    pub fn new(
60        tx: T,
61        utxos: Vec<ElementsUtxo>,
62        ix: u32,
63        script_cmr: Cmr,
64        control_block: ControlBlock,
65        annex: Option<Vec<u8>>,
66        genesis_hash: elements::BlockHash,
67    ) -> Self {
68        let c_tx = c_env::new_tx(&tx, &utxos);
69        let c_tap_env = c_env::new_tap_env(&control_block, script_cmr);
70        let c_tx_env = c_env::new_tx_env(c_tx, c_tap_env, genesis_hash, ix);
71        ElementsEnv {
72            c_tx_env,
73            tx,
74            ix,
75            control_block,
76            annex,
77            genesis_hash,
78        }
79    }
80
81    /// Obtains the FFI compatible CTxEnv from self
82    pub fn c_tx_env(&self) -> &c_elements::CTxEnv {
83        &self.c_tx_env
84    }
85
86    /// Returns the transaction of this environment
87    pub fn tx(&self) -> &elements::Transaction {
88        &self.tx
89    }
90
91    /// Returns the input index of this environment
92    pub fn ix(&self) -> u32 {
93        self.ix
94    }
95
96    /// Returns a reference to the control block of this [`ElementsEnv`].
97    pub fn control_block(&self) -> &ControlBlock {
98        &self.control_block
99    }
100
101    /// Returns the annex of this [`ElementsEnv`].
102    pub fn annex(&self) -> Option<&Vec<u8>> {
103        self.annex.as_ref()
104    }
105
106    /// Returns the genesis hash of this [`ElementsEnv`].
107    pub fn genesis_hash(&self) -> elements::BlockHash {
108        self.genesis_hash
109    }
110}
111
112#[cfg(test)]
113impl ElementsEnv<std::sync::Arc<elements::Transaction>> {
114    /// Return a dummy Elements environment
115    pub fn dummy() -> Self {
116        Self::dummy_with(elements::LockTime::ZERO, elements::Sequence::MAX)
117    }
118
119    /// Return a dummy Elements environment with given locktime
120    pub fn dummy_with(lock_time: elements::LockTime, sequence: elements::Sequence) -> Self {
121        use elements::AssetIssuance;
122        use hashes::Hash;
123
124        let ctrl_blk: [u8; 33] = [
125            0xc0, 0xeb, 0x04, 0xb6, 0x8e, 0x9a, 0x26, 0xd1, 0x16, 0x04, 0x6c, 0x76, 0xe8, 0xff,
126            0x47, 0x33, 0x2f, 0xb7, 0x1d, 0xda, 0x90, 0xff, 0x4b, 0xef, 0x53, 0x70, 0xf2, 0x52,
127            0x26, 0xd3, 0xbc, 0x09, 0xfc,
128        ];
129
130        ElementsEnv::new(
131            std::sync::Arc::new(elements::Transaction {
132                version: 2,
133                lock_time,
134                // Enable locktime in dummy txin
135                input: vec![elements::TxIn {
136                    previous_output: elements::OutPoint::default(),
137                    is_pegin: false,
138                    script_sig: elements::Script::new(),
139                    sequence,
140                    asset_issuance: AssetIssuance::default(),
141                    witness: elements::TxInWitness::default(),
142                }],
143                output: Vec::default(),
144            }),
145            vec![ElementsUtxo {
146                script_pubkey: elements::Script::new(),
147                asset: confidential::Asset::Null,
148                value: confidential::Value::Null,
149            }],
150            0,
151            Cmr::from_byte_array([0; 32]),
152            ControlBlock::from_slice(&ctrl_blk).unwrap(),
153            None,
154            elements::BlockHash::all_zeros(),
155        )
156    }
157}