人生,总避免不了开发几个 SDK ✧(•̀ω•́ )
系列索引: 上链与背后的流程 | 联盟链开发(一) 动手编 SDK | 联盟链开发(二) SDK 1.0 版本的打造 | 联盟链开发(三) 将 SDK 发布到 PIP | 联盟链开发(四) 什么样的数据应该上链?| 联盟链开发 (五) BSN 相关问与答 | 联盟链开发(六) 链上简历应用 — 设计 | 联盟链开发(七) FISCO BCOS 介绍 | 联盟链开发(八) WeIdentity 极速体验 | 联盟链开发(九) 给Remix升个级 | 联盟链开发(十) 伪代码简述 ECDSA 签名过程 | 联盟链开发(十一) WeIdentity 的多签及限量凭证的实现 | 联盟链开发(十二)
上回我们使用 BSN 官方提供的示例体验了一下上链操作及简要阐述了一下背后的原理。但是,由于仅为「示例」,所以代码耦合程度较高,要想「为我所用」还需要整理为 SDK。
自然可以将整理出来的代码直接放出来,但是记录与梳理「造轮子」的过程,对于自己的未来工作以及其它人未来的工作都会有帮助,因此我在这里会用几篇文章讲述如何一步步开发 SDK。
SDK 相当于现实生活中的一件工具。
那么,在生活中我们要发明一件让自己和别人使用的工具,需要哪些要素?
在官方提供的示例中,找到 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 最终得到结果。
如果要设计成 SDK 中的函数,那么要做如下改造:
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。
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):
……
为了方便调取,在 sdk 文件夹下创建了__init__.py
文件:
from sdk.operator import Operator
目录结构目前如下:
现在来看一下效果如何:
Okay,如期拿到了链上结果。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!