区块链研究实验室|使用Node.js开发Hyperledger Fabric Chaincode

  • 时间:
  • 浏览:48
  • 来源:区块链技术网

Hyperledger Fabric术语中的Chaincode是什么?

在Hyperledger Fabric中,Chaincode是在网络peer上运行的一段代码,用于实现应用程序如何与分类帐交互的业务逻辑。提出交易时,它会触发Chaincode,该Chaincode决定应将哪种状态更改应用于分类帐。因此为了在Hyperledger Fabric上开发去中心化的应用程序,必须编写称为Chaincode的应用程序逻辑。

Chaincode可以使用Go,Nodejs,Java编写。其他两种语言相比,Node.js是一种更容易理解和使用的语言。由于Node.js文档中可用的信息非常少,但编写和部署Node.js Chaincode并不困难。因此我决定编写一些Node.js Chaincode的概念,并逐步编写和部署简单的Chaincode。

Hyperledger Fabric数据库

在深入研究Chaincode之前,首先让我们看一下Hyperledger Fabric Network中数据的存储位置。Hyperledger Fabric使用键值数据库存储其状态。默认情况下,Fabric使用LevelDB。该数据库保存可以使用其键查询的特定对象的二进制数据。与传统的数据库不同,区块链数据库位于网络的每个peer上。因此它被称为分散网络。

除了LevelDB,还有另一个用于Hyperledger Fabric的数据库称为CouchDB。CouchDB是可选的替代外部可插拔状态数据库。与LevelDB键值存储一样,CouchDB可以存储以链码建模的任何二进制数据。但作为JSON文档存储,当将Chaincode值(例如资产)建模为JSON数据时,CouchDB还可以对Chaincode数据进行丰富的查询。

 Chaincode组件

1.fabric-contract-api:

用于实现智能合约的高级合约API(作为npm模块提供)

2.fabric-shim:

用于实现智能合约的低级合约API(作为npm模块提供)

我们可以将fabric-shim视为fabric-contract-api的递减版本。对新版本的fabric使用高级API是一个好习惯。但是fabric-contract-api可以完成shim可以做的所有事情。当然不止如此。

3.stub:

它是fabric-contract-api中的接口,用于访问和修改分类帐(数据库状态)。因此它是主要数据Chaincode接口,用于在分类账上读写数据,我们如何读写数据?让我们看一下Stub界面中的一些常用方法

Stub接口中的常用方法

1.getState(k):

众所周知,Hyperledger Fabric数据库以键值对的形式存储数据。

此方法从分类帐读取数据。它以输入“ k”作为键,并返回与键“ k”关联的二进制值。

2.putState(k,v):

此方法将数据写入分类帐。它以“ k”为键,“ v”为值。明确地说,假设我们想将Alice的年龄存储到分类帐中,我们可以将Alice作为键,并将AGE作为值。

3.deleteState(k):

此方法从分类账中删除关联密钥“ k”的值。

4.getStateByRange(k1,k9):

此方法在分类帐中的一组键上返回范围迭代器。它将迭代startKey(k1)和endKey(k9)并返回这两个键之间的所有键值。这类似于javascript中的for循环。假设如果我们已经按键k1,k2,k3…k99的顺序存储了一些用户数据,则可以使用此方法简单地获取所有这些值的状态。

5.getTxID():

此方法返回被调用事务的事务ID。交易ID对于链上的每个交易都是唯一的。因此交易ID在跟踪交易中起着至关重要的作用。

6.getTxTimestamp():

此方法返回创建事务时的时间戳。这是从交易ChannelHeader获取的,因此它将指示客户的时间戳,并且在所有背书人中都具有相同的值。

编写您的第一个Chaincode

您已经了解了在node.js中编写链码的一些先决条件。因此就目前而言,您可能会非常兴奋地编写您的第一个chaincode。

由于我们要用Nodejs编写Chaincode,因此我们首先需要创建传统的npm东西,例如package.json和index.js。如果您不知道此package.json。

列出您的项目所依赖的软件包

使用语义版本控制规则指定项目可以使用的软件包的版本

使您的构建具有可复制性,因此更易于与其他开发人员共享.

简而言之,我们的Chaincode取决于fabric-contract-api和fabric-shim模块。我们在package.json中提到了这些软件包和版本。

我们还将添加fabric-chaincode-node start作为我们的启动脚本,这是在peer节点上安装chaincode所需的。

这是我们的package.json:

{
    "name""Test-Chaincode",
    "version""1.0.0",
    "description""my first exciting node.js chaincode on Hyperledger-fabric",
    "main""index.js",
    "engines": {
        "node"">=8",
        "npm"">=5"
    },
    "scripts": {
        "lint""eslint .",
        "pretest""npm run lint",
        "test""nyc mocha --recursive",
        "start""fabric-chaincode-node start"
    },
    "engineStrict"true,
    "author""Hyperledger",
    "license""Apache-2.0",
    "dependencies": {
        "fabric-contract-api""~1.4.0",
        "fabric-shim""~1.4.0"
    },
    "devDependencies": {
        "chai""^4.1.2",
        "eslint""^4.19.1",
        "mocha""^5.2.0",
        "nyc""^12.0.2",
        "sinon""^6.0.0",
        "sinon-chai""^3.2.0"
    },
    "nyc": {
        "exclude": [
            "coverage/**",
            "test/**"
        ],
        "reporter": [
            "text-summary",
            "html"
        ],
        "all"true,
        "check-coverage"true,
        "statements"100,
        "branches"100,
        "functions"100,
        "lines"100
    }
}

如果您可以仔细观察代码,则有一行“ main”:“ index.js”。这意味着什么—在启动时(安装chaincode期间),npm模块用于检查index.js并在peer节点上安装提到的合约。”因此我们的index.js包含作为模块导出的合约。

这是我们的index.js文件:

'use strict';
const testContract = require(’./logic’);
module.exports.contracts = [ testContract ];

智能合约:

我们的业务逻辑是什么?

添加,检索和删除学生标记。

1.添加标记涉及将数据写入分类帐。因此我们将从chaincode的stub接口使用putState(k,v)方法。

2.检索标记涉及从分类帐读取数据。因此我们需要使用getState(k)方法。

3.删除标记涉及删除数据。因此我们需要使用deleteState(k)方法。

chaincode首先从fabric-contract-api模块引入作用域密钥类Contract。此类将用于编写逻辑,所有chaincode函数都应使用This库类。

const { Contract}=require(’fabric-contract-api’);
 class testContract extends Contract {
//Functions go here
}

添加标记:

我们将创建一个JavaScript对象来存储每个学科中学生的成绩,并将该对象存储为一个值,并将StudentId存储为一个键。通过服务器将数据发送到数据库时,数据必须是字符串。因此我们需要使用JSON.stringify()方法将此标记对象转换为字符串,并应用缓冲区以二进制数据的形式发送到数据库。

async addMarks(ctx,studentId,subject1,subject2,subject3
    let marks={
     subj1:subject1, 
     subj2:subject2,
     subj3:subject3 
     }; 
await  ctx.stub.putState(studentId,Buffer.from(JSON.stringify(marks))); 
console.log(’Student Marks added To the ledger Succesfully..’); 
}

删除标记

async deleteMarks(ctx,studentId{
 await ctx.stub.deleteState(studentId); 
console.log(’Student Marks deleted from the ledger Succesfully..’);
    }

查询学生成绩:

由于我们在先前的addMarks()函数中将值以缓冲区的形式放置。一旦查询,它将返回buffer。因此我们需要将缓冲区转换为字符串并将其解析为原始javascript对象。

async queryMarks(ctx,studentId){

     let marksAsBytes = await ctx.stub.getState(studentId); 
     if (!marksAsBytes || marksAsBytes.toString().length <= 0) { 
       throw new Error(’Student with this Id does not exist: '); 
         } 
    let marks=JSON.parse(marksAsBytes.toString()); 
    return JSON.stringify(marks); 
   }

最终版智能合约代码

您可以在此处找到完整的智能合约。https://gist.github.com/Salmandabbakuti/fb25d0429359c6d77ab64d097c5b588c

'use strict';


const { Contract} = require('fabric-contract-api');


class testContract extends Contract {


async queryMarks(ctx,studentId) {


    let marksAsBytes = await ctx.stub.getState(studentId); 


    if (!marksAsBytes || marksAsBytes.toString().length <= 0) {


      throw new Error('Student with this Id does not exist: ');


       }


      let marks=JSON.parse(marksAsBytes.toString());
      return JSON.stringify(marks);


  }


async addMarks(ctx,studentId,subject1,subject2,subject3) {
   let marks={


       subj1:subject1,


       subj2:subject2,


       subj3:subject3


       };


    await ctx.stub.putState(studentId,Buffer.from(JSON.stringify(marks))); 


    console.log('Student Marks added To the ledger Succesfully..');
  }


async deleteMarks(ctx,studentId) {
    await ctx.stub.deleteState(studentId); 
    console.log('Student Marks deleted from the ledger Succesfully..');
    }
}


module.exports=testContract;

为了安装和测试此智能合约,我将使用包含单个peer的基本网络。在这个网络上,我们将安装名为mycc的Node.js的chaincode到peer0.org1.example.com上,并在通道mychannel上实例化它。然后我们可以调用这些chaincode函数。确保在您的设置中安装了docker。为了简单起见,我已经将chaincode文件(logic.js,index.js,package.json)安装在chaincode/newcc目录中。

首先,我们需要启动网络并创建通道。

git clone https://github.com/Salmandabbakuti/hlf-chaincodeTest.git
cd hlf-chaincodeTest/basic-network
./start.sh

等待片刻。建立网络将需要一段时间。如果遇到任何权限错误,只需在root用户权限下运行就行。一旦我们的具有单个peer的网络建立并运行,我们就可以安装chaincode。

为了安装和调用chaincode,我们可以使用Peer的CLI容器。输入CLI容器

docker exec -it cli bash

安装和实例化Chaincode

peer chaincode install -n mycc -v 1.0 -p "/opt/gopath/src/github.com/newcc" -l "node"
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -l "node" -v 1.0 -c '{"Args":[]}'

增加学生标志

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"addMarks","Args":["Alice","68","84","89"]}'

查询学生“Alice”的标志

peer chaincode query -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"queryMarks","Args":["Alice"]}'

从Ledger删除“Alice”标志

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"deleteMarks","Args":["Alice"]}'

上面的脚本将从账本中删除密钥“ Alice”和相关数据。如果再次查询Alice的标记,则会收到一条错误消息,提示“ studentId不存在”。

我还制作了一个自动化脚本,用于在客户端目录中安装和测试此chaincode。请按照以下步骤进行快速演示

首先,退出CLI容器并在客户端目录中运行脚本

exit # exits from CLI docker container if you're in
cd ..
cd client  #change your directory to client
chmod a+x start.sh
./start.sh  #Automated script for testing

您也可以使用client / start.sh文件中定义的脚本手动调用chaincode函数。

结论

我们在这里演示了什么是Chaincode,chaincode的stub接口中的方法,chaincode的部署结构以及编写chaincode和在网络上进行部署的难易程度。希望本文能以某种方式帮助您开始编写chaincode并在网络上进行部署。

猜你喜欢

区块链红利吃饱后,这个巨头又想"征服"元宇宙?

据12月26日消息,百度与英伟达(NVIDIA)已达成协议,双方合作共建AI元宇宙。另外,在今日举行的百度AI开发者大会上,英伟达全球副总裁暨亚太区总裁 Raymond Teh将受邀出席,并发表主题演讲。

2021-12-27

2021年,区块链股权融资发生了怎么样的演变

过去一年,区块链行业融资井喷,在科技领域中独树一帜,A16z、红杉、老虎基金等等这些顶级机构在 2021 年的区块链行业肆意驰骋,在 DeFi、NFT、Metaverse 等领域扶持了一众创业项目。

2021-12-23

两个元宇宙的世界观,以及和区块链的关系

“元宇宙”这个名词音好听但义很难传达准确,想要更准确地理解义,取名为平行宇宙、竞争宇宙、山寨宇宙,更好。对应的,我们现在肉身所处的宇宙,我们称之为“肉身宇宙”。

2021-12-22

Alien Worlds(外星世界)区块链打金挖矿指南

Alien Worlds(外星世界)是一款4月就开始的游戏,10月27日又上线了全新的任务(Missions)游戏模式; 在WAX用户量排名中Alien Worlds(外星世界)一直排在前三,说明现在存量工作室还有很多;

2021-12-17

DeHorizon(地平线)区块链打金教程

今天我们就解析在一款社交主题游戏 — DeHorizon

2021-12-17