我想知道在Haskell或Idris等类型语言中表达智能合约的最佳方式是什么(例如,您可以将其编译为在以太坊网络上运行)。我主要担心的是:哪种类型可以捕获合同可以执行的所有操作?
一个天真的解决方案是将合同定义为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
}
即,合同开发商需要明确定义如何处理货币存款和取款。这种类型足以定义任何可以与主机区块链的货币互动的自包含合约。可悲的是,这样的合同将无法与其他合同互动。在实践中,合同经常相互影响。例如,Exchange需要与其交换的令牌合同进行通信以查询余额等。
所以,让我们退后一步,重写保守的解决方案:
type Contract = {
act : UserID -> Action -> Map ContractID State -> State,
init : State
}
根据这个定义,act
函数不仅可以访问合约自己的状态,还可以访问同一区块链上每个其他合约的状态。由于每个合同都可以读取彼此的状态,因此可以在此基础上轻松实现通信协议,因此,这种类型足以实现任意交互的合同。此外,如果区块链的货币本身是作为合约实现的(可能使用包装器),那么该类型也足以处理货币,尽管没有对货币进行硬编码。但该解决方案有两个问题:
偷看另一份合同的状态似乎是一种非常“hacky”的方式来实现沟通;
以这种方式定义的合同将无法与不了解该解决方案的现有合同进行交互。
现在我在黑暗中。我知道我对这个问题没有正确的抽象,但我不确定它会是什么。 看起来问题的根源在于我无法正确捕捉交叉合同通信现象。哪种具体类型更适合定义任意智能合约?