如何使用以太坊上的状态通道来构建应用程序
扫描二维码
随时随地手机看文章
频繁进行交易以推进以太坊虚拟机是不必要的昂贵和缓慢。今天大多数使用以太坊的应用程序都通过更新链上合约的存储变量来工作,用户为此支付交易费用并花长时间等待区块确认。
为了使用应用程序,我们强迫用户手动将数据库更新提交给世界上最安全,分散和无信任的环境。
通过将一些功能转移到客户端代码上,而不是单独依靠以太坊为我们做所有事情,我们可以编写完全安全的应用程序。通常我们将这些称为“layer2”技术。
大多数“以太坊应用都不可伸缩!”的叙述并不是因为底层的区块链不合适。更准确地说,这是因为开发人员很难使用状态通道等Layer2层技术。我们需要在以太坊之上拥有更好的开发人员工具,这将使以高效方式编写应用程序变得更加容易。
Counterfactual是一个开源项目,正致力于解决这个问题。我们的目标是使开发人员易于使用以太坊上的状态通道来构建应用程序。
为什么现在很难使用状态通道?
今天,如果开发人员希望使用以太坊编写分布式应用程序,他们可能要实现以下每一项:
1. 公共API-合约上的public或extenal函数
2. 授权逻辑(Authorization logic)-通常通过检查msg.sender
3. 解决逻辑(ResoluTIon logic)-决定如何分配资金
在大多数情况下,这是开发人员在设计分布式应用程序时要考虑的一个很好的抽象层次。 去年,我们已经看到成千上万的开发人员使用这种模式使用以太坊构建应用程序,所以最好不要彻底改变它。
从这种角度考虑状态通道会给应用程序开发人员产生更多共鸣。在大多数情况下,尝试设计状态通道应用程序时,您会遇到各种障碍,例如:
1. 不清楚应该如何编写公共API,因为您不再签署Ethereum事务,而是签署通用状态对象
2. 授权逻辑(AuthorizaTIon logic)要求状态通道的每个用户为每个更新签署一个对象,并使用ecrecover验证这些签名。
3. 由于每次提交新状态时都有一个内置的“挑战”或“争议”阶段,因此现在的解决逻辑(ResoluTIon logic)更加复杂。
最糟糕的是,对于整个状态通道协议,没有任何既定的标准,这使得框架或公共库很难出现。
我们可以做些什么来简化它?
使状态通道应用程序更易于推理的最重要的第一步是标准化通用状态通道功能,使状态通道解析逻辑与应用程序逻辑完全分离以与状态通道兼容的格式编写应用程序应该尽可能简单,理想情况下,应该感觉像是在编写常规的智能合约代码。
实现此目的的一种方法是将应用程序建模为状态机。强制移动游戏框架就是其中的一个示例,通常EVM已基于状态机的基本思想构建,状态机基于事务执行来更新每个区块的状态。
那么,普通智能合约和兼容状态通道的智能合约有什么区别?本质上可以归结为以下事实:无论公共API的实现如何,我们都需要一种标准方法来与应用程序的状态转换进行交互。简而言之,我们需要一个入口点函数来计算状态转换。
一个例子-井字游戏
假设我们要编写一个井字游戏应用程序。我们可能会编写一个智能合约,该合约具有带有placeX和placeO函数的公共API,并检查msg.sender以验证是否有正确的参与者在行动。
contract TIcTacToe {
address player1;
address player2;
uint8[3][3] board;
uint8 nextTurn;
function placeX(uint8 x, uint8 y) public {
if (msg.sender == player1) { 。。. }
}
function placeO(uint8 x, uint8 y) public {
if (msg.sender == player2) { 。。. }
}
}
用Solidity编写的井字游戏智能合约示例。
将这个游戏建模为一个状态机,我们可以看到在它们之间有5种状态和2种有效的转换类型。
井字游戏应用程序的状态机示例。 如果是X的回合,X可以采取行动赢得比赛,以平局结束比赛,或者只是放下棋子并将其传递给O进行回合。
回到用于更新应用程序状态的标准接口的想法,我们想创建一个函数,该函数接受状态机的某些先前状态(例如X_TURN)以及可以采取的操作以达到新状态 (例如PLACE_X)。 有趣的是,这与当今存在的某些常见Web框架(例如Redux)完全相同。 他们倾向于将这种功能称为“reducer”。 因此,让我们尝试以这种方式编写井字游戏应用程序:
contract TicTacToe {
enum ActionTypes { PLACE_X, PLACE_O }
enum StateTypes { X_TURN, O_TURN, X_WIN, O_WIN, DRAW }
struct Action {
ActionTypes actionType;
uint8 x;
uint8 y;
}
struct AppState {
StateTypes stateType;
address player1;
address player2;
uint8[3][3] board;
uint8 nextTurn;
}
function reduce(AppState state, Action action)
public
view
returns (AppState)
{
if (action.actionType == ActionTypes.PLACE_X) {
require(state.stateType == StateTypes.X_TURN);
return onPlaceX(state, action);
} else if (action.actionType == ActionTypes.PLACE_O) {
require(state.stateType == StateTypes.O_TURN);
return onPlaceO(state, action);
} else {
revert(“Invalid action type”);
}
}
function onPlaceX(AppState state, Action action) internal returns (AppState) { 。。. }
function onPlaceO(AppState state, Action action) internal returns (AppState) { 。。. }
}
一个井字游戏应用程序,它具有一个用于处理PLACE_X和PLACE_O动作的reduce函数而不是多个名为placeX和placeO的函数。reducer功能将动作“分派”到helper函数。
有了这个,我们现在有了一种计算状态更新的方法,可以通过一个公共接口——reduce接口对应用程序进行更新。在考虑必须保护状态通道的攻击类型时,这非常有用。
但是状态通道合约中需要做什么呢?
当然,状态通道对象应该使用应用程序逻辑来确定转换是否有效。核心状态通道功能可以存在于通用协定中,该协定处理可能的各种攻击情形,但会为其状态机的特定转换规则委派给应用程序。
状态通道可以使用App逻辑作为确定有效转换的手段,但是根据App逻辑提供给它的信息来处理授权和解析逻辑本身。
有两种主要情况需要处理。如果我们使用Alice和Bob相互交换消息的常见示例,则可以将它们构造为:
1、如果Bob提交过时的状态呢?
合约必须能够实现一个超时期,以便Alice有时间提交比Bob提交的状态更新的状态。如果Bob提交的状态可以证明是超时的,那么Bob应该受到惩罚。
2、如果Bob停止响应怎么办?
合约必须使Alice能够提交她从Bob那里收到的最新签名状态,以便将她的钱取出(在超时期限过去之后)。在某些情况下,Alice可能会“采取行动”以改善应用程序的状态机,因此在这种情况下,她必须能够使用应用程序的reducer。
为此,合约需要公开一个基本的API。请注意,这实际上是处理争议案件的API。状态通道的用户可以使用一组函数调用来确保他们正在签名的链下状态更新具有重要意义。
这个API大致包括:
· 创建争议案件。
一方提交状态的最新签名副本,并可选地对应用程序执行操作,该操作将在逻辑上将状态提升到下一个状态。
· 进行争议。
一方通过对已提交的状态采取行动来回应另一方的争议。
· 取消争议。
双方同意取消争议并恢复正常。
资金存放在哪里?
这就是本文中描述的许多特性变得有用的地方。我们将这些资金放在一个通用的多签名钱包中,并将其用作根据状态通道的结果作出分配资金承诺的主要智能合约。
一个简单的应用程序使用状态通道而不使用反事实实例化,而只是使用常规的智能合约引用。
这给了我们很多有益的好处。最好的方法之一是利用反事实实例化技术的能力,本文也对此进行了详细介绍。当我们将其添加到组合中时,我们可以使状态通道合约和应用程序逻辑合约保持链下状态。
与上述相同的设置,但是这次状态通道合约和应用程序逻辑合同是反事实的-仅在发生纠纷时才需要在链上进行部署。
设置之后,我们得到了另一个非常强大的特性:用于安装和卸载应用程序的零链上事务。
当我们使用反事实时,添加和删除应用程序是免费且即时的。
实际上,由于我们可以从多签名钱包进行无限次数的有条件转账,因此这些commitments可以用于任何数量的应用程序。
下一步
在以后的帖子,讲座和讨论中,我们将概述对将用于合约层之上的软件的愿景。要在生产环境中使用的状态通道,将需要整个生态系统的大量协调。我们目前正在一些具体领域应用,并希望与其他领域进一步合作:
1. 标准化研究术语,分享见解,并在状态通道和第2层缩放中跟进其他有趣的研究问题。
2. 将广义状态信道模式集成到现有的状态信道系统和基于非链式范式的应用程序。
3. 与web3框架合作,使链外关注点在开发人员api的未来开发中广为人知。
4. 与钱包提供者一起工作,帮助提供清晰的协议规范和标准,说明状态通道可以在其域中如何存在。