介绍
我尝试使用区块链发送交易以将令牌从我的帐户发送到另一个帐户。
本文旨在加深您对发送交易所需的数据结构的理解,这些数据结构是您在发送交易的过程中学到的。
背景
虽然我们的业务涉及区块链,但我们所处的环境经常使用其他公司准备的 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 小时。
要输入的值为初期ブロックからの経過時刻をミリ秒単位で指定。
很混乱,但是要输入的值是这样计算的。
-
用
Date.now()获取当前的UnixTimestamp(单位:毫秒) - 通过
EPOCH_ADJUSTMENT纠正UnixTimestamp(单位:秒) - 将 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.xym(数量 1)
https://testnet.symbol.fyi/transactions/6C749FB3B485BBEFCAEAF87C890C6147ACDB809E72CD006C4B096BE4B132888B
概括
我使用 Symbol 区块链提交了一个简单的交易来发送一个令牌。
当你听说区块链时,你可能会认为它很难处理,但是通过使用 SDK,我认为发送简单的交易除了了解数据结构之外并没有那么困难。
正如我在选择理由中所写,Symbol 适合作为入门级区块链链,因为它可以通过 API 操作,日本社区强大,您可以期待快速回答问题。参考
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308632626.html