Day 4 Sophia 智能合约基础
学习 Sophia 语言语法和合约编译流程。
学习目标
- 学习 Sophia 语言基础语法
- 理解智能合约的基本结构
- 掌握合约编译流程
- 生成和解析 Calldata
1. Sophia 语言概述
1.1 语言特性
| 特性 | 说明 |
|---|---|
| 函数式 | 基于 ML 家族,无副作用 |
| 强类型 | 编译时类型检查 |
| 状态受限 | 状态修改必须显式声明 |
| 安全优先 | 防止常见漏洞 |
| FATE 编译 | 高效的虚拟机执行 |
1.2 与 Solidity 对比
| 特性 | Sophia | Solidity |
|---|---|---|
| 范式 | 函数式 | 面向对象 |
| 类型系统 | 强类型、推断 | 强类型、显式 |
| 状态修改 | stateful 关键字 | 默认可修改 |
| 重入攻击 | 语言级防护 | 需手动防护 |
| 整数溢出 | 自动检查 | 需 SafeMath |
2. 合约结构
2.1 基本结构
// 编译器版本要求
@compiler >= 6
// 合约定义
contract MyContract =
// 状态定义
record state = {
owner : address,
value : int
}
// 初始化函数(构造函数)
entrypoint init(initial_value : int) = {
owner = Call.caller,
value = initial_value
}
// 只读函数(不修改状态)
entrypoint get_value() : int =
state.value
// 状态修改函数
stateful entrypoint set_value(new_value : int) =
put(state{ value = new_value })
2.2 函数修饰符
| 修饰符 | 说明 |
|---|---|
entrypoint | 外部可调用 |
function | 内部函数 |
stateful | 可修改状态 |
payable | 可接收 AE |
private | 私有函数 |
2.3 数据类型
// 基础类型
let a : int = 42 // 整数(任意精度)
let b : bool = true // 布尔
let c : string = "hello" // 字符串
let d : address = ak_xxx // 地址
let e : hash = #abc123 // 哈希
// 复合类型
let g : list(int) = [1, 2, 3] // 列表
let h : option(int) = Some(42) // 可选值
let i : map(string, int) = {} // 映射
let j : (int, string) = (1, "a") // 元组
// 自定义类型
record person = { name : string, age : int }
datatype color = Red | Green | Blue
3. 实践任务
任务 4.1: 编写简单存储合约
from aeternity.compiler import CompilerClient
# 简单存储合约
simple_storage = '''
@compiler >= 6
contract SimpleStorage =
record state = { value : int }
entrypoint init(initial : int) = { value = initial }
entrypoint get() : int = state.value
stateful entrypoint set(new_value : int) =
put(state{ value = new_value })
stateful entrypoint add(amount : int) =
put(state{ value = state.value + amount })
'''
# 编译合约
compiler = CompilerClient()
try:
bytecode = compiler.compile(simple_storage)
print("✅ 编译成功!")
print(f"字节码长度: {len(bytecode)} 字符")
print(f"字节码: {bytecode[:50]}...")
except Exception as e:
print(f"❌ 编译失败: {e}")
任务 4.2: 理解 ACI
from aeternity.compiler import CompilerClient
import json
compiler = CompilerClient()
# 合约源码
contract_source = '''
@compiler >= 6
contract Calculator =
entrypoint add(a : int, b : int) : int = a + b
entrypoint sub(a : int, b : int) : int = a - b
entrypoint mul(a : int, b : int) : int = a * b
entrypoint div(a : int, b : int) : int = a / b
'''
# 生成 ACI (Application Contract Interface)
aci = compiler.generate_aci(contract_source)
print("=== ACI (Application Contract Interface) ===\n")
print(json.dumps(aci, indent=2))
# 解析函数信息
print("\n=== 函数列表 ===")
contract_info = aci.get('contract', {})
for func in contract_info.get('functions', []):
name = func.get('name')
args = func.get('arguments', [])
returns = func.get('returns')
args_str = ", ".join([f"{a['name']}: {a['type']}" for a in args])
print(f" {name}({args_str}) -> {returns}")
任务 4.3: 生成 Calldata
from aeternity.compiler import CompilerClient
compiler = CompilerClient()
contract_source = '''
@compiler >= 6
contract Demo =
entrypoint init(value : int) = value
entrypoint greet(name : string) : string =
String.concat("Hello, ", name)
entrypoint add(a : int, b : int) : int = a + b
'''
# 编译合约
bytecode = compiler.compile(contract_source)
print("=== 生成 Calldata ===\n")
# 1. init 函数的 calldata
init_calldata = compiler.encode_calldata(contract_source, "init", ["42"])
print(f"init(42):")
print(f" Calldata: {init_calldata[:50]}...")
# 2. greet 函数的 calldata
greet_calldata = compiler.encode_calldata(contract_source, "greet", ['"World"'])
print(f"\ngreet(\"World\"):")
print(f" Calldata: {greet_calldata[:50]}...")
# 3. add 函数的 calldata
add_calldata = compiler.encode_calldata(contract_source, "add", ["10", "20"])
print(f"\nadd(10, 20):")
print(f" Calldata: {add_calldata[:50]}...")
# 参数格式说明
print("""
=== 参数格式说明 ===
- int: "42", "-1", "1000000"
- string: '"hello"' (需要引号)
- bool: "true", "false"
- address: '"ak_xxx..."'
- list: "[1, 2, 3]"
- tuple: "(1, \"hello\")"
- record: "{ name = \"test\", value = 42 }"
""")
任务 4.4: 控制流和高阶函数
@compiler >= 6
contract ControlFlow =
// if-else 表达式
entrypoint abs(x : int) : int =
if(x >= 0) x else -x
// 模式匹配
entrypoint describe(n : int) : string =
switch(n)
0 => "zero"
1 => "one"
_ => "many"
// Option 处理
entrypoint safe_div(a : int, b : int) : option(int) =
if(b == 0)
None
else
Some(a / b)
// 列表操作
entrypoint sum(xs : list(int)) : int =
List.sum(xs)
entrypoint double_all(xs : list(int)) : list(int) =
List.map((x) => x * 2, xs)
entrypoint filter_positive(xs : list(int)) : list(int) =
List.filter((x) => x > 0, xs)
// 递归
entrypoint factorial(n : int) : int =
if(n <= 1) 1
else n * factorial(n - 1)
4. 练习题
@compiler >= 6
contract Counter =
record state = { count : int }
entrypoint init() = { count = 0 }
entrypoint get() : int = state.count
stateful entrypoint increment() =
put(state{ count = state.count + 1 })
stateful entrypoint decrement() =
put(state{ count = state.count - 1 })
stateful entrypoint reset() =
put(state{ count = 0 })
@compiler >= 6
contract Voting =
record state = {
votes : map(string, int),
voted : map(address, bool)
}
entrypoint init() = {
votes = {},
voted = {}
}
entrypoint get_votes(candidate : string) : int =
Map.lookup_default(candidate, state.votes, 0)
entrypoint has_voted(voter : address) : bool =
Map.lookup_default(voter, state.voted, false)
stateful entrypoint vote(candidate : string) =
require(!has_voted(Call.caller), "Already voted")
let current = get_votes(candidate)
put(state{
votes = state.votes{ [candidate] = current + 1 },
voted = state.voted{ [Call.caller] = true }
})
知识检查点
- 理解 Sophia 语言特性
- 编写基本的合约结构
- 使用各种数据类型
- 使用编译器编译合约
- 生成和解码 Calldata
本页目录
预计: 3-4 小时