Skip to main content

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
123        let ctrl_blk: [u8; 33] = [
124            0xc0, 0xeb, 0x04, 0xb6, 0x8e, 0x9a, 0x26, 0xd1, 0x16, 0x04, 0x6c, 0x76, 0xe8, 0xff,
125            0x47, 0x33, 0x2f, 0xb7, 0x1d, 0xda, 0x90, 0xff, 0x4b, 0xef, 0x53, 0x70, 0xf2, 0x52,
126            0x26, 0xd3, 0xbc, 0x09, 0xfc,
127        ];
128
129        ElementsEnv::new(
130            std::sync::Arc::new(elements::Transaction {
131                version: 2,
132                lock_time,
133                // Enable locktime in dummy txin
134                input: vec![elements::TxIn {
135                    previous_output: elements::OutPoint::default(),
136                    is_pegin: false,
137                    script_sig: elements::Script::new(),
138                    sequence,
139                    asset_issuance: AssetIssuance::default(),
140                    witness: elements::TxInWitness::default(),
141                }],
142                output: Vec::default(),
143            }),
144            vec![ElementsUtxo {
145                script_pubkey: elements::Script::new(),
146                asset: confidential::Asset::Null,
147                value: confidential::Value::Null,
148            }],
149            0,
150            Cmr::from_byte_array([0; 32]),
151            ControlBlock::from_slice(&ctrl_blk).unwrap(),
152            None,
153            elements::BlockHash::GENESIS_PREVIOUS_BLOCK_HASH,
154        )
155    }
156}