动手编 SDK | BSN 联盟链开发(二)
人生,总避免不了开发几个 SDK (•̀ω•́ )
> **系列索引:** [上链与背后的流程 | 联盟链开发(一)](https://learnblockchain.cn/article/358) [动手编 SDK | 联盟链开发(二)](https://learnblockchain.cn/article/359) [SDK 1.0 版本的打造 | 联盟链开发(三)](https://learnblockchain.cn/article/380) [将 SDK 发布到 PIP | 联盟链开发(四)](https://learnblockchain.cn/article/385) [什么样的数据应该上链?| 联盟链开发 (五)](https://learnblockchain.cn/article/557) [BSN 相关问与答 | 联盟链开发(六)](https://learnblockchain.cn/article/683) [链上简历应用 — 设计 | 联盟链开发(七)](https://learnblockchain.cn/article/684) [FISCO BCOS 介绍 | 联盟链开发(八)](https://learnblockchain.cn/article/692) [WeIdentity 极速体验 | 联盟链开发(九)](https://learnblockchain.cn/article/1094) [给Remix升个级 | 联盟链开发(十)](https://learnblockchain.cn/article/984) [伪代码简述 ECDSA 签名过程 | 联盟链开发(十一)](https://learnblockchain.cn/article/1038) [WeIdentity 的多签及限量凭证的实现 | 联盟链开发(十二)](https://learnblockchain.cn/article/1285) --- 上回我们使用 BSN 官方提供的示例体验了一下上链操作及简要阐述了一下背后的原理。但是,由于仅为「示例」,所以代码耦合程度较高,要想「为我所用」还需要整理为 SDK。 自然可以将整理出来的代码直接放出来,但是记录与梳理「造轮子」的过程,对于自己的未来工作以及其它人未来的工作都会有帮助,因此我在这里会用几篇文章讲述如何一步步开发 SDK。 ## 1 一个趁手的 SDK 需要哪些要素 SDK 相当于现实生活中的一件工具。 那么,在生活中我们要发明一件让自己和别人使用的工具,需要哪些要素? - **文档友善** —— 需要友善的说明书告诉我怎么使用这个工具 - **可配置性好** —— 该能配置的地方需要配置不要写死 - **返回结果合理** —— 用工具加工出的产品需要在我们的预料之内 ## 2 以 get_data 为例进行函数改造 ### 2.1 解析源码 在官方提供的示例中,找到 views.py > get_data 函数,这个函数起到的作用是从链上查询信息: ```python def get_data(request): logger.info('\n #######进入get_data方法########') if request.method == 'POST': userCode = "reddate" appCode = "CL1851016378620191011150518" chainCode = "cc_base" funcName = "get" baseKey = request.POST.get('baseKey') if len(baseKey.strip()) == 0: return render(request, 'get.html', {'hint': '唯一标识不能为空!'}) logger.info('输入的baseKey:%s', baseKey) str = userCode + appCode + chainCode + funcName + baseKey logger.info('拼接待签名的字符串:%s', str) # 对字符串 A使用户证书的私钥进行 SHA256WITHECDSA签名 mac = myecdsa256.ecdsa_sign(str, './certificate/private_key.pem').decode() logger.info('base64格式mac值:%s', mac) url = 'https://quanzhounode.bsngate.com:17602/api/node/reqChainCode' headers = {'content-type': 'application/json'} datas = {"header": {"userCode": userCode, "appCode": appCode, "tId": "dc1d6010b7ff421dae0146f193dded09"}, "body": {"chainCode": chainCode, "funcName": funcName, "args": [baseKey]}, "mac": mac} logger.info('get_data请求传参:%s', datas) try: r = requests.post(url, headers=headers, json=datas, verify='./certificate/bsn_https.pem') if r.status_code == 200: result = r.json() …… ``` 我们可以看到,这个函数传入了一个 request 参数,然后拿了request 中的 baseKey 这个键的值,再通过一系列写死的参数加上 baseKey,去访问一个 url 最终得到结果。 ### 2.2 函数改造 如果要设计成 SDK 中的函数,那么要做如下改造: - 传入的不应该是request 类型的参数,而应该是一些更基本的值,例如字符串形式的 baseKey。 - 函数应当进一步拆分,拆分为`get_data` 和 `__do_get_data `两个函数,使代码结构更清晰。 因此,首先设计一个函数`get_data(baseKey, url)`: ```python def get_data(baseKey, url): userCode = "reddate" appCode = "CL1851016378620191011150518" chainCode = "cc_base" funcName = "get" if len(baseKey.strip()) == 0: logger.error("baseKey can not be null") else: return __do_get_data(userCode, appCode, chainCode, funcName, baseKey, url) ``` 然后设计一个`__do_get_data(...)`: ```python def __do_get_data(userCode, appCode, chainCode, funcName, baseKey, url): payload = userCode + appCode + chainCode + funcName + baseKey logger.info('拼接待签名的字符串:%s', payload) mac = myecdsa256.ecdsa_sign(payload, './certificate/private_key.pem').decode() logger.info('base64格式mac值:%s', mac) data = {"header": {"userCode": userCode, "appCode": appCode, "tId": "dc1d6010b7ff421dae0146f193dded09"}, "body": {"chainCode": chainCode, "funcName": funcName, "args": [baseKey]}, "mac": mac} headers = {'content-type': 'application/json'} res = requests.post(url, headers=headers, json=data, verify='./certificate/bsn_https.pem') return res.json() ``` 那么,我们就获得了这样一个函数`get_data`,传入 `baseKey `和 节点地址 `url`,最终得到从链上拿下来的 json。 ## 3 类的设计 Python 是一门基于面向对象思想的语言,所以函数最好还是放到一个类里面。因此设计一个叫做 Operator 的类。 ```python import requests from common.loggers import logger from common import myecdsa256 class Operator: def get_data(self, baseKey, url): …… else: return self.__do_get_data(userCode, appCode, chainCode, funcName, baseKey, url) def __do_get_data(self, userCode, appCode, chainCode, funcName, baseKey, url): …… ``` ## 4 init 文件 为了方便调取,在 sdk 文件夹下创建了`__init__.py`文件: ```python from sdk.operator import Operator ``` 目录结构目前如下: [![](https://learnblockchain.cn/image/show/attachments-2020-01-oibwzuhN5e1fdf6f0310d.png)](https://learnblockchain.cn/image/show/attachments-2020-01-oibwzuhN5e1fdf6f0310d.png) ## 5 测试 现在来看一下效果如何: [![](https://learnblockchain.cn/image/show/attachments-2020-01-k7B9OXR85e1fdf7bdb924.png)](https://learnblockchain.cn/image/show/attachments-2020-01-k7B9OXR85e1fdf7bdb924.png) Okay,如期拿到了链上结果。 [![](https://learnblockchain.cn/image/show/attachments-2020-01-dLd6W0uv5e1fdfb682a76.jpeg)](https://learnblockchain.cn/image/show/attachments-2020-01-dLd6W0uv5e1fdfb682a76.jpeg)
系列索引: 上链与背后的流程 | 联盟链开发(一) 动手编 SDK | 联盟链开发(二) SDK 1.0 版本的打造 | 联盟链开发(三) 将 SDK 发布到 PIP | 联盟链开发(四) 什么样的数据应该上链?| 联盟链开发 (五) BSN 相关问与答 | 联盟链开发(六) 链上简历应用 — 设计 | 联盟链开发(七) FISCO BCOS 介绍 | 联盟链开发(八) WeIdentity 极速体验 | 联盟链开发(九) 给Remix升个级 | 联盟链开发(十) 伪代码简述 ECDSA 签名过程 | 联盟链开发(十一) WeIdentity 的多签及限量凭证的实现 | 联盟链开发(十二)
上回我们使用 BSN 官方提供的示例体验了一下上链操作及简要阐述了一下背后的原理。但是,由于仅为「示例」,所以代码耦合程度较高,要想「为我所用」还需要整理为 SDK。
自然可以将整理出来的代码直接放出来,但是记录与梳理「造轮子」的过程,对于自己的未来工作以及其它人未来的工作都会有帮助,因此我在这里会用几篇文章讲述如何一步步开发 SDK。
1 一个趁手的 SDK 需要哪些要素
SDK 相当于现实生活中的一件工具。
那么,在生活中我们要发明一件让自己和别人使用的工具,需要哪些要素?
- 文档友善 —— 需要友善的说明书告诉我怎么使用这个工具
- 可配置性好 —— 该能配置的地方需要配置不要写死
- 返回结果合理 —— 用工具加工出的产品需要在我们的预料之内
2 以 get_data 为例进行函数改造
2.1 解析源码
在官方提供的示例中,找到 views.py > get_data 函数,这个函数起到的作用是从链上查询信息:
def get_data(request):
logger.info('\n #######进入get_data方法########')
if request.method == 'POST':
userCode = "reddate"
appCode = "CL1851016378620191011150518"
chainCode = "cc_base"
funcName = "get"
baseKey = request.POST.get('baseKey')
if len(baseKey.strip()) == 0:
return render(request, 'get.html', {'hint': '唯一标识不能为空!'})
logger.info('输入的baseKey:%s', baseKey)
str = userCode + appCode + chainCode + funcName + baseKey
logger.info('拼接待签名的字符串:%s', str)
# 对字符串 A使用户证书的私钥进行 SHA256WITHECDSA签名
mac = myecdsa256.ecdsa_sign(str, './certificate/private_key.pem').decode()
logger.info('base64格式mac值:%s', mac)
url = 'https://quanzhounode.bsngate.com:17602/api/node/reqChainCode'
headers = {'content-type': 'application/json'}
datas = {"header": {"userCode": userCode, "appCode": appCode, "tId": "dc1d6010b7ff421dae0146f193dded09"},
"body": {"chainCode": chainCode, "funcName": funcName, "args": [baseKey]},
"mac": mac}
logger.info('get_data请求传参:%s', datas)
try:
r = requests.post(url, headers=headers, json=datas, verify='./certificate/bsn_https.pem')
if r.status_code == 200:
result = r.json()
……
我们可以看到,这个函数传入了一个 request 参数,然后拿了request 中的 baseKey 这个键的值,再通过一系列写死的参数加上 baseKey,去访问一个 url 最终得到结果。
2.2 函数改造
如果要设计成 SDK 中的函数,那么要做如下改造:
- 传入的不应该是request 类型的参数,而应该是一些更基本的值,例如字符串形式的 baseKey。
- 函数应当进一步拆分,拆分为
get_data
和__do_get_data
两个函数,使代码结构更清晰。
因此,首先设计一个函数get_data(baseKey, url)
:
def get_data(baseKey, url):
userCode = "reddate"
appCode = "CL1851016378620191011150518"
chainCode = "cc_base"
funcName = "get"
if len(baseKey.strip()) == 0:
logger.error("baseKey can not be null")
else:
return __do_get_data(userCode, appCode, chainCode, funcName, baseKey, url)
然后设计一个__do_get_data(...)
:
def __do_get_data(userCode, appCode, chainCode, funcName, baseKey, url):
payload = userCode + appCode + chainCode + funcName + baseKey
logger.info('拼接待签名的字符串:%s', payload)
mac = myecdsa256.ecdsa_sign(payload, './certificate/private_key.pem').decode()
logger.info('base64格式mac值:%s', mac)
data = {"header": {"userCode": userCode, "appCode": appCode, "tId": "dc1d6010b7ff421dae0146f193dded09"},
"body": {"chainCode": chainCode, "funcName": funcName, "args": [baseKey]},
"mac": mac}
headers = {'content-type': 'application/json'}
res = requests.post(url, headers=headers, json=data, verify='./certificate/bsn_https.pem')
return res.json()
那么,我们就获得了这样一个函数get_data
,传入 baseKey
和 节点地址 url
,最终得到从链上拿下来的 json。
3 类的设计
Python 是一门基于面向对象思想的语言,所以函数最好还是放到一个类里面。因此设计一个叫做 Operator 的类。
import requests
from common.loggers import logger
from common import myecdsa256
class Operator:
def get_data(self, baseKey, url):
……
else:
return self.__do_get_data(userCode, appCode, chainCode, funcName, baseKey, url)
def __do_get_data(self, userCode, appCode, chainCode, funcName, baseKey, url):
……
4 init 文件
为了方便调取,在 sdk 文件夹下创建了__init__.py
文件:
from sdk.operator import Operator
目录结构目前如下:
5 测试
现在来看一下效果如何:
Okay,如期拿到了链上结果。
区块链技术网。
- 发表于 2020-01-16 11:51
- 阅读 ( 1465 )
- 学分 ( 107 )
- 分类:BSN
评论