当前位置:首页区块链区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法

本文讨论了状态机在以太坊的使用( 以太坊便捷方法工作流增强了事实上的区块链智能合约语言)。

状态机仅处于一种状态,通过更改输入或输入事件在状态之间移动。

对于Solidity的智能合约,消息将从其他帐户(外部帐户或其他合约)发送到合约功能,从而引起状态更改。如果输入对于当前状态有效,则状态机将移至新状态。

背景

在开发和测试Datona Labs的Solidity Smart Data Access Contract(S-DAC)模板时,我们经常使用状态机来覆盖工作流程。在本文的示例中,在两个提出问题并提供答案的参与方之间。

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法

UML状态机图

这是我们的示例的UML状态机图:

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法1

圆角矩形表示状态,箭头线表示转换,转换标签是导致转换发生的触发事件(来自指定源)。

固态机模

状态机通过转换函数在解决方案合同中定义的状态之间移动。这是部分开发的Solidity合同:

contractQnAsm100is … {enumStates {AwaitQuestion,GotQuestion,AwaitAnswer,GotAnswer} Statespublicstate = States.AwaitQuestion; … modifieronlyState(Statesexpected){require(state == expected,“ Notpermittedinthisstate”); _;} functionsetQuestion()publiconlyState(States .AwaitQuestion){state = States.GotQuestion;} functiongetQuestion()publiconlyState(States.GotQuestion){state = States.AwaitAnswer;} functionsetAnswer()publiconlyState(States.AwaitAnswer){state = States.GotAnswer;} functiongetAnswer()publiconlyState( States.GotAnswer){state = States.AwaitQuestion;}}

您可以轻松地看到当前状态(通过功能修饰符onlyState进行检查,以确保仅在正确的状态下执行状态转换),新状态和转换功能直接映射到UML状态机图上。

我们称数据所有者为数据所有者。这可能不同于合同所有者。

对使用数据感兴趣的一方称为数据请求者。

继承的支持合同

由于这些角色是Datona Labs合同中的常见主题,因此在合同开发过程中,我们可以将基类用于这些角色以及我们领域中的其他常见角色。为了方便操作,此技术实际上是使用继承而非综合进行劫持。该代码仅用于测试,我们不建议将其用于生产代码。

DataOwner基类包含常规的数据所有者操作,例如构造函数和函数修饰符(onlyDataOwner),如下所示:

contractDataOwner {addresspriatedataOwner; constructor(addressaccount)public {dataOwner = account;} modifieronlyDataOwner(){require(msg.sender == dataOwner,“ MustbeDataOwner”); _;} …}

可以提供其他功能,例如changeDataOwner(帐户)以帮助快速开发试用合同,但是在这种情况下,没有必要。

DataRequester与其他角色基础类相似。

我们可以将基本角色类中的功能修饰符添加到解决方案合同中:

contractQnAsm100isDataOwner,DataRequester,… {… functiongetAccount(addressaccount)internaliewreturns(address){return(account!= address(0))?account:msg.sender;}构造函数(addressdataOwner,addressdataRequester)DcDataOwner(getAccount(dataOwner) )DcDataRequester(getAccount(dataRequester))public {…} functionsetQuestion()publicisDataRequester … functiongetQuestion()publicisDataOwner … functionsetAnswer()publicisDataOwner … functiongetAnswer()publicisDataRequester …}

必须在解决方案合同构造函数期间初始化DataOwner和DataRequester基类。可以提供一个或两个帐户(AKA地址)作为解决方案合同的参数。如果未提供该帐户(即其值为0),则使用msg.sender帐户(即合同所有者)。我们使用getAccount函数来辅助上述构造函数的可读性。

DataOwner和DataRequester是同一个帐户是没有意义的,因此我们还必须在构造函数代码中测试此条件:

构造函数(addressdataOwner,addressdataRequester)DcDataOwner(getAccount(dataOwner))DcDataRequester(getAccount(dataRequester))public {require(dataOwner!= dataRequester,“ DataOwnermustnot”“ beDataRequester”);}

将数据存储在区块链

我们需要在等待数据所有者提取问题的同时存储数据请求者的问题,并在等待数据请求者提取问题的同时存储数据所有者的答案。在此示例中,我们将问题和答案都存储在合同的公共数据字符串中:

contractQnAsm100是… {stringdata; … functionsetQuestion(stringmemoryquestion)… {… data = question;} functiongetQuestion()… returns(stringmemoryquestion){… question = data;} functionsetAnswer(stringmemoryanswer)。 .. {… data = answer;} functiongetAnswer()… returns(stringmemoryanswer){… answer = data;}}

我们可以使用一个通用的数据字符串,因为状态机确保我们只需要在任何时候使用一次字符串(问题或答案),并且我们鼓励我们尽量减少使用存储,因为它太昂贵了,请参阅请按照以下内容了解费用。

分层状态机

当前解决方案的一个问题是合同不能终止,任何未付的资金都归还给合同所有者。

假设可以随时执行此操作,则该解决方案可以实现以下分层状态机设计(有关更多信息,请参见UML状态机):

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法2

合同所有者有权随时终止

通过从ContractOwner基类继承(再次劫持继承作为合成的替代方法),可以轻松地在我们的解决方案合同中实现这一点,该类自动记录合同所有者并提供onlyContractOwner修饰符(类似于上述DataOwner方法):

contractQnAsm100isContractOwner … {…. functionterminate()publiconlyContractOwner {selfdestruct(msg.sender);}}

Solidity selfdestruct()函数通过终止函数将未偿还的以太坊返回给给定帐户,合同所有者可以随时调用此函数。

合同测试

为了测试解决方案合同,我们可以将其部署在区块链上(测试网可以做到)。但是解决方案合同的构造函数有两个参数,DataOwner帐户和DataRequester帐户。

为了实现自动化测试,我们可以创建一个代理帐户来执行DataOwner和DataRequester的操作。以下是DataOwner代理帐户的示例:

contractProxyDataOwner {QnAsm100qnaStateMachine; functionsetStateMachine(QnAsm100_qnaStateMachine)public {qnaStateMachine = _qnaStateMachine;} functionsetAnswer(stringmemoryanswer)public {qnaStateMachine.setAnswer(answer);} functiongetQuestion(string)Requestion(string)

DataRequester代理合同是相似的。它提供了setQuestion和getAnswer函数。

测试合同本身会创建一个代理帐户,然后创建一个解决方案合同:

导入“ StringLib.SOL”; // equaletccontractTestQnAsm100 {usingStrlingLibforstring; ProxyDataOwnerpublicproxyDataOwner = newProxyDataOwner(); ProxyDataRequesterpublicproxyDataRequester = newProxyDataRequester(); QnaStateMachinepublicqnaStateMachine = newQnaStateMachine(proxyData(proxy); addressStateMachineMachineSet()) (stringmemoryquestion,stringmemoryanswer)public {// sendandcheckquestionproxyDataRequester.setQuestion(question); stringmemoryactual = proxyDataOwner.getQuestion(); require(question.equal(act; /“; /sendandcheckanswerproxyDataOwner.setAnswer(answer);actual=proxyDataRequester ; require(answer.equal(act),“ answernotequal”);}}

上面的示例提供了一个公共函数TestQnA,该函数通过proxyDataRequester将给定的问题发送到解决方案合同。然后,它从proxyDataOwner恢复问题并确认其有效性。在另一个方向上进行相同的操作。给定的答案通过proxyDataOwner提供给解决方案合同,然后从proxyDataRequester中提取并进行检查。

建议进行其他测试,以确保状态机的行为符合预期结果。

耗气量

连续询问20个字符的问题并立即获得20个字符的答案所需的气体消耗量是每个序列大约85,000种气体:

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法3

由于用于数据串的空间是第一次在存储器中分配的,因此第一次的气体消耗更大。答案很简单,就是更新分配的数据字符串。

耗气量还取决于字符串的长度。

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法4

0、32、64串问答序列耗气量

由于用于数据串的空间是第一次在存储器中分配的,因此第一次的气体消耗更大。非空字符串比空字符串消耗更多的气体,因为必须分配字符串的地址和实际的字符串字符。

使用事件的替代解决方案

如果您选择让解决方案合同在收到问题或答案时发出事件(请参阅Solidity事件),则可以简化状态机。例如:

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法5

但是,事件只能由前端DApp代码处理,而不能由其他合同处理。这导致需要前端测试的测试策略。解决方案合同还至少需要进行以下修改:

contractQnAsm100 … {… eentQuestion(addressindexed_from,addressindexed_to,bytes32_alue); … functionsetQuestion(stringmemoryquestion)publiconlyDataRequesteronlyState(States.AwaitQuestion){reportSet(question); emitQuestion(msg.sender,dataOwner(),bytes32of(question)) ); state = States.AwaitAnswer;} …}

状态机问题

如本示例所示,状态机的最大问题既是其最大的资产,也是其最大的弱点。必须根据设计执行工作流程。可能会有偏差。通过设计,它们是模态的。

在这种情况下,如果数据请求者希望提出第二个问题,则只有在获得第一个问题的答案后才能继续!这在实践中将非常笨拙并且无法使用。有多种解决方案,例如通过部署多个合同(非常昂贵)或使用队列问题和答案,但是真正的错误在于此特定状态机的基本设计。在这种情况下,出色的设计可能只是双向交互模式,在该模式下,问题和答案可以从一个角色自由地流向另一个角色。

结论

状态机是控制Solidity合同中工作流的理想方法。

状态机易于测试,就像在Solidity中的大多数其他语言中一样。

应该采用分层状态机设计,以确保对例如终止状态机的适当控制。

如果合同直接用于生产,则应精心设计“状态机”,以避免形式化。

Solidity提供有用的功能修改器功能,非常适合在更改状态机状态之前清楚地检查当前状态和其他要求。

与存储数据的成本相比,状态机的气体消耗非常小。也许最好将数据脱链存储…

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法6

通过绘制下面的QR码添加我,并将您拖到技术交流组中

扫描码

跟着我们

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法7

获得

温馨提示:

文章标题:区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法

文章链接:https://www.btchangqing.cn/54089.html

更新时间:2020年07月13日

本站大部分内容均收集于网络,若内容若侵犯到您的权益,请联系我们,我们将第一时间处理。

区块链研究实验室|详细使用状态机作为增强Solidity工作流程的便捷方法8
区块链

一币圈在5 - 6月的重大事件和行业趋势币圈

2020-7-13 9:29:10

区块链

[图形学院]国家级区块链和密码学教室2-9讲座:区块链和加密货币的“脚”

2020-7-13 9:36:02

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索