# 浣跨敤Golang杩涜鏅鸿兘鍚堢害寮€鍙� <font color=red>娉ㄦ剰锛氭湰鏂囨。鎻忚堪鐨勬櫤鑳藉悎绾︾紪鍐欐柟娉曢€傜敤浜�2.3.0浠ヤ笂鐨勯暱瀹夐摼锛屽闇€鏌ョ湅2.x.x鐗堟湰鐨勬櫤鑳藉悎绾︾紪鍐欐枃妗o紝璇峰垏鎹㈠埌[2.x.x鐗堟湰鐨勬枃妗(https://docs.chainmaker.org.cn/v2.2.1/html/operation/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6.html#docker-go)銆�</font> 璇昏€呭璞★細鏈珷鑺備富瑕佹弿杩颁娇鐢℅olang杩涜ChainMaker鍚堢害缂栧啓鐨勬柟娉曪紝涓昏闈㈠悜浜庝娇鐢℅olang杩涜ChainMaker鐨勫悎绾﹀紑鍙戠殑寮€鍙戣€呫€� **姒傝** 1銆佽繍琛屾椂铏氭嫙鏈虹被鍨嬶紙runtime_type锛夛細DOCKER_GO 2銆佷粙缁嶄簡鐜渚濊禆 3銆佷粙缁嶄簡寮€鍙戞柟寮忓強sdk鎺ュ彛 4銆佹彁渚涗簡涓€涓ず渚嬪悎绾� ## 鐜渚濊禆 1. 鎿嶄綔绯荤粺 鐩墠浠呮敮鎸佸湪Linux绯荤粺涓嬮儴缃插拰杩愯 Docker VM锛屽悎绾︾殑缂栬瘧涔熷繀椤诲湪Linux鐜涓嬫墽琛屻€傚鏋滈渶瑕佸湪鍏朵粬绯荤粺鐜涓嬬紪璇戝悎绾︼紝璇峰弬鑰僄olang鐨勪氦鍙夌紪璇戜慨鏀圭紪璇戝懡浠ゃ€� 2. 杞欢渚濊禆 鎺ㄨ崘浣跨敤Goland 鎴� vscode绛塈DE缂栧啓鍜岀紪璇慓olang鍚堢害銆� 缂栬瘧鍚庣殑鍚堢害闇€瑕佺粡杩�7zip鍘嬬缉褰㈡垚鏈€缁堢殑鍚堢害鏂囦欢锛�7zip鐨勫畨瑁呰鍙傜湅[7zip瀹樼綉](https://sparanoid.com/lab/7z/) 3. 闀垮畨閾剧幆澧冨噯澶� 鍑嗗涓€鏉℃敮鎸丏ocker_VM鐨勯暱瀹夐摼锛屼互鍙婇暱瀹夐摼CMC宸ュ叿锛岀敤浜庡皢鍐欑紪鍐欏ソ鐨勫悎绾︼紝閮ㄧ讲鍒伴摼涓婅繘琛屾祴璇曘€傜浉鍏冲畨瑁呮暀绋嬭璇﹁锛� - [閮ㄧ讲鏀寔Docker_VM鐨勯暱瀹夐摼鏁欑▼銆俔(./鍚姩鏀寔Docker_VM鐨勯摼.md) - [閮ㄧ讲闀垮畨閾綜MC宸ュ叿鐨勬暀绋嬨€俔(../dev/鍛戒护琛屽伐鍏�.md) ## 缂栧啓Golang鍚堢害 ### 閫氳繃go.mod寮曠敤鍚堢害SDK ChainMaker瀹樻柟Golang鍚堢害SDK鏀寔閫氳繃go.mod鐨勬柟寮忓紩鐢紝鍙洿鎺ヤ娇鐢╣o get寮曠敤锛岀ず渚嬪涓嬶細 ```shell $ go get chainmaker.org/chainmaker/contract-sdk-go/v2@v2.3.4 ``` 鎵ц瀹屾垚鍚庯紝鍗冲彲鍙傝€冧笅鏂囩殑缂栧啓鍚堢害娉ㄦ剰浜嬮」锛岃皟鐢ㄥ悎绾dk鐨勬柟娉曪紝缂栧啓鍚堢害銆� ### 缂栧啓鍚堢害娉ㄦ剰浜嬮」 1. 浠g爜鍏ュ彛鍖呭悕蹇呴』涓篳main` 2. 浠g爜鍏ュ彛 ```go package main // sdk浠g爜涓紝鏈変笖浠呮湁涓€涓猰ain()鏂规硶 func main() { // main()鏂规硶涓紝涓嬮潰鐨勪唬鐮佷负蹇呴』浠g爜锛屼笉寤鸿淇敼main()鏂规硶褰撲腑鐨勪唬鐮� // 鍏朵腑锛孴estContract涓虹敤鎴峰疄鐜板悎绾︾殑鍏蜂綋鍚嶇О err := sandbox.Start(new(FactContract)) if err != nil { log.Fatal(err) } } ``` 3. 鍚堢害蹇呰浠g爜 ```go // 鍚堢害缁撴瀯浣擄紝鍚堢害鍚嶇О闇€瑕佸啓鍏ain()鏂规硶褰撲腑 type FactContract struct { } // 鍚堢害蹇呴』瀹炵幇涓嬮潰涓や釜鏂规硶锛� // InitContract() protogo.Response // UpgradeContract() protogo.Response // InvokeContract(method string) protogo.Response // 鐢ㄤ簬鍚堢害鐨勯儴缃� // @return: 鍚堢害杩斿洖缁撴灉锛屽寘鎷琒uccess鍜孍rror func (f *FactContract) InitContract() protogo.Response { return sdk.Success([]byte("Init contract success")) } // 鐢ㄤ簬鍚堢害鐨勫崌绾� // @return: 鍚堢害杩斿洖缁撴灉锛屽寘鎷琒uccess鍜孍rror func (f *FactContract) UpgradeContract() protogo.Response { return sdk.Success([]byte("Upgrade contract success")) } // 鐢ㄤ簬鍚堢害鐨勮皟鐢� // @param method: 浜ゆ槗璇锋眰璋冪敤鐨勬柟娉� // @return: 鍚堢害杩斿洖缁撴灉锛屽寘鎷琒uccess鍜孍rror func (f *FactContract) InvokeContract(method string) protogo.Response { switch method { case "save": return f.save() case "findByFileHash": return f.findByFileHash() default: return sdk.Error("invalid method") } } ``` ### 鍚堢害SDK鎺ュ彛鎻忚堪 闀垮畨閾炬彁渚沢olang鍚堢害涓庨摼浜や簰鐨勭浉鍏虫帴鍙o紝鍐欏悎绾︽椂鍙洿鎺ュ鍏ュ寘锛屽苟杩涜寮曠敤锛屽叿浣撲俊鎭彲鍙傝€冩枃绔犳湯灏�"鎺ュ彛鎻忚堪绔犺妭"銆� ### 缂栬瘧鍚堢害 褰撳悎绾︾紪鍐欏畬鎴愬悗锛屽垯闇€瑕佺紪璇戝悎绾︼紝鍏蜂綋鏁欑▼濡備笅 #### 浣跨敤鑴氭湰缂栬瘧鍚堢害 1. 鍦ㄥ悎绾﹀伐绋嬩腑娣诲姞缂栬瘧鑴氭湰build.sh鎼缓缂栬瘧鐜銆� ```shell #!/bin/bash contractName=$1 if [[ ! -n $contractName ]] ;then echo "contractName is empty. use as: ./build.sh contractName" exit 1 fi go build -ldflags="-s -w" -o $contractName 7z a $contractName $contractName rm -f $contractName ``` 2. 缂栬瘧鎾板啓濂界殑鏅鸿兘鍚堢害銆� 鍏朵腑ContractName璇锋浛鎹㈡垚闇€瑕佸畨瑁呯殑鍚堢害鍚嶇О ```shell ./build.sh ContractName ``` 缂栬瘧鎴愬姛锛屽涓嬪浘鎵€绀猴細 <img loading="lazy" src="../images/go-vm-contract-build_success.png" style="zoom:70%;" /> #### 鎵嬪姩缂栬瘧鍚堢害 鎵嬪姩缂栬瘧鍚堢害鏃讹紝棣栧厛浣跨敤golang缂栬瘧鎴愬彲鎵ц鏂囦欢锛屽啀瀵圭紪璇戝悗鐨勫彲鎵ц鏂囦欢杩涜7zip鍘嬬缉锛屽帇缂╁悗鐨�".7z"鏂囦欢涓哄悎绾︽枃浠躲€� 鍙傝€冨涓嬬紪璇戝懡浠わ細 ```shell go build -ldflags="-s -w" -o contract_name 7z a contract_name contract_name ``` 闇€瑕佹敞鎰忕殑鏄細鍚堢害鐨勬墽琛岀幆澧冧负linux鐜锛岄渶瑕佷繚璇佹槸鍦↙inux鐜涓嬬紪璇戙€傚鏋滃湪鍏朵粬绯荤粺鐜锛坢ac鎴杦indows锛変笅缂栬瘧鍚堢害锛岃鍙傝€僄olang鐨勪氦鍙夌紪璇戜慨鏀筭o build鍛戒护銆� ### 閮ㄧ讲璋冪敤鍚堢害 缂栬瘧瀹屾垚鍚庯紝灏嗗緱鍒颁竴涓猔.7z`鏍煎紡鐨勫悎绾︽枃浠讹紝鍙皢涔嬮儴缃插埌鎸囧畾鍒伴暱瀹夐摼涓婏紝瀹屾垚鍚堢害閮ㄧ讲銆� 閮ㄧ讲鍚堢害鐨勪娇鐢ㄦ暀绋嬪彲璇﹁锛歔閮ㄧ讲绀轰緥鍚堢害](./閮ㄧ讲绀轰緥鍚堢害.md)銆� ## 绀轰緥鍚堢害浣跨敤婕旂ず ### 绀轰緥浠g爜璇存槑 ChainMaker瀹樻柟鎻愪緵浜嗛€氳繃go.mod寮曠敤鍚堢害SDK杩涜鍚堢害寮€鍙戠殑绀轰緥鍚堢害宸ョ▼銆� 浠ュ瓨璇佸悎绾︿负渚嬶紝鍙互鐩存帴涓嬭浇涓嬬紪璇戝瓨璇佸悎绾︼紝杩囩▼濡備笅锛� ```shell $ git clone --depth=1 https://git.chainmaker.org.cn/contracts/contracts-go.git $ cd contracts-go/fact $ ./build.sh fact ... ``` 鏇村鍚堢害绀轰緥鍙互鐩存帴鏌ョ湅浠撳簱[contracts-go](https://git.chainmaker.org.cn/contracts/contracts-go) ### 瀛樿瘉鍚堢害绀轰緥婧愮爜灞曠ず 鍙傝€僛瀛樿瘉鍚堢害绀轰緥婧愮爜](https://git.chainmaker.org.cn/chainmaker/contract-sdk-go/-/blob/v2.3.3/demo/contract_fact.go) ### 閮ㄧ讲璋冪敤绀轰緥鍚堢害 #### 浣跨敤cmc宸ュ叿閮ㄧ讲璋冪敤鍚堢害 ```shell ## 鍒涘缓鍚堢害 ./cmc client contract user create \ --contract-name=fact \ --runtime-type=DOCKER_GO \ --byte-code-path=./testdata/claim-docker-go-demo/docker-fact.7z \ --version=1.0 \ --sdk-conf-path=./testdata/sdk_config.yml \ --admin-key-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.key \ --admin-crt-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.crt \ --sync-result=true \ --params="{}" ## 璋冪敤鍚堢害 ./cmc client contract user invoke \ --contract-name=fact \ --method=save \ --sdk-conf-path=./testdata/sdk_config.yml \ --params="{\"file_name\":\"name007\",\"file_hash\":\"ab3456df5799b87c77e7f88\",\"time\":\"6543234\"}" \ --sync-result=true ## 鏌ヨ鍚堢害 ./cmc client contract user get \ --contract-name=fact \ --method=findByFileHash \ --sdk-conf-path=./testdata/sdk_config.yml \ --params="{\"file_hash\":\"ab3456df5799b87c77e7f88\"}" ``` #### 浣跨敤Go SDK閮ㄧ讲璋冪敤鍚堢害 ```go // 鍒涘缓鍚堢害 func testUserContractCreate(client *sdk.ChainClient, withSyncResult bool, isIgnoreSameContract bool, usernames ...string) { resp, err := createUserContract(client, factContractName, factVersion, factByteCodePath, common.RuntimeType_DOCKER_GO, []*common.KeyValuePair{}, withSyncResult, usernames...) if !isIgnoreSameContract { if err != nil { log.Fatalln(err) } } fmt.Printf("CREATE claim contract resp: %+v\n", resp) } func createUserContract(client *sdk.ChainClient, contractName, version, byteCodePath string, runtime common.RuntimeType, kvs []*common.KeyValuePair, withSyncResult bool, usernames ...string) (*common.TxResponse, error) { payload, err := client.CreateContractCreatePayload(contractName, version, byteCodePath, runtime, kvs) if err != nil { return nil, err } endorsers, err := examples.GetEndorsers(payload, usernames...) if err != nil { return nil, err } resp, err := client.SendContractManageRequest(payload, endorsers, createContractTimeout, withSyncResult) if err != nil { return nil, err } err = examples.CheckProposalRequestResp(resp, true) if err != nil { return nil, err } return resp, nil } // 璋冪敤鍚堢害 // 璋冪敤鎴栬€呮煡璇㈠悎绾︽椂锛宮ethod鍙傛暟璇疯缃负 invoke_contract锛屾鏂规硶浼氳皟鐢ㄥ悎绾︾殑InvokeContract鏂规硶锛屽啀閫氳繃鍙傛暟鑾峰緱鍏蜂綋鏂规硶 func testUserContractInvoke(client *sdk.ChainClient, method string, withSyncResult bool) (string, error) { curTime := strconv.FormatInt(time.Now().Unix(), 10) fileHash := uuid.GetUUID() kvs := []*common.KeyValuePair{ { Key: "method", Value: []byte("save"), }, { Key: "time", Value: []byte(curTime), }, { Key: "file_hash", Value: []byte(fileHash), }, { Key: "file_name", Value: []byte(fmt.Sprintf("file_%s", curTime)), }, } err := invokeUserContract(client, factContractName, method, "", kvs, withSyncResult) if err != nil { return "", err } return fileHash, nil } func invokeUserContract(client *sdk.ChainClient, contractName, method, txId string, kvs []*common.KeyValuePair, withSyncResult bool) error { resp, err := client.InvokeContract(contractName, method, txId, kvs, -1, withSyncResult) if err != nil { return err } if resp.Code != common.TxStatusCode_SUCCESS { return fmt.Errorf("invoke contract failed, [code:%d]/[msg:%s]\n", resp.Code, resp.Message) } if !withSyncResult { fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[txId:%s]\n", resp.Code, resp.Message, resp.ContractResult.Result) } else { fmt.Printf("invoke contract success, resp: [code:%d]/[msg:%s]/[contractResult:%s]\n", resp.Code, resp.Message, resp.ContractResult) } return nil } ``` ## 鎺ュ彛鎻忚堪 鐢ㄦ埛涓庨摼浜や簰鎺ュ彛锛屽弬鑰冿細[Golang鍚堢害鎺ュ彛璇存槑](https://git.chainmaker.org.cn/chainmaker/contract-sdk-go/-/blob/v2.3.3/sdk/sdk_interface.go)