<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          教程 | 使用WeBASE進(jìn)行“兩階段交易”

          共 7235字,需瀏覽 15分鐘

           ·

          2021-08-25 23:42

          作為一個(gè)友好的、功能豐富的區(qū)塊鏈中間件平臺(tái), WeBASE致力于提高區(qū)塊鏈開(kāi)發(fā)者的運(yùn)維與管理效率。在新近發(fā)布的 WeBASE v1.5.2 中,一大優(yōu)化是提供了獲取交易編碼的接口,更方便用戶使用"兩階段交易"。

          “兩階段交易”是什么?“兩階段交易”是指分成兩個(gè)步驟發(fā)送交易,即對(duì)交易編碼并簽名、將交易提交到鏈上這兩個(gè)階段:

          • 第一階段:構(gòu)造并獲取交易編碼值,并通過(guò)私鑰對(duì)交易編碼值簽名;
          • 第二階段:發(fā)送交易,也就是將已簽名的編碼值發(fā)送到鏈上。


          在WeBASE v1.5.2中,我們?cè)赪eBASE-Front節(jié)點(diǎn)前置服務(wù)中增加了獲取交易編碼值的功能。該接口可以返回未簽名的交易編碼值,也可以返回通過(guò)WeBASE-Front本地私鑰或WeBASE-Sign私鑰簽名后的交易編碼值。獲得已簽名的編碼值后,用戶直接調(diào)用前置服務(wù)的提交交易接口即可完成“兩階段交易”。

          以下演示,我們通過(guò)WeBASE-Front節(jié)點(diǎn)前置服務(wù)接口獲取交易編碼值,并通過(guò)FISCO-BCOS Java-SDK對(duì)編碼值進(jìn)行簽名,最后通過(guò)接口提交交易來(lái)加深對(duì)“兩階段交易”的了解。

            前期準(zhǔn)備

          部署HelloWorld合約

          在發(fā)起交易之前,首先要確保在鏈上部署一個(gè)可調(diào)用的合約。這里以WeBASE-Front “合約倉(cāng)庫(kù)-工具合約”中的 “HelloWorld” 合約為例,部署一份 HelloWorld 合約。

          我們?cè)?WeBASE-Front 的合約IDE中編譯一份 HelloWorld 合約并完成部署操作,如下圖所示:


          獲得合約地址、合約ABI等信息后,我們根據(jù) WeBASE-Front 的接口文檔指引,調(diào)用獲取交易編碼接口。

          查看接口文檔

          兩階段交易中,第一步交易編碼并簽名可以通過(guò) WeBASE-Front 的 /trans/convertRawTxStr/withSign 接口構(gòu)造一個(gè)已簽名的交易體,接口文檔簡(jiǎn)介如下:


          值得一提的是,調(diào)用 /trans/convertRawTxStr/withSign 接口時(shí):

          • 如果傳入了 signUserId 非空,則返回的交易體編碼值是通過(guò) signUserId 對(duì)應(yīng)私鑰簽名后的交易體編碼值。
          • 如果傳入的 signUserId 為空,則返回的是未簽名的交易體編碼值,開(kāi)發(fā)者也可以通過(guò)JAVA-SDK用私鑰對(duì)該值簽名。



          獲取已簽名的交易編碼值后,就可以進(jìn)行第二步的提交交易操作了。

          在 WeBASE-Front 中,我們可以通過(guò) /trans/signed-transaction 接口,將已簽名的交易體編碼值,完成交易上鏈并獲得交易回執(zhí)。


          上述各個(gè)接口的調(diào)用方法都可以在 WeBASE-Front 的接口文檔中找到:
          https://webasedoc.readthedocs.io/zh_CN/latest/docs/WeBASE-Front/interface.html

            結(jié)合WeBASE-Front接口進(jìn)行“兩階段交易”

          獲取交易編碼值

          下面以 WeBASE-Sign 簽名的獲取交易編碼接口( /trans/convertRawTxStr/withSign )為例,獲取未簽名的交易編碼值。

          我們可以訪問(wèn) WeBASE-Front 的 Swagger 進(jìn)行接口調(diào)用,如:
          http://localhost:5002/WeBASE-Front/swagger-ui.html

          找到Swagger接口列表中的"transaction interface"交易接口一欄,點(diǎn)開(kāi) /trans/convertRawTxStr/withSign 即可。


          在文章開(kāi)頭我們提到,“兩階段交易”的第一階段是交易編碼并通過(guò)私鑰對(duì)編碼值簽名。

          因此,我們調(diào)用接口時(shí)傳入的 “signUserId” 為空字符串,接口將返回未簽名的交易編碼值,稍后我們?cè)偻ㄟ^(guò) Java-SDK 手動(dòng)對(duì)編碼值簽名。在調(diào)用 /trans/convertRawTxStr/local 接口時(shí)同理,user 地址字段為空字符串時(shí)也會(huì)返回未簽名的交易編碼值。

          我們以調(diào)用HelloWorld合約的 "set" 方法為例,按接口文檔填入對(duì)應(yīng)參數(shù)。

          首先,點(diǎn)開(kāi)Swagger中的 /trans/convertRawTxStr/withSign 接口,再填入?yún)?shù)包括合約ABI、合約地址、函數(shù)名及函數(shù)入?yún)?、群組ID和WeBASE-Sign的私鑰用戶ID signUserId,點(diǎn)擊"Try it out"輸入?yún)?shù),刪除不必要的字段。注意,其中signUserId為空字符串。


          點(diǎn)擊"Execute"即可發(fā)起調(diào)用,獲得未簽名的交易編碼值。接口返回值為:


          拿到未簽名的交易編碼值之后,我們接下來(lái)通過(guò) Java-SDK 對(duì)編碼值進(jìn)行簽名。

          對(duì)交易編碼值簽名

          下面我們使用 FISCO-BCOS Java-SDK 加載私鑰,對(duì)上文獲取的未簽名交易編碼值進(jìn)行簽名操作,并根據(jù) RawTransaction 交易體再次編碼,得到最終簽名后的交易編碼值。
          public void testSign(TransactionEncoderService encoderService, RawTransaction rawTransaction) {    // 未簽名的交易編碼值    String encodedTransaction = "0xf8a9a001b41b2cc71fe0bf0450f1fa4d820209b6686a8f226d217be0bc51cd9fc4a020018405f5e100820204941f2dfecfd75b883b51762aef6326d3ae9ad5230180b8644ed3885e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033132330000000000000000000000000000000000000000000000000000000000010180";    // 私鑰    String privateKey = "0x123";    // ECDSA 加密套件    CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE);    // 對(duì)待簽名的編碼值作哈運(yùn)算    String hashMessageStr = cryptoSuite.hash(encodedTransaction);    System.out.println("hashMessageStr: " + hashMessageStr);    // 創(chuàng)建私鑰對(duì)    CryptoKeyPair myKeyPair = cryptoSuite.createKeyPair(privateKey);        // 對(duì)交易編碼值簽名    SignatureResult signedTx = cryptoSuite.sign(hashMessageStr, myKeyPair);    // 獲得最終簽名后的交易編碼值    byte[] signedTransaction = encoderService.encode(rawTransaction, signedTx);    // 轉(zhuǎn)十六進(jìn)制字符串    String signedTransactionStr = Numeric.toHexString(signedTransaction);    System.out.println("signedTransactionStr: " + signedTransactionStr);}

          提交交易

          有了已簽名的交易編碼值后,我們可以調(diào)用 /trans/signed-transaction 接口,將該交易發(fā)到鏈上,獲得交易回執(zhí)。這里我們繼續(xù)使用 Swagger 調(diào)用該接口。


          提交請(qǐng)求后,接口返回了交易的回執(zhí)??梢愿鶕?jù)交易回執(zhí)判斷交易是否執(zhí)行成功。


          當(dāng)看到返回的交易回執(zhí)中顯示 status0x0,也就意味著交易執(zhí)行成功了。

            交易編碼接口源碼解析

          WeBASE-Front 源碼中,位于 transaction 包里的 TransService 包含了對(duì)交易編碼并簽名的具體代碼。

          獲取交易編碼值

          我們找到 createRawTxEncoded() 方法,該方法通過(guò)合約函數(shù)的ABI,合約函數(shù)的函數(shù)名 funcName 和合約函數(shù)入?yún)?funcParam 等參數(shù)構(gòu)造了 Function 實(shí)例,并通過(guò) FunctionEncoderFunction 實(shí)例進(jìn)行編碼得到字符串 encodedFunction(代碼中的 cryptoSuite 是國(guó)密或非國(guó)密的加密套件,可用于計(jì)算哈希、創(chuàng)建私鑰對(duì)、簽名等)。
          // 構(gòu)造Function實(shí)例Function function = new Function(funcName, contractFunction.getFinalInputs(),            contractFunction.getFinalOutputs());// 編碼FunctionFunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite);String encodedFunction = functionEncoder.encode(function);

          下面使用 convertRawTx2Str() 方法,該方法主要負(fù)責(zé)構(gòu)造 RawTransaction 交易體。

          構(gòu)造 RawTransaction 需要傳入一個(gè)隨機(jī)數(shù)和從節(jié)點(diǎn)獲取當(dāng)前的 BlockLimit 值(避免重復(fù)提交交易)、合約地址和上文獲得的 encodedFunction 等參數(shù)。
          // 構(gòu)造交易體BigInteger randomId = new BigInteger(250, new SecureRandom());BigInteger blockLimit = web3j.getBlockLimit();RawTransaction rawTransaction =    RawTransaction.createTransaction(randomId, Constants.GAS_PRICE,        Constants.GAS_LIMIT, blockLimit, contractAddress, BigInteger.ZERO, encodedFunction,        new BigInteger(Constants.chainId), BigInteger.valueOf(groupId), "");// 編碼交易體RawTransactionTransactionEncoderService encoderService = new TransactionEncoderService(cryptoSuite);byte[] encodedTransaction = encoderService.encode(rawTransaction, null);

          對(duì)交易編碼值簽名

          對(duì)交易編碼值簽名前,WeBASE-Front 中會(huì)根據(jù)傳入的 user 字段和 isLocal 字段判斷:

          • 如果 user 字段為空,則將 encodedTransaction 轉(zhuǎn)為十六進(jìn)制后返回。該值就是第一階段未簽名的交易編碼值。
          • 如果 user 字段非空, isLocal 字段為 true,則 user 為 WeBASE-Front 本地的用戶私鑰,通過(guò)本地私鑰對(duì)交易編碼值 encodedTransaction 簽名。注意,簽名前還需對(duì) encodedTransaction 進(jìn)行一次哈希運(yùn)算后再簽名。
          • 如果 user 字段非空, isLocal 字段為 false,則 user 為 WeBASE-Sign 托管私鑰的signUserId,通過(guò)簽名服務(wù)對(duì)交易體編碼值 encodedTransaction 簽名。注意,此處簽名前沒(méi)有對(duì) encodedTransaction 進(jìn)行哈希,而是直接轉(zhuǎn)為十六進(jìn)制發(fā)到簽名服務(wù),簽名服務(wù)拿到該值后再做哈希運(yùn)算并簽名返回結(jié)果。

          下面展示的代碼為isLocal 字段為 false,user 字段非空,其值為 signUserId 的交易編碼值簽名邏輯。

          我們將交易編碼值 encodedTransaction 轉(zhuǎn)十六進(jìn)制后,傳到簽名服務(wù)進(jìn)行簽名,得到了 String 格式的簽名結(jié)果 signDataStr ,將簽名結(jié)果反序列化,得到了簽名結(jié)果 SignatureResult。同時(shí),通過(guò) TransactionEncoderService 將簽名結(jié)果和上文構(gòu)造的 RawTransaction 實(shí)例進(jìn)行編碼,最終可得到十六進(jìn)制的已簽名的交易編碼值 signResultStr 。
          // encodedTransaction轉(zhuǎn)十六進(jìn)制String hashMessageStr = Numeric.toHexString(encodedTransaction);// 通過(guò)WeBASE-Sign簽名EncodeInfo encodeInfo = new EncodeInfo(user, hashMessageStr);String signDataStr = keyStoreService.getSignData(encodeInfo);// 反序列化簽名結(jié)果SignatureResult signData = CommonUtils.stringToSignatureData(signDataStr, cryptoSuite.cryptoTypeConfig);// 加入簽名結(jié)果,再次編碼byte[] signedMessage = encoderService.encode(rawTransaction, userSignResult);// 轉(zhuǎn)為十六進(jìn)制String signResultStr = Numeric.toHexString(signedMessage);

          至此,獲取交易編碼,對(duì)交易編碼簽名交易體,并對(duì)編碼值簽名的過(guò)程就完成了。

          值得一提的是,提交交易后獲得的交易哈希 TransHash 值是通過(guò)對(duì)簽名交易體編碼值進(jìn)行哈希計(jì)算得到的,有了交易哈希,也可以在提交交易后,直接根據(jù)交易哈希到鏈上查詢交易回執(zhí)。
          // 通過(guò)CryptoSuite實(shí)例計(jì)算signResultStr的交易哈希值String transHash = cryptoSuite.hash(signResultStr);

            即刻使用


          上述優(yōu)化及功能所涉及的最新代碼和技術(shù)文檔已同步更新,歡迎體驗(yàn)和star支持。如需咨詢技術(shù)問(wèn)題,歡迎本公眾號(hào)對(duì)話框回復(fù)【小助手】進(jìn)技術(shù)交流群。


          WeBASE 代碼倉(cāng)庫(kù):
          https://github.com/WeBankFinTech/WeBASE
          WeBASE 代碼倉(cāng)庫(kù)國(guó)內(nèi)鏡像:
          https://gitee.com/WeBank/WeBASE
          WeBASE 技術(shù)文檔:
          https://webasedoc.readthedocs.io/zh_CN/latest
          WeBASE 技術(shù)文檔國(guó)內(nèi)鏡像:
          https://fintech.webank.com/developer/docs/webase


          首次體驗(yàn)WeBASE,可參考一鍵部署文檔:
          https://webasedoc.readthedocs.io/zh_CN/latest/docs/WeBASE/install.html


          瀏覽 109
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www18禁 | 日韩无码一卡二卡 | 亚洲金品 | 伊人一区| 啊啊啊操我视频 |