从并发视角来看智能合约(下)【渡鸦论文系列】

论文作者:

Ilya Sergey1and Aquinas Hobor2


1 University College London, United Kingdomi.sergey@ucl.ac.uk
2 Yale-NUS College and School of Computing, National University of Singaporehobor@comp.nus.edu.sg


翻译:渡鸦

让国内外的区块链技术没有时差」。






4、所有权和权限

替代禁止对合约不受欢迎的干预的另一种方法是设计一个定制的许可合约,控制不同方面允许的一组操作。


首先如果我们强制执行有限的访问规则,则可以避免图3 中的双线程示例所展示的问题,并阻止一个断言其状态x的任何内容。例如,通过在任何时刻表示最多一个线程可以查询/修改其状态。这将授予相应的线程在对象上的独占所有权[30] ,因此,证明从线程本地做出的有关对象状态的断言。


独占所有权,从传统意义上讲,是通过禁止任何干预来获得的,但独有者在合约状态中进行重大改变,Ethereum的合约中保证了独特的所有权。例如,图5 (左)显示了Counter合约的更改版本,所以没有其他方可以与它进行交互,除了它的“所有者”。所有权规则由Solidity的修饰机制执行,允许人们为功能提供自定义的动态检查前/后置条件。在我们的示例中,byOwner修饰符将强制执行,功能的获取和设置将仅代表固定方 - 合约所有者引用。




图.5. 独占(左)和读/锁定(右)合约


这是一个相当粗暴的解决方案,因为这意味着排除合约中的任何并发交互。然而,从一个角度来看,合约作为并发对象的观点是很明显的,请看我们的类比:帐号是线程。实际上,如图5 所示,通过对合约施加特定所有权规则类似于通过对Thread进行明确检查来增强其Java对等体。currentThread().getId()。


现在让我们尝试通过设计具有更详细访问权限的计数器来进一步推动帐户和线程之间的比较。我们将确保只要存在“有兴趣”的帐户(即“线程”)使其值不可变(因为内部逻辑可能依赖其不变性),则不允许其他方修改它。同样,如果目前正好有一方拥有修改合约的唯一许可,则不得允许其他方阅读。这种同步问题的解决方案是通过名称读/锁定[6],这在并发社区中是众所周知的。其实现需要跟踪当前正在读取和写入共享对象的线程,所以在执行读/写操作之前,线程应该明确获取相应的权限,然后在完成后释放它。


图5的右侧部分显示了读/写锁定合约实现的基本部分。两个新领域,跟踪目前活跃的读者和作家。新的修饰符canRead和canWrite将被用于省略的get和set操作。最后,只要在系统中没有活动写入器,AcquReadRock允许其调用者获取锁定,通过读取器映射注册。


我们可以看到,以线程方式类比是十分有效的。我们提出了一些解决可能的同步问题的方案,可以从并发文献中逐字逐句地进行。所提出的解决方案的唯一缺点是它是相当整体的事实:合约现在将数据结构(即,计数器)的功能与同步原语(即,锁)的功能相结合。我们将在第5节中讨论提高实现模块性的可能途径。


关于正式推理和验证的注意事项。关于许可账户和所有状态分离访问的正式推理是共享内存并发文献中长期研究的主题(参见例如[8] 的概述)。正式主义,如并发分离逻辑和[30]分数/计数权限[6]提供了一种灵活的方式来定义抽象所有权规则,并验证一个特定的实现是否忠实地遵循。例如,我们的读/写锁合约可以通过Bornat等人的正式的权限模型证明是安全的(即禁止并发修改)[6]。


5讨论

5.1合约的编写

在第4节中考虑的锁定合约“模式”具有重大的延伸:其设计是非模块化的。也就是说,锁定机构是由合约本身而不是由第三方数据实施的。这与软件工程的良好做法不同,建议将同步原语(例如普通和可重入锁)实现为独立库,可用于管理访问客户端特定的资源。


但是一旦锁定逻辑被解除合约之外,关于合约行为的推理就显得更加困难,因为为了证明其内部不变量的保存,需要了解锁定协议的属性,例如编者的独特性,这在合约之外。换句话说,合约的验证不能再以孤立的方式进行,需要建立一个模型,允许对与其他严格指定的合约交互的合约进行推理。解除合约逻辑的想法不只是我们这样认为的,而且在合约开发中是至关重要的。例如,同样的想法被提倡作为通过引入和额外的间接层次来实施Ethereum可升级合约的一种方式[11]。拥有由任何一方可以援引的另一个合约的“合约工厂”构成了与证明高阶并发对象的安全属性(即,与其他对象一起作用)类似的验证挑战[19]。


使用并发逻辑的组合推理和相互依赖和高阶并发对象验证的思想在过去十年中一直个热门课题[12,33,34, 37]。而大多数都集中在协议的概念上,在同时更新的情况下,作为对象行为的抽象接口,同时隐藏低级实现细节(即实际代码)。我们相信,通过利用我们的类比,我们将能够开发一种用于这种多合约交互的模块化验证的方法。


5.2活性

随着锁定和独占访问的引入,出现了另一个并发相关问题:推理合约实现的进展和活动属性。例如,不难想象一种情况,其中在图5 的示例中注册为“读者”的特定帐户可能永远不会释放读卡器锁,从而阻止其他人能够更改合约未来的状况。在这种情况下的活跃意味着最终会有好的事情发生,这意味着任何一方都有适当的激励来解除锁定。在并发词汇中,这样的假设可以被重新表述为系统调度器的公平性,使得可以重用现有的证明方法来进行单个和多合约执行中的进展[25] 和终止[18]的模块化推理。


6、相关工作

智能合约的正式推理是一个新兴和令人兴奋的,适用于描述合约行为的抽象行为,是值得研究的课题。在本节中,我们将我们的观察结果与正式化和验证合约属性的现有结果联系起来,概述将从我们的并发类比中受益的领域。


6.1验证合约实施

自从DAO bug [9] 以来,Ethereum社区一直专注于防止类似错误,借助通用工具进行程序验证。


目前,Solidity所写的合约可以用Hoare样式的前置/后置条件注释,并转换为OCaml代码[32],所以他们可以使用Why3工具进行验证,该工具使用自动化来排除生成的验证条件[16] 。这种方法对于验证Solidity程序的基本安全属性是有效的,例如总是位于特定数组索引边界内的特定变量,以及保留一般合约不变量(通常以一个形式表示,如果在uint值变量的值上的线性方程式)方法边界和执行外部合约调用之前–这也正是DAO合约违反的。


Bhargavan等人最近翻译了Solidity子集(无循环和递归)[5] 到F-a编程语言和验证框架,基于依赖类型[35] 。他们还提供了从EVM字节码到F程序的翻译。这两种方法可以使用F作为验证合约属性的统一工具,例如不变量保存和不存在未处理的异常,通过F对索引Hoaremonad的支持而被编码为效果[36] 。Pettersson和Edstr [31]采用了一种类似的指定合约行为和依赖类型的方法,他们实现了一种基于效果的小型合约DSL作为浅埋嵌入到Idris[7] 中,其可执行代码提取到Serpent[14] 一种Python风格的合约语言。


Hirai最近将Lem[28] 中的EthereumVirtual Maine [22] 的完整规范正式提交给了Isabelle/ HOL验证助手,对于编译为EVM字节码的合约的机械化验证,具有许多安全属性包括对可变状态的断言以及潜在的可重入的缺失。与以前的方法不同,Hirai的正式化并没有提供构造和组合证明的句法方式(例如通过Hoare式程序逻辑),所有关于合约行为的推理都是从低级执行语义[38]中进行的。


与这些主要侧重于低级别安全性质和不变性保存的工作相比,我们的观察提示了更高层次的形式意义,用于捕获合约行为的属性及其与外界的沟通模式。特别地,我们考虑将抽象状态转换系统(STS)[29]作为适当的形式来进行通信,使用诸如TLA+[24]等已建立的工具集来跟踪合约执行和活动属性。为了将这样的抽象表示与低级合约代码连接起来,必须证明高级和低级表示之间,即在STS和代码之间的细化[3] 。从某种意义上说,找到一个合适的合约不变量,并通过Why3或F证明它验证一个状态转换系统之间的细化,使得唯一的状态是不变量描述的状态,以及保留它的一个实现。然而,我们预计将需要更复杂的STS才能推理具有抢占并发性的合约。


6.2推动全球合约

[27].Luu等人发现,由于干扰现象,一些合约容易出现无意或者对抗性滥用的观点。他们将问题类似于我们在第3 节中的计数器示例中所表现,即交易顺序依赖性(TOD),根据我们的并发类比可以将其概括为无限制干扰的问题。Luu等人提出的TOD问题的解决方案需要改变Ethereum事务的语义,提供一个与图4中的testAndSet类似的原语。虽然这种方法的优点是没有需要修改已经部署的合约(只有与客户端代码交互的代码需要更改),才需要所有相关的用户升级他们的客户端应用程序,以便考虑更改。本质上,Luu等人的解决方案针对非常具体的并发模式:通过添加块支持的读 - 修改 - 写入原语来加强由原子寄存器提供的同步。意识到问题的本质,暗示我们的类比,可能会提出替代合约解决方案,例如工程化锁定代理合约。然而,这种方法的缺点在于,在设计和部署合约的时刻需要预见这种行为。也就是说,这样一种对这种行为进行建模的能力让我们相信我们的比喻能够实现的。


7、结论

我们相信,我们在智能合约和并发对象之间的比较可以提供新的视角,刺激研究,并允许有效地重用现有的结果,工具以及了解,调试和验证分布式分类帐中复杂的合约行为的见解。作为比喻,我们不应该逐字地采取行动:一方面,确实存在并发问题,在合约规划中似乎几乎不可观察到; 另一方面,智能合约执行者也应该谨慎对待并发领域没有直接对应的观念,例如气体执行和资金管理。


总而言之,我们留给读者几个猜测,灵感来自我们的观察,但既没有解决也不反对:

- 非垃圾收集语言中的常见并发挑战是跟踪堆位置的唯一性,这可以被后期回收和重用 - 被称为ABA问题[10] 。由于缺乏应有的谨慎,ABA问题可能导致违反对象状态完整性。我们可以想象在多合约环境中有类似的情况吗?

- 继续比较,如果将区块链看作共享状态,那么挖掘协议定义了调度的优先级。我们可以利用有效的并发线程管理的洞察力来分析和改进现有的分布式分类帐?

- 线性化[21] (又名原子性)是指定无锁并发对象的高级行为的正确性的标准概念。对于具有多种交易操作的复合合约(例如BlockKing),什么是等同的事实上的一致性概念?


原文: https://zhuanlan.zhihu.com/p/29354702

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过共识,智能合约是私人订购的一场革命:它们提供有保证的执行力,而不受领土政府的异想天开; 有效的形成和解释; 不受外界干扰; 并完全尊重当事方的意愿。 这些主张中的每一个都是神话。 尽管智能合约表现为自然和中立,但实际上却被深深地政治化了。 大约一个世纪前,法律现实主义者撕毁了智能合约的基础。 他们的拥护者们并没有解决过去的问题,而是忘记了它们。本文对智能合约的乐观主义以及通过代码而非法律确保相互协议的可取性提出了新的批评。 更具体地说,本条款旨在提出这样的主张,即智能合约可以而且应该提供传统合约法的替代品。 它辩称,智能合约的提倡者反过来依赖Lochner时代法律思想中激烈争论的假设,包括对“合约自由”的政治承诺,坚持“公共”和“私人”领域之间的划分,以及对国家在管理合同和财产的私法体系中的作用。 更具体地说,这些假设导致精明的合同党派人士从根本上低估了国家在维持运转良好的私法制度中的作用。 未能认识到国家对私法干预的必然程度,这意味着智能合约将创造出规范怀疑的财富和权力的新型分配。此外,本文借鉴了互联网法中的两个基本时刻—早期希望超越领土的境界治理,并尝试通过技术推翻版权法,以证明倡导者和学者基于这种新方法的短暂技术承诺而犯下的错误。 最后,本文证明,智能合约远未实现功利主义的效率理想,而是在没有民主监督和治理的情况下构建的,这对于合法的私法体系至关重要。
为什么区块链必须是高并发的? 1. 摩尔定律早已结束目前,提高并发性是解决人类计算能力的主要方向了。但是并发的编程模型一直受到来自上下两方的压力。2000年开始之际,人们已经意识到摩尔定律失效了。你不太可能期待着今年写的C代码在明年的时候能够被更快的处理器运行了。因为处理器性能的提升主要是通过堆积更多的core来完成。所以为了编写更快的代码,你要做的是编写并发式的程序,同时使用更多的核、更多的CPU、更多的机器。对于并发式的编程模型这就是来自于下方的压力。当今的主流商业应用软件都是跑在web端的,7乘24小时百万级以上的并发访问。人们已经无法想象一个运行在桌面的单机程序实现同样的商业价值。对于编程模型来说,这是来自于上方的压力。所以当我们谈论区块链时,我们需要明白支持并发性才能满足市场的需求。2. 线程模型并不理想线程模型是上世纪90年代提出的并发模型,线程模型广泛应用在Java虚拟机、CLR、.net虚拟机中,甚至应用于Erlang这样更高级的系统。线程模型失败的地方在于如果你在读一段Java或C sharp代码,你无法明白有多少个线程在里面。我们可以讨论并行性和并发性,也可以讨论并发式和分步式,前提是我们必须搞清这几个概念。并行性指同步进行的多项活动之间并不共享信息。就像一条八车道的公路,根本没有换道,那就是并行。当你开始允许换道时,不同的活动和线程之间出现交互,那就是并发。分布式就是把每一笔交易想像成一辆车,换道就是切换到不同的处理器上。分布式必然需要面对故障模式,如果允许单独某个任务失败,就带来了本地(local)的概念。线程有不同的概念,包括有操作系统线程和cpu内核的物理线程等等。我谈论的是虚拟机上提供并发性的编程模型。线程模型的问题是本质上在编程语言的语义层面并没有提供并发性的支持。我用语言集成查询作为一个例子,证明语言集成将最终胜出。语言集成查询开始于微软的函数式编程大牛Eric Meyer。数据存储的两个方法是:1,提供一个支持数据存储的库;2,提供一个查询的语言特性。在第一种情况下,并没有类型系统(type system)帮助你对查询进行语义检查。在后一种情况下,类型系统和编译器参与检查确保查询处于良好状态并且不会中断。在过去的十五年中,语言集成查询已经是最热门的话题之一。所以时间将会证明,语言整合的方法会稳步胜出。回到并发的话题,采用库的方法就是线程模式的思路。在语义层面的扩展就是Rholang、 Pict 或者Vim等移动进程演算(mobile process calculi )的思路。type system保证了你在读一段Rholang程序时,能够看到有多少个进程在进行。同样的,如果你采用 pi calculus 或者 ambient calculus也可以具有同样的优势。3. DAO事件其实是一个并发问题并发性成为一种语法现象。因为它是语法,是可以对代码进行分析并检查各种并发属性的语法。一个非常好的示例是竞争条件(race condition):两个事件是否有可能以任意顺序发生?DAO事件其实是一个并发问题,是竞争条件。如果有对应的语言表示,就可以通过语法分析(也称为静态分析),捕获这些错误。即使是熟悉并发问题的老程序员,仍然会不时地搞错,例如用餐哲学家(dining philosophers)或其他类型的问题,所在为并发编写算法是非常困难的。当我在八十年代末和九十年代初期在Rosette工作时,我注意到即使使用非常强大的编程语言,并发编程也是非常困难的事情。不幸的是编程理论停止了二三十年,市场好像卡住了。我惊诧于Javascript一直统治着浏览器平台。我计划开发一个基于Rholang的浏览器语言,使用Rholang从头编写浏览器。4.现在的区块链都错了大多数交易是孤立不相关的。大多数人的财务状况都是彼此分开的。当你去喝咖啡时,地球另一面的人在买菜,你们的交易不相关,在区块链世界中,这一点非常重要。如果我们必须对这些交易进行系列化,我们就走进了死胡同。所有的交易都必须经过一个虚拟机。如果那个虚拟机是顺序的(sequential),Transaction将不得不按线性排列,这正是以太坊虚拟机的模式。在这种情况下,无论是DAG还是区块,那都无所谓了。在区块链上使用序列化模型时,不可能有语言层面的并发的显式表示。因此无法使用静态分析来获得并发行为,并发都隐藏在幕后。这就像一个干净和纯粹的函数式语言和Java之间的区别。使用与lambda演算接近的函数式语言,你所看到的就是你所获得的。所有执行实际上都在代码中。而对于Java来说,程序中存在着一堆隐藏的状态:堆栈、线程数以及类似的东西都在代码中。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值