From 93244ecf6225a5c160a0267a8a372f7aa3d382a7 Mon Sep 17 00:00:00 2001 From: lzx <393768033@qq.com> Date: Thu, 26 Jun 2025 17:01:59 +0800 Subject: [PATCH] add output_smt_size but encording still is base64 --- log4rs_gbt.yml | 108 ------------------ src/main.rs | 292 ++++++++++++------------------------------------- 2 files changed, 71 insertions(+), 329 deletions(-) delete mode 100644 log4rs_gbt.yml diff --git a/log4rs_gbt.yml b/log4rs_gbt.yml deleted file mode 100644 index b70686b..0000000 --- a/log4rs_gbt.yml +++ /dev/null @@ -1,108 +0,0 @@ -# GBT Client 日志配置文件 -# 基于 log4rs 配置,用于GBT客户端的日志管理 -refresh_rate: 30 seconds - -appenders: - # 控制台输出 - stdout: - kind: console - encoder: - pattern: "{d(%H:%M)} {h({l}):5} {m}{n}" - filters: - - kind: threshold - level: info - - # GBT客户端日志文件 - gbt: - kind: rolling_file - path: "{{log_dir}}/log/gbt/gbt.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/gbt/gbt.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {l:5} {m}{n}" - - # ZMQ通信日志 - zmq: - kind: rolling_file - path: "{{log_dir}}/log/gbt/zmq.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/gbt/zmq.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {l:5} {m}{n}" - - # gRPC通信日志 - grpc: - kind: rolling_file - path: "{{log_dir}}/log/gbt/grpc.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/gbt/grpc.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {l:5} {m}{n}" - -# 根日志配置 -root: - level: warn - appenders: - - stdout - -loggers: - # GBT客户端日志 - gbt: - level: debug - appenders: - - gbt - - stdout - additive: false - - # ZMQ相关日志 - zmq: - level: debug - appenders: - - zmq - - stdout - additive: false - - # gRPC相关日志 - tonic: - level: debug - appenders: - - grpc - - stdout - additive: false - - # 其他第三方库日志 - tokio_util: - level: warn - appenders: - - gbt - additive: false - - h2: - level: warn - appenders: - - grpc - additive: false \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d2044a5..a5a6a1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,196 +56,14 @@ use tari_core::{ }, }; use tari_utilities::hex::Hex; -use hex::FromHex; +use tari_utilities::ByteArray; +use jmt::{JellyfishMerkleTree, KeyHash}; +use jmt::mock::MockTreeStore; +use tari_core::chain_storage::SmtHasher; +use tari_core::blocks::Block as CoreBlock; const LOG_TARGET: &str = "gbt::main"; -// 自定义的Block结构体,用于16进制序列化 -#[derive(Debug, Serialize, Deserialize)] -struct HexBlock { - header: Option, - body: Option, // 保持原有的body结构 -} - -#[derive(Debug, Serialize, Deserialize)] -struct HexBlockHeader { - #[serde(serialize_with = "serialize_bytes_as_hex")] - hash: Vec, - version: u32, - height: u64, - #[serde(serialize_with = "serialize_bytes_as_hex")] - prev_hash: Vec, - timestamp: u64, - #[serde(serialize_with = "serialize_bytes_as_hex")] - output_mr: Vec, - #[serde(serialize_with = "serialize_bytes_as_hex")] - block_output_mr: Vec, - #[serde(serialize_with = "serialize_bytes_as_hex")] - kernel_mr: Vec, - #[serde(serialize_with = "serialize_bytes_as_hex")] - input_mr: Vec, - #[serde(serialize_with = "serialize_bytes_as_hex")] - total_kernel_offset: Vec, - nonce: u64, - pow: HexProofOfWork, - kernel_mmr_size: u64, - output_mmr_size: u64, - #[serde(serialize_with = "serialize_bytes_as_hex")] - total_script_offset: Vec, - #[serde(serialize_with = "serialize_bytes_as_hex")] - validator_node_mr: Vec, - validator_node_size: u64, -} - -#[derive(Debug, Serialize, Deserialize)] -struct HexProofOfWork { - pow_algo: u64, - #[serde(serialize_with = "serialize_bytes_as_hex")] - pow_data: Vec, -} - -// 自定义序列化函数:将字节数组序列化为16进制字符串 -fn serialize_bytes_as_hex(bytes: &[u8], serializer: S) -> Result -where - S: serde::Serializer, -{ - let hex_string = hex::encode(bytes); - serializer.serialize_str(&hex_string) -} - -// 将Block转换为HexBlock -fn convert_block_to_hex(block: &Block) -> Result { - let header = if let Some(ref h) = block.header { - Some(HexBlockHeader { - hash: h.hash.clone(), - version: h.version, - height: h.height, - prev_hash: h.prev_hash.clone(), - timestamp: h.timestamp, - output_mr: h.output_mr.clone(), - block_output_mr: h.block_output_mr.clone(), - kernel_mr: h.kernel_mr.clone(), - input_mr: h.input_mr.clone(), - total_kernel_offset: h.total_kernel_offset.clone(), - nonce: h.nonce, - pow: HexProofOfWork { - pow_algo: h.pow.as_ref().map(|p| p.pow_algo).unwrap_or(0), - pow_data: h.pow.as_ref().map(|p| p.pow_data.clone()).unwrap_or_default(), - }, - kernel_mmr_size: h.kernel_mmr_size, - output_mmr_size: h.output_mmr_size, - total_script_offset: h.total_script_offset.clone(), - validator_node_mr: h.validator_node_mr.clone(), - validator_node_size: h.validator_node_size, - }) - } else { - None - }; - - // 将body转换为JSON值,保持原有结构 - let body_json = serde_json::to_value(&block.body).map_err(|e| anyhow!("Body serialization error: {}", e))?; - - Ok(HexBlock { - header, - body: Some(body_json), - }) -} - -// 自定义反序列化函数:将16进制字符串反序列化为字节数组 -fn deserialize_hex_to_bytes<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - let hex_string = String::deserialize(deserializer)?; - hex::FromHex::from_hex(&hex_string).map_err(|e: hex::FromHexError| serde::de::Error::custom(e.to_string())) -} - -// 用于反序列化的结构体 -#[derive(Debug, Deserialize)] -struct HexBlockDeserialize { - header: Option, - body: Option, -} - -#[derive(Debug, Deserialize)] -struct HexBlockHeaderDeserialize { - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - hash: Vec, - version: u32, - height: u64, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - prev_hash: Vec, - timestamp: u64, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - output_mr: Vec, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - block_output_mr: Vec, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - kernel_mr: Vec, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - input_mr: Vec, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - total_kernel_offset: Vec, - nonce: u64, - pow: HexProofOfWorkDeserialize, - kernel_mmr_size: u64, - output_mmr_size: u64, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - total_script_offset: Vec, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - validator_node_mr: Vec, - validator_node_size: u64, -} - -#[derive(Debug, Deserialize)] -struct HexProofOfWorkDeserialize { - pow_algo: u64, - #[serde(deserialize_with = "deserialize_hex_to_bytes")] - pow_data: Vec, -} - -// 将16进制JSON转换回Block -fn convert_hex_to_block(hex_block: &HexBlockDeserialize) -> Result { - let header = if let Some(ref h) = hex_block.header { - Some(minotari_app_grpc::tari_rpc::BlockHeader { - hash: h.hash.clone(), - version: h.version, - height: h.height, - prev_hash: h.prev_hash.clone(), - timestamp: h.timestamp, - output_mr: h.output_mr.clone(), - block_output_mr: h.block_output_mr.clone(), - kernel_mr: h.kernel_mr.clone(), - input_mr: h.input_mr.clone(), - total_kernel_offset: h.total_kernel_offset.clone(), - nonce: h.nonce, - pow: Some(minotari_app_grpc::tari_rpc::ProofOfWork { - pow_algo: h.pow.pow_algo, - pow_data: h.pow.pow_data.clone(), - }), - kernel_mmr_size: h.kernel_mmr_size, - output_mmr_size: h.output_mmr_size, - total_script_offset: h.total_script_offset.clone(), - validator_node_mr: h.validator_node_mr.clone(), - validator_node_size: h.validator_node_size, - }) - } else { - None - }; - - // 将body从JSON值转换回原始结构 - let body = if let Some(ref body_json) = hex_block.body { - serde_json::from_value(body_json.clone()).map_err(|e| anyhow!("Body deserialization error: {}", e))? - } else { - None - }; - - Ok(Block { - header, - body, - }) -} - // ZMQ消息结构 #[derive(Debug, Serialize, Deserialize, Clone)] pub struct MiningTask { @@ -389,6 +207,46 @@ impl GbtClient { Ok(node_conn) } + /// 计算output_smt_size + fn calculate_output_smt_size(&self, block: &CoreBlock, prev_output_smt_size: u64) -> Result { + // 创建JellyfishMerkleTree用于计算 + let mock_store = MockTreeStore::new(true); + let output_smt = JellyfishMerkleTree::<_, SmtHasher>::new(&mock_store); + + let mut batch = Vec::new(); + + // 处理所有输出(添加新的叶子节点) + for output in block.body.outputs() { + if !output.is_burned() { + let smt_key = KeyHash( + output.commitment.as_bytes().try_into().expect("commitment is 32 bytes") + ); + let smt_value = output.smt_hash(block.header.height); + batch.push((smt_key, Some(smt_value.to_vec()))); + } + } + + // 处理所有输入(删除叶子节点) + for input in block.body.inputs() { + let smt_key = KeyHash( + input.commitment()?.as_bytes().try_into().expect("Commitment is 32 bytes") + ); + batch.push((smt_key, None)); + } + + // 计算SMT变化 + let (_, changes) = output_smt + .put_value_set(batch, block.header.height) + .map_err(|e| anyhow!("SMT calculation error: {}", e))?; + + // 计算新的output_smt_size + let mut size = prev_output_smt_size; + size += changes.node_stats.first().map(|s| s.new_leaves).unwrap_or(0) as u64; + size = size.saturating_sub(changes.node_stats.first().map(|s| s.stale_leaves).unwrap_or(0) as u64); + + Ok(size) + } + pub async fn get_block_template_and_coinbase(&mut self) -> Result { info!(target: LOG_TARGET, "Getting new block template"); @@ -419,13 +277,6 @@ impl GbtClient { .ok_or_else(|| anyhow!("No header in block template"))? .height; - // 获取output_smt_size - let output_smt_size = block_template - .header - .as_ref() - .ok_or_else(|| anyhow!("No header in block template"))? - .output_smt_size; - // 获取挖矿数据 let miner_data = template_response .miner_data @@ -469,21 +320,37 @@ impl GbtClient { body.kernels.push(coinbase_kernel.into()); // 获取完整的区块 - let block_result = self.base_node_client.get_new_block(block_template).await?.into_inner(); + let block_result = self.base_node_client.get_new_block(block_template.clone()).await?.into_inner(); let block = block_result.block.ok_or_else(|| anyhow!("No block in response"))?; // 计算coinbase哈希 let coinbase_hash = coinbase_output.hash().to_hex(); - // 使用自定义的16进制序列化 - let hex_block = convert_block_to_hex(&block)?; - let block_template_json = serde_json::to_string(&hex_block).map_err(|e| anyhow!("Serialization error: {}", e))?; + // 将gRPC Block转换为CoreBlock以便计算output_smt_size + let core_block: CoreBlock = block.clone().try_into() + .map_err(|e| anyhow!("Block conversion error: {}", e))?; + + // 获取前一个区块的output_smt_size(从区块模板头中获取) + let prev_output_smt_size = block_template + .header + .as_ref() + .ok_or_else(|| anyhow!("No header in block template"))? + .output_smt_size; + + // 计算新的output_smt_size + let calculated_output_smt_size = self.calculate_output_smt_size(&core_block, prev_output_smt_size)?; + + info!(target: LOG_TARGET, "Calculated output_smt_size: {} (prev: {})", + calculated_output_smt_size, prev_output_smt_size); + + // 序列化区块模板 + let block_template_json = serde_json::to_string(&block).map_err(|e| anyhow!("Serialization error: {}", e))?; let mining_task = MiningTask { coinbase_hash, height, target: target_difficulty, - output_smt_size, + output_smt_size: calculated_output_smt_size, // 使用计算出的值 block_template: block_template_json, }; @@ -541,17 +408,9 @@ impl GbtClient { // 提交区块到BaseNode pub async fn submit_block_to_base_node(&mut self, submit_request: &SubmitRequest) -> Result { - // 反序列化区块数据(支持16进制格式) - let block: Block = if submit_request.block_data.contains("\"hash\":") { - // 尝试解析为16进制格式 - let hex_block: HexBlockDeserialize = serde_json::from_str(&submit_request.block_data) - .map_err(|e| anyhow!("Hex block deserialization error: {}", e))?; - convert_hex_to_block(&hex_block)? - } else { - // 尝试解析为原始Base64格式(向后兼容) - serde_json::from_str(&submit_request.block_data) - .map_err(|e| anyhow!("Block deserialization error: {}", e))? - }; + // 反序列化区块数据 + let block: Block = serde_json::from_str(&submit_request.block_data) + .map_err(|e| anyhow!("Block deserialization error: {}", e))?; info!(target: LOG_TARGET, "Submitting block to base node for height {}", submit_request.height); @@ -667,17 +526,8 @@ struct Args { #[tokio::main] async fn main() -> Result<()> { - // 初始化日志系统 - let log_config_path = PathBuf::from("log4rs_gbt.yml"); - if log_config_path.exists() { - // 使用log4rs配置文件 - let base_path = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); - tari_common::initialize_logging(&log_config_path, &base_path, "") - .map_err(|e| anyhow!("Failed to initialize logging: {}", e))?; - } else { - // 回退到env_logger - env_logger::init(); - } + // 初始化日志 + env_logger::init(); let args = Args::parse();