zoukankan      html  css  js  c++  java
  • API:BUMO Keypair 指导

    BUMO Keypair 指导

    概述

    本文档详细介绍了Keypair(公、私钥对)的生成过程以及在此基础上如何生成地址(address)并对交易签名,介绍了执行交易调用的两种接口方式以及相关流程,提供了多种ProtoBuf数据结构参考信息,最后以示例的方式详细介绍了两种交易提交方式,即调用接口生成transaction blob和自己生成transaction blob。

    原理图

    下图说明了私钥、公钥和地址的生成原理。

    生成私钥

    生成私钥需要使用随机算法、SHA256 等多个算法才能实现。生成私钥包括以下步骤:

    1. 利用随机算法生成一个256位的随机数(数学意义上的私钥),得到字节数组即 raw private key,如下所示:

      [17,236,24,183,207,250,207,180,108,87,224,39,189,99,246,85,138,120,236,78, 228,233,41,192,124,109,156,104,235,66,194,24]
      
    2. 在 raw private key前面加上3个字节的前缀(Prefix),然后再加上1个字节的版本号(Version),并在后面添加1个字节的填充位(Fill),得到新的字节数组,如下所示:

      [218,55,159,1,17,236,24,183,207,250,207,180,108,87,224,39,189,99,246,85,138,120,236,78,228,233,41,192,124,109,156,104,235,66,194,24,0]
      

      Note : 关于PrefixVersionChecksumFill,请查看表1

    3. 对第2步中得到的字节数组进行两次 SHA256 计算,取运算结果的前4个字节,得到校验码(Checksum)的字节数组,如下所示:

      [30,19,80,117]
      
    4. 将第2步中的字节数组和第3步中的校验码字节数组按照先后顺序连接在一起,得到新的字节数组,如下所示:

      [218,55,159,1,17,236,24,183,207,250,207,180,108,87,224,39,189,99,246,85,138,120,236,78,228,233,41,192,124,109,156,104,235,66,194,24,0,30,19,80,117]
      
    5. 对第4步中产生的字节数组进行Base58编码,得到以priv开始的字符串,即私钥(private key),如下所示:

      privbsGZFUoRv8aXZbSGd3bwzZWFn3L5QKq74RXAQYcmfXhhZ54CLr9z
      

      至此就完成了私钥的生成。

    表1

    名称 数据内容 长度
    Prefix 0xDA 0x37 0x9F 3个字节
    Version 0x01 1个字节
    Fill 0x00 1个字节
    Checksum 对第2步中得到的字节数组进行两次SHA256运算之后,取运算结果的前4个字节 4个字节

    该表对生成私钥中使用到的Prefix、Version、Fill以及Checksum进行了说明。

    生成公钥

    生成公钥需要在生成私钥之后才能实现,需要用到 ED25519 算法。生成公钥包含以下步骤:

    1. 通过 ED25519 算法对raw private key进行处理生成32位的字节数组,即raw public key。例如私钥是privbsGZFUoRv8aXZbSGd3bwzZWFn3L5QKq74RXAQYcmfXhhZ54CLr9z,其raw public key如下所示:

      [21,118,76,208,23,224,218,117,50,113,250,38,205,82,148,81,162,27,130,83,208,1,240,212,54,18,225,158,198,50,87,10]
      
    2. 在raw public key 前面加上1个字节的前缀(Prefix),然后再加上1个字节的版本号(Version),得到新的字节数组,如下所示:

      [176,1,21,118,76,208,23,224,218,117,50,113,250,38,205,82,148,81,162,27,130,83,208,1,240,212,54,18,225,158,198,50,87,10]
      

      Note:关于PrefixVersion以及Checksum请查看表2

    3. 对第2步中的字节数组进行两次 SHA256 计算,取运算结果的前4个字节,得到校验码(Checksum)的字节数组,如下所示:

      [116,171,22,107]
      
    4. 将第2步中的字节数组和3步的校验码字节数组按照先后顺序连接在一起,得到新的字节数组,如下所示:

      [176,1,21,118,76,208,23,224,218,117,50,113,250,38,205,82,148,81,162,27,130,83,208,1,240,212,54,18,225,158,198,50,87,10,116,171,22,107]
      
    5. 对第4步中的字节数组进行16进制编码,得到16进制字符串,即公钥(public key),如下所示:

      b00115764cd017e0da753271fa26cd529451a21b8253d001f0d43612e19ec632570a74ab166b
      

      至此就完成了公钥的生成。

    表2

    名称 数据内容 长度
    Prefix 0xB0 1个字节
    Version 0x01 1个字节
    Checksum 对第2步中得到的字节数组进行两次SHA256运算之后,取运算结果的前4个字节 4个字节

    该表对生成公钥中使用到的Prefix、Version以及Checksum进行了说明。

    生成地址

    在生成私钥和公钥后可以进一步通过算法生成地址。生成地址包含以下步骤:

    1. 通过 ED25519 算法对raw private key进行处理生成32位的字节数组,即 raw public key。例如私钥为 privbsGZFUoRv8aXZbSGd3bwzZWFn3L5QKq74RXAQYcmfXhhZ54CLr9z,其raw public key 如下所示:

      [21,118,76,208,23,224,218,117,50,113,250,38,205,82,148,81,162,27,130,83,208,1,240,212,54,18,225,158,198,50,87,10]
      
    2. 对 raw public key 进行一次 SHA256 运算,并取运算结果的后20位字节,得到字节数组,如下所示:

      [173,148,59,51,183,193,55,160,1,133,247,80,65,13,67,190,164,114,18,220]
      
    3. 在第2步产生的字节数组前面加上2个字节的前缀(Prefix),然后再加上1个字节的版本号(Version),得到新的字节数组,如下所示:

      [1,86,1,173,148,59,51,183,193,55,160,1,133,247,80,65,13,67,190,164,114,18,220]
      

      Note : 关于PrefixVersion以及Checksum请查看表3

    4. 对第3步中的字节数组进行两次 SHA256 计算,取运算结果的前4个字节,得到校验码(Checksum)的字节数组,如下所示:

      [167,127,34,35]
      
    5. 将第3步中的字节数组和第4步的校验码字节数组按照先后顺序连接在一起,得到新的字节数组,如下所示:

      [1,86,1,173,148,59,51,183,193,55,160,1,133,247,80,65,13,67,190,164,114,18,220,167,127,34,35]
      
    6. 对第5步中产生的字节数组进行Base58编码,得到以bu开头的字符串,即地址(address),如下所示:

      buQmWJrdYJP5CPKTbkQUqscwvTGaU44dord8
      

      至此就完成了地址的生成。

    表3

    名称 数据内容 长度
    Prefix 0x01 0x56 2个字节
    Version 0x01 1个字节
    PublicKey 取raw public key的后20个字节 20个字节
    Checksum 对第3步中得到的字节数组进行两次SHA256运算之后,取运算结果的前4个字节 4个字节

    该表对生成地址中使用到的Prefix、Version以及Checksum进行了说明。

    交易签名

    借助 ED25519 算法和私钥对待签名的交易(transaction_blob的反16进制编码得到的字节数组)进行签名,并进行16进制转换,得到签名字符串sign_data

    下面的示例展示了如何用 ED25519 和私钥对transaction_blob签名。

    私钥是:

    privbsGZFUoRv8aXZbSGd3bwzZWFn3L5QKq74RXAQYcmfXhhZ54CLr9z
    

    Transaction blob是:

    0A24627551566B5555424B70444B526D48595777314D553855376E676F5165686E6F31363569109F0818C0843D20E80732146275696C642073696D706C65206163636F756E743A5F08011224627551566B5555424B70444B526D48595777314D553855376E676F5165686E6F3136356922350A246275516E6936794752574D4D454376585850673854334B35615A557551456351523670691A0608011A02080128C7A3889BAB20
    

    用 ED25519 的签名接口对待签名的交易(transaction_blob的反16进制编码得到的字节数组)进行签名,并进行16进制转换后,得到的sign_data是:

    a46ee590a84abdeb8cc38ade1ae8e8a2c71bb69bdc4cd7dc0de1b74b37e2cbd1696229687f80dff4276b1a3dd3f95a9bc1d569943b337fe170317430f36d6401
    

    交易提交方式

    交易的执行有两种接口调用方式:调用接口生成transaction_blob 和自己生成transaction_blob

    由于transaction_blob很可能被截取和篡改,因此不建议调用接口生成transaction_blob。 如果需要调用接口生成transaction_blob、签名并提交交易,请查看HTTP中的序列化交易接口。

    调用接口

    调用接口生成transation_blob包含以下步骤:

    1. 调用 getAccount 接口获取待发起交易账户的nonce值,代码如下所示:

      HTTP GET host:port/getAccount?address=账户地址
      
    2. 根据需要填充json数据并完成交易数据填充,格式如下所示:

      {
          "source_address":"xxxxxxxxxxx", //交易源账号,即交易的发起方
          "nonce":2, //nonce的值
          "ceil_ledger_seq": 0, //可选
          "fee_limit":1000, //交易支付的费用
          "gas_price": 1000, //gas价格(不小于配置的最低值)
          "metadata":"0123456789abcdef", //可选,用户自定义给交易的备注,16进制格式
          "operations":[
              {
                  //根据不同的操作填写
              },
              {
                  //根据不同的操作填写
              }
              ......
          ]
      }
      

      nonce值需要在第1步中获取值的基础上加1。

    3. 通过调用 getTransactionBlob 接口将第2步中生成的json数据作为参数传入,得到一个交易hashtransaction_blob,实现交易序列化,格式如下所示:

      {
      "error_code": 0,
      "error_desc": "",
      "result": {
          "hash": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //交易的hash
          "transaction_blob": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //交易序列化之后的16进制表示
              }
      }
      
    4. 对交易进行签名并填充交易数据。根据之前生成的私钥对transaction_blob签名,然后填充提交交易的json数据,格式如下所示:

      {
          "items" : [{
              "transaction_blob" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //一个交易序列化之后的16进制表示
              "signatures" : [{//第一个签名
                  "sign_data" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //签名数据
                  "public_key" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //公钥
              }, {//第二个签名
                  "sign_data" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //签名数据
                  "public_key" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //公钥
              }]
          }]
      }
      
    5. 通过调用 submitTransaction 接口,将第4步中生成的json数据作为参数传入,得到响应结果,完成交易提交。响应结果的格式如下所示:

      {
          "results": [
              {
                  "error_code": 0,
                  "error_desc": "",
                  "hash": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //交易的hash
              }
          ],
          "success_count": 1
      }
      

    自己生成

    自己生成transaction_blob,签名,并提交交易,具体操作包括以下步骤:

    1. 通过调用 getAccount 接口获取待发起交易的账户的nonce值,如下所示:

      HTTP GET host:port/getAccount?address=账户地址
      
    2. 填充protocol buffer的交易对象Transaction,并进行序列化操作,从而得到transaction_blob。具体的交易数据结构详情请看ProtoBuf数据结构

    3. 签名交易,并填充交易数据。根据私钥生成公钥,并用私钥对transaction_blob签名,然后填充提交交易的json数据,格式如下:

      {
          "items" : [{
              "transaction_blob" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //一个交易序列化之后的16进制表示
              "signatures" : [{//第一个签名
                  "sign_data" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //签名数据
                  "public_key" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //公钥
              }, {//第二个签名
                  "sign_data" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", //签名数据
                  "public_key" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //公钥
              }]
          }]
      }
      
    4. 通过调用 submitTransaction 接口,将第3步生成的json数据作为参数传入,完成交易提交。响应结果格式如下:

      {
          "results": [
              {
                  "error_code": 0,
                  "error_desc": "",
                  "hash": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //交易的hash
              }
          ],
          "success_count": 1
      }
      

    ProtoBuf数据结构

    Protocol Buffers(ProtoBuf)是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或RPC数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了C++JavaPython 三种语言的 API。

    了解更多关于ProtoBuf的信息

    接下来将介绍ProtocolBuffer的数据结构详情,并提供针对脚本生成的各种语言的protocol buffer的文件和简单测试程序。

    数据结构

    下面介绍了交易中可能用到的各种ProtoBuf数据结构及其用途,供用户参考使用。

    Transaction

    该数据结构适用于完整的交易。

        message Transaction {
            enum Limit{
                UNKNOWN = 0;
                OPERATIONS = 1000;
            };
            string source_address = 1; // 交易发起账户地址
            int64 nonce = 2; // 交易序列号
            int64 fee_limit = 3; // 交易费用,默认1000Gas,单位是MO,1 BU = 10^8 MO
            int64 gas_price = 4; // 交易打包费用,默认是1000,单位是MO,1 BU = 10^8 MO
            int64 ceil_ledger_seq = 5; // 区块高度限制
            bytes metadata = 6; // 交易备注
            repeated Operation operations = 7; // 操作列表
        }
    

    Operation

    该数据结构适用于交易中的操作。

        message Operation {
            enum Type {
                UNKNOWN = 0;
                CREATE_ACCOUNT = 1;
                ISSUE_ASSET = 2;
                PAY_ASSE = 3;
                SET_METADATA = 4;
                SET_SIGNER_WEIGHT = 5;
                SET_THRESHOLD = 6;
                PAY_COIN = 7;
                LOG = 8;
                SET_PRIVILEGE = 9;
            };
            Type type = 1; // 操作类型
            string source_address = 2; // 操作源账户地址
            bytes metadata = 3; // 操作备注
            OperationCreateAccount create_account = 4; // 创建账户操作
            OperationIssueAsset issue_asset = 5; // 发行资产操作
            OperationPayAsset pay_asset = 6; // 转移资产操作
            OperationSetMetadata set_metadata = 7; // 设置metadata
            OperationSetSignerWeight set_signer_weight = 8; // 设置签名者权限
            OperationSetThreshold set_threshold = 9; // 设置交易门限
            OperationPayCoin pay_coin = 10; // 转移coin
            OperationLog log = 11; // 记录log
            OperationSetPrivilege set_privilege = 12; // 设置权限
        }
    

    OperationCreateAccount

    该数据结构用于创建账户。

        message OperationCreateAccount{
            string dest_address = 1; // 待创建的目标账户地址
            Contract contract = 2; // 合约
            AccountPrivilege priv = 3; // 权限
            repeated KeyPair metadatas = 4; // 附加信息
            int64 init_balance = 5; // 初始化余额
            string init_input = 6; // 合约入参
        }
    

    Contract

    该数据结构用于设置合约。

        message Contract{
            enum ContractType{
            JAVASCRIPT = 0;
            }
            ContractType type = 1; // 合约类型
            string payload = 2; // 合约代码
        }
    

    AccountPrivilege

    该数据结构用于设置账户权限。

        message AccountPrivilege {
            int64 master_weight = 1; // 账户自身权重
            repeated Signer signers = 2; // 签名者权重列表
            AccountThreshold thresholds = 3; // 门限
        }
    

    Signer

    该数据结构用于设置签名者权重。

        message Signer {
            enum Limit{
                SIGNER_NONE = 0;
                SIGNER = 100;
            };
            string address = 1; // 签名者账户地址
            int64 weight = 2; // 签名者权重
        }
    

    AccountThreshold

    该数据结构用于设置账户门限。

        message AccountThreshold{
            int64 tx_threshold = 1; // 交易门限
            repeated OperationTypeThreshold type_thresholds = 2; // 指定操作的交易门限列表,未指定的操作的交易以tx_threshold为门限
        }
    

    OperationTypeThreshold

    该数据结构用于指定类型的操作门限。

        message OperationTypeThreshold{
            Operation.Type type = 1; // 操作类型
            int64 threshold = 2; // 该操作对应的门限
        }
    

    OperationIssueAsset

    该数据结构用于发行资产。

    
        message OperationIssueAsset{
            string code = 1; // 待发行的资产编码
            int64 amount = 2; // 待发行的资产数量
        }
    

    OperationPayAsset

    该数据结构用于转移资产。

        message OperationPayAsset {
            string dest_address = 1; // 目标账户地址
            Asset asset = 2; // 资产
            string input = 3; // 合约入参
        }
    

    Asset

    该数据结构适用于资产。

        message Asset{
            AssetKey key = 1; // 资产标识
            int64 amount = 2; // 资产数量
        }
    

    AssetKey

    该数据结构用于标识资产唯一性。

        message AssetKey{
            string issuer = 1; // 资产发行账户地址
            string code = 2; // 资产编码
            int32 type = 3; // 资产类型(默认为0,表示不限制数量)
        }
    

    OperationSetMetadata

    该数据结构用于设置Metadata。

        message OperationSetMetadata{
            string key = 1; // 关键字,惟一
            string value = 2; // 内容
            int64 version = 3; // 版本控制,可不设置
            bool delete_flag = 4; // 是否删除
        }
    

    OperationSetSignerWeight

    该数据结构用于设置签名者权重。

        message OperationSetSignerWeight{
            int64 master_weight = 1; // 自身权重
            repeated Signer signers = 2; // 签名者权重列表
        }
    

    OperationSetThreshold

    该数据结构用于设置门限。

        message OperationSetThreshold{
            int64 tx_threshold = 1; // 交易门限
            repeated OperationTypeThreshold type_thresholds = 2; // 指定操作的交易门限列表,未指定的操作的交易以tx_threshold为门限
        }
    

    OperationPayCoin

    该数据结构用于发送coin。

        message OperationPayCoin{
            string dest_address = 1; // 目标账户地址
            int64 amount = 2; // coin的数量
            string input = 3; // 合约入参
        }
    

    OperationLog数据结构

    该数据结构用于记录log信息。

        message OperationLog{
            string topic = 1; // 日志主题
            repeated string datas = 2; // 日志内容
        }
    

    OperationSetPrivilege数据结构

    该数据结构用于设置账户权限。

        message OperationSetPrivilege{
            string master_weight = 1; // 账户自身权重
            repeated Signer signers = 2; // 签名者权重列表
            string tx_threshold = 3; // 交易门限
            repeated OperationTypeThreshold type_thresholds = 4; // 指定操作的交易门限列表,未指定的操作的交易以tx_threshold为门限
        }
    

    使用示例

    本节中提供了proto脚本,以及 cppjavajavascriptpytonobject-c 和 php 生成的proto源码的示例,详细信息请查看proto源码

    链接中的目录结构说明:

    1. cpp: C++的源码

    2. io: Java的测试程序

    3. go: Go的测试程序

    4. js: Javascript的测试程序

    5. python: Python的测试程序

    6. ios: Object-C的测试程序

    7. php: PHP的测试程序

    交易提交示例

    场景:账户A(buQVkUUBKpDKRmHYWw1MU8U7ngoQehno165i)创建账户B(通过Keypair中的 生成地址 来生成新账户地址)。

    接口生成transaction_blob示例

    通过接口生成transaction_blob包含以下步骤:

    1. 通过GET获取待发起交易账户的nonce值。

      GET http://seed1.bumotest.io:26002/getAccount?address=buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw
      

      得到的响应报文:

      {
          "error_code" : 0,
          "result" : {
              "address" : "buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw",
              "assets" : [
                  {
                      "amount" : 1000000000,
                      "key" : {
                          "code" : "HNC",
                          "issuer" : "buQBjJD1BSJ7nzAbzdTenAhpFjmxRVEEtmxH"
                      }
                  }
              ],
              "assets_hash" : "3bf279af496877a51303e91c36d42d64ba9d414de8c038719b842e6421a9dae0",
              "balance" : 27034700,
              "metadatas" : null,
              "metadatas_hash" : "ad67d57ae19de8068dbcd47282146bd553fe9f684c57c8c114453863ee41abc3",
              "nonce" : 5,
              "priv" : {
                  "master_weight" : 1,
                  "thresholds" : [{
                      "tx_threshold" : 1
                  }
                                 ]
              }
          }
      }
      
      address: 当前查询的账户地址
      assets: 账户资产列表
      assets_hash: 资产列表hash
      balance: 账户资产余额
      metadata: 交易备注,必须是16进制
      metadatas_hash: 交易备注hash
      nonce: 转出方交易序列号,通过查询账户信息接口返回的nonce | 1
      priv: 权限
      master_weight: 当前账户权重
      thresholds: 门限
      tx_threshold: 交易默认门限
      
    2. 完成交易数据填充。

      通过 Keypair 中的 生成地址 生成的新账户B的地址是buQoP2eRymAcUm3uvWgQ8RnjtrSnXBXfAzsV,填充的json数据如下:

      {
          "source_address":"buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw",
          "nonce":7,
          "ceil_ledger_seq": 0,
          "fee_limit":1000000,
          "gas_price": 1000,
          "metadata":"",
          "operations":[
              {
                  "type": 1,
                  "create_account": {
                      "dest_address": "buQoP2eRymAcUm3uvWgQ8RnjtrSnXBXfAzsV",
                      "init_balance": 10000000,
                      "priv": {
                          "master_weight": 1,
                          "thresholds": {
                              "tx_threshold": 1
                          }
                      }
                  }
              }
          ]
      }
      

      这里的nonce值不是6,没有连续,因此该交易会超时,不会成功。

    3. 对交易数据进行序列化处理。

      POST http://seed1.bumotest.io:26002/getTransactionBlob
      

      请求报文:

      {
          "source_address":"buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw",
          "nonce":7,
          "ceil_ledger_seq": 0,
          "fee_limit":1000000,
          "gas_price": 1000,
          "metadata":"",
          "operations":[
              {
                  "type": 1,
                  "create_account": {
                      "dest_address": "buQoP2eRymAcUm3uvWgQ8RnjtrSnXBXfAzsV",
                      "init_balance": 10000000,
                      "priv": {
                          "master_weight": 1,
                          "thresholds": {
                              "tx_threshold": 1
                          }
                      }
                  }
              }
          ]
      }
      

      响应报文:

      {
      "error_code": 0,
      "error_desc": "",
      "result": {
      "hash": "be4953bce94ecd5c5a19c7c4445d940c6a55fb56370f7f606e127776053b3b51",
      "transaction_blob": "0a2462755173757248314d34726a4c6b666a7a6b7852394b584a366a537532723978424e4577100718
       c0843d20e8073a37080122330a246275516f50326552796d4163556d33757657675138526e6a7472536e5
       8425866417a73561a0608011a0208012880ade204"
      }
      }
      
    4. 通过私钥对交易(transaction_blob)签名。

      导入包:

      import io.bumo.encryption.key.PrivateKey;
      

      私钥是:

      privbvTuL1k8z27i9eyBrFDUvAVVCSxKeLtzjMMZEqimFwbNchnejS81
      

      签名后的sign_data是:

      9C86CE621A1C9368E93F332C55FDF423C087631B51E95381B80F81044714E3CE3DCF5E4634E5BE77B12ABD
      3C54554E834A30643ADA80D19A4A3C924D0B3FA601
      
    5. 完成交易数据填充。

      {
          "items" : [{
              "transaction_blob" : "0a2462755173757248314d34726a4c6b666a7a6b7852394b584a366a537532723978424e4577100718
              c0843d20e8073a37080122330a246275516f50326552796d4163556d33757657675138526e6a7472536e5
              8425866417a73561a0608011a0208012880ade204",
              "signatures" : [{
                  "sign_data" : "9C86CE621A1C9368E93F332C55FDF423C087631B51E95381B80F81044714E3CE3DCF5E4634E5BE77B12
                  ABD3C54554E834A30643ADA80D19A4A3C924D0B3FA601",
                  "public_key" : "b00179b4adb1d3188aa1b98d6977a837bd4afdbb4813ac65472074fe3a491979bf256ba63895"
               }]
          }]
      }
      
    6. 通过POST提交交易。

      POST http://seed1.bumotest.io/submitTransaction
      

      得到如下的响应报文:

      {
          "results": [{
              "error_code": 0,
              "error_desc": "",
              "hash": "be4953bce94ecd5c5a19c7c4445d940c6a55fb56370f7f606e127776053b3b51"
          }],
          "success_count": 1 //1表示提交成功
      }
      

    自己生成transaction_blob示例

    自己生成transaction_blob(以Java为例)包含以下步骤:

    1. 通过GET获取待发起交易账户的nonce值。

      GET http://seed1.bumotest.io:26002/getAccount?address=buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw
      

      得到的响应报文:

      {
          "error_code" : 0,
          "result" : {
              "address" : "buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw",
              "assets" : [
                  {
                      "amount" : 1000000000,
                      "key" : {
                          "code" : "HNC",
                          "issuer" : "buQBjJD1BSJ7nzAbzdTenAhpFjmxRVEEtmxH"
                      }
                  }
              ],
              "assets_hash" : "3bf279af496877a51303e91c36d42d64ba9d414de8c038719b842e6421a9dae0",
              "balance" : 27034700,
              "metadatas" : null,
              "metadatas_hash" : "ad67d57ae19de8068dbcd47282146bd553fe9f684c57c8c114453863ee41abc3",
              "nonce" : 5,
              "priv" : {
                  "master_weight" : 1,
                  "thresholds" : [{
                      "tx_threshold" : 1
                  }]
              }
          }
      }
      
      address: 当前查询的账户地址
      assets: 账户资产列表
      assets_hash: 资产列表hash
      balance: 账户资产余额
      metadata: 交易备注,必须是16进制
      metadatas_hash: 交易备注hash
      nonce: 转出方交易序列号,通过查询账户信息接口返回的nonce | 1
      priv: 权限
      master_weight: 当前账户权重
      thresholds: 门限
      tx_threshold: 交易默认门限
      
    2. 填充交易(Transaction)数据结构,并生成transaction_blob

      import io.bumo.sdk.core.extend.protobuf.Chain;
      Chain.Transaction.Builder builder = Chain.Transaction.newBuilder();
      builder.setSourceAddress("buQsurH1M4rjLkfjzkxR9KXJ6jSu2r9xBNEw");
      builder.setNonce(7);
      builder.setFeeLimit(1000 * 1000);
      builder.setGasPrice(1000);
      builder.setCeilLedgerSeq(0);
      builder.setMetadata(ByteString.copyFromUtf8(""));
      Chain.Operation.Builder operation = builder.addOperationsBuilder();
      operation.setType(Chain.Operation.Type.CREATE_ACCOUNT);
      Chain.OperationCreateAccount.Builder operationCreateAccount = Chain.OperationCreateAccount.newBuilder();
      operationCreateAccount.setDestAddress("buQoP2eRymAcUm3uvWgQ8RnjtrSnXBXfAzsV");
      operationCreateAccount.setInitBalance(10000000);
      Chain.AccountPrivilege.Builder accountPrivilegeBuilder = Chain.AccountPrivilege.newBuilder();
      accountPrivilegeBuilder.setMasterWeight(1);
      Chain.AccountThreshold.Builder accountThresholdBuilder = Chain.AccountThreshold.newBuilder();
      accountThresholdBuilder.setTxThreshold(1);
      accountPrivilegeBuilder.setThresholds(accountThresholdBuilder);
      operationCreateAccount.setPriv(accountPrivilegeBuilder);
      operation.setCreateAccount(operationCreateAccount);
      String transaction_blob = HexFormat.byteToHex(builder.build().toByteArray());
      

      得到的transaction_blob是:

      77100718c0843d20e8073a37080122330a246275516f50326552796d4163556d3375765767
      5138526e6a7472536e58425866417a73561a0608011a0208012880ade204
      

      Note : 这里的nonce值不是6,没有连续,因此该交易会超时,不会成功。

    3. 通过私钥对交易(transaction_blob)签名。 导入包:

    4.  import io.bumo.encryption.key.PrivateKey;
      

      私钥是:

      privbvTuL1k8z27i9eyBrFDUvAVVCSxKeLtzjMMZEqimFwbNchnejS81
      

      签名后的sign_data是:

      9C86CE621A1C9368E93F332C55FDF423C087631B51E95381B80F81044714E3CE3DCF5E4634E5BE77B12
      ABD3C54554E834A30643ADA80D19A4A3C924D0B3FA601
      
    5. 完成交易数据填充。

      {
          "items" : [{
              "transaction_blob" : "0a2462755173757248314d34726a4c6b666a7a6b7852394b584a366a537532723978424e4577100718
              c0843d20e8073a37080122330a246275516f50326552796d4163556d33757657675138526e6a7472536e5
              8425866417a73561a0608011a0208012880ade204",
              "signatures" : [{
                  "sign_data" : "9C86CE621A1C9368E93F332C55FDF423C087631B51E95381B80F81044714E3CE3DCF5E4634E5BE77B12
                  ABD3C54554E834A30643ADA80D19A4A3C924D0B3FA601",
                  "public_key" : "b00179b4adb1d3188aa1b98d6977a837bd4afdbb4813ac65472074fe3a491979bf256ba63895"
              }]
          }]
      }
      
    6. 通过POST提交交易。

      POST http://seed1.bumotest.io/submitTransaction
      

      得到的响应报文:

      {
          "results": [{
              "error_code": 0,
              "error_desc": "",
              "hash": "be4953bce94ecd5c5a19c7c4445d940c6a55fb56370f7f606e127776053b3b51"
          }],
          "success_count": 1 //1表明交易提交成功。
      }
  • 相关阅读:
    idea 设置默认的maven
    IDEA中Tomcat部署时war和war exploded区别
    所谓的SaaS服务到底是什么?
    java8 Lambda表达式
    java8 :: 用法 (JDK8 双冒号用法)
    idea 本地调试,修改代码,代码自动生效
    nacos配置中心demo
    Logparser 的用法
    android软键盘的一些控制 转来的,格式有点乱
    TranslateAnimation 使用详解
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13313239.html
Copyright © 2011-2022 走看看