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 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 pub height_absolute: u32,
62 pub seconds_absolute: u64,
63 pub before_height_absolute: Option<u32>,
66 pub before_seconds_absolute: Option<u64>,
68 pub agg_sig_unsafe: Vec<(PublicKey, Bytes)>,
70 pub cost: u64,
71 pub removal_amount: u128,
73 pub addition_amount: u128,
75 pub validated_signature: bool,
78 pub execution_cost: u64,
79 pub condition_cost: u64,
80 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}