# ChainMaker Go SDK README ## 基本概念 - **Node(节点)**:代表一个链节点的基本信息,包括:节点地址、连接数、是否启用`TLS`认证等信息 - **ChainClient(链客户端)**:所有客户端对链节点的操作接口都来自`ChainClient` - **压缩证书**:可以为`ChainClient`开启证书压缩功能,开启后可以减小交易包大小,提升处理性能 ## 下载安装 ```bash $ git clone --recursive -b v1.1.1 https://git.chainmaker.org.cn/chainmaker/chainmaker-sdk-go.git ``` ## 使用示例 ### 创建节点 ```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 } ``` ### 创建ChainClient ```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), // 设置链ID 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 } ``` ### 接口调用 具体接口调用示例,请参看单元测试用例中的用法。 | 功能 | 单测代码 | | -------- | --------------------------- | | 用户合约 | sdk_user_contract_test.go | | 系统合约 | sdk_system_contract_test.go | | 链配置 | sdk_chain_config_test.go | | 证书管理 | sdk_cert_manage_test.go | | 消息订阅 | sdk_subscribe_test.go | ## 接口说明 ### 用户合约接口 #### 创建合约待签名payload生成 **参数说明** - contractName: 合约名 - version: 版本号 - byteCode: 支持传入合约二进制文件路径或Base64编码的二进制内容 - runtime: 合约运行环境 - kvs: 合约初始化参数 ```go CreateContractCreatePayload(contractName, version, byteCode string, runtime common.RuntimeType, kvs []*common.KeyValuePair) ([]byte, error) ``` #### 升级合约待签名payload生成 **参数说明** - contractName: 合约名 - version: 版本号 - byteCode: 支持传入合约二进制文件路径或Base64编码的二进制内容 - runtime: 合约运行环境 - kvs: 合约升级参数 ```go CreateContractUpgradePayload(contractName, version, byteCode string, runtime common.RuntimeType, kvs []*common.KeyValuePair) ([]byte, error) ``` #### 冻结合约payload生成 **参数说明** - contractName: 合约名 ```go CreateContractFreezePayload(contractName string) ([]byte, error) ``` #### 解冻合约payload生成 **参数说明** - contractName: 合约名 ```go CreateContractUnfreezePayload(contractName string) ([]byte, error) ``` #### 吊销合约payload生成 **参数说明** - contractName: 合约名 ```go CreateContractRevokePayload(contractName string) ([]byte, error) ``` #### 合约管理获取Payload签名 **参数说明** - payloadBytes: 待签名payload ```go SignContractManagePayload(payloadBytes []byte) ([]byte, error) ``` #### 合约管理Payload签名收集&合并 **参数说明** - signedPayloadBytes: 已签名payload列表 ```go MergeContractManageSignedPayload(signedPayloadBytes [][]byte) ([]byte, error) ``` #### 发送合约管理请求(创建、更新、冻结、解冻、吊销) **参数说明** - multiSignedPayload: 多签结果 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s - withSyncResult: 是否同步获取交易执行结果 当为true时,若成功调用,common.TxResponse.ContractResult.Result为common.TransactionInfo 当为false时,若成功调用,common.TxResponse.ContractResult.Result为txId ```go SendContractManageRequest(mergeSignedPayloadBytes []byte, timeout int64, withSyncResult bool) (*common.TxResponse, error) ``` #### 合约调用 **参数说明** - contractName: 合约名称 - method: 合约方法 - txId: 交易ID 格式要求:长度为64字节,字符在a-z0-9 可为空,若为空字符串,将自动生成txId - params: 合约参数 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s - withSyncResult: 是否同步获取交易执行结果 当为true时,若成功调用,common.TxResponse.ContractResult.Result为common.TransactionInfo 当为false时,若成功调用,common.TxResponse.ContractResult.Result为txId ```go InvokeContract(contractName, method, txId string, params map[string]string, timeout int64, withSyncResult bool) (*common.TxResponse, error) ``` #### 合约查询接口调用 **参数说明** - contractName: 合约名称 - method: 合约方法 - params: 合约参数 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s ```go QueryContract(contractName, method string, params map[string]string, timeout int64) (*common.TxResponse, error) ``` #### 构造待发送交易体 **参数说明** - contractName: 合约名称 - method: 合约方法 - txId: 交易ID 格式要求:长度为64字节,字符在a-z0-9 可为空,若为空字符串,将自动生成txId - params: 合约参数 ```go GetTxRequest(contractName, method, txId string, params map[string]string) (*common.TxRequest, error) ``` #### 发送已构造好的交易体 **参数说明** - txRequest: 已构造好的交易体 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s - withSyncResult: 是否同步获取交易执行结果 当为true时,若成功调用,common.TxResponse.ContractResult.Result为common.TransactionInfo 当为false时,若成功调用,common.TxResponse.ContractResult.Result为txId ```go SendTxRequest(txRequest *common.TxRequest, timeout int64, withSyncResult bool) (*common.TxResponse, error) ``` ### 系统合约接口 #### 根据交易Id查询交易 **参数说明** - txId: 交易ID ```go GetTxByTxId(txId string) (*common.TransactionInfo, error) ``` #### 根据区块高度查询区块 **参数说明** - blockHeight: 指定区块高度,若为-1,将返回最新区块 - withRWSet: 是否返回读写集 ```go GetBlockByHeight(blockHeight int64, withRWSet bool) (*common.BlockInfo, error) ``` #### 根据区块哈希查询区块 **参数说明** - blockHash: 指定区块Hash - withRWSet: 是否返回读写集 ```go GetBlockByHash(blockHash string, withRWSet bool) (*common.BlockInfo, error) ``` #### 根据交易Id查询区块 **参数说明** - txId: 交易ID - withRWSet: 是否返回读写集 ```go GetBlockByTxId(txId string, withRWSet bool) (*common.BlockInfo, error) ``` #### 查询最新的配置块 **参数说明** - withRWSet: 是否返回读写集 ```go GetLastConfigBlock(withRWSet bool) (*common.BlockInfo, error) ``` #### 查询节点加入的链信息 - 返回ChainId清单 ```go GetNodeChainList() (*discovery.ChainList, error) ``` #### 查询链信息 - 包括:当前链最新高度,链节点信息 ```go GetChainInfo() (*discovery.ChainInfo, error) ``` ### 链配置接口 #### 查询最新链配置 ```go GetChainConfig() (*config.ChainConfig, error) ``` #### 根据指定区块高度查询最近链配置 - 如果当前区块就是配置块,直接返回当前区块的链配置 ```go GetChainConfigByBlockHeight(blockHeight int) (*config.ChainConfig, error) ``` #### 查询最新链配置序号Sequence - 用于链配置更新 ```go GetChainConfigSequence() (int, error) ``` #### 链配置更新获取Payload签名 ```go SignChainConfigPayload(payloadBytes []byte) ([]byte, error) ``` #### 链配置更新Payload签名收集&合并 ```go MergeChainConfigSignedPayload(signedPayloadBytes [][]byte) ([]byte, error) ``` #### 发送链配置更新请求 ```go SendChainConfigUpdateRequest(mergeSignedPayloadBytes []byte) (*common.TxResponse, error) ``` 以下CreateChainConfigXXXXXXPayload方法,用于生成链配置待签名payload,在进行多签收集后(需机构Admin权限账号签名),用于链配置的更新 #### 更新Core模块待签名payload生成 **参数说明** - txSchedulerTimeout: 交易调度器从交易池拿到交易后, 进行调度的时间,其值范围为[0, 60],若无需修改,请置为-1 - txSchedulerValidateTimeout: 交易调度器从区块中拿到交易后, 进行验证的超时时间,其值范围为[0, 60],若无需修改,请置为-1 ```go CreateChainConfigCoreUpdatePayload(txSchedulerTimeout, txSchedulerValidateTimeout int) ([]byte, error) ``` #### 更新Core模块待签名payload生成 **参数说明** - txTimestampVerify: 是否需要开启交易时间戳校验 - (以下参数,若无需修改,请置为-1) - txTimeout: 交易时间戳的过期时间(秒),其值范围为[600, +∞) - blockTxCapacity: 区块中最大交易数,其值范围为(0, +∞] - blockSize: 区块最大限制,单位MB,其值范围为(0, +∞] - blockInterval: 出块间隔,单位:ms,其值范围为[10, +∞] ```go CreateChainConfigBlockUpdatePayload(txTimestampVerify bool, txTimeout, blockTxCapacity, blockSize, blockInterval int) ([]byte, error) ``` #### 添加信任组织根证书待签名payload生成 **参数说明** - trustRootOrgId: 组织Id - trustRootCrt: 根证书 ```go CreateChainConfigTrustRootAddPayload(trustRootOrgId, trustRootCrt string) ([]byte, error) ``` #### 更新信任组织根证书待签名payload生成 **参数说明** - trustRootOrgId: 组织Id - trustRootCrt: 根证书 ```go CreateChainConfigTrustRootUpdatePayload(trustRootOrgId, trustRootCrt string) ([]byte, error) ``` #### 删除信任组织根证书待签名payload生成 **参数说明** - trustRootOrgId: 组织Id ```go CreateChainConfigTrustRootDeletePayload(trustRootOrgId string) ([]byte, error) ``` #### 添加权限配置待签名payload生成 **参数说明** - permissionResourceName: 权限名 - policy: 权限规则 ```go CreateChainConfigPermissionAddPayload(permissionResourceName string, policy *accesscontrol.Policy) ([]byte, error) ``` #### 更新权限配置待签名payload生成 **参数说明** - permissionResourceName: 权限名 - policy: 权限规则 ```go CreateChainConfigPermissionUpdatePayload(permissionResourceName string, policy *accesscontrol.Policy) ([]byte, error) ``` #### 删除权限配置待签名payload生成 **参数说明** - permissionResourceName: 权限名 ```go CreateChainConfigPermissionDeletePayload(permissionResourceName string) ([]byte, error) ``` #### 添加共识节点地址待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id - nodeIds: 节点Id ```go CreateChainConfigConsensusNodeIdAddPayload(nodeOrgId string, nodeIds []string) ([]byte, error) ``` #### 更新共识节点地址待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id - nodeOldNodeId: 节点原Id - nodeNewNodeId: 节点新Id ```go CreateChainConfigConsensusNodeIdUpdatePayload(nodeOrgId, nodeOldNodeId, nodeNewNodeId string) ([]byte, error) ``` #### 删除共识节点地址待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id - nodeId: 节点Id ```go CreateChainConfigConsensusNodeIdDeletePayload(nodeOrgId, nodeId string) ([]byte, error) ``` #### 添加共识节点待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id - nodeIds: 节点Id ```go CreateChainConfigConsensusNodeOrgAddPayload(nodeOrgId string, nodeIds []string) ([]byte, error) ``` #### 更新共识节点待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id - nodeIds: 节点Id ```go CreateChainConfigConsensusNodeOrgUpdatePayload(nodeOrgId string, nodeIds []string) ([]byte, error) ``` #### 删除共识节点待签名payload生成 **参数说明** - nodeOrgId: 节点组织Id ```go CreateChainConfigConsensusNodeOrgDeletePayload(nodeOrgId string) ([]byte, error) ``` #### 添加共识扩展字段待签名payload生成 **参数说明** - kvs: 字段key、value对 ```go CreateChainConfigConsensusExtAddPayload(kvs []*common.KeyValuePair) ([]byte, error) ``` #### 添加共识扩展字段待签名payload生成 **参数说明** - kvs: 字段key、value对 ```go CreateChainConfigConsensusExtUpdatePayload(kvs []*common.KeyValuePair) ([]byte, error) ``` #### 添加共识扩展字段待签名payload生成 **参数说明** - keys: 待删除字段 ```go CreateChainConfigConsensusExtDeletePayload(keys []string) ([]byte, error) ``` ### 证书管理接口 #### 用户证书添加 **参数说明** - 在common.TxResponse.ContractResult.Result字段中返回成功添加的certHash ```go AddCert() (*common.TxResponse, error) ``` #### 用户证书删除 **参数说明** - certHashes: 证书Hash列表 ```go DeleteCert(certHashes []string) (*common.TxResponse, error) ``` #### 用户证书查询 **参数说明** - certHashes: 证书Hash列表 返回值说明: - *common.CertInfos: 包含证书Hash和证书内容的列表 ```go QueryCert(certHashes []string) (*common.CertInfos, error) ``` #### 获取用户证书哈希 ```go GetCertHash() ([]byte, error) ``` #### 生成证书管理操作Payload(三合一接口) **参数说明** - method: CERTS_FROZEN(证书冻结)/CERTS_UNFROZEN(证书解冻)/CERTS_REVOCATION(证书吊销) - kvs: 证书管理操作参数 ```go CreateCertManagePayload(method string, kvs []*common.KeyValuePair) ([]byte, error) ``` #### 生成证书冻结操作Payload **参数说明** - certs: X509证书列表 ```go CreateCertManageFrozenPayload(certs []string) ([]byte, error) ``` #### 生成证书解冻操作Payload **参数说明** - certs: X509证书列表 ```go CreateCertManageUnfrozenPayload(certs []string) ([]byte, error) ``` #### 生成证书吊销操作Payload **参数说明** - certs: X509证书列表 ```go CreateCertManageRevocationPayload(certCrl string) ([]byte, error) ``` #### 待签payload签名 *一般需要使用具有管理员权限账号进行签名* **参数说明** - payloadBytes: 待签名payload ```go SignCertManagePayload(payloadBytes []byte) ([]byte, error) ``` #### 证书管理Payload签名收集&合并 **参数说明** - signedPayloadBytes: 已签名payload列表 ```go MergeCertManageSignedPayload(signedPayloadBytes [][]byte) ([]byte, error) ``` #### 发送证书管理请求(证书冻结、解冻、吊销) **参数说明** - multiSignedPayload: 多签结果 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s - withSyncResult: 是否同步获取交易执行结果 当为true时,若成功调用,common.TxResponse.ContractResult.Result为common.TransactionInfo 当为false时,若成功调用,common.TxResponse.ContractResult.Result为txId ```go SendCertManageRequest(mergeSignedPayloadBytes []byte, timeout int64, withSyncResult bool) (*common.TxResponse, error) ``` ### 在线多签接口 #### 待签payload签名 *一般需要使用具有管理员权限账号进行签名* **参数说明** - payloadBytes: 待签名payload ```go SignMultiSignPayload(payloadBytes []byte) (*common.EndorsementEntry, error) ``` #### 多签请求 **参数说明** - txType: 多签payload交易类型 - payloadBytes: 待签名payload - endorsementEntry: 签名收集信息 - deadlineBlockHeight: 过期的区块高度,若设置为0,表示永不过期 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s **返回值** 若成功调用,common.TxResponse.ContractResult.Result为txId ```go SendMultiSignReq(txType common.TxType, payloadBytes []byte, endorsementEntry *common.EndorsementEntry, deadlineBlockHeight int, timeout int64) (*common.TxResponse, error) ``` #### 多签投票 **参数说明** - voteStatus: 投票状态(赞成、反对) - multiSignReqTxId: 多签请求交易ID(txId或payloadHash至少填其一,txId优先) - payloadHash: 待多签payload hash(txId或payloadHash至少填其一,txId优先) - payloadBytes: 待签名payload - endorsementEntry: 签名收集信息 - timeout: 超时时间,单位:s,若传入-1,将使用默认超时时间:10s **返回值** 若成功调用,common.TxResponse.ContractResult.Result为txId ```go SendMultiSignVote(voteStatus common.VoteStatus, multiSignReqTxId, payloadHash string, endorsementEntry *common.EndorsementEntry, timeout int64) (*common.TxResponse, error) ``` #### 投票查询 **参数说明** - multiSignReqTxId: 多签请求交易ID(txId或payloadHash至少填其一,txId优先) - payloadHash: 待多签payload hash(txId或payloadHash至少填其一,txId优先) ```go QueryMultiSignResult(multiSignReqTxId, payloadHash string) (*common.TxResponse, error) ``` ### 消息订阅接口 #### 区块订阅 **参数说明** - startBlock: 订阅起始区块高度,若为-1,表示订阅实时最新区块 - endBlock: 订阅结束区块高度,若为-1,表示订阅实时最新区块 - withRwSet: 是否返回读写集 ```go SubscribeBlock(ctx context.Context, startBlock, endBlock int64, withRwSet bool) (<-chan interface{}, error) ``` #### 交易订阅 **参数说明** - startBlock: 订阅起始区块高度,若为-1,表示订阅实时最新区块 - endBlock: 订阅结束区块高度,若为-1,表示订阅实时最新区块 - txType: 订阅交易类型,若为common.TxType(-1),表示订阅所有交易类型 - txIds: 订阅txId列表,若为空,表示订阅所有txId ```go SubscribeTx(ctx context.Context, startBlock, endBlock int64, txType common.TxType, txIds []string) (<-chan interface{}, error) ``` #### 合约事件订阅 **参数说明** - topic :指定订阅主题 - contractName :指定订阅的合约名称 ```go SubscribeContractEvent(ctx context.Context, topic string, contractName string) (<-chan interface{}, error) ``` #### 多合一订阅 **参数说明** - txType: 订阅交易类型,目前已支持:区块消息订阅(common.TxType_SUBSCRIBE_BLOCK_INFO)、交易消息订阅(common.TxType_SUBSCRIBE_TX_INFO) - payloadBytes: 消息订阅参数payload ```go Subscribe(ctx context.Context, txType common.TxType, payloadBytes []byte) (<-chan interface{}, error) ``` ### 证书压缩 *开启证书压缩可以减小交易包大小,提升处理性能* #### 启用压缩证书功能 ```go EnableCertHash() error ``` #### 停用压缩证书功能 ```go DisableCertHash() error ``` ### 工具类 #### 将EasyCodec编码解码成map ```go EasyCodecItemToParamsMap(items []*serialize.EasyCodecItem) map[string]string ``` #### 根据X.509证书路径得到EVM地址 **参数说明** - certFilePath: 证书文件路径 ```go GetEVMAddressFromCertPath(certFilePath string) (string, error) ``` #### 根据X.509证书内容得到EVM地址 **参数说明** - certBytes: 证书内容 ```go GetEVMAddressFromCertBytes(certBytes []byte) (string, error) ``` ### 层级属性加密类接口 **注意:**层级属性加密模块 `Id` 使用 `/` 作为分隔符,例如: Org1/Ou1/Member1 #### 生成层级属性参数初始化交易 payload **参数说明** - orgId: 参与方组织 id - hibeParams: 传入序列化后的hibeParams byte数组 ```go CreateHibeInitParamsTxPayloadParams(orgId string, hibeParams []byte) (map[string]string, error) ``` #### 生成层级属性加密交易 payload,加密参数已知 **参数说明** - plaintext: 待加密交易消息明文 - receiverIds: 消息接收者 id 列表,需和 paramsList 一一对应 - paramsBytesList: 消息接收者对应的加密参数,需和 receiverIds 一一对应 - txId: 以交易 Id 作为链上存储 hibeMsg 的 Key, 如果不提供存储的信息可能被覆盖 - keyType: 对明文进行对称加密的方法,请传入 common 中 crypto 包提供的方法,目前提供AES和SM4两种方法 ```go CreateHibeTxPayloadParamsWithHibeParams(plaintext []byte, receiverIds []string, paramsBytesList [][]byte, txId string, keyType crypto.KeyType) (map[string]string, error) ``` #### 生成层级属性加密交易 payload,参数由链上查询得出 **参数说明** - contractName: 合约名 - queryParamsMethod: 链上查询 hibe.Params 的合约方法 - plaintext: 待加密交易消息明文 - receiverIds: 消息接收者 id 列表,需和 paramsList 一一对应 - paramsList: 消息接收者对应的加密参数,需和 receiverIds 一一对应 - receiverOrgIds: 链上查询 hibe Params 的 Key 列表,需要和 receiverIds 一一对应 - txId: 以交易 Id 作为链上存储 hibeMsg 的 Key, 如果不提供存储的信息可能被覆盖 - keyType: 对明文进行对称加密的方法,请传入 common 中 crypto 包提供的方法,目前提供AES和SM4两种方法 - timeout: (内部查询 HibeParams 的)超时时间,单位:s,若传入-1,将使用默认超时时间:10s ```go CreateHibeTxPayloadParamsWithoutHibeParams(contractName, queryParamsMethod string, plaintext []byte, receiverIds []string, receiverOrgIds []string, txId string, keyType crypto.KeyType, timeout int64) (map[string]string, error) ``` #### 查询某一组织的加密公共参数,返回其序列化后的byte数组 **参数说明** - contractName: 合约名 - method: 查询的合约方法名 - orgId: 参与方 id - timeout: 查询超时时间,单位:s,若传入-1,将使用默认超时时间:10s ```go QueryHibeParamsWithOrgId(contractName, method, orgId string, timeout int64) ([]byte, error) ``` #### 已知交易id,根据私钥解密密文交易 **参数说明** - localId: 本地层级属性加密 id - hibeParams: hibeParams 序列化后的byte数组 - hibePrivKey: hibe私钥序列化后的byte数组 - txId: 层级属性加密交易 id - keyType: 对加密信息进行对称解密的方法,请和加密时使用的方法保持一致,请传入 common 中 crypto 包提供的方法,目前提供AES和SM4两种方法 ```go DecryptHibeTxByTxId(localId string, hibeParams []byte, hibePrvKey []byte, txId string, keyType crypto.KeyType) ([]byte, error) ``` ### 系统类接口 #### SDK停止接口 *关闭连接池连接,释放资源* ```go Stop() error ``` #### 获取链版本 ```go GetChainMakerServerVersion() (string, error) ```