本系列文章:


第一章:九析带你完爆 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

        全部创建完毕之后的目录结构如下:第十五章 九析带你轻松完爆 hyperledger fabric - chaincode 链码调用_第1张图片


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"]}'

        链码执行成功后,会生成链码容器,如下图所示:第十五章 九析带你轻松完爆 hyperledger fabric - chaincode 链码调用_第2张图片


12 调用链码

        执行如下语句调用链码:

peer chaincode query -C channel1 -n jiuxi  -c '{"Args": ["query", "a"]}'