add base64 to hex
This commit is contained in:
parent
28aa4e4650
commit
9d0a21ba5c
100
build.bat
100
build.bat
|
@ -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 ^<YOUR_WALLET_ADDRESS^>
|
||||
echo.
|
||||
echo 📖 更多选项:
|
||||
echo target\release\gbt.exe --help
|
||||
echo.
|
||||
pause
|
|
@ -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
|
231
src/main.rs
231
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<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 {
|
||||
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<SubmitBlockResponse> {
|
||||
// 反序列化区块数据
|
||||
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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue