跳到主要内容

合约运行时

Savitri 合约运行时在沙箱环境中执行智能合约,具备 Gas 计量、存储隔离和事件发射功能。

执行流程

Contract Call TX arrives


BaseContract validation
│ check paused, owner, reserved slots

Gas Meter initialization
│ gas_limit from TX fee

ContractStorage setup
│ load contract state, init cache

Function dispatch
│ match function_selector → handler

Execution (with gas tracking)
│ SLOAD, SSTORE, events, calls

Result
├── Success → commit storage, emit events
└── Failure → revert all changes

BaseContract

所有合约均继承 BaseContract,槽 0-99 为保留槽:

槽位字段大小描述
0owner32 字节合约所有者地址
1versionu64合约版本
2governance_hookbool治理集成是否启用
3fee_hookbool自定义费用逻辑是否启用
4pausedbool合约暂停状态
5-99保留-供将来使用

BaseContract 函数

函数访问权限描述
owner()公开获取合约所有者
transfer_ownership(new_owner)仅所有者转移所有权
version()公开获取合约版本
upgrade(new_version)仅所有者升级合约
pause()仅所有者暂停所有操作
unpause()仅所有者恢复操作

Gas 计量

Gas 费用

操作Gas描述
SLOAD100存储读取
SSTORE(新建)20,000存储写入(空槽)
SSTORE(更新)5,000存储写入(已有槽)
CALL2,300跨合约调用
CREATE32,000合约部署
TRANSFER300代币转账
LOG375事件发射(基础)
LOG_TOPIC375每个额外主题
LOG_DATA8每字节事件数据
CALLDATA16每字节调用数据

批量计费

Gas 计量器采用批量计费(每批 100 次操作)以减少开销。Gas 按批次提交,而非逐操作提交。

Gas 上限

Gas 上限由交易费用派生:

gas_limit = tx.fee / gas_price

若执行过程中 Gas 耗尽,整个交易将回滚。

合约存储

基于槽的模型

每个合约拥有独立的键值存储,键为 u64 槽编号,值为 32 字节数组。

槽派生

对于映射,使用 Keccak256 派生槽以防止冲突:

// Simple value
slot = FIXED_SLOT_NUMBER

// Mapping (address → value)
slot = keccak256(address || base_slot)[0..8] as u64

// Nested mapping (address → address → value)
inner = keccak256(outer_key || base_slot)
slot = keccak256(inner_key || inner)[0..8] as u64

Merkle 树

合约存储维护一棵 Merkle 树用于生成状态证明。

事件系统

合约向外部消费者发出事件:

pub struct CustomEvent {
pub event_type: String, // e.g., "Transfer", "Approval"
pub topics: Vec<Vec<u8>>, // indexed fields
pub data: Vec<u8>, // non-indexed data
}

标准事件(来自 BaseContract):

  • OwnershipTransferred(old_owner, new_owner)
  • ContractUpgraded(old_version, new_version)
  • Paused(by)
  • Unpaused(by)

合约部署

1. Create DeployTransaction (to = None, data = bytecode)
2. Assign contract address (derived from deployer + nonce)
3. Initialize BaseContract (set owner, version)
4. Run contract constructor (initialize function)
5. Store ContractInfo in CF_CONTRACTS
6. Emit ContractDeployed event

合约调用

1. Parse function_selector from TX data
2. Load contract from CF_CONTRACTS
3. Check BaseContract state (not paused, etc.)
4. Initialize GasMeter with gas_limit
5. Execute function with ContractStorage
6. If success: commit storage changes, deduct gas
7. If failure: revert all changes

EVM 解释器

evm_interpreter 模块提供基本 EVM 字节码执行,以兼容以太坊合约。这使得可以将 Solidity 编译的合约部署到 Savitri 上。

内存监控

memory_monitor 跟踪运行时内存使用情况以防止拒绝服务攻击:

  • 每个合约的内存限制
  • 分配跟踪
  • 超出限制时自动终止

并行执行

parallel 模块为独立交易启用并行合约执行:

  • 分析交易之间的依赖关系
  • 检测存储槽冲突
  • 并行执行无冲突的交易
  • 有冲突的交易回退为串行执行

合约追踪

tracing 模块提供用于调试的执行追踪:

  • 逐步执行日志
  • 存储读写追踪
  • 每次操作的 Gas 消耗
  • 事件发射日志