# Go SDK 浣跨敤璇存槑

<span id="section_sdk"></span>

鏈瘒浠嬬粛锛�

1銆佺幆澧冧緷璧�

2銆乻dk渚濊禆浣跨敤

3銆佹櫘閫氬悎绾﹀畨瑁呫€佽皟鐢�

4銆丒VM鍚堢害瀹夎銆佽皟鐢�

5銆佹洿澶氱殑绀轰緥鍙婂叏閮ㄦ帴鍙�

## 闀垮畨閾維DK姒傝堪

1. 鏁翠綋浠嬬粛

闀垮畨閾綻SDK`鏄笟鍔℃ā鍧椾笌闀垮畨閾句氦浜掔殑妗ユ锛屾敮鎸佸弻鍚慲TLS`璁よ瘉锛屾彁渚涘畨鍏ㄥ彲闈犵殑鍔犲瘑閫氫俊淇¢亾銆�

闀垮畨閾炬彁渚涗簡澶氱璇█鐨刞SDK`锛屽寘鎷細`Go SDK`銆乣Java SDK`銆乣Python SDK`銆乣Nodejs SDK`鏂逛究寮€鍙戣€呮牴鎹渶瑕佽繘琛岄€夌敤銆�

鎻愪緵鐨刞SDK`鎺ュ彛锛岃鐩栧悎绾︾鐞嗐€侀摼閰嶇疆绠$悊銆佽瘉涔︾鐞嗐€佸绛炬敹闆嗐€佸悇绫绘煡璇㈡搷浣溿€佷簨浠惰闃呯瓑鍦烘櫙锛屾弧瓒充簡涓嶅悓鐨勪笟鍔″満鏅渶瑕併€�

2. 鍚嶈瘝姒傚康璇存槑

- **`Node`锛堣妭鐐癸級**锛氫唬琛ㄤ竴涓摼鑺傜偣鐨勫熀鏈俊鎭紝鍖呮嫭锛氳妭鐐瑰湴鍧€銆佽繛鎺ユ暟銆佹槸鍚﹀惎鐢╜TLS`璁よ瘉绛変俊鎭�
- **`ChainClient`锛堥摼瀹㈡埛绔級**锛氭墍鏈夊鎴风瀵归摼鑺傜偣鐨勬搷浣滄帴鍙i兘鏉ヨ嚜`ChainClient`
- **鍘嬬缉璇佷功**锛氬彲浠ヤ负`ChainClient`寮€鍚瘉涔﹀帇缂╁姛鑳斤紝寮€鍚悗鍙互鍑忓皬浜ゆ槗鍖呭ぇ灏忥紝鎻愬崌澶勭悊鎬ц兘

## 鐜鍑嗗

### 杞欢鐜渚濊禆

**golang** 锛� 鐗堟湰涓�1.16鎴栦互涓�

涓嬭浇鍦板潃锛�<https://golang.org/dl/>

鑻ュ凡瀹夎锛岃閫氳繃鍛戒护鏌ョ湅鐗堟湰锛�

```bash
$ go version
go version go1.16 linux/amd64
```

### 涓嬭浇瀹夎sdk
杩涘叆鎮ㄧ殑Go椤圭洰锛屾墽琛屼互涓嬪懡浠ゆ坊鍔犲sdk鐨勫紩鐢細
```bash
go get chainmaker.org/chainmaker/sdk-go/v2@v2.3.3
```

### 闀垮畨閾剧幆澧冨噯澶�

鍒涘缓涓€鏉¤瘉涔︽ā寮忕殑闀垮畨閾撅紝骞剁‘淇濈浉鍏宠妭鐐圭綉缁滈€氱晠锛岀浉鍏虫暀绋嬭锛歔銆婇€氳繃鍛戒护琛屼綋楠岄摼銆媇(../quickstart/閫氳繃鍛戒护琛屼綋楠岄摼.md)

## 鎬庝箞浣跨敤SDK

### 绀轰緥浠g爜
#### 鍒涘缓鑺傜偣

璁剧疆鑺傜偣淇℃伅锛屽彲鐢ㄤ綔鍒涘缓涓庤鑺傜偣杩炴帴鐨勫鎴风

```go
// 鍒涘缓鑺傜偣
func createNode(nodeAddr string, connCnt int) *NodeConfig {
 node := NewNodeConfig(
  // 鑺傜偣鍦板潃锛屾牸寮忥細127.0.0.1:12301
  WithNodeAddr(nodeAddr),
  // 鑺傜偣杩炴帴鏁�
  WithNodeConnCnt(connCnt),
  // 鑺傜偣鏄惁鍚敤TLS璁よ瘉
  WithNodeUseTLS(true),
  // 鏍硅瘉涔﹁矾寰勶紝鏀寔澶氫釜
  WithNodeCAPaths(caPaths),
  // TLS Hostname
  WithNodeTLSHostName(tlsHostName),
 )

 return node
}
```

#### 浠ュ弬鏁板舰寮忓垱寤篊hainClient

> 鏇村鍐呭璇峰弬鐪嬶細`sdk_client_test.go`
>
> 娉細绀轰緥涓瘉涔﹂噰鐢ㄨ矾寰勬柟寮忓幓璁剧疆锛屼篃鍙互浣跨敤璇佷功鍐呭鍘昏缃紝鍏蜂綋璇峰弬鐪媊createClientWithCaCerts`鏂规硶

```go
// 鍒涘缓ChainClient
func createClient() (*ChainClient, error) {
 if node1 == nil {
  // 鍒涘缓鑺傜偣1
  node1 = createNode(nodeAddr1, connCnt1)
 }

 if node2 == nil {
  // 鍒涘缓鑺傜偣2
  node2 = createNode(nodeAddr2, connCnt2)
 }

 chainClient, err := NewChainClient(
  // 璁剧疆褰掑睘缁勭粐
  WithChainClientOrgId(chainOrgId),
  // 璁剧疆閾綢D
  WithChainClientChainId(chainId),
  // 璁剧疆logger鍙ユ焺锛岃嫢涓嶈缃紝灏嗛噰鐢ㄩ粯璁ゆ棩蹇楁枃浠惰緭鍑烘棩蹇�
  WithChainClientLogger(getDefaultLogger()),
  // 璁剧疆瀹㈡埛绔敤鎴风閽ヨ矾寰�
  WithUserKeyFilePath(userKeyPath),
  // 璁剧疆瀹㈡埛绔敤鎴疯瘉涔�
  WithUserCrtFilePath(userCrtPath),
  // 娣诲姞鑺傜偣1
  AddChainClientNodeConfig(node1),
  // 娣诲姞鑺傜偣2
  AddChainClientNodeConfig(node2),
  )

 if err != nil {
  return nil, err
 }

 //鍚敤璇佷功鍘嬬缉锛堝紑鍚瘉涔﹀帇缂╁彲浠ュ噺灏忎氦鏄撳寘澶у皬锛屾彁鍗囧鐞嗘€ц兘锛�
 err = chainClient.EnableCertHash()
 if err != nil {
  log.Fatal(err)
 }

 return chainClient, nil
}
```

#### 浠ラ厤缃枃浠跺舰寮忓垱寤篊hainClient

> 娉細鍙傛暟褰㈠紡鍜岄厤缃枃浠跺舰寮忎袱涓彲浠ュ悓鏃朵娇鐢紝鍚屾椂閰嶇疆鏃讹紝浠ュ弬鏁颁紶鍏ヤ负鍑�

```go
func createClientWithConfig() (*ChainClient, error) {

 chainClient, err := NewChainClient(
  WithConfPath("./testdata/sdk_config.yml"),
 )

 if err != nil {
  return nil, err
 }

 //鍚敤璇佷功鍘嬬缉锛堝紑鍚瘉涔﹀帇缂╁彲浠ュ噺灏忎氦鏄撳寘澶у皬锛屾彁鍗囧鐞嗘€ц兘锛�
 err = chainClient.EnableCertHash()
 if err != nil {
  return nil, err
 }

 return chainClient, nil
}
```

#### 閮ㄧ讲wasm鍚堢害

涓嬫枃锛屽皢婕旂ず閫氳繃sdk閮ㄧ讲wasm鍚堢害锛�

> `sdk_user_contract_claim_test.go`

```go
func testUserContractClaimCreate(t *testing.T, client *ChainClient,
 admin1, admin2, admin3, admin4 *ChainClient, withSyncResult bool, isIgnoreSameContract bool) {

 resp, err := createUserContract(client, admin1, admin2, admin3, admin4,
  claimContractName, claimVersion, claimByteCodePath, common.RuntimeType_WASMER, []*common.KeyValuePair{}, withSyncResult)
 if !isIgnoreSameContract {
  require.Nil(t, err)
 }

 fmt.Printf("CREATE claim contract resp: %+v\n", resp)
}

func createUserContract(client *ChainClient, admin1, admin2, admin3, admin4 *ChainClient,
 contractName, version, byteCodePath string, runtime common.RuntimeType, kvs []*common.KeyValuePair, withSyncResult bool) (*common.TxResponse, error) {

 payloadBytes, err := client.CreateContractCreatePayload(contractName, version, byteCodePath, runtime, kvs)
 if err != nil {
  return nil, err
 }

 // 鍚勭粍缁嘇dmin鏉冮檺鐢ㄦ埛绛惧悕
 signedPayloadBytes1, err := admin1.SignContractManagePayload(payloadBytes)
 if err != nil {
  return nil, err
 }

 signedPayloadBytes2, err := admin2.SignContractManagePayload(payloadBytes)
 if err != nil {
  return nil, err
 }

 signedPayloadBytes3, err := admin3.SignContractManagePayload(payloadBytes)
 if err != nil {
  return nil, err
 }

 signedPayloadBytes4, err := admin4.SignContractManagePayload(payloadBytes)
 if err != nil {
  return nil, err
 }

 // 鏀堕泦骞跺悎骞剁鍚�
 mergeSignedPayloadBytes, err := client.MergeContractManageSignedPayload([][]byte{signedPayloadBytes1,
  signedPayloadBytes2, signedPayloadBytes3, signedPayloadBytes4})
 if err != nil {
  return nil, err
 }

 // 鍙戦€佸垱寤哄悎绾﹁姹�
 resp, err := client.SendContractManageRequest(mergeSignedPayloadBytes, createContractTimeout, withSyncResult)
 if err != nil {
  return nil, err
 }

 err = checkProposalRequestResp(resp, true)
 if err != nil {
  return nil, err
 }

 return resp, nil
```

#### 璋冪敤wasm鍚堢害

涓嬫枃锛屽皢婕旂ず閫氳繃sdk璋冪敤wasm鍚堢害锛�

> `sdk_user_contract_claim_test.go`

```go
func testUserContractClaimInvoke(client *ChainClient,
 method string, withSyncResult bool) (string, error) {

 curTime := fmt.Sprintf("%d", CurrentTimeMillisSeconds())
 fileHash := uuid.GetUUID()
 params := map[string]string{
  "time":      curTime,
  "file_hash": fileHash,
  "file_name": fmt.Sprintf("file_%s", curTime),
 }

 err := invokeUserContract(client, claimContractName, method, "", params, withSyncResult)
 if err != nil {
  return "", err
 }

 return fileHash, nil
}

func invokeUserContract(client *ChainClient, contractName, method, txId string, params map[string]string, withSyncResult bool) error {

 resp, err := client.InvokeContract(contractName, method, txId, params, -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
}
```

#### 鍒涘缓鍙婅皟鐢╡vm鍚堢害

> `sdk-go/examples/user_contract_evm_balance/main.go`(<https://git.chainmaker.org.cn/chainmaker/sdk-go/-/blob/master/examples/user_contract_evm_balance/main.go>)

### 鏇村绀轰緥鍜岀敤娉�

> 鏇村绀轰緥鍜岀敤娉曪紝璇峰弬鐪嬪崟鍏冩祴璇曠敤渚�
<br>绀轰緥: (<https://git.chainmaker.org.cn/chainmaker/sdk-go/-/blob/master/examples>)

| 鍔熻兘     | 鍗曟祴浠g爜                      |
| -------- | ----------------------------- |
| 鐢ㄦ埛鍚堢害 | `sdk_user_contract_test.go`   |
| 绯荤粺鍚堢害 | `sdk_system_contract_test.go` |
| 閾鹃厤缃�   | `sdk_chain_config_test.go`    |
| 璇佷功绠$悊 | `sdk_cert_manage_test.go`     |
| 娑堟伅璁㈤槄 | `sdk_subscribe_test.go`       |

### demo

sdk-go demo鍙傝€冿細

[鏂囦欢 路 v2.3.2 路 chainmaker / sdk-go-demo 路 ChainMaker](https://git.chainmaker.org.cn/chainmaker/sdk-go-demo/-/tree/v2.3.2)

## 鎺ュ彛璇存槑

璇峰弬鐪嬶細[銆奵hainmaker-go-sdk銆媇(https://git.chainmaker.org.cn/chainmaker/sdk-go/-/blob/v2.3.3/sdk_interface.md)
鎵€鏈塯o-sdk鎺ュ彛鍙傝€冿細 https://git.chainmaker.org.cn/chainmaker/sdk-go/-/blob/v2.3.3/sdk_interface.go