Understanding UTxO Spending through a Script | Cardano Explorer (cexplorer.io)
支出 UTxO 可以以脚本定义的逻辑为条件。 在这种情况下,UTxO 的花费者必须向脚本提供能够解锁 UTxO 的数据。 在本文中,我们将了解如何锁定 UTxO 以及如何通过执行验证器脚本来解锁它。
UTxO 通过交易花费
要理解本文,需要了解 UTxO 记账模型、UTxO 的结构、Shelley 地址以及通过密钥凭证花费 UTxO 的常见方式。 我们在上一篇文章中对此进行了描述。
在下图中,您可以看到包含支付凭证的 Shelley 地址,其中包括用于花费相关 UTxO 的两个选项。 一个地址可以与多个 UTxO 关联。
支付凭证是 Shelley 地址的一部分,用于识别谁拥有该地址中的资金,从而确定谁能够使用 UTxO。 支付凭证可以是密钥凭证(基于公钥/验证密钥)或脚本凭证(脚本的哈希值)。
花费 UTxO 的触发因素是交易。 除其他参数外,交易必须包含见证人。 见证人是证明一笔交易得到资金所有者授权的数据。 如果见证人有效,则交易可以消耗输入的 UTxO。 见证人可以是签名(对于密钥凭证)或脚本执行(对于脚本凭证)。
在密钥凭证的情况下,见证人是由所有者的私钥所做的签名。 签名必须与属于持有 UTxO 的地址的密钥凭证(公钥)相对应。
当用户想要向其他人发送资金时,钱包会为他们构建常规交易。 钱包选择适当的 UTxO 并要求发送者签署交易。 在后台,每个要花费的 UTxO 都会在交易中插入一个见证人。
如果交易有效并且将由卡尔达诺网络最终确定(永久存储在区块链中),则交易将消耗输入的 UTxO,并从中创建新的 UTxO(完全按照发送者的定义)。 支出可以简单地想象为将 UTxO(资金)从一个地址转移到另一个地址。 资金可以在搬迁过程中重新分配,但总价值必须保持(或更少)。
在区块链的末尾,包含交易的新块会定期附加。 Cardano区块链可以看作是UTxO转账的记账记录。
我们在上一篇文章中详细描述过。 在本文中,我们重点讨论见证人是脚本执行的情况。
锁定UTxO
通过脚本(验证器脚本)花费 UTxO 是一个两阶段过程,包括两个交易。 第一个交易锁定资金,第二个交易通过执行脚本解锁资金。 我们将第一笔交易称为锁定交易,第二笔交易称为支出交易。
第一个交易是创建锁定脚本地址的 UTxO 的交易。 当 UTxO 被锁定在脚本地址时,不会执行任何脚本。 只有目标地址(在锁定交易的输出 UTxO 中定义)很重要,即脚本地址。
第二笔交易尝试花费脚本地址持有的 UTxO。 这会触发验证器脚本的执行。 脚本的返回值(脚本执行的结果)将决定是否解锁UTxO。
下图中您可以看到通过脚本锁定和解锁 UTxO 的过程。 锁定交易有一个输出UTxO,其目标地址显示脚本地址。 这会将 UTxO 锁定到脚本地址。 支出交易从脚本地址消耗UTxO,这会触发Cardano节点上脚本的执行(红色箭头)。 该图描述了基本概念。 我们将在下面更详细地解释这一点。
让我们解释一下脚本地址这个术语。 雪莱地址是卡尔达诺雪莱时代支持的任何地址的通用术语。 Shelley 地址可以具有不同的类型和格式,具体取决于凭据和网络标记。 Shelley 地址可以有一个脚本哈希作为支付凭证,这使其成为一个脚本地址。 如果您听到术语“脚本地址”,您就会知道 UTxO 的支出只能通过脚本来实现。
脚本地址源自验证器脚本的哈希值。 开发人员创建一个脚本并对其进行哈希处理。 该哈希值用作 Shelley 地址的支付凭证。 当UTxO与脚本地址关联时,它只能由脚本解锁。 该脚本将传递多个输入(稍后会详细介绍),如果其执行以 True 的返回值结束,则可以花费资金。
请注意一件重要的事情。 创建了脚本地址,但脚本(脚本内容)并未存储在区块链中。 仅使用脚本的哈希来创建脚本地址(这不足以执行)。 下面您将了解如何将脚本内容传递到卡尔达诺节点以验证支出交易。
在下图中,您可以看到在付款凭证中设置了脚本哈希的地址。 当脚本的源代码完成(并测试)后,开发人员将其用作创建脚本哈希的基础。 脚本哈希是从脚本内容派生的唯一标识符。 脚本哈希是一种短数字指纹的形式,可确保在验证(即脚本执行)期间使用用于创建哈希的确切脚本(脚本的内容)。 这确保了使用其他脚本无法更改花费 UTxO 的条件。
当验证节点是否验证正确的脚本时,卡尔达诺节点会验证脚本哈希。 如果更改原始脚本中的单个字符,其哈希值将完全不同。 如果脚本是通过交易传递的,则脚本的内容必须生成与支付凭证中存储的哈希相同的哈希。
存储在支付凭证中的哈希值与要执行以验证交易的脚本源代码的哈希值之间必须始终匹配。 如果哈希值不同,验证将失败。
在交易向其发送(关联)资金之前,必须创建脚本地址。 否则,锁定交易将不知道将资金发送到哪里以及如何使用脚本锁定它们。
创建脚本地址后,即可将资金发送到该地址,如下图所示。 该交易有一个输入 UTxO 和两个输出。 交易的发送者是 Alice。 Alice 通过为输入 UTxO 提供单一见证人来授权交易。 Alice想要发送1000个ADA到属于DEX的脚本地址。 她的钱包里只有一个 UTxO,里面有 2500 ADA。 第一个目的地地址属于她,并将 1500 ADA 返回到她的地址。 第二目的地址是属于DEX的脚本地址。
在下图中,您可以看到网络验证(并最终确定)交易后的脚本地址。 UTxO 与脚本地址相关联。
Uploading: image.png(3)…
Datum 是一个可选参数,可用于存储与花费 UTxO 相关的一些信息或状态。 数据与 UTxO 一起存储在脚本地址处,并且可以在执行期间由验证器脚本访问。
数据被插入到在脚本地址锁定 UTxO 的事务中,因此也被插入到从脚本地址解锁 UTxO 的事务中。
在下图中,您可以看到将 UTxO 与 Datum 一起锁定在脚本地址上的交易。 该锁定交易与之前的锁定交易的不同之处仅在于它包含将与 UTxO 关联的 Datum。
在下图中,您可以看到网络验证(并最终确定)交易后的脚本地址。 UTxO 与脚本地址相关联,它包含 Datum。
脚本地址上的资金由脚本本身控制,它定义了花费 UTxO 的条件。 该脚本接受一些输入,例如见证人、数据、救赎者和脚本上下文,并返回 True 或 False,指示支出是否有效。 稍后我们将详细讨论脚本输入。
现在我们已经将 UTxO 锁定在脚本地址上。
访问脚本
在我们开始解释如何解锁 UTxO 之前,我们需要了解节点如何找到用于验证尝试从脚本地址花费 UTxO 的交易的脚本。 脚本的内容必须可供卡尔达诺节点使用,以便它可以执行它,即验证支出交易。
脚本内容可以作为脚本见证插入到支出交易数据中。 这意味着尝试花费 UTxO 的交易必须包含脚本内容作为交易主体的一部分。 这增加了交易规模,从而增加了费用。 一般来说,它限制了脚本的复杂性,因为它迫使开发人员将脚本制作得尽可能小(块大小有限,用户不想支付高额费用)。
如果用户发送多个此类交易,则同一脚本的内容将多次存储在区块链中,这是不必要的空间浪费。
在下图中,您可以看到一笔支出交易,其中包含见证人部分中的脚本内容(红色)。 请注意输入 UTxO 如何通过脚本哈希定义必须使用哪个脚本进行验证。 卡尔达诺节点从交易主体中获取脚本内容并创建哈希。 该哈希值必须与支付凭证中包含的脚本哈希值(红色箭头)相匹配。
另一种可能性是该脚本可以与 UTxO 关联作为参考脚本。 这意味着创建 UTxO 的锁定交易必须包含脚本作为交易输出的一部分。 然后,脚本的内容作为参考脚本存储在区块链上,并且可以通过其哈希进行访问。
因此,脚本只能在区块链上存储一次,然后可以被后续交易重用,而不必包含脚本的内容。 相反,后续交易可以通过哈希值引用脚本,这也是在脚本地址中识别它们的方式。 这减少了交易的规模和费用,并允许脚本具有更大的灵活性和可扩展性。
在下图中,您可以看到一个锁定交易,它将脚本的内容存储到区块链的脚本地址处。
首先,如上所述创建脚本地址。 创建脚本地址后,并不包含脚本的内容。 一旦脚本地址存在,脚本的内容就可以通过交易存储在其上。
在下图中,您可以看到网络验证(并最终确定)交易后的脚本地址。 脚本的内容存储在区块链中,可以被其他交易引用。
始终只有一个与该脚本关联的脚本地址。 然后,用户可以通过锁定交易将其他 UTxO 发送(从而锁定)到同一脚本地址,并尝试通过支出交易从该地址花费它们(解锁始终需要执行脚本)。
带有脚本的 UTxO 始终位于脚本地址上,除非通过满足脚本而花费它。
因此,花费 UTxO 的交易可以通过其哈希引用脚本,而不必将其包含在交易数据中。
在下图中,您可以看到一个脚本地址,其中有一个存储脚本内容的 UTxO(红色),以及其他用户发送到该地址的 3 个 UTxO(蓝色),这些 UTxO 将从该地址通过 脚本的执行。 只要脚本被使用,该地址就会被重复使用。
现在您知道如何在脚本地址锁定 UTxO 以及 Cardano 节点如何获取脚本内容。 让我们仔细看看解锁 UTxO。
解锁 UTxO
锁定在脚本地址的UTxO可以通过触发脚本执行的支出交易来支出。 如果 UTxO 与脚本地址关联,则该脚本必须始终被执行,并且没有办法绕过它。
支出交易的输出 UTxO 中定义的目标地址以及如何通过新的 UTxO 分配资金并不重要。
让我们看看卡尔达诺节点如何验证需要执行脚本的支出交易。
节点检查支出交易是否在第一阶段有效,这意味着它的构造正确并且可以支付处理费。
交易必须支付足够的费用来支付验证器脚本的执行成本,这取决于脚本的大小和复杂性。 费用是使用coinsPerUTxOWord协议参数计算的,该参数决定了需要多少ADAed 每个脚本代码字节。
如果交易通过第一阶段验证,则可以执行脚本,否则交易将被拒绝。
在第 2 阶段验证期间,将执行该脚本。 仅当可以花费(解锁)每个输入 UTxO 时,交易才有效。 对于与脚本地址关联的每个输入 UTxO,脚本的返回值必须为 True。
节点检索与交易尝试花费的 UTxO 关联的脚本。 该脚本可以通过其哈希引用或插入到交易数据中。 该节点还检查检索或插入的脚本的哈希值是否与输出的支付凭证中存储的哈希值匹配。 如果不匹配,交易将被视为无效而被拒绝。
节点将输入传递给脚本并执行它。 验证器脚本可以获得以下输入:
数据:这是附加到脚本锁定的 UTxO 的一段数据。 数据可用于存储与花费 UTxO 相关的某些状态或条件。
救赎者:这是附加到支出输入的一条数据。 这通常用于从支出者向脚本提供输入。 它可用于提供解锁资金所需的一些信息或逻辑。 对于任何具有基于脚本的地址的输入 UTxO,救赎者都是必需的,无论脚本的类型或内容如何。
交易上下文:这是一段数据,表示有关支出交易的信息。 这用于对输出的使用方式做出断言。 例如,脚本的逻辑可能需要签名。 签名可用于证明脚本所需的某些资金或代币的所有权。
该脚本返回 True 或 False,指示是否满足支出条件。 如果为 True,则交易被接受并且 UTxO 被花费。 如果为 False,则交易被拒绝并且 UTxO 保持未花费状态。
下图显示了通过支出交易解锁 UTxO。 交易的输入是与脚本地址(蓝色箭头)相关联的UTxO。
交易引用脚本(在本例中,脚本内容不是交易主体的一部分)。 Cardano节点获取存储在区块链中(以UTxO形式)的脚本内容,并将脚本内容的哈希值与支付凭证中的脚本哈希值进行比较(红色箭头)。
接下来,需要获取脚本的输入并将其传递给脚本(绿色箭头)。
如果数据已经存储在区块链上,则无需将其再次插入到支出交易中。 节点可以通过查找存储在 UTxO 中的 Datum 哈希来找到 Datum 值。 但是,如果 Datum 未存储在区块链上,则支出交易必须提供与 UTxO 中的 Datum 哈希相匹配的 Datum 值。 这是为了确保脚本在验证支出交易时可以访问 Datum 值。
此外,救赎者和交易上下文作为脚本的输入传递。 交易上下文包含有关交易的所有必要信息,例如输入 UTxO 和输出 UTxO 的列表、费用、证人(签名)、数据、验证脚本(或对它们的引用)等。
输入被传递到脚本并执行脚本逻辑。 输入影响返回值。 在我们的示例中,返回值为 True,因此可以花费 UTxO(黑色箭头)。 资金将被转移到新的目的地地址。
关于DEX脚本的逻辑
在本章中,我们将尝试解释有关卡尔达诺智能合约的更多背景信息。
在我们的示例中,Alice 向 DEX 的脚本地址发送了 1000 个 ADA,这意味着她创建了一个被该脚本地址锁定的 UTxO。 脚本地址源自DEX验证器脚本的哈希值,其中包含在DEX平台上交换代币的逻辑。 该脚本还可以包含取消订单的逻辑。
Alice 怎么可能不需要手动创建交易呢? 她使用交易所的用户界面,输入她的请求(掉期订单),然后系统提示确认交易。 DEX(应用程序)为 Alice 创建了一笔交易。
在下图中,您可以看到在卡尔达诺生态系统中,智能合约可以由应用程序的链下和链上部分组成。 链下逻辑负责构建锁定和支出交易。 就 DEX 而言,链下逻辑在服务器(云端)上处理。 在本文中,我们只处理链上逻辑,即脚本验证,它通过卡尔达诺虚拟机在区块链上进行。
Alice 只与构建交易的 DEX 的链下部分进行交互。 锁定交易(交换订单)需要 Alice 的签名。
如果 Alice 决定取消订单,她可以取回资金德克斯。 为此,她必须创建一个交易,花费由脚本地址锁定的 UTxO,并将其发送回她自己的地址。 取消(支出)交易是由链下逻辑构建的,因此Alice只使用DEX的接口。 她必须提供一名证人来证明她对 UTxO 的所有权,并提供一名救赎者来表明她打算取消订单。 然后验证器脚本将验证 Alice 是否确实是 UTxO 的所有者。
各种 DEX(或其他应用程序)的验证器脚本在功能和为用户提供的选项方面存在显着差异。
要解锁资金,DEX、Alice 或任何其他想要花费 UTxO 的人必须向验证器脚本提供正确的输入,例如签名、救赎者或 Datum。 然后,验证器脚本将检查输入是否满足交换规则,例如匹配报价、支付费用以及遵守有效性间隔。
虽然基本上任何人都可以花费资金,但 DEX 应该匹配订单并执行交换,即它最能满足脚本的条件。 然而,脚本的条件之一可以是用Alice或DEX的私钥签名,因此可以定义一组可以花费资金的人。
DEX 无法窃取脚本地址上的资金。 DEX 只能通过提供输入来满足脚本,从而执行用户的命令。 DEX 履行订单时,不需要 Alice 的签名。 DEX 无需与 Alice 进行任何进一步交互即可执行交换。 换句话说,DEX能够构建满足脚本条件的支出交易。 由于请求交换一对代币,爱丽丝在她的地址收到了代币。
结论
验证器脚本通常非常简单,并且只能处理有限的信息。 他们基本上只是决定是否可以从脚本地址花费资金。 一个简单的条件可能就足够了。 大多数应用程序逻辑应该位于链外部分。 验证脚本的执行会消耗分布式网络的资源,这可能比使用服务器或用户本地计算机的资源更昂贵。