LoginSignup
5
2

More than 1 year has passed since last update.

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