首页 > GXChain(公信宝) > 正文

你居然还抢不到,第三次100GXC了!

公信宝 2019-03-22 19:59

  

  上周GXChain开发高级教程解密分别在第15,29,32,62分钟被开发者解开。

  揭秘规则在上期的基础上进行的修改,增加了开发者答对的机会。

  每期教程的最后,都会留下4个题目,请务必把答案回复至「GXChain社区」这个公众号后台,若正确即可获得私钥;

  每个问题的答案都对应一组完整的私钥,可导出问题对应的GXC。

  为了保证大家能同一时间看到,每期教程的最后,会公布下一期教程的发布时间。一定要去「GXChain社区」这个公众号后台回复哦。

  话不多说,开启本期教程解密。

  (以下为正文)

  如何确认交易与如何处理转账memo

  上篇文章我们讲了如何向GXChain发起一笔交易,包含了交易的构造、序列化、签名等内容,本篇文章继续讲解如何确认一笔交易以及如何解析转账中的memo字段。

  一笔交易被广播到区块链上之后,节点会打包该笔交易到区块中,并把最终打包完的区块向全网络广播,当2/3的公信节点确认该区块之后(即2/3的公信节点在该区块之后打包了新的区块),我们则称为这笔交易被最终确认了,或者说不可逆了。下面第一部分则对不可逆区块部分做一个讲解说明。

一、不可逆区块和不可逆交易

  在GXChain上,被2/3以上公信节点确认的区块,我们定义为不可逆区块,即最终确认区块(相当于Bitcoin的6个区块确认)。所有在不可逆区块中的交易,则称为不可逆交易。因此,判断某一笔交易是否不可逆,是通过判断这笔交易是否出现在不可逆区块中来实现的。

  不可逆交易的意义重大,可以用于转账确认、交易所充值确认等场景。主要的思路是通过遍历不可逆区块来查询相关的交易。

第一步: 获取最后不可逆区块号

  获取动态全局属性对象

  request:

  curl--data'{
   "jsonrpc": "2.0",
   "mETHod": "call",
   "params": [0, "get_dynamic_global_properties", []],
   "id": 1
}' https://node1.gxb.io/rpc

  response:

  {
   "id":1,
   "jsonrpc":"2.0",
   "result":{
       "id":"2.1.0",
       "head_block_number":16757465, // 最新区块号
       "head_block_id":"00ffb2d9f6e344f2190a8dfba58baaadd49e76c4", // 最新区块id
       "time":"2019-01-28T06:08:00", // 区块头时间
       "current_witness":"1.6.52",
       "next_maintenance_time":"2019-01-28T06:40:00",
       "last_budget_time":"2019-01-28T05:40:00",
       "witness_budget":3065824,
       "accounts_registered_this_interval":2,
       "recently_missed_count":0,
       "current_aslot":16958091,
       "recent_slots_FILled":"340282366920938463463374607431768211455",
       "dynamic_flags":0,
       "last_irreversible_block_num":16757449// 最后不可逆区块号
  }
}

  其中last_irreversible_block_num为最后不可逆区块号,当前区块链中所有小于last_irreversible_block_num的区块,都是不可逆区块,即最终确认的区块。

第二步: 遍历不可逆区块

  例如:判断某个txid为9df2d2a2804c235bb16428c44f71de9468409AE7的交易是否在不可逆区块中,我们会从交易发起的某个区块高度开始进行查询,一直到不可逆区块高度为止,如果发现返回的transaction_ids数组中查询到这个txid,则证明该交易不可逆了,即交易被网络最终确认了。

  request:

  curl--data'{
   "jsonrpc": "2.0",
   "method": "call",
   "params": [0, "get_block", [17136876]],
   "id": 1
}' https://node1.gxb.io/rpc

  response:

  {
 "previous": "01057cebdee3cf922d8fa54c2f6a7e0f01e4528a",
 "timestamp": "2019-02-10T18:25:42",
 "witness": "1.6.83",
 "transaction_merkle_root": "e8fdfcbd168ae9da64826d93c2fb88d19ac5f9fc",
 "extensions": [],
 "witness_signature": "1f4aa0526cf96d40f1b7c971b9bd39c72818b5dce421b3ec4e730d2f720e4a3a8e2f6dfe2696f8a52e221f4bfb4f828eff8488d6c6131933fc85a01437893564db",
 "transactions": [
  {
     "ref_block_num": 31978,
     "ref_block_prefix": 301877440,
     "expiration": "2019-02-10T18:26:08",
     "operations": [
      [
         73,
        {
           "proxy_memo": "QmcPwEMDdceMqzGNc7CCuffG7GvQnCFDJGteZMhTNtSYaA",
           "fee": {
             "amount": 1,
             "asset_id": "1.3.5"
          },
           "request_params": {
             "from": "1.2.17539",
             "to": "1.2.46",
             "proxy_account": "1.2.693712",
             "amount": {
               "amount": 10000,
               "asset_id": "1.3.5"
            },
             "percentage": 1000,
             "memo": "0ddad68dcb985a8031ff1a60c7984d36",
             "expiration": "2019-02-10T18:55:38",
             "signatures": [
               "2016918af85ee94ce72cf46f0dd8c0dec3e55eba9cf7b892e582f15b10f2949a3f7a6e4f9bdb1470414da2098032132c2ceb7725a9183fe2fe0eaa2b87c087ab88"
            ]
          },
           "extensions": []
        }
      ]
    ],
     "extensions": [],
     "signatures": [
       "1b0a289b4322ea6f522f7400bc368673a60aec7c28da463fcebf338a591cf7d8c8081ca39533a7ae28346cea503745804064f3d9f946f9bb2a13d5a04a3f751cfc"
    ],
     "operation_results": [
      [
         0,
        {}
      ]
    ]
  },
  {
     "ref_block_num": 31979,
     "ref_block_prefix": 2463097822,
     "expiration": "2019-02-10T18:26:09",
     "operations": [
      [
         0,
        {
           "fee": {
             "amount": 1000,
             "asset_id": "1.3.1"
          },
           "from": "1.2.19643",
           "to": "1.2.1061995",
           "amount": {
             "amount": "20916437581",
             "asset_id": "1.3.1"
          },
           "extensions": []
        }
      ]
    ],
     "extensions": [],
     "signatures": [
       "1f1918828badce7d0f0a05ee5890aba48dafe1e59f9ceb3a680f8abdaa17546c827f4302988d51857d1b89188bb2ba426410015c2d627cfa2dfa44c441348d3105"
    ],
     "operation_results": [
      [
         0,
        {}
      ]
    ]
  },
  {
     "ref_block_num": 31979,
     "ref_block_prefix": 2463097822,
     "expiration": "2019-02-10T18:26:09",
     "operations": [
      [
         73,
        {
           "proxy_memo": "QmTK6dHnEixSNoWgB14j1ZujKhT1RjEgXvUVJtcdWwJoTX",
           "fee": {
             "amount": 1,
             "asset_id": "1.3.5"
          },
           "request_params": {
             "from": "1.2.3840",
             "to": "1.2.46",
             "proxy_account": "1.2.693712",
             "amount": {
               "amount": 10000,
               "asset_id": "1.3.5"
            },
             "percentage": 1000,
             "memo": "5bfa26ee65ddc08558a8bf0f01dfe93a",
             "expiration": "2019-02-10T18:55:41",
             "signatures": [
               "2041dafb5c38ecc885f730af79cf741f5fc50c0f5b24c4f2d9fbfca7a34009394b3efea5ef426f4f7eb864431c8f9462b31a0e08af7fa6367b99d5673c502fe473"
            ]
          },
           "extensions": []
        }
      ]
    ],
     "extensions": [],
     "signatures": [
       "1b15649c701dad9aa38fc14ef85e28de849637a390fd46765c2960073f3993522d6d2a0e795f5c30005877cddafbcd926a9d94be6a763607d24b5fbf9e2b03fef2"
    ],
     "operation_results": [
      [
         0,
        {}
      ]
    ]
  }
],
 "block_id": "01057cecdc861a10a7c52052a1f681212fd99547",
 "signing_key": "GXC7iFA4ejkfbYQ8f7xR8rQ6dEANLqqFHKm3evo9NgCbtbx9aivXd",
 "transaction_ids": [
   "b53c8626bae9e17a07457fccca350c8edac42888",
   "9df2d2a2804c235bb16428c44f71de9468409ae7",
   "26a893ed6f6fd1b9781262c750dc8905a9af2add"
]
}

二、如何处理转账Memo2.1 构造memo

  我们回顾一下发起交易章节中构造的转账消息体,转账的memo除了交易双方之外,其他人无法查询到明文,下面内容则对memo的结构、签名方式做一个说明,以下是我们构造的转账消息体。

  {
 "ref_block_num": 54701, // an exist block num
 "ref_block_prefix": 2861949695, // The exist block id
 "expiration": "2019-01-18T03:35:54", // transaction expiration date, max expiration = current 24hours
 "operations": [
  [
     0, // operation id
    { // operation
       "fee": {
         "amount": 1179,
         "asset_id": "1.3.1"
      },
       "from": "1.2.937396",
       "to": "1.2.19645",
       "amount": {
         "amount": 173600000,
         "asset_id": "1.3.1"
      },
       "memo": { // memo
         "from": "GXC6cUP6LvdpcfC9G4TMre4yxB3PxttUjVK1ybybgt63ZtEKCXamC", // memo_key of from account
         "to": "GXC7o71VExYFoFJKtduFXEF15jgPdbmC1tdyT8BPCpnzCTeFiXEog", // memo_key of to account
         "nonce": 1, // nonce of encryption key
         "message": "15e06e19346d8f9c2d5355abcf5fffaa"// ECIES encrypted message
      },
       "extensions": []
    }
  ]
],
 "extensions": [],
 "signatures": []
}

  我们可以看到到转账交易的memo由以下4部分组成:

  from: 发起方的memo public key

  to: 接收方的memo public key

  nonce: 长整型随机数

  message: 加密消息体

第一步: 获取对方的memo public key

  通过get_account_by_name方法,我们可以获得对应账户的链上信息

  request:

  curl--data'{
   "jsonrpc": "2.0",
   "method": "call",
   "params": [0, "get_account_by_name", [<to_account>]],
   "id": 1
}' https://node1.gxb.io/rpc

  response:

  {
       "id": "1.2.19645",
       "membership_expiration_date": "1970-01-01T00:00:00",
       "merchant_expiration_date": "1970-01-01T00:00:00",
       "datasource_expiration_date": "1970-01-01T00:00:00",
       "data_transaction_member_expiration_date": "1970-01-01T00:00:00",
       "registrar": "1.2.26",
       "referrer": "1.2.26",
       "lifetime_referrer": "1.2.26",
       "merchant_auth_referrer": "1.2.0",
       "datasource_auth_referrer": "1.2.0",
       "network_fee_percentage": 2000,
       "lifetime_referrer_fee_percentage": 3000,
       "referrer_rewards_percentage": 0,
       "name": "binance-1",
       "vm_type": "",
       "vm_version": "",
       "code": "",
       "code_version": "",
       "abi": {
           "version": "gxc::abi/1.0",
           "types": [],
           "structs": [],
           "actions": [],
           "tables": [],
           "error_messages": [],
           "abi_extensions": []
      },
       "owner": {
           "weight_threshold": 1,
           "account_auths": [],
           "key_auths": [
              [
                   "GXC8XBces1ohTTVNeWB97HoyCHmRaTWNcFKdMWfdJqvMw8FmWjNqK",
                   1
              ]
          ],
           "address_auths": []
      },
       "active": {
           "weight_threshold": 1,
           "account_auths": [],
           "key_auths": [
              [
                   "GXC8FNySGvDBzRLTHyLTewWpiKbC718y7nZ3jU2Vbcx7XxF5z2SK3",
                   1
              ]
          ],
           "address_auths": []
      },
       "options": {
           "memo_key": "GXC7o71VExYFoFJKtduFXEF15jgPdbmC1tdyT8BPCpnzCTeFiXEog",
           "voting_account": "1.2.5",
           "num_witness": 0,
           "num_committee": 0,
           "votes": [],
           "extensions": []
      },
       "statistics": "2.6.19645",
       "whitelisting_accounts": [],
       "blacklisting_accounts": [],
       "whitelisted_accounts": [],
       "blacklisted_accounts": [],
       "owner_special_authority": [
           0,
          {}
      ],
       "active_special_authority": [
           0,
          {}
      ],
       "top_n_cONTrol_flags": 0
  }

  得到:

  letto_memo_key=to_account.options.memo_key

第二步: 计算Shared Secret

  letshared=secp256k1.ecdhUnsafe(to_memo_key, from_private_key)
letS=shared.Q.x.toBuffer({size: 32}); // Q is instance of Point(x,y), get x axis as shared seed
if(S.length<32) { // fill by 0 if length < 32
   letpad=newBuffer(32-S.length).fill(0);
   S=Buffer.concat([pad, S]);
}
letshared_secret=sha512(S);

第三步: 生成Nonce

  letnonce=randomUint64().toString();

第四步: AES加密, 计算checksum

  letkeyHash=sha512(nonce.toBytes().concat(shared_secret.toBytes()));
letiv=keyHash.slice(64, 96);
letkey=keyHash.slice(0, 64);
letaes=newAES(iv,key);
lETChecksum=sha256(message).slice(0,4);
letpayload=checksum.concat(message.toBytes());
letencryptedMessage=aes.encrypt(payload);

2.2 解析memo第一步: 获取对方的memo public key

  letfrom_memo_key=transaction.operations[0][1].memo.from;

第二步: 计算Shared Secret

  letshared=secp256k1.ecdhUnsafe(from_memo_key, to_private_key)
letS=shared.Q.x.toBuffer({size: 32}); // Q is instance of Point(x,y), get x axis as shared seed
if(S.length<32) { // fill by 0 if length < 32
   letpad=newBuffer(32-S.length).fill(0);
   S=Buffer.concat([pad, S]);
}
letshared_secret=sha512(S);

第三步: AES解密, 验证checksum

  letkeyHash=sha512(transaction.operations[0][1].memo.nonce.toBytes().concat(shared_secret.toBytes()));
letiv=keyHash.slice(64, 96);
letkey=keyHash.slice(0, 64);
letaes=newAES(iv,key);
letpayload=aes.decrypt(transaction.operations[0][1].memo.message);
letchecksum=payload.slice(0, 4);
letmessage=payload.slice(4).toString('utf8');
assert(sha256(message).slice(0,4) ==checksum,'Invalid checksum');

  问题:

  1.写出测试网账户nathan的memo-key(10个gxc)

  2.GXChain主网上,18229368区块中,存在两笔交易,其ref_block_num均为10359,ref_block_prefix为3297302971,那么这是引用的哪一个区块,写出区块号?(10进制)(25个gxc)

  3.GXChain主网上,当最新区块号18229368时,最新不可逆区块号为?(10进制)(25个gxc)

  提示:从最新区块号开始往前找,15个不同节点打包的区块。(15大于21个公信节点的2/3,代表15个不同公信节点确认了该区块,此时为最新不可逆区块)

  4.解析这个memo的明文字符串,其中from账户为测试网的from-test账户,账户私钥为5HwCaczD1yotNnHNPhVwkGxS9f2Zq4bEx6yeDSxZUZ5agvB6KUR(40个gxc)

  {
 "from": "GXC5fTHMVQsmik8wh4QrHm6VB6s5q4g8E9XMtF4c27qvonquj1iUx",
 "to": "GXC8AoHzhXhMRV9AFTihMAcQPNXKFEZCeYNYomdcc7vh8Gzp7b7xP",
 "nonce": "1514762620509931220",
 "message": "8908f4c196d6fc03bf42172172bff673e85b0b16049d710e2c8816c6e4a3fa13"
}

  下期教程发布:北京时间3月29日20点

  

  重点推荐

  (点击图片即可看文章)

  

  

  

  虽然看不懂,但留个脚印

阅读更多

上一篇:传说中的去中心化交易所长什么样?想登录看一看

下一篇:火了!GXC登陆Bithumb首日,交易量和媒体关注度双双爆棚

您可能喜欢:

关于我们联系我们自媒体进驻
Copyright © 2013 比特巴手机版
币圈人都爱上的网站,新闻行情教程人物测评资讯大全