title: Fabric链码实战(一)贷款还款
tags: Hyperledger, fabric ,区块链,chaincode
功能简述
假设需要用链码开发简单的贷款还款,要实现以下简单的几个业务需求:
1.通过账户身份证号,银行名字进行贷款
2.过账户身份证号,银行名字进行还款
功能实现
在fabric-samples/chaincode
下新建一个pay
目录用来存放代码。
1.创建结构体
创建银行、账户、交易历史和智能合约结构体
//银行、账户、定义交易历史
//定义银行
type Bank struct {
//名字
BankName string `json:"BankName"`
//金额
Amount int `json:"Amount"`
//1:贷款 2:还款
Flag int `json:"Flag"`
//起始时间
StartTime string `json:"StartTime"`
//结束时间
EndTime string `json:"EndTime"`
}
//定义账户
type Account struct {
//身份证号
CardNo string `json:"CardNo"`
//用户名
Aname string `json:"Aname"`
//性别
Gender string `json:"Gender"`
//电话
Mobile string `json:"Mobile"`
//银行
Bank Bank `json:"Bank"`
//交易历史
Histroys []HistoryItem
}
//定义交易历史
type HistoryItem struct {
//交易id
TxID string
//账户
Account Account
}
type TraceChaincode struct {
}
2.实现init函数和main函数
//初始化方法
func (t *TraceChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
//初始化测试数据
initTest(stub) //测试方法
return shim.Success(nil)
}
//链码入口invoke
//loan:贷款
//repayment:还款
//initTest:测试初始化
func (t *TraceChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
//得到方法名和参数
fun, args := stub.GetFunctionAndParameters()
//进行判断
if fun == "loan" {
//贷款
return loan(stub, args)
} else if fun == "repayment" {
//还款
return repayment(stub, args)
} else if fun == "initTest" {
return initTest(stub)
} else {
return shim.Error("方法名错误")
}
}
func main() {
err := shim.Start(new(TraceChaincode))
if err != nil {
fmt.Println("启动链码时发生错误")
}
}
3.贷款和还款功能实现
//定义贷款和还款
const (
Bank_Flag_Loan = 1
Bank_Flag_Repayment = 2
)
//贷款
//-c Args:[loan,账户身份证号,银行名字,金额]
func loan(stub shim.ChaincodeStubInterface, args []string) peer.Response {
//判断参数
if len(args) != 3 {
return shim.Error("参数个数错误")
}
//判断类型
v, err := strconv.Atoi(args[2])
if err != nil {
return shim.Error("类型错误")
}
//组装数据
bank := Bank{
BankName: args[1],
Amount: v,
Flag: Bank_Flag_Loan,
StartTime: "2011-01-10",
EndTime: "2021-01-09",
}
account := Account{
CardNo: args[0],
Aname: "jack",
Gender: "男",
Mobile: "159999999",
Bank: bank,
}
//保存状态
b := putAccount(stub, account)
//判断
if ! b {
return shim.Error("保存贷款数据失败")
}
return shim.Success([]byte("保存贷款数据成功"))
}
//序列化并保存
//参数将要保存的账户传过来,返回布尔
func putAccount(stub shim.ChaincodeStubInterface, account Account) bool {
//序列化
accBytes, err := json.Marshal(account)
if err != nil {
return false
}
//保存数据
err = stub.PutState(account.CardNo, accBytes)
if err != nil {
return false
}
return true
}
//还款
//-c Args:[repayment,账户身份证号,银行名字,金额]
func repayment(stub shim.ChaincodeStubInterface, args []string) peer.Response {
if len(args) != 3 {
return shim.Error("参数个数错误")
}
v, err := strconv.Atoi(args[2])
if err != nil {
return shim.Error("指定的还款金额错误")
}
//组装数据
bank := Bank{
BankName: args[1],
Amount: v,
Flag: Bank_Flag_Repayment,
StartTime: "2011-01-10",
EndTime: "2021-01-09",
}
account := Account{
CardNo: args[0],
Aname: "jack",
Gender: "男",
Mobile: "159999999",
Bank: bank,
}
b := putAccount(stub, account)
if !b {
return shim.Error("存款失败")
}
return shim.Success([]byte("存款成功"))
}
4.实现测试方法
//测试方法
func initTest(stub shim.ChaincodeStubInterface) peer.Response {
bank := Bank{
BankName: "icbc",
Amount: 6000,
//贷款
Flag: 1,
StartTime: "2010-01-01",
EndTime: "2020-01-01",
}
bank1 := Bank{
BankName: "abc",
Amount: 1000,
//还款
Flag: 2,
StartTime: "2010-02-01",
EndTime: "2020-02-01",
}
account := Account{
CardNo: "1234",
Aname: "jack",
Gender: "男",
Mobile: "15900000",
Bank: bank1,
Histroys: nil,
}
account1 := Account{
CardNo: "123444",
Aname: "jack2",
Gender: "男",
Mobile: "1590000000",
Bank: bank,
Histroys: nil,
}
//对象序列化,存储
accBytes, err := json.Marshal(account)
if err != nil {
return shim.Error("序列化账户失败")
}
accBytes1, err := json.Marshal(account1)
if err != nil {
return shim.Error("序列化账户1失败")
}
//保存
err = stub.PutState(account.CardNo, accBytes)
if err != nil {
return shim.Error("保存账户失败")
}
err = stub.PutState(account.CardNo, accBytes1)
if err != nil {
return shim.Error("保存账户1失败")
}
return shim.Success(nil)
}
部署和测试
把我们的代码放入之前建立的pay
目录下
详细部署可以查看我之前文章:
1. 打开网络
打开第一个终端
切换到chaincode-docker-devmode
目录
执行下面命令:
###删除所有活跃的容器###
docker rm -f $(docker ps -aq)
###清理网络缓存###
docker network prune
###开启网络###
docker-compose -f docker-compose-simple.yaml up
2.安装链码
打开第二个终端
###进入Docker容器cli###
docker exec -it chaincode bash
###进入到链码对应目录###
cd pay
###启动节点###
CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./pay
3.操作链码
打开第三个终端
###启动 cli###
docker exec -it cli /bin/bash
###安装链码###
peer chaincode install -p chaincodedev/chaincode/pay -n mycc -v 0
###实例化链码###
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["init"]}' -C myc
4.调用链码
###调用测试方法###
peer chaincode invoke -C myc -n mycc -c '{"Args":["initTest"]}'
###贷款###
peer chaincode invoke -C myc -n mycc -c '{"Args":["loan","110229","icbc","5000000"]}'
###还款###
peer chaincode invoke -C myc -n mycc -c '{"Args":["repayment","110229","icbc","500"]}'