add output_smt_size but encording still is base64
This commit is contained in:
parent
9d0a21ba5c
commit
93244ecf62
108
log4rs_gbt.yml
108
log4rs_gbt.yml
|
@ -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
|
292
src/main.rs
292
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<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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue