use crate::blockchain::coin::Coin;
use crate::blockchain::condition_opcode::{ConditionCost, ConditionOpcode};
use crate::blockchain::sized_bytes::{Bytes32, SizedBytes};
use crate::blockchain::utils::{additions_for_solution, fee_for_solution};
use crate::clvm::program::{Program, SerializedProgram};
use crate::clvm::utils::INFINITE_COST;
use dg_xch_macros::ChiaSerial;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};
use std::io::{Error, ErrorKind};
#[derive(ChiaSerial, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct CoinSpend {
pub coin: Coin,
pub puzzle_reveal: SerializedProgram,
pub solution: SerializedProgram,
}
impl CoinSpend {
pub fn additions(&self) -> Result<Vec<Coin>, Error> {
additions_for_solution(
self.coin.name(),
&self.puzzle_reveal,
&self.solution,
INFINITE_COST,
)
}
pub fn reserved_fee(self) -> BigInt {
fee_for_solution(&self.puzzle_reveal, &self.solution, INFINITE_COST)
}
}
pub fn compute_additions_with_cost(
cs: &CoinSpend,
max_cost: u64,
) -> Result<(Vec<Coin>, u64), Error> {
let parent_coin_info = cs.coin.name();
let mut ret: Vec<Coin> = vec![];
let (mut cost, r) = cs
.puzzle_reveal
.run_with_cost(max_cost, &cs.solution.to_program())?;
for cond in Program::to(r).as_list() {
if cost > max_cost {
return Err(Error::new(
ErrorKind::Other,
"BLOCK_COST_EXCEEDS_MAX compute_additions() for CoinSpend",
));
} else {
let atoms = cond.as_list();
if atoms.is_empty() {
return Err(Error::new(ErrorKind::Other, "Atoms List is Empty"));
}
let op = &atoms[0];
if [ConditionOpcode::AggSigMe, ConditionOpcode::AggSigUnsafe].contains(&op.into()) {
cost += ConditionCost::AggSig as u64;
continue;
}
if ConditionOpcode::from(op) != ConditionOpcode::CreateCoin {
continue;
}
cost += ConditionCost::CreateCoin as u64;
if atoms.len() < 3 {
return Err(Error::new(
ErrorKind::Other,
"Invalid Number ot Atoms in Program",
));
}
let puzzle_hash = Bytes32::new(&atoms[1].as_vec().unwrap_or_default());
let amount = atoms[2].as_int()?;
ret.push(Coin {
parent_coin_info,
puzzle_hash,
amount: amount
.to_u64()
.expect("Expected a positive amount when computing additions"),
});
}
}
Ok((ret, cost))
}