From 9d0a21ba5c3ac8780193186d34b41651cb13f11e Mon Sep 17 00:00:00 2001 From: lzx <393768033@qq.com> Date: Thu, 26 Jun 2025 15:22:52 +0800 Subject: [PATCH 1/2] add base64 to hex --- build.bat | 100 --------------------- log4rs_gbt.yml | 108 +++++++++++++++++++++++ src/main.rs | 231 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 331 insertions(+), 108 deletions(-) delete mode 100644 build.bat create mode 100644 log4rs_gbt.yml diff --git a/build.bat b/build.bat deleted file mode 100644 index c01d45d..0000000 --- a/build.bat +++ /dev/null @@ -1,100 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -REM GBT项目构建脚本 (Windows版本) - -echo 🚀 开始构建GBT项目... - -REM 检查Rust环境 -where cargo >nul 2>&1 -if %errorlevel% neq 0 ( - echo ❌ 错误: 未找到cargo,请先安装Rust - echo 访问: https://rustup.rs/ - pause - exit /b 1 -) - -REM 检查Rust版本 -for /f "tokens=2" %%i in ('rustc --version') do set RUST_VERSION=%%i -echo 📦 Rust版本: %RUST_VERSION% - -REM 检查是否在正确的目录 -if not exist "Cargo.toml" ( - echo ❌ 错误: 未找到Cargo.toml,请在gbt目录下运行此脚本 - pause - exit /b 1 -) - -REM 清理之前的构建 -echo 🧹 清理之前的构建... -cargo clean -if %errorlevel% neq 0 ( - echo ❌ 清理失败 - pause - exit /b 1 -) - -REM 更新依赖 -echo 📥 更新依赖... -cargo update -if %errorlevel% neq 0 ( - echo ❌ 更新依赖失败 - pause - exit /b 1 -) - -REM 检查代码 -echo 🔍 检查代码... -cargo check -if %errorlevel% neq 0 ( - echo ❌ 代码检查失败 - pause - exit /b 1 -) - -REM 运行测试 -echo 🧪 运行测试... -cargo test -if %errorlevel% neq 0 ( - echo ❌ 测试失败 - pause - exit /b 1 -) - -REM 构建发布版本 -echo 🔨 构建发布版本... -cargo build --release -if %errorlevel% neq 0 ( - echo ❌ 构建失败 - pause - exit /b 1 -) - -REM 检查构建结果 -if exist "target\release\gbt.exe" ( - echo ✅ 构建成功! - echo 📁 可执行文件位置: target\release\gbt.exe - - REM 显示文件信息 - echo 📊 文件信息: - dir target\release\gbt.exe - - REM 显示版本信息 - echo ℹ️ 版本信息: - target\release\gbt.exe --version 2>nul || echo 无法获取版本信息 - -) else ( - echo ❌ 构建失败! - pause - exit /b 1 -) - -echo 🎉 GBT项目构建完成! -echo. -echo 📖 使用方法: -echo target\release\gbt.exe --wallet-address ^ -echo. -echo 📖 更多选项: -echo target\release\gbt.exe --help -echo. -pause \ No newline at end of file diff --git a/log4rs_gbt.yml b/log4rs_gbt.yml new file mode 100644 index 0000000..b70686b --- /dev/null +++ b/log4rs_gbt.yml @@ -0,0 +1,108 @@ +# 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 3042c75..d2044a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,15 +56,203 @@ use tari_core::{ }, }; use tari_utilities::hex::Hex; +use hex::FromHex; 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 { pub coinbase_hash: String, pub height: u64, pub target: u64, + pub output_smt_size: u64, // 新增:output_smt_size pub block_template: String, // 序列化的区块模板 } @@ -231,6 +419,13 @@ 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 @@ -280,13 +475,15 @@ impl GbtClient { // 计算coinbase哈希 let coinbase_hash = coinbase_output.hash().to_hex(); - // 序列化区块模板 - let block_template_json = serde_json::to_string(&block).map_err(|e| anyhow!("Serialization error: {}", e))?; + // 使用自定义的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))?; let mining_task = MiningTask { coinbase_hash, height, target: target_difficulty, + output_smt_size, block_template: block_template_json, }; @@ -307,7 +504,8 @@ impl GbtClient { .send_multipart(&["mining_task".as_bytes(), task_json.as_bytes()], 0) .map_err(|e| anyhow!("ZMQ send error: {}", e))?; - info!(target: LOG_TARGET, "Sent mining task for height {} with target {}", task.height, task.target); + info!(target: LOG_TARGET, "Sent mining task for height {} with target {} and output_smt_size {}", + task.height, task.target, task.output_smt_size); Ok(()) } @@ -343,9 +541,17 @@ impl GbtClient { // 提交区块到BaseNode pub async fn submit_block_to_base_node(&mut self, submit_request: &SubmitRequest) -> Result { - // 反序列化区块数据 - let block: Block = serde_json::from_str(&submit_request.block_data) - .map_err(|e| anyhow!("Block deserialization error: {}", e))?; + // 反序列化区块数据(支持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))? + }; info!(target: LOG_TARGET, "Submitting block to base node for height {}", submit_request.height); @@ -461,8 +667,17 @@ struct Args { #[tokio::main] async fn main() -> Result<()> { - // 初始化日志 - env_logger::init(); + // 初始化日志系统 + 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(); + } let args = Args::parse(); 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 2/2] 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();