如何在UML中对智能合约建模?

mar*_*odb 4 uml solidity smartcontracts

我正在寻找一种使用UML等建模语言对以太坊智能合约交互进行建模的方法。

我有以下保密合同:

contract ServiceContract {


    constructor (address _storeC, address _quizC, address _signC) {

        StorageContract storeC = StoreContract(_storeC);
        QuizContract quizC = QuizContract(_quizC);
        SignatureContract signC = SignatureContract(_signC);
    }


    function storeData (bytes32 data) public {
        storeC.save(data);
    }

    function getAnswer( bytes32 question) public constant returns (bytes32) {
       return quizC.get(question);
    }

    function sign (bytes32 data) public returns (bytes32) {
        return signC.sign(data);
    }

}
Run Code Online (Sandbox Code Playgroud)

我用这个类图对它进行了建模,对吗?

在此处输入图片说明

qwe*_*_so 5

您仅与以下三个类有关联:

在此处输入图片说明

(我只画了一个关系)

右边的角色名称与点一起表明它是左边类的拥有的属性。不知道的知名度(如果那是私有的每默认更换+-)。


Nés*_*nez 5

[编辑以进行额外说明]

对系统进行建模是使用建模语言以正式方式对其进行描述,并且在某些情况下遵循一些通用准则。在这种情况下,您建议使用 UML(请参阅UML 规范)。

UML图可以分为三类:

  • 结构:通用结构、值、分类器和包都在这个类别中
  • 行为:常见行为、动作、状态机、活动和交互都属于这一类。
  • 补充:用例、部署和信息流都在此类别中。

作为建模者,您可以决定针对要应用的目标需要哪些图表。

在您的问题中,您说您正在寻找一种对交互进行建模的方法。那属于行为范畴。但是,您提供了一个示例代码和一个建议的类图,它们在结构类别中

话虽如此,您提出的图表是否正确?我会说它不准确和不完整(但不一定不正确)。让我进一步解释一下。

在你提出的图你有四类:ServiceContractStorageContractQuizContractSignatureContract。您已经绘制了称为依赖项的类之间的关系。这种依赖是一种特定的类型:用法(由 «use» 关键字表示)。这在 UML 中是什么意思?

UML 中的依赖关系被定义为一种关系,其中“没有供应商,客户的语义是不完整的”(UML 规范的第 7.7.3.1 节)。此外,使用依赖被定义为一种关系,其中“一个 NamedElement 需要另一个 NamedElement(或一组 NamedElements)来实现其完整的实现或操作”(7.7.3.2)。

因此,如果我们将这些定义应用到您提议的图表中,您可以将 theServiceContract和 the之间的关系理解StorageContract为“ServiceContract用途StorageContract”。但没有别的。使用此图,您不知道如何ServiceContract使用StorageContract,如果它使用多个 实例StorageContract,等等。

由于您知道这些类是如何相关的,因此您应该使用更准确和完整的图表。

第一步是使用关联而不是依赖。在 UML 中,关联被定义为“可以在类型化实例之间发生的语义关系”。并且您知道您在类图中建模的类之间的语义关系。因此使用关联更有意义。

关联被表示用实线(确实UML规范说,它可以被绘制为菱形,但对于二元关联它说,通常它仅仅是用实线画出)。因此,让我们开始将您的图表更改为新图表。下图中可以看到有关联关系的四个类(还是不完整):

在此处输入图片说明

现在我们有了关联,我们需要进一步定义它。协会有名字吗?可以通过两种方式读取关联吗?我们知道关联每一端的多重性值吗?关联的目的是否有限制?

在这个例子中,我们不需要关联的名称,它似乎可以通过两种方式读取,而且所有端的重数值都恰好为 1。那么我们不要在与这些问题相关的图表中添加任何内容。但是约束呢?

我们来看看源代码。当你把这个:

contract ServiceContract {
    constructor (address _storeC, address _quizC, address _signC) {
        StorageContract storeC = StoreContract(_storeC);
        QuizContract quizC = QuizContract(_quizC);
        SignatureContract signC = SignatureContract(_signC);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将其表示为“ServiceContract拥有(拥有)一个名为storeCStoreContract类型的属性,依此类推。关联中的所有权由一个小的实心圆圈(称为)表示,位于线与拥有的分类器的交点处。您也可以添加拥有所有权的属性的名称(第 11.5.4 节)。此时的图是这样的:

在此处输入图片说明

(见Thomas Kilian 的回答

由于我们无法从源推断属性的可见性,我们可以将其设为未定义(否则我们可以+在属性名称前使用符号表示公共属性,-符号表示私有属性,a#表示受保护的属性, 和 a~表示包)。

我们也可以显示分类器中的属性,ServiceContract而不是在关联中拥有的分类器的末尾。这将如下所示:

在此处输入图片说明

UML 规范(第 9.5.3 节)允许这两种样式,并且它也不强制执行任何约定。但是它提到了一般建模场景的约定“类型为类的属性是关联端,而类型为数据类型的属性不是”。

该图在符合 UML 规范的意义上是正确的,并且它描述了一个系统,您在其中拥有:

  • ServiceContract具有三个属性的命名分类器:
    • 一个名为storeC的属性,其类型是一个名为 的分类器StorageContract
    • 一个名为quizC的属性,其类型是一个名为 的分类器QuizContract
    • 一个名为signC的属性,其类型是一个名为 的分类器SignatureContract

请记住,作为建模者,这是否足以满足您的目标是您的选择。

从源头上我可以说,之前的图表仍然不完整和不准确。为什么?

  • 因为源包括三个未在图中表示的操作(功能)。这可以在完整性方面得到改进。
  • 因为您无法从图中判断出所拥有的分类器是否被拥有以将ServiceContract一组拥有的分类器的实例组合在一起。在这种情况下,如果拥有的分类器共享相同的范围。这可以在准确性方面得到改进。

首先,我们要将操作(函数)添加到图表中:

在此处输入图片说明

[注意:您也可以将 _constructor_ 添加到操作中。]

我猜函数是公共的,所以我+在每个操作名称的开头都包含了修饰符。

现在的准确性,在我看来,该ServiceContract组一起StorageContract,在QuizContractSignatureContract以提供一个共同的分类,以获得某些操作(功能)。如果是这样,那么我们谈论的是聚合。在 UML 中,聚合被定义为一种关联,其中“一个实例用于将一组实例组合在一起”(第 9.5.3 节)。

聚合可以有两种类型:共享(或通常称为规范先前版本的聚合)和复合(或通常称为规范先前版本的组合)。

UML 规范为聚合是复合类型的含义提供了或多或少特定的语义:“复合对象负责组合对象的存在和存储”。

比方说,你的情况的存在和存储StorageContract,在QuizContractSignatureContract是的责任ServiceContract。那么在这种情况下,您有一个复合聚合,由黑色菱形表示:

在此处输入图片说明

它被读作“ServiceContractStorageContract称为storeC的分类器类型的拥有属性组成,依此类推。

请记住,使用复合类型的聚合是指ServiceContract对象负责存在和存储。这意味着每当ServiceContract删除/销毁的实例时,关联的StorageContract,QuizContract和 也SignatureContract必须被销毁。

如果情况并非如此,并且鉴于关联仍然与聚合定义匹配,则唯一可用的其他选项是聚合必须是共享的。UML 规范明确没有提供共享聚合是什么的精确语义,让应用程序领域和建模者负责提供这些语义。

所以,如果StorageContract,在QuizContractSignatureContract独立存在的ServiceContract,如果你同意,ServiceContract聚集这些对象根据UML规范给出的定义,你必须使用一个共享的聚集。

共享聚集由空心菱形,分类该聚集体的其它分类器关联的端部表示。这就是它的外观:

在此处输入图片说明

这张图可以理解为:

  • 有四个分类器:ServiceContractStorageContractQuizContractSignatureContract
  • ServiceContract 聚合三个拥有的属性:
    • storeC, 类型StorageContract
    • quizC, 类型QuizContract
    • signC, 类型SignatureContract
  • ServiceContract 有一个需要三个参数的构造函数:
    • _storeC类型的address
    • _quizC类型的address
    • _signC类型的address
  • ServiceContract 具有三个公共功能:
    • storeData,这需要的类型的一个参数bytes32data并且没有返回。
    • getAnswer,需要类型的一个参数bytes32调用question,并返回一个bytes32数据类型。
    • sign,这需要一个bytes32名为 data类型的参数并返回一个bytes32数据类型。

请记住,对于您想要的目标,这个最终图表可能过于详细。作为建模者,您有责任决定是否在图表中包含一些细节。