XEMBook氏作成の『今日から現場で使える速習Symbolブロックチェーン JavaScript版』を、Symbol-SDK v3 対応バージョンにだーりんピ氏がアップデートしてくださったものを、さらに最新の Symbol-SDK v3.3.0 に対応させて書籍化し、技術書典19に合わせて発刊しました。その際の最終チェックはmikun氏にお願いしました。
今回の書籍は初めてSymbolに触れる方向けとするため、v2とv3の比較はせずに、v3の内容のみで構成しました。
以下がGithubのリンクです。
当初のv3対応版から最新のSymbol-SDK v3.3.0に対応させた際に、どんな改訂を行ったかをメモ的に書いていきます。
第3章 アカウント
3.4 現場で使えるヒント
3.4.1 暗号化と署名
削除箇所
以下の内容を削除しました。
▼ symbol-sdk v3.0.7 での注意点
注意: v3.0.7 では復号化データの構造が異なります。 v3.0.8 以降では、結果とメッセージを持つ オブジェクト ですが、v3.0.7 では結果とメッセージの 配列 です。 このため、復号化したメッセージへのアクセス方法が異なります。
v3.0.7
if (decryptMessageData[0]) {
decryptMessage = new TextDecoder().decode(decryptMessageData[1]);
console.log(decryptMessage);
} else {
console.log("decrypt failed!");
}
> [true, Uint8Array(13)]
> "Hello Symbol!"
3.4.2 アカウントの保管
この書籍を作成時において、V3 SDKの読み込み方法ではアカウント保管の内容がうまく動作しないため、下記のように追記をしました。
追記箇所
※本稿作成時点で、V3 SDKの読込方法ではこのページ内容は動作せずのためご注意ください。
第4章 トランザクション
4.2 トランザクション作成
4.2.1 Bobへの転送トランザクション
「暗号文メッセージ」の箇所において、冒頭に以下の文章を追加しました。
追加文
EncryptedMessageを使用すると、「指定したメッセージが暗号化されています」という意味のフラグ(目印)がつきます。 エクスプローラーやウォレットはそのフラグを参考にメッセージを無用にデコードしなかったり、非表示にしたりなどの処理を行います。 このメソッドが暗号化をするわけではありません。
4.4 確認
冒頭の文章が「4.3 署名とアナウンス」と重複するため、削除しました。
削除文
作成したトランザクションを秘密鍵で署名して、任意のノードを通じてアナウンスします。
4.6 アグリゲートトランザクション
4.6.1 起案者の署名だけが必要な場合
冒頭のコードを変更しました。
[変更内容]
・'tx1' → '\0tx1' に変更
・'tx2' → '\0tx2' に変更
・V2→ V3 に修正
変更前
bob = facade.createAccount(sdkCore.PrivateKey.random());
carol = facade.createAccount(sdkCore.PrivateKey.random());
// アグリゲートTxに含めるTxを作成
descriptor1 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
bob.address, // 送信先アドレス
[], // 送信モザイク
'tx1' // 平文メッセージ
);
innerTx1 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor1, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
);
descriptor2 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
carol.address, // 送信先アドレス
[], // 送信モザイク
'tx2' // 平文メッセージ
);
innerTx2 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor2, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
);
embeddedTransactions = [
innerTx1,
innerTx2
];
// アグリゲートTx作成
descriptor = new sdkSymbol.descriptors.AggregateCompleteTransactionV3Descriptor(
facade.static.hashEmbeddedTransactions(embeddedTransactions),
embeddedTransactions
);
aggregateTx = facade.createTransactionFromTypedDescriptor(
descriptor, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
100, // 手数料乗数
60 * 60 * 2, // Deadline:有効期限(秒単位)
0 // 連署者数
);
// 署名とアナウンス
sig = alice.signTransaction(aggregateTx);
jsonPayload = facade.transactionFactory.static.attachSignature(aggregateTx, sig);
await fetch(
new URL('/transactions', NODE),
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: jsonPayload,
}
)
.then((res) => res.json())
.then((json) => {
return json;
});
変更後
bob = facade.createAccount(sdkCore.PrivateKey.random());
carol = facade.createAccount(sdkCore.PrivateKey.random());
// アグリゲートTxに含めるTxを作成
descriptor1 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
bob.address, // 送信先アドレス
[], // 送信モザイク
'\0tx1' // 平文メッセージ
);
innerTx1 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor1, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
);
descriptor2 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
carol.address, // 送信先アドレス
[], // 送信モザイク
'\0tx2' // 平文メッセージ
);
innerTx2 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor2, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
);
embeddedTransactions = [
innerTx1,
innerTx2
];
// アグリゲートTx作成
descriptor = new sdkSymbol.descriptors.AggregateCompleteTransactionV3Descriptor(
facade.static.hashEmbeddedTransactions(embeddedTransactions),
embeddedTransactions
);
aggregateTx = facade.createTransactionFromTypedDescriptor(
descriptor, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
100, // 手数料乗数
60 * 60 * 2, // Deadline:有効期限(秒単位)
0 // 連署者数
);
// 署名とアナウンス
sig = alice.signTransaction(aggregateTx);
jsonPayload = facade.transactionFactory.static.attachSignature(aggregateTx, sig);
await fetch(
new URL('/transactions', NODE),
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: jsonPayload,
}
)
.then((res) => res.json())
.then((json) => {
return json;
});
これ以降、コード内の「v2」を「v3」に変更した箇所は、コードそのものの掲載は省略します。
第5章 モザイク
5.1 モザイク生成
「duration:有効期限」のコード内の「v2」を「v3」に変更
第7章 メタデータ
7.1 アカウントに登録
コード内の「v2」を「v3」に変更
7.2 モザイクに登録
BigInt の場合、先頭が0の時、変換すると0が省略されてしまい、正しいURLにならなくなってしまうので、冒頭のコード内の「targetMosaic」を変更しました。
また、
targetMosaic.toString(16).toUpperCase() ←これを
↓
targetMosaic.toUpperCase()
と変更しました。
変更前
// ターゲットと作成者アドレスの設定
targetMosaic = 0x1275B0B7511D9161n; // メタデータ記録先モザイク
mosaicInfo = await fetch(
new URL('/mosaics/' + targetMosaic.toString(16).toUpperCase(), NODE),
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
)
変更後
// ターゲットと作成者アドレスの設定
targetMosaic = "1275B0B7511D9161"; // メタデータ記録先モザイク
mosaicInfo = await fetch(
new URL('/mosaics/' + targetMosaic.toUpperCase(), NODE),
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
)
さらに、コード内の「v2」を「v3」に変更
7.3 ネームスペースに登録
冒頭コード内の「v2」を「v3」に変更
第8章 ロック
8.1 ハッシュロック
8.1.1 アグリゲートボンデッドトランザクションの作成
[変更内容]
冒頭コード内の
・thank you! → \0thank you! に変更
・「v2」を「v3」に変更
変更前
bob = facade.createAccount(sdkCore.PrivateKey.random());
namespaceIds = sdkSymbol.generateNamespacePath("symbol.xym");
namespaceId = namespaceIds[namespaceIds.length - 1];
// アグリゲートTxに含めるTxを作成
descriptor1 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
bob.address, // Bobへの送信
[
// 1XYM送金
new sdkSymbol.descriptors.UnresolvedMosaicDescriptor(
new sdkSymbol.models.UnresolvedMosaicId(namespaceId),
new sdkSymbol.models.Amount(1000000n)
)
],
new Uint8Array() // メッセージ無し
);
tx1 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor1, // トランザクション Descriptor 設定
alice.publicKey // Aliceから
);
descriptor2 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
alice.address, // Aliceへの送信
[],
new TextEncoder('utf-8').encode('thank you!') // 平文メッセージ
);
tx2 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor2, // トランザクション Descriptor 設定
bob.publicKey // Bobから
);
embeddedTransactions = [
tx1,
tx2
];
// アグリゲートTx作成
aggregateDescriptor = new sdkSymbol.descriptors.AggregateBondedTransactionV3Descriptor(
facade.static.hashEmbeddedTransactions(embeddedTransactions),
embeddedTransactions
);
aggregateTx = facade.createTransactionFromTypedDescriptor(
aggregateDescriptor, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
100, // 手数料乗数
60 * 60 * 2, // Deadline:有効期限(秒単位)
1 // 連署者数
);
// 署名
sig = alice.signTransaction(aggregateTx);
jsonPayload = facade.transactionFactory.static.attachSignature(aggregateTx, sig);
変更後
bob = facade.createAccount(sdkCore.PrivateKey.random());
namespaceIds = sdkSymbol.generateNamespacePath("symbol.xym");
namespaceId = namespaceIds[namespaceIds.length - 1];
// アグリゲートTxに含めるTxを作成
descriptor1 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
bob.address, // Bobへの送信
[
// 1XYM送金
new sdkSymbol.descriptors.UnresolvedMosaicDescriptor(
new sdkSymbol.models.UnresolvedMosaicId(namespaceId),
new sdkSymbol.models.Amount(1000000n)
)
],
new Uint8Array() // メッセージ無し
);
tx1 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor1, // トランザクション Descriptor 設定
alice.publicKey // Aliceから
);
descriptor2 = new sdkSymbol.descriptors.TransferTransactionV1Descriptor( // Txタイプ:転送Tx
alice.address, // Aliceへの送信
[],
new TextEncoder('utf-8').encode('\0thank you!') // 平文メッセージ
);
tx2 = facade.createEmbeddedTransactionFromTypedDescriptor(
descriptor2, // トランザクション Descriptor 設定
bob.publicKey // Bobから
);
embeddedTransactions = [
tx1,
tx2
];
// アグリゲートTx作成
aggregateDescriptor = new sdkSymbol.descriptors.AggregateBondedTransactionV3Descriptor(
facade.static.hashEmbeddedTransactions(embeddedTransactions),
embeddedTransactions
);
aggregateTx = facade.createTransactionFromTypedDescriptor(
aggregateDescriptor, // トランザクション Descriptor 設定
alice.publicKey, // 署名者公開鍵
100, // 手数料乗数
60 * 60 * 2, // Deadline:有効期限(秒単位)
1 // 連署者数
);
// 署名
sig = alice.signTransaction(aggregateTx);
jsonPayload = facade.transactionFactory.static.attachSignature(aggregateTx, sig);
第9章 マルチシグ化
9.1 マルチシグの登録
冒頭コード内の「v2」を「v3」に変更
9.3 マルチシグ署名
9.3.1 アグリゲートコンプリートトランザクションで送信
冒頭コード内の「v2」を「v3」に変更
9.3.2 アグリゲートボンデッドトランザクションで送信
冒頭コード内の「v2」を「v3」に変更
9.5 マルチシグ構成変更
9.5.1 マルチシグ構成の縮小
冒頭コード内の「v2」を「v3」に変更
9.5.2 連署者構成の差替え
冒頭コード内の「v2」を「v3」に変更
第11章 制限
11.1 アカウント制限
11.1.1 指定アドレスからの受信制限・指定アドレスへの送信制限
「restrictionFlags は v2 の AddressRestrictionFlagに相当します。」の直前に以下の説明を挿入しました。
AddressRestrictionFlagについては以下の通りです。
{1: 'AllowIncomingAddress', 16385: 'AllowOutgoingAddress', 32769: 'BlockIncomingAddress', 49153: 'BlockOutgoingAddress'}
11.1.2 指定モザイクの受信制限
「アカウント制限と同様、 restrictionFlags は v2 の MosaicRestrictionFlag に相当します。」の直前に以下の説明を挿入しました。
MosaicRestrictionFlagについては以下の通りです。
{2: 'AllowMosaic', 32770: 'BlockMosaic'}
11.1.2 指定トランザクションの送信制限
「アカウント制限やモザイク制限と同様、 restrictionFlags は v2 の OperationRestrictionFlag に相当します。」の直前に以下の説明を挿入しました。
OperationRestrictionFlagについては以下の通りです。
{16388: 'AllowOutgoingTransactionType', 49156: 'BlockOutgoingTransactionType'}
変更点は以上となります。
まとめ
Symbol-SDKもバージョンがあがっていってるため、こういった記録も必要かもしれない、と考え、メモ書き的に残してみました。
速習Symbol JavaScript版 Symbol-SDK V3 versionは、電子版が技術書典のオンラインマーケットでいつでも購入できます。また、技術書典のオフラインイベントや技書博に出展時には、紙の本も購入できるので、その際にはぜひお越しください。
今回のこのあたりの変更点を含め、次の新刊では、v2とv3の比較版を作るかどうか検討していきます。