/* Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. SPDX-License-Identifier: Apache-2.0 */ package chain import ( "encoding/base64" "encoding/pem" "errors" "fmt" "chainmaker.org/chainmaker/common/v2/crypto/x509" chainmaker_sdk_go "chainmaker.org/chainmaker/sdk-go/v2" ) // NodeConf add next time // @Description: type NodeConf struct { Url string EnableTls bool TlsHostName string UserTlsCert string UserTlsKey string } // createSDKClient 创建 sdk client // // @Description: // @param nodeConfs // @param chainId // @param chainMode // @param userKey // @param userCert // @param hashMethod // @return *chainmaker_sdk_go.ChainClient // @return error func createSDKClient(nodeConfs []NodeConf, chainId, chainMode, signKey, signCert, hashMethod, orgId, caCert string) (sdkClient *chainmaker_sdk_go.ChainClient, err error) { rpcConf := chainmaker_sdk_go.NewRPCClientConfig( chainmaker_sdk_go.WithRPCClientGetTxTimeout(60), chainmaker_sdk_go.WithRPCClientSendTxTimeout(60), chainmaker_sdk_go.WithRPCClientMaxReceiveMessageSize(100), chainmaker_sdk_go.WithRPCClientMaxSendMessageSize(100), ) cryptoConf := chainmaker_sdk_go.NewCryptoConfig( chainmaker_sdk_go.WithHashAlgo(hashMethod), ) sdkClientOpts := []chainmaker_sdk_go.ChainClientOption{ chainmaker_sdk_go.WithChainClientChainId(chainId), chainmaker_sdk_go.WithCryptoConfig(cryptoConf), chainmaker_sdk_go.WithRetryInterval(500), chainmaker_sdk_go.WithRetryLimit(20), chainmaker_sdk_go.WithEnableNormalKey(false), chainmaker_sdk_go.WithRPCClientConfig(rpcConf), } // 解码 ca cert caStr, err := base64.StdEncoding.DecodeString(caCert) if err != nil { return nil, fmt.Errorf("failed to base64 decode caCert,err: %v", err) } // 添加多个 node 配置 userTlsCert := "" userTlsKey := "" for _, n := range nodeConfs { nodeConf := chainmaker_sdk_go.NewNodeConfig( chainmaker_sdk_go.WithNodeAddr(n.Url), chainmaker_sdk_go.WithNodeConnCnt(10), chainmaker_sdk_go.WithNodeUseTLS(n.EnableTls), chainmaker_sdk_go.WithNodeTLSHostName(n.TlsHostName), // 如果是开启 tls,必须传 CaCert chainmaker_sdk_go.WithNodeCACerts([]string{string(caStr)}), ) sdkClientOpts = append(sdkClientOpts, chainmaker_sdk_go.AddChainClientNodeConfig(nodeConf)) // 任意取一个节点的 userTlsCert 和 userTlsKey if n.UserTlsCert != "" && n.UserTlsKey != "" { userTlsCert = n.UserTlsCert userTlsKey = n.UserTlsKey } } key, err := base64.StdEncoding.DecodeString(signKey) if err != nil { return nil, fmt.Errorf("failed to base64 decode signKey,err: %v", err) } switch chainMode { case KEY_MODE_PK: sdkClientOpts = append(sdkClientOpts, chainmaker_sdk_go.WithAuthType("public"), // 这里是用于签名的 chainmaker_sdk_go.WithUserSignKeyBytes(key), ) case KEY_MODE_CERT: userKey, err1 := base64.StdEncoding.DecodeString(userTlsKey) if err1 != nil { return nil, fmt.Errorf("failed to base64 decode userTlsKey,err: %v", err1) } userCert, err1 := base64.StdEncoding.DecodeString(userTlsCert) if err1 != nil { return nil, fmt.Errorf("failed to base64 decode userTlsCert,err: %v", err1) } sCert, err1 := base64.StdEncoding.DecodeString(signCert) if err1 != nil { return nil, fmt.Errorf("failed to base64 decode signCert,err: %v", err1) } sdkClientOpts = append(sdkClientOpts, chainmaker_sdk_go.WithAuthType("permissionedwithcert"), chainmaker_sdk_go.WithChainClientOrgId(orgId), // 这两个参数是证书模式下,用于验证节点端证书有效性的,并不是签名用的 chainmaker_sdk_go.WithUserKeyBytes(userKey), chainmaker_sdk_go.WithUserCrtBytes(userCert), // 这里是用于签名的 chainmaker_sdk_go.WithUserSignKeyBytes(key), chainmaker_sdk_go.WithUserSignCrtBytes(sCert), ) } if signKey != "" { sdkClient, err = chainmaker_sdk_go.NewChainClient(sdkClientOpts...) if err != nil { return nil, fmt.Errorf("failed to new sdk client,err: %v", err) } } else { sdkClient, err = chainmaker_sdk_go.NewChainClientWithoutKey(sdkClientOpts...) if err != nil { return nil, fmt.Errorf("failed to new sdk client without sign key,err: %v", err) } } return sdkClient, nil } // CreateSDKClient 创建 sdk client // // @Description: // @param nodeConfs // @param chainId // @param chainMode // @param userKey // @param userCert // @param hashMethod // @return *chainmaker_sdk_go.ChainClient // @return error func CreateSDKClient(nodeConfs []NodeConf, chainId, chainMode, signKey, signCert, hashMethod, orgId, caCert string) (*chainmaker_sdk_go.ChainClient, error) { return createSDKClient(nodeConfs, chainId, chainMode, signKey, signCert, hashMethod, orgId, caCert) } // CreateSDKClientWithoutKey 创建 sdk client 不带签名 key // // @Description: // @param nodeConfs // @param chainId // @param chainMode // @param hashMethod // @return *chainmaker_sdk_go.ChainClient // @return error func CreateSDKClientWithoutKey(nodeConfs []NodeConf, chainId, chainMode, orgId, caCert string) (*chainmaker_sdk_go.ChainClient, error) { return createSDKClient(nodeConfs, chainId, chainMode, "", "", "", orgId, caCert) } // GetOrgId 获取证书中的 org id // // @Description: // @param cert // @return string // @return error func GetOrgId(cert []byte) (string, error) { pemBlock, _ := pem.Decode(cert) if pemBlock == nil { return "", errors.New("invalid pem format cert") } c, err := x509.ParseCertificate(pemBlock.Bytes) if err != nil { return "", fmt.Errorf("failed to x509 parse cert,err: %v", err) } orgId := "" if len(c.Issuer.Organization) > 0 { orgId = c.Issuer.Organization[0] } return orgId, nil }