15
3

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.

nem / symbolAdvent Calendar 2022

Day 23

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

Last updated at Posted at 2022-12-22

この記事は、以下に紹介したtsunagi-functionsのRust実装版です。
なお、Rust化の実装についてはオープニングライン社にインターンされているヨシザワさんにご協力いただきました

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

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

リポジトリ

tsunagi-functions for Rust

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

テスト

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

v_0_1_0_3_5.rs

Cargo.toml
[package]
authors = ["XEMBook", "Yoshizawa Shogo <xxxx@gmail.com>"]
description = "This is a bridge until a de facto standard SDK is available."

name = "tsunagi_sdk"
version = "0.1.0"
edition = "2021"
license = "MIT"
readme = "README.md"
keywords = ["Symbol"]

repository = "https://github.com/xembook/tsunagi-sdk"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
json = "0.12.4"
url = "2.3.1"
reqwest = { version = "0.11", features = ["blocking"] }
rustc-serialize = "0.3.24"
hex = "0.4.3"
sha3 = "0.10.6"
ed25519-dalek = "1"
base32 = "0.4.0"
テスト実行
cargo test

実装例

テストスクリプトから転送トランザクションの書き方を紹介します。

転送トランザクション

use tsunagi_sdk::v0_1::*; // tsunagi_sdkの関数群をインポート
use json::object;

fn main() {
    // network情報を定義
    let network = object!{
        version:1,
        network:"TESTNET",
        generationHash:"7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836",
        currencyMosaicId:0x3A8416DB2D53B6C8u64,
        currencyNamespaceId:0xE74B99BA41F4AFEEu64,
        currencyDivisibility:6,
        epochAdjustment:1637848847,
        catjasonBase:"https://xembook.github.io/tsunagi-sdk/catjson/",
        wellknownNodes:[
            "https://sym-test.opening-line.jp:3001",
            "https://sym-test.opening-line.jp:3001",
            "https://sym-test.opening-line.jp:3001",
        ]
    };
    // 自分の秘密鍵
    let private_key: &str = "94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7";
    // トランザクションを定義
    let tx = object!{
        type:"TRANSFER",
        signer_public_key:"5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
        fee:25000u64,
        deadline:7200000u64,
        recipient_address:generate_address_id("TCO7HLVDQUX6V7C737BCM3VYJ3MKP6REE2EKROA"),
        mosaics:[
            {mosaic_id: 0x2A09B7F9097934C2u64, amount: 1u64},
            {mosaic_id: 0x3A8416DB2D53B6C8u64, amount: 100u64},
        ],
        message:"Hello Tsunagi(Catjson) SDK!",
    };
    // catjsonの取得
    let catjson = load_catjson(&tx, &network);
    // トランザクションレイアウトの取得
    let layout = load_layout(&tx, &catjson, false);
    // トランザクションの事前準備
    let mut prepared_tx = prepare_transaction(&tx, &layout, &network);
    // レイアウトの解析とトランザクションデータの注入
    let parsed_tx = parse_transaction(&mut prepared_tx, &layout, &catjson, &network);
    // トランザクションの構築
    let built_tx = build_transaction(&parsed_tx);
    // 署名
    let signature = sign_transaction(&built_tx, private_key, &network);
    // トランザクションの更新
    let built_tx = update_transaction(&built_tx, "signature", "value", &signature);

    //ペイロード出力
    let payload = hexlify_transaction(&built_tx.into(), 0);
    // payloadを任意の方法でJson形式でSymbolネットワークへ送信してください。
    // Send the payload to the Symbol network in Json format in any way you wish.
    
    assert_eq!(payload, 
        "dc000000000000001e1a289eef4550fe482ff5a073ba9b91bf38e8623e8767eb54eae5fd48dba354f662dce635ad299efb050cbf187c6b52674613d7e81bb58a4a662d2528d491005f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb0000000001985441a86100000000000000dd6d0000000000989df3aea3852feafc5fdfc2266eb84ed8a7fa242688a8b81c00020000000000c2347909f9b7092a0100000000000000c8b6532ddb16843a64000000000000000048656c6c6f205473756e616769284361746a736f6e292053444b21"
    );
}

通知

let json_request = format!(r#"{{"payload":"{}"}}"#, payload);
let r = ureq::put("https://sym-test-02.opening-line.jp:3001/transactions")
    .set("Content-Type", "application/json")
    .send_string(&json_request);
println!("{}", json_request);
println!("{:?}", r);

連署

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

let cosignature1 = object!{
	version:0u64,
	signer_public_key:"6199BAE3B241DF60418E258D046C22C8C1A5DE2F4F325753554E7FD9C650AFEC",
	signature:"",
};

let cosignature2 = object!{
	version:0u64,
	signer_public_key:"886ADFBD4213576D63EA7E7A4BECE61C6933C27CD2FF36F85155C8FEBFB6EB4E",
	signature:"",
};

let agg_tx = object!{
	type:"AGGREGATE_COMPLETE",
	signer_public_key:"5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb",
	fee:1000000u64,
	deadline:get_deadline(&get_network_info()),
	transactions:[tx1,tx2,tx3],
	cosignatures:[cosignature1,cosignature2]
};

let catjson = load_catjson(&agg_tx,&get_network_info());
let layout = load_layout(&agg_tx,&catjson,false); //isEmbedded false

let mut prepared_tx = prepare_transaction(&agg_tx,&layout,&get_network_info()); //TX事前準備
let parsed_tx   = parse_transaction(&mut prepared_tx,&layout,&catjson,&get_network_info()); //TX解析
let mut built_tx    = build_transaction(&parsed_tx); //TX構築

let signature = sign_transaction(&built_tx,PRIVATE_KEY,&get_network_info());
built_tx = update_transaction(&built_tx,"signature","value",&signature);

//トランザクションハッシュ作成
let tx_hash = hash_transaction(&agg_tx["signer_public_key"].to_string(),&signature.to_string(),&built_tx,&get_network_info());


//連署
prepared_tx["cosignatures"][0]["signature"] = cosign_transaction(&tx_hash,BOB_PRIVATE_KEY).into();
prepared_tx["cosignatures"][1]["signature"] = cosign_transaction(&tx_hash,CAROL_PRIVATE_KEY).into();

let cosignatures_layout = layout.iter().find(|&lf| lf["name"] == "cosignatures").unwrap().clone();
let parsed_cosignatures = parse_transaction(&mut prepared_tx,&vec![cosignatures_layout],&catjson,&get_network_info()); //構築
built_tx = update_transaction(&built_tx,"cosignatures","layout",&parsed_cosignatures[0]["layout"]);

let payload = hexlify_transaction(&built_tx.into(), 0);


他にもテストスクリプトに様々なトランザクションを記述しているのでぜひお試しください!

15
3
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
15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?