chia_consensus/
owned_conditions.rs

1use crate::conditions::ELIGIBLE_FOR_DEDUP;
2use chia_bls::PublicKey;
3use chia_protocol::{Bytes, Bytes32};
4use chia_streamable_macro::Streamable;
5use clvmr::{Allocator, NodePtr};
6
7use super::conditions::{SpendBundleConditions, SpendConditions};
8
9#[cfg(feature = "py-bindings")]
10use chia_py_streamable_macro::{PyJsonDict, PyStreamable};
11
12#[cfg(feature = "py-bindings")]
13use pyo3::exceptions::PyNotImplementedError;
14#[cfg(feature = "py-bindings")]
15use pyo3::prelude::*;
16#[cfg(feature = "py-bindings")]
17use pyo3::types::PyType;
18
19#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq, Default)]
20#[cfg_attr(
21    feature = "py-bindings",
22    pyo3::pyclass(name = "SpendConditions", get_all, frozen),
23    derive(PyJsonDict, PyStreamable)
24)]
25pub struct OwnedSpendConditions {
26    pub coin_id: Bytes32,
27    pub parent_id: Bytes32,
28    pub puzzle_hash: Bytes32,
29    pub coin_amount: u64,
30    pub height_relative: Option<u32>,
31    pub seconds_relative: Option<u64>,
32    pub before_height_relative: Option<u32>,
33    pub before_seconds_relative: Option<u64>,
34    pub birth_height: Option<u32>,
35    pub birth_seconds: Option<u64>,
36    pub create_coin: Vec<(Bytes32, u64, Option<Bytes>)>,
37    pub agg_sig_me: Vec<(PublicKey, Bytes)>,
38    pub agg_sig_parent: Vec<(PublicKey, Bytes)>,
39    pub agg_sig_puzzle: Vec<(PublicKey, Bytes)>,
40    pub agg_sig_amount: Vec<(PublicKey, Bytes)>,
41    pub agg_sig_puzzle_amount: Vec<(PublicKey, Bytes)>,
42    pub agg_sig_parent_amount: Vec<(PublicKey, Bytes)>,
43    pub agg_sig_parent_puzzle: Vec<(PublicKey, Bytes)>,
44    pub flags: u32,
45    /// per-spend execution and condition cost
46    pub execution_cost: u64,
47    pub condition_cost: u64,
48    pub fingerprint: Bytes,
49}
50
51#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq, Default)]
52#[cfg_attr(
53    feature = "py-bindings",
54    pyo3::pyclass(name = "SpendBundleConditions", get_all, frozen),
55    derive(PyJsonDict, PyStreamable)
56)]
57pub struct OwnedSpendBundleConditions {
58    pub spends: Vec<OwnedSpendConditions>,
59    pub reserve_fee: u64,
60    /// the highest height/time conditions (i.e. most strict)
61    pub height_absolute: u32,
62    pub seconds_absolute: u64,
63    /// when set, this is the lowest (i.e. most restrictive) of all
64    /// ASSERT_BEFORE_HEIGHT_ABSOLUTE conditions
65    pub before_height_absolute: Option<u32>,
66    /// ASSERT_BEFORE_SECONDS_ABSOLUTE conditions
67    pub before_seconds_absolute: Option<u64>,
68    /// Unsafe Agg Sig conditions (i.e. not tied to the spend generating it)
69    pub agg_sig_unsafe: Vec<(PublicKey, Bytes)>,
70    pub cost: u64,
71    /// the sum of all values of all spent coins
72    pub removal_amount: u128,
73    /// the sum of all amounts of CREATE_COIN conditions
74    pub addition_amount: u128,
75    /// set if the aggregate signature of the block/spend bundle was
76    /// successfully validated
77    pub validated_signature: bool,
78    pub execution_cost: u64,
79    pub condition_cost: u64,
80    /// the number of atoms and pairs allocated by the spend bundle
81    pub num_atoms: u32,
82    pub num_pairs: u32,
83    pub heap_size: u32,
84}
85
86impl OwnedSpendConditions {
87    pub fn from(a: &Allocator, spend: SpendConditions) -> Self {
88        let mut create_coin =
89            Vec::<(Bytes32, u64, Option<Bytes>)>::with_capacity(spend.create_coin.len());
90        for c in spend.create_coin {
91            create_coin.push((
92                c.puzzle_hash,
93                c.amount,
94                if c.hint == a.nil() {
95                    None
96                } else {
97                    Some(a.atom(c.hint).as_ref().into())
98                },
99            ));
100        }
101
102        let fingerprint = if (spend.flags & ELIGIBLE_FOR_DEDUP) != 0 {
103            Bytes::from(spend.fingerprint.to_vec())
104        } else {
105            Bytes::default()
106        };
107
108        Self {
109            coin_id: *spend.coin_id,
110            parent_id: a
111                .atom(spend.parent_id)
112                .as_ref()
113                .try_into()
114                .expect("OwnedSpend internal error (parent_id)"),
115            puzzle_hash: a
116                .atom(spend.puzzle_hash)
117                .as_ref()
118                .try_into()
119                .expect("OwnedSpend internal error (puzzle_hash)"),
120            coin_amount: spend.coin_amount,
121            height_relative: spend.height_relative,
122            seconds_relative: spend.seconds_relative,
123            before_height_relative: spend.before_height_relative,
124            before_seconds_relative: spend.before_seconds_relative,
125            birth_height: spend.birth_height,
126            birth_seconds: spend.birth_seconds,
127            create_coin,
128            agg_sig_me: convert_agg_sigs(a, &spend.agg_sig_me),
129            agg_sig_parent: convert_agg_sigs(a, &spend.agg_sig_parent),
130            agg_sig_puzzle: convert_agg_sigs(a, &spend.agg_sig_puzzle),
131            agg_sig_amount: convert_agg_sigs(a, &spend.agg_sig_amount),
132            agg_sig_puzzle_amount: convert_agg_sigs(a, &spend.agg_sig_puzzle_amount),
133            agg_sig_parent_amount: convert_agg_sigs(a, &spend.agg_sig_parent_amount),
134            agg_sig_parent_puzzle: convert_agg_sigs(a, &spend.agg_sig_parent_puzzle),
135            flags: spend.flags,
136            execution_cost: spend.execution_cost,
137            condition_cost: spend.condition_cost,
138            fingerprint,
139        }
140    }
141}
142
143impl OwnedSpendBundleConditions {
144    pub fn from(a: &Allocator, sb: SpendBundleConditions) -> Self {
145        let mut spends = Vec::<OwnedSpendConditions>::new();
146        for s in sb.spends {
147            spends.push(OwnedSpendConditions::from(a, s));
148        }
149
150        let mut agg_sigs = Vec::<(PublicKey, Bytes)>::with_capacity(sb.agg_sig_unsafe.len());
151        for (pk, msg) in sb.agg_sig_unsafe {
152            agg_sigs.push((pk, a.atom(msg).as_ref().into()));
153        }
154
155        Self {
156            spends,
157            reserve_fee: sb.reserve_fee,
158            height_absolute: sb.height_absolute,
159            seconds_absolute: sb.seconds_absolute,
160            before_height_absolute: sb.before_height_absolute,
161            before_seconds_absolute: sb.before_seconds_absolute,
162            agg_sig_unsafe: agg_sigs,
163            cost: sb.cost,
164            removal_amount: sb.removal_amount,
165            addition_amount: sb.addition_amount,
166            validated_signature: sb.validated_signature,
167            execution_cost: sb.execution_cost,
168            condition_cost: sb.condition_cost,
169            num_atoms: (a.atom_count() + a.small_atom_count()) as u32,
170            num_pairs: a.pair_count() as u32,
171            heap_size: a.heap_size() as u32,
172        }
173    }
174}
175
176fn convert_agg_sigs(a: &Allocator, agg_sigs: &[(PublicKey, NodePtr)]) -> Vec<(PublicKey, Bytes)> {
177    let mut ret = Vec::<(PublicKey, Bytes)>::new();
178    for (pk, msg) in agg_sigs {
179        ret.push((*pk, a.atom(*msg).as_ref().into()));
180    }
181    ret
182}
183
184#[cfg(feature = "py-bindings")]
185#[pymethods]
186impl OwnedSpendConditions {
187    #[classmethod]
188    #[pyo3(name = "from_parent")]
189    pub fn from_parent(_cls: &Bound<'_, PyType>, _instance: &Self) -> PyResult<Py<PyAny>> {
190        Err(PyNotImplementedError::new_err(
191            "OwnedSpendConditions does not support from_parent().",
192        ))
193    }
194}
195
196#[cfg(feature = "py-bindings")]
197#[pymethods]
198impl OwnedSpendBundleConditions {
199    #[classmethod]
200    #[pyo3(name = "from_parent")]
201    pub fn from_parent(_cls: &Bound<'_, PyType>, _instance: &Self) -> PyResult<Py<PyAny>> {
202        Err(PyNotImplementedError::new_err(
203            "OwnedSpendBundleConditions does not support from_parent().",
204        ))
205    }
206}