超級賬本HyperLedger:Fabric的Chaincode(智能合約、鏈碼)開發、使用演示


作者: 李佶澳   轉載請保留:原文地址   發布時間:2018/07/17 10:20:00

說明

這是網易雲課堂“IT技術快速入門學院”使用的素材。

這里演示合約的用法,合約代碼托管在在Github上:合約代碼

怎樣寫合約參考: 超級賬本HyperLedger:Fabric Chaincode(智能合約、鏈碼)開發方法

Example-1:demo

example-1: demo中演示了最基本、最常用的方法,可以通過這個合約進行下面操作:

func (t *Chaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    function, args := stub.GetFunctionAndParameters()
    switch function {
    //返回調用者信息
    case "creator":
        return t.creator(stub, args)
    //調用改合約中的其它方法,用來演示復雜的調用
    case "call":
        return t.call(stub, args)
    //直接對key的內容進行append,用來演示這樣操作的結果
    case "append":
        return t.append(stub, args)
    //讀取當前用戶的屬性值
    case "attr":
        return t.attr(stub, args)
    //查詢一個key的當前值
    case "query":
        if len(args) != 1 {
            return shim.Error("parametes's number is wrong")
        }
        return t.query(stub, args[0])
    //查詢一個key的所有歷史值
    case "history":
        if len(args) != 1 {
            return shim.Error("parametes's number is wrong")
        }
        return t.history(stub, args[0])
    //創建一個key,並寫入key的值
    case "write": //寫入
        if len(args) != 2 {
            return shim.Error("parametes's number is wrong")
        }
        return t.write(stub, args[0], args[1])
    //通過當前合約,到另一個合約中進行查詢
    case "query_chaincode":
        if len(args) != 2 {
            return shim.Error("parametes's number is wrong")
        }
        return t.query_chaincode(stub, args[0], args[1])
    //通過當前合約,到另一個合約中進行寫入
    case "write_chaincode":
        if len(args) != 3 {
            return shim.Error("parametes's number is wrong")
        }
        return t.write_chaincode(stub, args[0], args[1], args[2])
    default:
        return shim.Error("Invalid invoke function name.")
    }
}

完整代碼: 合約代碼

合約安裝&單合約調用

獲取合約代碼

可以用下面的方式獲取合約源代碼:

mkdir -p $GOPATH/github.com/introclass
cd $GOPATH/github.com/introclass
git https://github.com/introclass/hyperledger-fabric-chaincodes.git

或者:

go get github.com/introclass/hyperledger-fabric-chaincodes

安裝合約&初始化

安裝合約:

cd /opt/app/fabric/cli/user/member1.example.com/Admin-peer0.member1.example.com
 ./3_install_chaincode.sh

合約初始化:

./4_instantiate_chaincode.sh

到另一個Peer上再安裝一次合約:

cd /opt/app/fabric/cli/user/member1.example.com/Admin-peer1.member1.example.com/
./3_install_chaincode.sh
<不需要再次實例化>

合約直接調用

下面的操作可以在任意一個Peer進行。

查看當前調用者,調用creator方法:

$ ./peer.sh chaincode query -C mychannel -n mycc -c  '{"Args":["creator"]}'
2018-07-18 12:45:48.083 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 12:45:48.083 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result:
peers.member1.example.com�-----BEGIN CERTIFICATE-----
MIICIjCCAcmgAwIBAgIRANQT46AE7SALHhoFnvodmiowCgYIKoZIzj0EAwIweTEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xHDAaBgNVBAoTE21lbWJlcjEuZXhhbXBsZS5jb20xHzAdBgNVBAMT
FmNhLm1lbWJlcjEuZXhhbXBsZS5jb20wHhcNMTgwNzE1MDcwMzIzWhcNMjgwNzEy
MDcwMzIzWjBeMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
A1UEBxMNU2FuIEZyYW5jaXNjbzEiMCAGA1UEAwwZQWRtaW5AbWVtYmVyMS5leGFt
cGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDMq5zAdcQgGWklQMdTf
irdHhbTBsLALJ0hjKFfaLIRyKO7Bq39HFrxPybLc/d4PXDXXrQsS9HCnKj9PSO6u
DBSjTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKA
IIPK7RfYFuMcuUQahKin2FxuaskfZl3WWtCMmEhN06lMMAoGCCqGSM49BAMCA0cA
MEQCIBnA0dhz/AnvsjNoWEuNBWIxRgKpG9CHbScrbQ7U9WK+AiAaZ4Qi7OZd8zev
ZZUxizW00+GqDXJWJ9VX6edtKDNVFw==
-----END CERTIFICATE-----

2018-07-18 12:45:48.087 CST [main] main -> INFO 003 Exiting.....

寫入Key:

$ ./peer.sh  chaincode invoke -o orderer0.member1.example.com:7050 --tls true --cafile tlsca.member1.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["write","key","keyvalue"]}'
2018-07-18 12:48:30.728 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 12:48:30.728 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-07-18 12:48:30.775 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200
2018-07-18 12:48:30.775 CST [main] main -> INFO 004 Exiting.....

查詢剛寫入的key:

$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["query","key"]}'
2018-07-18 12:49:14.464 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 12:49:14.464 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: keyvalue    <-- 查詢的結果
2018-07-18 12:49:14.468 CST [main] main -> INFO 003 Exiting.....

更改key的值:

$ ./peer.sh  chaincode invoke -o orderer0.member1.example.com:7050 --tls true --cafile tlsca.member1.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["write","key","keyvalue1"]}'
2018-07-18 12:50:44.023 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 12:50:44.023 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-07-18 12:50:44.027 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200
2018-07-18 12:50:44.028 CST [main] main -> INFO 004 Exiting.....

查詢key的歷史數據:

$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["history","key"]}'
2018-07-18 12:52:25.332 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 12:52:25.332 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: {"93ea6b185bb886c70f66b8b0dc8f5c727043269e2b7b7e76ae36644cd8ef3916":"keyvalue","f87a0f6f972226a57ade04a8e54db1a014d12cbab40abcbd8a5d65fe10bdfeff":"keyvalue1"}
<可以看到歷史值有兩個>
2018-07-18 12:52:25.340 CST [main] main -> INFO 003 Exiting.....

並發或快速修改數據時需要注意的問題

合約中的append方法的用是,讀取一個key的value,然后在讀取出來的數值上修改,最后重新寫入賬本。

需要特別注意,這種做法是有問題的,例如下面腳本預期的最終結果是[“1”,”2”,”3”,”4”,”5”,”6”,”7”,”8”,”9”,”10”]:

for i in {1..10}
do
    echo $i
    sleep 1
    ./peer.sh chaincode invoke -o orderer0.member1.example.com:7050 --tls true --cafile tlsca.member1.example.com-cert.pem -C mychannel -n mycc -c "{\"Args\":[\"append\",\"key-array\",\"$i\"]}"
done

但執行結束后,得到的結果卻是:

./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["query","key-array"]}'
2018-07-18 13:28:35.996 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:28:35.997 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: ["1","3","5","7","9"]
2018-07-18 13:28:36.001 CST [main] main -> INFO 003 Exiting.....

查看歷史價值,發現也有很多缺失的數據:

$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["history","key-array"]}'
2018-07-18 13:28:44.773 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:28:44.773 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: {
	"2bace9ac4812416969f623a471e902ecb6198bc9d16c1ca1e7e9586adf6cd428":"[\"1\",\"3\",\"5\",\"7\",\"9\"]",
	"6832ef710f74a39bc08e3386d0eb8aa757cb53ccd7fe149b042417b5cc436750":"[\"1\",\"3\",\"5\"]",
	"8c041cd53f045999dc41ca1facb8dbce8acb4a07ff5dd558a53f8f2908789b3d":"[\"1\"]",
	"d1b68113730f0bb8adb9a19c64594e64729b4a1c1aa81a412edd6b1b1ad84e06":"[\"1\",\"3\"]",
	"d5fe258cc64d5f10f63b8a9f3c1d321d966f4d5c45b17b5b8c31eccad231e3fd":"[\"1\",\"3\",\"5\",\"7\"]"}
2018-07-18 13:28:44.777 CST [main] main -> INFO 003 Exiting.....

出現這種結果的原因是,其中一些append操作是基於“舊”的數據的:之前的append操作依舊修改了數據,但是當前的append還不能查詢到最新的數據。

這些append操作不會被接受。

如果只“修改”數據,則會是另一種結果:

for i in {1..10}
do
    ./peer.sh  chaincode invoke -o orderer0.member1.example.com:7050 --tls true --cafile tlsca.member1.example.com-cert.pem -C mychannel -n mycc -c "{\"Args\":[\"write\",\"key-single\",\"$i\"]}"
done

執行以后查詢當前值,為10:

$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["query","key-single"]}'
2018-07-18 13:41:45.257 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:41:45.257 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 10
2018-07-18 13:41:45.261 CST [main] main -> INFO 003 Exiting.....

但可以在歷史數據中找到所有的值:

$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["history","key-single"]}'
2018-07-18 13:42:47.206 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:42:47.206 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: {
	"0b6e46b6397ad2e76b2de842f162d558ce88b2409656d16a30b9f53f6a038357":"6",
	"1015deb1cdfd3e08a5da2fd03ddeb0e1df69287d88c017f7d55678405fbac774":"8",
	"5291a41b310b31b14b5b96c981dc9a6923ed4c956b52ee4e662fc65167531435":"3",
	"691678195fd7fbd7787ff6fb128adff87c34de9c96e62b599320d8c1966a8397":"7",
	"876374f0551eb227351f5312ca494d141cdddae99e7d67ffeffdd0094e5532bb":"1",
	"8b02dae72f1d6f9a4db6e2daa4947be1d5bcdbfa4f4fbb7a69382cc85510732b":"4",
	"b5c89bacda118d0e0a7777aad8083c1920ac90201e3dac0e8df6385038afee5c":"10",
	"de111d7b19b68918502a52d36f49fbd17a18db46a69379d3566f8d0531307871":"2",
	"e2dbb13a5d42c33756341f487357a526e669ca5fbdefd7e49026f12e3979889c":"5",
	"eb802055364096703b351cea60c0392119c487b0ab3a9cd6ed344ee897b6fa1a":"9"}
2018-07-18 13:42:47.210 CST [main] main -> INFO 003 Exiting.....

並發寫入的問題可以參考:

HyperLedger High-Throughput Network

Hyperledger Fabric and how it isn’t concurrent out of the box.

How hyperledger handle the Concurrent of “invoke” of the same Key-Value pair of chaincode?

合約鏈式調用

就是通過當前合約,調用另一個合約。

demo合約中提供了一個call方法,可以很方便的測試合約鏈式調用:

["call","chaincode","method"...]   通過demo合約調用另一個合約

例如再部署一個叫做mycc2的合約,也使用demo的源代碼,部署的合約名不同。

通過mycc調用mycc2的query:

在mycc2中查詢不到通過mycc寫入的數據
$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["call","mycc2","query","key-single"]}'
2018-07-18 13:53:15.680 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:53:15.680 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result:
2018-07-18 13:53:15.774 CST [main] main -> INFO 003 Exiting.....

直接調用mycc2也是一樣查不到
$ ./peer.sh chaincode query -C mychannel -n mycc2 -c '{"Args":["query","key-single"]}'
2018-07-18 13:55:23.315 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:55:23.315 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result:
2018-07-18 13:55:23.327 CST [main] main -> INFO 003 Exiting.....

在mycc中可以查到
$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["query","key-single"]}'
2018-07-18 13:53:31.077 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:53:31.077 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 10
2018-07-18 13:53:31.082 CST [main] main -> INFO 003 Exiting.....

如果用query方式調用另一個合約的invoke是無效的:

在mycc2中寫入key
$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["call","mycc2","write","key-single","inmycc2"]}'
2018-07-18 13:59:25.610 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:59:25.610 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result:
2018-07-18 13:59:25.615 CST [main] main -> INFO 003 Exiting.....

無效,查詢不到key
$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["call","mycc2","query","key-single"]}'
2018-07-18 13:59:15.796 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:59:15.796 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result:
2018-07-18 13:59:15.802 CST [main] main -> INFO 003 Exiting.....

如果用invoke方式調用另一個合約的invoke是有效的:

$ ./peer.sh  chaincode invoke -o orderer0.member1.example.com:7050 --tls true --cafile tlsca.member1.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["call","mycc2","write","key-single","inmycc2"]}'
2018-07-18 13:59:48.432 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:59:48.432 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-07-18 13:59:48.439 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200
2018-07-18 13:59:48.440 CST [main] main -> INFO 004 Exiting.....

可以查詢到
$ ./peer.sh chaincode query -C mychannel -n mycc -c '{"Args":["call","mycc2","query","key-single"]}'
2018-07-18 13:59:55.470 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-07-18 13:59:55.470 CST [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: inmycc2
2018-07-18 13:59:55.476 CST [main] main -> INFO 003 Exiting.....

參考

  1. 演示使用的合約代碼
  2. example-1: demo
  3. 超級賬本HyperLedger:Fabric Chaincode(智能合約、鏈碼)開發方法
  4. Hyperledger Fabric and how it isn’t concurrent out of the box.
  5. How hyperledger handle the Concurrent of “invoke” of the same Key-Value pair of chaincode?
  6. HyperLedger High-Throughput Network

限時活動,每邀請一人即返回25元!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM