NAC_Blockchain/nac-wallet-core/src/transaction.rs

419 lines
11 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交易包含两部分交易体 + 宪法收据(CR)
use crate::constitutional_receipt::ConstitutionalReceipt;
use serde::{Deserialize, Serialize};
use sha3::{Digest, Sha3_256};
/// 交易类型
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum TransactionType {
/// XTZH转账
XTZHTransfer = 0,
/// XIC转账
XICTransfer = 1,
/// ACC-20代币转账
ACC20Transfer = 2,
/// ACC-1400证券型代币转账
ACC1400Transfer = 3,
/// 合约部署
ContractDeploy = 4,
/// 合约调用
ContractCall = 5,
/// 资产发行
AssetIssuance = 6,
}
/// 交易载荷(原始交易数据)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionPayload {
/// 交易类型
pub tx_type: TransactionType,
/// 发送方地址
pub from: [u8; 32],
/// 接收方地址
pub to: [u8; 32],
/// 金额对于XTZH/XIC/ACC-20
pub amount: u64,
/// 资产GNACS编码对于ACC-20/ACC-1400
pub asset_gnacs: Option<[u8; 6]>,
/// 分区ID对于ACC-1400
pub partition_id: Option<[u8; 32]>,
/// 附加数据(合约调用参数等)
pub data: Vec<u8>,
/// Nonce防重放
pub nonce: u64,
/// Gas限制
pub gas_limit: u64,
/// Gas价格XIC
pub gas_price: u64,
/// 时间戳
pub timestamp: u64,
}
impl TransactionPayload {
/// 创建XTZH转账交易
pub fn new_xtzh_transfer(
from: [u8; 32],
to: [u8; 32],
amount: u64,
nonce: u64,
) -> Self {
Self {
tx_type: TransactionType::XTZHTransfer,
from,
to,
amount,
asset_gnacs: None,
partition_id: None,
data: Vec::new(),
nonce,
gas_limit: 21000, // 基础转账Gas
gas_price: 1,
timestamp: Self::current_timestamp(),
}
}
/// 创建XIC转账交易
pub fn new_xic_transfer(
from: [u8; 32],
to: [u8; 32],
amount: u64,
nonce: u64,
) -> Self {
Self {
tx_type: TransactionType::XICTransfer,
from,
to,
amount,
asset_gnacs: None,
partition_id: None,
data: Vec::new(),
nonce,
gas_limit: 21000,
gas_price: 1,
timestamp: Self::current_timestamp(),
}
}
/// 创建ACC-20代币转账交易
pub fn new_acc20_transfer(
from: [u8; 32],
to: [u8; 32],
amount: u64,
asset_gnacs: [u8; 6],
nonce: u64,
) -> Self {
Self {
tx_type: TransactionType::ACC20Transfer,
from,
to,
amount,
asset_gnacs: Some(asset_gnacs),
partition_id: None,
data: Vec::new(),
nonce,
gas_limit: 50000, // 代币转账需要更多Gas
gas_price: 1,
timestamp: Self::current_timestamp(),
}
}
/// 创建ACC-1400证券型代币转账交易
pub fn new_acc1400_transfer(
from: [u8; 32],
to: [u8; 32],
amount: u64,
asset_gnacs: [u8; 6],
partition_id: [u8; 32],
nonce: u64,
) -> Self {
Self {
tx_type: TransactionType::ACC1400Transfer,
from,
to,
amount,
asset_gnacs: Some(asset_gnacs),
partition_id: Some(partition_id),
data: Vec::new(),
nonce,
gas_limit: 80000, // 证券型代币需要更多Gas合规检查
gas_price: 1,
timestamp: Self::current_timestamp(),
}
}
/// 计算交易哈希
pub fn hash(&self) -> [u8; 32] {
let serialized = bincode::serialize(self).unwrap_or_default();
let mut hasher = Sha3_256::new();
hasher.update(&serialized);
let result = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&result);
hash
}
/// 获取当前时间戳
fn current_timestamp() -> u64 {
// TODO: 使用系统时间
0
}
/// 估算Gas费用XIC
pub fn estimate_gas_fee(&self) -> u64 {
self.gas_limit * self.gas_price
}
}
/// 完整交易包含CR
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
/// 交易载荷
pub payload: TransactionPayload,
/// 宪法收据
pub receipt: Option<ConstitutionalReceipt>,
/// 签名
pub signature: Vec<u8>,
}
impl Transaction {
/// 创建新交易(未签名)
pub fn new(payload: TransactionPayload) -> Self {
Self {
payload,
receipt: None,
signature: Vec::new(),
}
}
/// 附加宪法收据
pub fn attach_receipt(&mut self, receipt: ConstitutionalReceipt) {
self.receipt = Some(receipt);
}
/// 签名交易
pub fn sign(&mut self, signature: Vec<u8>) {
self.signature = signature;
}
/// 计算签名消息(交易体+CR的联合哈希
pub fn signing_message(&self) -> [u8; 32] {
let mut hasher = Sha3_256::new();
// 添加交易载荷哈希
hasher.update(&self.payload.hash());
// 如果有CR添加CR哈希
if let Some(ref receipt) = self.receipt {
hasher.update(&receipt.transaction_hash);
}
let result = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&result);
hash
}
/// 验证交易完整性
pub fn verify(&self) -> Result<(), String> {
// 检查是否有CR
if self.receipt.is_none() {
return Err("Missing constitutional receipt".to_string());
}
// 检查是否已签名
if self.signature.is_empty() {
return Err("Transaction not signed".to_string());
}
// 验证CR
if let Some(ref receipt) = self.receipt {
if !receipt.verify() {
return Err("Invalid constitutional receipt".to_string());
}
// 验证CR的交易哈希是否匹配
if receipt.transaction_hash != self.payload.hash() {
return Err("Constitutional receipt hash mismatch".to_string());
}
}
Ok(())
}
/// 序列化为字节(用于广播)
pub fn to_bytes(&self) -> Result<Vec<u8>, String> {
bincode::serialize(self).map_err(|e| format!("Serialization error: {}", e))
}
/// 从字节反序列化
pub fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
bincode::deserialize(bytes).map_err(|e| format!("Deserialization error: {}", e))
}
}
/// 交易构造器Builder模式
pub struct TransactionBuilder {
tx_type: TransactionType,
from: Option<[u8; 32]>,
to: Option<[u8; 32]>,
amount: u64,
asset_gnacs: Option<[u8; 6]>,
partition_id: Option<[u8; 32]>,
data: Vec<u8>,
nonce: u64,
gas_limit: u64,
gas_price: u64,
}
impl TransactionBuilder {
/// 创建新的构造器
pub fn new(tx_type: TransactionType) -> Self {
let default_gas = match tx_type {
TransactionType::XTZHTransfer | TransactionType::XICTransfer => 21000,
TransactionType::ACC20Transfer => 50000,
TransactionType::ACC1400Transfer => 80000,
TransactionType::ContractDeploy => 200000,
TransactionType::ContractCall => 100000,
TransactionType::AssetIssuance => 150000,
};
Self {
tx_type,
from: None,
to: None,
amount: 0,
asset_gnacs: None,
partition_id: None,
data: Vec::new(),
nonce: 0,
gas_limit: default_gas,
gas_price: 1,
}
}
/// 设置发送方
pub fn from(mut self, from: [u8; 32]) -> Self {
self.from = Some(from);
self
}
/// 设置接收方
pub fn to(mut self, to: [u8; 32]) -> Self {
self.to = Some(to);
self
}
/// 设置金额
pub fn amount(mut self, amount: u64) -> Self {
self.amount = amount;
self
}
/// 设置资产GNACS
pub fn asset_gnacs(mut self, gnacs: [u8; 6]) -> Self {
self.asset_gnacs = Some(gnacs);
self
}
/// 设置分区ID
pub fn partition_id(mut self, partition_id: [u8; 32]) -> Self {
self.partition_id = Some(partition_id);
self
}
/// 设置附加数据
pub fn data(mut self, data: Vec<u8>) -> Self {
self.data = data;
self
}
/// 设置nonce
pub fn nonce(mut self, nonce: u64) -> Self {
self.nonce = nonce;
self
}
/// 设置Gas限制
pub fn gas_limit(mut self, gas_limit: u64) -> Self {
self.gas_limit = gas_limit;
self
}
/// 设置Gas价格
pub fn gas_price(mut self, gas_price: u64) -> Self {
self.gas_price = gas_price;
self
}
/// 构建交易
pub fn build(self) -> Result<Transaction, String> {
let from = self.from.ok_or("Missing 'from' address")?;
let to = self.to.ok_or("Missing 'to' address")?;
let payload = TransactionPayload {
tx_type: self.tx_type,
from,
to,
amount: self.amount,
asset_gnacs: self.asset_gnacs,
partition_id: self.partition_id,
data: self.data,
nonce: self.nonce,
gas_limit: self.gas_limit,
gas_price: self.gas_price,
timestamp: TransactionPayload::current_timestamp(),
};
Ok(Transaction::new(payload))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xtzh_transfer() {
let from = [1u8; 32];
let to = [2u8; 32];
let payload = TransactionPayload::new_xtzh_transfer(from, to, 1000000, 1);
assert_eq!(payload.tx_type, TransactionType::XTZHTransfer);
assert_eq!(payload.amount, 1000000);
assert_eq!(payload.gas_limit, 21000);
}
#[test]
fn test_transaction_builder() {
let from = [1u8; 32];
let to = [2u8; 32];
let tx = TransactionBuilder::new(TransactionType::XTZHTransfer)
.from(from)
.to(to)
.amount(1000000)
.nonce(1)
.build()
.unwrap();
assert_eq!(tx.payload.amount, 1000000);
}
#[test]
fn test_transaction_hash() {
let from = [1u8; 32];
let to = [2u8; 32];
let payload = TransactionPayload::new_xtzh_transfer(from, to, 1000000, 1);
let hash1 = payload.hash();
let hash2 = payload.hash();
assert_eq!(hash1, hash2); // 相同输入应产生相同哈希
}
}