IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Fabric链码实践之简单转账交易 -> 正文阅读

[系统运维]Fabric链码实践之简单转账交易

配置文件

docker-compose-cli.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer.itcast.com:
  peer0.orggo.itcast.com:
  peer1.orggo.itcast.com:
  peer0.orgcpp.itcast.com:
  peer1.orgcpp.itcast.com:

networks:
  byfn:

services:

  orderer.itcast.com:
    extends:
      file:   base/docker-compose-base.yaml
      service: orderer.itcast.com
    container_name: orderer.itcast.com
    networks:
      - byfn

  peer0.orggo.itcast.com:
    container_name: peer0.orggo.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.orggo.itcast.com
    networks:
      - byfn

  peer1.orggo.itcast.com:
    container_name: peer1.orggo.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.orggo.itcast.com
    networks:
      - byfn

  peer0.orgcpp.itcast.com:
    container_name: peer0.orgcpp.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.orgcpp.itcast.com
    networks:
      - byfn

  peer1.orgcpp.itcast.com:
    container_name: peer1.orgcpp.itcast.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.orgcpp.itcast.com
    networks:
      - byfn

  cli:
    container_name: cli
    image: hyperledger/fabric-tools:latest
    tty: true
    stdin_open: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      #- CORE_LOGGING_LEVEL=DEBUG
      - CORE_LOGGING_LEVEL=INFO
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/Admin@orggo.itcast.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
        - /var/run/:/host/var/run/
        - ./chaincode/:/opt/gopath/src/github.com/chaincode
        - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
        - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
        - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - orderer.itcast.com
      - peer0.orggo.itcast.com
      - peer1.orggo.itcast.com
      - peer0.orgcpp.itcast.com
      - peer1.orgcpp.itcast.com
    networks:
      - byfn

configtx.yaml

Organizations:
    - &OrdererOrg
        Name: OrdererOrg
        ID: OrdererMSP
        MSPDir: crypto-config/ordererOrganizations/itcast.com/msp 

    - &org_go
        Name: OrgGoMSP
        ID: OrgGoMSP
        MSPDir: crypto-config/peerOrganizations/orggo.itcast.com/msp
        AnchorPeers:
            - Host: peer0.orggo.itcast.com
              Port: 7051

    - &org_cpp
        Name: OrgCppMSP
        ID: OrgCppMSP
        MSPDir: crypto-config/peerOrganizations/orgcpp.itcast.com/msp
        AnchorPeers:
            - Host: peer0.orgcpp.itcast.com
              Port: 7051
Capabilities:
    Global: &ChannelCapabilities
        V1_1: true
    Orderer: &OrdererCapabilities
        V1_1: true
    Application: &ApplicationCapabilities
        V1_2: true
Application: &ApplicationDefaults

    Organizations:
Orderer: &OrdererDefaults
    OrdererType: solo

    Addresses:
        - orderer.itcast.com:7050
    BatchTimeout: 2s

    BatchSize:

        MaxMessageCount: 10
        AbsoluteMaxBytes: 32 MB
        PreferredMaxBytes: 512 KB

    Kafka:
        Brokers:
            - 127.0.0.1:9092
    Organizations:
Profiles:

    ItcastOrgsOrdererGenesis:
        Capabilities:
            <<: *ChannelCapabilities
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *org_go
                    - *org_cpp
    ItcastOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *org_go
                - *org_cpp
            Capabilities:
                <<: *ApplicationCapabilities

crypton-config.yaml

OrdererOrgs:
  - Name: Orderer
    Domain: itcast.com
    Specs:
      - Hostname: orderer
PeerOrgs:
  - Name: OrgGo
    Domain: orggo.itcast.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 3
  - Name: OrgCpp
    Domain: orgcpp.itcast.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 3

docker-compose-base.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

services:

  orderer.itcast.com:
    container_name: orderer.itcast.com
    image: hyperledger/fabric-orderer:latest
    environment:
      - ORDERER_GENERAL_LOGLEVEL=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer
    volumes:
    - ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
    - ../crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp:/var/hyperledger/orderer/msp
    - ../crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/tls/:/var/hyperledger/orderer/tls
    - orderer.itcast.com:/var/hyperledger/production/orderer
    ports:
      - 7050:7050

  peer0.orggo.itcast.com:
    container_name: peer0.orggo.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.orggo.itcast.com
      - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer0.orggo.itcast.com:/var/hyperledger/production
    ports:
      - 7051:7051
      - 7053:7053

  peer1.orggo.itcast.com:
    container_name: peer1.orggo.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.orggo.itcast.com
      - CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orggo.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orggo.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgGoMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer1.orggo.itcast.com:/var/hyperledger/production

    ports:
      - 8051:7051
      - 8053:7053

  peer0.orgcpp.itcast.com:
    container_name: peer0.orgcpp.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.orgcpp.itcast.com
      - CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgCppMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer0.orgcpp.itcast.com:/var/hyperledger/production
    ports:
      - 9051:7051
      - 9053:7053

  peer1.orgcpp.itcast.com:
    container_name: peer1.orgcpp.itcast.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.orgcpp.itcast.com
      - CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orgcpp.itcast.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orgcpp.itcast.com:7051
      - CORE_PEER_LOCALMSPID=OrgCppMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
        - peer1.orgcpp.itcast.com:/var/hyperledger/production
    ports:
      - 10051:7051
      - 10053:7053

peer-base.yaml

version: '2'
services:
  peer-base:
    image: hyperledger/fabric-peer:latest
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=itcast_byfn
      - CORE_LOGGING_LEVEL=INFO
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start

生成相关文件

mkdir channel-artifacts
cryptogen generate --config=crypton-config.yaml
configtxgen -profile ItcastOrgsOrdererGenesis -outputBlock ./genesis.block
configtxgen -profile  ItcastOrgsChannel -outputCreateChannelTx channel.tx -channelID itcastchannel
configtxgen -profile  ItcastOrgsChannel -outputAnchorPeersUpdate GOMSPanchors.tx -channelID itcastchannel -asOrg OrgGoMSP
configtxgen -profile  ItcastOrgsChannel -outputAnchorPeersUpdate CppMSPanchors.tx -channelID itcastchannel -asOrg OrgCppMSP
mv *.tx *.block channel-artifacts/

启动网络./startup.sh

#!/bin/bash
systemctl start docker
docker-compose -f docker-compose-cli.yaml up -d
docker exec -it cli /bin/bash

在这里插入图片描述

创建通道

peer channel create -o orderer.itcast.com:7050 -c itcastchannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem

加入通道

peer channel join -b itcastchannel.block

编写链代码

业务描述

主要实现四大功能:用户注册(userRgister)、用户注销(userDelete)、用户转账(userTransfer)、用户查询(userQuery)

  • 用户属性如下:
  • 姓名
  • 性别
  • 年龄
  • 余额
  • 转账记录

导入包及结构体定义

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
)
type User struct {
	Name string `json:"name"` //姓名
	Gender string `json:"gender"` //性别 F/M
	Age string `json:"age"`  //年龄
	Balance int `json:balnace` //余额
	Txs []string `json:txs` //交易列表
}
//结构体来实现方法
type ChaincodeInterface struct {

}

Init()与Invoke()

链码必须实现Init()与Invoke(),不然main函数里面无法运行。这里我进行初始化的时候不要传参。简单理解Invoke():实现函数的导航功能,并将参数传入到对应函数中。

func (t *ChaincodeInterface) Init(stub shim.ChaincodeStubInterface) pb.Response{
	return shim.Success(nil)
}
func (t *ChaincodeInterface) Invoke(stub shim.ChaincodeStubInterface) pb.Response{
	function,args := stub.GetFunctionAndParameters()
	switch function {
	case "userRegister":
		return t.userRegister(stub,args)
	case "userDelete":
		return t.userDelete(stub,args)
	case "userQuery":
		return t.userQuery(stub,args)
	case "userTransfer":
		return t.userTransfer(stub,args)
	default:
		return shim.Error("Unsupported function")
	}
	return shim.Success(nil)
}

userRegister

  • 一般来说,链码的编写有一个普遍套路
  • 0.明确需要用到什么参数
  • 1.检查参数个数是否正确
  • 2.验证参数正确性
  • 3.验证存在性
  • 4.写入状态
func (t *ChaincodeInterface) userRegister(stub shim.ChaincodeStubInterface,args []string)pb.Response{
	//验证参数个数是否正确
	if len(args) != 4{
		return shim.Error("Incorrect number of args.Expecting 4")
	}
	name := args[0]
	gender := args[1]
	age := args[2]
	val := args[3]
	//验证参数正确性
	if name == "" || gender == "" || age == "" || val == ""{
		return shim.Error("Invalid args.")
	}
	balanace,err := strconv.Atoi(val)
	if err != nil{
		return shim.Error("convert to Int error")
	}
	exByes,err := stub.GetState(name)
	if err == nil && len(exByes) != 0{
		return shim.Error("user already exists")
	}
	//对象序列化,为写入状态做准备
	user := User{
		Name: name,
		Gender: gender,
		Age: age,
		Balance: balanace,
		Txs: make([]string,0), //最开始交易列表为空
	}
	userByes,err := json.Marshal(user)
	if err != nil{
		return shim.Error("marshal user error")
	}
	//写入状态
	if err = stub.PutState(name,userByes);err != nil{
		return shim.Error("Failed to put state")
	}
	return shim.Success(nil)
}

userDelete

func (t *ChaincodeInterface) userDelete(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	if len(args) != 1{
		return shim.Error("Incorrect number of args.Expecting 1")
	}
	name := args[0] //传入姓名进行删除
	if err := stub.DelState(name);err != nil{
		return shim.Error("Failed to delete user")
	}
	return shim.Success(nil)
}

userQuery

func (t *ChaincodeInterface) userQuery(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	if len(args) != 1{
		return shim.Error("Incorrect number of args.Expecting 1")
	}
	name := args[0]
	userBytes,err := stub.GetState(name)
	if err != nil{
		return shim.Error("Failed to get state")
	}
	return shim.Success(userBytes)
}

userTransfer

//Transfer from A to B
func (t *ChaincodeInterface) userTransfer(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	//传入参数:发送者,接收者,金额
	if len(args) != 3{
		return shim.Error("Incorrect number of args.Expecting 3")
	}
	userFrom,userTo,val := args[0],args[1],args[2]
	if userFrom == "" || userTo == "" || val == ""{
		return shim.Error("Invalid args")
	}
	//验证发送者是否存在
	existFrom,err := stub.GetState(userFrom)
	if err == nil && len(existFrom) == 0{
		return shim.Error("sender does not exist")
	}
	//验证接收者是否存在
	existTo,err := stub.GetState(userTo)
	if err == nil && len(existTo) == 0{
		return shim.Error("receiver does not exist")
	}
	var from,to User
	tx,err := strconv.Atoi(val) //获取转账金额
	if err != nil{
		return shim.Error("convert to Int error")
	}
	//将对象从状态数据库中取出来,方便后面更新状态
	userFromBytes,err := stub.GetState(userFrom)
	if err != nil{
		return shim.Error("Failed to get userFrom state")
	}
	if err = json.Unmarshal(userFromBytes,&from);err != nil{
		return shim.Error("Failed to unmarshal userFrom")
	}
	userToByes,err := stub.GetState(userTo)
	if err != nil{
		return shim.Error("Failed to get userFrom state")
	}
	if err = json.Unmarshal(userToByes,&to);err != nil{
		return shim.Error("Failed to unmarshal userFrom")
	}
	//不允许转账金额比发送者的余额还多
	if (tx > from.Balance){
		return shim.Error("Insufficient balance")
	}
	//进行转账交易
	from.Balance = from.Balance - tx
	to.Balance = to.Balance + tx
	from.Txs = append(from.Txs,fmt.Sprintf("Transfer %d to %s \n",tx,to.Name))
	to.Txs = append(to.Txs,fmt.Sprintf("Recive %d from %s \n",tx,from.Name))
	newFrom,err := json.Marshal(from)
	if err != nil{
		return shim.Error("marshal user error")
	}
	newTo,err := json.Marshal(to)
	if err != nil{
		return shim.Error("marshal user error")
	}
	//写入新的状态
	if err = stub.PutState(from.Name,newFrom);err != nil{
		return shim.Error("Failed to put state")
	}
	if err = stub.PutState(to.Name,newTo);err != nil{
		return shim.Error("Failed to put state")
	}
	return shim.Success(nil)
}

完整链码

package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
)
type User struct {
	Name string `json:"name"` //姓名
	Gender string `json:"gender"` //性别 F/M
	Age string `json:"age"`  //年龄
	Balance int `json:balnace` //余额
	Txs []string `json:txs` //交易列表
}
type ChaincodeInterface struct {

}

func (t *ChaincodeInterface) Init(stub shim.ChaincodeStubInterface) pb.Response{
	return shim.Success(nil)
}

func (t *ChaincodeInterface) Invoke(stub shim.ChaincodeStubInterface) pb.Response{
	function,args := stub.GetFunctionAndParameters()
	switch function {
	case "userRegister":
		return t.userRegister(stub,args)
	case "userDelete":
		return t.userDelete(stub,args)
	case "userQuery":
		return t.userQuery(stub,args)
	case "userTransfer":
		return t.userTransfer(stub,args)
	default:
		return shim.Error("Unsupported function")
	}
	return shim.Success(nil)
}

func (t *ChaincodeInterface) userRegister(stub shim.ChaincodeStubInterface,args []string)pb.Response{
	if len(args) != 4{
		return shim.Error("Incorrect number of args.Expecting 4")
	}
	name := args[0]
	gender := args[1]
	age := args[2]
	val := args[3]
	if name == "" || gender == "" || age == "" || val == ""{
		return shim.Error("Invalid args.")
	}
	balanace,err := strconv.Atoi(val)
	if err != nil{
		return shim.Error("convert to Int error")
	}
	exByes,err := stub.GetState(name)
	if err == nil && len(exByes) != 0{
		return shim.Error("user already exists")
	}
	user := User{
		Name: name,
		Gender: gender,
		Age: age,
		Balance: balanace,
		Txs: make([]string,0), //最开始交易列表为空
	}
	userByes,err := json.Marshal(user)
	if err != nil{
		return shim.Error("marshal user error")
	}
	if err = stub.PutState(name,userByes);err != nil{
		return shim.Error("Failed to put state")
	}
	return shim.Success(nil)
}

func (t *ChaincodeInterface) userDelete(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	if len(args) != 1{
		return shim.Error("Incorrect number of args.Expecting 1")
	}
	name := args[0]
	if err := stub.DelState(name);err != nil{
		return shim.Error("Failed to delete user")
	}
	return shim.Success(nil)
}

func (t *ChaincodeInterface) userQuery(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	if len(args) != 1{
		return shim.Error("Incorrect number of args.Expecting 1")
	}
	name := args[0]
	userBytes,err := stub.GetState(name)
	if err != nil{
		return shim.Error("Failed to get state")
	}
	return shim.Success(userBytes)
}

//A -> B
func (t *ChaincodeInterface) userTransfer(stub shim.ChaincodeStubInterface,args []string) pb.Response{
	if len(args) != 3{
		return shim.Error("Incorrect number of args.Expecting 3")
	}
	userFrom,userTo,val := args[0],args[1],args[2]
	existFrom,err := stub.GetState(userFrom)
	if err == nil && len(existFrom) == 0{
		return shim.Error("sender does not exist")
	}
	existTo,err := stub.GetState(userTo)
	if err == nil && len(existTo) == 0{
		return shim.Error("receiver does not exist")
	}
	var from,to User
	if userFrom == "" || userTo == "" || val == ""{
		return shim.Error("Invalid args")
	}
	tx,err := strconv.Atoi(val) //获取转账金额
	if err != nil{
		return shim.Error("convert to Int error")
	}
	userFromBytes,err := stub.GetState(userFrom)
	if err != nil{
		return shim.Error("Failed to get userFrom state")
	}
	if err = json.Unmarshal(userFromBytes,&from);err != nil{
		return shim.Error("Failed to unmarshal userFrom")
	}
	userToByes,err := stub.GetState(userTo)
	if err != nil{
		return shim.Error("Failed to get userFrom state")
	}
	if err = json.Unmarshal(userToByes,&to);err != nil{
		return shim.Error("Failed to unmarshal userFrom")
	}
	if (tx > from.Balance){
		return shim.Error("Insufficient balance")
	}
	from.Balance = from.Balance - tx
	to.Balance = to.Balance + tx
	from.Txs = append(from.Txs,fmt.Sprintf("Transfer %d to %s \n",tx,to.Name))
	to.Txs = append(to.Txs,fmt.Sprintf("Recive %d from %s \n",tx,from.Name))
	newFrom,err := json.Marshal(from)
	if err != nil{
		return shim.Error("marshal user error")
	}
	newTo,err := json.Marshal(to)
	if err != nil{
		return shim.Error("marshal user error")
	}
	if err = stub.PutState(from.Name,newFrom);err != nil{
		return shim.Error("Failed to put state")
	}
	if err = stub.PutState(to.Name,newTo);err != nil{
		return shim.Error("Failed to put state")
	}
	return shim.Success(nil)
}

func main(){
	err := shim.Start(new(ChaincodeInterface))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

安装链码、链码初始化

安装链码

peer chaincode install -n testcc -v 1.0 -l golang -p github.com/chaincode

链码初始化

peer chaincode instantiate -o orderer.itcast.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem -C itcastchannel -n testcc -l golang -v 1.0 -c '{"Args":["init"}' -P " OR ('OrgGoMSP.member','OrgCppMSP.member')"

链码效果

userRegister测试

peer chaincode invoke -o orderer.itcast.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem -C itcastchannel -n testcc -c '{"Args":["userRegister","Bruce","M","23"]}'

在这里插入图片描述

userQuery测试

peer chaincode query -C itcastchannel -n testcc -c '{"Args":["userQuery","Bruce"]}'

在这里插入图片描述

userTransfer测试

再创建一个用户Alice,余额为800

peer chaincode invoke -o orderer.itcast.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem -C itcastchannel -n testcc -c '{"Args":["userTransfer","Bruce","Alice","150"]}'

在这里插入图片描述

userDelete测试

peer chaincode invoke -o orderer.itcast.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypt
o/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem -C itcastchannel -n testcc -c '{"Args":["userDelete","Bruce"]}'

在这里插入图片描述

退出并关闭

exit
docker-compose -f docker-compose-cli.yaml down -v

目前的话,我试出来的土办法:更新链码都是删除docker容器然后重新启动、安装链码。不知道你们有没有比较规范的办法。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-15 15:58:38  更:2021-08-15 15:59:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 20:01:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计