名称:multiversx-protocol-experts 描述:深入了解MultiversX架构,包括分片、共识、ESDT标准和跨分片交易。用于审查协议级代码、设计复杂dApp架构或解决跨分片问题时使用。
MultiversX协议专业知识
对MultiversX协议架构的深度技术知识,用于审查协议级变更、设计涉及跨分片逻辑的复杂dApp架构,以及主权链集成。
使用时机
- 审查协议级代码变更
- 设计跨分片智能合约交互
- 故障排除异步交易问题
- 理解代币标准实现
- 处理主权链集成
- 优化分片架构
1. 核心架构:自适应状态分片
MultiversX同时实施网络、交易和状态分片。分片分配:地址最后一个字节 % 分片数量。
元链
协调分片处理:验证器洗牌、纪元转换、系统智能合约(质押、ESDT发行、委托、治理)以及分片块公证。
重要:元链不执行通用智能合约。合约地址决定哪个分片处理其交易。
2. 跨分片交易
交易流程
当发送方和接收方在不同分片上时:
1. 发送方分片:处理交易,生成智能合约结果(SCR)
2. 元链:公证发送方块,中继SCR
3. 接收方分片:执行SCR,完成交易
原子性保证
关键属性:跨分片交易是原子性的,但是异步的。
// 这个跨分片调用是原子性的
self.tx()
.to(&other_contract) // 可能在不同分片
.typed(other_contract_proxy::OtherContractProxy)
.some_endpoint(args)
.async_call_and_exit();
// 要么双方都成功,要么双方都回滚
// 但发送方执行和接收方执行之间有延迟
回调处理
#[endpoint]
fn cross_shard_call(&self) {
// 这里的状态变化立即发生(发送方分片)
self.pending_calls().set(true);
self.tx()
.to(&other_contract)
.typed(proxy::Proxy)
.remote_function()
.callback(self.callbacks().on_result())
.async_call_and_exit();
}
#[callback]
fn on_result(&self, #[call_result] result: ManagedAsyncCallResult<BigUint>) {
// 这稍后执行,回到发送方分片
// 在接收方分片处理后
match result {
ManagedAsyncCallResult::Ok(value) => {
// 远程调用成功
self.pending_calls().set(false);
},
ManagedAsyncCallResult::Err(_) => {
// 远程调用失败
// 原始状态变化不会自动回滚!
// 必须手动处理回滚
self.pending_calls().set(false);
self.handle_failure();
}
}
}
3. 共识:安全权益证明(SPoS)
验证器选择基于:权益量、评级(性能历史)和随机种子(前一个块)。区块生产在提议/验证/提交阶段使用BLS多重签名。
终局性
- 分片内:约0.6秒每轮(Supernova)
- 跨分片:约2-3秒(在接收方分片处理后)
4. 代币标准(ESDT)
ESDT代币是协议级的(非智能合约)。余额直接存储在账户状态中——基本操作不需要合约。
ESDT属性
| 属性 | 描述 | 安全含义 |
|---|---|---|
| CanFreeze | 协议可以冻结资产 | 应急响应能力 |
| CanWipe | 协议可以销毁资产 | 法规合规 |
| CanPause | 协议可以暂停转移 | 断路器 |
| CanMint | 地址可以铸造新代币 | 通胀控制 |
| CanBurn | 地址可以燃烧代币 | 供应控制 |
| CanChangeOwner | 所有权可转移 | 管理员密钥轮换 |
| CanUpgrade | 属性可以修改 | 灵活性与不变性 |
ESDT角色
// 角色按每个地址每个代币分配
ESDTRoleLocalMint // 可以铸造代币
ESDTRoleLocalBurn // 可以燃烧代币
ESDTRoleNFTCreate // 可以创建NFT/SFT nonces
ESDTRoleNFTBurn // 可以燃烧NFT/SFT
ESDTRoleNFTAddQuantity // 可以增加SFT数量
ESDTRoleNFTUpdateAttributes // 可以更新NFT属性
ESDTTransferRole // 受限制转移所需
代币转移类型
| 转移类型 | 功能 | 使用场景 |
|---|---|---|
| ESDTTransfer | 可替代代币转移 | 简单代币发送 |
| ESDTNFTTransfer | 单个NFT/SFT转移 | NFT市场 |
| MultiESDTNFTTransfer | 批量转移 | 带有多个代币的合约调用 |
5. 内置函数
转移函数
ESDTTransfer@<token_id>@<amount>
ESDTNFTTransfer@<token_id>@<nonce>@<amount>@<receiver>
MultiESDTNFTTransfer@<receiver>@<num_tokens>@<token1_id>@<nonce1>@<amount1>@...
带支付的合约调用
MultiESDTNFTTransfer@<contract>@<num_tokens>@<token_data>...@<function>@<args>...
直接ESDT操作
ESDTLocalMint@<token_id>@<amount>
ESDTLocalBurn@<token_id>@<amount>
ESDTNFTCreate@<token_id>@<initial_quantity>@<name>@<royalties>@<hash>@<attributes>@<uris>
6. 主权链与互操作性
主权链架构
MultiversX主链(L1)
│
├── 主权链A(L2)
│ └── 网关合约
│
└── 主权链B(L2)
└── 网关合约
跨链通信
// 主链 → 主权链:存款流程
1. 用户向主链上的网关合约存款代币
2. 网关发出存款事件
3. 主权链验证器观察事件
4. 代币在主权链上铸造
// 主权链 → 主链:提款流程
1. 用户在主权链上发起提款
2. 主权链验证器创建证明
3. 证明提交到主链网关
4. 代币在主链上释放
安全考虑
| 风险 | 缓解措施 |
|---|---|
| 桥资金被盗 | 多重签名验证器、时间锁 |
| 无效证明 | 密码学验证 |
| 重组攻击 | 在处前等待终局性 |
| 验证器共谋 | 罚没、权益要求 |
7. 协议开发者的关键检查
分片内与跨分片意识
// 错误:假设同步执行
#[endpoint]
fn process_and_transfer(&self) {
let result = self.external_contract().compute_value(); // 可能是异步!
self.storage().set(result); // result可能是回调,不是值
}
// 正确:显式处理异步
#[endpoint]
fn process_and_transfer(&self) {
self.tx()
.to(&self.external_contract().get())
.typed(proxy::Proxy)
.compute_value()
.callback(self.callbacks().handle_result())
.async_call_and_exit();
}
#[callback]
fn handle_result(&self, #[call_result] result: ManagedAsyncCallResult<BigUint>) {
match result {
ManagedAsyncCallResult::Ok(value) => {
self.storage().set(value);
},
ManagedAsyncCallResult::Err(_) => {
// 处理失败
}
}
}
微服务的重组处理
// 错误:立即处理
async function handleTransaction(tx: Transaction) {
await processPayment(tx); // 如果块被回滚了怎么办?
}
// 正确:等待终局性
async function handleTransaction(tx: Transaction) {
// 等待终局性(可配置轮次)
await waitForFinality(tx.hash, { rounds: 3 });
// 或仅订阅最终化块
const status = await getTransactionStatus(tx.hash);
if (status === 'finalized') {
await processPayment(tx);
}
}
跨分片的燃气考虑
// 跨分片调用在两个分片上都消耗燃气
// 发送方:发起调用 + 回调执行的燃气
// 接收方:执行被调用函数的燃气
// 为回调预留足够燃气
const GAS_FOR_CALLBACK: u64 = 10_000_000;
const GAS_FOR_REMOTE: u64 = 20_000_000;
#[endpoint]
fn cross_shard_call(&self) {
self.tx()
.to(&other_contract)
.typed(proxy::Proxy)
.remote_function()
.gas(GAS_FOR_REMOTE)
.callback(self.callbacks().on_result())
.with_extra_gas_for_callback(GAS_FOR_CALLBACK)
.async_call_and_exit();
}
8. MIP标准参考
监控MultiversX改进提案以获取标准实现:
| MIP | 主题 | 状态 |
|---|---|---|
| MIP-2 | 分数NFT(SFT标准) | 已实施 |
| MIP-3 | 动态NFT | 已实施 |
| MIP-4 | 代币版税 | 已实施 |
9. 网络常量
| 常量 | 值 | 注释 |
|---|---|---|
| 最大分片 | 3 + 元链 | 当前主网配置 |
| 轮次时长 | 约0.6秒 | 块时间(Supernova) |
| 纪远时长 | 约24小时 | 验证器重新洗牌周期 |
| 最大交易大小 | 256 KB | 交易数据限制 |
| 最大燃气限制 | 600,000,000 | 每笔交易 |