| Crates.io | chia-generator-parser |
| lib.rs | chia-generator-parser |
| version | 0.2.0 |
| created_at | 2026-01-20 18:30:34.713183+00 |
| updated_at | 2026-01-20 18:30:34.713183+00 |
| description | Chia blockchain generator bytecode parser |
| homepage | |
| repository | |
| max_upload_size | |
| id | 2057170 |
| size | 68,655 |
A production-ready Rust crate for parsing Chia blockchain generator bytecode, extracting transaction generators and reference lists from serialized blocks. This implementation exactly mirrors the Python chia.full_node.full_block_utils module.
This crate provides efficient, production-quality parsing of Chia blockchain blocks to extract:
block_info_from_block() - Extract complete generator informationgenerator_from_block() - Extract raw generator bytecodeget_height_and_tx_status_from_block() - Fast height/status extractionheader_block_from_block() - Generate header blocks for networkingThe crate implements exactly the same logic as Chia's Python full_block_utils.py:
// Python: block_info_from_block(buf)
let block_info = parser.parse_block_info(block_bytes)?;
// Python: generator_from_block(buf)
let generator_bytes = parser.extract_generator_from_block(block_bytes)?;
// Python: get_height_and_tx_status_from_block(buf)
let height_info = parser.get_height_and_tx_status_from_block(block_bytes)?;
Add this to your Cargo.toml:
[dependencies]
chia-generator-parser = { path = "./crate/chia-generator-parser" }
use chia_generator_parser::{BlockParser, GeneratorBlockInfo};
let parser = BlockParser::new();
// Parse complete block information (Python: block_info_from_block)
let block_info = parser.parse_block_info(block_bytes)?;
println!("Previous hash: {}", hex::encode(block_info.prev_header_hash));
println!("Generator size: {} bytes", block_info.generator_size());
println!("References: {:?}", block_info.transactions_generator_ref_list);
// Extract raw generator (Python: generator_from_block)
let raw_generator = parser.extract_generator_from_block(block_bytes)?;
// Get block metadata (Python: get_height_and_tx_status_from_block)
let height_info = parser.get_height_and_tx_status_from_block(block_bytes)?;
println!("Block height: {}, Is transaction block: {}",
height_info.height, height_info.is_transaction_block);
// Parse and analyze generator from hex
let parsed_generator = parser.parse_generator_from_hex(generator_hex)?;
println!("Size: {} bytes", parsed_generator.analysis.size_bytes);
println!("Contains CLVM patterns: {}", parsed_generator.analysis.contains_clvm_patterns);
println!("Contains coin patterns: {}", parsed_generator.analysis.contains_coin_patterns);
println!("Entropy: {:.2}", parsed_generator.analysis.entropy);
println!("Is empty: {}", parsed_generator.analysis.is_empty);
The parser follows the exact block structure as defined in the Chia protocol:
pub struct GeneratorBlockInfo {
pub prev_header_hash: Bytes32, // From foliage
pub transactions_generator: Option<SerializedProgram>, // CLVM bytecode
pub transactions_generator_ref_list: Vec<uint32>, // Referenced blocks
}
// Generate header block for networking (Python: header_block_from_block)
let header_block = parser.header_block_from_block(
block_bytes,
true, // request_filter
&[], // tx_addition_coins
&[] // removal_names
)?;
The parser uses production-quality CLVM serialization matching chia_rs::serialized_length:
fn calculate_serialized_length(&self, buf: &[u8]) -> Result<usize> {
if buf[0] == 0x80 {
Ok(1) // Null/empty
} else if buf[0] == 0xff {
// Cons cell - recursive calculation
let left_len = self.calculate_serialized_length(&buf[1..])?;
let right_len = self.calculate_serialized_length(&buf[1+left_len..])?;
Ok(1 + left_len + right_len)
} else if buf[0] & 0x80 == 0 {
Ok(1) // Small positive integer
} else {
// Variable length encoding
let size_bytes = (buf[0] & 0x7f) as usize;
Ok(1 + size_bytes)
}
}
// Efficient streaming parser - no full deserialization required
buf = self.skip_list(buf, |b| self.skip_end_of_sub_slot_bundle(b))?;
buf = self.skip_reward_chain_block(buf)?;
// ... continue parsing to reach generator
// Direct offset calculation like Python reference
fn skip_transactions_info(&self, buf: &[u8]) -> Result<&[u8]> {
let total_size = 32 + 32 + 96 + 8 + 8; // Fixed field sizes
let buf = &buf[total_size..];
self.skip_list(buf, |b| self.skip_coin(b)) // Skip reward_claims_incorporated
}
cargo run --example production_test
This validates:
cargo run --example basic_usage
Production-grade error handling with specific error types:
use chia_generator_parser::GeneratorParserError;
match parser.parse_block_info(block_bytes) {
Ok(block_info) => { /* Process block info */ },
Err(GeneratorParserError::BufferTooShort { expected, actual }) => {
eprintln!("Buffer too short: need {}, got {}", expected, actual);
},
Err(GeneratorParserError::InvalidBlockFormat(msg)) => {
eprintln!("Invalid block format: {}", msg);
},
Err(GeneratorParserError::ClvmParsingError(msg)) => {
eprintln!("CLVM parsing failed: {}", msg);
},
Err(e) => eprintln!("Other error: {}", e),
}
| Python Function | Rust Method | Status |
|---|---|---|
block_info_from_block() |
parse_block_info() |
✅ Complete |
generator_from_block() |
extract_generator_from_block() |
✅ Complete |
get_height_and_tx_status_from_block() |
get_height_and_tx_status_from_block() |
✅ Complete |
header_block_from_block() |
header_block_from_block() |
✅ Complete |
chia_rs.serialized_length() |
calculate_serialized_length() |
✅ Complete |
MIT License
This is a production implementation that maintains strict compatibility with the Python reference. Changes should:
full_block_utils.py compatibilitycargo run --example production_test