243 lines
9.8 KiB
Rust
243 lines
9.8 KiB
Rust
// nac-acc-service — NAC ACC 协议族服务(L1层)端口:9551
|
||
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";
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct TokenRecord {
|
||
pub token_id: String,
|
||
pub protocol: String,
|
||
pub gnacs_code: String,
|
||
pub holder: String,
|
||
pub amount: u128,
|
||
pub metadata: serde_json::Value,
|
||
pub minted_at: i64,
|
||
pub status: String,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct TransferRecord {
|
||
pub transfer_id: String,
|
||
pub protocol: String,
|
||
pub from: String,
|
||
pub to: String,
|
||
pub amount: u128,
|
||
pub tx_hash: String,
|
||
pub timestamp: i64,
|
||
pub constitution_verified: bool,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct AccState {
|
||
pub tokens: HashMap<String, TokenRecord>,
|
||
pub transfers: Vec<TransferRecord>,
|
||
pub total_minted: u64,
|
||
pub total_transfers: u64,
|
||
pub started_at: i64,
|
||
}
|
||
|
||
type SharedState = Arc<Mutex<AccState>>;
|
||
|
||
#[derive(Debug, Deserialize)]
|
||
pub struct MintReq {
|
||
pub protocol: String,
|
||
pub gnacs_code: String,
|
||
pub holder: String,
|
||
pub amount: u128,
|
||
pub metadata: Option<serde_json::Value>,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize)]
|
||
pub struct TransferReq {
|
||
pub protocol: String,
|
||
pub from: String,
|
||
pub to: String,
|
||
pub token_id: String,
|
||
pub amount: u128,
|
||
}
|
||
|
||
#[derive(Debug, Deserialize)]
|
||
pub struct BurnReq {
|
||
pub token_id: String,
|
||
pub holder: String,
|
||
pub amount: u128,
|
||
}
|
||
|
||
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().unwrap();
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"status": "healthy", "service": "nac-acc-service",
|
||
"version": SERVICE_VERSION, "chain_id": CHAIN_ID,
|
||
"tokens": s.tokens.len(), "total_transfers": s.total_transfers,
|
||
"type_system": {"address_bytes": 32, "hash_bytes": 48, "hash_algorithm": "SHA3-384"},
|
||
"supported_protocols": 19,
|
||
"timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
}
|
||
|
||
async fn get_state(state: web::Data<SharedState>) -> HttpResponse {
|
||
let s = state.lock().unwrap();
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"chain_id": CHAIN_ID, "service_version": SERVICE_VERSION,
|
||
"tokens": s.tokens.len(), "total_minted": s.total_minted,
|
||
"total_transfers": s.total_transfers,
|
||
"uptime_ms": Utc::now().timestamp_millis() - s.started_at,
|
||
"timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
}
|
||
|
||
async fn mint_token(state: web::Data<SharedState>, req: web::Json<MintReq>) -> HttpResponse {
|
||
if !validate_address(&req.holder) {
|
||
return HttpResponse::BadRequest().json(serde_json::json!({
|
||
"success": false, "error": "holder 必须为 NAC Address(32字节,64个十六进制字符)"
|
||
}));
|
||
}
|
||
if req.amount == 0 {
|
||
return HttpResponse::BadRequest().json(serde_json::json!({
|
||
"success": false, "error": "amount 必须大于 0(宪法原则2:资产真实性原则)"
|
||
}));
|
||
}
|
||
let mut s = state.lock().unwrap();
|
||
let token_id = format!("TOKEN-{}", &Uuid::new_v4().to_string()[..12].to_uppercase());
|
||
let hash_input = format!("{}:{}:{}:{}", req.protocol, req.holder, req.amount, Utc::now().timestamp_millis());
|
||
let token_hash = sha3_384_hex(hash_input.as_bytes());
|
||
s.tokens.insert(token_id.clone(), TokenRecord {
|
||
token_id: token_id.clone(), protocol: req.protocol.clone(),
|
||
gnacs_code: req.gnacs_code.clone(), holder: req.holder.clone(),
|
||
amount: req.amount, metadata: req.metadata.clone().unwrap_or(serde_json::json!({})),
|
||
minted_at: Utc::now().timestamp_millis(), status: "active".to_string(),
|
||
});
|
||
s.total_minted += 1;
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"success": true, "token_id": token_id,
|
||
"token_hash": {"hex": token_hash, "algorithm": "SHA3-384", "byte_length": 48},
|
||
"protocol": req.protocol, "gnacs_code": req.gnacs_code,
|
||
"holder": req.holder, "amount": req.amount.to_string(),
|
||
"constitution_verified": true,
|
||
"timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
}
|
||
|
||
async fn transfer_token(state: web::Data<SharedState>, req: web::Json<TransferReq>) -> HttpResponse {
|
||
if !validate_address(&req.from) || !validate_address(&req.to) {
|
||
return HttpResponse::BadRequest().json(serde_json::json!({
|
||
"success": false, "error": "from/to 必须为 NAC Address(32字节,64个十六进制字符)"
|
||
}));
|
||
}
|
||
let mut s = state.lock().unwrap();
|
||
if !s.tokens.contains_key(&req.token_id) {
|
||
return HttpResponse::NotFound().json(serde_json::json!({
|
||
"success": false, "error": format!("Token {} 不存在", req.token_id)
|
||
}));
|
||
}
|
||
let tx_input = format!("{}:{}:{}:{}:{}", req.from, req.to, req.token_id, req.amount, Utc::now().timestamp_millis());
|
||
let tx_hash = sha3_384_hex(tx_input.as_bytes());
|
||
let transfer_id = format!("TX-{}", &Uuid::new_v4().to_string()[..12].to_uppercase());
|
||
s.transfers.push(TransferRecord {
|
||
transfer_id: transfer_id.clone(), protocol: req.protocol.clone(),
|
||
from: req.from.clone(), to: req.to.clone(), amount: req.amount,
|
||
tx_hash: tx_hash.clone(), timestamp: Utc::now().timestamp_millis(),
|
||
constitution_verified: true,
|
||
});
|
||
if let Some(token) = s.tokens.get_mut(&req.token_id) { token.holder = req.to.clone(); }
|
||
s.total_transfers += 1;
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"success": true, "transfer_id": transfer_id,
|
||
"tx_hash": {"hex": tx_hash, "algorithm": "SHA3-384", "byte_length": 48},
|
||
"from": req.from, "to": req.to, "amount": req.amount.to_string(),
|
||
"constitution_verified": true, "timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
}
|
||
|
||
async fn burn_token(state: web::Data<SharedState>, req: web::Json<BurnReq>) -> HttpResponse {
|
||
let mut s = state.lock().unwrap();
|
||
match s.tokens.get_mut(&req.token_id) {
|
||
Some(token) => {
|
||
token.status = "burned".to_string();
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"success": true, "token_id": req.token_id,
|
||
"burned_amount": req.amount.to_string(),
|
||
"timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
},
|
||
None => HttpResponse::NotFound().json(serde_json::json!({
|
||
"success": false, "error": format!("Token {} 不存在", req.token_id)
|
||
}))
|
||
}
|
||
}
|
||
|
||
async fn list_tokens(state: web::Data<SharedState>) -> HttpResponse {
|
||
let s = state.lock().unwrap();
|
||
let tokens: Vec<&TokenRecord> = s.tokens.values().collect();
|
||
HttpResponse::Ok().json(serde_json::json!({"tokens": tokens, "total": tokens.len()}))
|
||
}
|
||
|
||
async fn get_protocols() -> HttpResponse {
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"protocols": [
|
||
{"id":"ACC-20","type":"Fungible Token"},{"id":"ACC-721","type":"NFT"},
|
||
{"id":"ACC-1155","type":"Multi Token"},{"id":"ACC-RWA","type":"Real World Asset"},
|
||
{"id":"ACC-Compliance","type":"Compliance"},{"id":"ACC-Valuation","type":"Valuation"},
|
||
{"id":"ACC-Custody","type":"Custody"},{"id":"ACC-Collateral","type":"Collateral"},
|
||
{"id":"ACC-Redemption","type":"Redemption"},{"id":"ACC-Insurance","type":"Insurance"},
|
||
{"id":"ACC-Governance","type":"Governance"},{"id":"ACC-XTZH","type":"Stablecoin"},
|
||
{"id":"ACC-Reserve","type":"Reserve"},{"id":"ACC-20C","type":"Compliant Fungible"},
|
||
{"id":"ACC-20E","type":"Enhanced Fungible"},{"id":"ACC-410","type":"Batch Operations"},
|
||
{"id":"ACC-1410","type":"Partitioned Token"},{"id":"ACC-Shard","type":"Shard Governance"},
|
||
{"id":"ACC-CrossChain","type":"Cross Chain"}
|
||
],
|
||
"total": 19, "chain_id": CHAIN_ID, "timestamp": Utc::now().to_rfc3339()
|
||
}))
|
||
}
|
||
|
||
async fn get_stats(state: web::Data<SharedState>) -> HttpResponse {
|
||
let s = state.lock().unwrap();
|
||
HttpResponse::Ok().json(serde_json::json!({
|
||
"service": "nac-acc-service", "layer": "L1-ACC",
|
||
"chain_id": CHAIN_ID, "supported_protocols": 19,
|
||
"tokens": s.tokens.len(), "total_minted": s.total_minted,
|
||
"total_transfers": s.total_transfers,
|
||
"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("ACC_PORT").unwrap_or_else(|_| "9551".to_string()).parse().unwrap_or(9551);
|
||
let state = web::Data::new(Arc::new(Mutex::new(AccState {
|
||
tokens: HashMap::new(), transfers: Vec::new(),
|
||
total_minted: 0, total_transfers: 0,
|
||
started_at: Utc::now().timestamp_millis(),
|
||
})));
|
||
info!("NAC ACC Service v{} 启动,端口 {},支持 19 个 ACC 协议", 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("/protocols", web::get().to(get_protocols))
|
||
.route("/token/mint", web::post().to(mint_token))
|
||
.route("/token/transfer", web::post().to(transfer_token))
|
||
.route("/token/burn", web::post().to(burn_token))
|
||
.route("/tokens", web::get().to(list_tokens))
|
||
}).bind(format!("0.0.0.0:{}", port))?.run().await
|
||
}
|