本系列文章:
第一章:九析帶你完爆 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 - 創建靜態組織
目錄
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"]}'