Tip: After the article is written, the table of contents can be automatically generated. How to generate it can refer to the help document on the right
Article directory
foreword
The previous article recorded how to use Hyperledger Fabric official test-network to run your own Chaincode process,
link here
This article records one, refer to the official go fabcar example to write your own application code, and interact with cc.
1. fabcar example
Official address
go language fabcar project directory structure
fabcar.go is the main application code, runfabcar.sh is a shell script that mainly sets environment variables and starts the application code.
fabcar.go
It mainly contains three functions:
Registering and Enrolling Application Users
//这个程序使用一个 证书签名请求 (CSR)——现在本地生成公钥和私钥,然后把公钥发送到 CA ,CA 会发布会一个让应用程序使用的证书。这三个证书会保存在钱包中,以便于我们以管理员的身份使用 CA 。
os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
wallet, err := gateway.NewFileSystemWallet("wallet")
if err != nil {
fmt.Printf("Failed to create wallet: %s\n", err)
os.Exit(1)
}
// 创建一个新的应用程序用户,它将被用于与区块链交互。
// populateWallet 拿到用户的证书凭据
if !wallet.Exists("appUser") {
err = populateWallet(wallet)
if err != nil {
fmt.Printf("Failed to populate wallet contents: %s\n", err)
os.Exit(1)
}
}
//代码中存在路径定义 要换成自己的路径
ccpPath := filepath.Join(
"..",
"..",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"connection-org1.yaml",
)
connect channel and cc
gw, err := gateway.Connect(
//身份认证 gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
gateway.WithIdentity(wallet, "appUser"),
)
if err != nil {
fmt.Printf("Failed to connect to gateway: %s\n", err)
os.Exit(1)
}
defer gw.Close()
// 连接通道
// 改成自己的名称
network, err := gw.GetNetwork("mychannel")
if err != nil {
fmt.Printf("Failed to get network: %s\n", err)
os.Exit(1)
}
//连接智能合约
// 改成自己的名称
contract := network.GetContract("fabcar")
Test the function of interacting with cc, that is, the function of accessing cc
//测试创建
result, err = contract.SubmitTransaction("createCar", "CAR10", "VW", "Polo", "Grey", "Mary")
//查询
result, err = contract.EvaluateTransaction("queryCar", "CAR10")
//修改
_, err = contract.SubmitTransaction("changeCarOwner", "CAR10", "Archie")
runfabcar.sh
ENV_DAL=`echo $DISCOVERY_AS_LOCALHOST`
echo "ENV_DAL:"$DISCOVERY_AS_LOCALHOST
if [ "$ENV_DAL" != "true" ]
then
export DISCOVERY_AS_LOCALHOST=true
fi
echo "DISCOVERY_AS_LOCALHOST="$DISCOVERY_AS_LOCALHOST
echo "run fabcar..."
# 修改此处改为自己的启动代码名称即可
go run fabcar.go
Two, my example
Application project directory structure
1. connect
Encapsulate a function, call the function directly, mark the modification, you need to change it into your own
code as follows:
func Getcontract1() *gateway.Contract {
err := os.Setenv("DISCOVERY_AS_LOCALHOST", "flase")
if err != nil {
log.Fatalf("Error setting DISCOVERY_AS_LOCALHOST environemnt variable: %v", err)
}
wallet, err := gateway.NewFileSystemWallet("wallet")
if err != nil {
log.Fatalf("Failed to create wallet: %v", err)
}
if !wallet.Exists("appUser") {
err = populateWallet1(wallet)
if err != nil {
log.Fatalf("Failed to populate wallet contents: %v", err)
}
}
//修改
ccpPath := filepath.Join(
"..",
"github.com",
"fabric-samples",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"connection-org1.yaml",
)
gw, err := gateway.Connect(
// lyj:使用ccpath 的路径 以及 appuser 的身份认证 通过使用Gateway类连接网络
gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
gateway.WithIdentity(wallet, "appUser"),
)
if err != nil {
log.Fatalf("Failed to connect to gateway: %v", err)
}
defer gw.Close()
//修改
network, err1 := gw.GetNetwork("channeltest")
if err != nil {
log.Fatalf("Failed to get network: %v", err1)
}
//修改
contract := network.GetContract("savelist")
return contract
}
func populateWallet1(wallet *gateway.Wallet) error {
//修改
credPath := filepath.Join(
"..",
// "src",
"github.com",
"fabric-samples",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"users",
"[email protected]",
"msp",
)
certPath := filepath.Join(credPath, "signcerts", "[email protected]")
// read the certificate pem
cert, err := ioutil.ReadFile(filepath.Clean(certPath))
if err != nil {
return err
}
keyDir := filepath.Join(credPath, "keystore")
// there's a single file in this dir containing the private key
files, err := ioutil.ReadDir(keyDir)
if err != nil {
return err
}
if len(files) != 1 {
return fmt.Errorf("keystore folder should have contain one file")
}
keyPath := filepath.Join(keyDir, files[0].Name())
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
if err != nil {
return err
}
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
return wallet.Put("appUser", identity)
}
call in main
func main() {
var contract *gateway.Contract
contract = manufacture.Getcontract1()
}
2. Interact with CC
Example of interactive function 1, pay attention to parameter passing, parameter 1 is the function name in CC, and other parameters correspond to the parameters of the function in CC, which are only string type.
code show as below:
func (c *Contract) SubmitTransaction(name string, args ...string) ([]byte, error) {
txn, err := c.CreateTransaction(name)
if err != nil {
return nil, err
}
return txn.Submit(args...)
}
func (c *Contract) EvaluateTransaction(name string, args ...string) ([]byte, error) {
txn, err := c.CreateTransaction(name)
if err != nil {
return nil, err
}
return txn.Evaluate(args...)
}
But the data structure, there is an array type
type SvcInfo struct {
SvcID string `json:"SvcID"`
ManufacturerName string `json:"ManufacturerName"`
SvcName string `json:"SvcName"`
SaveSvc []string `json:"SaveSvc"`
}
It is also possible to pass parameters to
the cc terminal to receive
, and the entire structure object is serialized in json as a whole and passed on. The cc terminal sets the corresponding parameters and deserializes them after receiving them. The parameters at both ends should correspond.
Three runs
Just replace go run fabcar.go in runfabcar.sh with your own code name.
sh runfabcar.sh
After running it looks like this:
Summarize
It is the first time to write go and interact codes using Hyperledger Fabric for reference and understanding by novices. There are many deficiencies in self-exploration, and please correct me.