作者:时跃堂 陈曦 智能合约又称链码(Chaincode),是用计算机语言描述合约条款、交易的条件、交易的业务逻辑等,通过调用智能合约实现交易的自动执行和对账本数据的操作。一个BSN应用可以部署多个链码,每个链码包含多个方法。 链码支持多种语言编写,包括Nodejs、golang、java。每个链码程序都必须实现Chaincode接口,链码包含:Init ,Invoke ,Query三个基本操作: ?Init :链码初始化的方法,在链码实例化或者升级的时候调用一次,以便链码可以执行任何必要的初始化,包括应用程序状态的初始化。 ?Invoke :接收和处理链下业务系统调用事务处理提案,其参数包含调用的链码程序中函数的名称和具体业务处理数据参数。即在Invoke中根据不同的方法参数调用其他分支处理响应的业务。Invoke可以简单的理解为链码方法的入口。 ?Query:提供查询链码数据的方法,该方法只作为查询使用,不提供操作链上数据的操作。可在Query操作时调用,亦可在Invoke方法中作为某些方法的分支被调用。该方法可以不实现。 本文主要介绍用户如何用Nodejs语言开发智能合约,以及在BSN中对智能合约开发的一些规范和建议。 如何开发智能合约 编写链码,关键是实现 Init 与 Invoke 两个方法。 ?Init:在链码实例化或者升级的时候调用一次, 完成初始化数据的工作。建议处理一些简单的处理,禁止使用该方法去初始化大量基础数据,如果有需要初始化的数据,建议在Invoke中处理。 ?Invoke:更新或查询提案事务中的帐本数据状态时,Invoke 方法被调用。因此响应调用或查询的业务实现逻辑都需要在此方法中编写实现。 在实际开发中,开发人员可以自定义一个结构体,然后重写 Chaincode接口的 Init 与 Invoke方法,并将两个方法指定为自定义结构体的成员方法。两个方法被调用时都会传入 一个存根对象(stub),链码可以利用该对象来获取请求的相关信息,例如调用 者身份、目标通道、参数等等。下面具体说一下如何开发智能合约。 目录说明:main.js:程序入口;bsnchaincode:链码文件夹;models:数据转换包;utils通用工具包; chaincode.js 代码示例 base.js set方法示例 ?依赖包 "fabric-shim": "~1.4.0" fabric-shim 包为链码提供了 API 用来访问/操作数据状态、事务上下文和调用其他链代码; ?链码方法介绍 ◆getFunctionAndParameters() 返回一个方法调用描述对象,第一个值调用的链码方法名,第二个值要传入目标方法的参数对象。 ◆getArgs() 从链码调用请求中返回参数字符串数组,等价于getStringArgs()。 ◆getStringArgs() 返回链码调用请求中的参数字符串数组。 ◆getTxID() 返回当前链码调用请求的交易ID。交易ID在通道范围内唯一标识一个交易。 ◆getChannelID() 返回链码处理提议的通道ID ◆invokeChaincode(chaincodeName, args, channel) 跨链提交链码: 如果被调用的链码在同一个通道,那么它只是简单地将被调用链码的读写集添加到被调用交易中。如果被调用的链码处于不同的通道,那么只会返回响应结果,在被调用链码中的putState调用不会影响账本的状态。 调用参数: chaincodeName:要调用的链码名称。 args:调用参数列表,字节数组的数组。 channel:要调用的链码所在通道名称。 ◆getState(key) 获取指定状态变量键的当前值。 ●参数 key: 要提取当前值的状态变量键。 ◆putState(key, value) 更新状态库中指定的状态变量键。如果变量已经存在,那么覆盖已有的值。 ●参数: key:要更新的状态键,字符串。 value:状态变量的新值,字节数组或字符串。 ◆deleteState(key) 从状态库中删除指定的状态变量键。 ●参数 key:要从状态库中删除的状态变量键 ◆getStateByRange(startKey, endKey) 返回一个账本状态键的迭代器,可用来 遍历在起始键和结束键之间的所有状态键,返回结果按词典顺序排列。当使用完毕后,调用返回的StateQueryIterator迭代器对象的close()方法关闭迭代器。 ●参数 startKey:起始键。 endKey:结束键。 ◆getStateByPartialCompositeKey(objectType, keys) 基于给定的部分复合键查询账本状态。 该方法返回的迭代器可用于遍历查询结果集。 当使用完毕后,调用返回的StateQueryIterator迭代器的close()方法关闭迭代器。 ●参数 objectType:结果键前缀。 keys:用于拼接复合键值的属性值列表,字符串数组。 ◆createCompositeKey(objectType, attributes) 通过组合对象类别和给定的属性创建一个组合键。对象类别及属性都必须是 有效的utf8字符串,并且不能包含U+0000 (空字节) 和 U+10FFFF (最大未分配代码点)。 结果组合键可以用作PushState()调用中的参数键。 ●参数 objectType:组合键前缀。 attributes:要拼接到组合键的各属性值,string数组。 ◆splitCompositeKey(compositeKey) 将组合键分离,返回数据1:组合键前缀;返回数据2:要拼接到组合键的各属性值,string数组;返回数据3:错误信息。 ●参数 compositeKey:组合键。 ◆getQueryResult(query) 在状态数据库上执行一个rich查询。该方法 仅在支持rich查询的状态数据库上有效,例如CouchDB。查询语句采用 底层状态数据库的语法。返回的StateQueryIterator可用于遍历查询 结果集。 ●参数 query:查询语句。 ◆getQueryResultWithPagination(query, pageSize, bookmark) 在状态数据库上执行一个rich查询, 该方法仅在支持rich查询的状态数据库上有效,例如CouchDB。查询语法依据 所采用的底层数据库。 ●参数 query:查询语句,字符串。 pageSize:分页大小,整数。 bookmark:书签,字符串。 ◆getHistoryForKey(key) 返回指定状态键的值历史记录。每次历史更新,都记录有 当时的值和关联的交易id、时间戳。时间戳取自交易提议头。 ●参数 key:状态键。 ◆getCreator() 返回链码调用者身份。 ◆getTxTimestamp() 返回交易创建时的时间戳,值取自交易的ChannelHeader部分, 因此它表示的是客户端的时间戳,并且在所有的背书服务节点上有相同的值。 ◆setEvent(name, payload) 设置链码事件,事件只有在Invoke中有效 ●参数 name:时间名称 payload:通知内容。 ◆getTransient() 返回交易中带有的一些临时信息,可以存放一些应用相关的保密信息,这些信息不会被写到账本中。 链码开发规范 ?所有链码方法参数信息必须校验。 ●校验参数个数。 ●校验参数值(长度、类型等等,根据业务场景定义)。 ?Init方法不能大量初始化数据。 需要初始化数据,单独写方法进行处理。 ?引用第三方包,需要使用npm管理。 使用Nodejs依赖包管理工具:npm。 安装: 新版的nodejs已经集成了npm,安装了Nodejs同时就安装了npm,可以通过输入 "npm -v" 来测试是否成功安装。如果你安装的是旧版本的 npm,可以通过 npm 命令来升级,命令如下: npm install npm -g 使用: ●进入项目目录 ●安装所需依赖:npm install package.json ●项目目录下自动生成 node_modules 文件 ?main函数,必须在项目中所有链码的上级或同级。 ?发布服务时,链码包打包时进入项目根目录进行打包,格式为.zip。 ?发布服务时,添加链码包的链码名称要与项目名称相同。 链码开发建议 ?关于key的定义 ●描述 现阶段所有业务数据都存在于一个账本数据库中,并存储方式是以key-value的形式存储,可能存在不同业务的key值相同的情况。 ●解决方案 在不同的业务key值添加业务前缀 ●例子 如用户和角色他们的标识相同,如果以标识作为key存储时,后者保存会覆盖前者信息;但是如果用户:user_用户标识,角色:role_角色标识这样存储就会避免这个问题 ?关于根据key值模糊查询 ●描述 根据key查询同一个业务数据时。 ●解决方案 查询语句使用正则表达式进行查询的,{\"_id\":{\"$regex\":\"ChargeUnit_.*\"}修改为{\"_id\":{\"$regex\":\"^ChargeUnit_.*\"};前者检索key中只要含有“ChargeUnit”的数据,后者检索key以“ChargeUnit”开头的数据。 ●例子 正则表达式:特殊符号转义:例:()[] {} . \ ?关于跨链调用(invokeChaincode) ●描述 由于BSN是提供的是公用的Fabric环境,为了保障通道ID(channelId)与链码名称(chaincodeName)的唯一性,链码部署完成后,用户才能拿到通道ID(channelId)与链码名称(chaincodeName)。那么链码中该如何得到这些值? ●解决方案 需要跨链调用的链码,需将channelId和chaincodeName作为业务参数传递。 ●例子 —- 编译者/作者:区块链服务网络 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
使用BSN开发区块链应用智能合约-Nodejs篇
2020-03-03 区块链服务网络 来源:区块链网络
LOADING...
相关阅读:
- bitFlyer推出区块链房屋租赁2020-10-31
- 波场链智能合约2020-10-31
- CIBS项目评级(A)——去中心化金融的基本架构DeFi的开放性趋势2020-10-31
- 最新发布的Cardano路线图设定Goguen将于2021年3月发布2020-10-31
- DeFi开发人员Andre Cronje的新项目在12小时内飙升了15,000%2020-10-31