编写你的第一个hyperledger fabric network程序
Posted Share_Boy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编写你的第一个hyperledger fabric network程序相关的知识,希望对你有一定的参考价值。
Writing Your First Application编写你的第一个程序。 本文档的目标是使阅读本文档的人能基于HyperLedger Fabric Network编写自己的第一个程序。 在这个程序里,我们提供最基本的功能: 用户能在账本中查询一条数据或者用户更新账本中的一条数据。
我们的程序是使用javascript编写,运行在NODEJS平台上。 此文档将会指导你通过三步去编写你的第一个程序。 第一步:
运行一个HyperLedger Fabric BlockChain Network。
我们需要一些基础组件去查询和更新账本。 一个通道节点(peer node), 排序节点(Ordering node)和认证授权中心(Certificate Authority )--作为我们的网络支撑。
我们还需要一个CLI容器来执行管理命令。 一个单独的脚本将会下载和运行这个测试网络。
第二步:
学习我们的程序将要使用的智能合约的参数。
我们的智能合约允许我们使用多种不同的方法去操作账本(Ledger)。 例如: 我们可以读取数据的整体或者是一部分(we can
read data holistically or on a more granular level.)。
第三步:
部署程序去查询和更新数据。
我们提供两种简单的程序 ---- 一个查询账本,另一个更新账本。 我们的程序将会使用超级账本的SDK API 去影响 HyperLedger.
在完成本教程之后,你应该对如何使用HyperLedger Fabric Network提供的NODEJS的API去编写自己的程序有一个基本的理解。
首先,让我们运行我们的HyperLedger。 Getting a Test Network
获取一个测试网络。 确保你已经安装了所有必须的依赖软件。
首先决定你要克隆Fabric-samples到哪一个目录,然后运行克隆脚本,随后进入fabric的子目录。
git clone https://github.com/hyperledger/fabric-samples.git
cd fabric-samples/fabcar
这个子目录(fabcar)包含脚本和程序代码可以运行简单的fabric程序。 运行ls命令你将会看到如下内容:
chaincode invoke.js network package.json query.js startFabric.sh
现在我们运行startFabric.sh脚本去运行网络。
./startFabric.sh
注意: 这个脚本将会下载HyperLedger Fabric Docker 镜像,所以它将会运行一会儿。
为了简洁起见, 我们不会深挖这个命令运行时发生了什么, 这里给出了一个大概内容。
启动一个通道节点(peer node), 排序节点(Ordering node)和认证授权中心(Certificate Authority )和一个CLI 容器。
创建一个通道并且将启动的节点加入通道。
在启动的节点上安装智能合约并且安装启动chainCode。
调用initLedger添加10条数据到账本中。
注意: 这些操作通常有管理员来完成。 本脚本使用CLI执行脚本完成操作。同时SDK也能很好的支持这些操作。
执行docker ps 命令去显示startFabric.sh脚本运行的进程。 你可以通过Building Your First Network来学习更多细节和关于这些机器的操作。
在这里我们把注意力放在程序这里。下面的图片简单展示了程序是如何访问HyperLedger Fabric Netowrk。
好吧, 现在你有了一个简单的网络环境和一些能与这个环境交互的代码,让我们将这两部分组合到一起吧。 How Applications Interact with the Network
如何使用程序访问Fabric 程序使用APIs去访问智能合约(chaincode)。这些智能合约在网络的主机上以名字和版本作为唯一标识。例如: 我们的智能合约的标题是: dev-peer0.org.example.com-fabcar-1.0 ----名称的部分是fabcar, 版本的部分是1.0,运行的peer的名称是dev-peer0.org.example.com.
API可以通过软件开发工具包(SDK)来访问。这次练习中我们将使用Hyper-ledger Fabric Node SDK来开发。当然你也可以使用JAVA SDK或者CLI来进行练习。
Querying the Ledger
查询账本 查询是从账本中读取数据。你可以查询数据的单个值或者多个值。如果账本写入的时候使用的是像JSON一样的富文本 ---- 执行复杂的搜索。
正如我们之前说的,我们的网络中有一个运行Chaincode容器和一个账本,其中有10条不同的数据。 我们还需要一些简单的JAVASCRIPT脚本 --
-- 在fabcar目录下可以去查询账本下的块的信息。
在我们了解程序如何运行之前,我们需要为我们的程序安装依赖的SDK模块,在你的fabcar目录下,运行如下命令:npm install。
注意: 你将从fabcar目录发出所有后续的命令。
现在我们可以运行我们的JAVASCRIPT程序了。 首先,让我们运行query.js程序列出账本中的所有区块的信息。 一个函数将会查询出所有的区块,
queryAllCars, 预加载到我们的程序中, 我们可以简单的运行这个脚本: node query.js
它将会返回如下内容:
Query result count = 1
Response is ["Key":"CAR0", "Record":"colour":"blue","make":"Toyota","model":"Prius
˓→ ","owner":"Tomoko",
"Key":"CAR1", "Record":"colour":"red","make":"Ford","model":"Mustang","owner":
˓→ "Brad",
"Key":"CAR2", "Record":"colour":"green","make":"Hyundai","model":"Tucson","owner":
˓→ "Jin Soo",
"Key":"CAR3", "Record":"colour":"yellow","make":"Volkswagen","model":"Passat","owner
˓→ ":"Max",
"Key":"CAR4", "Record":"colour":"black","make":"Tesla","model":"S","owner":"Adriana
˓→ ",
"Key":"CAR5", "Record":"colour":"purple","make":"Peugeot","model":"205","owner":
˓→ "Michel",
"Key":"CAR6", "Record":"colour":"white","make":"Chery","model":"S22L","owner":"Aarav",
"Key":"CAR7", "Record":"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari
˓→ ",
"Key":"CAR8", "Record":"colour":"indigo","make":"Tata","model":"Nano","owner":
˓→ "Valeria",
"Key":"CAR9", "Record":"colour":"brown","make":"Holden","model":"Barina","owner":
˓→ "Shotaro"]
这里有10条数据。 一辆属于adriana黑色(black)的特斯拉(Tesla)Mode S,一辆红色(red)的福特(ford)野马(mustang)是Brad 和其他的。
账本是基于键值(key/value)来实现,而且我们实现键(key)的CAR0 到CAR9。 这一点将会变的非常重要。
让我们看看程序是如何实现的吧。 使用编辑器打开程序query.js。
程序的初始化章节定义了主要的变量例如: (智能合约)chaincode ID, 通道名称(channel name)和 访问端口。
var options =
wallet_path : path.join(__dirname, './network/creds'),
user_id: 'PeerAdmin',
channel_id: 'mychannel',
chaincode_id: 'fabcar',
network_url: 'grpc://localhost:7051',
这一部分使我们构造查询的语句:
// queryCar - requires 1 argument, ex: args: ['CAR4'],
// queryAllCars - requires no arguments , ex: args: [''],
const request =
chaincodeId: options.chaincode_id,
txId: transaction_id,
fcn: 'queryAllCars',
args: ['']
我们将chaincode_id定义为fabcar,允许我们到达这个智能合约。 然后调用智能合约中定义的queryAllCars函数。
当我们运行 node query.js命令的时候,这个函数被调用来查询账本。然而这并不是我们唯一能调用的函数。
我们来看下其他的代码。进入chaincode子目录然后打开fabcar.go文件, 你将会看到被声明为 -- initLedger,
queryAllCars, createCar 和 changeCarOwner等函数。 让我们在queryAllCars中去了解如何操作账本。
func (s
* SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response
˓→
startKey := "CAR0"
endKey := "CAR999"
resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) 这个函数使用了shim的接口函数GetStateByRange通过两个区间函数startKey和endKey来返回之间的账本数据。
我们分别定义了CAR0到CAR999的键。因此, 如果键被正确使用的话,我们可以存储1000辆车,而且queryAllCars会列出每一辆车。
下面的图片展示了程序如何智能合约(chaincode)的不同的函数。
在上图中我们可以看到我们的queryAllCars, 还有一个createCar。createCar函数允许我们更新账本。createCar最终将一个新的块添加到区块链中。
但是首先我们先做另一个查询。
回到我们的query.js程序,编辑query.js的构造请求去查询一个特殊的车辆。 我们将会修改queryAllCars为queryCar,并且指定一个Key作为参数(这里我们
使用CAR4)。我们编辑query.js成下面这样。
const request =
chaincodeId: options.chaincode_id,
txId: transaction_id,
fcn: 'queryCar',
args: ['CAR4']
保存程序并返回fabcar目录下。然后再次运行程序:
node query.js
你应该看到如下的数据:
"colour":"black","make":"Tesla","model":"S","owner":"Adriana"
现在我们已经从查询所有到查询指定的一条。 使用queryCar函数,我们可以查询任意Key获取其映射的数据。
非常好, 现在你应该能使用智能合约(chaincode)的基础函数用来查询并且可以传递查询参数了。
Updating the Ledger
更新账本。
现在我们已经做过了账本查询并且修改了一点点代码, 我们已经做好了更新账本的准本。
我们可以对账本做很多更新,但是前提是我们得有数据来更新。所以首先我们来创建一辆车(一条数据)。
账本更新从一个事务的生成开始。 就像查询一样, 一个请求需要一个唯一的channelID, 调用函数和智能合约才能被创建,并且需要将这些数据传递。
然后程序将调用channel.SendTransactionProposal API 将事务发送给peer获得建议(endorsement)。
Fabric 返回一个请求响应,应用程序使用它来创建和提交一个事务请求。这个请求通过调用channel.sendTransaction API 发送到 排序服务
(The Ordering Service)。排序服务(The Ordering Service)将此事务绑定到一个块中, 然后将该块发送给所有对等的节点上去认证
(我们的例子中仅有一个节点)。
最终程序会调用eh.setPeerAddr去链接节点的事件监听端口并且调用eh.registerTxEvent去注册时间关联到事务的ID。这个API允许程序去获取
交易的流程(成功(successfully), committed(已提交)或者未成功(unsuccessful))。把他想象成为一个通知机制。
注意: 我们不会深入的了解事务的生命周期。你可以查阅事务流程(Transaction Flow)文档来了解如何提交事务给账本的底层细节。
我们最初的调用是建立一项新的资产(也就是一辆车)。我们有一个单独的程序 - invoke.js -我们将使用这些事务。就像查询(query.js)一样,
我们使用编辑工具打开invoke.js 并找到构造调用API的代码:
// createCar - requires 5 args, ex: args: ['CAR11', 'Honda', 'Accord', 'Black', 'Tom
˓→ '],
// changeCarOwner - requires 2 args , ex: args: ['CAR10', 'Barry'],
// send proposal to endorser
var request =
targets: targets,
chaincodeId: options.chaincode_id,
fcn: '',
args: [''],
chainId: options.channel_id,
txId: tx_id
你将会看到我们调用两个函数 createCar和changeCarOwner. 让我们创建一辆红色的Chevy Volt,并且将他的拥有者设置为 Nick. 我们的账本的唯一标识的最顶端
是CAR9, 所以我们将用CAR10. 更改代码块像下面这样:
var request =
targets: targets,
chaincodeId: options.chaincode_id,
fcn: 'createCar',
args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'],
chainId: options.channel_id,
txId: tx_id
保存并运行它:
node invoke.js
你的控制台终将会输出响应和事务ID。当我们看到这条信息的时候:
The transaction has been committed on peer localhost:7053
节点会发出事件通知,我们通过eh.registerTxEvent去接受通知。所以现在如果我们重复去运行query.js的话我们是可以查询到CAR10的。
我们应该会看到如下结果:
Response is "colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"
最后让我们调用我们最后一个函数: changeCarOwner。 Nick是非常慷慨大方的,它准备将他的车送个一个叫Barry的朋友。所以我们简单
的修改一下我们的invoke.js
var request =
targets: targets
chaincodeId: options.chaincode_id,
fcn: 'changeCarOwner',
args: ['CAR10', 'Barry'],
chainId: options.channel_id,
txId: tx_id
再次运行程序 - node invoke.js - 然后再运行query.js。 我们将看到CAR10, 我们看到的是修改后的:
Response is "colour":"Red","make":"Chevy","model":"Volt","owner":"Barry"
Additional Resources
附加资源
Hyperledger Fabric Node SDK repo 中有更多的优秀的资源和实例代码。当然你也可以咨询Hyperledger FAbric的社区。
以上是关于编写你的第一个hyperledger fabric network程序的主要内容,如果未能解决你的问题,请参考以下文章
用Java为Hyperledger Fabric(超级账本)编写区块链智能合约链代码
Hyperledger Fabric 开发环境搭建&构建Fabric
Hyperledger Fabric 智能合约实战 整体步骤