hal_simplicity/actions/simplicity/pset/
mod.rs1mod create;
5mod extract;
6mod finalize;
7mod run;
8mod update_input;
9
10pub use create::*;
11pub use extract::*;
12pub use finalize::*;
13pub use run::*;
14pub use update_input::*;
15
16use std::sync::Arc;
17
18use elements::hashes::Hash as _;
19use elements::pset::PartiallySignedTransaction;
20use elements::taproot::ControlBlock;
21use elements::Script;
22use serde::Serialize;
23
24use crate::simplicity::jet::elements::{ElementsEnv, ElementsUtxo};
25use crate::simplicity::Cmr;
26
27#[derive(Debug, thiserror::Error)]
28pub enum PsetError {
29 #[error("input index {index} out-of-range for PSET with {total} inputs")]
30 InputIndexOutOfRange {
31 index: usize,
32 total: usize,
33 },
34
35 #[error("failed to parse genesis hash: {0}")]
36 GenesisHashParse(elements::hashes::hex::HexToArrayError),
37
38 #[error("could not find Simplicity leaf in PSET taptree with CMR {cmr})")]
39 MissingSimplicityLeaf {
40 cmr: String,
41 },
42
43 #[error("failed to extract transaction from PSET: {0}")]
44 PsetExtract(elements::pset::Error),
45
46 #[error("witness_utxo field not populated for input {0}")]
47 MissingWitnessUtxo(usize),
48}
49
50#[derive(Serialize)]
51pub struct UpdatedPset {
52 pub pset: String,
53 pub updated_values: Vec<&'static str>,
54}
55
56pub fn execution_environment(
58 pset: &PartiallySignedTransaction,
59 input_idx: usize,
60 cmr: Cmr,
61 genesis_hash: Option<&str>,
62) -> Result<(ElementsEnv<Arc<elements::Transaction>>, ControlBlock, Script), PsetError> {
63 let n_inputs = pset.n_inputs();
64 let input = pset.inputs().get(input_idx).ok_or(PsetError::InputIndexOutOfRange {
65 index: input_idx,
66 total: n_inputs,
67 })?;
68
69 let genesis_hash = match genesis_hash {
71 Some(s) => s.parse().map_err(PsetError::GenesisHashParse)?,
72 None => elements::BlockHash::from_byte_array([
73 0xc1, 0xb1, 0x6a, 0xe2, 0x4f, 0x24, 0x23, 0xae, 0xa2, 0xea, 0x34, 0x55, 0x22, 0x92,
75 0x79, 0x3b, 0x5b, 0x5e, 0x82, 0x99, 0x9a, 0x1e, 0xed, 0x81, 0xd5, 0x6a, 0xee, 0x52,
76 0x8e, 0xda, 0x71, 0xa7,
77 ]),
78 };
79
80 let mut control_block_leaf = None;
83 for (cb, script_ver) in &input.tap_scripts {
84 if script_ver.1 == simplicity::leaf_version() && &script_ver.0[..] == cmr.as_ref() {
85 control_block_leaf = Some((cb.clone(), script_ver.0.clone()));
86 }
87 }
88 let (control_block, tap_leaf) = match control_block_leaf {
89 Some((cb, leaf)) => (cb, leaf),
90 None => {
91 return Err(PsetError::MissingSimplicityLeaf {
92 cmr: cmr.to_string(),
93 });
94 }
95 };
96
97 let tx = pset.extract_tx().map_err(PsetError::PsetExtract)?;
98 let tx = Arc::new(tx);
99
100 let input_utxos = pset
101 .inputs()
102 .iter()
103 .enumerate()
104 .map(|(n, input)| match input.witness_utxo {
105 Some(ref utxo) => Ok(ElementsUtxo {
106 script_pubkey: utxo.script_pubkey.clone(),
107 asset: utxo.asset,
108 value: utxo.value,
109 }),
110 None => Err(PsetError::MissingWitnessUtxo(n)),
111 })
112 .collect::<Result<Vec<_>, _>>()?;
113
114 let tx_env = ElementsEnv::new(
115 tx,
116 input_utxos,
117 input_idx as u32, cmr,
119 control_block.clone(),
120 None, genesis_hash,
122 );
123
124 Ok((tx_env, control_block, tap_leaf))
125}