链码安装和实例化之后就可以调用chaincode执行交易,下面分析简单的账户转账操作是如何完成的。

源码分析

1.首先看app.js的路由函数

app.post('/channels/:channelName/chaincodes/:chaincodeName', async function(req, res) {
var peers = req.body.peers;
var chaincodeName = req.params.chaincodeName;
var channelName = req.params.channelName;
var fcn = req.body.fcn;
var args = req.body.args;
// 此处省略了参数校验
let message = await invoke.invokeChaincode(peers, channelName, chaincodeName, fcn, args, req.username, req.orgname);
res.send(message);
});

2.接下来找到

var invokeChaincode = async function(peerNames, channelName, chaincodeName, fcn, args, username, org_name) {
var error_message = null;
var tx_id_string = null;
try {
var client = await helper.getClientForOrg(org_name, username); // 创建client对象
var channel = client.getChannel(channelName); // 创建channel对象
// 获取交易id:基于client对象上分配的用户身份(_userContext)
var tx_id = client.newTransactionID();
tx_id_string = tx_id.getTransactionID();
// 请求结构
var request = {
targets: peerNames,
chaincodeId: chaincodeName,
fcn: fcn,
args: args,
chainId: channelName,
txId: tx_id
};
// SDK根据request生成proposal,并调用sendPeersProposal()
// 将提案发送给背书节点,然后将返回的提案响应连同交易提案一起打包返回给client
let results = await channel.sendTransactionProposal(request); // 返回的交易提案和提案响应
var proposalResponses = results[0];
var proposal = results[1]; // 检查提案响应是否正确
var all_good = true;
for (var i in proposalResponses) {
let one_good = false;
if (proposalResponses && proposalResponses[i].response &&
proposalResponses[i].response.status === 200) {
one_good = true;
logger.info('invoke chaincode proposal was good');
} else {
logger.error('invoke chaincode proposal was bad');
}
all_good = all_good & one_good;
} if (all_good) {
var promises = [];
// 基于channel的事件中心
let event_hubs = channel.getChannelEventHubsForOrg();
#event_hubs.forEach((eh) => {
#let invokeEventPromise = new Promise((resolve, reject) => {
#let event_timeout = setTimeout(() => {
let message = 'REQUEST_TIMEOUT:' + eh.getPeerAddr();
logger.error(message);
eh.disconnect();
}, 3000);
// 注册交易事件监听,当交易被peer提交到账本中时可以得到反馈
#eh.registerTxEvent(tx_id_string, (tx, code, block_num) => {
clearTimeout(event_timeout);
}, (err) => {
clearTimeout(event_timeout);
logger.error(err);
reject(err);
},
{unregister: true, disconnect: true}
);
eh.connect();
});
promises.push(invokeEventPromise);
});
// 将txID,交易提案和提案响应打包成交易请求
var orderer_request = {
txId: tx_id,
proposalResponses: proposalResponses,
proposal: proposal
};
// 将交易请求发送给orderer节点,内部调用sendBroadcast(envelope)
var sendPromise = channel.sendTransaction(orderer_request);
promises.push(sendPromise);
let results = await Promise.all(promises); let response = results.pop();
if (response.status === 'SUCCESS') {
logger.info('Successfully sent transaction to the orderer.');
} else {
error_message = util.format('Failed to order the transaction. Error code: %s',response.status);
logger.debug(error_message);
} } else {
error_message = util.format('Failed to send Proposal and receive all good ProposalResponse');
logger.debug(error_message);
}
} catch (error) {
logger.error('Failed to invoke due to error: ' + error.stack ? error.stack : error);
error_message = error.toString();
} if (!error_message) {
// 返回交易id
return tx_id_string;
} else {
let message = util.format('Failed to invoke chaincode. cause:%s',error_message);
logger.error(message);
throw new Error(message);
}
};

3.如果我们进行简单的转账交易 A->B,则需要调用链码中的move方法,代码如下:

func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// 两个账户A,B
var A, B string
// 账户的余额数
var Aval, Bval int
// 转移的数值
var X int
var err error if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 2 names and 1 value")
} A = args[0]
B = args[1] // 获取账户A的值
Avalbytes, err := stub.GetState(A)
if err != nil {
return shim.Error("Failed to get state")
}
if Avalbytes == nil {
return shim.Error("Entity not found")
}
Aval, _ = strconv.Atoi(string(Avalbytes))
// 获取账户B的值
Bvalbytes, err := stub.GetState(B)
if err != nil {
return shim.Error("Failed to get state")
}
if Bvalbytes == nil {
return shim.Error("Entity not found")
}
Bval, _ = strconv.Atoi(string(Bvalbytes)) X, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("Invalid transaction amount, expecting a integer value")
}
// 余额转移计算
Aval = Aval - X
Bval = Bval + X
logger.Infof("Aval = %d, Bval = %d\n", Aval, Bval) // 将改变后的值写入状态数据库中
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
} err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
} return shim.Success(nil);
}

测试

交易:

curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes/mycc \
-H "authorization: Bearer <Token>" \
-H "content-type: application/json" \
-d '{
"peers": ["peer0.org1.example.com","peer1.org1.example.com"],
"fcn":"move",
"args":["a","b","10"]
}'

结果:

Transacton ID is 970928c6acbae452a43cbc59e1cb9a558a09c4f354cda0025bd51dafcca3ad96

Hyperledger Fabric——balance transfer(五)执行交易的更多相关文章

  1. Hyperledger Fabric——balance transfer(一)启动示例

    Blacne transfer是Hyperledger fabric Node SDK的一个示例应用,主要使用了SDK中fabric-client 和 fabric-ca-client 模块中的API ...

  2. Hyperledger Fabric——balance transfer(六)查询

    balance transfer 提供了很多查询接口,包括链码查询,根据区块号查询区块数据,根据交易ID查询交易信息,查询链上的区块数,查询已安装或已实例化的链码,查询通道. 源码解析 1.调用链码查 ...

  3. Hyperledger Fabric——balance transfer(四)安装和实例化chaincode

    详细解析blance transfer示例的安装(install)和实例化(Instantiate)链码(chaincode)的过程.安装chaincode会根据本地的链码文件生成chaincode镜 ...

  4. Hyperledger Fabric——balance transfer(三)创建和加入Channel

    详细解析blance transfer示例的创建通道(Channel)和加入节点到通道的过程. 创建Channel 1.首先看app.js的路由函数 var createChannel = requi ...

  5. Hyperledger Fabric——balance transfer(二)注册用户

    详细分析blance transfer示例的用户注册(register)与登录(enroll)功能. 源码分析 1.首先分析项目根目录的app.js文件中关于用户注册和登录的路由函数.注意这里的tok ...

  6. Hyperledger fabric 1.3版本的安装部署(原创多机多Orderer部署

    首先,我们在安装前,要考虑一个问题 Hyperledger Fabric,通过指定的节点进行背书授权,才能完成交易的存储 延伸开来,就是为了实现容错.高并发.易扩展,需要zookeeper来选择排序引 ...

  7. 深入解析Hyperledger Fabric启动的全过程

    在这篇文章中,使用fabric-samples/first-network中的文件进行fabric网络(solo类型的网络)启动全过程的解析.如有错误欢迎批评指正. 至于Fabric网络的搭建这里不再 ...

  8. [Hyperledger] Fabric系统中 peer模块的 gossip服务详解

    最近一直在看fabric系统中的核心模块之一——peer模块.在看peer的配置文件core.yaml的信息时,对其中的gossip配置选项很感兴趣.看了一上午,还是不能明白这个选项到底什么意思呢?表 ...

  9. 浅析Hyperledger Fabric共识算法 摘自http://www.cocoachina.com/blockchain/20180829/24728.html

    Hyperledger Fabric共识算法 区块链系统是一个分布式架构,交易账本信息由各个节点管理,组成一个庞大的分布式账本.在分布式系统中,各个节点收到的交易信息的顺序可能存在差异(例如,网络延迟 ...

随机推荐

  1. MySQL5.7中InnoDB不可不知的新特性

    讲师介绍  赖铮 Oracle InnoDB团队 Principle Software Developer 曾任达梦.Teradata高级工程师,主要负责研发数据库执行引擎和存储引擎,十年以商数据库内 ...

  2. #Week7 Neural Networks : Learning

    一.Cost Function and Backpropagation 神经网络的损失函数: \[J(\Theta) = - \frac{1}{m} \sum_{i=1}^m \sum_{k=1}^K ...

  3. 内存淘汰机制——LRU与LFU

    内存淘汰机制之LRU与LFU LRU(Least Recently Used):淘汰 近期最不会访问的数据 LFU(Least Frequently Used):淘汰 最不经常使用(访问次数少) 所谓 ...

  4. PUBG 1V3 线段树扫描线

    PUBG 1V3 这个题目我觉得好难写啊. 感觉自己码力不太行啊. 题目大意是,给你n个人,n个人组成m个队伍,每个队伍最多4个人. 然后给你每一个人的位置队伍信息还有攻击范围. 问当一个队伍剩下一个 ...

  5. System类&StringBuilder类

    System类 1.currentTimeMillis()方法 作用:获取当前系统时间的毫秒值[注意:从现在到1970年1月1日 00:00:00] 2.arraycopy(...)方法 作用:复制数 ...

  6. python学习之组成字符串的两种方式

    第一种就是加法,比如 a ='张三' b = '李四' 那么print c =a+b 例如之前提到的 或者数值转换成字符串的 num  = 100 str(num) 其他参照表格中的转换即可 2.组成 ...

  7. 【HBase】底层原理

    目录 系统架构 表数据模型 物理存储 系统架构 在文章[HBase]基本介绍和基础架构中已经有简单介绍 Client -- 包含访问hbase的接口,client维护着一些cache来加快对hbase ...

  8. 【Hadoop离线基础总结】HDFS详细介绍

    HDFS详细介绍 分布式文件系统设计思路 概述 只有一台机器时的文件查找:hello.txt /export/servers/hello.txt 如果有多台机器时的文件查找:hello.txt nod ...

  9. [hdu3364]xor方程组消元

    题意:n个灯,m个开关,给定每个开关控制的灯,全部的灯初始时全部熄灭,开关按一下其所控制的灯的状态全部反转,开关最多只能按一下.问达到目标状态的方案数. 思路:xor方程组的模型. 1 2 3 4 5 ...

  10. 整理了最全的Python3数据类型转换方法,可以收藏当手册用

    本文基于python3.8版本,总结了各种数据类型直接的转换规则和方法.算是比较全了,可以收藏当手册来查. 概述 数据类型转换,指的是通过某种方法,将一个数据由原来的类型转换为另外一个类型.比如,我们 ...