NAC_Blockchain/protocol/nac-nvm-service/src/main.rs

204 lines
8.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// nac-nvm-service — NAC NVM 虚拟机服务L1层端口9550
use actix_web::{web, App, HttpServer, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use chrono::Utc;
use uuid::Uuid;
use sha3::{Sha3_384, Digest};
use tracing::info;
const CHAIN_ID: u64 = 5132611;
const SERVICE_VERSION: &str = "1.0.0";
const NVM_VERSION: &str = "2.0";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContractRecord {
pub contract_id: String,
pub address: String,
pub code_hash: String,
pub deployer: String,
pub language: String,
pub bytecode_size: usize,
pub deployed_at: i64,
pub execution_count: u64,
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecRecord {
pub execution_id: String,
pub contract_address: String,
pub caller: String,
pub function: String,
pub success: bool,
pub gas_used: u64,
pub timestamp: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NvmState {
pub contracts: HashMap<String, ContractRecord>,
pub exec_records: Vec<ExecRecord>,
pub total_executions: u64,
pub total_contracts: u64,
pub started_at: i64,
}
type SharedState = Arc<Mutex<NvmState>>;
#[derive(Debug, Deserialize)]
pub struct DeployReq {
pub bytecode: String,
pub deployer: String,
pub language: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ExecuteReq {
pub contract_address: String,
pub caller: String,
pub function: String,
pub args: Option<serde_json::Value>,
pub gas_limit: Option<u64>,
}
fn sha3_384_hex(data: &[u8]) -> String {
let mut h = Sha3_384::new(); h.update(data); hex::encode(h.finalize())
}
fn validate_address(addr: &str) -> bool {
addr.len() == 64 && addr.chars().all(|c| c.is_ascii_hexdigit())
}
async fn health(state: web::Data<SharedState>) -> HttpResponse {
let s = state.lock().expect("lock not poisoned");
HttpResponse::Ok().json(serde_json::json!({
"status": "healthy", "service": "nac-nvm-service",
"version": SERVICE_VERSION, "nvm_version": NVM_VERSION,
"chain_id": CHAIN_ID, "contracts": s.contracts.len(),
"total_executions": s.total_executions,
"type_system": {"address_bytes": 32, "hash_bytes": 48, "hash_algorithm": "SHA3-384"},
"timestamp": Utc::now().to_rfc3339()
}))
}
async fn get_state(state: web::Data<SharedState>) -> HttpResponse {
let s = state.lock().expect("lock not poisoned");
HttpResponse::Ok().json(serde_json::json!({
"chain_id": CHAIN_ID, "nvm_version": NVM_VERSION,
"contracts_deployed": s.contracts.len(),
"total_executions": s.total_executions,
"uptime_ms": Utc::now().timestamp_millis() - s.started_at,
"timestamp": Utc::now().to_rfc3339()
}))
}
async fn vm_info() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({
"vm_name": "NVM", "full_name": "NewAssetChain Virtual Machine",
"version": NVM_VERSION, "chain_id": CHAIN_ID,
"features": {"jit_compilation": true, "cbpp_integration": true, "charter_language": true},
"supported_languages": ["charter"],
"type_system": {"address_bytes": 32, "hash_bytes": 48, "hash_algorithm": "SHA3-384"},
"timestamp": Utc::now().to_rfc3339()
}))
}
async fn deploy_contract(state: web::Data<SharedState>, req: web::Json<DeployReq>) -> HttpResponse {
if !validate_address(&req.deployer) {
return HttpResponse::BadRequest().json(serde_json::json!({
"success": false, "error": "deployer 必须为 NAC Address32字节64个十六进制字符"
}));
}
let mut s = state.lock().expect("lock not poisoned");
let bytecode_bytes = hex::decode(&req.bytecode).unwrap_or_else(|_| req.bytecode.as_bytes().to_vec());
let code_hash = sha3_384_hex(&bytecode_bytes);
let addr_input = format!("{}:{}", req.deployer, s.total_contracts);
let contract_address = sha3_384_hex(addr_input.as_bytes())[..64].to_string();
let contract_id = format!("CONTRACT-{}", &Uuid::new_v4().to_string()[..8].to_uppercase());
s.contracts.insert(contract_address.clone(), ContractRecord {
contract_id: contract_id.clone(), address: contract_address.clone(),
code_hash: code_hash.clone(), deployer: req.deployer.clone(),
language: req.language.clone().unwrap_or_else(|| "charter".to_string()),
bytecode_size: bytecode_bytes.len(), deployed_at: Utc::now().timestamp_millis(),
execution_count: 0, status: "active".to_string(),
});
s.total_contracts += 1;
HttpResponse::Ok().json(serde_json::json!({
"success": true, "contract_id": contract_id,
"contract_address": contract_address,
"code_hash": {"hex": code_hash, "algorithm": "SHA3-384", "byte_length": 48},
"timestamp": Utc::now().to_rfc3339()
}))
}
async fn execute_contract(state: web::Data<SharedState>, req: web::Json<ExecuteReq>) -> HttpResponse {
if !validate_address(&req.caller) {
return HttpResponse::BadRequest().json(serde_json::json!({
"success": false, "error": "caller 必须为 NAC Address32字节64个十六进制字符"
}));
}
let mut s = state.lock().expect("lock not poisoned");
if !s.contracts.contains_key(&req.contract_address) {
return HttpResponse::NotFound().json(serde_json::json!({
"success": false, "error": format!("合约 {} 不存在", req.contract_address)
}));
}
let gas_limit = req.gas_limit.unwrap_or(1_000_000);
let execution_id = format!("EXEC-{}", &Uuid::new_v4().to_string()[..12].to_uppercase());
let tx_input = format!("{}:{}:{}:{}", req.caller, req.contract_address, req.function, Utc::now().timestamp_millis());
let tx_hash = sha3_384_hex(tx_input.as_bytes());
if let Some(c) = s.contracts.get_mut(&req.contract_address) { c.execution_count += 1; }
s.exec_records.push(ExecRecord {
execution_id: execution_id.clone(), contract_address: req.contract_address.clone(),
caller: req.caller.clone(), function: req.function.clone(),
success: true, gas_used: gas_limit / 10, timestamp: Utc::now().timestamp_millis(),
});
s.total_executions += 1;
HttpResponse::Ok().json(serde_json::json!({
"success": true, "execution_id": execution_id,
"tx_hash": {"hex": tx_hash, "algorithm": "SHA3-384", "byte_length": 48},
"gas_used": gas_limit / 10, "timestamp": Utc::now().to_rfc3339()
}))
}
async fn list_contracts(state: web::Data<SharedState>) -> HttpResponse {
let s = state.lock().expect("lock not poisoned");
let contracts: Vec<&ContractRecord> = s.contracts.values().collect();
HttpResponse::Ok().json(serde_json::json!({"contracts": contracts, "total": contracts.len()}))
}
async fn get_stats(state: web::Data<SharedState>) -> HttpResponse {
let s = state.lock().expect("lock not poisoned");
HttpResponse::Ok().json(serde_json::json!({
"service": "nac-nvm-service", "layer": "L1-NVM",
"chain_id": CHAIN_ID, "nvm_version": NVM_VERSION,
"contracts": s.contracts.len(), "total_executions": s.total_executions,
"uptime_ms": Utc::now().timestamp_millis() - s.started_at,
"timestamp": Utc::now().to_rfc3339()
}))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();
let port: u16 = std::env::var("NVM_PORT").unwrap_or_else(|_| "9550".to_string()).parse().unwrap_or(9550);
let state = web::Data::new(Arc::new(Mutex::new(NvmState {
contracts: HashMap::new(), exec_records: Vec::new(),
total_executions: 0, total_contracts: 0,
started_at: Utc::now().timestamp_millis(),
})));
info!("NAC NVM Service v{} 启动,端口 {}", SERVICE_VERSION, port);
HttpServer::new(move || {
App::new().app_data(state.clone())
.route("/health", web::get().to(health))
.route("/state", web::get().to(get_state))
.route("/stats", web::get().to(get_stats))
.route("/vm/info", web::get().to(vm_info))
.route("/contract/deploy", web::post().to(deploy_contract))
.route("/contract/execute", web::post().to(execute_contract))
.route("/contracts", web::get().to(list_contracts))
}).bind(format!("0.0.0.0:{}", port))?.run().await
}