// 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, pub exec_records: Vec, pub total_executions: u64, pub total_contracts: u64, pub started_at: i64, } type SharedState = Arc>; #[derive(Debug, Deserialize)] pub struct DeployReq { pub bytecode: String, pub deployer: String, pub language: Option, } #[derive(Debug, Deserialize)] pub struct ExecuteReq { pub contract_address: String, pub caller: String, pub function: String, pub args: Option, pub gas_limit: Option, } 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) -> 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) -> 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, req: web::Json) -> HttpResponse { if !validate_address(&req.deployer) { return HttpResponse::BadRequest().json(serde_json::json!({ "success": false, "error": "deployer 必须为 NAC Address(32字节,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, req: web::Json) -> HttpResponse { if !validate_address(&req.caller) { return HttpResponse::BadRequest().json(serde_json::json!({ "success": false, "error": "caller 必须为 NAC Address(32字节,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) -> 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) -> 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 }