dig_clvm/consensus/
block.rs1use chia_bls::{BlsCache, Signature};
8use chia_consensus::allocator::make_allocator;
9use chia_consensus::flags::DONT_VALIDATE_SIGNATURE;
10use chia_consensus::owned_conditions::OwnedSpendBundleConditions;
11use chia_consensus::run_block_generator::run_block_generator2;
12use chia_consensus::solution_generator::solution_generator_backrefs;
13use chia_consensus::spendbundle_conditions::run_spendbundle;
14use chia_protocol::{Coin, SpendBundle};
15use clvmr::cost::Cost;
16use clvmr::LIMIT_HEAP;
17
18use super::config::ValidationConfig;
19use super::context::ValidationContext;
20use super::error::ValidationError;
21use super::result::{BlockGeneratorResult, SpendResult};
22
23pub fn build_block_generator(
30 bundles: &[SpendBundle],
31 context: &ValidationContext,
32 max_cost: Cost,
33) -> Result<BlockGeneratorResult, ValidationError> {
34 let consensus = context.constants.consensus();
35 let mut cost_remaining = max_cost;
36 let mut included_spends: Vec<(Coin, Vec<u8>, Vec<u8>)> = Vec::new();
37 let mut all_additions: Vec<Coin> = Vec::new();
38 let mut all_removals: Vec<Coin> = Vec::new();
39 let mut signatures: Vec<Signature> = Vec::new();
40 let mut total_cost: Cost = 0;
41 let mut bundles_included: usize = 0;
42
43 for bundle in bundles {
44 let mut a = make_allocator(LIMIT_HEAP);
46 let result = run_spendbundle(
47 &mut a,
48 bundle,
49 cost_remaining,
50 context.height,
51 DONT_VALIDATE_SIGNATURE,
52 consensus,
53 );
54
55 let (sbc, _pkm_pairs) = match result {
56 Ok(r) => r,
57 Err(_) => continue, };
59
60 let conditions = OwnedSpendBundleConditions::from(&a, sbc);
61 let bundle_cost = conditions.cost;
62
63 if bundle_cost > cost_remaining {
64 continue; }
66
67 for cs in &bundle.coin_spends {
69 included_spends.push((cs.coin, cs.puzzle_reveal.to_vec(), cs.solution.to_vec()));
70 all_removals.push(cs.coin);
71 }
72
73 for spend in &conditions.spends {
75 let parent_id = spend.coin_id;
76 for cc in &spend.create_coin {
77 all_additions.push(Coin::new(parent_id, cc.0, cc.1));
78 }
79 }
80
81 signatures.push(bundle.aggregated_signature.clone());
82 total_cost += bundle_cost;
83 cost_remaining -= bundle_cost;
84 bundles_included += 1;
85 }
86
87 let spends_iter = included_spends
89 .iter()
90 .map(|(coin, puz, sol)| (*coin, puz.as_slice(), sol.as_slice()));
91
92 let generator = solution_generator_backrefs(spends_iter)
93 .map_err(|e| ValidationError::Clvm(format!("solution_generator_backrefs: {}", e)))?;
94
95 let aggregated_signature = if signatures.is_empty() {
97 Signature::default()
98 } else {
99 let mut agg = signatures[0].clone();
100 for sig in &signatures[1..] {
101 agg += sig;
102 }
103 agg
104 };
105
106 Ok(BlockGeneratorResult {
107 generator,
108 block_refs: Vec::new(), aggregated_signature,
110 additions: all_additions,
111 removals: all_removals,
112 cost: total_cost,
113 bundles_included,
114 })
115}
116
117pub fn validate_block(
124 generator: &[u8],
125 generator_refs: &[Vec<u8>],
126 context: &ValidationContext,
127 config: &ValidationConfig,
128 bls_cache: Option<&mut BlsCache>,
129 aggregated_signature: &Signature,
130) -> Result<SpendResult, ValidationError> {
131 let consensus = context.constants.consensus();
132 let mut a = make_allocator(LIMIT_HEAP);
133
134 let sbc = run_block_generator2(
137 &mut a,
138 generator,
139 generator_refs.iter().map(|r| r.as_slice()),
140 config.max_cost_per_block,
141 config.flags,
142 aggregated_signature,
143 bls_cache.map(|c| &*c),
144 consensus,
145 )
146 .map_err(|e| ValidationError::Clvm(format!("{:?}", e)))?;
147
148 let conditions = OwnedSpendBundleConditions::from(&a, sbc);
149
150 if conditions.cost > config.max_cost_per_block {
152 return Err(ValidationError::CostExceeded {
153 limit: config.max_cost_per_block,
154 consumed: conditions.cost,
155 });
156 }
157
158 let additions: Vec<Coin> = conditions
160 .spends
161 .iter()
162 .flat_map(|spend| {
163 let parent_id = spend.coin_id;
164 spend
165 .create_coin
166 .iter()
167 .map(move |cc| Coin::new(parent_id, cc.0, cc.1))
168 })
169 .collect();
170
171 let removals: Vec<Coin> = conditions
173 .spends
174 .iter()
175 .map(|spend| Coin::new(spend.parent_id, spend.puzzle_hash, spend.coin_amount))
176 .collect();
177
178 let total_input: u64 = removals.iter().map(|c| c.amount).sum();
180 let total_output: u64 = additions.iter().map(|c| c.amount).sum();
181
182 if total_input < total_output {
183 return Err(ValidationError::ConservationViolation {
184 input: total_input,
185 output: total_output,
186 });
187 }
188
189 let fee = total_input - total_output;
190
191 Ok(SpendResult {
192 additions,
193 removals,
194 fee,
195 conditions,
196 })
197}