├── .gitignore ├── sip-2 ├── images │ ├── starcoin_consensue.png │ ├── starcoin_security.png │ ├── starcoin_block_proof.png │ └── starcoin_state_model.png └── index.zh.md ├── sip-3 ├── images │ ├── starcoin_ecosystem.png │ └── starcoin_block_reward.png ├── index.zh.md └── index.md ├── sip-1 ├── index.zh.md └── index.md ├── sip-5 ├── index.md └── index.zh.md ├── sip-4 ├── index.md └── index.zh.md ├── sip-21 ├── index.zh.md └── index.md ├── sip-20 ├── index.md └── index.zh.md ├── sip-23 ├── index.md └── index.zh.md ├── _index.zh.md ├── _index.md ├── README.md ├── sip-22 ├── index.zh.md └── index.md ├── sip-6 ├── index.zh.md ├── images │ ├── cross_layer_contract.svg │ ├── stargate_layers_arch.svg │ └── crosslayer_state_moving.svg └── index.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .jekyll-cache 2 | .DS_Store -------------------------------------------------------------------------------- /sip-2/images/starcoin_consensue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-2/images/starcoin_consensue.png -------------------------------------------------------------------------------- /sip-2/images/starcoin_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-2/images/starcoin_security.png -------------------------------------------------------------------------------- /sip-3/images/starcoin_ecosystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-3/images/starcoin_ecosystem.png -------------------------------------------------------------------------------- /sip-2/images/starcoin_block_proof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-2/images/starcoin_block_proof.png -------------------------------------------------------------------------------- /sip-2/images/starcoin_state_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-2/images/starcoin_state_model.png -------------------------------------------------------------------------------- /sip-3/images/starcoin_block_reward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/starcoinorg/sips/HEAD/sip-3/images/starcoin_block_reward.png -------------------------------------------------------------------------------- /sip-1/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 1 3 | title: "[SIP1] SIP 提案指南" 4 | author: Starcoin Core Dev 5 | sip_type: Standards Track 6 | category: Core 7 | status: Beta 8 | created: 2021-11-01 9 | weight: 1 10 | --- 11 | 12 | # SIP 提案指南 13 | -------------------------------------------------------------------------------- /sip-1/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 1 3 | title: "[SIP1] SIP Purpose and Guidelines" 4 | author: Starcoin Core Dev 5 | sip_type: Standards Track 6 | category: Core 7 | status: Beta 8 | created: 2020-11-01 9 | weight: 1 10 | --- 11 | 12 | # SIP Purpose and Guidelines -------------------------------------------------------------------------------- /sip-5/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 5 3 | title: "[SIP5] Introduce Treasury" 4 | author: "@jolestar" 5 | sip_type: paper 6 | category: Core 7 | status: Beta 8 | created: 2021-4-13 9 | weight: 5 10 | --- 11 | 12 | # Introduce Treasury 13 | 14 | 15 | 16 | {{< todo >}} -------------------------------------------------------------------------------- /sip-4/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 4 3 | title: "[SIP4] SIP as feature flag" 4 | author: Starcoin Core Dev 5 | sip_type: paper 6 | category: Core 7 | status: Beta 8 | created: 2021-11-01 9 | weight: 4 10 | --- 11 | 12 | # SIP as feature flag 13 | 14 | 15 | 16 | {{< todo >}} -------------------------------------------------------------------------------- /sip-21/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 21 3 | title: "[SIP21] 收款识别码(Receipt Identifier)" 4 | author: "@lerencao" 5 | sip_type: SDK 6 | category: SDK 7 | status: Alpha 8 | created: 2021-05-06 9 | weight: 21 10 | --- 11 | 12 | ## 收款识别码(Receipt Identifier) 13 | 14 | 15 | 16 | 17 | {{< todo >}} -------------------------------------------------------------------------------- /sip-20/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 20 3 | title: "[SIP20] JSONRPC" 4 | author: "@lerencao" 5 | sip_type: API 6 | category: API 7 | status: Alpha 8 | created: 2020-11-17 9 | weight: 20 10 | --- 11 | 12 | # Unifying the JSONRPC API for parameter and return value types 13 | 14 | 15 | 16 | {{< todo >}} -------------------------------------------------------------------------------- /sip-23/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 23 3 | title: "[SIP23] Oracle" 4 | author: "@jolestar" 5 | sip_type: Standard 6 | category: Contract 7 | status: Alpha 8 | created: 2021-08-11 9 | weight: 23 10 | --- 11 | 12 | ## Oracle 13 | 14 | Oracle implementation and extension protocol 15 | 16 | 17 | {{< todo >}} -------------------------------------------------------------------------------- /_index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SIPs 3 | bookCollapseSection: true 4 | --- 5 | 6 | Starcoin 改进提案 7 | 8 | 9 | 10 | 1. [SIP 指南](./sip-1/) 11 | 2. [技术白皮书](./sip-2/) 12 | 3. [经济模型](./sip-3/) 13 | 4. [SIP as feature flag](./sip-4/) 14 | 5. [国库](./sip-5/) 15 | 6. [Stargate: 统一的分层协议框架](./sip-6) 16 | 20. [JSON RPC](./sip-20) 17 | 21. [Receipt Identifier](./sip-21) 18 | 22. [NFT](./sip-22/) 19 | 23. [Oracle](./sip-23/) 20 | -------------------------------------------------------------------------------- /_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SIPs 3 | bookCollapseSection: true 4 | --- 5 | 6 | Starcoin Improvement Proposals 7 | 8 | 9 | 10 | 1. [SIP Purpose and Guidelines](./sip-1/) 11 | 2. [Technical white paper](./sip-2/) 12 | 3. [Token Economics](./sip-3/) 13 | 4. [SIP as feature flag](./sip-4/) 14 | 5. [Introduce Treasury](./sip-5/) 15 | 6. [Stargate: Universal Layers Protocol Framework](./sip-6) 16 | 20. [JSON RPC](./sip-20) 17 | 21. [Receipt Identifier](./sip-21) 18 | 22. [NFT](./sip-22/) 19 | 23. [Oracle](./sip-23/) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | bookHidden: true 3 | --- 4 | # Starcoin Improvement Proposals (SIPs) 5 | 6 | [English](./_index.md)|[中文](_index.zh.md) 7 | 8 | 9 | ## Mission 10 | 11 | The goal of the SIP project is: 12 | 13 | 1. Document standardized protocols for Starcoin clients and applications. 14 | 2. Collect ideas and suggestions from the community about Starcoin's eco-projects, and the core development team can arrange the roadmap based on the suggestions, or encourage the community developers to build the eco-projects together through the [starcoin grant](https://grant.starcoin.org). 15 | 16 | ## Contributing 17 | 18 | 1. Submit an idea or suggestion about Starcoin's eco-projects to issue. 19 | 2. Write SIP documents for standardized protocols and submit PR. 20 | 21 | 22 | ## Support 23 | 24 | Reach out to the maintainer at one of the following places: 25 | 26 | - [Starcoin Discord](https://discord.gg/starcoin) 27 | - [Starcoin Contributor Telegram group](https://t.me/starcoin_contributor) -------------------------------------------------------------------------------- /sip-4/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 4 3 | title: "[SIP4] SIP 作为特性开关" 4 | author: Starcoin Core Dev 5 | sip_type: paper 6 | category: Core 7 | status: Draft 8 | created: 2021-04-11 9 | weight: 4 10 | --- 11 | 12 | # SIP 作为特性开关 13 | 14 | ## 动机 15 | 16 | 区块链上的协议如果需要升级,并且无法与旧的版本兼容,也是大家常说的『硬分叉』升级,通常的做法是通过高度设置一个特性开关(feature flag),约定好在某个高度激活该升级。但这种方式面临几个挑战: 17 | 18 | 1. 代码要合并进主分支的时候,就需要确定一个激活的高度,如果社区对是否支持该特性,以及激活时间不能达成一致,则会导致该特性的代码一直不能合并进入主代码分支,无法进入版本发布流程。 19 | 2. 代码合并进入主分支并发布版本后,到激活高度这段时间,是留给矿工(或者验证者)的"投票"时间,矿工通过是否升级来进行投票。如果大多数算力的矿工决定不升级,则会导致链分叉为两条。 20 | 21 | 按照 Starcoin 白皮书中的治理设计原则『技术创造可能,社区决定取舍』,我们对链上的协议升级做出了改进,通过链上的特性开关机制和 DAO 来实现不兼容性协议升级。 22 | 23 | 24 | ## 技术方案 25 | 26 | 定义一个链上的 SIP module,并提供判断方法来检测该 Module 是否存在,如果存在则认为改 SIP 已经激活。对 Feature Flag 的投票按照 stdlib 升级流程即可。 27 | 28 | 29 | ```move 30 | address 0x1{ 31 | module SIP_2{ 32 | } 33 | 34 | module SIP_2{ 35 | } 36 | 37 | } 38 | ``` 39 | 40 | 41 | 在链的代码框架中提供简便的方法来根据链的状态判断某个 SIP 是否激活。 42 | 43 | ```rust 44 | trait StateReader { 45 | 46 | is_activated(sip: SIP): bool; 47 | 48 | } 49 | ``` 50 | 51 | ## 升级流程 52 | 53 | 1. 用户或者社区开发者提出需要升级的特性需求,并提交 SIP 提案。 54 | 2. 核心开发者从技术角度评估该 SIP 并决定是否接受。 55 | 3. 接受的 SIP 进入开发流程,开发测试完成后,需要合并到主代码分支的时候,核心开发者只需要通过以下角度进行评估: 56 | * 实现的特性是否和 SIP 的目标相符。 57 | * 新的逻辑是否被特性开关控制,是否会影响旧的逻辑。 58 | * 是否满足技术性指标:比如性能,可维护性等。 59 | 4. 合并之后,新的版本中就会携带该特性的逻辑,但处于未激活状态,矿工正常升级即可。 60 | 5. 发起一次 stdlib 升级提案,该 stdlib 的版本中定义新的 SIP 的 flag Module, 呼吁社区进行投票,决定是否激活改特性, 以及激活的时间。 61 | 6. 投票通过,升级 stdlib, flag Module 写入链上,特性开关生效,全网启用新特性。 62 | 7. 投票未通过,该特性将一直处于未激活状态,等待必要的时候清理。 63 | 64 | 65 | ## 期望效果 66 | 67 | 加速功能以及版本的迭代速度,让争议后置处理。实现『技术创造可能,社区决定取舍』的目标。 68 | -------------------------------------------------------------------------------- /sip-3/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 3 3 | title: "[SIP3] 经济模型" 4 | author: Starcoin Foundation 5 | sip_type: paper 6 | category: Core 7 | status: Beta 8 | created: 2021-11-01 9 | weight: 3 10 | --- 11 | 12 | # Starcoin 经济白皮书 13 | 14 | STC 是 Starcoin 网络的原生 Token,发行总量为 3,185,136,000 STC,总量恒定。 15 | 16 | 它的当前的主要用途有: 17 | 18 | 1. 支付交易的 gas 费用。 19 | 2. 支付状态空间费用(未来状态计费机制激活以后)。 20 | 3. 用于链上治理投票。 21 | 22 | 未来,随着链上生态的成熟,STC 将会有越来越多的使用场景。 23 | 24 | ## Token 创世分发 25 | 26 | 在 Starcoin 上,所有的 Token 都是链上一等公民,所以 STC 也符合 Starcoin 的 Token 规范。每一种 Token 创建后,发行账号会得到铸币权,拥有铸币权的账号可以铸造该 Token。 27 | 28 | STC 的发行账号是 0x1 这个创世账号,该账号只用在创世交易以及区块的 meta 交易执行(类似于 Bitcoin 的 coinbase 交易)。创世交易中,创世账号会一次性将所有的 STC 铸造出来,并存到国库中,然后销毁铸币权,保证 STC 不能增发。 29 | 30 | 然后执行以下操作: 31 | 32 | * 将 159,256,800 STC (5%)提取出来,转给 Starcoin 基金会账号(0xA550C18),用于分配给早期投资人。 33 | * 发行一个总额度为 255,129,390 STC (8%),释放周期为 3 年的线性提款权,归属 Starcoin 基金会,用于生态建设。 34 | * 发行一个总额度为 222,641,010 STC (7%),释放周期为 3 年的线性提款权,归属 Starcoin 基金会,用于核心项目开发。 35 | * 将国库的提款权锁定到 DAO 中,以后从国库提款只能通过链上治理进行。 36 | 37 | 注:线性提款权只是一种凭据,转让的时候并没有发生 Token 的转移。拥有者可以定期从国库将提款权中已经线性释放的部分提取出来。 38 | 39 | ## 区块奖励 40 | 41 | Starcoin 中的区块奖励遵循按时间线性释放的模式,每个区块的奖励通过以下公式计算: 42 | 43 | ``` 44 | block_reward = base_block_reward/base_block_time_target * current_epoch.block_time_target 45 | ``` 46 | 47 | 初始化时, base_block_reward 为 10 STC,base_block_time_target 为 10 秒钟,也就是说 1 秒释放一个 STC。如果当前 Epoch 的目标出块时间是 15 秒,当前 Epoch 每个区块的奖励就是 15 STC。 48 | 49 | 其中 base_block_reward 和 base_block_time_target 是链上配置,可通过链上治理调整。每个 Epoch 的出块目标时间(block_time_target)会根据前一个 Epoch 的叔块率动态调整(具体调整方式请参看技术白皮书)。 50 | 51 | 为了鼓励矿工汇报网络中的叔块,Starcoin 会给每个包含了叔块头的矿工额外的奖励(注:并不奖励挖出叔块的矿工)。 52 | 53 | ``` 54 | uncle_reward = block_reward * base_reward_per_uncle_percent * uncle_count 55 | ``` 56 | 57 | 其中 base_reward_per_uncle_percent 为链上配置,初始化为 10%,可通过链上治理调整。uncle_count 是当前区块中包含的叔块头,最多 2 个。也就是说,如果某个区块中包含了 2 个叔块,可额外获得 20% 的奖励。 58 | 59 | block reward 60 | 61 | 每个区块的奖励由创世账号从国库中提取出来,发送给出块的矿工,延迟 N 个块到帐,初始值是 7 个块。如果国库中余额为 0 ,则该区块没有区块奖励。 62 | 63 | ## 链上治理 64 | 65 | Starcoin 内置了一套 DAO 合约,创世交易中,创世账号会初始化一个 DAO,并将 STC 设置为治理 Token。STC 的持有者可以参与以下治理项的治理: 66 | 67 | 1. 链上配置变更,比如上面的区块奖励参数。 68 | 2. DAO 相关参数的变更。 69 | 3. Stdlib 中的系统合约升级。 70 | 4. 从国库中申请提款权。 71 | 72 | 投票方式为 1 个 STC 1 票,当同意的票数大于反对的票数,并且超过 DAO 的最低票数阈值,则该提案通过。最低票数阈值由 STC 的真实流通量乘 DAO 的阈值比例得出,初始化的阈值比例是 4%。初始化的投票周期为 7 天,投票周期内参与投票的 STC 会锁定到提案中,直到投票结束。 73 | 74 | 注:STC 真实流通量 = STC 铸币总量 - 国库中的余额。也就是说,如果线性提款权未被使用,不会算在真实流通中。 75 | 76 | ## 国库提款权 77 | 78 | 国库提款权是一种矿工奖励之外的 STC 分发机制,如果有生态项目建设方,可发起提案,申请提款权。以下是发起流程: 79 | 80 | 1. 任何人都可以发起提案。提案中需指定线性提款权的接收方,需要的总数,线性释放的周期。 81 | 2. 社区成员通过 STC 投票支持或者反对该提案。 82 | 3. 提案通过后,接收方需要在链上执行提案,获取到线性提款权。 83 | 4. 接收方通过线性提款权定期从国库中提款。 84 | 85 | ## 经济模型自举 86 | 87 | ecosystem 88 | 89 | 当前的 PoW 公链,PoW 既是保证安全的一种共识机制,也是 Token 的分发策略。PoW 链的经济模型中,Token 先分发给矿工,然后再流转到其他生态。 90 | 91 | 但这种模型对于 BTC 这样的以价值存储为目标的链来说,是可以形成生态闭环的,但对于智能合约链来说,Token 的价值依赖于链上的生态的繁荣,所以 Token 分发策略中应该向上层的生态应用倾斜,同时需要通过生态建设分发 Token,而不单纯通过矿工分发。 92 | 93 | 从长远来看,链上的基础生态收益,最后归入到国库中,国库资金如果最后可以覆盖未来的研发投入以及矿工奖励,说明链的经济模型实现了自举。 -------------------------------------------------------------------------------- /sip-5/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 5 3 | title: "[SIP5] 引入国库机制,让链的发展可持续" 4 | author: "@jolestar" 5 | sip_type: paper 6 | category: Core 7 | status: Draft 8 | created: 2021-04-13 9 | weight: 5 10 | --- 11 | 12 | # 引入国库机制,让链的发展可持续 13 | 14 | ## 背景与动机 15 | 16 | 国库是一个和 DAO 关联起来的资金库,可以通过治理机制支配其中的资金。当前 Starcoin 的经济模型中,预留了一部分固定的生态基金的 Token 额度,用于发展生态,但固定额度的生态基金有可持续问题。另外通过 PoW 分发的 Token,如果分发完之后,链如何运转,也尚未有明确答案。 17 | 18 | 所以这个提案中建议引入国库 (Treasury) 机制,为链的可持续的生态系统打好基础,同时也给 DAO 系统补上了不可或缺的一环。 19 | 20 | ## 方案 21 | 22 | 1. STC 总量恒定,在创世块中一次性铸造出来锁到国库中,并销毁铸造能力。 23 | 2. 国库中的的 STC 支取需要通过链上的治理机制进行决策。 24 | 3. PoW 矿工奖励也从国库中提取,出块奖励的基础额度通过链上治理机进行调整。 25 | 4. 如果 STC 国库没有余额,则出块无奖励。 26 | 5. 链的生态k可以创造一些收益,并注入国库。 27 | 28 | 29 | ## 经济模型解释 30 | 31 | 当前的 PoW 公链,PoW 既是保证安全的一种共识机制,也是 Token 的分发策略。PoW 链的经济模型中,Token 先分发给矿工,然后再流转到其他生态。 32 | 33 | 但这种模型对于 BTC 这样的以价值存储为目标的链来说,是可以形成生态闭环的,但对于智能合约链来说,Token 的价值依赖于链上的生态的繁荣,所以 Token 分发策略中应该向上层的生态应用倾斜,同时需要通过生态应用分发 Token,而不单纯通过矿工分发。 34 | 35 | 从长远来看,链上的基础生态收益,最后归入到国库中,国库资金如果最后可以覆盖未来的研发投入以及矿工奖励,说明链的经济模型实现了自举。 36 | 37 | 38 | ## 技术方案 39 | 40 | 定义一个链上的 Treasury, 这个 Treasury 是一个通用的模块,支持任意 Token,所以第三方 Token 也可以使用国库机制。 只有 Token 但 issuer 可以创造 Treasury. 41 | 42 | 43 | ```rust 44 | module Treasury{ 45 | 46 | struct Treasury has store,key { 47 | balance: Token, 48 | /// event handle for treasury withdraw event 49 | withdraw_events: Event::EventHandle, 50 | /// event handle for treasury deposit event 51 | deposit_events: Event::EventHandle, 52 | } 53 | 54 | public fun deposit(token: Token) { 55 | // deposit token to Treasury 56 | } 57 | 58 | 59 | } 60 | ``` 61 | 62 | 在当前的 DAO 系统中新增一种 TreasuryProposal, 通过 DAO 投票来决定国库资金的支配。 63 | 64 | ```rust 65 | module TreasuryWithdrawDaoProposal{ 66 | /// WithdrawToken request. 67 | struct WithdrawToken has copy, drop, store { 68 | /// the receiver of withdraw tokens. 69 | receiver: address, 70 | /// how many tokens to mint. 71 | amount: u128, 72 | /// How long in milliseconds does it take for the token to be released 73 | period: u64, 74 | } 75 | } 76 | ``` 77 | 78 | 投票通过后,receiver 可以收到一个 LinearWithdrawCapability, 可以通过这个 capability 从 Treasury 中通过线性释放的方式提款。 79 | 80 | ```rust 81 | module Treasury{ 82 | 83 | 84 | /// A linear time withdraw capability which can withdraw token from Treasury in a period by time-based linear release. 85 | struct LinearWithdrawCapability has key, store { 86 | /// The total amount of tokens that can be withdrawn by this capability 87 | total: u128, 88 | /// The amount of tokens that have been withdrawn by this capability 89 | withdraw: u128, 90 | /// The time-based linear release start time, timestamp in seconds. 91 | start_time: u64, 92 | /// The time-based linear release period in seconds 93 | period: u64 94 | } 95 | 96 | /// Withdraw tokens with given `LinearWithdrawCapability`. 97 | public fun withdraw_with_linear_capability(cap: &mut LinearWithdrawCapability): Token { 98 | 99 | } 100 | } 101 | ``` 102 | 103 | ## 升级方案 104 | 105 | 1. Stdlib upgrade package 的 init_script 中需要初始化 Treasury 并销毁 genesis account 下的 MintCapability。 106 | 2. 需要修改当前的区块奖励获取方式,不再通过铸币的方式进行区块奖励。 -------------------------------------------------------------------------------- /sip-21/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 21 3 | title: "[SIP21] Receipt Identifier" 4 | author: "@lerencao" 5 | sip_type: SDK 6 | category: SDK 7 | status: Alpha 8 | created: 2021-05-06 9 | weight: 21 10 | --- 11 | 12 | ## Receipt Identifier 13 | 14 | For communicating account identity of payee, we propose using a compact, versioned and case-insensitive identifier. To meet this criteria, we selected the Bech32 encoding implementation used in Bitcoin Segwit (BIP 0173) excluding the Segwit byte known-length restrictions. 15 | 16 | ## Desired attributes 17 | - Consistent - Users can build a muscle memory for identifying and using these account addresses 18 | - Atomic - The string identifier feels like a single unit. Users shouldn’t try to separate or truncate the string 19 | - Versioned - The format contains human readable information about how to interpret the payload, preventing subtle errors and reserving space for future identifier schemes 20 | - Error detecting - Bech32 checksums help clients validate input and reduce risk of bad transactions due to mistypings and truncations 21 | 22 | ## Format 23 | 24 | The Receipt Identifier consists of 25 | 26 | 1. A prefix (also known as hrp (human readable part) which identifies the network version this address is intended for: “stc” for Starcoin Network. 27 | 2. A Bech32 delimiter: The character “1” (one) 28 | 3. A Bech32 version identifier: The character “p” (version = 1). 29 | 4. A Bech32 encoded payload. For version 1, is Starcoin account address (16 bytes) 30 | 5. The last 6 characters correspond to the Bech32 checksum 31 | 32 | The Receipt Identifier shall not be mixed-cases. It shall be all uppercases, or all lowercases. For example, stc1p8umxurxjd7kwgy058r3f7sgk8qgp509m or STC1P8UMXURXJD7KWGY058R3F7SGK8QGP509M are valid but stc1P8UMXURXJD7KWGY058R3F7SGK8QGP509M is not. 33 | 34 | Overall address format: prefix | delimiter | version | encoded payload | checksum 35 | 36 | Identifier information 37 | 38 | Prefix (string) 39 | Network: stc 40 | Address type (version prefix): 01 (letter p in Bech32 alphabet) 41 | Address payload (in hex) 42 | Address: 0x3f366e0cd26face411f438e29f411638 43 | Checksum: gp509m 44 | Result: stc1p8umxurxjd7kwgy058r3f7sgk8qgp509m 45 | 46 | ## Looking ahead 47 | 48 | In the future, we plan to define additional Receipt Identifier versions to support other forms of identity, such as more compact formats. These would leverage a similar overall structure but would have a different version identifier, preventing naming collisions. 49 | 50 | 51 | ### Basic implementation in Rust 52 | 53 | 54 | ``` rust 55 | impl AccountAddress { 56 | 57 | pub fn to_bech32(&self) -> String { 58 | let mut data = self.to_vec().to_base32(); 59 | data.insert( 60 | 0, 61 | bech32::u5::try_from_u8(1).expect("1 to u8 should success"), 62 | ); 63 | bech32::encode("stc", data, bech32::Variant::Bech32).expect("bech32 encode should success") 64 | } 65 | 66 | fn parse_bench32(s: impl AsRef) -> anyhow::Result> { 67 | let (hrp, data, variant) = bech32::decode(s.as_ref())?; 68 | 69 | anyhow::ensure!(variant == bech32::Variant::Bech32, "expect bech32 encoding"); 70 | anyhow::ensure!(hrp.as_str() == "stc", "expect bech32 hrp to be stc"); 71 | 72 | let version = data.first().map(|u| u.to_u8()); 73 | anyhow::ensure!(version.filter(|v| *v == 1u8).is_some(), "expect version 1"); 74 | 75 | let data: Vec = bech32::FromBase32::from_base32(&data[1..])?; 76 | 77 | if data.len() == AccountAddress::LENGTH { 78 | Ok(data) 79 | } else if data.len() == AccountAddress::LENGTH + 32 { 80 | // for address + auth key format, just ignore auth key 81 | Ok(data[0..AccountAddress::LENGTH].to_vec()) 82 | } else { 83 | anyhow::bail!("Invalid address's length"); 84 | } 85 | } 86 | 87 | //This method should not be part of the move core type, but can not implement from_str in starcoin project. 88 | //May be the AccountAddress should not be move core type, move only take care of AddressBytes. 89 | pub fn from_bech32(s: impl AsRef) -> Result { 90 | Self::from_bytes(Self::parse_bench32(s).map_err(|_| AccountAddressParseError)?) 91 | } 92 | } 93 | 94 | #[test] 95 | fn test_bech32() { 96 | let hex = "0xca843279e3427144cead5e4d5999a3d0"; 97 | let json_hex = "\"0xca843279e3427144cead5e4d5999a3d0\""; 98 | let bech32 = "stc1pe2zry70rgfc5fn4dtex4nxdr6qyyuevr"; 99 | let json_bech32 = "\"stc1pe2zry70rgfc5fn4dtex4nxdr6qyyuevr\""; 100 | 101 | let address = AccountAddress::from_str(hex).unwrap(); 102 | let bech32_address = AccountAddress::from_str(bech32).unwrap(); 103 | let json_address: AccountAddress = serde_json::from_str(json_hex).unwrap(); 104 | let json_bech32_address: AccountAddress = serde_json::from_str(json_bech32).unwrap(); 105 | 106 | assert_eq!(address, bech32_address); 107 | assert_eq!(address, json_address); 108 | assert_eq!(address, json_bech32_address); 109 | } 110 | 111 | ``` -------------------------------------------------------------------------------- /sip-23/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 23 3 | title: "[SIP23] 预言机" 4 | author: "@jolestar" 5 | sip_type: Standard 6 | category: Contract 7 | status: Alpha 8 | created: 2021-08-11 9 | weight: 23 10 | --- 11 | 12 | ## 预言机 13 | 14 | 预言机(Oracle) 的实现和扩展协议 15 | 16 | 17 | 18 | ## 动机 19 | 20 | 智能合约中,通常通过预言机来获取外部数据。预言机属于基础设施之一。 21 | 22 | ## 目标 23 | 24 | 提供一种通用的,可扩展的预言机标准以及基本的读写方法,让各种预言机的协议以及数据提供方可以共享统一的基础库以及数据格式。 25 | 26 | ## 类型以及方法定义 27 | 28 | ```rust 29 | struct DataRecord has copy, store, drop { 30 | ///The data version 31 | version: u64, 32 | ///The record value 33 | value: ValueT, 34 | ///Update timestamp millisecond 35 | updated_at: u64, 36 | } 37 | ``` 38 | 39 | DataRecord 代表一条预言机更新记录,包含了该记录的版本号,更新时间以及数据 ValueT。 ValueT 是一个泛型参数,它可能是一个价格,也可能是个哈希,也可能是一个复杂的结构,这个由预言机开发者来定义。 40 | 41 | 42 | ```rust 43 | struct OracleInfo has key { 44 | ///The datasource counter 45 | counter: u64, 46 | ///Ext info 47 | info: Info, 48 | } 49 | 50 | public fun register_oracle(sender: &signer, info: Info); 51 | ``` 52 | 53 | 预言机开发者需要先定义一种类型 OracleT,来标记这个预言机,同时可以提供一些扩展信息的说明(Info),并通过 `register_oracle` 方法来注册预言机。 54 | 55 | 56 | ```rust 57 | struct DataSource has key { 58 | /// the id of data source of ValueT 59 | id: u64, 60 | /// the data version counter. 61 | counter: u64, 62 | update_events: Event::EventHandle>, 63 | } 64 | 65 | public fun init_data_source(sender: &signer, init_value: ValueT); 66 | ``` 67 | 68 | 预言机数据提供方需要通过 `init_data_source` 方法来初始化预言机数据源。 69 | 70 | ```rust 71 | struct OracleFeed has key { 72 | record: DataRecord, 73 | } 74 | ``` 75 | 每个数据提供源的账号下,会有一个 `OracleFeed` 结构来维护 `OracleT` 和 `DataRecord` 的关系。 76 | 77 | 78 | ```rust 79 | struct OracleUpdateEvent has copy,store,drop { 80 | source_id: u64, 81 | record: DataRecord, 82 | } 83 | 84 | public fun update(sender: &signer, value: ValueT); 85 | 86 | ``` 87 | 88 | 预言机数据提供方可以通过 update 方法来更新自己账号下的 `OracleFeed`, 每次更新都会触发一个 `OracleUpdateEvent` 事件。 89 | 90 | ```kotlin 91 | public fun read(ds_addr: address): ValueT 92 | ``` 93 | 94 | 任何人都可以通过 `read` 方法来读取预言机的值,读取时需要指定数据源的账号地址。 95 | 96 | ## 扩展方式 97 | 98 | ### 自定义更新策略 99 | 100 | 默认情况下,每个数据源提供方可直接更新自己账号下预言机数据,但如果想通过合约更新策略,比如定义一种去中心化的数据更新协议,可以先通过 101 | 102 | ```kotlin 103 | public fun remove_update_capability(sender: &signer):UpdateCapability; 104 | ``` 105 | 方法将自己账号下的 `UpdateCapability` 取出来,然后重新定义数据结构,将 Capability 锁在新的合约中,然后在该合约中定义更新策略,通过调用 106 | 107 | ```kotlin 108 | public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT); 109 | ``` 110 | 111 | 方法来更新数据。 112 | 113 | 114 | ### 自定义数据类型 115 | 116 | 比如 Token 的价格数据,通过 u128 来表示, 预言机中的 `ValueT` 就是 u128。同时可以在扩展信息中记录了价格的精度 `scaling_factor`,方便使用方换算。 117 | 118 | ```rust 119 | struct PriceOracleInfo has copy,store,drop{ 120 | scaling_factor: u128, 121 | } 122 | 123 | public fun register_oracle(sender: &signer, precision: u8){ 124 | let scaling_factor = Math::pow(10, (precision as u64)); 125 | Oracle::register_oracle(sender, PriceOracleInfo{ 126 | scaling_factor, 127 | }); 128 | } 129 | 130 | public fun init_data_source(sender: &signer, init_value: u128){ 131 | Oracle::init_data_source(sender, init_value); 132 | } 133 | ``` 134 | 135 | ### 自定义数据聚合策略 136 | 137 | 任何人都可以定义一种聚合策略,来从多个数据源提供方筛选和聚合数据。 138 | 139 | 比如下面的 `latest_price_average_aggregator` 方法,接受多个数据源地址,会将每个数据源地址下的数据读取出来,并通过 `updated_in` 的更新时间限制进行过滤,然后求平均值。 140 | 141 | ```kotlin 142 | public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { 143 | let len = Vector::length(addrs); 144 | let price_records = PriceOracle::read_records(addrs); 145 | let prices = Vector::empty(); 146 | let i = 0; 147 | let expect_updated_after = Timestamp::now_milliseconds() - updated_in; 148 | while (i < len){ 149 | let record = Vector::pop_back(&mut price_records); 150 | let (_version, price, updated_at) = Oracle::unpack_record(record); 151 | if (updated_at >= expect_updated_after) { 152 | Vector::push_back(&mut prices, price); 153 | }; 154 | i = i + 1; 155 | }; 156 | // if all price data not match the update_in filter, abort. 157 | assert(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); 158 | Math::avg(&prices) 159 | } 160 | ``` 161 | 162 | ## 总结 163 | 164 | 通过 Move 定义的预言机协议有以下优点: 165 | 166 | 1. 扩展性强,无论是数据结构,还是数据汇报更新协议,还是聚合协议,都可以在当前协议之上扩展出来。 167 | 2. Onchain 和 Offchain 数据结构一致。合约中读取到的数据结构和通过链下的 RPC 接口获取到的 Resource 结构一致,方便解析使用。 168 | 169 | 尚未解决的点:当前的协议只支持了更新和读取最新版本的数据,历史版本的数据未在合约中保存。如何保存以及聚合历史数据,比较难提供通用的方法,需要根据具体的场景进行设计。当然,如果在实践中发现了比较通用的方法,也可以沉淀到系统合约的预言机库中。 -------------------------------------------------------------------------------- /sip-20/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 20 3 | title: "[SIP20] JSONRPC" 4 | author: "@lerencao" 5 | sip_type: API 6 | category: API 7 | status: Alpha 8 | created: 2020-11-17 9 | weight: 20 10 | --- 11 | 12 | # 统一 JSONRPC 接口的参数和返回值类型 13 | 14 | 目前 Starcoin 的 json rpc 接口返回值类型直接使用了内部的数据结构,比如 Block, Header, Transaction, TransactionInfo 等等。 15 | 但是在接口的实际使用过程中,这些内部结构的字段无法满足外部使用需求,往往是缺乏必要的关联字段,比如外部使用可能需要 TransactionInfo 里包含 txn 被打包的 block id,亦或是某个 u64 类型的字段序列化成 json 后,无法被 javascript 端的正确的解析出来。 16 | 为了解决诸如此类的问题,该 RFC 定义了一系列 jsonrpc 接口返回值类型,试图将内部使用的数据结构和对外接口的数据结构解耦。 17 | 18 | 19 | ## 类型定义 20 | 21 | 经过梳理,接口中使用的以下几类核心数据结构需要替换成自定义的对外返回的类型。 22 | 23 | - Block, 以及关联的 BlockHeader, BlockBody。 24 | - Transaction,以及关联的 RawUserTransaction,BlockMetadata 等。 25 | - TransactionInfo:Transaction 在链上的结果数据。 26 | - Transaction 在链上产生的 Events 数据。 27 | 28 | 以下部分列出了新的接口返回类型定义。 29 | 30 | ### Block 31 | 32 | ```rust 33 | pub struct BlockView { 34 | pub header: BlockHeaderView, 35 | pub body: BlockTransactionsView, 36 | pub uncles: Vec, 37 | } 38 | 39 | pub struct BlockHeaderView { 40 | /// block hash 41 | pub block_hash: HashValue, 42 | /// Parent hash. 43 | pub parent_hash: HashValue, 44 | /// Block timestamp. 45 | pub timestamp: u64, 46 | /// Block number. 47 | pub number: BlockNumber, 48 | /// Block author. 49 | pub author: AccountAddress, 50 | /// Block author auth key. 51 | pub author_auth_key: Option, 52 | /// The transaction accumulator root hash after executing this block. 53 | pub accumulator_root: HashValue, 54 | /// The parent block accumulator root hash. 55 | pub parent_block_accumulator_root: HashValue, 56 | /// The last transaction state_root of this block after execute. 57 | pub state_root: HashValue, 58 | /// Gas used for contracts execution. 59 | pub gas_used: u64, 60 | /// Block difficulty 61 | pub difficulty: U256, 62 | /// Consensus nonce field. 63 | pub nonce: u32, 64 | /// hash for block body 65 | pub body_hash: HashValue, 66 | /// The chain id 67 | pub chain_id: u8, 68 | } 69 | pub enum BlockTransactionsView { 70 | Hashes(Vec), 71 | Full(Vec), 72 | } 73 | ``` 74 | 75 | 需要注意的是,BlockBodyView 包含了两种,一种是只包含 block 中所有 transaction 的 hash 值,另外一种是完整的 txn 数据。这样客户端在不需要具体 txn 数据时,可以选择性调用。 76 | 77 | ### Transaction 78 | 79 | ``` rust 80 | pub struct TransactionView { 81 | block_hash: HashValue, 82 | block_number: BlockNumber, 83 | transaction_hash: HashValue, 84 | transaction_index: u64, 85 | block_metadata: Option, 86 | user_transaction: Option, 87 | } 88 | pub struct BlockMetadataView { 89 | /// Parent block hash. 90 | pub parent_hash: HashValue, 91 | pub timestamp: u64, 92 | pub author: AccountAddress, 93 | pub author_auth_key: Option, 94 | pub uncles: u64, 95 | pub number: BlockNumber, 96 | pub chain_id: u8, 97 | pub parent_gas_used: u64, 98 | } 99 | pub struct SignedUserTransactionView { 100 | /// The raw transaction 101 | pub raw_txn: RawUserTransactionView, 102 | 103 | /// Public key and signature to authenticate 104 | pub authenticator: TransactionAuthenticator, 105 | } 106 | pub struct RawUserTransactionView { 107 | /// Sender's address. 108 | pub sender: AccountAddress, 109 | // Sequence number of this transaction corresponding to sender's account. 110 | pub sequence_number: u64, 111 | 112 | // The transaction payload in scs bytes. 113 | #[serde(serialize_with = "serialize_binary")] 114 | pub payload: Vec, 115 | 116 | // Maximal total gas specified by wallet to spend for this transaction. 117 | pub max_gas_amount: u64, 118 | // Maximal price can be paid per gas. 119 | pub gas_unit_price: u64, 120 | // The token code for pay transaction gas, Default is STC token code. 121 | pub gas_token_code: String, 122 | // Expiration timestamp for this transaction. timestamp is represented 123 | // as u64 in seconds from Unix Epoch. If storage is queried and 124 | // the time returned is greater than or equal to this time and this 125 | // transaction has not been included, you can be certain that it will 126 | // never be included. 127 | // A transaction that doesn't expire is represented by a very large value like 128 | // u64::max_value(). 129 | pub expiration_timestamp_secs: u64, 130 | pub chain_id: u8, 131 | } 132 | ``` 133 | 134 | 这里需要注意两点: 135 | 136 | 1. TransactionView 将 BlockMedata 类型和 SignedUserTransaction 平铺在一起,减少嵌套,绝大部分情况下,外部调用应该只关心 `user_transaction` 字段。 137 | 2. RawUserTransactionView 中,将 payload 存储为 scs 序列化后的 bytes 数据,外部如果需要使用里面的具体数据,可以通过 scs 反序列化成 scs 数据结构。这样可以减少 payload 复杂的数据结构给 jsonrpc 使用端带来的负担。 138 | 139 | ### TransactionInfo 140 | 141 | ``` rust 142 | pub struct TransactionInfoView { 143 | block_hash: HashValue, 144 | block_number: BlockNumber, 145 | /// The hash of this transaction. 146 | transaction_hash: HashValue, 147 | transaction_index: u64, 148 | /// The root hash of Sparse Merkle Tree describing the world state at the end of this 149 | /// transaction. 150 | state_root_hash: HashValue, 151 | 152 | /// The root hash of Merkle Accumulator storing all events emitted during this transaction. 153 | event_root_hash: HashValue, 154 | 155 | /// The amount of gas used. 156 | gas_used: u64, 157 | 158 | /// The vm status. If it is not `Executed`, this will provide the general error class. Execution 159 | /// failures and Move abort's receive more detailed information. But other errors are generally 160 | /// categorized with no status code or other information 161 | status: TransactionVMStatus, 162 | } 163 | 164 | #[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize)] 165 | pub enum TransactionVMStatus { 166 | Executed, 167 | OutOfGas, 168 | MoveAbort { 169 | location: AbortLocation, 170 | abort_code: u64, 171 | }, 172 | ExecutionFailure { 173 | location: AbortLocation, 174 | function: u16, 175 | code_offset: u16, 176 | }, 177 | MiscellaneousError, 178 | } 179 | ``` 180 | 181 | TransactionInfoView 中在 TransactionInfo 的基础上加入了 txn 所在 block 的相关信息。 182 | 183 | ### Transaction Events 184 | 185 | ``` rust 186 | pub struct TransactionEventView { 187 | pub block_hash: Option, 188 | pub block_number: Option, 189 | pub transaction_hash: Option, 190 | // txn index in block 191 | pub transaction_index: Option, 192 | 193 | pub data: Vec, 194 | pub type_tags: TypeTag, 195 | pub event_key: EventKey, 196 | pub event_seq_number: u64, 197 | } 198 | ``` 199 | 200 | ## 缺点 201 | 202 | 自定义的 rpc 类型定义大部分和已有的内部结构,在数据字段上是重叠的,显的繁琐和重复。 203 | -------------------------------------------------------------------------------- /sip-3/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 3 3 | title: "[SIP3] Token Economics" 4 | author: Starcoin Foundation 5 | sip_type: paper 6 | category: Core 7 | status: Beta 8 | created: 2020-11-14 9 | weight: 3 10 | --- 11 | 12 | # Starcoin Economic White Paper 13 | 14 | STC is the native token of the Starcoin network, with a total constant issuance of 3,185,136,000. 15 | 16 | Currently, it is mainly used for: 17 | 18 | 1. Paying the GAS fee of the transaction. 19 | 2. Paying the state space fee (after the future state billing mechanism is activated). 20 | 3. The voting of on-chain governance. 21 | 22 | In the future, as the on-chain ecosystem becomes mature, STC will have more and more application scenarios. 23 | 24 | ## The Genesis Token Distribution 25 | 26 | For Starcoin, all Tokens are first-class citizens on the chain, so STC also conforms to the Token specification of Starcoin. After each type of Token is generated, the issuing account will get the seigniorage, and only the accounts with the seigniorage can mint the Token. 27 | 28 | The genesis account 0x1 is the issuance account for STC, which is only used for the generation transaction and the meta transaction execution of the blocks (similar to the coinbase transactions for Bitcoin). In the generation transaction, the genesis account will mint all STCs at once and deposit them in the treasury, and then revoke the seigniorage to ensure that no more STCs can be issued. 29 | 30 | Then the following operations will be performed: 31 | 32 | * 159,256,800 STCs (5%) are withdrawn and transferred to the Starcoin Foundation account (0xA550C18) and will be distributed to early investors. 33 | * A linear withdrawal right with a 3-year release period of 255,129,390 STCs (8%) will be issued to the Starcoin Foundation for ecological construction. 34 | * A linear withdrawal right with 3-year release period of 222,641,010 STCs (7%) will be issued to the Starcoin Foundation for core project development. 35 | * The withdrawal rights of the Treasury will be locked in the DAO, and future withdrawals from the Treasury can only be performed through on-chain governance. 36 | 37 | Note: The linear withdrawal right is only a credential of ownership, and Tokens are not involved in the transfer. The owners can periodically withdraw the Tokens from the Treasury that are linearly released by owning the withdrawal rights. 38 | 39 | ##Block Reward 40 | 41 | The block rewards in Starcoin follow the model of linear release in time, and the rewards of each block are calculated by the following equation: 42 | 43 | ``` 44 | block_reward = base_block_reward/base_block_time_target * current_epoch.block_time_target 45 | ``` 46 | 47 | During initialization, base_block_reward is 10 STCs, and base_block_time_target is 10 seconds, which means that one STC is released in each second. If the target block generation time of the current Epoch is 15 seconds, the reward for each block of the current Epoch is 15 STCs. 48 | 49 | Among them, base_block_reward and base_block_time_target are on-chain configurations and can be adjusted through on-chain governance. The block target time (block_time_target) of each Epoch will be dynamically adjusted according to the uncle block rate of the previous Epoch (for specific adjustment methods, please refer to the technical white paper). 50 | 51 | In order to encourage miners to report uncle blocks in the network, Starcoin will give additional rewards to each miner that has the uncle block header (note: miners who dig out the uncle block are not rewarded). 52 | 53 | ``` 54 | uncle_reward = block_reward * base_reward_per_uncle_percent * uncle_count 55 | ``` 56 | 57 | Among them, base_reward_per_uncle_percent is the on-chain configuration, which is initialized to 10% and can be adjusted through on-chain governance. uncle_count is the number of uncle headers included in the current block with a maximum value of 2. In other words, if a block contains 2 uncle blocks, you can get an additional 20% reward. 58 | 59 | block reward 60 | 61 | The reward of each block is extracted from the Treasury by the genesis account, and sent to the miner who offered the block, delayed by N blocks to the account, and the initial value is 7 blocks. If the balance in the Treasury is 0, there is no block reward for this block. 62 | 63 | ## On-chain Governance 64 | 65 | Starcoin has a built-in DAO contract. In the generation transaction, the genesis account will initialize a DAO and set the STC as the governance Token. STC holders can participate in the governance of the following governance items: 66 | 67 | 68 | 1. On-chain configuration changes, such as the aforementioned block reward parameters. 69 | 2. The changes of DAO-related parameters. 70 | 3. System contract upgrade in Stdlib. 71 | 4. Application for withdrawal rights from the Treasury. 72 | 73 | For voting, one STC accounts for one vote. When the number of affirmative votes exceeds the minimum number of votes in the DAO and is greater than the number of negative votes, the proposal is accepted. The minimum number of votes is calculated by the multiplication of both the circulating STC amount and the DAO threshold ratio (the initial threshold is 4%). The initial voting period is 7 days. All participating STCs in the voting period will remain locked in the proposal until the end of the voting. 74 | 75 | Note: the circulating STC amount = total minted STC amount - Treasury balance. In other words, if the linear withdrawal right is not used, it will not be counted towards actual circulation. 76 | 77 | ## Treasury Withdrawal Rights 78 | 79 | Treasury withdrawal rights are an STC distribution mechanism in addition to miner rewards. Any one can initiate proposals and submit it to the ecological project construction party to apply for withdrawal rights. The following is the initiation process: 80 | 81 | 1. Anyone can initiate a proposal. The proposal needs to specify the recipient of linear withdrawal rights, the total number of Tokens in the application, and the period of linear release. 82 | 2. Community members may support or oppose the proposal via STC voting. 83 | 3. After the proposal is passed, the receiver needs to execute the proposal on the chain to obtain linear withdrawal rights. 84 | 4. The recipient periodically withdraws funds from the treasury through linear withdrawal rights. 85 | 86 | ## Economic Model Bootstrapping 87 | 88 | ecosystem 89 | 90 | In the current PoW-based public chain, PoW is not only a security-wise consensus mechanism, but also a Token distribution strategy. In the economic model of the PoW chain, Tokens are firstly distributed to miners and then transferred to other ecosystems. 91 | 92 | However, for chains such as BTC that target value storage, this model can form an ecological closed loop. But for smart contract chains, the value of Tokens depends on the prosperity of the on-chain ecology, so the Token distribution strategy should be leaning toward the upper-level ecological applications, and at the same time, Tokens need to be distributed through ecological construction, not simply through miners. 93 | 94 | In the long run, the basic on-chain ecological benefits are finally included in the Treasury. If the funds in the Treasury can finally cover future R&D investment and miner rewards, it means that the economic model of the chain has bootstrapped itself up. 95 | -------------------------------------------------------------------------------- /sip-22/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 22 3 | title: "[SIP22] NFT" 4 | author: "@jolestar" 5 | sip_type: Standard 6 | category: Contract 7 | status: Alpha 8 | created: 2021-08-10 9 | weight: 22 10 | --- 11 | 12 | ## NFT 13 | 14 | NFT 的实现和扩展协议 15 | 16 | 17 | 18 | ## 动机 19 | 20 | 在智能合约中,Token 用来表达可拆分的数字资源,而要表达不可拆分的资源,就需要 NFT。在 Move 中,任何一个不可 copy 和 drop 的类型实例,都可以认为是一个不可拆分的资源,是一个 NFT。但 NFT 需要一种统一展示的标准,以及 NFT 的收集和转移方法,所以设计本标准。 21 | 22 | ## 目标 23 | 24 | 提供一种通用的,可扩展的标准,同时提供 NFT 相关的基本操作实现。 25 | 26 | ## 类型定义 27 | 28 | ```rust 29 | struct NFT has store { 30 | /// The creator of NFT 31 | creator: address, 32 | /// The unique id of NFT under NFTMeta type 33 | id: u64, 34 | /// The metadata of NFT 35 | base_meta: Metadata, 36 | /// The extension metadata of NFT 37 | type_meta: NFTMeta, 38 | /// The body of NFT, NFT is a box for NFTBody 39 | body: NFTBody, 40 | } 41 | ``` 42 | 43 | NFT 是 Move 中的一种类型,它支持 store ability,但不可 copy 以及 drop,包含一些基本的元信息: 44 | 45 | 1. creator: NFT 创建者的 address。 46 | 2. id: 该 NFT 类型下的唯一 id。 47 | 3. base_meta: 基础的通用 metadata 信息,主要用来表达如何展示 NFT。 48 | 4. type_meta: 开发者自定义的 metadata,同时用来标记 NFT 的类型。Metadata 不是资源,它表达信息,所以支持 copy + store + drop。 49 | 5. body: NFT 包含的资源,可以用来嵌入其他的资源。 50 | 51 | 如果把 NFT 视为一个箱子,NFT 本身定义了这个箱子的归属,唯一编号,以及展示方式,而 NFTBody 就是箱子中封装的珠宝。展示方式通过 Metadata 来定义。 52 | 53 | ```rust 54 | struct Metadata has copy, store, drop { 55 | /// NFT name's utf8 bytes. 56 | name: vector, 57 | /// Image link, such as ipfs://xxxx 58 | image: vector, 59 | /// Image bytes data, image or image_data can not empty for both. 60 | image_data: vector, 61 | /// NFT description utf8 bytes. 62 | description: vector, 63 | } 64 | ``` 65 | 66 | Metadata 定义了 NFT 展示所需要的基本信息,名称,图片,描述。如果有其他需要扩展的信息,可以定义在 type_meta 中。图片有两个字段表达,`image` 表示图片地址,`image_data` 可以直接保存图片的二进制数据,客户端展示的时候,使用 `image` 和 `image_data` 中不为空的那个字段。 67 | 68 | 另外,有的 NFT 的所有实例会使用同一个图片,这种情况下,NFT metadata 中的 `image` 和 `image_data` 可以都为空,客户端展示的时候使用 NFTTypeInfoV2 中的 metadata。 69 | 70 | ```rust 71 | /// The info of NFT type 72 | struct NFTTypeInfoV2 has key, store { 73 | counter: u64, 74 | meta: Metadata, 75 | mint_events: Event::EventHandle>, 76 | burn_events: Event::EventHandle>, 77 | } 78 | ``` 79 | 80 | NFTTypeInfoV2 用于维护 NFT id 的计数器,以及该 NFT 类型的全局 metata,每一种 NFT 类型需要先在注册中心注册。所有的 NFT 类型都注册在 0x1 这个账号下。 81 | 82 | >注: NFTTypeInfo 在 stdlibv7 中变为 NFTTypeInfoV2 83 | 84 | ## 方法定义 85 | 86 | 每种 NFT 的类型需要先注册,注册时需要 NFT 的标记类型 NFTMeta 以及该类型的全局 metadata。 87 | 88 | ```rust 89 | public fun register(sender: &signer, info: NFTTypeInfoExt, meta: Metadata) 90 | ``` 91 | 92 | 注册后 `sender` 账号下会被写入三个权限: 93 | 94 | 1. MintCapability : 用于铸造该类型的 NFT 95 | 2. BurnCapability:用于烧毁该类型的 NFT 96 | 3. UpdateCapability:用于更新该类型的 NFT metadata 97 | 98 | 这三个权限对应三个方法: 99 | 100 | ```rust 101 | /// 铸造 NFT,返回 NFT 的实例 102 | public fun mint_with_cap(creator: address, cap: &mut MintCapability, base_meta: Metadata, type_meta: NFTMeta, body: NFTBody): NFT 103 | 104 | ///烧毁 NFT,返回 NFT 内部嵌套的 NFTBody 105 | public fun burn_with_cap(cap: &mut BurnCapability, nft: NFT): NFTBody 106 | 107 | ///更新 NFT 的 metadata 108 | public fun update_meta_with_cap(cap: &mut UpdateCapability, nft: &mut NFT, base_meta: Metadata, type_meta: NFTMeta) 109 | ``` 110 | 111 | 上面列举了 NFT 相关的基本方法,而 NFT 如何存储,如何转让,这个不是 NFT 模块本身关心的事情,是 NFTGallery 的功能。 112 | 113 | ## NFT 陈列室(NFTGallery) 114 | 115 | NFTGallery 模块提供了用户用来收集和存储 NFT 的基本功能。主要包含以下方法: 116 | 117 | ```rust 118 | /// 初始化一个 NFTGallery 去接受类型为 NFT 的 NFT,用户每接受一种新的 NFT,都需要调用这个方法初始化。 119 | public fun accept(sender: &signer) 120 | 121 | /// 将 id 为参数 `id` 的 NFT 从 `sender` 转给 `receiver` 122 | public fun transfer(sender: &signer, id: u64, receiver: address) 123 | 124 | /// 获取 `ownder` 的类型为 NFTMeta 的所有 NFT info, 返回 NFTInfo 列表 125 | public fun get_nft_infos(owner: address):vector> 126 | 127 | /// 将 `nft` 存放到 `sender` 的 NFTGallery 中 128 | public fun deposit(sender: &signer, nft: NFT) 129 | 130 | /// 将 `nft` 存放到 `receiver` 的 NFTGallery 131 | public fun deposit_to(receiver: address, nft: NFT) 132 | 133 | /// 从 `sender` 的 NFTGallery 中取一个类型为 NFTMeta 的 NFT 134 | public fun withdraw_one(sender: &signer): NFT 135 | 136 | /// 从 `sender` 的 NFTGallery 中取一个类型为 NFTMeta,id 为参数 `id` 的 NFT 137 | public fun withdraw(sender: &signer, id: u64): Option> 138 | ``` 139 | 140 | NFTGallery 提供了一个通用的空间用来存储和查询 NFT,当然,开发者也可以自行设计 NFT 的存储模块。 141 | 142 | ## 扩展方式 143 | 144 | ### 自定义 Metadata 145 | 146 | 如果开发者需要增加新的 Metadata,可以在 NFTMeta 类型中定义,例如要定义一个视频类的 NFT,需要增加一个视频地址: 147 | 148 | ```rust 149 | struct VideoNFT has copy, store, drop { 150 | video_url: vector, 151 | } 152 | struct VideoNFTBody has store{} 153 | ``` 154 | 155 | 实际的 NFT 数据格式相当于: 156 | 157 | ```rust 158 | struct NFT{ 159 | creator: address, 160 | id: u64, 161 | base_meta: Metadata, 162 | type_meta: VideoNFT, 163 | body: VideoNFTBody, 164 | } 165 | ``` 166 | 167 | 168 | 169 | ### 嵌套 NFTBody 170 | 171 | 如果开发者想再 NFT 中嵌入其他的资源,可以通过自定义 Body 的方式进行,比如上面的 VideoNFTBody 中想嵌入一些 Token: 172 | 173 | ```rust 174 | struct VideoNFTBody has store{ 175 | token: Token, 176 | } 177 | ``` 178 | 179 | 180 | 181 | ### 自定义转让逻辑 182 | 183 | 有的 NFT 应用场景下,NFT 转让是受限的,比如作为会员凭证。这种情况下,需要自定义一种 NFT 的存储机制,从而实现自定义转让机制。储存在 NFTGallery 中的 NFT,完全受用户控制,NFT 的开发者不能限制它的使用和转让。 184 | 185 | 以 IdentifierNFT 为例, IdentifierNFT 是一种 NFT 容器,它保证每个用户只能拥有一个同一个类型的 NFT,NFT 开发者授予用户 NFT 后,用户无法转让,一般用在用户身份相关的 NFT 场景下,比如荣誉奖章等。 186 | 187 | ```rust 188 | /// IdentifierNFT 中包含了一个 Option 的 NFT,默认是空的,相当于一个可以容纳 NFT 的箱子 189 | struct IdentifierNFT has key { 190 | nft: Option>, 191 | } 192 | 193 | /// 用户通过 Accept 方法初始化一个空的 IdentifierNFT 在自己的账号下 194 | public fun accept(sender: &signer) { 195 | move_to(sender, IdentifierNFT { 196 | nft: Option::none(), 197 | }); 198 | } 199 | 200 | /// 开发者通过 MintCapability 给 receiver 授予该 nft,将 nft 嵌入到 IdentifierNFT 中 201 | public fun grant_to(_cap: &mut MintCapability, receiver: address, nft: NFT) acquires IdentifierNFT { 202 | let id_nft = borrow_global_mut>(receiver); 203 | Option::fill(&mut id_nft.nft, nft); 204 | } 205 | 206 | /// 开发者也可以通过 BurnCapability 将 `owner` IdentifierNFT 中的 NFT 取出来 207 | public fun revoke(_cap: &mut BurnCapability, owner: address): NFT acquires IdentifierNFT { 208 | let id_nft = move_from>(owner); 209 | let IdentifierNFT { nft } = id_nft; 210 | Option::destroy_some(nft) 211 | } 212 | ``` 213 | 214 | 以上的方案中,NFTMeta 定义和注册的开发者可以通过程序来定义 NFT 的转让逻辑(当然,也可以不允许转让)。 215 | 216 | ## 使用场景示例 217 | 218 | ### NFT 游戏道具 219 | 用 Move 中的 NFT 来定义游戏道具的一个优势是可以在同一个 Module 中定义多个 NFT 类型,还可以实现道具间的组合,比如: 220 | 221 | ```rust 222 | /// 玩家通过两个 L1 的 Card 合成一个新的 L2 的 Card 223 | struct L1Card has store {} 224 | struct L2Card has store { 225 | first: L1Card, 226 | second: L1Card, 227 | } 228 | ``` 229 | 230 | 更详细的例子参看 [nft_card.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/nft_card.move) 231 | 232 | ### NFT 作为会员身份 233 | 234 | ```rust 235 | /// XMembership NFTMeta 中记录了会员的开始时间以及结束时间 236 | struct XMembership has copy, store, drop{ 237 | join_time: u64, 238 | end_time: u64, 239 | } 240 | /// XMembership NFTBody 中锁了用户的会员费 241 | struct XMembershipBody has store{ 242 | fee: Token, 243 | } 244 | ``` 245 | 246 | 用户缴会员费成为会员后,会员费是锁在 NFT 中的,只有用户每次进行会员操作或者退出的时候,会检查会员是否到期并按时间流扣除会员费。更详细的例子参看 [identifier_nft.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/identifier_nft.move) 247 | 248 | ### NFT 作为购物凭证 249 | 用户直接通过支付 Token 在链上自行铸造 NFT,然后用 NFT 来兑换实物。用户之间可以交易 NFT。更详细的例子参看 [nft_boxminer.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/nft_boxminer.move) 250 | 251 | ### 通过 MerkleTree 证明来分发 NFT 252 | 253 | 有些 NFT 要分发给那些账号地址是确定的,但由于数量较多,无法一次性铸造出来,可以通过 MerkleTree 证明来分发。NFT 开发者定义 NFT 并在链上提交 MerkleTree 的 root,用户拿着 NFT 证明来自行铸造。 254 | 255 | Starcoin 的 GenesisNFT 就是通过这种方式铸造的。GenesisNFT 分发给 starcoin 主网启动前参与 Barnard 网络挖矿的账号地址。主网创世块的 parent_hash(0x0f2fdd39d11dc3d25f21d05078783d476ff98ca4035320e5932bb3938af0e827) 指向的 Barnard 网络的区块,高度为 310000。Barnard 网络上在此高度之前所有出过块的地址,都可以自行铸造一枚 GenesisNFT。详细实现参看:[GenesisNFT.move](https://github.com/starcoinorg/starcoin/blob/master/vm/stdlib/modules/GenesisNFT.move) [MerkleNFT.move](https://github.com/starcoinorg/starcoin/blob/master/vm/stdlib/modules/MerkleNFT.move) 256 | 257 | ## Starcoin NFT 标准与 ERC721/ERC1155 之间的差异 258 | 259 | 1. ERC721/ERC1155 是 Interface,并没有定义实现,可扩展性通过不同的实现来完成。而 Starcoin NFT 标准包含数据类型与基本操作的实现,可扩展性通过上层组合来实现。 260 | 2. 默认情况下,Starcoin NFT 和 ERC721 类似,是不可拆分的。但第三方可以自行扩展出拆分和合并逻辑,从而达到 ERC1155 的目的。 261 | 3. ERC721/ERC1155 的 NFT 都只能在合约内部移动,无法从合约移动到另外一个合约,所以 NFT 之上的协议组合非常困难。而得益于 Move 的类型特征,Starcoin 中的 NFT 可以在不同的合约之间移动,其他的合约可以定义新的类型来对 NFT 进行封装,扩展出新的转让逻辑(比如拍卖)。这给 NFT 之上的协议设计带来了极大的便利,可以组合出很多的玩法。 262 | 4. ERC721/ERC1155 是通过合约地址来区分 NFT 类型的,要想实现多种 NFT,需要部署多个合约,如果 NFT 类型很多的情况,会导致合约调用非常复杂。 263 | 5. Starcoin 的 NFT 存储在用户的状态空间里,可以通过列举用户状态空间的资源来展示用户所有的 NFT,包括嵌入到其他合约中的 NFT。这给周边生态工具,比如钱包以及区块浏览器中中展示 NFT,拍卖市场展示 NFT 等,都带来了极大的便利。 264 | 265 | -------------------------------------------------------------------------------- /sip-6/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 6 3 | title: "[SIP6] Stargate: 统一的分层协议框架" 4 | author: "Starcoin Core Dev" 5 | sip_type: paper 6 | category: Core 7 | status: Draft 8 | created: 2022-01-26 9 | weight: 6 10 | --- 11 | 12 | 13 | ## 前言 14 | 15 | 当前,区块链之上的各种应用的雏形已经具备,但如何让区块链技术大规模采用,是所有的公链需要解答的问题。 16 | 17 | 这个问题可以拆解为两个问题: 18 | 19 | 1. 区块链如何接受大规模用户?也就是区块链的扩容难题。 20 | 2. 应用应该以什么形态和链结合?也就是链和 Web3 应用的关系。 21 | 22 | 关于扩容的问题,当前区块链世界主要有三条路线: 23 | 24 | 1. 通过改进共识机制,或者减少验证节点等方式来实现扩容。 25 | 2. 通过分片或者平行链来实现扩容。 26 | 3. 通过分层的方式进行扩容。 27 | 28 | Starcoin 选择了第三种路线,主要是基于以下理由: 29 | 30 | 1. 分层是一种人类社会习惯的解决扩容问题的方式,比如司法系统,政治机构,都是通过分层来解决扩容难题,不同层之间的制约机制可以保证安全。 31 | 2. 区块链的不可能三角中,Layer1 应该更侧重安全。 32 | 3. 不同的应用,应用的不同阶段,对去中心化的要求,对安全的要求,对吞吐的要求都不一样,需要有一种面向应用的演进方案,通过分层的方式更容易实现。 33 | 34 | Stargate 是 Starcoin 区块链网络上的分层协议框架。它通过统一的抽象,支持不同的分层方案。Layer1 保证安全(Security)和无准入(Permissionless)。Layer2 实现终局性(Finality),将状态和计算从 Layer1 迁移到 Layer2,实现全局扩容以及交易的即时确认。Layer3 通过面向应用的局部共识,最终实现对 Web3 应用的支撑。 35 | 36 | 37 | 38 | 39 | 40 | ## 关键方案 41 | 42 | 分层的所有方案中,主要面临三个技术难题: 43 | 44 | 1. 如何在 Layer1 校验 Layer2 的执行结果并进行仲裁?Layer3 到 Layer2 同理。 45 | 2. Layer2 以及 Layer3 能否依赖 Layer1 的合约? 这个影响智能合约跨层的可组合性。 46 | 3. 合约的状态如何在不同的层之间迁移? 47 | 48 | ### 交易校验 49 | 50 | 区块链上执行一个交易,虽然要基于历史状态进行,但实际上不会读取全部的历史状态。如果只提供该交易所依赖的状态,也可以计算出新的状态。 51 | 52 | 区块链的状态转换可以通过以下公式表达(以太坊黄皮书): 53 | 54 | σt+1 ≡ Υ(σt, T) 55 | 56 | - σ𝑡+1 代表下一个世界状态 57 | - Υ 代表状态转换函数 58 | - σ𝑡 代表当前世界状态 59 | - T 代表一个交易 60 | 61 | Y 要执行 T 的时候,依赖当前状态 σ𝑡,但 Y 并不会读取所有的历史状态,如果把 Y 需要的状态抽出一个子集 σ`𝑡,并同时提供证明,σ`𝑡 属于 σ𝑡,就可以实现状态转换。 62 | 63 | ![StateFullTransaction](./images/statefulltransaction.svg) 64 | 65 | 我们把交易执行所依赖的前置状态子集叫做读取集(ReadSet),状态的证明叫读取集证明(ReadSetProof),把它们和交易以及执行后的状态树的根哈希一起打包,叫做富状态交易(StateFullTransaction)。 66 | 67 | 数据结构表达如下: 68 | 69 | ```rust 70 | pub struct ReadSet { 71 | state:Vec<(AccessPath,Vec)>, 72 | } 73 | pub struct ReadSetProof { 74 | //TODO define proof 75 | } 76 | 77 | pub struct StateFullTransaction { 78 | read_set: ReadSet, 79 | proof: ReadSetProof, 80 | transaction: SignedUserTransaction, 81 | // Transaction info is transaction execute result, include new state_root, event_root, etc. 82 | transaction_info: TransactionInfo, 83 | } 84 | 85 | ``` 86 | 87 | 富状态交易包含了交易执行依赖的状态,是可以自校验的,校验方法的伪代码表达如下: 88 | 89 | ```rust 90 | StateLessVM { 91 | 92 | fn eval(txn: StateFullTransaction, prev_state_root: HashValue): bool { 93 | // 通过 ReadSet 构造状态树 94 | let state_tree = build_state_tree(txn.read_set); 95 | // 验证 state_tree 的 root 和 prev_state_root 一致 96 | assert(state_tree.root == prev_state_root); 97 | // 在状态树的基础上执行交易 98 | let output = execute_txn(&state_tree, txn.transaction); 99 | // 将执行结果中的 WriteSet 写入 state_tree 100 | state_tree.apply(output.write_set); 101 | // 验证执行后的结果和 StateFullTransaction 的 transaction info 匹配 102 | assert(state_tree.root == txn.transaction_info.state_root); 103 | // 验证 transaction_info 中的其他字段 104 | } 105 | } 106 | ``` 107 | 108 | 109 | 110 | ### 智能合约的依赖 111 | 112 | 区块链分层后,给智能合约之间的依赖关系带来了难题,Layer2 的合约能否依赖 Layer 1 的合约?这里的依赖包含两方面的意义,一代码的依赖,二状态的依赖。当前的所有分层方案中,跨层的合约依赖问题都没有得到很好的解决,只能通过异步消息的机制互通。 113 | 114 | 在 Stargate 中,基于 Move 的静态依赖的特性,Layer2 可以在编译期直接依赖 Layer1 的合约。当 Layer2 的合约执行时,执行上下文的切换如下图所示: 115 | 116 | ![Cross Layer Contract](./images/cross_layer_contract.svg) 117 | 118 | 1. 如果 Layer2 合约依赖的 Layer1 的合约是无状态的,不需要读取状态(比如纯算法的合约),则和 Layer1 合约和 Layer1 合约之间的依赖一样。 119 | 2. 如果 Layer2 合约依赖的 Layer1 的合约获取了只读状态(使用 borrow_global 指令),则通过远程状态加载器从 Layer1 获取状态。不过读取的状态不是 Layer1 的最新状态,而是该 Layer2 交易关联的 Layer1 高度的历史状态。 120 | 3. 如果 Layer2 合约依赖的 Layer1 的合约获取了可修改状态(使用 borrow_global_mut/move_from/move_to 指令),则表明这个交易是一个跨层的交易,需要到 Layer1 执行跨层的状态迁移交易。这部分是否可以做成对开发者完全透明,需要进一步技术调研。当前先通过一种显式的方式进行状态迁移。 121 | 122 | 这样,就可以提供一种近乎于无缝的跨层的编程体验。 123 | 124 | ### 状态迁移 125 | 126 | 状态在不同的 Layer 之间迁移,类似于跨链方案,当前大多数方案都是通过合约将 Token 或者资产在某一层锁定,然后在另外一层铸造出来,需要针对每一种状态或者资产类型设计校验以及铸造方案(比如 Token 和 NFT 的校验是不一样的),或者只实现跨链的合约调用,确保交易执行成功,并不校验状态(有安全风险)。 127 | 128 | 使用 Move 这种面向资源的编程语言时,状态在不同的 Layer 之间迁移和合约中从外部存储加载状态类似,我们可以设计一种通用的状态迁移模型,支持任意的自由状态的跨层迁移。 129 | 130 | 1. 定义一种跨层的交易类型,该类型的交易实际上包含两个交易,一个需要在 Layer1 执行,一个需要在 Layer2 执行。 131 | 2. Layer1 的交易中,通过调用跨层的合约,将状态 S 从 Layer1 移动出来,锁定在一个特殊的数据结构中,叫做 SpacetimeBox, 这个结构同时存在与 Layer1 和 Layer2 的状态中。 132 | 3. Layer2 的交易中,通过调用跨层的合约,将 SpacetimeBox 移动出来并销毁,得到 S。 133 | 4. Layer2 给 Layer1 汇报 StateRoot 时,同时提交 SpacetimeBox 的不存在状态证明,证明 SpacetimeBox 已经在 Layer2 得到正确处理,Layer1 释放 SpacetimeBox。 134 | 5. 如果想从 Layer2 将 S 迁移回 Layer 1, 方法同理,不过顺序相反。从 Layer2 到 Layer1 的迁移,不同的方案有不同的挑战期,挑战期间中间状态会锁在 SpacetimeBox 中。 135 | 136 | ![crosslayer state moving](./images/crosslayer_state_moving.svg) 137 | 138 | 示例代码如下: 139 | 140 | ```rust 141 | module CrossLayer { 142 | // Move state `s` to layer2 with the `id`, only can call on layer1 143 | public native move_to_layer2(signer: &signer, id: Layer2ID, s: S); 144 | // Move state `S` from layer2 with the `id`, only can call on layer1 145 | public native move_from_layer2(signer: &signer, id: Layer2ID): S; 146 | // Move state `s` to layer1, only can call on layer2 147 | public native move_to_layer1(signer: &signer, s: S); 148 | // Move state `S` from layer1, only can call on layer2 149 | public native move_from_layer1(signer: &signer):S; 150 | } 151 | 152 | // transaction on layer1 153 | public(script) script_on_layer1(signer: Signer){ 154 | let s = MyModule::get_state_from_somewhere(&signer); 155 | CrossLayer::move_to_layer2(&siger, dappx_layer2, s); 156 | } 157 | 158 | // transaction on dappx layer2 159 | public(script) script_on_layer2(signer: Signer){ 160 | let s = CrossLayer::move_from_layer1(&siger); 161 | // do something with s. 162 | LocalModule::save_to_layer2(&signer,s); 163 | } 164 | ``` 165 | 166 | SpacetimeBox 的封装以及校验是在 native 层实现的,对合约层是透明的。通用的状态迁移最大的难题在于状态的校验,我们可以把状态分为两种: 167 | 168 | 1. 可以合并的状态,例如 Token。比如 1000 个 A Token 和 100 个 A Token 可以合并为 1100 个 Token。每种可以合并的状态需要在 Layer1 累加一个总数,跨层迁移时进行校验,保证二层不能凭空创造出 Token。 169 | 2. 不可合并的状态,例如 NFT,或者用户合约自定义的自由状态。SpacetimeBox 中记录了原始状态的哈希,保证状态跨层迁移时状态不会被改变。不可合并的状态,从 Layer1 迁移到 Layer2,只能改变归属,不能在 Layer2 更新。 170 | 171 | ## 技术架构 172 | 173 | ![stargate layers architecture](./images/stargate_layers_arch.svg) 174 | 175 | 整体架构分为三层, 176 | 177 | 1. Layer1 通过 PoW 共识保证安全(Security)和无准入(Permissionless)。这部分已经实现。 178 | 2. Layer2 通过 PoS 共识给 Layer1 提供终局性(Finality),同时给 Rollup 的 Accumulator 提供去中心化能力。 Rollup 方案可以让网络整体的 TPS 提高到 10~100 倍。 179 | 3. Layer3 通过状态通道(State Channel)以及 DAppChain ,将不同的应用的共识隔离在应用的局部网络中,可提供无限的扩展能力。 180 | 181 | ### Rollup 182 | 183 | Rollup 是一种相对成熟的扩容机制,一些项目已经实现,在 Rollup 中有几个角色: 184 | 185 | 1. 累加器(Accumulator),在其他项目中叫定序器(Sequencer)或者聚合器(Aggregator)。它主要的功能是给交易排序,并且定期将 Layer2 的交易提交到 Layer1 。Stargate 的 Rollup 方案中,它不仅仅提供排序,同时会将交易哈希进行累加,用于提供交易的顺序证明。累加器同时也要执行交易,并且定时将每个交易执行之后的状态树的根哈希提交到 Layer1。 186 | 2. 状态提供者(State Provider),按照累加器提供的交易顺序,执行交易,给第三方提供状态查询接口。 187 | 3. 校验者(Verifier),执行交易并与累加器提交到 Layer1 的状态树的根哈希进行比较,如果发现累加器作弊则向 Layer1 提交欺诈证明。 188 | 189 | 当前 Stargate 的 Rollup 方案属于 Optimistic Rollup 的一种。Optimistic Rollup 方案下,Layer1 并不会校验 Layer2 的每个交易,而是乐观的相信 Layer2 的 Accumulator 节点,直到有校验者提出欺诈证明,这样相当于把计算和状态都迁移到了 Layer2。 190 | 191 | 考虑到未来可能引入 ZK Rollup 方案,Stargate 的架构上,交易的校验机制设计为一种抽象的方案,可以通过富状态交易的重复执行的方式实现,也可以通过零知识证明的方式实现,可以通过统一的架构适配不同的方案。 192 | 193 | Stargate 的 Rollup 方案相对于其他的 Rollup 方案有几个差异点: 194 | 195 | 1. 累加器和 Layer1 共享一套 PoS 共识网络,实现去中心化以及高可用。 196 | 2. 通过累加器提供的顺序证明,以及富状态交易的验证机制,让钱包客户端也具有验证交易的能力,从而承担校验者的能力。 197 | 3. 数据可用性由 Layer2 PoS 共识网络以及钱包客户端来保证,累加器可以只给 Layer1 提交 Layer2 交易的哈希,这样 Rollup 可以将吞吐提升 100x。 198 | 199 | Rollup 依然依赖 Layer1 的全局共识,所以受限于 Layer1 的吞吐能力。它的主要目标是降低 Layer1 的计算成本,将状态维护在链下,通过乐观(Optimistic)挑战机制保证安全,可以即时确认 Layer2 的交易状态,给用户提供类似互联网应用的体验,同时也为 Layer3 的扩展方案打好基础。 200 | 201 | ### State Channel 202 | 203 | 状态通道(State Channel) ,或者叫支付通道(Payment Channel),以闪电网络(Lightning Network )为代表,也是一种比较成熟的扩容方案。它的思路是双方各自抵押一部分资产在链上,然后在链下维护一个两个参与方(理论上也可以扩展到多个参与方)的局部共识状态,每次变更都需要双方确认。但为了解决单方不合作难题,任何一方都可以单方在链上发起关闭通道的交易,等待一个挑战期后,通道自动关闭,参与方按最后一次双方确认的状态进行清算。 204 | 205 | Stargate 中的 State Channel 方案和其他状态通道有几个差异点: 206 | 207 | 1. State Channel 中可以执行合约,这样通道不仅仅用来转账,还可以执行一些复杂的,有状态累计的合约。 208 | 2. 因为它可以执行合约,所以也可以支付任意类型的 Token,以及 NFT。 209 | 3. 状态通道构建在 Layer2 之上,而不是 Layer1 之上,主要是要依赖 Layer2 的即时确认能力,降低建立通道的成本以及确认时间。 210 | 211 | 状态通道要大规模的应用,其中一个关键门槛是,Layer1 上的状态通道创建成本比较高,等待确认时间比较长。 212 | 213 | 但如果状态通道在 Layer2 之上,则可以消除这个门槛。这样 Starcoin/Stargate P2P 网络中的任意两个节点,都可以将自己的 P2P 连接升级为状态通道,然后通过状态通道进行数据传输和流式计费。这也是 DAppService 的基础设施。 214 | 215 | ### DAppService 216 | 217 | 基于 Stargate 框架搭建的,通过状态通道网络提供付费的 RPC 服务。 218 | 219 | DAppService 本身不是去中心化的,但它运行在 P2P 网络上,可以通过 P2P 网络进行服务发现以及远程调用,通过状态通道进行计费。 220 | 221 | 它相当于 Web2 服务到 Web3 服务的一个桥,任意当前的互联网服务都可以将自己的付费机制变更为流式计费机制,直接接入到 Web3 的 P2P 网络中。 222 | 223 | ### DAppChain 224 | 225 | 基于 Stargete 框架搭建的,包含子共识机制的 DApp Chain。它需要注册到 Layer2 中,同时抵押一定数额的 Layer2 资产。如果用户遇到 DApp 的欺诈,可向 Layer2 提交欺诈证明,Layer2 会对 DApp 进行惩罚,但惩罚的上限以 DApp 的注册抵押资产为上限。 226 | 227 | 整体网络概览架构如下图: 228 | 229 | ![stargate network architecture](./images/stargate_network_arch.svg) 230 | 231 | 1. Layer1 与 Layer2,Layer3 以及用户的终端钱包,都在同一个 P2P 网络中,都可以通过 P2P 网络进行通信。 232 | 2. 充分发挥终端的作用。终端钱包有自己在 P2P 网络中的身份,可以执行和验证交易,可以存储交易历史,提供数据可用性,可以提交 Layer2 的欺诈证明给 Layer1。同样,也可以提交 DApp 的欺诈证明给 Layer2。 233 | 3. 不同的 DApp,比如 X DApp, Y DApp 可选择不同的方案接入到 Starcoin 网络。 234 | 235 | 最后回答开篇提出的两个问题: 236 | 237 | 1. 区块链如何接受大规模用户?Starcoin 通过分层的方案来实现扩容。并且一个链要支持大规模的 DApp 接入,仅仅靠 Rollup 方案很难达到目的,必须考虑局部共识机制,所以 Stargate 提供了整体的 Layer1 + Layer2(Rollup) + Layer3(DAppService + DAppChain) 解决方案。 238 | 2. 应用应该以什么形态和链结合?未来应用会以两种方式和链结合,一种是只将链作为付费通道,Stargate 提供 DAppService 可以将传统的 WebService 直接接入到 Web3 的基础设施中。另外一种是 DApp 本身作为一个链,Stargate 提供一个应用链框架,可以快速搭建应用链,并接入到 Starcoin 网络中,安全受 Layer2 和 Layer1 的约束,资产可以在不同的层以及 DApp 之间迁移。 239 | 240 | ## 路线图 241 | 242 | ![stargate roadmap](./images/stargate-roadmap.svg) 243 | 244 | 路线图包含了三个主要的方向: 245 | 246 | 1. Layer1 , Layer2,Layer3,主要目标解决链的扩展性难题以及给 DApp 提供集成方案。 247 | 2. Move 以及 DApp 生态,主要目标是降低开发者的学习门槛以及给开发者提供全栈工具。 248 | 3. 多链生态的互操作性,主要目标是尽可能和其他链互通,融入到其他链的生态中去。 249 | 250 | 其中,箭头表示依赖关系,虚线表示可能的探索方向。 251 | 252 | Starcoin 团队在团队成立最初的一年多时间里,尝试在 Bitcoin 以及 Ethereum 上试验 Layer2 的方案,并得出了两个基本的结论: 253 | 254 | 1. Bitcoin 由于 Script 的限制,Layer1 很难给 Layer2 的交易提供仲裁能力,必须通过复杂的协议,将仲裁逻辑转换成锁模式(哈希锁,时间锁),很难支撑面向 DApp 的 Layer2 的需求。 255 | 2. Ethereum 的智能合约功能强大,但由于它的合约状态都绑定在合约账户内,无法做到跨层的状态迁移以及类型复用。一方面很难实现通用的状态迁移,另外一方面跨层的智能合约之间很难发挥出组合能力,等应用之间的关系进一步复杂就会遇到瓶颈。 256 | 257 | 所以 Starcoin 团队尝试了一种新的智能合约语言 Move,并先通过模拟 Layer1 的方式来对 Stargate 技术思路进行 PoC 试验,尝试在状态通道中执行智能合约,然后决定做一条新的 Layer1 for Layer2 的公链,在 Layer1 引入 Move 智能合约。 258 | 259 | 2021 年 5月,Starcoin 主网上线。经过半年的稳定运行和持续迭代,到现在(2022 年 1月)Layer1 已经初步具备了 Layer2 的关键依赖,所以继续 Stargate 项目的设计与开发,有以下几个关键节点: 260 | 261 | 1. EasyGas,实现以任意 Token 支付 Gas 的能力。该特性依赖于链上的 swap。大约在 2022 年第一季度实现。 262 | 2. 轻节点,轻节点虽然不保存全局状态,但可以执行交易,校验区块,生成富状态交易。嵌入式轻节点(浏览器或者手机客户端)依赖轻节点的实现,富状态客户端钱包依赖嵌入式轻节点的实现。 263 | 3. 分层的混合共识机制,在 PoW 基础上新增一套 PoS 的共识机制,给 Layer1 提供终局性。 264 | 4. Rollup 第一阶段,不考虑 Accumulator 的高可用,主要实现富状态交易的验证,状态的在不同层之间的迁移,以及跨层的合约依赖。 265 | 5. Rollup 第二阶段,将 Rollup 和 PoS 共识整合在一起,解决 Accumulator 高可用和去中心化的问题。 266 | 6. P2P 网络之上的 RPC 框架,这个是一个通用的 P2P 网络服务框架,用来简化 P2P 网络上的 RPC 服务的开发。 267 | 7. 基于 Rollup 的状态通道,以及状态通道之上的 DAppService 框架。 268 | 8. 基于 Rollup 的 DAppChain 框架。 269 | 270 | 271 | 272 | ### 术语说明 273 | 274 | 1. 自由状态:在 Move 中,如果某种类型的实例可以由外部 Module 持有,则认为该状态的自由的。 275 | 276 | > 注:本文档还在持续更新完善中,并不是最终版本。 277 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /sip-22/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 22 3 | title: "[SIP22] NFT" 4 | author: "@jolestar" 5 | sip_type: Standard 6 | category: Contract 7 | status: Alpha 8 | created: 2021-08-10 9 | weight: 22 10 | --- 11 | 12 | ## NFT 13 | 14 | NFT implementation and extension protocol 15 | 16 | 17 | 18 | ## Motivation 19 | 20 | In smart contracts, Tokens are used to represent fungible digital resources, while NFTs are needed to represent non-fungible resources. in Move, any instance of a type that cannot be copied and dropped can be considered a non-fungible resource and is an NFT. But NFTs need a standard for uniform presentation and collecting and transferring , so the design of this standard. 21 | 22 | ## Objectives 23 | 24 | To provide a common, extensible NFT standard, and providing a basic implementation of NFT-related operations. 25 | 26 | ## Type Definition 27 | 28 | ```rust 29 | struct NFT has store { 30 | /// The creator of NFT 31 | creator: address, 32 | /// The unique id of NFT under NFTMeta type 33 | id: u64, 34 | /// The metadata of NFT 35 | base_meta: Metadata, 36 | /// The extension metadata of NFT 37 | type_meta: NFTMeta, 38 | /// The body of NFT, NFT is a box for NFTBody 39 | body: NFTBody, 40 | } 41 | ``` 42 | 43 | NFT is a Move type that supports store ability, but not copy and drop, and contains some basic meta-information: 44 | 45 | 1. creator: address of the NFT creator. 46 | 2. id: the unique id under this NFT type. 47 | 3. base_meta: basic generic metadata information, mainly used to define how to display NFT. 48 | 4. type_meta: developer-defined metadata, also used to mark the type of NFT. metadata is not a resource, it represent information, so it supports copy + store + drop. 49 | 5. body: NFT contains resources, can be used to embed other resources. 50 | 51 | If you think of NFT as a box, NFT itself defines the box's ownership, unique number, and presentation, and NFTBody is the gem encapsulated in the box. Presentation is defined by Metadata. 52 | 53 | ```rust 54 | struct Metadata has copy, store, drop { 55 | /// NFT name's utf8 bytes. 56 | name: vector, 57 | /// Image link, such as ipfs://xxxx 58 | image: vector, 59 | /// Image bytes data, image or image_data can not empty for both. 60 | image_data: vector, 61 | /// NFT description utf8 bytes. 62 | description: vector, 63 | } 64 | ``` 65 | 66 | Metadata defines the basic information needed to display the NFT, name, image and description. If there is other information that needs to be extended, it can be defined in the type_meta. Image has two fields to represent, `image` indicates the image url, `image_data` can be directly stored in the image binary data, the client use the non-empty field in `image` and `image_data` to display the NFT. 67 | 68 | In addition, some type of NFT will use the same image for all instance, in this case, the `image` and `image_data` in the NFT metadata can both be empty, the client using the metadata in the NFTTypeInfo. 69 | 70 | 71 | ```rust 72 | /// The info of NFT type 73 | struct NFTTypeInfoV2 has key, store { 74 | counter: u64, 75 | meta: Metadata, 76 | mint_events: Event::EventHandle>, 77 | burn_events: Event::EventHandle>, 78 | } 79 | ``` 80 | 81 | NFTTypeInfoV2 is used to maintain a counter for the NFT id, as well as the global metata of the NFT type, each NFT type needs to be registered in the registry first. All NFT type is in the 0x1 account resources. 82 | 83 | >Note: NFTTypeInfo is upgrade NFTTypeInfoV2 in the stdlibv7 84 | 85 | ## Method Definition 86 | 87 | Each NFT type needs to be registered first, and the registration requires the NFT's NFTMeta type and a global metadata for that type. 88 | 89 | ```rust 90 | public fun register(sender: &signer, info: NFTTypeInfoExt, meta: Metadata) 91 | ``` 92 | 93 | After registration, three capabilities representing permissions will be move to the `sender`'s account. 94 | 95 | 1. MintCapability : used to mint the type of NFT 96 | 2. BurnCapability : used to burn the type of NFT 97 | 3. UpdateCapability: used to update the type of NFT's metadata 98 | 99 | These three permissions correspond to three methods: 100 | 101 | ```rust 102 | /// Mint NFT,return NFT's instance 103 | public fun mint_with_cap(creator: address, cap: &mut MintCapability, base_meta: Metadata, type_meta: NFTMeta, body: NFTBody): NFT 104 | 105 | /// Burn NFT,return NFTBody in the NFT 106 | public fun burn_with_cap(cap: &mut BurnCapability, nft: NFT): NFTBody 107 | 108 | /// Update NFT's metadata 109 | public fun update_meta_with_cap(cap: &mut UpdateCapability, nft: &mut NFT, base_meta: Metadata, type_meta: NFTMeta) 110 | ``` 111 | 112 | The above lists the basic methods related to NFT, and NFT how to store, how to transfer, this is not the NFT module itself care about things, is the function of NFTGallery. 113 | 114 | ## NFTGallery 115 | 116 | NFTGallery module provides the basic functions that users use to collect and store NFT. It contains the following methods: 117 | 118 | ```rust 119 | 120 | /// Init a NFTGallery to accept NFT for `sender` 121 | public fun accept(sender: &signer); 122 | 123 | /// Transfer NFT from `sender` to `receiver` 124 | public fun transfer(sender: &signer, id: u64, receiver: address); 125 | 126 | /// Get the all NFT info 127 | public fun get_nft_infos(owner: address): vector>; 128 | 129 | /// Deposit nft to `sender` NFTGallery 130 | public fun deposit(sender: &signer, nft: NFT); 131 | 132 | /// Deposit nft to `receiver` NFTGallery 133 | public fun deposit_to(receiver: address, nft: NFT); 134 | 135 | /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. 136 | public fun withdraw_one(sender: &signer): NFT; 137 | 138 | /// Withdraw nft of NFTMeta and id from `sender` 139 | public fun withdraw(sender: &signer, id: u64): Option>; 140 | 141 | ``` 142 | 143 | NFTGallery provides a generic space for storing and querying NFT, of course, developers can also design their own NFT storage module. 144 | 145 | ## Extensions 146 | 147 | ### Custom Metadata 148 | 149 | If the developer needs to add a custom metadata, you can define it in the NFTMeta type, for example, to define a video NFT, you need to add a video url. 150 | 151 | ```rust 152 | struct VideoNFT has copy, store, drop { 153 | video_url: vector, 154 | } 155 | struct VideoNFTBody has store{} 156 | ``` 157 | 158 | The actual NFT data format is equivalent to. 159 | 160 | ```rust 161 | struct NFT{ 162 | creator: address, 163 | id: u64, 164 | base_meta: Metadata, 165 | type_meta: VideoNFT, 166 | body: VideoNFTBody, 167 | } 168 | ``` 169 | 170 | ### Nested NFTBody 171 | 172 | If the developer wants to embed additional resources in the NFT, this can be done by way of a custom Body, for example, in the VideoNFTBody above where we wants to embed some Token: 173 | 174 | ```rust 175 | struct VideoNFTBody has store{ 176 | token: Token, 177 | } 178 | ``` 179 | 180 | ### Custom transfer 181 | 182 | There are NFT application scenarios, NFT transfer is restricted, such as as membership credentials. In this case, a custom NFT storage is needed to implement a custom transfer method. The NFT stored in the NFTGallery is fully controlled by the user, and the NFT developer cannot restrict its use and transfer. 183 | 184 | Take IdentifierNFT as an example, IdentifierNFT is a kind of NFT container, which guarantees that each user can only have one NFT of the same type and cannot be transferred by the user after the NFT developer grants the user an NFT, which is generally used in user identity-related NFT scenarios, such as medals of honor. 185 | 186 | ```rust 187 | /// IdentifierNFT contains an Option, which is empty by default, which is equivalent to a box that can hold NFT 188 | struct IdentifierNFT has key { 189 | nft: Option>, 190 | } 191 | 192 | /// The user uses the `accept` method to initialize an empty IdentifierNFT under his account 193 | public fun accept(sender: &signer) { 194 | move_to(sender, IdentifierNFT { 195 | nft: Option::none(), 196 | }); 197 | } 198 | 199 | /// The developer grants the nft to the receiver by MintCapability and embeds the nft into the IdentifierNFT 200 | public fun grant_to(_cap: &mut MintCapability, receiver: address, nft: NFT) acquires IdentifierNFT { 201 | let id_nft = borrow_global_mut>(receiver); 202 | Option::fill(&mut id_nft.nft, nft); 203 | } 204 | 205 | /// Developers can also take out the NFT in the `owner` IdentifierNFT by BurnCapability 206 | public fun revoke(_cap: &mut BurnCapability, owner: address): NFT acquires IdentifierNFT { 207 | let id_nft = move_from>(owner); 208 | let IdentifierNFT { nft } = id_nft; 209 | Option::destroy_some(nft) 210 | } 211 | ``` 212 | 213 | In the above scenario, the NFTMeta definition and the registered developer can programmatically define the transfer logic of the NFT (of course, it is possible to disallow the transfer). 214 | 215 | ## Example usage scenarios 216 | 217 | ### NFT game props 218 | 219 | One advantage of using the NFT in Move to define game props is that you can define multiple NFT types in the same Module, and you can also define the combination of props, such as: 220 | 221 | ```rust 222 | /// The player combines two L1 cards into a new L2 card 223 | struct L1Card has store {} 224 | struct L2Card has store { 225 | first: L1Card, 226 | second: L1Card, 227 | } 228 | ``` 229 | For a more detailed example see [nft_card.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/nft_card.move) 230 | 231 | ### NFT as membership 232 | 233 | A user pays the membership fee to become a member, the membership fee is locked in the NFT. When the user performs a membership action or quit, the membership is checked for expiration and the membership fee is deducted according to the join time. For a more detailed example, see [identifier_nft.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/identifier_nft.move) 234 | 235 | ### NFT as shopping credentials 236 | 237 | Users directly mint NFTs by paying Token and then exchange NFTs for physical goods. Users also can trade NFTs between themselves. for a more detailed example,see [nft_boxminer.move](https://github.com/starcoinorg/starcoin/blob/master/vm/functional-tests/tests/testsuite/nft/nft_boxminer.move) 238 | 239 | ### Distribute NFTs via MerkleTree proofs 240 | 241 | The NFT developer defines the NFT and submits the MerkleTree root on the chain, and the user takes the NFT proof and mint it by themselves. 242 | 243 | Starcoin's GenesisNFT is minted in this way. GenesisNFT is distributed to the addresses of accounts that participated in Barnard network mining before the starcoin mainnet was launched. 244 | 245 | The parent_hash(0x0f2fdd39d11dc3d25f21d05078783d476ff98ca4035320e5932bb3938af0e827) of the main network's genesis block points to the block on the Barnard network with a height of 310,000. All addresses on the Barnard network that have minted blocks prior to this height can mint a GenesisNFT. 246 | 247 | For details, see [GenesisNFT.move](https://github.com/starcoinorg/starcoin/blob/master/vm/stdlib/modules/GenesisNFT.move) [MerkleNFT.move](https://github.com/starcoinorg/starcoin/blob/master/vm/stdlib/modules/MerkleNFT.move) 248 | 249 | ## Differences between Starcoin NFT standard and ERC721/ERC1155 250 | 251 | 1. ERC721/ERC1155 is Interface and does not define the implementation, extensibility is achieved through different implementations. The Starcoin NFT standard contains implementations of data types and basic operations, and extensibility is achieved through upper-level combinations. 252 | 2. By default, Starcoin NFT, similar to ERC721, is not fungible. However, third parties can extend the splitting and merging logic to achieve the purpose of ERC1155. 253 | 3. The NFT of ERC721/ERC1155 can only be moved within the contract, and cannot be moved from the contract to another contract, so the agreement combination on the NFT is very difficult. Thanks to the type feature of Move, the NFT in Starcoin can be moved between different contracts, and other contracts can define new types to encapsulate the NFT and expand new transfer logic (such as auctions). This brings great convenience to the protocol design on the NFT, and can combine a lot of gameplay. 254 | 4. ERC721/ERC1155 distinguishes NFT types by contract address. To implement multiple NFTs, multiple contracts need to be deployed. If there are many types of NFTs, contract calls will be very complicated. 255 | 5. Starcoin's NFT is stored in the user's state space, and all of the user's NFTs can be displayed by listing the resources of the user's state space, including NFTs embedded in other resource. This brings great convenience to ecological tools, such as displaying NFTs in wallets or block explorer, or the auction market. 256 | -------------------------------------------------------------------------------- /sip-6/images/cross_layer_contract.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layer2 Contract

MyL2Module

function my_l2_function{
    let s2 = borrow_global<S2>(addr1);
    let s1 = MyL1Module::my_l1_functoin();
    //... handle s1 and s2
}

MyL2Module...
Layer1 Contract

MyL1Module

function my_l1_function: S1 {
    let s1 = borrow_global<S1>(addr2);
    return s1;
}

MyL1Module...
Layer2 state tree
Layer2 state tree
Layer1 state tree
Layer1 state tree
Load state
Load state
Load state
Load state
Context 
Switch
Context...
Call
Call
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /sip-2/index.zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 2 3 | title: "[SIP2] 技术白皮书" 4 | author: Starcoin Core Dev 5 | sip_type: paper 6 | category: Core 7 | status: Beta 8 | created: 2021-11-01 9 | weight: 2 10 | --- 11 | 12 | # Starcoin, 一个分层智能合约及去中心化金融网络 13 | 14 | 摘要:Starcoin 是一个去中心化分层智能合约网络,它旨在提供一种安全的数字资产及去中心化金融运行平台,让区块链能够更低门槛应用在更多领域。我们提出了一个分层区块链模型的建议,旨在创建一个数字资产安全、并能达到性能及可扩展的目标。安全是区块链立身之本,Starcoin 从设计之初就把安全作为首要目标,从基础层、共识层、协议层、扩展层、应用层等多层面进行深度探索与改进,全力保障主链和数字资产的安全。 15 | 16 | 为了达到去中心化的目的,Starcoin 选择成熟的中本聪共识算法,并在其基础上进行增强,可以动态适应网络算力状态,达到链上性能及稳定性的平衡。交易是基于智能合约来运行,使用一种名为 Move 的编程语言。我们使用 Move 来定义区块链的核心机制,如数字资产和 DAO 治理规则。这些核心机制能够创建一个独特的去中心化治理机制。 17 | 18 | 为了验证 Starcoin 整体设计,我们已经构建了一个开源的原型实现。 19 | 20 | 21 | ## 简介 22 | 23 | Starcoin 是新一代的区块链公链基础设施,是一个分层的,去中心化的区块链系统。 24 | 25 | Starcoin 一层专注于提供数字资产基本能力,能够安全快速的定义资产,并通过智能合约灵活地实现资产转移交换等能力。 26 | 27 | Starcoin 二层专注于解决资产转移交换等过程中的扩展性和性能问题。由于 Starcoin 的特殊设计,Starcoin 二层可以使用一层的数据,一层也可以校验二层的运算结果,一层二层有机结合在一起,资产可以在一二层之间自由流动。 28 | 29 | 长久以来,区块链系统存在所谓的区块链不可能三角,即无法同时达到可扩展(Scalability)、去中心化(Decentralization)、安全(Security),三者只能得其二。 30 | 31 | 比特币以及以太坊便是一种追求“去中心化”与“安全”的技术组合,而不追求可扩展。其他区块链项目也都是在这三者之间进行选择。而三者只选择其二的做法,很大程度上难以满足商业使用的需求。 32 | 33 | Starcoin 试图通过区块链分层技术,在区块链一层达到去中心化和安全,通过区块链二层达到很大的可扩展性,达到可以供商业使用的程度。因此可以说 Starcoin 试图通过紧密结合的区块链一层二层来打破区块链不可能三角。 34 | 35 | 36 | ### 设计理念 37 | 38 | 1. 以价值流转为中心 —— 所有的分层以及周边功能的改进都是以促进价值流转为中心目标。 39 | 2. 共识分层治理 —— 不是所有的认知都需要全局共识,共识也需要分层。越底层越侧重于安全和去中心化,越上层越侧重于性能和便利性。 40 | 3. 技术创造可能,社区决定取舍 —— 尽量通过技术消弭分歧,创造可能,保持技术中立,价值观层面的的选择和取舍留给社区决定。 41 | 42 | 接下来从 6 个方面来介绍 Starcoin 的设计。 43 | 44 | ## 1. 增强的中本聪共识协议 45 | 46 | 47 | Starcoin 共识是一种比特币中本聪共识的增强版本。为了加快出块速度和降低交易确认时间,我们引入叔块率等运行期数据,对出块时间,难度,出块奖励进行动态调整,可以最大限度利用网络,减少用户等待时间。此外,我们还提供了区块链的动态调整能力,一些关键参数通过链上治理机制来实现配置修改。 48 | 49 | 中本聪共识最早由比特币采用,也是区块链早期广泛使用的一种共识方法 [1]。目前为止中本聪共识是容错能力最好的公有链共识机制,其设计简单,通讯开销低,经过了数十年的验证。但是其吞吐能力较低,出块时间过长,用户体验较差。因此,我们选择了对中本聪共识进行加强,使得 Starcoin 具备以下的特性: 50 | 51 | 1. 动态调整出块速度以及区块大小,在安全,网络吞吐,用户体验之间寻求平衡。 52 | 3. 共识相关的参数可通过社区治理,经合约升级。 53 | 54 | ### 引入叔块 55 | 56 | 中本聪共识中,要提高网络吞吐,可以通过 (1) 增加区块大小,或 (2) 缩短出块间隔。这两种办法都会增大网络中竞争块出现的概率。而这些竞争块中,最多只有一个区块能够进入主链,为打包交易提升吞吐作出贡献,而其他块则成为孤块。区块越大,出块时间越短,孤块会越多,而孤块率增加会降低双花攻击的难度,所以我们需要将孤块率限制在一个阈值之内。 57 | 58 | 我们在孤块基础上,引入叔块概念。首先,定义每 N 个块为一个 Epoch。当满足如下条时,则定义区块 B2 为 B1 的叔块: 59 | 60 | 1. 在同一个 Epoch 内。 61 | 2. B2 的父块属于 B1 的任一祖先。 62 | 63 | 我们用 Epoch 内的叔块率评估网络的拥塞情况,并以此作为出块时间,出块大小调整的依据,实现充分利用网络,提升吞吐的同时,也可避免区块过大或者出块时间太短导致孤块过多,安全降低。 64 | 65 | consensue 66 | 67 | 68 | ### 动态出块时间调整 69 | 70 | 为了将叔块维持在一个合适的阈值内,在每个 Epoch 末,都会重新调整下一个周期的出块时间。 71 | 72 | 如果叔块率较高,则说当前的出块时间间隔下,网络中存在较多的分叉和孤块,我们需要调大出块的时间,缓解此问题。反之,则说明全网出块情况良好,还能进一步缩短出块时间,进一步提高全网吞吐。 73 | 74 | 算法引入以下参数: 75 | 76 | | 名称 | 描述 | 77 | | ------------------ | ------------------------------ | 78 | | epoch_avg_time | 上一个周期内的算数平均出块时间 | 79 | | epoch_uncles_rate | 上一个周期的叔块率 | 80 | | uncles_rate_target | 目标叔块率 | 81 | | next_time_target | 下一个周期的出块时间 | 82 | 83 | 84 | 计算方式: 85 | 86 | ```rust 87 | next_time_target = epoch_avg_time * epoch_uncles_rate / uncles_rate_target 88 | ``` 89 | 90 | ### 动态调整区块大小 91 | 92 | 我们希望区块的大小限制能根据网络情况来动态调节,而区块的大小和区块中所有交易使用掉的 Gas 成正比,所以我们通过调整区块的 Gas 限制来调整区块大小。 93 | 94 | 针对一个 Epoch 内的所有区块 Gas 消耗统计,并结合出块速度,动态的调整区块 Gas 限制。当出块速度达到系统设置的最小值,全网拥塞情况处于良好,因此可以调大区块的 Gas 限制,增加区块大小;反之,当出块速度达到系统设置的最大值时,全网较为拥塞,因此需要降低区块的 Gas 限制,降低区块大小。 95 | 96 | 97 | ### 动态难度调整机制 98 | 99 | Starcoin 改进了中本聪共识的难度调整算法,使得: 100 | 101 | 1. 反应更快速:当全网算力发生变化时,难度值能够快速做出反应。 102 | 2. 出块时间更稳定:在全网算力不变时,有的块偶发性的出快或者出慢,难度不应该剧烈的波动。 103 | 104 | 105 | 通过以下办法进行改进: 106 | 107 | 1. 根据叔块率调整出块时间从而调整下一个 Epoch 的难度。 108 | 2. 难度计算中引入区块高度做为权重,对平均出块时间的计算为高度加权的算术平均。 109 | 3. 使用更短的难度周期。 110 | 111 | 112 | 算法引入以下参数: 113 | 114 | | 名称 | 描述 | 115 | | ------------------ | ------------------------------ | 116 | | block_time_target | 下一 Epoch 的出块时间 | 117 | | n | 难度调整周期内的区块数(小于 Epoch 内的区块数,初始值为 Epoch 区块数的十分之一)| 118 | | next_target | 下一周期的难度目标 | 119 | | block_target_i | 高度为 i 的区块难度 | 120 | | block_time_i | 高度为 i 的区块出块时间 | 121 | 122 | 123 | 计算方法: 124 | 125 | ```rust 126 | next_target = avg_target * avg_time / block_time_target 127 | ``` 128 | 129 | 其中: 130 | 131 | ```rust 132 | Arithmetic Mean avg_target 133 | avg_target = (block_target_cur-n+1 + block_target_cur-n +...+ block_target_cur) / n 134 | 135 | Weighted Arithmetic Mean avg_time 136 | avg_time = block_time_cur-n+1 * 1 + block_time_cur-n * 2 +...+ block_time_cur * n / ((n) * (n+1) / 2) 137 | ``` 138 | 139 | ### 动态出块奖励调整 140 | 141 | Starcoin 出块奖励的调整遵循如下原则: 142 | 143 | 1. 奖励为难度 / 时间线性。根据下一个周期的出块时间,来动态调整出块奖励。 144 | 2. 分配一定比例的奖励给汇报叔块的区块。 145 | 146 | Starcoin 的动态调整的算法依赖叔块率的数据,而叔块信息需要矿工额外的付出成本去收集,为了奖励矿工在区块中汇报叔块信息,会分配一定的奖励给当前汇报叔块的矿工。 147 | 148 | 叔块奖励计算方式: 149 | 150 | ```rust 151 | reward = next_epoch_block_reward * (1 + reward_per_uncle_percent * uncles) 152 | next_epoch_reward_block = base_reward_per_block * block_next_time_target / base_time_target 153 | ``` 154 | 155 | ## 2. 所有权明晰的状态存储 156 | 157 | 区块链的状态存储机制是区块链系统设计中的关键点之一,对链的性能以及安全性都有很大的影响。Starcoin 的状态存储,采用类似以太坊的账户模型,所有用户的状态构成了一个通过地址映射的状态树。 从创世状态开始,随着将交易作为输入信息,将状态推进到下一个新的状态中,生成新的状态树。 158 | 159 | 以太坊将账号分为合约账号和用户账号。合约账号用于部署合约的代码以及存储合约的状态,用户在某个合约中的状态都保存到该合约账号下,读写权限也由合约自己控制。这样的设计自由度很高,但导致合约状态的所有权不明确,从而容易带来安全上的问题以及很难解决"状态爆炸"问题。 160 | 161 | Starcoin 以太坊账户模型基础上做了以下改进: 162 | 163 | 1. 废弃了合约账号,任意账号都可以部署智能合约,部署的智能合约在当前账号下。 164 | 2. 通过对合约编程语言中状态存储机制的改变,让智能合约的开发者很容易的把合约的状态分散保存到该状态所属的用户地址下,从而明确状态的所有权。 165 | 166 | 通过这样的改造,一方面增强了链对用户状态的安全保护能力,另外一方面也为状态计费提供了可能。 167 | 168 | ### 两级状态模型 169 | 170 | 我们在 Diem 的 Jellyfish-Merkle 树的基础上,增加了可分叉功能作为状态存储的基础组件,封装成两级状态树结构。Jellyfish-Merkle 是一种前缀查询树结构。整个链的状态是一个全局树,叶子节点是每个用户的状态 AccountState,查询路径是账号地址;AccountState 里存的便是用户的 Resource 和 Code 的二级 Merkle 树的根哈希值。如下图所示: 171 | 172 | state model 173 | 174 | Code 树的叶节点是每个合约 Module 的代码,查询路径是 Module 名称。Resource 树的叶节点是合约中的状态,查询路径是状态类型 StructTag。这样合约中即可通过 `borrow_global(address)` 方法读取或者通过 `move_to(address,resource)` 写入状态。 175 | 176 | Starcoin 通过两级状态模型,可以便捷的提供状态存在和权益证明。 177 | 178 | ### 计费策略 179 | 180 | 由于区块链网络状态会随着账号增加而增加,而对状态的读写计费都是发生交易的时候一次性通过 Gas 计算,用户并不会为自己长期占用了链上的状态而承担额外成本,从而也没有动机删除和清理无用的老旧状态。所以区块链技术圈一直在探索一种合适的状态计费机制,也有人在以太坊上提出了状态租赁机制,但由于前面提到的以太坊上合约状态的所有权不明确,要实现状态计费非常困难。而 Starcoin 的状态机制明确了状态所有权,从而为状态计费提供了可能。 181 | 182 | Starcoin 状态计费策略采用后置抵押方式,用户可以使用的存储空间 STCBytes 根据用户持有的 STC 实时换算,每次执行交易前,检查用户的 STCBytes 余额(计算公式如下),如果余额小于阈值则拒绝该交易执行。 183 | 184 | 余额的计算方法: 185 | 186 | ```rust 187 | STCBytes = STC * 置换率 - 用户已经使用的 STCBytes 大小 188 | ``` 189 | 190 | STCBytes 余额是每次交易前计算截止到上次用户的交易结束时用户的存储状态,允许用户超额使用一次,这样计算 STCBytes 时不需要考虑当前的交易。这样可以鼓励用户主动释放掉不用的资源,减少 STCBytes 的使用,从而利于系统的良性发展。 191 | 192 | 193 | ## 3. 新一代智能合约编程语言、虚拟机和标准库 194 | 195 | 智能合约编程语言,虚拟机,以及合约标准库是去中心化金融基础设施的核心部分,如何安全、便捷的在智能合约中表达资产,是区块链智能合约领域一直在研究的方向。Starcoin 选择面向数字资产的智能编程语言,以及虚拟机,并提供了丰富的合约标准库。 196 | 197 | 198 | ### Move 编程语言 199 | 200 | Move 编程语言最早出现在 Facebook 的 Diem 区块链项目中 [5]。作为一种面向数字资产的智能合约编程语言,Move 具有 Resource 作为一等公民、灵活、安全、可验证等特性。这些特性和 Starcoin 的智能合约编程语言设计理念极为契合,因此 Starcoin 选择 Move 做为其智能合约的首选编程语言。 201 | 202 | **Resource 作为一等公民** 203 | 204 | 以太坊中的链上原生资产是 ETH,而用户定义的的资产是符合 ERC20 的 Token,合约中处理原生资产和 Token 需要使用完全不同的规则。同时链本身只对 ETH 有感知,对 Token 无感知,二者的安全级别有差异。而在 Starcoin 中,无论是链上原生的 STC,还是用户自定义的 Token,都是 Resource 类型,对链来说都是一等公民,使用同样的编程接口操作,安全级别一致。 205 | 206 | **安全性** 207 | 208 | 以太坊里资产是用整型来表示 [2]。资产实际上存放在合约账户中一个用户地址到余额的映射表里,它用来记录每个用户所拥有的资产数量。合约需要非常仔细的实现每个接口,以保证不会发生资产被复制或者丢失的情况。而 Move 不同于 Solidity ,它能够以线性逻辑的语义来定义 Resource 类型,开发者可以用 Resource 来自定义资产,Resource 永远不能复制或隐式丢弃,只能在程序存储位置之间移动。 这种安全保证根植于 Move 的静态类型系统,开发者不仅可以使用 Resource 来创建安全的数字资产,而且更容易编写正确的业务逻辑来操作资产。 209 | 210 | 保证资源安全、类型安全、内存安全通常有两个选择:使用高级编程语言,编译器检查保证;或者使用低级无类型汇编,运行时检查保证。Move 采用一个折衷方案:使用有类型的字节码,字节码在执行前进行安全校验,类似于 JVM 的字节码校验,然后再解释执行。这样做的好处是源码的编译器不用是可信的。 211 | 212 | 此外,Move 的 Module 是一种强类型抽象机制,Module 里面可以声明类型和方法,这些方法可以用来创建、销毁和更新 Module 里声明的类型。 在声明类型的 Module 内部,类型是透明的,而在其外部是不透明的。也就是说在 Module 外部无法直接创建、更新和销毁 Module 内声明的数据类型。必须通过 Module 里声明的方法来创建、更新和销毁。 213 | 214 | **可验证性** 215 | 216 | 理想情况下可以通过链上的字节码运行时校验保证所有的安全属性,可是这样会增加链上计算开销和协议复杂度。静态验证工具包括形式化验证工具可以有效降低链上计算开销、提升安全性。Move 定义了一套规范语言叫做 Move specification language,它通过前提条件、后置条件、不变式等来描述程序怎么样才算正确运行,即所谓的规范。然后通过 Move to boogie compiler 将 Move 程序和规范转换成 boogie 程序(一种具有形式化语义的中间验证语言)。最后通过形式验证领域的自动定理证明求解器来验证程序是否符合规范。 217 | 218 | **灵活性** 219 | 220 | Move 的交易由 Module 和 Script 组成。Module 允许开发人员使用和扩展标准库功能来开发其智能合约。Script 可以让用户在交易中使用一个或多个Module,加入更多逻辑。这种 Module 和 Script 相结合的形式使交易更加灵活,同时节省时间和资源。 221 | 222 | ### Move 虚拟机 223 | 224 | 从抽象的角度看,区块链实际上是一个复制状态机(Replicated State Machine)。世界状态通过在虚拟机上执行交易而更新。Move 虚拟机的输入就是交易的字节码加上当前的世界状态,输出是对世界状态进行更新的变更集。 225 | 226 | Move 虚拟机由两部分组成:一个字节码解释器,一个字节码校验器。为了表达 Resource 的语义,基于寄存器的虚拟机实现会导致在方法间移动 Resource 变得复杂,而基于栈的虚拟机实现再加上有类型的局部变量会使这种操作变得自然。所以 Move 的解释器采用了类似于 JVM 的基于栈的字节码解释器。跟 EVM 类似,Move 也是采用 Gas 机制来解决停机问题。 227 | 228 | Move 的安全性主要是由字节码校验器来保证的。在解释器执行之前,先要由校验器对安全性进行检查。校验器的核心功能包括:控制流图的生成、栈的越界检查、类型和种类检查、引用检查,还有与世界状态的链接等。其中栈越界检查就是检测每个方法访问操作数栈的范围,保证访问的栈的深度是合法的。具体做法是以基础代码块为单位,查看每条字节码执行之后对操作数栈的影响。接下来是通过类型检查保证操作数的类型是正确的。通过种类检查保证 Resource 不可复制、不可销毁。通过引用检查保证即便没有所有权也可以通过借用机制正确使用某 Resource。最后将字节码里的 Resource 类型同世界状态进行链接。 229 | 230 | ### 标准库 231 | 232 | 作为一个通用、安全的智能合约平台,Starcoin 为开发者提供了经过形式化验证的智能合约标准库。标准库包含了40多个常用的功能模块,其中除了账户、转账、交易、事件、Errors、Math、Vector 等基本功能模块外,还包含了Token、Dao、OnChainConfig 等前瞻性功能模块。 233 | 234 | **Token** 235 | 236 | 以太坊是通过 ERC20 接口来定义 Token 的。如上中提到的,以太坊的 Token 存放在合约账户中一个映射表里,实际上是一个中央账本,合约需要非常仔细的实现每个 ERC20 接口,以保证不会发生资产被复制或者丢失的情况。Starcoin 没有使用中央账本,而是利用 Resource 和 Capability 实现了去中心化管理的 Token 机制。 237 | 238 | **DAO** 239 | 240 | 区块链作为一个快速发展、自我更新的组织集合,去中心化治理发挥了至关重要的作用。Starcoin 抽象出一套链上治理机制,包括提议者提议、参与者(投票者)投票、决策、部署、执行等几个步骤,分别封装在不同的智能合约标准模块中,合约开发者可以直接复用标准模块中的治理机制。 241 | 242 | **形式化验证** 243 | 244 | Starcoin 标准库里所有的 Module 都经过了形式化验证。Module 中的每个方法都建立了对应的规范,它通过前提条件、后置条件、不变式等来描述程序怎么样才算正确运行。然后通过 Move 的形式化验证工具 Move Prover 来保证 Module 的实现跟规范相符。形式化验证在很大程度上提升了标准库的安全性和可靠性。 245 | 246 | ## 4. 自我演进的去中心化链上治理体系 247 | 248 | 区块链的治理结构包含了决策和沟通的过程,对区块链特别是公链生态具有隐形但长远的作用。链下治理始于上一代公链,新一代的公链则更青睐链上治理。 合约协议的代币治理也将以太坊上去中心化金融浪潮推到了前所未有的高峰,这也是下一代公链应该考虑的严肃议题。 长远来看链上治理符合区块链的开放内涵,Starcoin 在链上治理以及合约治理方面也做出了自己独特的改进。 249 | 250 | ### 治理是什么 251 | 252 | 如果将区块链社区识为一个组织,治理是这个组织就改变区块链特性所做出的决策过程,尤其针对于共识和经济分配,可以说是区块链的“宪法”。在流程上说,治理包含提议者提议、参与者(投票者)投票、决策、部署、执行等几个内容。 治理的作用在于使得区块链系统进入一个更加长久、有序的发展过程,提升整个网络的价值。传统的组织一般局限于一国,治理机制遵循当地法律的规则,治理产生的争议可通过司法系统裁决。而去中心化的区块链治理,其参与者来自全球,无法依赖司法系统裁决,怎样从中抽象出一套合理治理机制,解决争议,构建约束力,仍处于探索阶段。 253 | 254 | 比特币的 BIP,以太坊的 EIP 等治理模式,基本属于链下治理模式。 一般流程是提出提案,社区讨论,核心开发者开发并发布版本,矿工进行节点升级,代码中约定在某个高度自动激活新特性。大多数情况下,这种治理模式也运作良好,但一旦社区中的开发者和矿工就某个特性之间产生不可调和的分歧,链和社区则会面临硬分叉的风险。 255 | 256 | 纵观比特币和以太坊面临的几次重大的分歧,可以发现社区治理面临的最大困境有两个: 257 | 258 | 1. 没有一个明确的指标来判断哪一种主张在社区中达成了多数的共识。 259 | 2. 链下协商的协议在链上没有约束力。 260 | 261 | 因此,我们试图在 Starcoin 中进行链上治理,尝试一定程度解决上面的两个困境。 262 | 263 | ### Starcoin 的治理 264 | 265 | 我们认为链上治理一定程度能解决前面提到的两个困境。首先无论治理的机制如何设计,投票最终会产生一个明确的结果,给社区传达一个明确的信息。其次,链上治理推迟了决策的时间节点,开发者和矿工可以先履行自己的职业责任,只是从技术角度评估提案的可行性,开发以及升级节点,然后再和社区成员一起决策是否激活以及在什么时候激活新的特性。最后,一旦链上投票产生结果,由于节点实际上已经都升级完成,最终投票结果在链上会自动执行,具有约束力。 266 | 267 | 所以我们提出了治理机制的设计原则:『技术创造可能,社区决定取舍』。在开发以及升级阶段,开发者和矿工应该对提案保持技术中立态度,等升级完成,需要投票的阶段,再作为社区成员一起来行使价值观选择权,决定取舍。 268 | 269 | Starcoin 的链上治理有以下几个流程: 270 | 271 | 1. 提案者发起提案,当前发起提案没有准入限制,任何系统参与者都可以发起提案。 272 | 2. 经过公示后,投票者进行投票,当前的投票机制是 Token 质押投票,票数与质押的 Token 数量成正比。 273 | 3. 投票期过后,任何系统参与者都可以调用,决策合约进行提案决策。 274 | 4. 决策通过后的提案,再次经过公示后,可由任意系统参与者提交执行。 275 | 276 | Starcoin 的链上治理机制有几个重要的设计考量: 277 | 278 | **治理制度可治理** 279 | 280 | 每个链上治理系统的设计都需要考虑: 281 | 282 | 1. 提案者和投票者的准入原则。 283 | 2. 决策时的投票参与率以及投票通过率。 284 | 3. 投票制度的选择。 285 | 286 | 这几个因素决定了治理系统的去中心化程度以及决策执行效率。但由于治理的复杂性,不可能在一开始就设计一个完美的治理制度,所以治理制度本身的演进机制非常重要。Starcoin 系统的参与者可以通过链上治理策略对该系统本身的治理参数以及投票制度进行去中心化治理升级,不断演进,以适应瞬息万变,不断更新的区块链技术热潮。 287 | 288 | **治理制度可复用** 289 | 290 | 很多去中心化金融协议构建于代币治理系统之上,通过协议代币的治理来不断迭代协议。 Starcoin 的治理系统原生支持任意的代币协议,代币协议只需要接入 Starcoin 的治理合约即可实现代币治理,从而复用整个治理制度。 合约治理内置在 Starcoin 的合约标准库中,这使得去中心化金融协议能够更好的利用代币治理达到协议的持续升级和发展。 291 | 292 | **最低准入门槛** 293 | 294 | 治理过程中多种角色,无论是提案者,投票者,执行者,都尽量不设置准入机制,保证最低准入门槛,充分利用社区的群体智慧。 295 | 296 | **小结** 297 | 298 | 区块链的成功取决于其进化能力。这种演变将带来许多方向性决定,而围绕这些决定的治理最能决定系统的未来。有别于其他拥有治理能力的区块链系统, Starcoin 将链本身的治理和合约协议的治理统一在一起,使得 Starcoin 的治理机制能够服务于更广泛的去中心化应用, 同时可通过自演进,不断升级成更加成熟的治理制度。 299 | 300 | 301 | ## 5. 安全的区块链 302 | 303 | 304 | Starcoin 从设计之初就把「安全」作为首要目标之一,从基础层、共识层、协议层、扩展层、应用层等多层面进行深入思考,从数据逻辑、智能合约、操作权等多维度进行深度设计,力争全方位覆盖,全力保障链和数字资产的安全。 305 | 306 | security 307 | 308 | ### 基础层安全 309 | 310 | Starcoin 使用 Rust 语言开发,保障基础组件的内存安全与高效。众所周知,使用 C/C++ 语言经常有内存安全方面的问题,而其他一些高级语言如 Java/Go/Python 等,受 Runtime 和垃圾回收机制等方面的影响,执行效率通常会比 C/C++ 略逊一筹。Rust 语言集二者长处于一身,在保证了内存安全的同时,又兼顾了极致的执行效率。Starcoin 在选择开发语言的时候充分考虑到了安全性和运行效率等因素,选择 Rust 语言开发,最大程度上保障 Starcoin 的安全与高效。 311 | 312 | 在 Starcoin 的整体设计中,提供了四个层面的数据校验机制: 313 | 314 | 1. 交易可校验:BlockHeader 包含一个全局交易累加器的根哈希,任何上链的交易都有对应的全局证明。 315 | 2. 状态可校验:BlockHeader 包含一个全局状态状态树的根哈希,保障了状态可验证。 316 | 3. 区块可校验:BlockHeader 包含一个 BlockBody 的哈希,用于校验 BlockBody 中的数据。 317 | 4. 链可校验:BlockHeader 包含一个全局区块累加器的根哈希。任何一个区块可以提供一个和当前区块的关系证明,不需要遍历区块即可验证某个区块是否是当前区块的祖先区块。参考下图 318 | 319 | block proof 320 | 321 | 以上是 Starcoin 安全性的基石。其中,「交易累加器」和「区块累积器」组成了 Starcoin 独特的「双累加器」模型,为数据安全提供坚实的基础。 322 | 323 | 324 | ### 共识层安全 325 | 326 | Starcoin 共识针对中本聪共识做了一些改良,在继承中本聪共识安全、完全去中心化和防篡改等特性的同时,在安全方面的改进体现在: 327 | 328 | 1. 更加敏锐的感知和适应算力波动 329 | 4. 可通过链上治理调整共识参数,降低硬分叉带来的安全风险的可能 330 | 331 | ### 协议层安全 332 | 333 | Starcoin 协议在数据安全和共识层安全的基础上进行设计,充分保障了链在非可信网络中的安全性。Starcoin 协议本着数据可验证的原则,对接收到的网络数据进行严格的校验,迅速甄别作恶节点,从而起到保护节点安全的作用。 334 | 335 | ### 扩展层安全 336 | 337 | 为了更好地扩展区块链的能力,Starcoin 将智能合约的安全作为重要设计目标。Starcoin 使用 Move 语言作为智能合约语言。Move 语言的设计理念是让针对数字资产的编程更加安全、简单,所以在语言的设计过程中首先考虑了安全性和可靠性。Move 语言的设计者们从以往的智能合约安全事件中充分吸取经验教训,最大可能的降低 Move 合约出现意外漏洞或安全事件的风险,其安全性主要由以下几个方面保证: 338 | 339 | 1. 自底向上的静态类型系统; 340 | 2. 资源不可复制或者隐式丢弃; 341 | 3. 资源按用户存储,重新定义链,合约,用户三方的数据操作权限; 342 | 4. 引入形式化验证技术,通过数学原理来证明合约的安全性; 343 | 344 | ### 应用层安全 345 | 346 | Starcoin 主要在以下层面支撑应用层的安全性: 347 | 348 | 1. 提供多签交易,方便通过多签来管理数字资产。 349 | 2. 提供私钥重置功能,在账号地址不变的情况下,可变更私钥。 350 | 3. 应用层可通过前面提到的数据校验机制,方便地确定交易是否上链、验证状态以及区块是否合法,从而保证应用的安全与可靠。 351 | 352 | 353 | ## 6. 分层网络 354 | 355 | **背景** 356 | 357 | 当前区块链面临的可扩展性问题的解决思路主要有两种,一种是一层(layer1)扩展,另外一种是二层(layer2)扩展。一层的扩展受不可能三角限制,很难平衡安全和可扩展性,所以 Starcoin 的设计中,一层主要负责安全,二层负责扩展,一二层有机结合起来,解决区块链面临的可扩展性问题。这种思路,已经是公链领域在一层扩展遇到困难后,基本达成的共识,比如以太坊的 Rollup 发展路线 [4],Nervos 的 CKB [7]。 358 | 359 | 一层在分层网络中的职能: 360 | 361 | 1. 通过增强的中本聪共识机制来尽可能的在保证安全的基础上在一层扩容,最大化一层网络的利用率(出块时间以及区块大小的动态调整机制,参看共识部分)。 362 | 2. 提供资产的定义,发行,以及流转,以及一二层之间的流转能力。 363 | 3. 给二层提供仲裁能力,二层可以利用一层的安全机制来保证自己的安全。 364 | 365 | 二层在分层网络中的职能: 366 | 367 | 1. 将一层的交易分流到二层,一层不再关心二层交易的细节以状态的变更。 368 | 2. 提供一套监督机制,二层的不同角色之间可以互相监督。 369 | 3. 提供证据保全能力,用户如果对二层的交易有争议,可以到一层仲裁。 370 | 371 | ### 二层方案概览 372 | 373 | **状态通道** 374 | 375 | 通用的状态通道包含支付通道,只是后者的状态只能是资产,而通用的状态通道试图把状态扩展到应用的任意状态。状态通道的根本思路是通过通道双方的互相监督,让双方之前的状态变化从链上迁移到链下,等通道关闭时再进行链上清算(也可以优化为定时清算),相当于把多次交易的状态变更合并为一次,从而降低交易成本,提升整体的交易容量。通道内的状态变化成本极其低廉,所以可以支持高频交易或者双方交互频繁的互联网应用(比如游戏)。虽然理论上状态通道的参与者可以是多方,但由于状态通道上的任何变更都需要所有参与方共同确认,所以很难扩展到两个以上的参与方,也因此限制了它的应用场景。 376 | 377 | **侧链** 378 | 379 | 侧链或者子链,业界并没有非常准确的定义,很多人也不认为侧链是二层方案的一种。但我们这里限定一个条件,当侧链的共识机制依赖于一层的共识机制,提供了一种仲裁机制,允许侧链的用户或者节点运营方对侧链共识达成的状态在一层进行挑战,并可以通过一层的仲裁机制,推翻侧链共识状态,我们就认为这种侧链方案属于一种二层的解决方案,否则侧链是一个独立的链,本质上和多个链之间的跨链没有区别。侧链作为二层解决方案的好处是可以扩展到任意多方,并且侧链有了一层的仲裁约束,可以做到只要有一个侧链节点是诚实节点即可保证网络安全。 380 | 381 | **RollupChain** 382 | 383 | RollupChain 是区块链社区新兴的一种二层解决方案,本质上可以理解成是对原来 Commit-Chain 方案(如 Plasma )的改进。在 Commit-Chain 方案中,二层链的运营方需要定时向一层提交二层链的状态根或者区块头证明,而用户可以通过自己状态的证明直接在一层退出二层的资产,如果运营方提供了错误的证明,用户也可以对运营方提交的证明进行挑战,从而保证二层的安全。但 Plasma 的方案中,数据可用性一直是一个难题,用户没有全量的数据,二层链的运营方可能通过隐藏数据或者拒绝服务等方式阻止用户构造出挑战自己的证明。而 RollupChain 的关键改进就是将二层的数据直接提交到一层区块中,一层的区块只是『记录』了二层的交易数据,但并不执行。但当用户需要挑战运营方时,总能在一层找到数据并构造证明,从而解决了数据可用性问题。虽然 RollupChain 也会受限于一层的容量(因为它的交易也需要占用一层区块的容量),但它简化了 Plasma 等方案的挑战机制设计的复杂度,是当前更容易落地实现的方案。 384 | 385 | **可验证的链下计算** 386 | 387 | 可验证的链下计算入 zk-rollup 等方案,思路和 RollupChain 的机制一样。但它引入了零知识证明,避免了二层的交易如果需要挑战,依然需要在一层执行的难题,一层只需要提供校验零知识证明的能力即可。 388 | 389 | **统一的二层方案模型** 390 | 391 | 总结当前的各种二层方案,可以发现并没有『银弹』可以一次性解决区块链的可扩展性问题,区块链的扩展性问题的解决,需要在实践中不断的演进。但同时,二层各种方案之间本质上是有共同之处的,因此我们可以抽象出一种通用的二层方案模型,以适应二层方案的不断演进。当前各种二层网络中的几个关键问题: 392 | 393 | 1. 应用的状态(包括资产)如何在一层和二层之间安全的转移。 394 | 2. 如何保证二层的数据可用性。 395 | 3. 如何证明和提供仲裁机制。 396 | 397 | 这几个关键问题的解决,都和二层交易和状态的存储机制有关系。任何二层的方案,都是将一层的状态锁定并在二层重建,这些状态的变更可以表达为一个状态树,只需要定时或者最终(取决于证明以及挑战机制的设置)将状态树的根提交到一层,作为一层状态树的一个外部子树节点。这样状态的迁移以及证明可以和一层使用同样一套机制。而在 Starcoin 的一层设计中,更容易实现这样的统一模型,主要体现在: 398 | 399 | 1. 所有合约的状态抽象为统一的资源模型,方便一层和二层之间的状态迁移。 400 | 2. 合约的无状态设计,使得合约本身不维护状态,状态由底层的状态存储模型提供,方便合约在一层二层之间迁移。 401 | 3. 交易的累加器以及状态存储的模型,可以更好的提供状态证明机制,一二层复用。 402 | 403 | 关于 Starcoin 的二层设计的具体方案,会在未来发布的 Starcoin 二层设计白皮书中详述,这里只阐述了一层设计中对二层的考量。 404 | 405 | ## 总结 406 | 407 | 综上所述,Starcoin 通过在共识机制,状态存储以及智能合约编程语言方面的改进,一方面增强了安全性,使其更适合当前去中心化金融的应用场景,另外一方面也为分层架构奠定了基础,不同的层做出不同的取舍,未来可支撑高性能 DApp 运行的需求。同时通过链上治理机制,保证了链的持续演进能力和生态构建能力。 408 | 409 | **参考资源** 410 | 411 | 1. S. Nakamoto, “Bitcoin: A Peer-to-Peer Electronic Cash System,” https://bitcoin.org/bitcoin.pdf, 2008. 412 | 2. V. Buterin, "Ethereum A Next-Generation Smart Contract and Decentralized Application Platform", 2014. 413 | 3. Z. Amsden et al., “The Libra Blockchain.” https://developers.libra.org/docs/the-libra-blockchainpaper. 414 | 4. V. Buterin, “A rollup-centric ethereum roadmap" https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698. 415 | 5. S. Blackshear et al., “Move: A language with programmable resources,” https://developers.diem.com/docs/technical-papers/move-paper . 416 | 6. EOS IO. Eos.io technical white paper. https://github.com/EOSIO/Documentation, 2017. 417 | 7. “Nervos CKB: A Common Knowledge Base for Crypto-Economy” https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0002-ckb/0002-ckb.md. 418 | -------------------------------------------------------------------------------- /sip-6/images/stargate_layers_arch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
PoW Consensus(Security, Permissionless)
PoW Consensus(Security, Permissionless)
PoS(Finality)
PoS(Finality)
State Channel
State Channel
Rollup(Accumulator & StateProvider)
Rollup(Accumulator & StateProvider)
Layer3 DApp Chain 1
Layer3 DApp Chain 1
Layer1
Layer1
Layer2
Layer2
Layer3 DApp Service
Layer3 DApp Service
.... 
.... 
Layer3 DApp Chain N
Layer3 DApp Chain N
100
100
10000
10000
∞ 
∞ 
TPS
TPS
Layer3
Layer3
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /sip-6/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sip: 6 3 | title: "[SIP6] Stargate: Universal Layers Protocol Framework" 4 | author: "Starcoin Core Dev" 5 | sip_type: paper 6 | category: Core 7 | status: Draft 8 | created: 2022-01-26 9 | weight: 6 10 | --- 11 | 12 | ## Preface 13 | 14 | Currently, the prototypes of various applications on top of blockchain are already available. However, a question that all public chains need to answer remains: How to make blockchain technology adopted on a large scale? 15 | 16 | This question can be broken down into two questions: 17 | 18 | 1. How does the blockchain support massive users? That is, the blockchain's scaling problem. 19 | 2. In what way should applications be combined with the chain? That is, the relationship between the chain and Web3 applications. 20 | 21 | Regarding the issue of scaling, there are three main approaches in the current blockchain world. 22 | 23 | 1. Scaling by improving the consensus mechanism, or by reducing the number of validation nodes, etc. 24 | 2. Scaling through sharding or parallel chains. 25 | 3. Scaling through layering. 26 | 27 | 28 | Starcoin has chosen the third approach for the following reasons: 29 | 30 | 1. Layering is a customary approach to solve the scaling problem in human societies. For example, judicial systems and political institutions, all solve the scaling problem by layering. The constraint mechanism between different layers can ensure security. 31 | 2. In the impossible triangle of blockchain, Layer1 should focus more on security. 32 | 3. The requirements for decentralization, security, and throughput differs for different applications and different stages of applications. It is easier to achieve a gradual application-oriented evolutionary solution through a layered approach. 33 | 34 | Stargate is a layered protocol framework on the Starcoin blockchain network. It supports different layering solutions through a universal abstraction. 35 | 36 | 1. Layer1 ensures Security and Permissionless. 37 | 2. Layer2 enables Finality, migrating state and computation from Layer1 to Layer2, enabling global scaling and instant confirmation of transactions. 38 | 3. Layer3 supports Web3 applications through application-oriented consensus solutions. 39 | 40 | 41 | 42 | ## Key Solutions 43 | 44 | There are three main technical challenges in all the layering solutions: 45 | 46 | 1. How to verify and arbitrate the transaction execution results of Layer2 at Layer1 (and that of Layer3 at Layer2)? 47 | 2. Can Layer2 and Layer3 depend on Layer1's smart contracts? This affects the interlayer composability of smart contracts. 48 | 3. How does the state of a smart contract move between layers? 49 | 50 | ### Transaction verification 51 | 52 | The execution of a transaction on the blockchain, while to be executed based on the historical state, will not actually read the entire historical state. A new state can also be calculated if only the state that the transaction depends on is provided. 53 | 54 | The blockchain state transition can be represented by the following formula (from Ethereum Yellow Paper). 55 | 56 | σt+1 ≡ Υ(σt, T) 57 | 58 | - σ𝑡+1 represents the next world state 59 | - Υ represents the state transition function 60 | - σ𝑡 represents the current state of the world 61 | - T represents a transaction 62 | 63 | Y relies on the current state σ𝑡 to execute T, but Y does not read all σ𝑡 states. If a subset of the states required by Y, denoted by σ`𝑡, is extracted, and the proof that σ`𝑡 σ𝑡 is also provided, the state transition can also be achieved. 64 | 65 | ![StateFullTransaction](./images/statefulltransaction.svg) 66 | 67 | We call 68 | - the subset of states on which the execution of the transaction depends as ReadSet 69 | - the proof of the states as ReadSetProof 70 | - the package of ReadSet, ReadSetProof, the transaction, and the root hash of the state tree after execution as StateFullTransaction. 71 | 72 | The data structure is represented as follows: 73 | 74 | ```rust 75 | pub struct ReadSet { 76 | state:Vec<(AccessPath,Vec)>, 77 | } 78 | pub struct ReadSetProof { 79 | // TODO define proof 80 | } 81 | 82 | pub struct StateFullTransaction { 83 | read_set: ReadSet, 84 | proof: ReadSetProof, 85 | transaction: SignedUserTransaction, 86 | // Transaction info is transaction execute result, include new state_root, event_root, etc. 87 | transaction_info: TransactionInfo, 88 | } 89 | ``` 90 | 91 | The StateFullTransaction contains the state that transaction execution depends on and is self-verifiable. The pseudo-code of the verification method is as follows. 92 | 93 | ```rust 94 | StateLessVM { 95 | 96 | fn eval(txn: StateFullTransaction, prev_state_root: HashValue): bool { 97 | // Constructing a state tree via ReadSet 98 | let state_tree = build_state_tree(txn.read_set); 99 | assert(state_tree.root == prev_state_root); 100 | let output = execute_txn(&state_tree, txn.transaction); 101 | state_tree.apply(output.write_set); 102 | assert(state_tree.root == txn.transaction_info.state_root); 103 | // assert other field in transaction_info 104 | } 105 | } 106 | ``` 107 | 108 | 109 | 110 | ### Dependency of Smart Contracts 111 | 112 | The layering of the blockchain brings a challenge of dependency relationship between smart contracts: Can Layer2 contracts depend on Layer1 contracts? The dependency here is twofold: The code dependency and the state dependency. In all current layered solutions, the problem of cross-layer contract dependency has not been well solved, and can only be interoperated through the mechanism of asynchronous messages. 113 | 114 | In Stargate, Layer2 can depend on Layer1's contract directly at compile time due to the static dependency feature of Move. When a Layer2's contract executes, the execution context switches as shown in the following figure: 115 | 116 | ![Cross Layer Contract](./images/cross_layer_contract.svg) 117 | 118 | 1. If the Layer1 contract on which the Layer2 contract depends is stateless and does not need to read state (e.g., a purely algorithmic contract), the dependency is the same as between Layer1 contracts. 119 | 2. If the Layer1 contract on which the Layer2 contract depends acquires a read-only state (using the borrow_global directive), the state is acquired from Layer1 via a remote state loader. However, the state read is not the latest state of Layer1, but rather a historical state of Layer1 associated with the Layer2 transaction. 120 | 3. If the Layer1 contract on which the Layer2 contract depends acquires a modifiable state (using the borrow_global_mut/move_from/move_to directive), then the transaction is a cross-layer transaction and a cross-layer state move transaction needs to be executed at Layer1. Whether this part can be made completely transparent to developers requires further technical research. Currently, the state move is performed explicitly. 121 | 122 | This will provide a seamless cross-layer programming experience. 123 | 124 | ### State Movement 125 | 126 | State movement between different Layers is similar to cross-chain solutions. Most current solutions lock Token or assets in one layer through contracts and then mint them in another layer, which requires designing verification and minting solutions for each state or asset type (for example, the verification of Token and NFT is different), or only implementing cross-chain contract calls to ensure successful transaction execution without verifying the state (which has security risks). 127 | 128 | When using a resource-oriented programming language like Move, where state moves between different Layers similarly to how state is loaded from external storage in a contract, we can design a generic state movement model that supports cross-layer movements of free state. 129 | 130 | 1. Define a cross-layer transaction type that actually contains two transactions, one to be executed in Layer1 and another to be executed in Layer2. 131 | 2. In the Layer1 transaction, the state S is moved out of Layer1 via a call to the cross-layer contract and locked in a special data structure called SpacetimeBox, which exists in both the Layer1 and Layer2 states. 132 | 3. In Layer2's transaction, the SpacetimeBox is moved out and destroyed by calling the cross-layer contract to get S. Layer2 reports the status of S to Layer1. 133 | 4. When Layer2 reports the StateRoot to Layer1, it also submits the non-existence proof of the SpacetimeBox, which proves that the SpacetimeBox has been properly processed in Layer2, and Layer1 releases the SpacetimeBox. 134 | 5. The steps are similar when to move S from Layer2 back to Layer1, but in reverse order. The movement from Layer2 to Layer1 has different challenging periods for different scenarios, and the intermediate state is locked in the SpacetimeBox during the challenging period. 135 | 136 | ![crosslayer state moving](./images/crosslayer_state_moving.svg) 137 | 138 | The example code as follow: 139 | 140 | ```rust 141 | module CrossLayer { 142 | // Move state `s` to layer2 with the `id`, only can call on layer1 143 | public native move_to_layer2(signer: &signer, id: Layer2ID, s: S); 144 | // Move state `S` from layer2 with the `id`, only can call on layer1 145 | public native move_from_layer2(signer: &signer, id: Layer2ID): S; 146 | // Move state `s` to layer1, only can call on layer2 147 | public native move_to_layer1(signer: &signer, s: S); 148 | // Move state `S` from layer1, only can call on layer2 149 | public native move_from_layer1(signer: &signer):S; 150 | } 151 | 152 | // transaction on layer1 153 | public(script) script_on_layer1(signer: Signer) { 154 | let s = MyModule::get_state_from_somewhere(&signer); 155 | CrossLayer::move_to_layer2(&siger, dappx_layer2, s); 156 | } 157 | 158 | // transaction on dappx layer2 159 | public(script) script_on_layer2(signer: Signer) { 160 | let s = CrossLayer::move_from_layer1(&siger); 161 | // do something with s. 162 | LocalModule::save_to_layer2(&signer,s); 163 | } 164 | ``` 165 | 166 | The encapsulation and verification of SpacetimeBox are implemented in the native layer and are transparent to the contract layer. The biggest challenge of generic state movement is the verification of the state, which can be divided into two types: 167 | 168 | 1. Mergeable stats, such as Token. For example, 1000 A Tokens and 100 A Tokens can be merged into 1100 Tokens. Each mergeable state needs to accumulate a total number in Layer1 and be verified when migrating across layers to ensure that Layer2 cannot create Token out of thin air. 169 | 2. Non-mergeable states, such as NFT, or user-contracted free states. Layer1 generates a state tree for all original state moved from Layer1, and records the root hash of the tree to ensure that the state is not changed when it is moved across layers. Non-mergeable state, when moved from Layer1 to Layer2, can only change the ownership and cannot be updated in Layer2. 170 | 171 | ## Technical Architecture 172 | 173 | ![stargate layers architecture](./images/stargate_layers_arch.svg) 174 | 175 | The overall architecture consists of three layers, 176 | 177 | 1. Layer1 ensures Security and Permissionless through PoW consensus. This part has been implemented. 178 | 2. Layer2 provides finality to Layer1 through PoS consensus and decentralization to Rollup's Accumulator. The Rollup solution can increase the overall TPS of the network by a factor of 10 to 100. 179 | 3. Layer3 isolates the consensus of different applications in the application network through State Channel and DAppChain, which enables unlimited scalability. 180 | 181 | ### Rollup 182 | 183 | Rollup is a scaling solution and there are several roles in Rollup: 184 | 185 | 1. Accumulator, also known as Sequencer or Aggregator in other projects. Stargate's Rollup solution, not only provides sorting but also accumulates transaction hashes, which are used to provide proof of the order of transactions. The accumulator also executes transactions and periodically commits the root hash of the state tree to Layer1 after each transaction is executed. 186 | 2. The State Provider executes the transactions according to the transaction order provided by the accumulator and provides the state query API to users. 187 | 3. Verifier, executes transactions and compares them with the root hash of the state tree submitted to Layer1 by the accumulator, and submits proof of fraud to Layer1 if the accumulator is found to be cheating. 188 | 189 | The current Stargate rollup solution is a type of Optimistic Rollup, where Layer1 does not verify every transaction in Layer2, but optimistically trusts Layer2's Accumulator node until a verifier presents proof of fraud, which is equivalent to migrating both computation and state to Layer2. 190 | 191 | Considering that the ZK Rollup scheme will be introduced in the future, Stargate's architecture is designed as an abstract solution for the verification mechanism of transactions, which can be implemented by verifying FullStatusTransactions or by verifying zero-knowledge proofs, and the different solutions can be adopted through a universal architecture. 192 | 193 | Stargate's Rollup solution differs from other Rollup solutions in several ways. 194 | 195 | 1. The accumulator and Layer1 share a PoS consensus network, achieving decentralization and high availability. 196 | 2. The accumulator provides the sequential proofs and the verification mechanism for StateFullTransaction, allowing the wallet client to verify the transactions and take on the verifier role. 197 | 3. Data availability is guaranteed by the Layer2 PoS consensus network and the wallet client, and the accumulator can submit hashes of Layer2 transactions to Layer1 only, allowing Rollup to increase throughput by 100x. 198 | 199 | Rollup still relies on the global consensus of Layer1, so it is limited by the throughput capacity of Layer1. Its main goal is to reduce the computational cost of Layer1, maintain state off-chain, and ensure security through an optimistic challenge mechanism. It can instantly confirm the transaction status of Layer2, providing users with an Internet-like application experience, and also laying the foundation for the Layer3 solutions. 200 | 201 | ### State Channel 202 | 203 | State Channel, or Payment Channel, represented by Lightning Network, is also a proven scaling solution. The idea is that each participant pledges a certain amount of assets on the chain, and then maintains a local consensus state off-chain for both participants (theoretically, it can be extended to multiple participants), and each transaction requires confirmation from both participants. However, to solve the problem of non-cooperation, either party can be forced to initiate a liquidation transaction on the chain, and after waiting for a challenging period, the channel will be automatically closed and the participants will be liquidated based on the last confirmed state by both participants. 204 | 205 | The State Channel solution in Stargate differs from other state channels in several ways: 206 | 207 | 1. SmartContract can be executed in the State Channel so that the channel can be used not only to transfer Token but also to execute complex, stateful contracts. 208 | 2. As it can execute contracts, it can also pay any type of Assert, as well as NFTs. 209 | 3. State Channel are built on Layer2 instead of Layer1, mainly because they rely on Layer2's instant confirmation capability to reduce the cost and confirmation time to create the channel. 210 | 211 | One of the key thresholds for the massive adoption of State Channel is that the cost of creating a channel on Layer1 is high and the waiting time is long. 212 | 213 | However, if the State Channel is on Layer2, this threshold can be eliminated. This allows any two nodes in the Starcoin/Stargate P2P network to upgrade their P2P connections to a State Channel, and then perform data transfer and streaming billing over the State Channel. This is also the infrastructure of DAppService. 214 | 215 | ### DAppService 216 | 217 | Built on the Stargate framework, it provides a paid RPC service through State Channel network. 218 | 219 | DAppService is not decentralized, but it runs on a P2P network, allowing service discovery and remote call through the P2P network, and billing through the State Channel. 220 | 221 | It is equivalent to a bridge from Web2 service to Web3 service, and any current Web2 service can change its payment method to a streaming billing method and enter into Web3 P2P network directly. 222 | 223 | ### DAppChain 224 | 225 | The DApp Chain is built based on the Stargete framework and includes a sub-consensus mechanism, which requires registration in Layer2 and collateralizing a certain amount of Layer2 assets. A user who encountered a fraudulent DApp can submit proof of fraud to Layer2, and Layer2 will punish the DApp, but the penalty is limited to the maximum amount of the DApp's registered collateral assets. 226 | 227 | The overview of network architecture is shown in the following figure: 228 | 229 | ![stargate network architecture](./images/stargate_network_arch.svg) 230 | 231 | 1. Layer1 is in the same P2P network as Layer2, Layer3, and the user's endpoint wallet, all of which can communicate through the P2P network. 232 | 2. The endpoints are fully exploited. The endpoint wallets have their own identity in the P2P network, can execute and verify transactions, can store transaction history, provide data availability, and can submit Layer2's fraud proofs to Layer1. Similarly, they can submit DApp's fraud proofs to Layer2. 233 | 3. Different DApps, such as X DApp, Y DApp, can choose different options to access the Starcoin network. 234 | 235 | Finally, to answer the two questions in the opening paragraph. 236 | 237 | 1. How does a blockchain support massive users? Starcoin achieves scaling through a layered solution. Moreover, if a chain wants to support massive DApp users, it is difficult to achieve the goal by Rollup solution alone, so local consensus mechanism must be considered. Therefore, Stargate provides the integrated Layer1 + Layer2 (Rollup) + Layer3 (DAppService + DAppChain) solution. 238 | 2. In what way should applications be combined with the chain? In the future, applications will be combined with chains in two approaches: One is to use the chain as a payment channel, and Stargate provides DAppService that can connect traditional WebService directly to the Web3 infrastructure. The other is application chains, where Stargate provides an application chain framework to quickly build application chains and integrate them into the Starcoin network, securely governed by Layer2 and Layer1, and where assets can be moved between different layers and DApps. 239 | 240 | 241 | 242 | ## Roadmap 243 | 244 | ![stargate roadmap](./images/stargate-roadmap.svg) 245 | 246 | Roadmap contains three main areas: 247 | 248 | 1. Layer1, Layer2, Layer3: Solve the chain scalability problem and provide integration solutions for DApps. 249 | 2. Move and DApp ecosystem: Lower the barrier of entry for developers and provide full-stack tools to them. 250 | 3. Interoperability of multi-chain ecosystem: To interoperate with other chains and integrate into the ecosystem of other chains as much as possible. 251 | 252 | Here, the arrows indicate dependencies and dashed lines indicate possible exploration areas. 253 | 254 | The Starcoin team tried to explore the Layer2 solution on Bitcoin and Ethereum during the first year and came to two basic conclusions: 255 | 256 | 1. Bitcoin's Script limitations make it difficult for Layer1 to provide arbitration ability for Layer2 transactions, and the arbitration logic must be converted to lock mode (hash lock, time lock) through a complex protocol, making it difficult to support the requirements of DApp-oriented Layer2. 257 | 2. Ethereum's smart contracts are powerful, but because its contract state is bound in the contract account, it cannot do cross-layer state movement and type reuse. On the one hand, it is difficult to achieve universal state movement, and on the other hand, it is difficult to support the composability of smart contracts across layers, and the bottleneck will be unavoidable when the relationship between applications is more complicated in feature. 258 | 259 | Therefore, the Starcoin team adopted a new smart contract language, Move, and first conducted PoC tests on the Stargate technology idea by simulating Layer1, trying to execute smart contracts in the State Channel, and then decided to make a new Layer1 for Layer2 public chain, introducing Move smart contracts in Layer1. 260 | 261 | In May 2021, the Starcoin main network was launched. After half year of stable operation and continuous iteration, by now (January 2022) Layer1 has the initial key dependencies of Layer2, so the design and development of the Stargate project will continue. 262 | 263 | The Stargate roadmap has the following key milestones: 264 | 265 | 1. EasyGas, which implements the ability to pay for Gas with any Token. This feature relies on swap on the chain and will be implemented around Q1 2022. 266 | 2. Light nodes, do not keep all states, but can execute transactions, verify blocks, and generate rich state transactions. Embedded light nodes (browser or mobile clients) rely on the implementation of light nodes, and rich-state client wallets rely on the implementation of embedded light nodes. 267 | 3. Layered hybrid consensus mechanism, adding a PoS consensus mechanism on top of PoW, providing finality to Layer1. 268 | 4. In the first phase of Rollup, the high availability of the Accumulator is not considered. The focus is the verification of FullStateTransactions, movement of state between different layers, and cross-layer contract dependencies. 269 | 5. In the second phase of Rollup, Rollup and PoS consensus are integrated to solve the problems of Accumulator high availability and decentralization. 270 | 6. RPC framework on top of the P2P network. it is a generic P2P web service framework to simplify the development of RPC services on P2P networks. 271 | 7. Rollup-based state channel, and DAppService framework on top of state channel. 272 | 8. Rollup-based DAppChain framework. 273 | 274 | 275 | 276 | ### Glossary of Terms 277 | 278 | 1. Free state: In Move, if an instance of a type can be held by other Modules, the state is regarded as free. 279 | 280 | > Note: This document is still being updated and improved, and is not the final version. 281 | -------------------------------------------------------------------------------- /sip-6/images/crosslayer_state_moving.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
CrossLayer Transaction
CrossLayer Transaction
1
1
l2s2
l2s2
STC
STC
NFT
NFT
R
R
0x111
0x111
id:1
id:1

Transaction l1

0x111 
CrossLayer::move_to_layer2(NFT:id1) 

Transaction l1...

Transaction l2

0x111 
CrossLayer::move_from_layer1(NFT:id1) 

Transaction l2...
Layer1
Layer1
Layer2
Layer2
10
10
S1
S1
STC
STC
R
R
0x111
0x111
NFT
NFT
id:1
id:1
0x1
0x1
R
R
Layer2
Layer2
root:l2s1
root:l2s1
cross_root
cross_root
10
10
S2
S2
STC
STC
R
R
0x111
0x111
0x1
0x1
R
R
Layer2
Layer2
root:l2s2
root:l2s2
cross_root
cross_root
id:1
id:1
NFT
NFT
Text is not SVG - cannot display
--------------------------------------------------------------------------------