京东智臻链开放联盟网络的快速部署调用

前言:

最近要用区块链用于存证,然后看到京东智臻链开放联盟网络,就了解了一下,然后决定自己写代码来调用它来用于存证,免费还是挺香的。

建议在阅读本文时先了解一下京东智臻链开放联盟网络

完成注册,登陆后就可以继续了。

一、创建自己的第一个合约:

建立子账户:

合约管理 => 我的智能合约 => 点击创建 => 添加子业务账户

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR54ix6K6p5py65Zmo5a2m5Lmg,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR54ix6K6p5py65Zmo5a2m5Lmg,size_20,color_FFFFFF,t_70,g_se,x_16

 选择密钥非托管,然后将密钥下载后保存后面调用需要用到。

创建第一个智能合约:

回到智能合约页面,在“我的智能合约”中点击“创建合约”。

子账户选择刚才创建的子账户,其余的根据自己心意填。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR54ix6K6p5py65Zmo5a2m5Lmg,size_20,color_FFFFFF,t_70,g_se,x_16

模板我选择的第一个通用存证模板,根据自己的需求进行选择。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR54ix6K6p5py65Zmo5a2m5Lmg,size_20,color_FFFFFF,t_70,g_se,x_16

然后便是新增字段。

索引字段即主键,我设置的为‘id’。当然此处根据自己的需求来进行填写设计,我只设置了一个字段,方便测试。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR54ix6K6p5py65Zmo5a2m5Lmg,size_20,color_FFFFFF,t_70,g_se,x_16

 二、签名代码的实现:

合约创建成功后 => 调用 => 开发者调用 ,我们就能看到JD提供的开发文档。

JD提供的文档有些坑,有些地方有点错误。

不过建议大家还是先看一下了解一下大致的流程。

在整个过程中,一共用到了两次签名,一次是本地签名(公钥+私钥+时间戳),一次是交易签名(公钥+私钥+交易哈希)。都是调用JD提供的java编写SDK来完成,于是我将他们封装在了一起。如果不知道如何使用Python调用jar可以先看一下我的这篇文章,传送门

公钥和私钥就是在创建子账户时,下载的key.txt中。SDK在点击调用 => 开发者调用 ,官方的第一个步骤中点击“下载SDK”。

SignName.py

from jpype import *
import jpype
import time

class SignName:
    """
    调用京东提供的SDK,实现本地签名,交易签名
    * @param01: publicKey 公钥原文
    * @param02: privateKey 私钥原文
    
    """
    def __init__(self,publicKey:str,privateKey:str) -> None:
        jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=../jar/local-signature.jar")  #调用京东区块链的SDK
        self.__JDClass =jpype.JClass("com.jd.bt.chain.Signature") #这说明类在jar包中的目录结构是"com.jd.bt.chain.Signature"  数字签名
        self.__jdChain = self.__JDClass()  #实例化
        self.publicKey = publicKey
        self.privateKey = privateKey

    def localSign(self) -> str:

        """
        返回得到本地签名。
        调用SDK,signOrigin方法
        * @param01: timestamp 时间戳
        * @param02: publicKey 公钥原文
        * @param03: privateKey 私钥原文
        """
        self.timestampContent = str(round(time.time() * 1000))  #毫秒级时间戳
        self.result = str(self.__jdChain.signOrigin(self.timestampContent, self.publicKey,self.privateKey))  #子账户签名结果
        return self.result

    def transactionSign(self,txHash:str) -> str:

        """
        txHash:组装交易后的返回值中。
        返回得到交易签名。
        调用SDK,sign方法
        * @param01: txHash 交易哈希
        * @param02: publicKey 公钥原文
        * @param03: privateKey 私钥原文
        """

        self.result = str(self.__jdChain.sign(txHash, self.publicKey,self.privateKey))  #子账户签名结果
        return self.result
        

 三、请求Token

话不多说直接上代码。使用requests的get方法即可,url为:https://openchain.jd.com/server/account/getServerToken。didKey找不到的看官方提供的开发者调用文档的第一步,上面有didKey的值,复制粘贴即可,公钥和私钥就是子账户的公钥私钥。

GetServerToken.py

import requests
import json
# from SignName import SignName

class GetServerToken:
    """
    token请求类
    """
    def __init__(self,publicKey:str,privateKey:str,didKey:str,signName) -> None:

        """
        * @param01:publicKey:子账户公钥
        * @param02:privateKey:子账户密钥
        * @param03:didKey:账户
        * @param04:SignName:签名类的实例化
        """
        self.publicKey = publicKey
        self.privateKey = privateKey
        self.didKey = didKey
        self.signName = signName


    def getURl(self,url='https://openchain.jd.com/server/account/getServerToken') -> dict:
        """
        请求的token
        * @param01:url:请求的网址
        """

        param = {
            'didKey':self.didKey,
            'subAccountPubKey':self.publicKey,
            'signature':self.signName.localSign(),   #子账户签名结果
            'timestamp':self.signName.timestampContent   #时间戳(被签名内容)
        }
        page = requests.get(url,params=param)
        msg = json.loads(page.text)
        return msg


# if __name__ == '__main__':
#     didKey = '填写自己的账户'
#     publicKey = '公钥'
#     privateKey = '私钥'
    
#     signName = SignName(publicKey,privateKey)
#     print(type(signName))
#     askToken = GetServerToken(publicKey,privateKey,didKey,signName)
#     msg = askToken.getURl()

#     print(msg)

如需测试,将注释的打开给相应参数就行。返回值如下

626d5c7b770d4220a8412da37459a7bc.png

四、组装交易

接下来就是组装交易,用到了token,需要将上一步得到的返回值中的token取出。给定参数后直接使用Post即可,url='https://openchain.jd.com/server/contract/call'

didPkPubK:DID身份信息公钥原文,contractAddress:合约地址找不到,同样也可以在官方文档的第三步中找到。

具体实现看代码,代码给出了详细注释。注意:primaryKey:存证所需的主键。它代表存的是具体参数,不是参数名,不要写错了,最初我掉了进去,然后我创建了一个托管的子账户的合约直接在页面中调用,然后F12,查看了它发送的请求才注意到。同时如果你写错了,他是能够post并返回结果的,我在最后一步中出现问题,回过头来才发现这里的坑。

ContractCall.py

import requests
import json
import sys
# from GetServerToken import GetServerToken
# from SignName import SignName

class ContractCall():
    """
    组装交易
    """

    def __init__(self,result:str,didKey:str,didPkPubK:str,publicKey:str,contractAddress:str,method:str,primaryKey:str,paramJson:dict={}) -> None:

        """
        * @param01:result:请求的token
        * @param02:didPkPubK:DID身份信息公钥原文
        * @param03:publicKey:调用合约用的子账户公钥,必须和签名用的子账户私钥是同一对秘钥
        * @param04:contractAddress:合约地址
        * @param05:method:调用方法(insert,query,update,insertOrUpdate四选一)
        * @param06:primaryKey:存证所需的主键。注:存的具体参数,非参数名!
        * @param07:paramJson:存证参数(按照数据格式的dict),调用insert和update方法时需要,query方法不需要
        """

        if result['code'] != 20000:
            print(f'获取Token失败:{result["msg"]}')
            sys.exit(1)
        self.token = result['data']['token']

        #请求头
        self.postHead = {
            'Gateway-Appid': didKey,
            'Gateway-Token': self.token,
        }

        self.postData = {
            'didPkPubK': didPkPubK,
            'subAccountPubKey': publicKey,  # 调用合约用的子账户公钥,必须和签名用的子账户私钥是同一对秘钥
            'contractAddress': contractAddress,
            'method': method,
            'primaryKey': primaryKey,
            'paramJson':  json.dumps(paramJson)
        }


    def postURL(self,url:str='https://openchain.jd.com/server/contract/call') -> dict:
        """
        组装交易后的返回值
        * @param01:url:请求的网址
        """

        page = requests.post(url, headers=self.postHead, json=self.postData) 
        msg = json.loads(page.text)
        return msg

        
# if __name__ == '__main__':

#     didKey = ''
#     publicKey = ''
#     privateKey = ''
#     didPkPubK = '' 
#     contractAddress = ''
#     method = 'insert' 
#     paramJson = {
#         'id' = 11
#     }
#     primaryKey = paramJson['id']  #存证所需的主键
#     signName = SignName(publicKey,privateKey)
#     getServerToken = GetServerToken(publicKey, privateKey, didKey,signName)
#     result = getServerToken.getURl()

#     contractCall = ContractCall(result,didKey,didPkPubK,publicKey,contractAddress,method,primaryKey,paramJson)
#     ans = contractCall.postURL()
#     print(ans)

 返回值示例:

{'code': 20000, 'msg': '操作成功', 'data': {'params': [{'address': 'LdeP5sRTSLNLpScahgrH51sfgVroJES2hAtjH', 'methodName': 'insert', 'key': 'wan', 'paramJson': '{"name": "wan"}', 'paramType': 'String'}], 'txContent': '112JJhCfsgmv4pK6Xhd7WCbSiCYVepFAiMdabY3RN7sRotLhTHfKQZK4WPeanxfn9VpK3Tb5h3sAQ49bpx68NRj8ZoavrTNCEt9D515BFsKwouLEenXBDJRaGa1xMmJaexZxbXqChCuAV4HjV1Wrfz8DhrsqcQ5Ek1eTvHQ7HC8xbjALNw6w6YWpvRvtTUm3xkNTz7xc8AxbpPjEHAxYVUDE4rpgrjHK4Cv5SwiB2dEp2H', 'txHash': 'j5kd9kT62AqM97QVSX8pygL8DXv8S34Z4esMpyomVqnpWB', 'signerPubKey': '7VeRLfw1QyERWTPZmPJPKwiHUHGFJIUyK9XRsU2L9cL5vf6w', 'signature': None}}

五、交易

最后一步。

官方文档在最后一步把参数名'signerPubKey' 错误的写成了 'publicKey',我使用F12调试后才发现,上一步骤我已说具体方法。同时上一步的请求头和这次是一样的,并且返回值中Data与我们Post需要给的json参数,相差不大,我们只需要再向其中加入我们的交易签名结果即可。url='https://openchain.jd.com/server/contract/sign'

Transaction.py

import requests
import json

# from GetServerToken import GetServerToken
# from ContractCall import ContractCall
# from SignName import SignName

class Transaction:
    """
    交易
    """
    def __init__(self,result:dict,postHead,signName) -> None:

        """
        * @param01: result 组装交易后的返回值
        * @param02:SignName:签名类的实例化
        """

        self.postHead = postHead
        self.data = result['data']
        self.txHash = result['data']['txHash']
        self.signName = signName
        self.signerPubKey = self.signName.transactionSign(self.txHash)
        self.data['signature'] = self.signerPubKey

    def postURL(self,url='https://openchain.jd.com/server/contract/sign') -> dict:
        """
        最终交易后的返回值
        * @param01:url:请求的网址
        """
        
        page = requests.post(url, headers=self.postHead,json=self.data) 
        msg = json.loads(page.text)
        return msg

# if __name__ == '__main__':

#     didKey = '
#     publicKey = ''
#     privateKey = ''
#     didPkPubK = '' 
#     contractAddress = ''
#     method = 'insert' 
#     paramJson = {
#         
#     }
#     signName = SignName(publicKey,privateKey)
#     primaryKey = paramJson['id'] 
#     getServerToken = GetServerToken(publicKey, privateKey, didKey,signName)
#     result = getServerToken.getURl()

#     contractCall = ContractCall(result,didKey,didPkPubK,publicKey,contractAddress,method,primaryKey,paramJson)
#     ans = contractCall.postURL()
#     transaction = Transaction(ans,contractCall.postHead,signName)
#     ans = transaction.postURL()
#     print(ans)

返回值示例:

{

"code": 20000,

"msg": "操作成功",

"data": {

"transactionHash": "j5pMNEQolpWgX1y1m2q37CWkBD1yQfQcpvVSVuNb5fftpd",

"blockHeight": "507",

"content": "{\"xingMing\":\"update1204\",\"zhuJian\":2}",

"time": "2020-12-04 10:58:08",

}

}

同时我们也能够在“我的智能合约” 中点击数据列表中查询到刚才上链的信息。

猜你喜欢

转载自blog.csdn.net/youngwyj/article/details/124395161