5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

nemAdvent Calendar 2021

Day 5

tsunagi-functionsでSymbolブロックチェーンのトランザクションを自由自在に作ろう!(Ruby編)

Last updated at Posted at 2022-09-22

この記事は、以下に紹介したtsunagi-functionsのRuby実装版です。

トランザクション構築の内部処理やノードへの通知方法については以下の記事もご参考ください。

Symbolブロックチェーンをよく知らないという方はこちらで速習することができます。

リポジトリ

tsunagi-functions for Ruby

関数群の提供のため、sdkという名称は今後functionsに変更予定です。

テスト

テストスクリプトを以下に置いています。実行することができればそのロジックをそのまま実装に利用することができます。

test_0_1.rb

Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

# gem "rails"

gem 'base32', '~> 0.3.4'
gem 'ed25519', '~> 1.3'
gem 'digest', '~> 3.1'
gem 'sha3', '~> 1.0', '>= 1.0.4'
gem 'test-unit', '~> 3.2', '>= 3.2.9'
gem 'activerecord', '~> 7.0', '>= 7.0.4'
テスト実行
bundle exec ruby test_0_1.rb

実装例

まずは簡単な実装例を紹介します。

転送トランザクション

private_key = "94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7"

network = {
	"version" => 1,
	"network" => "TESTNET",
	"generationHash" => "7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836",
	"epochAdjustment" => 1637848847,
	"catjasonBase" => "https://xembook.github.io/tsunagi-sdk/catjson/",
}

#now = Time.now.to_i;
now = network["epochAdjustment"];
return ((now  + 7200) - network["epochAdjustment"]) * 1000;


tx1 = {
	"type" => "TRANSFER",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"recipient_address" => generate_address_id("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
	"mosaics" => [
		{"mosaic_id" =>  0x2A09B7F9097934C2, "amount" => 1},
		{"mosaic_id" =>  0x3A8416DB2D53B6C8, "amount" => 100},
	],
	"message" => "Hello Tsunagi(Catjson) SDK!",
}


catjson = load_catjson(tx,network)
layout = load_layout(tx,catjson,false)

prepared_tx = prepare_transaction(tx,layout,network) 
parsed_tx = parse_transaction(prepared_tx,layout,catjson,network) 
built_tx = build_transaction(parsed_tx)

signature = sign_transaction(built_tx,private_key,network);
built_tx = update_transaction(built_tx,"signature","value",signature);
tx_hash = hash_transaction(tx["signer_public_key"],signature,built_tx,network);
payload_string = hexlify_transaction(built_tx)

通知

payload = { "payload" => payload_string}
uri = URI.parse('https://sym-test-02.opening-line.jp:3001/transactions')
req = Net::HTTP::Put.new(uri.request_uri)
req["Content-Type"] = "application/json" 
req.body = payload.to_json

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.request(req)
puts response

連署

連署を必要とするトランザクションの場合は、tx1 に加えて以下のような定義と署名の追加が必要になります。

cosignature1 = {
	"version" => 0,
	"signer_public_key" =>"6199bae3b241df60418e258d046c22c8c1a5de2f4f325753554e7fd9c650afec",
	"signature"=>"",
};

cosignature2 = {
	"version" => 0,
	"signer_public_key" => "886adfbd4213576d63ea7e7a4bece61c6933c27cd2ff36f85155c8febfb6eb4e",
	"signature" => "",
};

agg_tx = {
	"type" => 'AGGREGATE_COMPLETE',
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 1000000,
	"deadline" => get_deadline(network),
	"transactions" => [tx1,tx2,tx3],
	"cosignatures" => [cosignature1,cosignature2]

};

catjson = load_catjson(agg_tx,network)
layout = load_layout(agg_tx,catjson,false)
prepared_tx = prepare_transaction(agg_tx,layout,network) 
parsed_tx = parse_transaction(prepared_tx,layout,catjson,network) 
built_tx = build_transaction(parsed_tx)

private_key = "94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7"
signature = sign_transaction(built_tx,private_key,network);
built_tx = update_transaction(built_tx,"signature","value",signature);
tx_hash = hash_transaction(agg_tx["signer_public_key"],signature,built_tx,network);

#//連署
bob_private_key = "fa6373f4f497773c5cc55c103e348b139461d61fd4b45387e69d08a68000e06b";
carol_private_key = "1e090b2a266877a9f88a510af2eb0945a63dc69dbce674ccd83272717d4175cf";

prepared_tx["cosignatures"][0]["signature"] = cosign_transaction(tx_hash,bob_private_key);
prepared_tx["cosignatures"][1]["signature"] = cosign_transaction(tx_hash,carol_private_key);

cosignatures_layout = layout.find{|lf| lf["name"] == "cosignatures"}
parsed_cosignatures = parse_transaction(prepared_tx,[cosignatures_layout],catjson,network) #//構築
built_tx = update_transaction(built_tx,"cosignatures","layout",parsed_cosignatures[0]["layout"])

payload = hexlify_transaction(built_tx)

トランザクションタイプ別記述例

その他のトランザクションの記述方法について説明します。

アグリゲートボンデッドトランザクション

ハッシュロックトランザクション
tx1 = {
	"type" => "HASH_LOCK",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"mosaic" => [{"mosaic_id" =>  0x3A8416DB2D53B6C8, "amount" => 10000000}],
	"duration" =>  480,
	"hash" => "a3ed27ee26592f6c501349a7de3427fc729e8d625ed214a6331c11b981f59f78"
}
ボンデッド
agg_tx = {
	"type" => 'AGGREGATE_BONDED',
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 1000000,
	"deadline" => get_deadline(network),
	"transactions" => [tx1,tx2,tx3],

}

モザイク生成
tx1 = {
	"type" => "MOSAIC_DEFINITION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"duration" => 0,
	"id" => generate_mosaic_id(generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),nonce),
	"nonce" => nonce,
	"flags" => 'TRANSFERABLE RESTRICTABLE',
	"divisibility" => 2,
}

tx2 = {
	"type" => "MOSAIC_SUPPLY_CHANGE",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"mosaic_id" => generate_mosaic_id(generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),nonce),
	"delta" => 1000 * 100,
	"action" => 'INCREASE',
}

ネームスペース生成

ルートネームスペース
tx1 = {
	"type" => "NAMESPACE_REGISTRATION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"duration" => 86400,
	"registration_type" => "ROOT",
	"name" => "xembook",
	"id" => generate_namespace_id("xembook"),
}

サブネームスペース
tx1 = {
	"type" => "NAMESPACE_REGISTRATION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"parent_id" => generate_namespace_id("xembook"),
	"registration_type" => "CHILD",
	"name" => "tomato",
	"id" => generate_namespace_id("tomato",generate_namespace_id("xembook")),
}

アドレスへのリンク
tx1 = {
	"type" => "ADDRESS_ALIAS",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"namespace_id" => generate_namespace_id("xembook"),
	"address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"alias_action" => "LINK"
}

モザイクへのリンク
tx1 = {
	"type" => "MOSAIC_ALIAS",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"namespace_id" => generate_namespace_id("tomato",generate_namespace_id("xembook")),
	"mosaic_id" => 0x4DAFFBE5505DE676,
	"alias_action" => "LINK"
}

メタデータ

モザイクへのメタデータ
tx1 = {
	"type" => "MOSAIC_METADATA",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"target_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"target_mosaic_id" => 0x4DAFFBE5505DE676,
	"scoped_metadata_key" => generate_key("key_mosaic"),
	"value_size_delta" => 27,
	"value" => "Hello Tsunagi(Catjson) SDK!",
}

agg_tx = {
	"type" => 'AGGREGATE_COMPLETE',
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 1000000,
	"deadline" => get_deadline(network),
	"transactions" => [tx1],

}
ネームスペースへのメタデータ
tx1 = {
	"type" => "NAMESPACE_METADATA",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"target_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"target_namespace_id" => generate_namespace_id("xembook"),
	"scoped_metadata_key" => generate_key("key_namespace"),
	"value_size_delta" => 27,
	"value" => "Hello Tsunagi(Catjson) SDK!",
}

agg_tx = {
	"type" => 'AGGREGATE_COMPLETE',
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 1000000,
	"deadline" => get_deadline(network),
	"transactions" => [tx1],

}

マルチシグ

tx1 = {
	"type" => "MULTISIG_ACCOUNT_MODIFICATION",
	"signer_public_key" => "66adb706bc9a93e6e803b2b76a1341a8acd98690ef204b402643ae3d4701ee77",
	"min_removal_delta" => 1,
	"min_approval_delta" => 1,
	"address_additions" => [
		generate_address_id("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
		generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	],
	"address_deletions" => [],
}

cosignature1 = {
	"version" => 0,
	"signer_public_key" =>"5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"signature"=>"",
}

cosignature2 = {
	"version" => 0,
	"signer_public_key" => "6199bae3b241df60418e258d046c22c8c1a5de2f4f325753554e7fd9c650afec",
	"signature" => "",
}

agg_tx = {
	"type" => 'AGGREGATE_COMPLETE',
	"signer_public_key" => "66adb706bc9a93e6e803b2b76a1341a8acd98690ef204b402643ae3d4701ee77",
	"fee" => 1000000,
	"deadline" => get_deadline(network),
	"transactions" => [tx1],
	"cosignatures" => [cosignature1,cosignature2]

}

制限

アカウントアドレス制限
tx1 = {
	"type" => "ACCOUNT_ADDRESS_RESTRICTION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"restriction_flags" => "ADDRESS BLOCK OUTGOING",
	"restriction_additions" => [
		generate_address_id("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
		generate_address_id("TDZBCWHAVA62R4JFZJJUXQWXLIRTUK5KZHFR5AQ")
	],
	"restriction_deletions" => [],
}

アカウントモザイク制限
tx1 = {
	"type" => "ACCOUNT_MOSAIC_RESTRICTION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"restriction_flags" => "MOSAIC_ID BLOCK",
	"restriction_additions" => [0x4DAFFBE5505DE676,0x2A09B7F9097934C2],
	"restriction_deletions" => [],
}

アカウント操作制限
tx1 = {
	"type" => "ACCOUNT_OPERATION_RESTRICTION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"restriction_flags" => "TRANSACTION_TYPE BLOCK OUTGOING",
	"restriction_additions" => ["TRANSFER","AGGREGATE_COMPLETE"],
	"restriction_deletions" => [],
}

グローバルモザイク制限

モザイクグローバル制限
tx1 = {
	"type" => "MOSAIC_GLOBAL_RESTRICTION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"mosaic_id" => 0x4DAFFBE5505DE676,
	"reference_mosaic_id" => 0,
	"restriction_key" => generate_key("key_account"),
	"previous_restriction_value" => 0,
	"new_restriction_value" => 0x1,
	"previous_restriction_type" => "NONE",
	"new_restriction_type" => "EQ"
}

モザイクアドレス制限
tx1 = {
	"type" => "MOSAIC_ADDRESS_RESTRICTION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"mosaic_id" => 0x4DAFFBE5505DE676,
	"restriction_key" => generate_key("key_account"),
	"previous_restriction_value" => 0xFFFFFFFFFFFFFFFF,
	"new_restriction_value" => 0x1,
	"target_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
}

リボーカブルトランザクション

tx1 = {
	"type" => "MOSAIC_SUPPLY_REVOCATION",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"source_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"mosaic" => [
		{"mosaic_id" =>  0x0552BC5EF5BD589D, "amount" => 100},
	],
}

シークレット

シークレットロック
tx1 = {
	"type" => "SECRET_LOCK",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"recipient_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"secret" => "f260bfb53478f163ee61ee3e5fb7cfcaf7f0b663bc9dd4c537b958d4ce00e240",
	"mosaic" => [
		{"mosaic_id" =>  0x3A8416DB2D53B6C8, "amount" => 10000000},
	],
	"duration" => 480,
	"hash_algorithm" => "SHA3_256",
}


シークレットプルーフ
tx1 = {
	"type" => "SECRET_PROOF",
	"signer_public_key" => "5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	"fee" => 25000,
	"deadline" => get_deadline(network),
	"recipient_address" => generate_address_id("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"),
	"secret" => "f260bfb53478f163ee61ee3e5fb7cfcaf7f0b663bc9dd4c537b958d4ce00e240",
	"hash_algorithm" => "SHA3_256",
	"proof" => "7944496ac0f572173c2549baf9ac18f893aab6d0",
}


5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?