219 lines
5.0 KiB
Rust
219 lines
5.0 KiB
Rust
// NVM-L1 合约定义
|
|
|
|
use crate::types::{Address, Hash};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// 合约代码
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ContractCode {
|
|
/// 字节码
|
|
pub bytecode: Vec<u8>,
|
|
/// 代码哈希
|
|
pub code_hash: Hash,
|
|
}
|
|
|
|
impl ContractCode {
|
|
/// 创建新的合约代码
|
|
pub fn new(bytecode: Vec<u8>) -> Self {
|
|
let code_hash = Hash::sha3_384(&bytecode);
|
|
Self {
|
|
bytecode,
|
|
code_hash,
|
|
}
|
|
}
|
|
|
|
/// 获取字节码
|
|
pub fn bytecode(&self) -> &[u8] {
|
|
&self.bytecode
|
|
}
|
|
|
|
/// 获取代码哈希
|
|
pub fn code_hash(&self) -> &Hash {
|
|
&self.code_hash
|
|
}
|
|
|
|
/// 获取代码大小
|
|
pub fn size(&self) -> usize {
|
|
self.bytecode.len()
|
|
}
|
|
}
|
|
|
|
/// 合约元数据
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ContractMetadata {
|
|
/// 合约名称
|
|
pub name: String,
|
|
/// 合约版本
|
|
pub version: String,
|
|
/// 合约作者
|
|
pub author: String,
|
|
/// 合约描述
|
|
pub description: String,
|
|
/// 创建时间
|
|
pub created_at: u64,
|
|
}
|
|
|
|
impl Default for ContractMetadata {
|
|
fn default() -> Self {
|
|
Self {
|
|
name: String::new(),
|
|
version: "1.0.0".to_string(),
|
|
author: String::new(),
|
|
description: String::new(),
|
|
created_at: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 合约状态
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum ContractState {
|
|
/// 活跃
|
|
Active,
|
|
/// 暂停
|
|
Paused,
|
|
/// 已销毁
|
|
Destroyed,
|
|
}
|
|
|
|
/// 合约
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Contract {
|
|
/// 合约地址
|
|
pub address: Address,
|
|
/// 合约代码
|
|
pub code: ContractCode,
|
|
/// 合约元数据
|
|
pub metadata: ContractMetadata,
|
|
/// 合约状态
|
|
pub state: ContractState,
|
|
/// 合约所有者
|
|
pub owner: Address,
|
|
/// 合约余额
|
|
pub holdings: u128,
|
|
/// 存储根哈希
|
|
pub storage_root: Hash,
|
|
/// Nonce
|
|
pub nonce: u64,
|
|
}
|
|
|
|
impl Contract {
|
|
/// 创建新合约
|
|
pub fn new(
|
|
address: Address,
|
|
code: ContractCode,
|
|
owner: Address,
|
|
metadata: ContractMetadata,
|
|
) -> Self {
|
|
Self {
|
|
address,
|
|
code,
|
|
metadata,
|
|
state: ContractState::Active,
|
|
owner,
|
|
holdings: 0,
|
|
storage_root: Hash::zero(),
|
|
nonce: 0,
|
|
}
|
|
}
|
|
|
|
/// 检查合约是否活跃
|
|
pub fn is_active(&self) -> bool {
|
|
self.state == ContractState::Active
|
|
}
|
|
|
|
/// 暂停合约
|
|
pub fn pause(&mut self) {
|
|
self.state = ContractState::Paused;
|
|
}
|
|
|
|
/// 恢复合约
|
|
pub fn resume(&mut self) {
|
|
self.state = ContractState::Active;
|
|
}
|
|
|
|
/// 销毁合约
|
|
pub fn destroy(&mut self) {
|
|
self.state = ContractState::Destroyed;
|
|
}
|
|
|
|
/// 增加余额
|
|
pub fn add_balance(&mut self, amount: u128) {
|
|
self.holdings = self.holdings.saturating_add(amount);
|
|
}
|
|
|
|
/// 减少余额
|
|
pub fn sub_balance(&mut self, amount: u128) -> Result<(), String> {
|
|
if self.holdings < amount {
|
|
return Err("Insufficient holdings".to_string());
|
|
}
|
|
self.holdings -= amount;
|
|
Ok(())
|
|
}
|
|
|
|
/// 增加nonce
|
|
pub fn increment_nonce(&mut self) {
|
|
self.nonce = self.nonce.saturating_add(1);
|
|
}
|
|
|
|
/// 更新存储根
|
|
pub fn update_storage_root(&mut self, root: Hash) {
|
|
self.storage_root = root;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn create_test_contract() -> Contract {
|
|
let address = Address::new([1u8; 20]);
|
|
let owner = Address::new([2u8; 20]);
|
|
let code = ContractCode::new(vec![0x60, 0x60, 0x60, 0x40]);
|
|
let metadata = ContractMetadata::default();
|
|
Contract::new(address, code, owner, metadata)
|
|
}
|
|
|
|
#[test]
|
|
fn test_contract_creation() {
|
|
let contract = create_test_contract();
|
|
assert!(contract.is_active());
|
|
assert_eq!(contract.holdings, 0);
|
|
assert_eq!(contract.nonce, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_contract_pause_resume() {
|
|
let mut contract = create_test_contract();
|
|
contract.pause();
|
|
assert!(!contract.is_active());
|
|
contract.resume();
|
|
assert!(contract.is_active());
|
|
}
|
|
|
|
#[test]
|
|
fn test_contract_balance() {
|
|
let mut contract = create_test_contract();
|
|
contract.add_balance(1000);
|
|
assert_eq!(contract.holdings, 1000);
|
|
assert!(contract.sub_balance(500).is_ok());
|
|
assert_eq!(contract.holdings, 500);
|
|
}
|
|
|
|
#[test]
|
|
fn test_contract_nonce() {
|
|
let mut contract = create_test_contract();
|
|
contract.increment_nonce();
|
|
assert_eq!(contract.nonce, 1);
|
|
contract.increment_nonce();
|
|
assert_eq!(contract.nonce, 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_contract_destroy() {
|
|
let mut contract = create_test_contract();
|
|
contract.destroy();
|
|
assert_eq!(contract.state, ContractState::Destroyed);
|
|
}
|
|
}
|