本系列文章:
第一章:九析带你完爆 hyperledger fabric - 快速上手 basic-network 样例
第二章:九析带你完爆 hyperledger fabric - 快速搭建 GO 环境
第三章:九析带你完爆 hyperledger fabric - 快速上手 first-network 样例
第四章:九析带你完爆 hyperledger fabric - 系统逻辑架构篇
第五章:九析带你完爆 hyperledger fabirc - 网络节点介绍
第六章: 九析带你轻松完爆 hyperledger fabric - 区块和区块链介绍
第七章: 九析带你轻松完爆 hyperledger fabric - 区块链防篡改机制
第八章:九析带你轻松完爆 hyperledger fabric - Couchdb 安装
第九章:九析带你轻松完爆 hyperledger fabric - NVM 和 Nodejs 安装
第十章:九析带你轻松完爆 hyperledger fabric - chaincode 生命周期介绍
第十一章: 九析带你轻松完爆 hyperledger fabric - 创建联盟
第十二章: 九析带你轻松完爆 hyperledger fabric - configtxlator 尝鲜
第十三章: 九析带你轻松完爆 hyperledger fabric - 创建静态组织
第十四章: 九析带你轻松完爆 WARNING: The COMPOSE_PROJECT_NAME
第十五章: 九析带你轻松完爆 hyperledger fabric - chaincode 链码调用
目录
1 前言
在第十章九析带你了解了 chaincode 是什么以及它的生命周期都有哪些阶段。本节将通过具体的实例来实际操作一下 chaincode。本文将采用 go 版本的 chaincode,如果你对 go 不了解也没关系,你只需要根据我的记录实际操作即可,当然前提是你必须正确配置了 go 运行环境。如果你对 go 环境配置也不清楚,可以参考本人的第二章。
2 创建配置文件和目录
2.1 创建工作目录
mkdir jiuxi
cd jiuxi
2.2 创建配置目录和证书目录
mkdir crypto-config config
2.3 创建创世区块、通道、联盟资源问题
touch configtx.yaml
configtx.yaml 用来存放创世区块、联盟、通道、组织等配置信息。configtx.yaml 内容如下:
Organizations:
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: crypto-config/ordererOrganizations/jiuxi.org/msp
- &Org1
Name: Org1MSP
ID: Org1MSP
MSPDir: crypto-config/peerOrganizations/org1.jiuxi.org/msp
AnchorPeers:
- Host: peer0.org1.jiuxi.org
Port: 11151
- &Org2
Name: Org2MSP
ID: Org2MSP
MSPDir: crypto-config/peerOrganizations/org2.jiuxi.org/msp
AnchorPeers:
- Host: peer0.org2.jiuxi.org
Port: 12151
- &Org3
Name: Org3MSP
ID: Org3MSP
MSPDir: crypto-config/peerOrganizations/org3.jiuxi.org/msp
AnchorPeers:
- Host: peer0.org3.jiuxi.org
Port: 13151
Orderer: &OrdererDefaults
OrdererType: solo
Addresses:
- orderer.jiuxi.org:7050
BatchTimeout: 2s
BatchSize:
MaxMessageCount: 10
AbsoluteMaxBytes: 99 MB
PreferredMaxBytes: 512 KB
Kafka:
Brokers:
- 127.0.0.1:9092
Organizations:
Application: &ApplicationDefaults
Organizations:
Profiles:
JiuxiOrdererGenesis:
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Consortiums:
JiuxiConsortium:
Organizations:
- *Org1
- *Org2
- *Org3
JiuxiChannel:
Consortium: JiuxiConsortium
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
- *Org3
如果你复制粘贴上面内容到 vim 中去的时候,可能会有空行出现,你可以在 vim 中执行命令操作 :g/^s*$/d 来删除多余的空行。
2.4 创建证书配置文件
touch crypto-config.yaml
crypto-config.yaml 用来配置 orderer、peer 节点的信息,用来生成证书用,内容如下:
OrdererOrgs:
- Name: Orderer
Domain: jiuxi.org
Specs:
- Hostname: orderer
PeerOrgs:
- Name: Org1
Domain: org1.jiuxi.org
Template:
Count: 2
Users:
Count: 1
- Name: Org2
Domain: org2.jiuxi.org
Template:
Count: 2
Users:
Count: 1
- Name: Org3
Domain: org3.jiuxi.org
Template:
Count: 2
Users:
Count: 1
2.5 创建 docker-compose.yaml 文件
touch docker-compose.yaml
docker-compose.yaml 文件用来声明容器编排和容器之间的依赖关系,内容如下:
version: '2'
networks:
jiuxi:
services:
couchdb:
container_name: couchdb
image: hyperledger/fabric-couchdb
environment:
- COUCHDB_USER=
- COUCHDB_PASSWORD=
ports:
- 5984:5984
networks:
- jiuxi
orderer.jiuxi.org:
container_name: orderer.jiuxi.org
image: hyperledger/fabric-orderer
environment:
- FABRIC_LOGGING_SPEC=info
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer
command: orderer
ports:
- 7050:7050
volumes:
- ./config/:/etc/hyperledger/configtx
- ./crypto-config/ordererOrganizations/jiuxi.org/orderers/orderer.jiuxi.org/:/etc/hyperledger/msp/orderer
- ./crypto-config/peerOrganizations/org1.jiuxi.org/peers/peer0.org1.jiuxi.org/:/etc/hyperledger/msp/peerOrg1
networks:
- jiuxi
peer0.org1.jiuxi.org:
container_name: peer0.org1.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org1.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer0.org1.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 11151:7051
- 11153:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.jiuxi.org/peers/peer0.org1.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org1.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
peer1.org1.jiuxi.org:
container_name: peer1.org1.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer1.org1.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer1.org1.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 11251:7051
- 11253:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.jiuxi.org/peers/peer1.org1.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org1.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
peer0.org2.jiuxi.org:
container_name: peer0.org2.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org2.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer0.org2.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 12151:7051
- 12153:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org2.jiuxi.org/peers/peer0.org2.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org2.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
peer1.org2.jiuxi.org:
container_name: peer1.org2.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer1.org2.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer1.org2.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 12251:7051
- 12253:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org2.jiuxi.org/peers/peer1.org2.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org2.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
peer0.org3.jiuxi.org:
container_name: peer0.org3.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org3.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org3MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer0.org3.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 13151:7051
- 13153:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org3.jiuxi.org/peers/peer0.org3.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org3.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
peer1.org3.jiuxi.org:
container_name: peer1.org3.jiuxi.org
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer1.org3.jiuxi.org
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org3MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer1.org3.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: peer node start
ports:
- 13251:7051
- 13253:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org3.jiuxi.org/peers/peer1.org3.jiuxi.org/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org3.jiuxi.org/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.jiuxi.org
- couchdb
networks:
- jiuxi
cli:
container_name: cli
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=debug
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.jiuxi.org:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_jiuxi
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.jiuxi.org/users/[email protected]/msp
- CORE_CHAINCODE_KEEPALIVE=10
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/jiuxi/:/opt/gopath/src/github.com/
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
networks:
- jiuxi
2.6 创建环境配置文件 .env
touch .env
echo "COMPOSE_PROJECT_NAME=jiuxi" > .env
3 生成证书
cryptogen generate --config=./crypto-config.yaml
命令执行成功会在 crypto-config 目录下生成各个组织节点的证书文件。
4 生成创世区块
configtxgen -profile JiuxiOrdererGenesis -outputBlock ./config/genesis.block
命令执行成功会在 config 目录下生成创世区块 genesis.block。
5 生成通道交易文件
configtxgen -profile JiuxiChannel -outputCreateChannelTx ./config/channel1.tx -channelID channel1
命令执行成功会在 config 目录下生成通道交易文件 channel1.tx。
6 创建 Anchor 节点的 MSP 会话文件
configtxgen -profile JiuxiChannel -outputAnchorPeersUpdate ./config/channel1Org1MSPanchors.tx -channelID channel1 -asOrg Org1MSP
configtxgen -profile JiuxiChannel -outputAnchorPeersUpdate ./config/channel1Org2MSPanchors.tx -channelID channel1 -asOrg Org2MSP
7 初始化容器
启动 docker-compose.yaml 配置文件生成容器:
docker-compose -f docker-compose.yaml up &
docker ps -a
执行到此步骤完成了区块链的搭建、orderer、peer、cli、couchdb 节点的启动,但是目前组织的 peer 节点还没有处于通道之中,下一步需要开始创建通道和将节点加入到通道之中了。
8 创建通道
在 peer0.org1.jiuxi.org 节点上创建通道 channel1,通道创建成功后,会生成通道区块文件 .block,并将自身组织加入到通道中:
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.jiuxi.org peer channel create -o orderer.jiuxi.org:7050 -c channel1 -f /etc/hyperledger/configtx/channel1.tx
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.jiuxi.org ls
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.jiuxi.org peer channel join -b channel1.block
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.jiuxi.org peer channel list
将 peer0.org2.jiuxi.org 节点也加入到通道 channel1 中:
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.jiuxi.org peer channel fetch 0 channel1.block -o orderer.jiuxi.org:7050 -c channel1
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.jiuxi.org ls
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.jiuxi.org peer channel join -b channel1.block
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.jiuxi.org peer channel list
自此,区块链网络、联盟、组织、通道都创建完成,并且将组织 org1 加入到了通道 channel1 中。下一步就可以编写链码、安装链码、初始化链码、调用链码了。
9 编写链码
cd jiuxi
mkdir -p chaincode/jiuxi
touch jiuxi.go
jiuxi.go 的源码如下:
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Init")
_, args := stub.GetFunctionAndParameters()
var A, B string // Entities
var Aval, Bval int // Asset holdings
var err error
if len(args) != 4 {
return shim.Error("Incorrect number of arguments. Expecting 4")
}
// Initialize the chaincode
A = args[0]
Aval, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
B = args[2]
Bval, err = strconv.Atoi(args[3])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state to the ledger
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)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Invoke")
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
// Make payment of X units from A to B
return t.invoke(stub, args)
} else if function == "delete" {
// Deletes an entity from its state
return t.delete(stub, args)
} else if function == "query" {
// the old "Query" is now implemtned in invoke
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A, B string // Entities
var Aval, Bval int // Asset holdings
var X int // Transaction value
var err error
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
A = args[0]
B = args[1]
// Get the state from the ledger
// TODO: will be nice to have a GetAllState call to ledger
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))
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))
// Perform the execution
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
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state back to the ledger
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)
}
// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
A := args[0]
// Delete the key from the state in ledger
err := stub.DelState(A)
if err != nil {
return shim.Error("Failed to delete state")
}
return shim.Success(nil)
}
// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A string // Entities
var err error
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
}
A = args[0]
// Get the state from the ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
return shim.Error(jsonResp)
}
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
fmt.Printf("Query Response:%s\n", jsonResp)
return shim.Success(Avalbytes)
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
10 安装链码
安装和初始化链码在 cli 容器中进行,首先进入 cli 容器:
docker exec -it cli /bin/bash
执行如下语句安装链码:
peer chaincode install -n jiuxi -v 1.0.0 -p github.com/jiuxi
链码安装成功截图如下:
11 实例化链码
执行如下语句实例化链码:
peer chaincode instantiate -o orderer.jiuxi.org:7050 -C channel1 -n jiuxi -v 1.0.0 -c '{"Args": ["init", "a", "100", "b", "200"]}'
12 调用链码
执行如下语句调用链码:
peer chaincode query -C channel1 -n jiuxi -c '{"Args": ["query", "a"]}'