1use chia_bls::PublicKey;
2use chia_protocol::{Bytes, Bytes32};
3use chia_streamable_macro::Streamable;
4use clvmr::{Allocator, NodePtr};
5
6use super::conditions::{SpendBundleConditions, SpendConditions};
7
8#[cfg(feature = "py-bindings")]
9use chia_py_streamable_macro::{PyJsonDict, PyStreamable};
10
11#[cfg(feature = "py-bindings")]
12use pyo3::exceptions::PyNotImplementedError;
13#[cfg(feature = "py-bindings")]
14use pyo3::prelude::*;
15#[cfg(feature = "py-bindings")]
16use pyo3::types::PyType;
17
18#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq)]
19#[cfg_attr(
20 feature = "py-bindings",
21 pyo3::pyclass(name = "SpendConditions", get_all, frozen),
22 derive(PyJsonDict, PyStreamable)
23)]
24pub struct OwnedSpendConditions {
25 pub coin_id: Bytes32,
26 pub parent_id: Bytes32,
27 pub puzzle_hash: Bytes32,
28 pub coin_amount: u64,
29 pub height_relative: Option<u32>,
30 pub seconds_relative: Option<u64>,
31 pub before_height_relative: Option<u32>,
32 pub before_seconds_relative: Option<u64>,
33 pub birth_height: Option<u32>,
34 pub birth_seconds: Option<u64>,
35 pub create_coin: Vec<(Bytes32, u64, Option<Bytes>)>,
36 pub agg_sig_me: Vec<(PublicKey, Bytes)>,
37 pub agg_sig_parent: Vec<(PublicKey, Bytes)>,
38 pub agg_sig_puzzle: Vec<(PublicKey, Bytes)>,
39 pub agg_sig_amount: Vec<(PublicKey, Bytes)>,
40 pub agg_sig_puzzle_amount: Vec<(PublicKey, Bytes)>,
41 pub agg_sig_parent_amount: Vec<(PublicKey, Bytes)>,
42 pub agg_sig_parent_puzzle: Vec<(PublicKey, Bytes)>,
43 pub flags: u32,
44}
45
46#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq)]
47#[cfg_attr(
48 feature = "py-bindings",
49 pyo3::pyclass(name = "SpendBundleConditions", get_all, frozen),
50 derive(PyJsonDict, PyStreamable)
51)]
52pub struct OwnedSpendBundleConditions {
53 pub spends: Vec<OwnedSpendConditions>,
54 pub reserve_fee: u64,
55 pub height_absolute: u32,
57 pub seconds_absolute: u64,
58 pub before_height_absolute: Option<u32>,
61 pub before_seconds_absolute: Option<u64>,
63 pub agg_sig_unsafe: Vec<(PublicKey, Bytes)>,
65 pub cost: u64,
66 pub removal_amount: u128,
68 pub addition_amount: u128,
70 pub validated_signature: bool,
73 pub execution_cost: u64,
74 pub condition_cost: u64,
75}
76
77impl OwnedSpendConditions {
78 pub fn from(a: &Allocator, spend: SpendConditions) -> Self {
79 let mut create_coin =
80 Vec::<(Bytes32, u64, Option<Bytes>)>::with_capacity(spend.create_coin.len());
81 for c in spend.create_coin {
82 create_coin.push((
83 c.puzzle_hash,
84 c.amount,
85 if c.hint == a.nil() {
86 None
87 } else {
88 Some(a.atom(c.hint).as_ref().into())
89 },
90 ));
91 }
92
93 Self {
94 coin_id: *spend.coin_id,
95 parent_id: a
96 .atom(spend.parent_id)
97 .as_ref()
98 .try_into()
99 .expect("OwnedSpend internal error (parent_id)"),
100 puzzle_hash: a
101 .atom(spend.puzzle_hash)
102 .as_ref()
103 .try_into()
104 .expect("OwnedSpend internal error (puzzle_hash)"),
105 coin_amount: spend.coin_amount,
106 height_relative: spend.height_relative,
107 seconds_relative: spend.seconds_relative,
108 before_height_relative: spend.before_height_relative,
109 before_seconds_relative: spend.before_seconds_relative,
110 birth_height: spend.birth_height,
111 birth_seconds: spend.birth_seconds,
112 create_coin,
113 agg_sig_me: convert_agg_sigs(a, &spend.agg_sig_me),
114 agg_sig_parent: convert_agg_sigs(a, &spend.agg_sig_parent),
115 agg_sig_puzzle: convert_agg_sigs(a, &spend.agg_sig_puzzle),
116 agg_sig_amount: convert_agg_sigs(a, &spend.agg_sig_amount),
117 agg_sig_puzzle_amount: convert_agg_sigs(a, &spend.agg_sig_puzzle_amount),
118 agg_sig_parent_amount: convert_agg_sigs(a, &spend.agg_sig_parent_amount),
119 agg_sig_parent_puzzle: convert_agg_sigs(a, &spend.agg_sig_parent_puzzle),
120 flags: spend.flags,
121 }
122 }
123}
124
125impl OwnedSpendBundleConditions {
126 pub fn from(a: &Allocator, sb: SpendBundleConditions) -> Self {
127 let mut spends = Vec::<OwnedSpendConditions>::new();
128 for s in sb.spends {
129 spends.push(OwnedSpendConditions::from(a, s));
130 }
131
132 let mut agg_sigs = Vec::<(PublicKey, Bytes)>::with_capacity(sb.agg_sig_unsafe.len());
133 for (pk, msg) in sb.agg_sig_unsafe {
134 agg_sigs.push((pk, a.atom(msg).as_ref().into()));
135 }
136
137 Self {
138 spends,
139 reserve_fee: sb.reserve_fee,
140 height_absolute: sb.height_absolute,
141 seconds_absolute: sb.seconds_absolute,
142 before_height_absolute: sb.before_height_absolute,
143 before_seconds_absolute: sb.before_seconds_absolute,
144 agg_sig_unsafe: agg_sigs,
145 cost: sb.cost,
146 removal_amount: sb.removal_amount,
147 addition_amount: sb.addition_amount,
148 validated_signature: sb.validated_signature,
149 execution_cost: sb.execution_cost,
150 condition_cost: sb.condition_cost,
151 }
152 }
153}
154
155fn convert_agg_sigs(a: &Allocator, agg_sigs: &[(PublicKey, NodePtr)]) -> Vec<(PublicKey, Bytes)> {
156 let mut ret = Vec::<(PublicKey, Bytes)>::new();
157 for (pk, msg) in agg_sigs {
158 ret.push((*pk, a.atom(*msg).as_ref().into()));
159 }
160 ret
161}
162
163#[cfg(feature = "py-bindings")]
164#[pymethods]
165impl OwnedSpendConditions {
166 #[classmethod]
167 #[pyo3(name = "from_parent")]
168 pub fn from_parent(_cls: &Bound<'_, PyType>, _instance: &Self) -> PyResult<PyObject> {
169 Err(PyNotImplementedError::new_err(
170 "OwnedSpendConditions does not support from_parent().",
171 ))
172 }
173}
174
175#[cfg(feature = "py-bindings")]
176#[pymethods]
177impl OwnedSpendBundleConditions {
178 #[classmethod]
179 #[pyo3(name = "from_parent")]
180 pub fn from_parent(_cls: &Bound<'_, PyType>, _instance: &Self) -> PyResult<PyObject> {
181 Err(PyNotImplementedError::new_err(
182 "OwnedSpendBundleConditions does not support from_parent().",
183 ))
184 }
185}