...
如果 Layer2 合约依赖的 Layer1 的合约是无状态的,不需要读取状态(比如纯算法的合约),则和 Layer1 合约和 Layer1 合约之间的依赖一样。
如果 Layer2 合约依赖的 Layer1 的合约获取了只读状态(使用 borrow_global 指令),则通过远程状态加载器从 Layer1 获取状态。不过读取的状态不是 Layer1 的最新状态,而是该 Layer2 交易关联的 Layer1 高度的历史状态。
如果 Layer2 合约依赖的 Layer1 的合约获取了可修改状态(使用 borrow_global_mut/move_from/move_to 指令),则表明这个交易是一个跨层的交易,需要到 Layer1 执行跨层的状态迁移交易。这部分是否可以做成对开发者完全透明,需要进一步技术调研。当前先通过一种显示的方式进行状态迁移。
这样,就可以提供一种近乎于无缝的跨层的编程体验。
状态迁移
状态在不同的 Layer 之间迁移,类似于跨链方案,当前大多数方案都是通过合约将 Token 或者资产在某一层锁定,然后在另外一层铸造出来,需要针对每一种状态或者资产类型设计校验以及铸造方案(比如 Token 和 NFT 的校验是不一样的),或者只实现跨链的合约调用,确保交易执行成功,并不校验状态(有安全风险)。
使用 Move 这种面向资源的编程语言时,状态在不同的 Layer 之间迁移和合约中从外部存储加载状态类似,我们可以设计一种通用的状态迁移模型。
定义一种跨层的交易类型,该类型的交易实际上包含两个交易,一个需要在 Layer1 执行,一个需要在 Layer2 执行。
Layer1 的交易中,通过调用跨层的合约,将状态 S 从 Layer1 移动出来,锁定在一个特殊的数据结构中,叫做 SpacetimeBox, 这个结构同时存在与 Layer1 和 Layer2 的状态中。
Layer2 的交易中,通过调用跨层的合约,将 SpacetimeBox 移动出来并销毁,得到 S。
Layer2 给 Layer1 汇报 StateRoot 时,同时提交 SpacetimeBox 的不存在状态证明,证明 SpacetimeBox 已经在 Layer2 得到正确处理,Layer1 释放 SpacetimeBox。
如果想从 Layer2 将 S 迁移回 Layer 1, 方法同理,不过顺序相反。
从 Layer2 到 Layer1 的迁移,不同的方案有不同的挑战期,挑战期间中间状态会锁在 SpacetimeBox 中。
...
示例代码如下:
代码块 | ||
---|---|---|
| ||
module CrossLayer{
// Move state `s` to layer2 with the `id`, only can call on layer1
public native move_to_layer2<S>(signer: &signer, id: Layer2ID, s: S);
// Move state `S` from layer2 with the `id`, only can call on layer1
public native move_from_layer2<S>(signer: &signer, id: Layer2ID): S;
// Move state `s` to layer1, only can call on layer2
public native move_to_layer1<S>(signer: &signer, s: S);
// Move state `S` from layer1, only can call on layer2
public native move_from_layer1<S>(signer: &signer):S;
}
//transaction on layer1
public(script) script_on_layer1(signer: Signer){
let s = MyModule::get_state_from_somewhere(&signer);
CrossLayer::move_to_layer2(&siger, dappx_layer2, s);
}
//transaction on dappx layer2
public(script) script_on_layer2(signer: Signer){
let s = CrossLayer::move_from_layer1<S>(&siger);
//do something with s.
LocalModule::save_to_layer2(&signer,s);
}
|
SpacetimeBox 的封装以及校验是在 native 层实现的,对合约层是透明的。通用的状态迁移最大的难题在于状态的校验,我们可以把状态分为两种:
可以合并的状态,例如 Token。比如 1000 个 A Token 和 100 个 A Token 可以合并为 1100 个 Token。每种可以合并的状态需要在 Layer1 累加一个总数,跨层迁移时进行校验,保证二层不能凭空创造出 Token。
不可合并的状态,例如 NFT,或者用户合约自定义的自由状态。SpacetimeBox 中记录了原始状态的哈希,保证状态跨层迁移时状态不会被改变。不可合并的状态,从 Layer1 迁移到 Layer2,只能改变归属,不能在 Layer2 更新。 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.
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.
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 in a clear method first.
This will provide a seamless cross-layer programming experience.
状态迁移
State Movement
状态在不同的 Layer 之间迁移,类似于跨链方案,当前大多数方案都是通过合约将 Token 或者资产在某一层锁定,然后在另外一层铸造出来,需要针对每一种状态或者资产类型设计校验以及铸造方案(比如 Token 和 NFT 的校验是不一样的),或者只实现跨链的合约调用,确保交易执行成功,并不校验状态(有安全风险)。
State movement between different Layers is similar to cross-chain solutions. Most current solutions are to 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).
使用 Move 这种面向资源的编程语言时,状态在不同的 Layer 之间迁移和合约中从外部存储加载状态类似,我们可以设计一种通用的状态迁移模型。
定义一种跨层的交易类型,该类型的交易实际上包含两个交易,一个需要在 Layer1 执行,一个需要在 Layer2 执行。
Layer1 的交易中,通过调用跨层的合约,将状态 S 从 Layer1 移动出来,锁定在一个特殊的数据结构中,叫做 SpacetimeBox, 这个结构同时存在与 Layer1 和 Layer2 的状态中。
Layer2 的交易中,通过调用跨层的合约,将 SpacetimeBox 移动出来并销毁,得到 S。
Layer2 给 Layer1 汇报 StateRoot 时,同时提交 SpacetimeBox 的不存在状态证明,证明 SpacetimeBox 已经在 Layer2 得到正确处理,Layer1 释放 SpacetimeBox。
如果想从 Layer2 将 S 迁移回 Layer 1, 方法同理,不过顺序相反。
从 Layer2 到 Layer1 的迁移,不同的方案有不同的挑战期,挑战期间中间状态会锁在 SpacetimeBox 中。
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.
Define a cross-layer transaction type that actually contains two transactions, one that needs to be executed in Layer1 and one that needs to be executed in Layer2.
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.
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.
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.
If you want to move S from Layer2 back to Layer1, do the same thing, but in reverse order.
The movement from Layer2 to Layer1 has different challenge periods for different scenarios, and the intermediate state is locked in the SpacetimeBox during the challenge period.
Drawio | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
示例代码如下:
代码块 | ||
---|---|---|
| ||
module CrossLayer{
// Move state `s` to layer2 with the `id`, only can call on layer1
public native move_to_layer2<S>(signer: &signer, id: Layer2ID, s: S);
// Move state `S` from layer2 with the `id`, only can call on layer1
public native move_from_layer2<S>(signer: &signer, id: Layer2ID): S;
// Move state `s` to layer1, only can call on layer2
public native move_to_layer1<S>(signer: &signer, s: S);
// Move state `S` from layer1, only can call on layer2
public native move_from_layer1<S>(signer: &signer):S;
}
//transaction on layer1
public(script) script_on_layer1(signer: Signer){
let s = MyModule::get_state_from_somewhere(&signer);
CrossLayer::move_to_layer2(&siger, dappx_layer2, s);
}
//transaction on dappx layer2
public(script) script_on_layer2(signer: Signer){
let s = CrossLayer::move_from_layer1<S>(&siger);
//do something with s.
LocalModule::save_to_layer2(&signer,s);
}
|
SpacetimeBox 的封装以及校验是在 native 层实现的,对合约层是透明的。通用的状态迁移最大的难题在于状态的校验,我们可以把状态分为两种:
可以合并的状态,例如 Token。比如 1000 个 A Token 和 100 个 A Token 可以合并为 1100 个 Token。每种可以合并的状态需要在 Layer1 累加一个总数,跨层迁移时进行校验,保证二层不能凭空创造出 Token。
不可合并的状态,例如 NFT,或者用户合约自定义的自由状态。SpacetimeBox 中记录了原始状态的哈希,保证状态跨层迁移时状态不会被改变。不可合并的状态,从 Layer1 迁移到 Layer2,只能改变归属,不能在 Layer2 更新。
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:
For mergeable state , such as Token, for example, 1000 A Token and 100 A Token can be merged into 1100 Token. 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.
For non-mergeable state, such as NFT, or user-contracted free state, 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, moved from Layer1 to Layer2, can only change the ownership and cannot be updated in Layer2.
技术架构
Drawio | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
...