FROM : https://docs.blockstack.org/core/smart/functions.html
Clarity包括用于创建用户定义函数的定义函数和本机函数。
定义和定义公共函数
定义只读功能
数据定义映射函数
列表操作和函数
Intra-contract调用
--- 阅读其他智能合约
定义和定义公共函数
通过define-public语句指定的函数是公共函数。没有这些名称的函数(简单定义语句)是私有函数。您可以通过clear -cli直接或从其他合约执行命令行运行合约的公共函数。可以使用clarity eval或clarity eval_raw命令通过命令行计算私有函数。
公共函数返回响应类型结果。如果函数返回ok类型,则认为函数调用是有效的,对区块链状态所做的任何更改都将实现。如果函数返回一个err类型,则认为它是无效的,并且对智能合约的状态没有影响。
例如,考虑两个函数foo.A 和 bar.B。函数foo.A调用bar.B,下表显示了可能的返回值组合产生的数据物化结果:
"" | FOO.A => | BAR.B | 数据影响结果 |
---|---|---|---|
函数返回值 | err | ok | 这两个函数都不会导致任何更改。 |
函数返回值 | ok | err | 改变foo.A是可能的,但是foo.B没有改变 |
定义常量和函数可以使用define语句简化代码。然而,这些都是纯语法的。如果定义不能内联,合约将被视为非法而被拒绝。这些定义也是私有的,因为以这种方式定义的函数只能由给定智能合约中定义的其他函数调用。
定义只读功能
通过define-read-only指定的函数是公共的。与定义公共创建的函数不同,使用定义只读创建的函数可以返回任何类型。然而,定义只读语句不能执行状态更改。由这些函数或由这些函数调用的函数修改合约状态的任何尝试都会导致错误。
数据定义映射函数
智能合约的数据空间中的数据存储在映射中。这些存储将一个类型元组与另一个类型元组关联起来(几乎与类型化键值存储类似)。与表数据结构相反,映射只将给定键与一个值关联。智能合约使用define-map函数定义数据映射的数据模式。
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
Clarity合约只能在智能合约的顶层调用define-map函数(类似于define)。这个函数接受映射的名称,以及键和值类型结构的定义。其中每一个都是(名称、类型)对的列表。类型可以是值'principal '、'integer '、'bool,也可以是一个哈希调用的输出,它是一个n字节固定长度的缓冲区。
为了支持在键和值中使用命名字段,Clarity允许使用函数(tuple ((key0 expr0) (key1 expr1)…)构造元组,例如:
(tuple (name "blockstack") (id 1337))
这允许动态地创建命名元组,这对于键和值本身是命名元组的数据映射非常有用。要访问给定元组的指定值,函数(get #name元组)将从元组返回该项。
如前所述,定义映射接口不允许在数据映射上使用范围查询和前缀查询。在智能合约函数中,您不能遍历整个映射。给定映射中的值是使用以下函数设置或获取的:
功能 | 描述
-|-|-
(fetch-entry map-name key-tuple) | 获取映射中与给定键关联的值,如果没有,则返回'null '。
(set-entry! map-name key-tuple value-tuple) | 设置数据映射中键元组的值。
(insert-entry! map-name key-tuple value-tuple) | 当且仅当条目不存在时,设置数据映射中键元组的值。
(delete-entry! map-name key-tuple)| 删除与给定映射的输入键关联的值。
数据映射使函数的推理更加容易。通过检查给定的函数定义,很清楚哪些映射将被修改,甚至在这些映射中,哪些键受给定调用的影响。数据映射接口保证映射操作的返回类型为固定长度;固定长度返回是对合约的运行时、成本和其他属性进行静态分析的必要条件。
列表操作和函数
列表可以是多维的。但是,请注意,运行时对类型化函数-参数和数据映射函数set-entry!根据多维列表的最大大小进行收费。
您可以使用用户定义的函数(即使用(define…)、(define-read-only ...)或(define-public…)或简单的本机函数(例如,+、-、not)调用filter map和fold函数。
合约内部调用
智能合约可以使用(contract-call!)函数从其他智能合约调用函数:
(contract-call! contract-name function-name arg0 arg1 ...)
此函数接受函数名和智能合约的名称作为输入。例如,要调用智能合约中的token-transfer函数,您可以使用:
(contract-call! tokens token-transfer burn-address name-price))
对于内部合约调用,不支持动态分派。当一个合约启动时,它所依赖的任何合约(调用)都必须存在。此外,智能合约的调用图中可能不存在周期。这可以防止递归(以及可重入错误)。调用图的静态分析检测到这些结构,然后它们被网络拒绝。
智能合约不得直接修改其他智能合约的数据;它可以读取存储在智能合约maps中的数据。此读取功能不会更改任何对Clarity机密性保证。智能合约中的所有数据本质上都是公开的,并且在任何情况下都可以通过查询底层数据库来读取。
从其他智能合约读取
要读取另一个合约的数据,请使用(fetch-contract-entry)函数。这与(fetch-entry)的行为相同,但是除了映射名之外,它还接受合约主体作为参数:
(fetch-contract-entry
'contract-name
'map-name
'key-tuple) ;; value tuple or none
例如,你可以这样做:
(fetch-contract-entry
names
name-map 1) ;;returns owner principal of name
与(合约调用)函数一样,映射名和合约主体参数必须是常量,在发布时指定。
最后,也是重要的一点,tx-sender变量在合约调用期间不会更改。这意味着,如果事务调用给定智能合约中的函数,该函数就能够代表您调用其他智能合约。这支持各种各样的应用程序,但是对于使用智能合约的用户来说,这也带来了一些危险。然而,静态分析保证了Clarity,允许客户预先知道给定的智能合约将调用哪些功能。好的客户端应该始终警告用户给定事务的任何潜在副作用。
网友评论