2
1

More than 1 year has passed since last update.

symbol-sdk@3.0.7で作るシークレットロック/プルーフトランザクション

Last updated at Posted at 2023-07-23

はじめに

こんにちは。

symbol-sdkの3系、トランザクションシリーズ第七弾です。

今回はシークレットロック・シークレットプルーフをやっていきます。

注意事項

書いてあるコードについて、正確性や完全性を保証するものではありません。あくまで参考程度として頂き、最新情報は公式ドキュメンテーションをご確認ください。

デッドラインと鍵ペア

まずはデッドラインと鍵ペアです。

import symbolSdk from 'symbol-sdk';

const network = symbolSdk.symbol.Network.TESTNET;
const deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;

const facade = new symbolSdk.facade.SymbolFacade(network.name);

const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY);
const keyPair = new facade.constructor.KeyPair(privateKey);

TextEncoderとハッシュ関数

文字列をUint8Arrayに変換するので、 TextEncoder をインポートします。

import { TextEncoder } from 'util';

const textEncoder = new TextEncoder();

ハッシュ関数ライブラリをインポートします。 symbol-sdk の依存ライブラリでもあるので、追加でインストールしなくても使えます。

import { sha3_256 } from '@noble/hashes/sha3';
import { sha256 } from '@noble/hashes/sha256';
import { ripemd160 } from '@noble/hashes/ripemd160';

プルーフ

プルーフを先に作ります。文字列です。

const proof = `secret${Date.now()}`;

ハッシュアルゴリズム

使用するアルゴリズムに合わせて、 LockHashAlgorithm を選択します。

const hashAlgorithm = symbolSdk.symbol.LockHashAlgorithm.SHA3_256;
const hashAlgorithm = symbolSdk.symbol.LockHashAlgorithm.HASH_160;
const hashAlgorithm = symbolSdk.symbol.LockHashAlgorithm.HASH_256;

シークレット

各種アルゴリズムに合わせてシークレットを作成します。

SHA3_256

SHA3_256 ではこのような形になります。この secretBufferUint8Array 型となります。

const secretBuffer = sha3_256.create().update(textEncoder.encode(proof)).digest();

トランザクションに取り込むときに様々な型が使用できます。

やってみた感じだと、Uint8Array 型そのままか、16進数文字列が使用できました。

const secret = secretBuffer;
const secret = symbolSdk.utils.uint8ToHex(secret);

HASH_160

HASH_160 ですと、SHA256でハッシュした後、RIPEMD160でハッシュします。ハッシュの出力が20バイトになるので、0で埋めて32バイトにしなければなりません。

16進数文字列で扱うのが慣れているので、文字列で0埋めしました。

const secret1 = sha256.create().update(textEncoder.encode(proof)).digest();
const secret2 = ripemd160.create().update(secret1).digest();
const secret = symbolSdk.utils.uint8ToHex(secret2).padEnd(64, "0");

HASH_256

HASH_256 ですと、SHA256で2回ハッシュします。

const secret1 = sha256.create().update(textEncoder.encode(proof)).digest();
const secretBuffer = sha256.create().update(secret1).digest();

トランザクションに取り込むときに様々な型が使用できます。

const secret = secretBuffer;
const secret = new Uint8Array(secretBuffer);
const secret = symbolSdk.utils.uint8ToHex(secretBuffer);

ロック期間

ブロック数でシークレットロックの有効期限を指定します。BigInt型か BlockDuration 型が使えます。

const duration = 86400n;
const duration = new symbolSdk.symbol.BlockDuration(86400n);

シークレットロックトランザクション

それではシークレットロックトランザクションを作ります。

上記で作成したパラメータと共に、 recipientAddressmosaic を指定します。

const transaction = facade.transactionFactory.create({
  type: 'secret_lock_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: ADDRESS_RECEIVER_1,
  secret,
  mosaic: { mosaicId: 0xE74B99BA41F4AFEEn, amount: 1000000n },
  duration,
  hashAlgorithm,
});

署名と送信

署名して送信します。

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();
console.log(hash);

const sendRes = await axios.put(`${NODE_URL}/transactions`, jsonPayload).then((res) => res.data);
console.log(sendRes);

承認されるのを待つ

この次にシークレットプルーフトランザクションを送信したいので、ここでシークレットロックトランザクションの承認を待ちます。

while (true) {
  await new Promise((resolve) => setTimeout(resolve, 5000));

  const statusRes = await axios.get(`${NODE_URL}/transactionStatus/${hash}`).then((res) => res.data);
  console.log(statusRes);

  if (statusRes.group === 'confirmed') {
    break;
  }

  if (statusRes.group !== 'unconfirmed') {
    throw new Error();
  }
}

シークレットプルーフトランザクション

シークレットロックトランザクションが承認されたので、シークレットプルーフトランザクションを作成していきます。

const transaction = facade.transactionFactory.create({
  type: 'secret_proof_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: ADDRESS_RECEIVER_1,
  secret: secret,
  hashAlgorithm,
  proof: proof,
});

署名と送信とステータス確認

署名して送信してステータスを確認します。

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

const sendRes = await node.put("/transactions", jsonPayload).then((res) => res.data);
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await node.get("/transactionStatus/" + hash).then((res) => res.data);
console.log(statusRes);

おわりに

今回は、シークレットロックトランザクションとシークレットプルーフトランザクションをやっていきました。記事の都合上、2つのトランザクションをいっぺんに作りましたが、アプリへの実装の際には別々に使うことがほとんどだと思います。

シリーズ

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1