介绍

我尝试使用区块链发送交易以将令牌从我的帐户发送到另一个帐户。
本文旨在加深您对发送交易所需的数据结构的理解,这些数据结构是您在发送交易的过程中学到的。

背景

虽然我们的业务涉及区块链,但我们所处的环境经常使用其他公司准备的 API。
我想亲自体验发送交易的核心部分,所以我尝试发送一个发送令牌的交易。

目标

目标是能够将代币从您自己的帐户发送到其他帐户,并能够在外部站点上确认转移已完成。

使用的区块链

我们使用了 Symbol 区块链。
选择的理由如下。

  • REST API节点超过1000个,参考节点选择多,不依赖特定节点
  • 可通过 API 操作,易于从现有系统连接
  • 对志愿者开发有用的 SDK 和外围设备向公众开放
  • 多层上的多重签名在协议级别合并,在考虑组织中的操作时非常实用
  • 日语社区很强大,您可以期待快速回答您的问题

环境/主包

这一次,我使用了带有 NEMTUS 发布的类型信息的 TypeScript 版本 SDK。

  • Node.js 17.9.0
  • TypeScrypt 4.8.4
  • ts-node 10.9.1
  • nemtus/symbol-sdk-typescript
  • nemtus/symbol-sdk-openapi-generator-typescript-axios

代码流

在区块链上发送交易时,基本流程是
创建交易→签名→发送到区块链网络
变成。

除了上述之外,本次发送交易的程序在发送完成后会输出信息进行确认。

政策

我的目标是用尽可能少的代码创建一个简单的表单。
以成功发送交易为目标,我们还将动态可获取的属性值设置为直接值。
要放在事务上的消息是可选的,但它是作为标准附加的。

代码

所有的

import { SymbolFacade } from "@nemtus/symbol-sdk-typescript/esm/facade/SymbolFacade";
import { PrivateKey } from "@nemtus/symbol-sdk-typescript/esm/CryptoTypes";
import { KeyPair } from "@nemtus/symbol-sdk-typescript/esm/symbol/KeyPair";
import { Signature } from "@nemtus/symbol-sdk-typescript/esm/symbol/models";
import {
   Configuration,
   TransactionRoutesApi,
} from "@nemtus/symbol-sdk-openapi-generator-typescript-axios";

(async () => {
   // ネットワークタイプを指定してSDKを初期化
   const facade = new SymbolFacade("testnet");

   // トランザクションを送信するアカウントの鍵ペアを取得
   const privateKeyString = "AFB4B406B5BF047BE2045E5AB9EA81A7971A854B402D93C10DA2ABA0467271A5";
   const privateKey = new PrivateKey(privateKeyString);
   const keyPair = new KeyPair(privateKey);
   const publicKeyString = keyPair.publicKey.toString();

   // ブロックチェーンの初期ブロックが生成されたときの時間(UnixTime秒)
   const EPOCH_ADJUSTMENT = 1637848847;

   // トランザクションの有効期限
   const now = Date.now();
   const deadline = BigInt(now - EPOCH_ADJUSTMENT * 1000 + 2 * 60 * 60 * 1000);

   // トランザクションの送信先アドレス
   const targetAddressString = "TDMYLKCTEVPSRPTG4UXW47IQPCYNLW2OVWZMLGY";

   // 平文メッセージ
   const messageString = "Hello Symbol!!";
   const messageNumberArray = [0, ...(new TextEncoder()).encode(messageString)];
   const messageUint8Array = new Uint8Array(messageNumberArray);

   // 送信するトークンのID
   const TOKEN_ID = BigInt("0x3A8416DB2D53B6C8");

   // トランザクションのデータ生成
   const transaction = facade.transactionFactory.create({
      type: "transfer_transaction",
      signerPublicKey: publicKeyString,
      deadline,
      recipientAddress: targetAddressString,
      mosaics: [{ mosaicId: TOKEN_ID, amount: 1000000n }],
      message: messageUint8Array
   });

   // 手数料設定
   const feeMultiplier = 100;
   (transaction as any).fee.value = BigInt(
           (transaction as any).size * feeMultiplier
   );

   // 署名
   const signature = facade.signTransaction(keyPair, transaction);
   (transaction as any).signature = new Signature(signature.bytes);

   // トランザクションのハッシュを計算
   const hash = facade.hashTransaction(transaction);
   console.log(hash.toString());
   console.log(`https://testnet.symbol.fyi/transactions/${hash.toString()}`);

   // トランザクション送信時のpayload
   const transactionPayload = (
           facade.transactionFactory.constructor as any
   ).attachSignature(transaction, signature);

   // トランザクションを送信する際の設定情報
   const NODE_URL = "https://sym-test-02.opening-line.jp:3001";
   const configurationParameters = {
      basePath: NODE_URL,
   };
   const configuration = new Configuration(configurationParameters);

   // トランザクションのアナウンス実行(送信)
   try {
      const transactionRoutesApi = new TransactionRoutesApi(configuration);
      console.log(transactionPayload);
      const response = await transactionRoutesApi.announceTransaction({
         transactionPayload,
      });
      console.log(response.data);
      console.log(`${NODE_URL}/transactionStatus/${hash.toString()}`)
   } catch (err) {
      console.error(err);
   }
})();

每个部分

SDK初始化

使用您的网络类型初始化 SDK。如何指定如下。

  • 测试网:“测试网”
  • 主网:“主网”
// ネットワークタイプを指定してSDKを初期化
const facade = new SymbolFacade("testnet");

交易源账户的密钥对信息推导

从私钥导出用于签名的交易源账户的密钥对信息。

const privateKeyString = "AFB4B406B5BF047BE2045E5AB9EA81A7971A854B402D93C10DA2ABA0467271A5";
const privateKey = new PrivateKey(privateKeyString);
const keyPair = new KeyPair(privateKey);
const publicKeyString = keyPair.publicKey.toString();

设置交易过期

设置事务过期时间。如果到达此处设置的日期和时间并且没有被区块链批准,则该交易将被丢弃。
这次,将其设置为 2 小时。

要输入的值为初期ブロックからの経過時刻をミリ秒単位で指定

很混乱,但是要输入的值是这样计算的。

  1. Date.now()获取当前的UnixTimestamp(单位:毫秒)
  2. 通过EPOCH_ADJUSTMENT纠正UnixTimestamp(单位:秒)
  3. 将 2 小时转换为毫秒

    EPOCH_ADJUSTMENT...
    Symbol 区块链中独特的时间概念,基于初始块创建的时间 (0)(类似于 UnixTimestamp),每个 1秒 加 1 的值

    • 测试网:1637848847(截至 2022 年 10 月 24 日)
    • 主网:1615853185

    如上所述,EPOCH_ADJUSTMENT 的值根据第一个块的生日而波动。
    由于测试网很少从第一个区块重置和重新生成,在实现时是从节点端点/network/properties获取或确认的吗?
    查看以下持续维护的文章。

    从节点检索时,需要排除处理,因为在末尾添加了s

    // ブロックチェーンの初期ブロックが生成されたときの時間(UnixTime秒)
    const EPOCH_ADJUSTMENT = 1637848847;
    
    // トランザクションの有効期限
    const now = Date.now();
    const deadline = BigInt(now - EPOCH_ADJUSTMENT * 1000 + 2 * 60 * 60 * 1000);
    

    设置目标地址

    设置交易的目标地址。
    这次,我们设置了 Faucet 的地址,它是测试网发行代币的来源。

    如果地址的第一个字符是T,则可以区分为测试网地址,如果是N,则可以区分为主网地址。

    // トランザクションの送信先アドレス
    const targetAddressString = "TDMYLKCTEVPSRPTG4UXW47IQPCYNLW2OVWZMLGY";
    

    配置事务消息

    一笔交易有一个 1024 字节数据的可写区域,在 Symbol 区块链中称为消息区域。
    目前向公众开放的许多 Symbol Wallet 应用程序都允许将书写/阅读作为自由文本消息区域。
    在不知道发送方或接收方的私钥的情况下,也可以发送无法解密的加密数据。
    这次它以纯文本形式发送。

    在创建稍后描述的事务数据时,可以通过将messageUint8Array字符串设置为message对象键的值来设置事务中的消息。
    在本文介绍的代码中添加0是因为需要在开头添加0才能在资源管理器中显示不乱码的消息内容。
    如果您想使用完整的 1024 字节而不用担心在资源管理器中出现乱码,您可以不使用0 发送。

    // 平文メッセージ
    const messageString = "Hello Symbol!!";
    const messageNumberArray = [0, ...(new TextEncoder()).encode(messageString)];
    const messageUint8Array = new Uint8Array(messageNumberArray);
    

    设置要发送的令牌 ID

    设置要发送的令牌的 ID。这一次,我们设置了symbol.xym,这是 Symbol 区块链的原生代币。
    symbol.xym 令牌 ID 可以在可以从节点端点 /network/properties 获取的 currencyMosaicId 属性中找到。
    它由'分隔,间隔为4个字符,不包括开头的0x,所以如果你想动态获取它,不要忘记解析。

    • 测试网:0x6BED913FA20223F8
    • 主网:0x3A8416DB2D53B6C8
    // 送信するトークンID
    const TOKEN_ID = BigInt("0x3A8416DB2D53B6C8");
    

    交易数据创建

    为要发送的交易创建数据。让我们来看看我们设置的每个值。

    物品 内容 必需的
    类型 本次交易类型设置为简单转账交易。
    Symbol 区块链定义了超过 20 种交易类型,可以发行各种交易,例如发行代币、为地址和代币设置别名、聚合多个交易。
    签名者公钥 设置发送上一节中导出的交易的帐户的密钥对的公钥。这是必需的设置项目。
    最后期限 设置上一节中衍生的交易的到期日期
    收件人地址 设置目标地址。
    马赛克 我正在设置要发送的令牌的 ID 和数量。
    由于数据是作为整数值处理的,因此需要设置一个考虑可除性的值(使用多少位小数作为数量单位)。
    symbol.xym 是1000000,由于可除性为 6,数量为 1。
    -
    信息 设置要发送的消息。 -
    // トランザクションのデータ生成
    const transaction = facade.transactionFactory.create({
        type: "transfer_transaction",
        signerPublicKey: publicKeyString,
        deadline,
        recipientAddress: targetAddressString,
        mosaics: [{ mosaicId: TOKEN_ID, amount: 1000000n }],
        message: messageUint8Array
    });
    

    费用设置

    我们使用费用系数来设置发送交易时收取的最高费用。不会收取超过此处设定的费用的费用。
    有效费用取决于交易规模和目标节点的设置。
    细节是这里请确认。

     // 手数料設定
     const feeMultiplier = 100;
     (transaction as any).fee.value = BigInt(
         (transaction as any).size * feeMultiplier
     );
    

    签名

    交易使用上一节中获得的密钥对进行签名。

    // 署名
    const signature = facade.signTransaction(keyPair, transaction);
    (transaction as any).signature = new Signature(signature.bytes);
    

    计算交易哈希值

    计算上一节创建的交易的交易哈希值。
    这里计算的哈希值不用于交易传输,而是用于传输后的确认。

     // トランザクションのハッシュを計算
     const hash = facade.hashTransaction(transaction);
     console.log(hash.toString());
     console.log(`https://testnet.symbol.fyi/transactions/${hash.toString()}`);
    

    获取有效载荷

    发送交易时检索有效负载。此有效负载将在下一节中通知节点。

    // トランザクション送信時のpayload
    const transactionPayload = (
      facade.transactionFactory.constructor as any
    ).attachSignature(transaction, signature);
    

    发送交易时的设置

    设置发送交易时所需的信息。 apiKey、username、accessToken等认证信息看似是可选的,但由于这次没有特别认证,所以只设置了连接目标节点的URL。

     // 接続先ノード情報
     const NODE_URL = "https://sym-test-02.opening-line.jp:3001";
     const configurationParameters = {
         basePath: NODE_URL,
     };
     const configuration = new Configuration(configurationParameters);
    

    提交交易

    最后,将创建的交易提交到区块链。

    // トランザクションのアナウンス実行(送信)
    try {
      const transactionRoutesApi = new TransactionRoutesApi(configuration);
      console.log(transactionPayload);
      const response = await transactionRoutesApi.announceTransaction({
          transactionPayload,
      });
      console.log(response.data);
      console.log(`${NODE_URL}/transactionStatus/${hash.toString()}`)
    } catch (err) {
      console.error(err);
    }
    

    很重要的一点

    请注意,发送交易时响应消息中不返回以下内容 = 发送成功。
    { message: 'packet 9 was pushed to the network via /transactions' }
    上述消息仅确认所公布交易的数据格式正确且已被节点接受,不保证一定会被区块链认可,即使传输失败也会返回响应.
    要检查它是否正确发送,请转到资源管理器并尽可能检查节点。

    检查交易提交结果

    节点确认

    使用上一节中的console.log(${NODE_URL}/transactionStatus/${hash.toString()})访问控制台输出的URL,查看传输结果。

    显示示例 1 未批准

    {"group":"unconfirmed","code":"Success","hash":"21E1AF8649E6A23FFF6C8C84371832BEE70E9C34F04A320F50E54E07BB843270","deadline":"29000398773","height":"0"}
    

    发送后立即没有被区块链批准,group变成了unconfirmed
    deadline,即上一节中设置的交易的到期日期,也会显示出来。如果在此期限内未获得批准,交易将被拒绝。
    height,表示由于未批准状态导致的块高度,是0,因为尚未确定将包含多少块高度。

    显示示例 2 批准

    {"group":"confirmed","code":"Success","hash":"6C749FB3B485BBEFCAEAF87C890C6147ACDB809E72CD006C4B096BE4B132888B","deadline":"29000922855","height":"803674"}
    

    提交后,group 变成了confirmed,因为交易在区块链上得到了确认。
    由于包含在区块中,因此区块高度是固定的,包含交易时的区块高度输出到height

    显示示例 3 失败

    {"hash":"22CE975B6EF156C27195A8D4DD30EAD990AD400E01917F57E13480C1DAE9A7B4","code":"Failure_Core_Insufficient_Balance","deadline":"29001116654","group":"failed"}
    

    这是由于发件人帐户中的资金不足而导致发送失败的示例。
    code输出为Failure_Core_Insufficient_Balance,表示余额不足。

    请参阅此处了解code 类型。
    https://github.com/symbol/symbol/blob/dev/client/rest/src/catapult-sdk/model/status.js

    日文补充文章

    在外部网站上确认

    访问下面的资源管理器进行检查。
    测试网:https://testnet.symbol.fyi/
    主网:https://symbol.fyi/

    当您执行本文中描述的代码时,会输出在控制台中显示事务详细信息的 Explorer 中的 URL。
    在您发送的交易被区块链批准之前,会显示一条不存在的消息,因此如果您想在资源管理器中查看交易详情,请等待几秒钟到 30 秒,直到交易被批准后再访问。

    例子

    概括

    我使用 Symbol 区块链提交了一个简单的交易来发送一个令牌。
    当你听说区块链时,你可能会认为它很难处理,但是通过使用 SDK,我认为发送简单的交易除了了解数据结构之外并没有那么困难。
    正如我在选择理由中所写,Symbol 适合作为入门级区块链链,因为它可以通过 API 操作,日本社区强大,您可以期待快速回答问题。

    参考


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308632626.html

相关文章:

  • 2021-10-22
  • 2021-11-05
  • 2021-12-28
  • 2021-11-07
  • 2021-11-18
  • 2021-11-08
  • 2021-10-03
  • 2018-07-15
猜你喜欢
  • 2021-12-28
  • 2021-10-25
  • 2021-11-07
  • 2021-11-07
  • 2021-08-29
  • 2021-06-14
  • 2021-10-03
  • 2021-12-20
相关资源
相似解决方案