add output_smt_size but encording still is base64

This commit is contained in:
lzx 2025-06-26 17:01:59 +08:00
parent 9d0a21ba5c
commit 93244ecf62
2 changed files with 71 additions and 329 deletions

View File

@ -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

View File

@ -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<HexBlockHeader>,
body: Option<serde_json::Value>, // 保持原有的body结构
}
#[derive(Debug, Serialize, Deserialize)]
struct HexBlockHeader {
#[serde(serialize_with = "serialize_bytes_as_hex")]
hash: Vec<u8>,
version: u32,
height: u64,
#[serde(serialize_with = "serialize_bytes_as_hex")]
prev_hash: Vec<u8>,
timestamp: u64,
#[serde(serialize_with = "serialize_bytes_as_hex")]
output_mr: Vec<u8>,
#[serde(serialize_with = "serialize_bytes_as_hex")]
block_output_mr: Vec<u8>,
#[serde(serialize_with = "serialize_bytes_as_hex")]
kernel_mr: Vec<u8>,
#[serde(serialize_with = "serialize_bytes_as_hex")]
input_mr: Vec<u8>,
#[serde(serialize_with = "serialize_bytes_as_hex")]
total_kernel_offset: Vec<u8>,
nonce: u64,
pow: HexProofOfWork,
kernel_mmr_size: u64,
output_mmr_size: u64,
#[serde(serialize_with = "serialize_bytes_as_hex")]
total_script_offset: Vec<u8>,
#[serde(serialize_with = "serialize_bytes_as_hex")]
validator_node_mr: Vec<u8>,
validator_node_size: u64,
}
#[derive(Debug, Serialize, Deserialize)]
struct HexProofOfWork {
pow_algo: u64,
#[serde(serialize_with = "serialize_bytes_as_hex")]
pow_data: Vec<u8>,
}
// 自定义序列化函数将字节数组序列化为16进制字符串
fn serialize_bytes_as_hex<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
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<HexBlock> {
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<Vec<u8>, 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<HexBlockHeaderDeserialize>,
body: Option<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
struct HexBlockHeaderDeserialize {
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
hash: Vec<u8>,
version: u32,
height: u64,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
prev_hash: Vec<u8>,
timestamp: u64,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
output_mr: Vec<u8>,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
block_output_mr: Vec<u8>,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
kernel_mr: Vec<u8>,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
input_mr: Vec<u8>,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
total_kernel_offset: Vec<u8>,
nonce: u64,
pow: HexProofOfWorkDeserialize,
kernel_mmr_size: u64,
output_mmr_size: u64,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
total_script_offset: Vec<u8>,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
validator_node_mr: Vec<u8>,
validator_node_size: u64,
}
#[derive(Debug, Deserialize)]
struct HexProofOfWorkDeserialize {
pow_algo: u64,
#[serde(deserialize_with = "deserialize_hex_to_bytes")]
pow_data: Vec<u8>,
}
// 将16进制JSON转换回Block
fn convert_hex_to_block(hex_block: &HexBlockDeserialize) -> Result<Block> {
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<u64> {
// 创建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<MiningTask> {
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<SubmitBlockResponse> {
// 反序列化区块数据支持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();