この記事は、以下に紹介した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",
}