contract KittyLedger {
struct Kitty {}
priv let kitties: {Int: Kitty}
fun transfer(kittyId: Int, newOwner: AccountId) {
if (msg.sender == kitties[kittyId].owner) {
kitties[kittyId].owner = newOwner
}
}
}
transaction(signer: Account) {
// tells the central ledger to assign ownership of
// myKittyId to a different account
centralKittyLedger.transfer(myKittyId, receiverAccountId)
}
contract CryptoKitties {
// Accounts store a collection in their account storage
resource KittyCollection {
// Each collection has functions to
// move stored resources in and out
fun withdraw(kittyId: int): CryptoKitty
fun deposit(kitty: CryptoKitty)
}
// The resource objects that can be stored in the collection
resource CryptoKitty {}
}
transaction(signerL Account){
// Remove the Kitty from signer's collection, and stores it
// temporarily on the stack
let theKitty <- signer.kittyCollection.withdraw(kittyId: myKittyId)
// Moves the Kitty into the receiver's account
let receiver = getAccount(receiverAccountId)
receiver.kittyCollection.deposit(kitty: <-theKitty)
}
软件工程师经常使用“所有权”这个术语来比喻跟踪哪段代码负责管理某种数据结构或系统资源。这种隐喻在编程环境中最为常见,在这种环境中,内存管理并没有完全从程序员那里抽象出来,说代码“拥有” 一个对象就是说代码必须管理和释放分配给该对象的内存。
然而,当我们在任何其他情况下谈论"所有权"时,我们通常是在谈论具有持久价值的资产,而不是短暂的数据结构。虽然现有的编程环境可以用来跟踪资产的所有权,但它们最典型的使用场景是反映所有权而不是直接定义它。公共区块链的独特之处在于,它们被明确设计为管理具有真正稀缺性和完全访问控制的数字资产的所有权。比特币或Flow等公共区块链上的数字资产应该像实物资产一样:它们不能被复制或伪造,只能被转移。
随着区块链的发展,代表所有权的机制也发生了变化。比特币是使用“未用交易输出”或称之为
UTXO
的所有权模型构建的。虽然UTXO
模型非常高效,但它很复杂并且会创建一些异常的边缘情况,因此以太坊采用了更灵活的分类账户模型。不幸的是,以太坊模型几乎没有针对编程出现错误进行保护的措施,程序错误造成加密货币社区损失了超过1亿美元的资金。理想情况下,管理数字所有权的编程语言应包括数字资产的本身的表示形式,并具有防止破坏价值的内置保护措施。
Cadence:第一个面向资源的高级编程语言
去年, Flow 团队在对智能合约语言进行学术研究后,着手调研线性类型在区块链下的使用。就在同一时间,Libra团队发布了他们的初始公告,包括
MoveVM
的技术细节。就在同一时期,Libra 团队发布了他们的初始公告,包括MoveVM
的技术细节等。Libra 团队受线性类型的启发,为
Move
定义了一个新的编程所有权模型:资源(Resource)。资源是一种直接用编程语言表示资产所有权和启用加密数字资产属性的新方法。如下是来自Move
的介绍:我们被面向资源的编程的力量所震撼,它成为了 Flow 的智能合约编程语言
Cadence
的最重要的特点之一。作为一种高级的面向资源的编程语言,Cadence 具有舒适的,符合人体工程学的语法,非常易于阅读。它使用强大的静态类型系统来最大程度地减少运行时错误,并允许所有方法,接口和事务包含前置条件和后置条件以强制执行预期的行为。我们认为,这将使一种语言更易于学习,更易于审计,最终将提高生产力。
你可以在 Flow Playground 上试验
Cadence
:play.onflow.org面向资源的编程如何工作
资源提供了比
EVM
或WASM
更丰富的可组合性选项,并且非常适合数字资产。将某样东西标记为“资源”,可以告诉编程环境,该数据结构代表某种有形的价值,并且所有与该数据结构交互的代码都需要遵循一些特殊规则,以保证该数据结构的价值。那么,这些规则是什么?
仅仅由编译器强制执行资源对象的特殊状态是不够的;这些规则还必须在代码在链上执行时被强制执行。如果没有链上运行时的支持,攻击者很容易使用黑客的编译器来绕过保持资源安全的规则。
然而! 如果你能正确地执行这些规则,你可以让网络中最重要的资产--代币--安全地存储在由用户提交的代码控制的数据结构内。非常强大!
来看个例子
思考资源的最简单方法是通过使用非可替换代币(NFT)的例子来思考,例如 CryptoKitty。每个 CryptoKitty 都是不可分割的,不可复制的,并且可以有一个直接所有者,这与资源编程结构直接匹配。
在以太坊这样的账本模型中,所有的 CryptoKitty 都作为一个巨大的列表存储在一个智能合约中。每个 Kitty 的所有权是通过在中央账本中存储每个所有者的账户ID来追踪的,改变Kitty所有权的唯一方法是联系中央账本,要求它更新与该 Kitty 相关的账户ID。
在资源模型中,Kitty 本身被表示为一个资源对象,它被直接存储在拥有它的账户中 。就像在物理世界中一样,所有权是由占有表示的。你不需要在中央账簿中查看你是否拥有某样东西,你要么把它储存在你的账户中,要么没有。如果你拥有它,你可以转让它或以其他方式控制它,如果你不拥有它,就没有办法捕获或改变它。
注意:为了保持专注于账本和直接所有权模型之间的差异,上面的两个例子都忽略了访问控制、定义每个变量等问题,以及其他线上代码需要担心的因素。
为什么资源很重要
资源可以便于管理所有权的抽象,并且防止错误的同时提高智能合约开发人员的生产力,但是使用资源还有一些其他的好处。
可扩展的智能合约平台需要某种方式来收取 "状态租金",以便存储在区块链上的数据要么被支付,要么从工作集中删除。
有了分类账模型,就很难知道谁应该支付这种租金。例如,CryptoKitties 合约代表了数以万计的玩家,拥有近200万 Kitties 和超过 111MB 的链上数据。以太坊没有提供向所有这些 Kitty 所有者公平收取租金的方法。
通过资源类型使用直接所有权模式,每个 Kitty 将被存储在其所有者的账户内,与该人的其他资产一起。谁需要支付存储费用的责任是明确的。更重要的是,个人用户(在其客户端软件的协助下)可以将未使用的资产归档,以减少他们的成本并降低网络的负载。
使用所有权的分类账模型限制了可用的所有者关系的种类。例如,
ERC-721
为 NFT 定义了一个所有权模型,假设只有以太坊地址可以拥有一个 NFT。然而,资产本身拥有其他资产的想法(如 CryptoKitty 拥有一副漂亮的太阳镜)在某些用例中非常有趣,并需要创建一个新的规范(ERC-998
)。ERC-998
非常强大,但它也比ERC-721
复杂得多。正确实施它是非常困难的,而且由于以太坊智能合约的不可更改性,将其功能追溯到现有的ERC-721
资产实际上是不可能的。直接所有权模型允许任何使用资源类型建模的资产安全地存储在系统中的任何地方,包括 "在 "其他资产里面,如果合适的话。所有的安全和价值保证都可以由运行时系统来维护,同时为开发者释放出创造性的灵活性,而不会有过度的复杂性。
资源类型提供了实现基于能力的安全模型的 "能力" 概念所需的所有保证。能力是定义安全系统的一个强大的机制,它可以使最小特权原则(安全系统中常见的最佳实践,它要求安全系统的所有部分没有超过其所需的特权)变得更加容易。
基于能力的安全模型通常被认为更容易推理(这增强了安全性),同时允许更强大的灵活性。
以太坊历史上最有名的智能合约漏洞是由于重入问题造成的,Solidity开发者需要不断地警惕引入容易受到重入攻击的逻辑流。(你可以在这个页面上找到一个关于重入问题的精彩解释)。
幸运的是,定义在资源对象上的方法不会成为任何重入攻击的受害者。
这似乎是一个大胆的主张!但是,它自然而然地来自于资源的使用方式,由资源的定义方式自然产生。每个资源都有一个所有者,而且只有资源的所有者可以调用其上的方法。如果一个资源方法在 "堆栈 "中,我们知道该对象的单一所有权引用已经被使用了;我们从该方法中调用的任何代码--无论多么间接--都不可能得到该对象的第二个引用来进行可重入的方法调用。
当然,直接使用全局共享状态(绕过资源对象的使用)仍然可以创建易受重入错误影响的代码。这就是为什么
Cadence
的习惯风格是使用资源来处理所有的共享状态;接受资源的智能合约作者不需要再考虑可重入性错误了。更多学习资源
要深入挖掘资源和面向资源的编程,你可以: