schema如何约束智能合约

Schema的文件格式

一个完整的schema由三部分组成组成:前缀列表、class、predicate

前缀列表

定义前缀,是为了更简短的描述一个资源。

如果没有前缀,那么需要采用完整的URI来描述资源,如描述Person_001实体:

<http://relationlabs.ai/entity/Person_001>

定义了前缀之后,我们描述同样的实体,只需要使用简短字符:

:Person_001

完整的前缀列表:

PREFIX : <http://relationlabs.ai/entity/>
PREFIX p: <http://relationlabs.ai/property/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

需要说明的是,rdf:xsd:rdfs: 是W3C提供的标准前缀,:p: 是 Relation Protocol中定义的前缀,分别用于表示实体和属性。

Class

Class是对实体的抽象,实体是class的具体实例。比如,我们定义一组Soul实体,那么可以首先定义一个Soul的class,使用rdf描述为:

:Soul a rdfs:Class . 

Predicate

Predicate也叫做属性,用于描述主语和宾语的关系。Predicate通常需要定义domainrange,比如:

p:following a rdf:Property ;
    rdfs:domain :Soul ;
    rdfs:range :Soul .

这段Schema定义了:

  • 谓词p:following是一个Property。

  • p:following:Soul的一个属性。

  • p:following对应的属性值是:Soul

Schema示例

我们以Name Service的需求为例:

  • 用户可以注册一个名称,即持有该域名

  • 用户对持有的域名设置解析,将域名解析到自己的地址上

想要实现上面场景,我们需要有Soul实体表示用户的地址,Namen实体表示名称。 还需要谓词来描述两者的关系,这里有两个状态需要描述,分别为hold表示地址持有域名,resolved表示地址已被该域名解析。

因此,我们在schema里需要有下面的class和predicate

  • Class

    • Soul

    • Name

  • Predicate

    • hold

    • resolved

    • profileURI

基于上面定义的class和predicate,我们组装成一个完整的schema:

PREFIX : <http://relationlabs.ai/entity/>
PREFIX p: <http://relationlabs.ai/property/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

###################
# class
###################
:Soul a rdfs:Class ;
    rdfs:label "Soul" ;
    rdfs:comment "A soul." .

:Name a rdfs:Class ;
    rdfs:label "Name" ;
    rdfs:comment "A name." .

###################
# predicate
###################
p:hold a rdf:Property ;
    rdfs:label "hold" ;
    rdfs:comment "A Soul to own a name." ;
    rdfs:domain :Soul ;
    rdfs:range :Name .

p:resolved a rdf:Property ;
    rdfs:label "resolved" ;
    rdfs:comment "The resolved name of a soul." ;
    rdfs:domain :Soul ;
    rdfs:range :Name .

p:profileURI a rdf:Property ;
    rdfs:label "profileURI" ;
    rdfs:comment "The profileURI of a soul." ;
    rdfs:domain :Soul ;
    rdfs:range xsd:string .

一个完整的持有域名的rdf示例:

:Soul_0x0000000000000000000000000000000000000011 p:hold :Name_example.

一个完整的被域名解析的rdf示例:

:Soul_0000000000000000000000000000000000000011 p:resolved :Name_resolve.

Schema对合约的约束

schema定义了RDF数据格式,作为合约数据模型的词汇表,需要合约内的数据模型定义跟schema保持一致(见图 4-2),这样合约生成的RDF数据才可以被Graph Indexer正确解析。

为此,我们在合约初始化时,需要传入参数schemaURI、className以及Predicate,将schema定义的内容转化成合约可读的代码结构。其中,schemaURI可以访问得到完整的schema内容;className为schema里定义的class名称;Predicate由schema里定义的predicate名称以及range类型组成。

下面是一个初始化合约传入的参数:

const name = 'Relation Name Service V1';
const symbol = 'SBT';
const baseURI = 'https://api.example.com/v1/';
const schemaURI = 'ar://PsqAxxDYdxfk4iYa4UpPam5vm8XaEyKco3rzYwZJ_4E';
const className = ["Domain"];
const predicates = [["hold", 3], ["resolved", 3], ["profileURI", 1]];
await semanticSBT.initialize(
        owner.address,
        name,
        symbol,
        baseURI,
        schemaURI,
        className,
        predicates);

可以看到, schemaURI是Arweave上的交易哈希,可以通过Arweave的网关直接访问schema完整内容。className以及predicates与schema里定义的class和predicate是一致的。

Last updated