【发布时间】:2017-07-02 00:24:23
【问题描述】:
我想知道用 Haskell 或 Idris 等类型语言表达智能合约的最佳方式是什么(例如,您可以编译它以在以太坊网络上运行)。我主要关心的是:捕获合约可以做的所有事情的类型是什么?
简单的解决方案:EthIO
一个天真的解决方案是将合约定义为EthIO 类型的成员。这样的类型就像 Haskell 的IO,但不是启用系统调用,而是包括区块链调用,即可以读取和写入区块链的状态,调用其他合约,获取区块数据等。
-- incrementer.contract
main: EthIO
main = do
x <- SREAD 0x123456789ABCDEF
SSTORE (x + 1) 0x123456789ABCDEF
这显然足以执行任何合同,但是:
-
太强大了。
-
特别是与以太坊区块链非常耦合。
保守的解决方案:事件溯源模式
在这个想法下,合约将被定义为折叠操作列表:
type Contract action state = {
act : UserID -> action -> state -> state,
init : state
}
所以,一个程序应该是这样的:
incrementer.contract
main : Contract
main = {
act _ _ state = state + 1,
init = 0
}
也就是说,您定义初始状态、操作类型以及当用户提交操作时该状态如何变化。这将允许人们定义任何不涉及发送/接收资金的任意合同。大多数区块链都有某种货币,而最有用的合约以某种方式涉及货币,因此这种类型的限制过于严格。
不太保守的解决方案:事件 + 货币
我们可以通过将货币逻辑硬编码到上面的类型中来让上面的类型知道货币。因此,我们会得到类似的东西:
type Contract action state = {
act : UserID -> action -> state -> state,
init : state,
deposit : UserID -> Amount -> state -> state,
withdrawal : UserID -> Amount -> state -> Maybe state
}
即,合约开发者需要明确定义如何处理货币存款和取款。这种类型足以定义任何可以与主机区块链货币交互的自包含合约。遗憾的是,这样的合约无法与其他合约交互。在实践中,合同经常相互影响。例如,交易所需要与其交换的 Token 合约进行通信以查询余额等。
泛化:全局状态?
所以,让我们退后一步,将保守的解决方案重写为:
type Contract = {
act : UserID -> Action -> Map ContractID State -> State,
init : State
}
根据此定义,act 函数不仅可以访问合约自身的状态,还可以访问同一区块链上所有其他合约的状态。由于每个合约都可以读取彼此的状态,因此可以轻松地在此之上实现通信协议,因此,这种类型足以实现任意交互的合约。此外,如果区块链的货币本身是作为合同实现的(可能使用包装器),那么该类型也足以处理货币,尽管它没有在类型上进行硬编码。但该解决方案有两个问题:
-
查看另一个合约的状态看起来像是一种非常“hacky”的通信方式;
-
以这种方式定义的合约将无法与不了解该解决方案的现有合约交互。
现在怎么办?
现在我在黑暗中。我知道我对这个问题没有正确的抽象,但我不确定它会是什么。 看起来问题的根源在于我无法正确捕捉跨合约通信的现象。什么具体类型更适合定义任意智能合约?
【问题讨论】:
-
“[事件溯源风格]将允许定义任何不涉及发送/接收资金的任意合同。”为什么事件溯源不能处理汇款和收款?
-
@BenjaminHodgson 如果它使用我在此处发布的类型,编译的合约将如何能够从主机区块链发送/接收资金?它没有在定义中的任何地方指定如何处理传入的以太币,也没有在什么情况下合约应该将以太币发送出去......
-
你读过 Pettersson 和 Edstrom 的硕士论文Safer smart contracts through type-driven development吗?它描述了使用其效果系统将以太坊合约嵌入到 Idris 中。
-
或许bitcoin community对此有更多想法
标签: haskell functional-programming idris ethereum smartcontracts